用ffmpeg代替Adobe Premiere剪辑视频
2024年8月4日我已经曾学过Adobe Premiere,但是没有剪很多影片。在那时候,一般我会需要10倍于影片时间的时间来剪片。比如,影片是30分钟,我剪辑要花300分钟。
Adobe Premiere剪片有什么问题?
Adobe Premiere是收费软件,软件又很笨重。
Adobe Premiere不容易学习。
剪片操作不能复制、套用。这是对我来说最主要的问题。假设我有一系列片子要剪,每一集的剪法都差不多。都是每个片段头尾整理一下,加字幕,合并起来,加速1.3倍。我即使上一集已经这么做过了,这一集还是要鼠标重新点一次。
就说裁剪这一个操作好了,Premiere里面就是鼠标点到某个时间点,按个裁剪按钮。但是裁剪按钮在哪里必须记忆。浮在表面还好,有的功能藏在很多级菜单里,记不住。
ffmpeg剪片有什么好处?
我用gnumake (makefile)编写ffmpeg的剪片指令。
starting.mkv : raw/v-starting.mkv raw/a-starting.m4a
# -ss is not accurate without reencoding.
ffmpeg $(flags) \
-i raw/v-starting.mkv \
-i raw/a-starting.m4a \
-filter_complex "[1:a] volume=15dB [speaking]; [0:a][speaking]amix=inputs=2: duration=shortest[a]" \
-map 0:v -map "[a]" -c:v copy -ac 2 -shortest \
$@
这个规则根据raw/v-starting.mkv和raw/a-starting.m4a生成starting.mkv,并且音量提高15dB,两个音频混合。
音量提高和音频混合在Premiere里显然是两个不同操作,要鼠标去不同地方点击。而且每次都要输入15dB这个参数。但是这里我用makefile,只要输入文件名改一下,整个剪辑流程就直接套用。
其他操作如加特效、综艺字、转场、加速等,都以此类推。代码写好,只要输入输出文件名改一下就可以了。
Last but not least,整个makefile是纯文本文件,可以加注释。Adobe Premiere是需要鼠标点来点去的软件,你只能拿另外的笔记本记东西。
一个makefile制作一部影片。要剪下一部影片了,就直接复制最近的makefile,改改文件名。想要用的特效应该有了。
ffmpeg剪片有什么特点和坏处?
ffmpeg与makefile配合,剪片子是有层次的。类似图像软件的图层概念,可以单独查看每个“图层”的效果,就是单独运行某个make rule。要查看前几层的合并效果,就运行后面的rule。每个rule都输出一个视频文件。
每个rule都输出一个视频文件,这既是ffmpeg+makefile剪片的核心,又是缺点。
之所以称为核心,是你需要观看、检查输出的视频文件。就像写程序,光写代码不运行,写出来肯定是bug。
缺点
视频文件有所谓“关键帧”的概念。一般来说是5秒一个关键帧。
ffmpeg -ss 3 -i input output
这句命令从第3秒开始提取input,存为output。但是关键帧在第0、5秒,无法在第3秒截开。
有两种办法,第一允许inaccurate seeking。ffmepg会自己找到最早的关键帧,从那里截断。这样整个操作的速度非常快,因为可以用-codec copy
。第二是re-encoding,ffmepg把第3、8、13秒编码为关键帧。这等于整个文件都重新编码了,速度慢。而且re-encoding会降低画质。(无损画质的视频太大了,一般不用。就像我们一般不用bmp图像)
由于这个seeking problem,我们剪片没办法剪得很精确。有的Youtuber要求自己的视频每秒变换一个画面,那re-encoding花费的时间就很多。
现在,视频的片段都做好了,我们要把它们连接起来,或许还要加速。加速一定需要re-encoding。
$(project)-30.mp4 : $(project).mkv
ffmpeg $(flags) \
-i $^ \
-filter_complex "[0:v] subtitles=ep1.srt, setpts=PTS/1.3 [v]; [0:a] atempo=1.3 [a]" \
-map "[v]" -map "[a]" \
$@
有一些减少re-encoding的办法,比如用filter_complex,一次套用多个filter。比如这里,我burn in subtitle,然后视频和音频加速。整个命令行编码一次。如果我断开,比如先burn in subtitle生成个文件,再加速,生成第二个文件,那么就会编码两次,而且画质变低。
$(project).mkv : starting-1.mkv starting-2.mkv mission-intro.mkv starting-3.mkv \
r2-1.mkv r3.mkv
./same_codec.sh $^
echo -n '' > $(project)-clips
for f in $^; do
echo "file $$f" >> $(project)-clips
done
ffmpeg $(flags) -f concat -i $(project)-clips \
-c copy $@
ffmpeg有concat format,它从一个文本文件里读取指令指示连接那些文件。除了file指令,还有offset等指令相当于-ss, -to的效果。但是如果在concate这一步用-ss -to,我就不能实现预览了,所以我在前面就把要精确剪辑的片段先剪好。
到这里就引出了Adobe Premiere的优势。它应该会内部追踪时间戳,比如最终版的第几秒相当于第几个源影片的第几秒,在最终输出时只编码一次。Premiere也应该会组合filter,把很多操作放进一个filter_complex,于是只编码一次。
上字幕
华人影片都喜欢字幕。我用AI自动生成字幕,但肯定不是很准确,时间没对很齐。这个时候需要GUI tool一般看影片一边调整字幕。如果某些地方还需要调整,比如有的地方要哔掉,那ffmpeg就比较困难,因为我们不知道这一秒是哪个源文件的哪一秒。
ffmpeg硬件加速
$ Measure-Command { ffmpeg -y -hwaccel cuda -ss 4 -i demolish.mp4 demolish-gpu.mp4 }
TotalSeconds : 80.0501349
$ Measure-Command { ffmpeg -y -ss 4 -i demolish.mp4 demolish-cpu.mp4 }
TotalSeconds : 80.5122661
$ Measure-Command { ffmpeg -y -hwaccel cuda -ss 4 -i demolish.mp4 -codec:v h264_nvenc demolish-h264_nvenc.mp4 } |
Select-Object -Property TotalSeconds
TotalSeconds
------------
21.5574304
发现第一,seeking需要re-encoding;第二,需要指定codec h264_nvenc,它才会利用GPU加速。[1]
参考资料
- Mokubai. Ffmpeg GPU encoding not speeding up processing. . 2022-04-06 [2024-08-05].↑