如何用ffmpeg提取当前显示的帧?

如何用ffmpeg提取当前显示的帧?

我正在对一段以每秒 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

我们可以验证我们在 6.0 秒时捕获了帧:
在此处输入图片描述


使用可变帧速率进行测试(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)进行了测试。

相关内容