我正在对一段以每秒 1 帧的速度播放的 10 秒视频进行测试。我的目标是捕获特定帧作为快照。目前,我为此使用以下 ffmpeg 命令:
ffmpeg -y -ss 6.3 -i input.mp4 -frames:v 1 -q:v 1 output.png
我想提取视频播放器中 6.3 秒处显示的帧。但是,我使用的命令却给出了 7.0 秒处的帧。有没有办法准确捕获 6.0 秒处的帧,最好不要对视频的(恒定)帧速率做出假设?
答案1
我们可以应用帧复制,并使用select
过滤器:
ffmpeg -y -ss 5 -i input.mp4 -copyts -vf "fps=10,select=gte(t\,6.3)" -frames:v 1 -update 1 output.png
-ss 5
- 在相关时间前约一秒开始(可选择跳过文件的开头,以节省时间)。-copyts
- 将输入帧的时间戳复制到输出(如果没有它,我们必须减去开始时间:select=gte(t\,6.3-5)
。fps=10
- 将帧速率提高到 10fps 以提高时间精度 - 因为我们要选择 6.3 秒,所以我们需要 0.1 秒的精度。
请注意,这部分并非完全独立于帧速率 - 我们可能会使用它fps=1000
来提高精度。select=gte(t\,6.3)
- 选择所有时间戳超过 6.3 秒的帧。
测试:
构建一个以 1fps 前进计数器的输入视频文件(用于测试):
ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=1:duration=10 input.mp4
执行上述命令:
ffmpeg -y -ss 5 -i input.mp4 -copyts -vf "fps=10,select=gte(t\,6.3)" -frames:v 1 -update 1 output.png
使用可变帧速率进行测试(VFR 视频):
构建具有可变帧率的输入视频文件:
ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=1:duration=10 -fps_mode:v passthrough -vf setpts="N*N/TB" input.mp4
使用 FFprobe 检查时间戳:
ffprobe -of default=noprint_wrappers=1 -show_entries packet=pts_time input.mp4
pts_time=0.000000
pts_time=16.000000
pts_time=4.000000
pts_time=1.000000
pts_time=9.000000
pts_time=25.000000
pts_time=81.000000
pts_time=49.000000
pts_time=36.000000
pts_time=64.000000
10.3 秒处捕获帧:
ffmpeg -y -ss 5 -i input.mp4 -copyts -vf "fps=10,select=gte(t\,10.3)" -frames:v 1 -update 1 output.png
上述解决方案使用 FFmpeg 版本 5.1.2-full_build-www.gyan.dev(带有 Windows 10)进行了测试。