ffmpeg - 从视频中提取精确的帧数

ffmpeg - extract exact number of frames from video

我想从一个视频中创建最多 30 张图像(并将它们拼贴为精灵 sheet)。

我试过将 'select' 与 'mod' 一起使用,但如果总帧数不能完全适合所需的图像数量 (30),那么我有时会得到更多图像, 有时更少。

例如,如果我的视频是 72 帧长,我的 'mod' 将是 72 / 30,即 2.4。

我是 运行 来自 python 脚本的,所以我正在为过滤器执行类似以下操作:

select='not(mod(n\," + str(mod) + "))'

我认为 mod 必须是一个整数(?)所以我可以向下舍入并使用 2 得到 36 张图片,或者向上舍入得到 24 张图片

准确获得 30 的最佳方法是什么? - 显然间隔不会相同,但没关系。

也许我可以使用 for 循环生成最接近所需间隔的帧列表,然后将其作为 select 过滤器传递?

例如要获得帧,我会做这样的事情:

nframes = 72 # number of frames in video
outImages = 30 # number of images I want
mod = float(nframes) / outImages # 2.4

frames = []

idx = 1

while i < nframes:
    print str(idx) + ": " + str(math.floor(i+0.5)) 
    frames.append(int(math.floor(i+0.5)))
    idx += 1
    i += mod

然后我可以将它(帧列表)传递给 ffmpeg 命令吗?或者我可以告诉 ffmpeg 做类似的事情吗?

如果你有帧列表,你可以 运行

ffmpeg -i in.mp4 -vf select='eq(n,5)+eq(n,11)+eq(n,15)..' -vsync 0 frames%d.jpg

如果您可以将频率分解为有理数(并做一些数学运算),则可以使用 select 过滤器直接执行此操作。

我们取 f = 2.412/5 相同。所以这意味着你需要每 12 帧中的 5 帧。你可以将其分解为 3 中的 1 + 12 中的 1。因为在这种情况下,后者将与前者重合 selection,我们可以选择一个较早的帧,即每 12 帧的第 11 帧。

ffmpeg -i in.mp4 -vf select='not(mod(n,3))+not(mod(n+1,12))' -vsync 0 frames%d.jpg

这个想法是将您的频率表示为倒数之和,1/f = 1/m + 1/n + 1/p。如果其中一个分母是其他分母的倍数,则可以使用偏移设备 n+cn-c


更粗略的方法是

ffmpeg -i in.mp4 -vf select='not(mod(n,12))+not(mod(n+3,12))+not(mod(n+5,12))+not(mod(n+7,12))+not(mod(n+11,12))` -vsync 0 frames%d.jpg

其中 select 个子句的总数等于每组 X 帧所需的帧数。


无论如何,你可以通过添加-vframes 30

来粗略地限制总帧数