我正在使用concat.txt
如下文件:
ffconcat version 1.0
file 000001.png #13-24 0.433767-0.834167
duration 0.4004
file 000002.png #25-35 0.834167-1.2012
duration 0.367033
file 000003.png
...
以及以下命令行:
ffmpeg -i input.VOB -itsoffset 0.433767 -i concat.txt -filter_complex "[0]overlay=eof_action=pass,showinfo;[1]showinfo" -c:a copy output.VOB
这是使用 concat 文件的图像序列叠加。
这是我的 FFmpeg 版本:
ffmpeg version 4.4.1 Copyright (c) 2000-2021 the FFmpeg developers
我遇到的问题是我希望覆盖具有帧精度:第一张图像应覆盖第 13-24 帧,第二张图像应覆盖第 25-35 帧,等等。
我有每一帧的精确信息pts_time
(来自 showinfo),并相应地设置了持续时间,但无法让覆盖在所需的帧开始/结束(通过调整持续时间,我只能管理一帧太早,或者一帧太晚)。
showinfo 输出给出了提示:
[Parsed_showinfo_1 @ 0x564719ed1600] config in time_base: 1/90000, frame_rate: 30000/1001
[Parsed_showinfo_1 @ 0x564719ed1600] config out time_base: 0/0, frame_rate: 0/0
[Parsed_showinfo_2 @ 0x564719ed1dc0] config in time_base: 1/25, frame_rate: 25/1
[Parsed_showinfo_2 @ 0x564719ed1dc0] config out time_base: 0/0, frame_rate: 0/0
[Parsed_showinfo_2 @ 0x564719ed1dc0] n: 0 pts: 11 pts_time:0.44 pos: 0 fmt:rgb24 sar:8/9 s:720x480 i:P iskey:1 type:I checksum:F8CA2959 plane_checksum:[F8CA2959] mean:[63] stdev:[35.9]
视频(input.VOB)为 29.97fps 流,而叠加层设置为默认 25fps。
由于持续时间是手动设置的,我认为这frame_rate
不是实际问题,而是time_base
旁边是:1/25。叠加流中的第一幅图像的开始时间 (0.433767) 四舍五入到最接近的 1/25 (0.44),晚了一帧。其他图像也出现了同样的情况:
[Parsed_showinfo_1 @ 0x55c01673f600] n: 24 pts: 72072 pts_time:0.8008 pos: 301070 fmt:yuv420p sar:8/9 s:720x480 i:P iskey:1 type:I checksum:44EFD0BE plane_checksum:[17B5BDB9 3C4A8674 83098C82] mean:[67 138 118] stdev:[26.4 5.6 3.1]
[Parsed_showinfo_1 @ 0x55c01673f600] n: 25 pts: 75075 pts_time:0.834167 pos: 313358 fmt:yuv420p sar:8/9 s:720x480 i:P iskey:0 type:P checksum:44EFD0BE plane_checksum:[17B5BDB9 3C4A8674 83098C82] mean:[67 138 118] stdev:[26.4 5.6 3.1]
[Parsed_showinfo_2 @ 0x55c01673f600] n: 1 pts: 21 pts_time:0.84 pos: 0 fmt:rgb24 sar:8/9 s:720x480 i:P iskey:1 type:I checksum:C47D9BDA plane_checksum:[C47D9BDA] mean:[63] stdev:[36.3]
[Parsed_showinfo_1 @ 0x55c01673f600] n: 26 pts: 78078 pts_time:0.867533 pos: 315406 fmt:yuv420p sar:8/9 s:720x480 i:P iskey:0 type:P checksum:29E90C18 plane_checksum:[A845EC05 E0C99215 FFD58DE0] mean:[67 138 118] stdev:[26.6 5.8 3.3]
...
[Parsed_showinfo_1 @ 0x55c01673f600] n: 35 pts: 105105 pts_time:1.16783 pos: 354318 fmt:yuv420p sar:8/9 s:720x480 i:P iskey:0 type:P checksum:29E90C18 plane_checksum:[A845EC05 E0C99215 FFD58DE0] mean:[67 138 118] stdev:[26.6 5.8 3.3]
[Parsed_showinfo_2 @ 0x55c01673f600] n: 2 pts: 30 pts_time:1.2 pos: 0 fmt:rgb24 sar:8/9 s:720x480 i:P iskey:1 type:I checksum:7A31E90F plane_checksum:[7A31E90F] mean:[64] stdev:[36.7]
[Parsed_showinfo_1 @ 0x55c01673f600] n: 36 pts: 108108 pts_time:1.2012 pos: 358414 fmt:yuv420p sar:8/9 s:720x480 i:P iskey:1 type:I checksum:6A1DCE13 plane_checksum:[DC94840F 6D0ED2E5 F82E7710] mean:[69 138 118] stdev:[27.0 5.8 3.3]
四舍五入到最接近的 1/25。我尝试添加[1]settb=expr=1/90000
,这导致 time_base 与输入视频匹配,如预期的那样,但对pts_time
覆盖的粒度没有影响(但请注意pts
从 11 变为 39600 的方式):
[Parsed_showinfo_1 @ 0x55ffb8a06940] config in time_base: 1/90000, frame_rate: 30000/1001
[Parsed_showinfo_1 @ 0x55ffb8a06940] config out time_base: 0/0, frame_rate: 0/0
[Parsed_showinfo_3 @ 0x55ffb8a07780] config in time_base: 1/90000, frame_rate: 25/1
[Parsed_showinfo_3 @ 0x55ffb8a07780] config out time_base: 0/0, frame_rate: 0/0
[Parsed_showinfo_3 @ 0x55ffb8a07780] n: 0 pts: 39600 pts_time:0.44 pos: 0 fmt:rgb24 sar:8/9 s:720x480 i:P iskey:1 type:I checksum:F8CA2959 plane_checksum:[F8CA2959] mean:[63] stdev:[35.9]
后续图片也是同样的情况。不知道接下来该怎么做。
使用连接文件在图像叠加中可以获得大于 1/25 秒的粒度吗?
答案1
有一个方法可以解决此限制。
问题是什么?
正如所提到的一个答案由 ffmpeg 的一位开发人员编写,concat 图像序列帧速率是硬编码的:
... 每幅图像的默认帧速率为 25 fps。目前无法更改。
我通过运行确认了这一点:
ffmpeg -i concat.txt -vf fps=250,showinfo concat.mkv
即使输出中可用的粒度为 1/250,帧持续时间也会四舍五入到最接近的 1/25=0.04 秒:
[Parsed_showinfo_1 @ 0xd00b60] config in time_base: 1/250, frame_rate: 250/1
有什么解决方法?
可以将连接文件的持续时间乘以某个将粒度保持在 25fps 以上的因子,然后在生成覆盖时将相同的因子除以 4。
一个方便使用的因素是时间尺度。将时间戳乘以时间刻度,我们得到...它们各自的pts
值,所以我们可以直接使用这些值。由于pts
值是整数,因此也可以安全地将它们除以 25。使用上面的示例 concat 文件,我们得到:
ffconcat version 1.0
file 000001.png #13-24 0.433767-0.834167
duration 1441.44 # 0.4004 * 90000 = 36036 (pts) /25
file 000002.png #25-35 0.834167-1.2012
duration 1321.32 # 0.367033 * 90000 = 33033 (pts) /25
file 000003.png #36
...
然后覆盖命令将是:
ffmpeg -i input.VOB -i concat.txt -filter_complex "[1]settb=1/90000,setpts=39039+PTS*25/90000[o];[0:v:0][o]overlay=eof_action=pass" -c:a copy -vsync passthrough output.VOB
请注意,-itsoffset
已经移至过滤器(0.433767s pts=39039),然后通过分解时间尺度以及我们之前除以的额外 25 来提取精确的时间戳。