Streaming 使用FFmpeg,如何解码H264数据包

Streaming 使用FFmpeg,如何解码H264数据包,streaming,ffmpeg,decode,h.264,Streaming,Ffmpeg,Decode,H.264,我是FFmpeg新手,正在努力解码H264数据包,这些数据包可以作为uint8_t数组获得 经过多次调查,我认为它应该能够将数组放入如下所示的AVPacket中 AVPacket *avpkt = (AVPacket *)malloc(sizeof(AVPacket) * 1); av_init_packet(avpkt); avpkt->data = ct; // ct is the array avpkt->length =.... 并通过avcodec\u decod

我是FFmpeg新手,正在努力解码H264数据包,这些数据包可以作为uint8_t数组获得

经过多次调查,我认为它应该能够将数组放入如下所示的AVPacket中

AVPacket *avpkt = (AVPacket *)malloc(sizeof(AVPacket) * 1);
av_init_packet(avpkt);  
avpkt->data = ct;   // ct is the array
avpkt->length =....
并通过
avcodec\u decode\u video2()
进行解码

代码的一部分类似于:

...
codec = avcodec_find_decoder(CODEC_ID_H264);
gVideoCodecCtx = avcodec_alloc_context();
gFrame = avcodec_alloc_frame();
avcodec_decode_video2(gVideoCodecCtx, gFrame, &frameFinished, packet);
...
我想我已正确设置了所有必需的属性,但此函数仅返回
-1

我刚刚发现
-1
来自

ret = avctx->codec->decode(avctx, picture, got_picture_ptr, avpkt);
avcodec\u decode\u video2()中

实际上,我想知道的是如何通过
avcodec\u decode\u video2()
解码H264数据包(没有RTP报头)


更新:

好的,我还在努力寻找解决办法。我现在做的是下面的

AVPacket *avpkt = (AVPacket *)malloc(sizeof(AVPacket) * 1);
av_init_packet(avpkt);  
avpkt->data = ct;   // ct is the array
avpkt->length =....
**该RTP流中的H264流由FU-A编码

  • 接收RTP数据包

  • 查看RTP报头的第二个字节是否大于0,这意味着它是第一个数据包(可能会紧跟其后)

  • 查看下一个RTP数据包的第二个字节是否也大于0,则表示前一帧是完整的NAL,或者如果该帧小于0,则应将该数据包附加到前一个数据包

  • 删除数据包的所有RTP头,使其仅具有类似FU指示符| FU头| NAL

  • 尝试使用
    avcodec\u decode\u video2()播放它

  • 但它只返回
    -1

    我是否也应该移除FU指示器和收割台


    如果您有任何建议,我们将不胜感激。

    我认为您无法在没有RTP报头的情况下解码H264数据包,因为RTP报头中嵌入了相当多的视频流信息。同时,我猜想所有的视频流信息都有可能被复制到RTP视频包中。因此,它还取决于流是如何生成的

    Vibgyor

    实际上,我想知道的是,我是否可以通过avcodec_decode_video2()解码H264数据包(没有RTP报头)

    如果使用非单个NAL单元模式的打包模式,则在将NAL单元传递给解码器之前,可能需要预处理RTP有效负载(重新组装碎片NAL、拆分聚合NAL)。流中允许的NAL单元类型(STAP、MTAP、FU)取决于打包模式。有关打包模式的更多信息,请阅读


    其次,虽然我对FFMPEG不太熟悉,但它可能更像是一个一般的H.264解码问题:在解码其他帧之前,必须始终使用H.264序列(SPS)和图片参数集(PPS)初始化解码器。你做到了吗?

    这是我的工作代码

    bool VideoDecoder::decode(const QByteArray &encoded)
    {
        AVPacket packet;
       av_new_packet(&packet, encoded.size());
       memcpy(packet.data, encoded.data(), encoded.size());
       //TODO: use AVPacket directly instead of Packet?
       //TODO: some decoders might in addition need other fields like flags&AV_PKT_FLAG_KEY
    
       int ret = avcodec_decode_video2(d->codec_ctx, d->frame, &d->got_frame_ptr, &packet);
       av_free_packet(&packet);
    
       if ((ret < 0) || (!d->got_frame_ptr))
           return false;
    
        d->sws_ctx = sws_getCachedContext(d->sws_ctx
            , d->codec_ctx->width, d->codec_ctx->height, d->codec_ctx->pix_fmt
            , d->width, d->height, d->pix_fmt
            , (d->width == d->codec_ctx->width && d->height == d->codec_ctx->height) ? SWS_POINT : SWS_BICUBIC
            , NULL, NULL, NULL
            );
    
        int v_scale_result = sws_scale(
            d->sws_ctx,
            d->frame->data,
            d->frame->linesize,
            0,
            d->codec_ctx->height,
            d->picture.data,
            d->picture.linesize
            );
        Q_UNUSED(v_scale_result);
    
        if (d->frame->interlaced_frame)
            avpicture_deinterlace(&d->picture, &d->picture, d->pix_fmt, d->width, d->height);
        return true;
    }
    
    bool视频解码器::解码(常量QByteArray和编码)
    {
    数据包;
    av_新_数据包(&packet,encoded.size());
    memcpy(packet.data,encoded.data(),encoded.size());
    //TODO:直接使用AVPacket而不是Packet?
    //TODO:一些解码器可能还需要其他字段,如flags和AV_PKT_FLAG_KEY
    int-ret=avcodec\u decode\u video2(d->codec\u ctx,d->frame,&d->got\u frame\u ptr,&packet);
    av_免费_数据包(&数据包);
    如果((ret<0)| |(!d->got_frame_ptr))
    返回false;
    d->sws\U ctx=sws\U getCachedContext(d->sws\U ctx
    ,d->codec_ctx->width,d->codec_ctx->height,d->codec_ctx->pix_fmt
    ,d->宽度,d->高度,d->pix\U fmt
    ,(d->width==d->codec\u ctx->width&&d->height==d->codec\u ctx->height)?SWS\u点:SWS\u双三次曲线
    ,空,空,空
    );
    int v_比例结果=sws_比例(
    d->sws_ctx,
    d->帧->数据,
    d->框架->线条尺寸,
    0,
    d->codec_ctx->高度,
    d->picture.data,
    d->picture.linesize
    );
    Q_未使用(v_标度结果);
    如果(d->帧->交错帧)
    avpicture\u解交错(&d->picture,&d->picture,d->pix\U fmt,d->宽度,d->高度);
    返回true;
    }
    
    谢谢Vibgyor,实际上发送方是spydroid开源软件,它的rtp头看起来不包含很多东西。。它由有效负载类型、序列号、时间戳、同步源标识符组成。。其中任何一个表示视频流信息??我不这么认为。。我仍在努力,并将更新我的进度。感谢拉尔夫,结果证明spydroid在单nal模式和fu-1模式下都发送rtp包,所以我想我需要将fu-1情况下的数据包作为rtp头处理,但不知道如何使用ffmpeg库解码rtp。我认为RTP层没有功能,这就是为什么我要从H264开始这项工作:(…我能得到一些建议吗?如果ffmpeg在RTP层不起作用,你要么在将代码传递给ffmpeg之前自己编写代码(没有那么糟糕),要么使用另一个第三方库。Live555(www.Live555.com)将是一个开源LGPL库,用于处理RTP,包括H.264负载特定的打包等。@Ralf我相信单NAL单元数据包模式也是RFC6184的一部分,有关RFC,请参阅第5.6节。我不确定您为什么说它不需要RTP头。如果我错了,请纠正我。@Krishna_Oza谢谢,没错,我没有表达得很好。更新答案。