使用 FFmpeg 管理视频字幕(添加、删除、替换字幕的方法)

By | 2024-10-02

转载

前言

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 用户,通过本文你应该能自由的管理字幕了。如果是纯小白,可能仍只能照猫画虎,我建议使用更低门槛的图形化工具(虽然我没有推荐的)。