如何使用ffmpeg从视频中剪切一段?
想象一下,我有一个60秒的mp4A
。
我想删除从0:15到0:45的所有内容。
结果应该是一个30秒的mp4,它由A
的前15秒和A
的最后15秒组成。
如果不使用concat,我怎么能做到这一点?
我知道如何创建两个中间文件,然后使用ffmpeg将它们连接起来。我不想为这个(简单的?(操作做那么多手工工作。
我还看到trim
过滤器用于从视频中删除多个部分。我发现的所有用法都表明它似乎非常冗长,而且我还没有找到一个像我希望的那样简单的例子(只是删除了单个部分(。
这次手术我必须使用修剪吗?或者还有其他不那么冗长的解决方案吗?
当然,理想的是至少像-ss 0:15 -to 0:45
这样简单的东西,它删除了视频的结尾(例如-cut 0:15-0:45
(。
我从https://stackoverflow.com/a/54192662/3499840(目前唯一的答案是"FFmpeg从视频中间删除2秒并插入部分。单线解决方案"(。
从这个例子来看,以下对我有效:
# In order to keep <start-15s> and <45s-end>, you need to
# keep all the frames which are "not between 15s and 45s":
ffmpeg -i input.mp4
-vf "select='not(between(t,15,45))', setpts=N/FRAME_RATE/TB"
-af "aselect='not(between(t,15,45))', asetpts=N/SR/TB"
output.mp4
这是一个单行linux命令,但我使用了bash行延续字符("\"(,这样我就可以垂直对齐等号,因为这有助于我了解发生了什么。
我以前从未见过ffmpeg的not
和between
运算符,但我在这里找到了它们的文档。
关于通常的ffmpeg";复制与重新编码";二分法,我希望能够使用ffmpeg的";复制"编解码器";(是的,我知道它不是真正的编解码器(,所以ffmpeg不会对我的视频进行重新编码,但如果我指定";"复制";,然后ffmpeg在离我想要的开始点和停止点不够近的最近的关键帧处开始和停止。(我想删除一段大约20秒长的视频,但我的源视频每45秒只有一个关键帧!(。因此,我不得不重新编码。看见https://trac.ffmpeg.org/wiki/Seeking#Seekingwhiledoingacodeccopy了解更多信息。
setpts/setpts过滤器将每帧上的时间戳设置为正确的值,以便您的媒体播放器在正确的时间播放每帧。
HTH。
如果您想使用副本"编解码器";,考虑以下方法:
ffmpeg -i input.mp4 -t "$start_cut_section" -c copy part1.mp4&
ffmpeg -i input.mp4 -ss "$end_cut_section" -c copy part2.mp4&
echo "file 'part1.mp4'" > filelist;
echo "file 'part2.mp4'" >> filelist;
wait;
ffmpeg -f concat -i filelist -c copy output.mp4;
rm filelist;
这将创建剪切前后的两个文件,然后将它们组合成一个新的修剪后的最终视频。显然,这可以用来创建任意数量的切割。这似乎是一种比公认答案更长的方法,但由于使用了复制编解码器,它可能会执行得更快。
对于那些希望删除视频的不同部分而不仅仅是一个块的人,您可以在命令中传递多个"查询":
ffmpeg -i in.mp4
-vf select='not(between(t,0,10))',select='not(between(t,15,30))',setpts=N/FRAME_RATE/TB
-af aselect='not(between(t,0,10))',aselect='not(between(t,15,30))',asetpts=N/SR/TB
out.mp4