c - FFMPEG:视频解码器解析器的工作原理

标签 c parsing video ffmpeg codec

我正在了解 FFMPEG 多媒体框架中的 H.263 视频解码器解析器的工作原理。

我所知道的:

每个视频解码器都需要一个解析器从给定的输入流中获取帧,一旦获得与帧相关的数据,就会将其发送到解码器进行解码过程。

每个编解码器的解析器都需要定义一个 AVCodecParser 类型的结构。该结构有一个函数指针:

.parser_parse -> 指向处理解析功能的函数

.parser_close -> 指向执行缓冲区释放的函数。

以视频解码器H.264为例,它有一个解析器函数,如下所示:

static int h263_parse(AVCodecParserContext *s,
                           AVCodecContext *avctx,
                           const uint8_t **poutbuf, int *poutbuf_size,
                           const uint8_t *buf, int buf_size)
{
    ParseContext *pc = s->priv_data;
    int next;

    if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
        next = buf_size;
    } else {
        next= ff_h263_find_frame_end(pc, buf, buf_size);

        if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
            *poutbuf = NULL;
            *poutbuf_size = 0;
            return buf_size;
        }
    }

    *poutbuf = buf;
    *poutbuf_size = buf_size;
    return next;
}

谁能解释一下上述函数的参数。

据我所知:

poutbuf -> 是一个指向已解析帧数据的指针。

poutbuf_size -> 包含数据的大小。

我的上述假设正确吗?哪个参数保存输入缓冲区数据?上面的解析函数返回什么?任何引用该帖子的人都会对上述代码进行简要解释。任何有关相同内容的信息都会非常有帮助。

最佳答案

首先免责声明:自从我上次研究这个东西以来已经有一段时间了......

Are my above assumptions right?

是的,poutbuf是指向帧数据(开始)的指针,poutbuf_size包含帧数据的大小。

Which parameter holds the input buffer data?

buf,大小为 buf_size。请注意,解析器不一定会复制数据,因此 buf 和 poutbuf 可能指向相同的分配。 (例如,当跳过解析时)。 只是说,如果您想弄乱输出缓冲区,这也可能会修改输入缓冲区并产生意想不到的副作用。

输出缓冲区将指向与输入缓冲区相同的分配,或者指向解析器上下文保存的内部缓冲区。因此,输出缓冲区将因释放输入缓冲区而被释放,或者当解析器上下文重新分配其缓冲区或被销毁时被释放。

And what is the above parse function returning?

该函数有三个输出:

  • 实际返回值。该值指定下一次调用的输入的相对偏移量。
  • poutbuf。实际的帧数据(如果有)。或者如果跳过解析则输入缓冲区。
  • poutbuf_size。实际帧数据的大小(如果有),或输入缓冲区大小(如果跳过解析)。

一个不太明显的事情是,这个解析器函数将重用指针变量 bufbuf_size,但这些更改不会离开函数(按值传递)等等)。

Also a brief explanation for the above code will be anyone who is referring to the post.

  • PARSER_FLAG_COMPLETE_FRAMES 如今本质上意味着“不需要实际解析”(请参阅​​ libavformat/utils.c 了解如何设置)。因此,如果指定了该标志,只需设置 `output = input 并返回完整缓冲区大小作为下一个偏移量。
  • 如果未设置该标志,解析器将尝试查找帧结尾 (ff_h263_find_frame_end(pc, buf, buf_size))
  • 接下来,它将缓冲数据到找到的末尾,或者如果未找到末尾,则缓冲整个数据(“ff_combine_frame”)。

    • 如果帧仍然不完整(未找到帧结尾),该函数会将输出缓冲区和大小设置为 0,表明此调用未产生完整的帧,并返回下一个偏移量。数据仍被缓冲,以便该帧可以在后续调用中完成。
    • 如果无法组合帧,例如由于内存不足的情况,ff_combine_frame 将删除缓冲的数据(和帧),并返回空缓冲区和 buf_size 下一个偏移量。
  • 此时我们要么有一个完整的帧(或完全跳过解析),所以将输出缓冲区设置为帧缓冲区(和大小)并返回计算出的偏移量(要么是帧结尾,要么是整个帧)未解析时缓冲)。

那些*_parse例程几乎看起来都一样并且工作在相同的 IIRC 上。

关于c - FFMPEG:视频解码器解析器的工作原理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20343821/

相关文章:

c - 有符号无符号减法

c - 如何在 C 中的 8 皇后程序的二维数组上放置一个字符

perl - 如何在 Perl WWW::Mechanize 中处理一个简单的循环?

Swift 合并 .ts 或 mpeg 文件

android - 全屏播放视频

c - 使用 memset() 将动态分配的结构初始化为全 0 是一个好习惯吗?如果是,有什么好处?

c - 虚函数==函数指针?

json - 使用 SAS BASE 解析来自 JSON 的变量中带有 unicode 字符的表

python - 无效的日期解析器

css - 在 div 内移动视频