如何使用 FFmpeg 剪切不需要的视频部分并将其余部分合并为一个视频?

J P*_*ack 3 video ffmpeg video-editing

我已经阅读了有关使用concat 进行切割和拼接的文章,但这对我来说还不够。

我想剪切标记的视频部分并加入单个视频文件而无需重新编码。是否可以一次性剪切和合并(在内存中)?

对要剪切或加入的视频部分的数量应该没有理论上的限制。音频应该是同步的。

视频:H.264+AAC

编辑:

从答案中我了解到仍然需要重新编码视频。

我想澄清一下,从视频文件的中间剪切视频剪辑可能需要通过多个步骤来完成。我在想,通过保存一些 I/O 活动,一次性处理视频会提高性能。然而,它本身并不是一个目标。

小智 6

你的问题,如果我没猜错的话,有四个主要部分:

  • 如何从电影中剪切时间段
  • 如何将多个段合并在一起
  • 如何在不转码电影的情况下执行上述操作,从而不损失任何质量
  • 如何在速度方面有效地执行上述操作

切割时间段

您可以通过使用-ss选项跳到起点来剪切线段,然后使用 设置线段的持续时间-t,或使用 设置终点-to

# skip 30 seconds, then copy the next 60 seconds
ffmpeg -ss 30 -t 60 full-movie.mp4 segment.mp4
Run Code Online (Sandbox Code Playgroud)

在 ffmpeg 文档中,请参阅第5.4主要选项,了解将-ss-t选项放置在输入文件之前或输出文件之前的区别。一旦您对此进行试验,您可能会发现这种差异与您的情况相关。

重要提示:以上示例导致视频被转码。我们将在下面讨论在没有转码的情况下执行此操作的可能性。

合并多个段

执行电影合并的主要方法有三种,其中两种在ffmpeg wiki 文章中得到了最好的解释,第三种是concat demuxer。如果您的所有段在 a/v 编码规范和容器格式方面都相同,您可能会发现最简单的方法是concat:协议:

# merge the segments
ffmpeg -i "concat:seg1.mp4|seg2.mp4|seg3.mp4" final.mp4
Run Code Online (Sandbox Code Playgroud)

需要注意的是,这次合并,就像剪辑一样,再次对电影进行转码,所以我们这里有一个转码的转码,可能会降低视频质量,所以我们真的想尽可能地避免这种转码!

无需转码即可剪切和合并

前面部分中的示例需要转码的原因是因为每个文件和每个生成的片段都是一个独立的电影,它被打包以提供您打开完整电影时所期望的所有内容,例如电影的持续时间和其他元数据。但是,嘿,您不希望将这些作为独立电影播放,您希望这些片段成为更大视频流的一部分。因此,与其为 ffmpeg 提供盒装电影,您应该更好地将输入文件重新打包 - 重新复用 - 到实时流媒体容器中,忘记此时您并不真正需要的标题内容。在 H.264 的情况下,流复用格式称为 MPEG-TS,以下是您重新复用流而不进行转码的方法:

# re-muxing the whole movie (see a better option in next example)
ffmpeg -i full-movie.mp4 -c:v copy -c:a copy -bsf:v h264_mp4toannexb full-movies-as-ts.ts
Run Code Online (Sandbox Code Playgroud)

好吧,既然你已经开始了,你不妨利用这个机会来削减你需要的部分:

# skip 30 seconds and re-mux a 60 seconds segment
ffmpeg -ss 30 -t 60 -i full-movie.mp4 -c:v copy -c:a copy -bsf:v h264_mp4toannexb segment.ts
Run Code Online (Sandbox Code Playgroud)

当您合并 TS 段时,您还可以重新复用回 mp4 容器:

# merge the segments and re-mux them as mp4
ffmpeg -i "concat:seg1.ts|seg2.ts|seg3.ts" -c:v copy -c:a copy -movflags empty_moov -flags global_header -bsf:v dump_extra edited-final.mp4
Run Code Online (Sandbox Code Playgroud)

所以现在我们完成了整个过程,无需对电影进行转码,保留了原始质量。但与往常一样,有一个警告......

CAVEAT:只能在关键帧边界上进行切割。说明:H.264 以数据包的形式组织压缩帧,每个帧都从第一帧的完整压缩图像开始,然后是后续帧的增量,从而减少每个数据包所需的存储空间。就我们的目的而言,每个数据包就像是该时间段内所有帧的密封拉链 - 要么全部要么没有。如果您只想要一个数据包,那么您必须将其解压缩并重新压缩,换句话说 - 对其进行转码。因此,仅当您要剪切电影的每个位置都有一个关键帧时,上述方法才相关。例如,如果您每 5 秒有一个关键帧,则只能每 5 秒剪切一次。

所以现在的问题是您是否可以接受对剪切点的限制,特别是因为您可能不知道您的电影中的哪个位置有关键帧。这就是我上面建议在5.4 Main Options 中阅读有关指定-s-t输入之前或输出之前的原因。如果您在输入之前指定,则 ffmpeg 将找到附近的关键帧来执行您的请求,这将是您想要执行剪切的“或多或少”。如果您不介意切割的精确度,那很好,那就去做吧。

但是,如果您需要剪辑在那个精确的位置,那么您别无选择,您必须解码电影以精确定位您正在寻找的帧。好吧,至少我们有一些好消息:您可以使用单个转码代替转码和重新转码,这在一定程度上改善了这种情况:

# skip PRECISELY 30 seconds and transcode a 60 seconds TS segment
ffmpeg -i full-movie.mp4 -ss 30 -t 60 -bsf:v h264_mp4toannexb segment.ts
Run Code Online (Sandbox Code Playgroud)

由于生成的片段将在 TS 中,因此在将片段合并在一起时不需要另一个转码。

速度

关于合并ffmpeg wiki 文章中,解释了如何通过管道运行整个过程,从而消除对中间文件的需求并加快整个过程。别。你会花更长的时间. 在内存中完成所有工作需要更长时间的原因不是因为它会运行更长时间,而是因为在弄清楚如何完成整个事情时将没有中间结果,并且您会发现自己再次运行整个过程并且再次。所以管道理论是好的,但在你的情况下,你应该从制定和完善每一步开始。你会发现让一切正常工作并产生一个不错的结果需要更多的调整和调整。一旦您掌握了整个过程并希望为自动批量编辑编写一些脚本,那么您就可以重新审视管道概念。

希望以上有帮助。