【问题标题】:Trouble Decoding H264 Frames with FFMpeg使用 FFMpeg 解码 H264 帧时遇到问题
【发布时间】:2017-04-23 23:32:28
【问题描述】:

我正在尝试使用 FFMPeg 解码 H264 原始流。

我得到了保存的视频并使用以下命令进入了 FFMpeg:

ffmpeg -i 20161201-090322.264 -pixel_format yuv420p -filter:v fps=fps=600/60 $filename%03d.raw

并成功从视频中获取帧。 然后,我开始尝试解码直接流(这些视频中保存的确切内容)。

我正在像这样初始化 ffmpeg:

    cam->ffmpegCodec = avcodec_find_decoder(AV_CODEC_ID_H264);
    cam->ffmpgContext = avcodec_alloc_context3(cam->ffmpegCodec);
    cam->ffmpgContext->width = cam->Width;
    cam->ffmpgContext->height = cam->Height;
    cam->ffmpgContext->pix_fmt = AV_PIX_FMT_YUV420P;

    cam->ffmpegFrame = av_frame_alloc();
    cam->ffmpegParser = av_parser_init(AV_CODEC_ID_H264);

    if(!cam->ffmpegParser)
    {
        sprintf(msg, "Error, initializing parser");
        libLogCtx(msg, MODULE_NAME, PLogFileRelease, true);
    }

    int res = avcodec_open2(cam->ffmpgContext, cam->ffmpegCodec, 0);
    if( res != 0)
    {
        sprintf(msg, "Error, openning codec [%d]", res);
        libLogCtx(msg, MODULE_NAME, PLogFileRelease, true);
    }

这些是我在 cam 结构中的声明:

 AVCodecContext  *ffmpgContext;
 AVCodec         *ffmpegCodec;
 AVFrame         *ffmpegFrame;
 AVCodecParserContext *ffmpegParser;

当我收到流内容时,我会执行以下步骤:

/// Copy the received data to buffer
memcpy(cam->imageBuffer + cam->imageBufferSz, pBuffer, dwBufSize);
cam->imageBufferSz += dwBufSize;

/// If there's some data,
if(cam->imageBufferSz > 0)
{
    /// Try to parse
    uint8_t* data = NULL;
    int size = 0;
    int len = av_parser_parse2(cam->ffmpegParser, cam->ffmpgContext, &data, &size, 
         cam->imageBuffer,  cam->imageBufferSz, 0, 0, AV_NOPTS_VALUE);

    if(size > 0 && len >= 0)
    {
        /// Fill the packet and decode
        AVPacket pkt;
        av_init_packet(&pkt);
        pkt.data = cam->imageBuffer;
        pkt.size = cam->imageBufferSz;
        int frameFinished = 0;

        int nres = avcodec_decode_video2(cam->ffmpgContext, cam->ffmpegFrame, &frameFinished, &pkt);
        /// If decoding was successfully, Save only the Y to file (i'm just testing).
        if(frameFinished)
        {
            char fnm[255];
            sprintf(fnm, "C:\\Users\\Black_Spiders\\Desktop\\Rls\\test%d.raw", n);
            n++;
            FILE* f = (FILE*)fopen(fnm, "w");

            for (int y = 0; y < cam->ffmpegFrame->height; y++)
            {
                fwrite(cam->ffmpegFrame->data[0] + y*cam->ffmpegFrame->linesize[0], 1, cam->ffmpegFrame->width, f);
            }

            fclose(f);
        }
    }


}

虽然我的代码看起来还不错(在互联网上研究了一段时间),但我得到了这个结果:

谁能给我一些建议?

最好的问候,

【问题讨论】:

  • 我不知道正确的解析器 API 用法,但您的似乎是错误的。您不应该以某种方式使用lendatasize 输出吗?并且应该有一个围绕av_parser_parse2 call/consume 的循环。
  • @AndreyTurkin 这是我正在使用的 DVR 调用的回调。这就是为什么 av_parser_parse2 不在循环中的原因(每次 DVR 有数据时都会调用它)。关于 len、data 和 size 的使用,我对 h264 和 ffmpeg 没有经验,我尝试按照这个教程进行操作:link。顺便说一下,本教程使用此方法的目的似乎是检查是否有足够的数据来使用 avcodec_decode_video2。我尝试使用len 作为我的pkt 大小,但结果仍然相同。

标签: c++ ffmpeg h.264 yuv


【解决方案1】:

这是直接来自 ffmpeg 文档的示例代码:

while(in_len) {
     len = av_parser_parse2(myparser, AVCodecContext, &data, &size,
                                 in_data, in_len,
                                 pts, dts, pos);
     in_data += len;
     in_len  -= len;
     if(size)
        decode_frame(data, size);
}

所以,想法是调用这个函数,它会返回:

1) 指向要传递给解码器的编码帧的指针和大小;请注意您指出的示例中使用的大小(但他们没有使用错误的指针;由于 H264 比特流的性质及其对缓冲区的使用,他们很幸运)

2) 输入的处理部分的长度。输入可能并且可能会包含多个帧或帧的不完整部分。您应该使用其余输入再次调用该函数(一次又一次,直到整个数据块被解析)。如果您仔细检查您的示例,您会发现它可以做到这一点,而您的代码却没有。

此外,您可能不需要缓冲传入的数据,因为解析器应该在内部缓冲不完整的帧。

【讨论】:

    猜你喜欢
    • 2011-08-24
    • 1970-01-01
    • 1970-01-01
    • 2012-07-05
    • 2016-11-10
    • 2011-11-24
    • 2011-03-30
    • 1970-01-01
    • 2021-09-04
    相关资源
    最近更新 更多