我的运动相机拍摄的视频是自动分段的,每段时长 15 分钟。由于骑摩托车时用,风噪太大,在录制视频时,做了不录制声音的设定。因此,对于得到的视频,我需要做两个处理,首先是视频的合并,其次是增加背景音乐。此外,倘若枯燥沉闷的路段,让视频的播放速度能加快一些会更好。
倘若用手机 APP 或者 PC 上的应用软件来处理这些事,免费的软件不是那么好找,能找到的也不见得会多么好用,还是用 ffmpeg 吧,好久没用它了。上一次用它,是这个时候:https://liyanrui.github.io/posts/some-minor-operation-for-videos.html
增加背景音乐
先从增加背景音乐开始。假设我有一段视频,文件为 foo.mp4,我想将 MP3 格式的一段音乐作为 它的背景音乐——音乐文件为 bar.mp3,为便于理解,做法可以分为两步。第一步去除 foo.mp4 文件中的音轨,即便它无声,但不代表它没声音:
$ ffmpeg -an -i foo.mp4 -c copy foo-no-audio.mp4
输出的 foo-no-audio.mp4 即为去掉了音轨的视频文件。然后,将 bar.mp3 作为 foo-no-audio.mp4 的音轨:
$ ffmpeg -i foo-no-audio.mp4 -stream_loop -1 -i bar.mp3 -c copy -t 00:15:00 foobar.mp4
其中,-stream_loop -1 用于设定以 bar.mp3 的循环播放作为 foo-no-audio.mp4 的音轨。-c copy 可简单理解为保持输出视频画质的选项。-t 选项用于设定视频的时长,由于 foo-no-audio.mp4 的时长为 15 分钟,所以命令中就是 -t 00:15:00。最终得到的结果为 foobar.mp4,即原视频增加了背景音乐的结果。
-t 选项是必须的,倘若没设定这个选项,那么 ffmpeg 会认为,既然背景音乐在循环播放,那么输出的视频也应该是无限长的。倘若不想打开原视频查看截止时长,也可以用 -shortest 取代 -t 时长 这个选项。-shortest 会让 ffmpeg 根据视频和音轨的时长哪个更短来确定时长,倘若音轨是无限长的,那么就以视频时长为截止时长。
掌握了为视频增加背景音乐的基本方法后,为视频做后期配音的事情也自然就会了。
混音
倘若保留原视频 foo.mp4 的音轨,在此基础上混入新的音轨,命令如下:
$ ffmpeg -i foo.mp4 -stream_loop -1 -i bar.mp3 -filter_complex [0:a][1:a]amix -shortest foobar.mp4
视频合并
假设有视频文件 a.mp4, b.mp4, c.mp4,它们位于同一目录,要将它们合并为 abc.mp4,只需在该目录下建立一个文本文件,例如 list.txt,内容为:
file 'a.mp4'
file 'b.mp4'
file 'c.mp4'
然后在该目录下执行命令:
$ ffmpeg -f concat -i list.txt -c copy abc.mp4
便可得到视频的合并结果 abc.mp4。
视频加速
所谓视频,无非是很多画面的集合。每一张画面(帧)都有其显示的时间。视频播放器根据这个时间显示和切换画面。理解了这一点,视频加速问题本质上就是修改画面显示时间的问题。倘若将每个画面的原来的播放时间都缩短,那么视频播放的就快了,反之就慢了。
ffmpeg 可通过 PTS 的倍率修改视频画面播放时间。例如,将 foobar.mp4 播放速度提高一倍,只需:
$ ffmpeg -an -i foobar.mp4 -filter:v "setpts=0.5*PTS" -q 1 foobar-quick.mp4
其中,-an 是必须的,即在视频加速时要去掉音轨,否则决定加速后视频时长的是音轨的时长,因为上述命令是在对视频进行加速,而非音轨。去掉的音轨,可以在视频加速后,再重新加到视频里。选项 -q 1 用于保留视频的原有画质,之所以用这个选项,是因为在修改视频速度的命令中,之前用的 -c copy 不可用了。
同理,若将视频速度提高 2 倍,只需:
$ ffmpeg -an -i foobar.mp4 -filter:v "setpts=0.3*PTS" -q 1 foobar-quick.mp4
但是,视频加速后,必然会丢失一些画面。因为每个视频,每秒钟播放出多少画面,这个数量叫帧率,它通常是固定的。例如,我的运动相机拍摄的视频,帧率是 30,亦即视频的每一秒的片段里包含着 30 个画面。倘若我将视频加速,这样每一秒实际上包含的画面是高于 30 的(提速一倍,视频的每一秒的片段就会包含了 60 个画面),但是此时视频帧数还是 30,那必定会有一部分画面没有机会播放,结果就会导致原本连续的画面有所卡顿。解决方法是,在 ffmpeg 命令中指定新的视频的帧率。例如,提速一倍的视频,可以将帧率设为 60:
$ ffmpeg -an -i foobar.mp4 -r 60 -filter:v "setpts=0.5*PTS" -q 1 foobar-quick.mp4
视频加速处理,要对每个画面都要进行变动,相当于一个图像编辑软件在对每个画面进行格式转换,所以这个过程会很慢。
字幕
我喜欢 MP4 格式的视频,但是给这样的视频增加字幕,就有些麻烦,因为 MP4 本质上是个容器,它包含了视频和音频(前文中为视频增加的背景音乐就是音频部分),但是却不包含字幕。有些视频格式,包含了视频、音频和字幕,为它们添加字幕,只需要将字幕内容做成符合要求的文件,添加至容器内即可。MP4 视频的字幕,需要将字幕内容制成图像,然后合并到视频图像上,本质上是要对 MP4 的视频部分进行转码,即对视频的每一幅画面进行了修改,生成含有字幕的新画面,俗称字幕烧录。
ffmpeg 可将 SRT 格式的字幕文件中的内容烧录至 MP4,例如
$ ffmpeg -i foo.mp4 -vf "subtitles=bar.srt" foobar.mp4
注:对于 Gentoo 用户而言,这个命令需要 ffmpeg 包开启
libass。
这条命令虽然简单,但是原视频可能会被 ffmpeg 重新编码为体积偏小但是画面质量大幅下降的视频。要控制画面质量,可使用 -q 选项,但是 ffmpeg 默认的视频转码格式在画质提高的同时,生成的文件体积也会数倍增大。倘若想画质与文件体积兼顾,可以考虑选用一种画面压缩比较高的视频格式进行转吗,例如使用 H265 格式:
$ ffmpeg -i foo.mp4 -vf "subtitles=bar.srt" -c:v libx265 -c:a copy foobar.mp4
-c:v 选项用于设定视频转码格式。-c:a 用于设定音频转码格式,上例中,使用 copy,表示不对音频转码,依然使用 foo.mp4 里的音频。对视频和音频进行转码,通常比较耗时。使用画面压缩比高的视频格式,转码过程会更加耗时。
注:要使用上述的 H265 转码格式,Gentoo 的 ffmpeg 包需要开启
x265。
下面是一份简单的 SRT 字幕格式示例:
1
00:00:00.0 --> 00:00:04.0
骑上我心爱的小摩托
2
00:00:04.0 --> 00:00:08.0
它永远不会堵车
3
00:00:08.0 --> 00:00:12.0
骑上我心爱的小摩托
4
00:00:12.0 --> 00:00:15.0
我马上就到家了
5
00:00:16.0 --> 00:00:20.0
它让我远离烦恼和忧伤
6
00:00:20.0 --> 00:00:24.0
它带我重新回到自由天堂
7
00:00:24.0 --> 00:00:29.0
来吧,来吧,和我一起上路
8
00:00:29.0 --> 00:00:37.0
嘟嘟嘟嘟嘟……
其中,时间格式的最后一位数字表示毫秒。









网友评论