我注意到,ffmpeg-t
在 M2TS 输入上使用时有时会写入无效的 PTS 时间戳。这是我的错误还是 ffmpeg 中的错误?
重现步骤:
下载此 M2TS 文件并将其另存为1.m2ts
。此文件包含一个视频流25 fps
(即一个视频帧正好占用0.04 s
(40 ms
))和一个音频流(对于本文的目的而言,该音频流并不重要)。
打开终端,导航到包含该文件的目录,然后执行以下命令:
ffmpeg.exe -i 1.m2ts -codec copy -map 0 -t 2 2.m2ts
现在检查输出文件,,2.m2ts
并观察到最新视频帧的 PTS 是3.560
,并且前一个视频帧的 PTS 是3.480
。
这显然是错误的。在 处的帧之后3.480
,下一帧应该出现在 处3.520
,而不是 处3.560
。要么是 ffmpeg 丢弃了应该出现在 处的视频帧,要么是它向最后一个视频帧(而不是)3.520
写入了错误的 PTS 。3.560
3.520
当然,当谈到“最后”或“之前”时,我指的是时间上的帧顺序(更准确地说,我已经按 PTS 排列了视频帧),而不是文件中帧的顺序。
问题:
这是ffmpeg的一个bug,还是我上面的命令有错误?
ffmpeg 版本:
ffmpeg version 2024-01-14-git-34a47b97de-full_build-www.gyan.dev
在 Windows 10 x64 企业版上
进一步说明:
我注意到我的几个 M2TS 文件有问题;我没有时间测试其他格式。不幸的是,我无法提供我的文件供下载。这就是我链接到另一个文件的原因。
换句话说:问题并不只存在于我链接的文件中。相反,我在不同来源的各种 M2TS 文件中遇到过各种视频帧速率和音轨的问题。
我还没有调查过与类似差距有关的音轨。
答案1
这不是一个错误,只是 B 帧依赖的结果。
视频流有 3 种类型的帧:
- I-Frame-不依赖于任何帧。
- P 帧 - 仅依赖于它之前的帧。
- B 帧 - 依赖于编码帧之前的帧和之后的帧。
最后一个与 2 秒持续时间相匹配的编码视频帧是B 帧。2.m2ts
中的第一帧有pts_time=1.48
。2.m2ts
中的最后一帧应该有pts_time=3.48
。
由于 为pts_time=3.48
B 帧,因此它依赖于在其后编码的 P 帧。
后面的 P 帧具有pts_time=3.56
。
没有该 P 帧,就无法解码 B 帧,因此复用器会保留最后一个额外的 P 帧。
使用 FFprobe 分析视频帧:
我们可以使用 FFprobe 来获取这两个文件的视频流的 pts_time 和 pict_type。
ffprobe -select_streams v -of default=noprint_wrappers=1:nokey=1 -show_entries frame=pts_time,pict_type 1.m2ts > 1.txt
ffprobe -select_streams v -of default=noprint_wrappers=1:nokey=1 -show_entries frame=pts_time,pict_type 2.m2ts > 2.txt
使用比较工具比较文件,得到以下结果:
1.txt 2.txt
------ ------
1.480000 1.480000
I I
...
B B
3.040000 3.040000
B B
3.080000 3.080000
P P
3.120000 3.120000
B B
3.160000 3.160000
B B
3.200000 3.200000
B B
3.240000 3.240000
P P
3.280000 3.280000
B B
3.320000 3.320000
B B
3.360000 3.360000
B B
3.400000 3.400000
P P
3.440000 3.440000
B B
3.480000 3.480000
B B
3.520000
B
3.560000 3.560000
P P
pts_time=3.52
请注意,解码不需要B 帧3.48
(3.48
依赖于3.56
P 帧但不依赖于3.52
B 帧),因此3.52
被跳过。