前言
FFmpeg 是一个强大的多媒体处理工具,但过多的参数很容易劝退人。其实它的使用并没有想象的麻烦,例如通过它管理视频的字幕是很方便的,也很容易理解。
本文将告诉你应该怎么做。这是一篇新手向教程。过程十分简单!
前提知识
在往下阅读前,你最好掌握一些基本的 FFmpeg 参数含义和用途。
输入文件
本文的命令多次使用 -i 参数,它表示输入文件,即我们要操作的文件。当存在多个输入时(例如视频文件、字幕文件)就会有多个 -i 参数。
编码器
本文的命令多次使用 -c 参数,它用于指定编码器。但由于操作字幕通常是无需重新编码的,所以使用 copy 这个特殊值,它表示直接复制而不涉及编码。
因为没有重编码过程,所以速度通常非常快。它基本上只是流的复制和容器格式的重新封装。
流选择/映射
本文的命令多次使用 -map 参数,它用于选择流并将其映射到输出。例如 -map 0 表示将第一个输入文件的所有流映射到输出,-map 0:a 表示将第一个输入文件的音频流映射到输出。或者更具体一点如 -map 0:a:0 表示将第一个输入文件的第一个音频流映射到输出。
映射可以指定多个,它是本文的核心参数。
字幕元数据
字幕可以通过 —metadata:s:s:[i] 参数设置元数据,其中 [i] 表示字幕流的索引。不同的字幕格式可能有不同的元数据,本文的重点在于设置字幕的 language 和 title。前者基本上是必要的,它表示字幕的语言,而后者是可选的,它表示字幕的标题。
为了便于理解,后文普遍会将「索引」称作「位置」。
标题在本文被用于展示语言名称,如 Simplified Chinese(简体中文)。
添加字幕
本章节会列举添加字幕的方法,你需要提前准备好字幕的 .srt 文件,并将其命名为 chi.srt。
此处的 chi 是一个语言代码,是符合 ISO-639-2 规范的代表「中文」的标准值。
在下面的过程中,我会将原视频命名为 input.mkv,输出的视频命名为 output.mkv。如果你使用 MP4 格式,可参考输出为 MP4章节。
插入字幕
这是最简便的方式,我们直接将字幕插入到最前面,作为第一个流(或者叫轨道)。执行如下 FFmpeg 命令:
ffmpeg -i input.mkv -i chi.srt \
-c copy \
-map 1:s -map 0 \
-metadata:s:s:0 language=chi \
-metadata:s:s:0 title="Simplified Chinese" \
-disposition:s:s:0 default \
output.mkv
注意它同时设置了与中文相关的字幕元数据并作为默认字幕。这个命令的优势是,我们无需事先知道原视频中有多少字幕流,因为我们始终把字幕添加到第一个位置,原有的流向后移动。
这样造成的问题是,视频文件不再按照传统的 视频 -> 音频 -> 字幕 顺序排列流,变成了 字幕 -> 视频 -> 音频 -> 字幕。这一般不会对视频的播放造成影响,但不排除有软件是按照流的固定位置(如第一个一定是视频)来解析视频文件。如果你认为存在隐患,那么可以使用下面的方法将字幕添加到最后。
追加字幕
要想把字幕添加为末尾的流,得获取原视频的字幕流数量。执行如下命令:
ffprobe -v error -show_entries stream=codec_type -of default=nw=1:nk=1 input.mp4 | uniq -c
输出如下(留意 subtitle 左边的数字):
1 video
1 audio
2 subtitle
这表示视频文件中有 1 个视频流、1 个音频流和 2 个字幕流。所以我们指定新字幕的位置为 2 即可:
ffmpeg -i input.mkv -i chi.srt \
-c copy \
-map 0 -map 1:s \
-metadata:s:s:2 language=chi \
-metadata:s:s:2 title="Simplified Chinese" \
-disposition:s:s:2 default \
output.mkv
位置从 0 开始数,因为原视频有 2 个字幕,所以是位置是 0+2(其实就等于字幕数量)。注意以上命令的 -metadata:s:s:[i] 和 -disposition:s:s:[i] 是需要替换值的部分,如果 [i] 搞错会错误的修改原有字幕的元信息而不是新字幕。
此处介绍的方法是「插入(头部)」或「追加(尾部)」字幕到原视频中,原有的字幕仍然保留。如果你想替换掉原有字幕,请参考替换字幕章节。
删除字幕
删除字幕的方法相对简单。我们仅需指定需要保留的流,或需删除的流即可。删除前记得用 ffmpeg -i input.mkv 查看原视频的流信息,让自己了解原视频的字幕数量和对应位置。
删除全部字幕
删除全部字幕无需在意原视频信息,直接执行:
ffmpeg -i input.mkv -map 0:v -map 0:a -c copy output.mkv
以上命令将保留原视频的视频和音频流,但不保留字幕流。即达到删除全部字幕的目的。
删除特定字幕
首先我们用 -map 0 选中所有流,然后指定需要排除的字幕流即可。比如我们要删除第二个和第三个字幕:
ffmpeg -i input.mkv -map 0 -map -0:s:1 -map -0:s:2 -c copy output.mkv
注意不要忘了,我之前提到过位置以 0 开始。所以此处的 0:s:1 表示第二个字幕而不是第一个,后面的 0:s:2 同理。
保留特定字幕
我们依然用 -map 0 选中所有流,然后指定需要保留的字幕流即可。比如我们仅保留第一个流:
ffmpeg -i input.mkv -map 0 -map 0:s:0 -c copy output.mkv
注意到区别了吗?删除字幕的参数值 -0:s:1 多了一个 - 前缀,没有 - 即表示保留。通常保留特定字幕的目的也是为了删除字幕,例如字幕实在太多指定删除会很麻烦。保留只是删除的思维反转。
替换字幕
替换字幕实际上是以上操作的综合。替换的逻辑是,在添加字幕的同时删除或仅保留特定字幕。替换可能是大多人会考虑的做法,尤其是从国外知名 BT 网站下载的视频。因为它总是包含很多语言的字幕,却可能缺失中文。
替换全部
假设我们不在意原视频中的字幕,仅需我们自己添加的字幕。那么:
ffmpeg -i input.mkv -i chi.srt \
-c copy \
-map 0:v -map 0:a -map 1:s \
-metadata:s:s:0 language=chi \
-metadata:s:s:0 title="Simplified Chinese" \
-disposition:s:s:0 default \
output.mkv
在这个例子中,我仅选中了新字幕以及原有的视频流和音频流,所以只会保留我们新增的字幕。这样就达成了一个命令添加新字幕并替换掉所有字幕的目的。
替换特定
假设我们的原视频有 2 个字幕流,我们用新字幕替换掉原来的第二个字幕(位置 1)。如下:
ffmpeg -i input.mkv -i chi.srt \
-c copy \
-map 0 -map 1:s -map -0:s:1 \
-metadata:s:s:1 language=chi \
-metadata:s:s:1 title="Simplified Chinese" \
-disposition:s:s:1 default \
output.mkv
这次我们选中了所有字幕(包括新字幕),但排除掉位置为 1 的字幕。因为我们提前知道字幕的数量,所以编辑字幕 1 的元数据(因为排除掉原字幕后新字幕会在这个位置,而不是 2)。这样就达成了替换特定字幕的目的。
如果我们进一步扩展命令使用 -map 排除或保留更多,就可以实现删除多个字幕流的目的。但要注意新字幕的位置,它会随着删除的字幕数量而变化(原字幕数量减去删除的字幕数量)。明确知道删除了多少字幕流很重要。
移除默认流配置
如果原有字幕已经存在默认标识了,但又想把新增的字幕设置为默认,可以清除原字幕流的配置。如果存在多个默认流配置,选择哪个字幕是不一定的(看播放器行为)。
假设我们保留第一个原字幕,但移除它的默认流配置。操作如下:
ffmpeg -i input.mkv -i chi.srt \
-c copy \
-map 0 -map 1:s \
-metadata:s:s:1 language=chi \
-metadata:s:s:1 title="Simplified Chinese" \
-disposition:s:s:1 default \
-disposition:s:s:0 0 \
output.mkv
注意新增的 -disposition:s:s:0 0 参数,它会清除第一个字幕流的配置。注意 s:s:0 是指定字幕位置,参数值 0 才表示清除。这样就只有新字幕被设置为默认。
输出为 MP4
以上的例子全部使用 MKV 容器格式,默认情况下这些参数不一定能输出为其它容器格式。例如导出为 MP4 时需要指定为字幕为 mov_text 格式,并且 mov_text 不支持 title 元数据。但保留命令参数是无害的,虽然播放器看不到字幕标题。
具体如下:
ffmpeg -i input.mkv -i chi.srt \
-c copy \
-c:s mov_text \
-map 0 -map 1:s \
-metadata:s:s:1 language=chi \
-metadata:s:s:1 title="Simplified Chinese" \
-disposition:s:s:1 default \
output.mp4
注意新增的 -c:s mov_text 参数,它会将原视频的所有字幕转换为 mov_text 格式。也许有人会问,你仅指定新字幕为 mov_text 不就行了,为什么要影响其它字幕?好问题,因为 MKV 容器中的其它字幕可能是 SubRip 等 MP4 不支持的格式,如果不转换全部字幕就会失败。
字幕标题显示(mov_text 并不支持):
SubRip 字幕的 title 截图
结束语
这就是用 FFmpeg 操作视频字幕的方法了。对于有一定经验的 FFmpeg 用户,通过本文你应该能自由的管理字幕了。如果是纯小白,可能仍只能照猫画虎,我建议使用更低门槛的图形化工具(虽然我没有推荐的)。