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

发布于 2025-01-06 17:25:44 字数 1388 浏览 1 评论 0原文

我是 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_decode_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_decode_video2();

实际上,我想知道如何通过 avcodec_decode_video2() 解码 H264 数据包(没有 RTP 标头)?


更新:

好的,我仍在尝试寻找解决方案。我现在正在做的是下面

** 这个RTP流中的H264流是由FU-A编码

  1. 接收一个RTP数据包

  2. 看看RTP的第二个字节是否标题是> 0 表示它是第一个数据包(并且可能会跟随)

  3. 查看下一个 RTP 数据包是否有 >0第二个字节也为 0,则表示前一帧是完整的 NAL,或者如果它 < 0,该数据包应该追加到前一个数据包的后面。

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

  5. 尝试使用 avcodec_decode_video2()

但它只返回 -1。 ....
我是否也应该删除 FU 指示器和标头?

任何建议将不胜感激

I'm new to FFmpeg and struggling to decode H264 packets which can be obtained as an array of uint8_t.

After many of investigations, I think it should be able to just put the array into an AVPacket like the below

AVPacket *avpkt = (AVPacket *)malloc(sizeof(AVPacket) * 1);
av_init_packet(avpkt);  
avpkt->data = ct;   // ct is the array
avpkt->length =....

and decode by avcodec_decode_video2().

A part of the code is like:

...
codec = avcodec_find_decoder(CODEC_ID_H264);
gVideoCodecCtx = avcodec_alloc_context();
gFrame = avcodec_alloc_frame();
avcodec_decode_video2(gVideoCodecCtx, gFrame, &frameFinished, packet);
...

I guess I set all required properties properly but this function returns only -1

I just found the -1 is coming from

ret = avctx->codec->decode(avctx, picture, got_picture_ptr, avpkt);

in the avcodec_decode_video2();

Actually, what I'm wondering is how can I decode H264 packets (without RTP header) by avcodec_decode_video2()?


Updated:

OK, I'm still trying to find a solution. What I'm doing now is the below

** The H264 stream in this RTP stream is encoded by FU-A

  1. Receive an RTP packet

  2. Look if the second byte of the RTP header is > 0 which means it's the first packet (and possibly will be followed)

  3. See if the next RTP packet has > 0 at its second byte also, then it means the previous frame was a complete NAL or if this is < 0, the packet should be appended to the previous packet.

  4. Remove all RTP header of the packets so it has only like FU indicator | FU header | NAL

  5. Try play it with avcodec_decode_video2()

But it's only returning -1.....
Am I supposed to remove FU indicator and header too??

Any suggestion will be very appreciated

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

三生路 2025-01-13 17:25:44

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

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

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

Actually, what I'm wondering is if I can decode H264 packets (without RTP header) by avcodec_decode_video2().

You may need to pre-process the RTP payload(s) (re-assemble fragmented NALUs, split aggregated NALUs) before passing NAL units to the decoder if you use packetization modes other than single NAL unit mode. The NAL unit types (STAP, MTAP, FU) allowed in the stream depends on the packetization mode. Read RFC 6184 for more info on packetization modes.

Secondly, while I am not that familiar with FFMPEG, it could be more of a general H.264 decoding issue: you must always initialise the decoder with the H.264 sequence (SPS) and picture parameter sets (PPS) before you will be able to decode other frames. Have you done that?

软糖 2025-01-13 17:25:44

我认为您无法在没有 RTP 标头的情况下解码 H264 数据包,因为 RTP 标头中嵌入了相当多的视频流信息。同时,我猜测所有视频流信息可能会在RTP视频数据包中重复。所以这也取决于流是如何生成的。

维布杰尔

I don't think that you will be able to decode H264 packets without RTP header as quite a bit of video stream information is embedded in the RTP headers. At the same time, I guess it is possible that all the video stream information can be duplicated in the RTP video packets. So it also depends how the stream is generated.

Vibgyor

谜泪 2025-01-13 17:25:44

这是我的工作代码

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;
}

This is my working code

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文