用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]

参考资料

  1. Mokubai. Ffmpeg GPU encoding not speeding up processing. . 2022-04-06 [2024-08-05].