FFmpeg命令行参数分析-re—ffmpeg.c源码分析
作者:罗上文,微信:Loken1,公众号:FFmpeg弦外之音
re
的全称是 rate emulator(速率模拟),可以用这个选项来模拟输入的速度。因为 ffmpeg.exe
默认情况下是尽量以最快的速度来读取输入数据,具体多快,取决于 CPU 的性能。
下面这条命令就是未使用 -re
的场景,可以看到,速度是 5 倍速。
ffmpeg.exe -i juren.mp4 juren.flv
现在我们加上 -re
选项之后的效果如下:
ffmpeg.exe -re -i juren.mp4 juren.flv
可以看到加上 -re
选项之后,处理速度变成了一倍速。
一倍速意味着什么呢?
它意味着处理完 2小时的视频,就需要 2小时。从另一个角度来解释,如果这个视频是 1 秒 24 帧的视频,那就是 ffmpeg.exe
会每隔 40 毫秒从输入文件读取一个 AVPacket
进行处理。
如果你不加 -re
,ffmpeg.exe
处理完一个 AVPacket
就会立即去读下一个 AVPacket
,它不会等够 40 毫秒。
-re
在推直播流的时候非常有用,当你需要将一个 mp4
推送到 rtmp
服务器,基本都会加上 -re
来模拟摄像头采集画面的速度。
下面就让我们来学习一下在 ffmpeg.c
里面是怎么实现 -re
模拟速率的功能的。
-re
的定义如下:
{ "re", OPT_BOOL | OPT_EXPERT | OPT_OFFSET | OPT_INPUT, { .off = OFFSET(rate_emu) },
.off = OFFSET(rate_emu)
这句代码是重点,代表这个 -re
会赋值给 OptionsContext
结构里面的 rate_emu
字段,由于 -re
是 OPT_BOOL
(布尔类型),所以 OptionsContext::rate_emu
会被设置为 1。
rate_emu
字段在哪里被使用呢?
如下:
在 ffmpeg_opt.c
的 open_input_file()
函数里把 OptionsContext
里面的 rate_emu
赋值给了 InputFile
的 rate_emu
。
然后,如果 InputFile
的 rate_emu
被设置为 1,会导致 input_streams
的 start
字段被设置,如下:
input_streams
的 start
字段字段代表什么意思呢?
它代表什么时候开始读取 AVPacket。
然后在 get_input_packet
获取 AVPacket
的时候,就会根据这个 start
字段,计算当前任务已经运行了多久,跟 input_streams
的 dts 字段进行比较,如果 运行时间小于 input_streams
的 dts
,就会返回 EAGAIN
,如下:
input_streams
的 dts
是什么意思?
它记录的是最后一个从输入文件读取出来的 AVPacket
的 dts,如下:
这几个时间变量如果细细研究,是有点绕的。不过也可以不用细究。我举个简单的例子,例如现在 ffmpeg.exe
启动了 80 毫秒,他已经读到了第 3 帧视频,第三帧的视频的 dts
是 120 毫秒。
所以,此时此刻,上图中的 now
就等于 80 毫秒,而 pts
就 等于 120 毫秒,代码如下:
for (i = 0; i < f->nb_streams; i++) {
InputStream *ist = input_streams[f->ist_index + i];
int64_t pts = av_rescale(ist->dts, 1000000, AV_TIME_BASE);
int64_t now = av_gettime_relative() - ist->start;
if (120 > 80)
return AVERROR(EAGAIN);
}
120 大于 80,所以就会返回 EAGAIN
,继续等待。当 ffmpeg.exe
运行足够久了,now
就会变成大于 120 的值,就会继续去读 AVPacket
进行处理。
不过需要注意的是,他上面这段代码,是遍历一个输入文件里面的所有流的,也就是音频流,视频流,都会做速率模拟。只要有其中一个流不符合速度,就会返回 EAGAIN
通常情况下,音频流的速度是采样率决定的,视频流的速度是帧率决定的。
感谢 NETINT(镕铭微电子) 赞助《FFmpeg原理》免费版一书的服务器费用,下面是 VPU 产品介绍