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

如何添加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日

悬赏问题

  • ¥60 版本过低apk如何修改可以兼容新的安卓系统
  • ¥25 由IPR导致的DRIVER_POWER_STATE_FAILURE蓝屏
  • ¥50 有数据,怎么建立模型求影响全要素生产率的因素
  • ¥50 有数据,怎么用matlab求全要素生产率
  • ¥15 TI的insta-spin例程
  • ¥15 完成下列问题完成下列问题
  • ¥15 C#算法问题, 不知道怎么处理这个数据的转换
  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!
  • ¥15 drone 推送镜像时候 purge: true 推送完毕后没有删除对应的镜像,手动拷贝到服务器执行结果正确在样才能让指令自动执行成功删除对应镜像,如何解决?