我读过关于使用连接但这对我来说还不够。
我想剪切标记的视频部分并将其合并为单个视频文件而无需重新编码。是否可以一次性进行剪切和合并(在内存中)?
理论上,剪切或合并的视频片段数量应该没有限制。音频应该同步。
视频:H.264+AAC
编辑:
从答案中我了解到仍然需要视频重新编码。
我想澄清的是,从视频文件中间剪切视频片段可能需要多个步骤。我认为一次性处理视频可以节省一些 I/O 活动,从而提高性能。但这本身并不是目标。
答案1
如果我没理解错的话,你的问题主要有四个部分:
- 如何从电影中剪切时间段
- 如何将多个片段合并在一起
- 如何做到上述操作而不转码电影,从而不损失任何质量
- 如何以速度高效地完成上述任务
剪切时间段
您可以使用选项跳到片段的起点来剪切片段-ss
,然后使用 设置片段的持续时间-t
,或使用 设置终点-to
:
# skip 30 seconds, then copy the next 60 seconds
ffmpeg -ss 30 -t 60 full-movie.mp4 segment.mp4
在 ffmpeg 文档中,请参阅部分5.4 主要选项-ss
关于将和选项放在输入文件之前还是输出文件之前的区别-t
。一旦你尝试了这一点,你可能会发现这种区别与你的情况有关。
重要提示:上述示例会导致视频转码。我们将在下面讨论不进行转码的情况下执行此操作的可能性。
合并多个片段
合并电影有三种主要方法,其中两种方法在这里有最好的解释ffmpeg 维基文章,第三个是连接解复用器。如果所有段在 a/v 编码规范和容器格式方面都相同,您可能会发现最简单的方法是协议concat:
:
# merge the segments
ffmpeg -i "concat:seg1.mp4|seg2.mp4|seg3.mp4" final.mp4
值得注意的是,这种合并与剪切一样,会再次对电影进行转码,因此我们在这里进行了转码的转码,这可能会降低视频质量,因此我们真的我们希望尽可能避免这种转码!
无需转码即可剪切和合并
前面部分中的示例之所以需要转码,是因为每个文件和每个生成的片段都是一个独立的电影,打包后可以提供打开整部电影时所需的所有内容,例如电影的时长和其他元数据。但是,嘿,您不想将它们作为独立电影播放,而是希望这些片段成为更大视频流的一部分。因此,您不应该使用盒装电影来为 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
好吧,既然你已经这样做了,你不妨利用这个机会只剪切你需要的部分:
# 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
当您合并 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
所以现在我们完成了所有工作,无需转码电影,保留了原始质量。但一如既往,有一个警告...
警告:剪切只能在关键帧边界上进行。说明:H.264 将压缩帧组织成数据包,每个数据包以第一帧的完整但压缩的图像开始,然后是后续帧的增量,从而减少每个数据包所需的存储空间。对于我们的目的而言,每个数据包就像是该持续时间内所有帧的密封 zip - 要么全部,要么没有。如果您只想要数据包的一部分,那么您必须将其解压缩并重新压缩,换句话说 - 对其进行转码。因此,上述方法仅在您想要剪切影片的每个位置都有关键帧时才适用。例如,如果每 5 秒有一个关键帧,则只能每 5 秒剪切一次。
所以现在的问题是,你是否能接受剪切点的限制,特别是你可能不知道电影中的关键帧在哪里。这就是我上面建议阅读的原因5.4 主要选项关于在输入之前或输出之前指定-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
由于生成的片段将位于 TS 中,因此在合并片段时无需进行另一次转码。
速度
在里面ffmpeg wiki 中有关合并的文章其中解释了如何通过管道运行整个过程,从而消除对中间文件的需要并加快整个过程。不。它将带你更长。在内存中完成所有操作会花费更长时间的原因不是因为它会运行更长时间,而是因为在弄清楚如何完成整个操作时,您将没有中间结果,并且您会发现自己一次又一次地运行整个过程。因此,管道理论是好的,但在您的情况下,您应该从制定和完善每个步骤开始。您会发现,要使一切正常运转并产生不错的结果,需要进行更多的调整和调整。一旦您掌握了整个过程并希望编写一些脚本以进行自动批量编辑,您就可以重新审视管道概念。
希望以上内容能有所帮助。