如何使用 ffmpeg 精确切割帧?

cur*_*mil 43 ffmpeg command-line video-editing video-conversion

我正在尝试使用 ffmpeg 在精确的时间剪切视频文件。ffmpeg 帮助显示了一个选项 -timecode_frame_start 来指定起始帧,但我无法使此命令起作用。生成的视频始终从原始视频的开头开始。这是我正在运行的命令的示例:

ffmpeg -i input.mpg -acodec copy -vcodec copy -timecode_frame_start 200 -vframes 210 -n ouput.mpg
Run Code Online (Sandbox Code Playgroud)

我在其他选项之前和之后移动了 timecode_frame_start 选项,结果没有变化。我需要指定其他选项吗?我尝试了各种文件格式,mkv、avi、mp4,但似乎问题与编解码器无关。这是我试过的一个文件:

http://www.seotter.com/marine/movies/hermit-long-01.mpg

我错过了什么吗?

slh*_*hck 66

timecode_frame_start 不是这样工作的。

无法根据帧号进行查找。从特定帧开始的唯一方法是将多个帧转换为ss.ms语法或hh:mm:ss.ms. 因此,如果您的视频为 25 fps,并且您希望从 133 帧开始,则需要首先计算时间戳:

133 / 25 = 5.32

然后运行:

ffmpeg -ss 5.32 -i input.mp4 -c:v libx264 -c:a aac out.mp4
Run Code Online (Sandbox Code Playgroud)

请注意,使用比特流复制 ( -c:v copy)切割精确帧是不可能的,因为并非所有帧都是帧内编码的(“关键帧”)。视频必须以关键帧开头才能正确解码。因此,您必须使用-c:v libx264如上所示重新编码视频,例如编码为 H.264 。您还可以选择无损编解码器,例如-c:v ffv1保留输入视频的质量。

总而言之,-ss在执行重新编码时将始终保持帧准确。

如果您还想对特定数量的帧进行编码,请使用-frames:v,例如:

ffmpeg -ss 5.32 -i input.mp4 -c:v libx264 -c:a aac -frames:v 60 out.mp4
Run Code Online (Sandbox Code Playgroud)

请注意,您还可以选择使用select/aselect过滤器来选择帧/音频样本。

ffmpeg -i input.mp4 -vf 'select=gte(n\,100)' -c:v libx264 -c:a aac out.mp4
Run Code Online (Sandbox Code Playgroud)

但是,这比-ss上面显示的选项慢,因为将解码整个视频。

  • 对于超过 10 分钟的丢帧(例如 29.97fps)视频;您将如何准确计算特定帧的时间? (6认同)
  • `select=gte(n\,100)` 方法有效,但查找会消耗性能。如果您一次只编码 30 帧进行测试,我开始的视频越深入,由于查找,ffmpeg 完成所需的时间就越长。 (2认同)
  • @t-mart 添加 `-shortest` 以使其在最短流完成时停止编码(即您的情况下的视频流)。 (2认同)

小智 12

选项

-vf select="between(n\,start_frame_num\,end_frame_num),setpts=PTS-STARTPTS"
Run Code Online (Sandbox Code Playgroud)

例如,

-vf select="between(n\,200\,300),setpts=PTS-STARTPTS"
Run Code Online (Sandbox Code Playgroud)

将视频从(包括)第 200 帧剪切到(包括)第 300 帧,序列计数从 0 开始。

  • `setpts=PTS-STARTPTS` 的作用是什么? (2认同)

小智 5

LosslessCut是一个跨平台 GUI 工具,使用 FFmpeg 作为后端,无损剪切视频。您可以选择在关键帧或任意帧处进行剪切。

  • 我认为情况并非如此。[LosslessCut 的自述文件](https://github.com/mifi/lossless-cut#known-issues--limitations) 指出它舍入到最近的关键帧。 (2认同)