我似乎对 PTS (显示时间戳) 的理解是,它总是以 time_base 的整数单位进行编码,time_base 是秒数的一小部分。我们有关系time=PTS*time_base
。
相反,我们有帧索引,通常在过滤器表达式变量中标记为“N”或“POS”。当我们假设帧速率恒定时,我们通常会利用关系N=time*frame_rate=PTS*time_base*frame_rate
。
这是我们几乎在 ffmpeg 中随处可见的,尤其是在 FFPROBE 和 showinfo 过滤器的输出以及 setpts 过滤器的变量中。所有上述模块都对 time、pts、n、position、frame_rate、time_base 进行了明确的区分和命名。
好吧,我承认 drawtext 过滤器会在我们访问“pts”函数时打印时间,但我认为这是一个非常糟糕的名字。
然后我尝试使用如下命令来提取所有帧,并尝试使用 image2 muxer 的文件名输出中的帧 PTS 来识别它们,以便轻松地将它们与 FFPROBE 的输出进行比较。SS 跳过第一秒,因此我们可以确认它不是从零开始的索引,copyts 保留源时间戳,vsync=0 保证我们在源帧的时间准确输出帧,而不会丢失或重复任何帧。
ffmpeg -ss 1 -copyts -i input.mp4 -vsync 0 -f image2 -frame_pts 1 output_%05d.jpg
当我对一个帧速率为 25 fps、时间基数为 1/12800 秒的文件使用此命令并像上面一样跳过第一秒时,第一个文件是“output_025.jpg”,而 ffprobe 显示时间 1 秒是 12800 PTS。这证实了这一点PTS=N/frame_rate/time_base=25/25*12800=12800
。对于任何探测的帧,计算方法都相同,只是 PTS、时间和位置/索引的设置不同。
我们应该期望-FRAME_PTS
生成一个 PTS,但我们得到的却是文件名中的帧索引。
文档中也明确写出了这一点。
- 在 ffmpeg 图像合并器文档中:
frame_pts If set to 1, expand the filename with pts from pkt->pts. Default value is 0.
- 在 AVPacket 结构参考中:
int64_t pts Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will be presented to the user.
为什么 image2 muxer-frame_pts
如此不连贯?是不是因为它的名字不好,还是因为它的行为不正确?我是不是误解了什么?
是否有技巧可以在文件名中获取 PTS ?我不需要帮助来使用外部工具来解析和重命名输出,但我宁愿使用更简单的方法。
到目前为止,我只找到了 Gyan 的这个解决方法和另一个令人困惑的答案。Gyanhttps://superuser.com/a/1421195/549957 超级新手AU4000https://superuser.com/a/1479491/549957
上面链接的 Gyan 答案让我遇到了麻烦
- 理解为什么
-r
选项不会发生-vsync 0
严重矛盾,尽管文档中的说法完全相反,-r 选项可以复制/删除帧,而 vsync 0 选项可以禁用它- tldr 为什么当我增加 -r 时我没有得到额外的帧图像,是因为 vsync 0 吗?
- 使用输出帧速率来伪造 PTS 代替索引的一般规则是什么?
- Gyan 写了关于设置 -r 1000 来写毫秒这样的数字,但我想要一个 PTS
- 我认为我可以使用 time_base 的乘法逆元作为 -r 帧速率来欺骗索引以反映 PTS,但我不确定它是否能在任何地方一致地起作用
答案1
默认情况下,image2 多路复用器将设置输出流是输出帧速率的倒数。这就是我设置-r 1000
的原因-vsync 0
,以获得相当于毫秒值的索引。
为了保持输入流的时间基准,添加-enc_time_base -1
为输出选项。