FrameSync帧同步—参数

作者:罗上文,微信:Loken1,公众号:FFmpeg弦外之音

FrameSync 里面有 3 个参数来满足不同的同步需求,如下:

1-1

本文我们来研究一下这些参数的功能在代码里是如何实现的。


eof_action 参数

eof_action 参数的作用是定义 第二个流结束时候 的处理逻辑,它有 3 个值。

  1. repeat,重复上一帧的数据,也就是第二个流结束之后,后面一直用最后一帧来跟第一个流的帧进行 overlay 操作。
  2. endall,结束滤波处理,当第二个流结束的时候,overlay 滤波处理就要立即结束。
  3. pass,跳过滤波处理,也就是当第二个流结束的时候,后面不再进行 overlay 滤波操作了,直接把 main 帧传递给下一级 滤镜处理。

其实 这些参数的功能都是通过两个字段来实现的,分别是 FFFrameSyncIn::beforeFFFrameSyncIn::after

FFFrameSyncIn::before 代表输入流开始前的操作,FFFrameSyncIn::after 代表输入流结束后的操作。

其实 beforeafter 这两个字段有些值我也不太懂,我没有找到对应的命令来演示某些值的功能,所以我只讲我懂的那部分。


eof_action 等于 repeat 的时候,第二个流的 FFFrameSyncIn::after 就是 EXT_INFINITY,这也是默认值。是在初始化的时候赋值的,如下:

1-2

当第二个流结束的时候,consume_from_fifos() 函数就从第二个流里面读不到 AVFrame 了,他就会跑到 framesync_inject_status() 里面,如下:

1-3

framesync_inject_status() 里面发现 afterEXT_INFINITY 的时候,它就会把 第二个流的 pts_next 设为最大值 INT64_MAX

这样后面在 framesync_advance() 循环的时候,第一个流的 pts_next 总是最小的了。这样第二个流就不会把 frame_next 移到 frame 里,一直使用的都是最后一帧数据来进行 overlay 操作。


eof_action 等于 endall ,其实就是 opt_shortest 等于 1,这两个参数实现的是同一个功能,你可以理解为别名。代码如下:

1-4

也就是说下面两条命令是等价的。

ffmpeg -eof_action endall ...省略...
ffmpeg -shortest ...省略...

opt_shortest 等于 1 的时候,他就会把所有输入流FFFrameSyncIn::after 设置为 EXT_STOP,如下:

if (fs->opt_shortest) {
    for (i = 0; i < fs->nb_in; i++)
        fs->in[i].after = EXT_STOP;
}

然后在 framesync_advance() 里面,当某个输入流结束了,也就是 state 等于 STATE_EOF,就会执行 framesync_eof(),如下:

1-5

framesync_eof() 里面的重点是 设置了下级 AVFIlterLink 的状态为 AVERROR_EOF,如下:

ff_outlink_set_status(fs->parent->outputs[0], AVERROR_EOF, AV_NOPTS_VALUE);

这实际上是把 overlay 滤波输出的状态设置为 AVERROR_EOF,但是并不代表整个 Graph 的滤波处理都要结束,只是 overlay 这个环节结束了。

因为有些命令可能比较复杂,他可能有一个跟 overlay 同级的滤镜Y,如下:

1-6

endall 这个参数他结束的只是他对应的滤镜的滤波处理,并不是整个 Graph 的滤波处理。

如上图,虽然 overlay 结束了,但是滤镜 Y 还没结束,Y 还可以继续传递数据给 滤镜 Z 进行滤波处理。


eof_action 等于 pass 的时候,其实就是 opt_repeatlast 等于 0,这两个参数实现的是同一个功能,你可以理解为别名。代码如下:

1-7

也就是说下面两条命令是等价的。

ffmpeg -eof_action pass ...省略...
ffmpeg -norepeatlast ...省略...

opt_repeatlast 等于 0 的时候,他就会把所有输入流FFFrameSyncIn::after 设置为 EXT_NULL,如下:

if (!fs->opt_repeatlast) {
    for (i = 1; i < fs->nb_in; i++) {
        fs->in[i].after = EXT_NULL;
        fs->in[i].sync  = 0;
    }
}

EXT_NULL 代表其余的流可以在缺少了该流的情况下执行滤波处理。

framesync_inject_status() 里面发现 afterEXT_NULL 的时候,它就不会把 第二个流的 pts_next 设为最大值 INT64_MAX

这样会导致第二个流的 FFFrameSyncIn::frame 后面被清空,再导致后面再 do_blend() 里面拿不到第二帧数据,然后就会直接传递 mainpic 帧给下一级的滤镜。

1-8

这就是 eof_action 等于 pass 的代码实现逻辑。


其实 overlay.c 里面也有跟 framesync.c 一样的参数,如下:

1-9

虽然 FrameSync 帧同步在其他滤镜里面也有使用,例如:vf_alphamerge.cvf_bm3d.cvf_displace.c 等等。

但是我看了一下,只有 overlay.ceof_actionshortestrepeatlast 这些帧同步参数,其他滤镜是没有的,无法配置这些参数的。

所以我个人认为这 3 个参数,是 overlay 滤镜专属的。


FFmpeg书籍版权所属@罗上文 2025 all right reserved,powered by Gitbook该文件修订时间: 2026-08-14 15:25:19

results matching ""

    No results matching ""