FFmpeg:根据时间戳列表从视频中提取几个单独的帧?

FFmpeg:根据时间戳列表从视频中提取几个单独的帧?

假设我有一个时间戳列表,例如1.4,,,等等5.610.5

对于每个时间戳,我想提取最近的帧并将其保存到 jpeg 文件中。

我可以一次完成一帧:

ffmpeg -i video.mp4 -ss 1.4 -frames 1 frame_1_4.jpg
ffmpeg -i video.mp4 -ss 5.6 -frames 1 frame_5_6.jpg
ffmpeg -i video.mp4 -ss 10.5 -frames 1 frame_10_5.jpg
...

这种方法的问题在于它似乎会占用大量资源,原因如下:反复运行 ffmpeg 会产生进程开销,并且如果视频有较远的关键帧(或者在最坏的情况下根本没有关键帧),那么解码器必须在每次调用时解码多个帧。如果假设最坏的情况(没有可用的关键帧),那么提取帧的最有效方法是解码一次流并在出现每个帧时将其提取出来。对于只有三帧的情况可能还不错,但如果我想提取 100 或 200 或更多帧的列表,即使对于具有良好关键帧的文件,它也会很快变得难以处理。

一个非常基本的测试表明,对于一个 5 分钟长的测试文件,每 5 秒有一个关键帧,每次调用ffmpeg平均需要大约 0.22 秒才能运行,最快的是 0.11 秒,最慢的是 0.34 秒。同一个文件只需 6 秒就可以解码为空。因此,如果我想从这个文件中获取 40 帧,我最多需要等待 12 秒,而整个文件的解码时间是这个时间的一半。这告诉我很多开销只是在ffmpeg初始化、打开文件等。

一种非常简单的方法可能是将所有帧提取到磁盘,然后挑选所需的帧。当然,这比多次运行 ffmpeg 还要慢,因为 JPEG 编码器会反复运行,所需的磁盘空间很快就会变得非常大。

是否存在一个vf select或相关的过滤器,可以选择出我提供的特定时间戳列表并仅提取那些帧?

(需要澄清的是,带有时间戳的文件名不必由 ffmpeg 生成;只需连续的数字就可以了,因为调用应用程序/脚本可以根据相同的时间戳列表重命名文件本身)

答案1

如果您可以将时间戳转换为帧号 - 即100, 184, 213- 那么您可以执行以下操作:

ffmpeg -i video.mp4 -vf select='eq(n\,100)+eq(n\,184)+eq(n\,213)' -vsync 0 frame_%d.jpg

-vsync 0(获得正确的帧似乎很重要)

并且它需要一些脚本来获取列表并生成字符串select=

脚本甚至可以获取时间戳和 FPS 来计算帧数。


根据以下问题Stack Overflowshell - 使用 ffmpeg 提取特定帧的列表


最终我会使用Python和模块cv( ),因为它可以从视频文件(或网络摄像头或流)中OpenCV逐帧读取(可能使用)并将帧保存为图像。ffmpeg


编辑:

文档选择表明您可以使用变量,t因此timestamp
也许它可以直接与1.4, 5.6,一起使用10.5

ffmpeg -i video.mp4 -vf select='eq(t\,1.4)+eq(t\,5.6)+eq(t\,10.5)' -vsync 0 frame_%d.jpg

相关内容