同声 2022-04-15 16:58 采纳率: 50%
浏览 206
已结题

如何添加PPS SPS数据,在FFMPEG取USB相机RGBA数据后,再实现H.264压缩后RTMP推流

问题遇到的现象和发生背景

项目中读取Kinect TOF相机中RGBA与深度数据,需要将RGBA色彩数据推流到服务器上。我采用FFMPEG 编解RGBA数据,用H.264编码压缩,推流到ZLMediaKIT上,

1、采用ffplay拉流可以解码播放,但报错如下信息:

Input #0, flv, from 'rtmp://127.0.0.1:1936/live/livestream':f=0/0
Metadata:
encoder : Lavf57.83.100
server : ZLMediaKit(git hash:a0c1bc1,branch:master,build time:Apr 11 2022 09:38:46)
Duration: 00:00:00.00, start: 8.667000, bitrate: N/A
Stream #0:0: Video: h264 (Constrained Baseline), yuv420p(progressive), 1280x720, 20971 kb/s, 15.17 fps, 15 tbr, 1k tbn, 30 tbc
[h264 @ 0x7f48f40a5a40] non-existing PPS 0 referenced 0B f=0/0
[h264 @ 0x7f48f40a5a40] decode_slice_header error
[h264 @ 0x7f48f40a5a40] no frame!
[h264 @ 0x7f48f409ad80] non-existing PPS 0 referenced 0B f=0/0
[h264 @ 0x7f48f409ad80] decode_slice_header error
[h264 @ 0x7f48f409ad80] no frame!
[h264 @ 0x7f48f40a13a0] non-existing PPS 0 referenced 0B f=0/0
[h264 @ 0x7f48f40a13a0] decode_slice_header error
[h264 @ 0x7f48f40a13a0] no frame!

2、另外用我本地Android app 播放RTMP url 不成功

3、如果直接采用“ffmpeg -f v4l2 -r 25 -i /dev/video0 -c:v libx264 -pix_fmt yuv420p -preset ultrafast -g 30 -b:v 500k -threads 0 -bufsize 512k -f flv rtmp://127.0.0.1:1935/live/livestream &”推流,可以本地Android app成功 播放RTMP url。

4 我推测FFMPEG 按照H.264直接编码RGBA数据推流时,没有把pps\sps等信息加进去,想请教一下各位该怎么处理呢?

其中推流代码如下:

for(;;) {

    k4a_image_t color_image;
    gettimeofday(&tv,NULL);    
    switch (k4a_device_get_capture(device,&capture,TIMEOUT_IN_MS)){
        case K4A_WAIT_RESULT_SUCCEEDED:
            break;
        case K4A_WAIT_RESULT_TIMEOUT:
            printf("Timed out waiting for a capture\n");
            continue;
            break;
        case K4A_WAIT_RESULT_FAILED:
            printf("Failed to read a capture\n");
            return -1;
    }     
    cout<<"完成取流后---->"<<tv.tv_sec*1000 + tv.tv_usec/1000<<endl; 
    // probe for a color image
    color_image = k4a_capture_get_color_image(capture);
    if(color_image) {            
        // printf(" | Color res:%4dx%4d stride:%5d ",
        //         k4a_image_get_height_pixels(color_image),
        //         k4a_image_get_width_pixels(color_image),
        //         k4a_image_get_stride_bytes(color_image)); 
               
    }else{
        printf("获取彩色帧数据失败");
    } 
         
    // 得到YUV420数据地址 
    // 后续替换为队列保存数据
    uint8_t * color_image_buffer = k4a_image_get_buffer(color_image); 
    AVFrame *yuv = convertRGBtoYUV(color_image_buffer);   
    yuv->pts = videoPts++;     
  
    int ret = avcodec_send_frame(avCodecContext, yuv);
    if (ret != 0) {
        break ;
    }
    ret = avcodec_receive_packet(avCodecContext, &outVideoPacket);
    if (ret != 0 || outVideoPacket.size <= 0) {
        break ;
    }  
    AVPacket *pkt = &outVideoPacket;
    if (pkt)
    {           
        ////推流
        if (sendFrame(pkt,vindex))
        {
            cout << "@" << flush;
        }
    }     

}     

}

参照网上资料:
**  我在代码 ret = avcodec_receive_packet(avCodecContext, &outVideoPacket);后添加如下代码**也没有成功

斜体部分参考网上资料写的,但也没有成功,  


```c++
if (pkt->flags &AV_PKT_FLAG_KEY)
         {
             cPacketData = (char*)pkt->data; 
             int n = 0;
             while ((char*)pkt->data)
             {   
                // 找到NAL中I帧位置
                 if (cPacketData[n] == 0 && cPacketData[n + 1] == 0 && cPacketData[n + 2] == 0 && cPacketData[n + 3] == 1 && cPacketData[n + 4] == 101)
                 {
                     //找到I帧,插入SPS和PPS
                    memcpy(cExtradata, avCodecContext->extradata, avCodecContext->extradata_size);
                    memcpy(cExtradata + avCodecContext->extradata_size, pkt->data, pkt->size);//&enc_packet.data[0]
                     pkt->size += avCodecContext->extradata_size;
                     pkt->data = cExtradata;
                     break;
                }
                 if (n == pkt->size)
                 {                 
                     break;
                 }
                 cPacketData++;
                n++;            
            }                    
         }      


另外我的编码器代码如下:



```c++
/**
     * 初始化编码器
     * @return
     */
    bool initVideoCodec() {
        int ret = 0;
        // 创建编码器上下文
         AVCodec* videoCodec = avcodec_find_encoder(AV_CODEC_ID_H264);
        // AVCodec* videoCodec = avcodec_find_encoder(AV_CODEC_ID_HEVC);
        
        if (!videoCodec) {
            cout << "没有找到编码器" << endl;
            return false;
        }
        // 编码器分配上下文
        avCodecContext = avcodec_alloc_context3(videoCodec);
        if (!avCodecContext) {
            cout << "编码器上下文空间分配错误" << endl;
            return false;
        }  

        // 配置编码器参数 
        avCodecContext->codec_id = videoCodec->id;
        avCodecContext->thread_count = 3; // 如果多个相机播放,这样没啥效果
        cout << "initVideoCodec 获取CPU NUM: " << avCodecContext->thread_count << endl;
        //压缩后每秒视频的bit位大小 20kB
        avCodecContext->bit_rate = bitRate; // 码率
        avCodecContext->width = outWidth;
        avCodecContext->height = outHeight;
        avCodecContext->time_base = {1, fps};
        avCodecContext->framerate = {fps, 1};        
        // 画面组的大小,多少帧一个关键帧
        avCodecContext->gop_size = 5;
        avCodecContext->max_b_frames = 0;  //编码器不使用B帧,提高直播解码效率
        avCodecContext->pix_fmt = AV_PIX_FMT_NV12;
        avCodecContext->codec_type = AVMEDIA_TYPE_VIDEO;

        av_opt_set(avCodecContext->priv_data,"preset","ultrafast",0);
        av_opt_set(avCodecContext->priv_data,"tune","zerolatency",0);
        AVDictionary *opts = NULL;
        av_dict_set(&opts, "profile", "baseline", 0);
        // 打开编码器上下文
        ret = avcodec_open2(avCodecContext, 0, &opts);      
        if (ret != 0) {
            cout << "avcodec_open2出错" << endl;
            return false;
        }

        cout << "视频编码器初始化 完成"<< endl;
        return true;
    }

  • 写回答

1条回答 默认 最新

  • 不会写代码的猴子 Android领域优质创作者 2022-04-16 21:21
    关注

    1.编码后推流,可以先把编码后的数据保存成文件,看看能不能正常播放
    2.ffmpeg推流,可以手动把sps和pps加上试试(一般情况下I帧自带sps和pps)

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 4月26日
  • 已采纳回答 4月18日
  • 创建了问题 4月15日

悬赏问题

  • ¥15 我这个代码哪里有问题 acm 平台上显示错误 90%,我自己运行好像没什么问题
  • ¥50 C#编程中使用printDocument类实现文字排版打印问题
  • ¥15 找会编程的帅哥美女 可以用MATLAB里面的simulink编程,用Keil5编也可以。
  • ¥15 已知隐函数其中一个变量τ的具体值,求另一个变量
  • ¥15 r语言Hurst指数
  • ¥15 Acrn IVSHMEM doorbell问题
  • ¥15 yolov5中的val测试集训练时数量变小问题
  • ¥15 MPLS/VPN实验中MPLS的配置问题
  • ¥15 materialstudio氢键计算问题
  • ¥15 echarts图表制作