【问题标题】:H264 decoding using ffmpeg使用 ffmpeg 进行 H264 解码
【发布时间】:2019-05-18 10:28:58
【问题描述】:

我正在尝试使用 ffmpeg 库解码视频流,我基本上就是这样做的:

void video_decode(const char *filename)
{
    AVCodec *codec;
    AVCodecContext *c= NULL;
    int frame_count=0;
    FILE *f;
    AVFrame *frame;
    uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
    AVPacket avpkt;
    av_init_packet(&avpkt);
    memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE);
    printf("Decoding video file...\n");
    /* find the h264 video decoder */
    codec = avcodec_find_decoder(AV_CODEC_ID_H264);
    c = avcodec_alloc_context3(codec);
    c->bit_rate = 400000;
    c->width = 1920;
    c->height = 1080;

    if (avcodec_open2(c, codec, NULL) < 0) {
        fprintf(stderr, "Could not open codec\n");
        exit(1);
    }
    frame = av_frame_alloc();
    for (;;) {
        avpkt.size = fread(inbuf, 1, INBUF_SIZE, f);         
    if (avpkt.size == 0)
            break;
        avpkt.data = inbuf;
        while(avpkt.size > 0){

        int len, got_frame;
            len = avcodec_decode_video2(c, frame, &got_frame, &avpkt);          
        if (len < 0) {
                fprintf(stderr, "Errr while decding frame %d\n", frame_count);
                exit (1);
            }
            if (got_frame) {
                //Print out frame information..
        }
            if (avpkt.data) {
                avpkt.size -= len;
                avpkt.data += len;
            }
    }               
    }  
}

但我得到了以下输出:

Decoding video file...
[h264 @ 0x303c040] decode_slice_header error
[h264 @ 0x303c040] decode_slice_header error
[h264 @ 0x303c040] decode_slice_header error
[h264 @ 0x303c040] no frame!
Errr while decding frame 0

很明显,编解码器的启动是不完整的。你有使用 h264 api 的经验吗?任何帮助将不胜感激。

【问题讨论】:

  • 您是否有证据证明该文件确实是原始 h264 流?至少一帧可以吗?你的 IBUF_SIZE 会不会太小?请将您的代码与roxlu.com/2014/039/decoding-h264-and-yuv420p-playback 进行比较:您缺少的一件事是它们的 H264_Decoder::readBuffer()
  • 好提示!谢谢:-)
  • 我很困惑为什么某些 .h264 文件一帧(只有一帧)可以走,但某些 .h264 文件没有帧可以?我的意思是,它们都是 .h264 文件,解码的差异在哪里?又如何知道 h264 流是否是原始 h264 流? @亚历克斯科恩
  • 您可以使用ffprobeffmpeg 来检查文件的格式。关于第一个问题,下面的@szatmary 给出了提示:您选择了一些任意的INBUF_SIZE。如果 h264 流的第一帧恰好适合此缓冲区,则 avcodec 可以对其进行解码。如果流的第一帧碰巧更大,那么您的方法将失败。您是否更新了代码以执行我上面链接的 roxlu.com readBuffer() 的逻辑?
  • 嗨,我确实阅读了您推荐的代码。我没有使用随机 IBUF_SIZE,而是使用了最大大小:这有点浪费内存,但节省了更新缓冲区的工作量。我认为 AU 或 NALU 确实在这种情况下发挥了重要作用,我必须进一步阅读这些东西。非常感谢!

标签: c ffmpeg


【解决方案1】:

您不能只将随机数 (INBUF_SIZE) 字节放入 AV 数据包中。应该是全AU或者NALU,如果不是附件B,必须先设置extra data字段。对于您的情况,我建议使用 libavformat 打开文件并读取 AVPackets。

【讨论】:

  • “使用 libavformat 打开文件”是什么意思?你能给我一个简单的代码sn-p吗? @szatmary
  • 您的评论对我来说很有意义。我只有一个问题:当你说完整的 NALU 时,是不是因为 NALU 会像 RTP 数据包一样被分解成碎片?如果是这样,我应该如何将它们粘合在一起以获得一个完整的 NALU 以放入 AV 数据包中?非常感谢您的帮助,在网上很难找到有关 ffmpeg 的信息
【解决方案2】:

这个问题的答案在demuxing_decoding.c ffmpeg的例子下面给出。

如果您的ffmpeg安装目录默认为“usr/local/”,则可以如下独立编译该文件。

gcc -I/usr/local/include  -c demuxing_decoding.c -o demuxing_decoding.o
gcc demuxing_decoding.o -pthread -L/usr/local/lib -lavdevice -lavfilter -lpostproc -lavformat -lavcodec -lva-x11 -lva -lxcb-xfixes -lxcb-render -lxcb-shape -lxcb -lX11 -lx264 -lpthread -ldl -lz -lswresample -lswscale -lavutil -lm  -o demuxing_decoding

如果安装目录更改为“ffmpeg_ins_dir”,请将上述命令中的“usr/local/”替换为“path upto” ffmpef_ins_dir/”。

如下运行二进制文件。

./demuxing_decoding test.h264 v_out.yuv a_out.yuv

注意:这个例子有很多你可能根本不需要的东西,删除不需要的东西并重新编译。

【讨论】:

    【解决方案3】:

    也许你应该尝试在你的 fread() 和 avcodec_decode_video2() 之间使用 AVCODECPARSER; av_parser_parse2()。使您的原始数据从at数据更改为h264以提供您的解码器。 像这样的C代码:

    #
    while (1)
    {
        cur_size = fread(in_buffer, 1, in_buffer_size, fp_in);
        cur_ptr = in_buffer;
        while (cur_size > 0)
        {
            int len = av_parser_parse2(pCodecParserCtx, pCodecCtx, &packet.data, &packet.size, cur_ptr, cur_size, AV_NOPTS_VALUE, AV_NOPTS_VALUE, AV_NOPTS_VALUE);
            cur_ptr += len;
            cur_size -= len;
    
            ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, &packet);  
            if (ret < 0)
            {
                printf("Decode Error\n");
                return ret;
            }
            if (got_picture)
            {
                printf("Succeed to decode 1 frame!\n");
            }
        }
    

    受此启发: https://blog.csdn.net/leixiaohua1020/article/details/42181571

    【讨论】:

    • 我是堆栈溢出的新手。你是什​​么意思 ?文本样式?还是代码错了?
    • 您的代码有什么问题?堆栈溢出如何帮助您解决问题?
    • 不是我的问题,我想给 Kindermann 一些提示。我遇到了类似的问题,我通过使用 av_parser_parse2 解决了
    • 试着一步一步地阐述你的答案,很混乱
    猜你喜欢
    • 2011-11-24
    • 2011-08-26
    • 2011-08-24
    • 2020-10-06
    • 2015-06-07
    • 2020-06-13
    • 2012-03-07
    • 2012-06-30
    • 2021-05-05
    相关资源
    最近更新 更多