FFMpeg与MKV

序
如果要用一个词来形容MKV容器, 大约用"妖孽"比较恰当吧, 相比常见的mp4, mov等容器格式, 它更像一个压缩包, 不管视频流, 音频流, 字幕流, 字体, 都可以封装, 甚至封装一个PDF文件, 一个MKV中封装两个视频流都不是什么问题. 像mkvtoolnix
, 小丸工具箱
等软件都可以对MKV进行处理, 以下尝试使用ffmpeg
处理mkv文件.
ffmpeg 的 map 参数
ffmpeg 的 map 选项是用来从输入中选择流的. 通常单个 mp4 文件只有一路视频流和一路音频流, 使用 ffmpeg 处理时基本上不用指定, 当有多个输入时就有必要使用 map 选项选择输入流了, 由于 mkv 能封装的东西太多了, 故大多数时候 map 选项也是必要参数.
以下是 ffmpeg 官方用来说明 map 参数功能的图片:

两条 ffmpeg 命令行的功能是相同的, 以下对选项的参数做出解释.
map 选项的语法为:
-map input_file_index:stream_type_specifier:stream_index
- input_file_index: 第几个输入文件(从0开始算起)
- stream_type_specifier: 流类型(可选参数)
- stream_index: 流索引
stream_type_specifier
有如下几种值:
v
: video, 视频流a
: audio, 音频流s
: subtitle, 字幕流d
: data, 数据t
: attachemnt, 附件
以上图中的命令行举例说明:
ffmpeg -i input0.mp4 -i input1.mkv -map 0:0 -map 1:3 output.mp4
-map 0:0
表示第1个输入(input0.mp4
)中的第1个流-map 1:3
表示第2个输入(input1.mkv
)中的第4个流
ffmpeg -i input0.mp4 -i input1.mkv -map 0:v:0 -map 1:a:2 output.mp4
-map 0:v:0
表示第1个输入中的第1个视频流(v
参数)-map 1:a:2
表示第2个输入中的第3个音频流(a
参数)
从MKV中抽取流
如果要查看 MKV 中封装的流, 使用如下命令行即可:
ffprobe -i input.mkv
以下是使用 ffprobe
查看某个mkv视频封装流的输出:
1i@flytech:~$ffprobe -i laputa.mkv
2...(略)
3Input #0, matroska,webm, from 'laputa.mkv':
4 Metadata:
5 title : Laputa: Castle in the Sky
6 encoder : libebml v1.2.3 + libmatroska v1.3.0
7 creation_time : 2012-08-15T12:41:14.000000Z
8 Duration: 02:04:33.57, start: 0.000000, bitrate: 6397 kb/s
9 Chapters:
10 Chapter #0:0: start 0.054000, end 0.097000
11 Metadata:
12 title : 00:00:00.054
13...(略)
14 Stream #0:0: Video: h264 (High), yuv420p(progressive), 2000x1080 [SAR 1:1 DAR 50:27], 23.98 fps, 23.98 tbr, 1k tbn (default)
15 Stream #0:1(jpn): Audio: dts (DTS-HD MA), 48000 Hz, stereo, s16p (default)
16 Metadata:
17 title : 天空の城ラピュタ / 日本語
18 Stream #0:2(chi): Audio: ac3, 48000 Hz, stereo, fltp, 192 kb/s
19 Metadata:
20 title : 天空之城 / 普通话
21...(略)
22 Stream #0:8(chi): Subtitle: ass (default)
23 Metadata:
24 title : 简体中文字幕
25 Stream #0:9(jpn): Subtitle: srt
26 Metadata:
27 title : 日文字幕
28...(略)
29 Stream #0:19: Attachment: ttf
30 Metadata:
31 filename : simhei.ttf
32 mimetype : application/x-truetype-font
33 Stream #0:20: Attachment: ttf
34 Metadata:
35 filename : Geometr706_Md_BT_Medium.ttf
36 mimetype : application/x-truetype-font
37...(略)
此 MKV 文件包含了 7 条音轨, 十几条字幕, 5 种字体, 算是比较有代表的 mkv 封装了, 以下以示例方式说明对引 MKV 文件的常用操作.
1. 将此 mkv 文件转换为只包含中文配音的mp4文件:
1ffmpeg -i laputa.mkv -map 0:0 -map 0:2 -c copy laputa.mp4
其中-map 0:0
表示选择第1个输入中的第1个流, 在此输入文件中是 H.264 编码的视频流:
1Stream #0:0: Video: h264 (High), yuv420p(progressive), 2000x1080 [SAR 1:1 DAR 50:27], 23.98 fps, 23.98 tbr, 1k tbn (default)
-map 0:2
表示第1个输入中的第3个流, 在此输入文件中是普通话配音:
1 Stream #0:2(chi): Audio: ac3, 48000 Hz, stereo, fltp, 192 kb/s
2 Metadata:
3 title : 天空之城 / 普通话
-c copy
表示将输入流复制到输出, 以避免重新编码耗费时间.
2. 提取此 mkv 文件中的简体中文字幕:
1ffmpeg -i laputa.mkv -map 0:8 -c:s ass laputa-chi.ass
其中-map 0:8
表示选择第1个输入中的第8个流, 此处是 ass 格式的简体中文字幕:
1 Stream #0:8(chi): Subtitle: ass (default)
2 Metadata:
3 title : 简体中文字幕
-c:s ass
表示对字幕使用ass编码器, 实际上使用-c copy
也是可以的, 因为输入和输出均是 ass 文件.
3. 提取字体 simhei.ttf
1ffmpeg -dump_attachment:19 simhei.ttf -i laputa.mkv
将输出文件名留空的话就可以提取所有附件:
1ffmpeg -dump_attachment:19 "" -i laputa.mkv
提取所有附件的命令在 Linux 下可正常提取, Windows 下会报参数错误, 原因未知.
合并为MKV
1. 为 MP4 新增2路音频流并封装为MKV
以下命令行将视频input.mp4
和英语配音音频流eng.m4a
, 日语配音音频流jpn.m4a
合并为一个mkv文件:
1ffmpeg -i input.mp4 -i eng.m4a -i jpn.m4a -map 0 -map 1 -map 2 -c copy out.mkv
在 potplayer 中查看:

虽然音频被添加进去了, 但标题本文是有问题的, 所以还需要为其添加元数据metadata:
1ffmpeg -i input.mp4 \
2-i eng.m4a \
3-i jpn.m4a \
4-map 0 -map 1 -map 2 \
5-metadata:s:a:0 language="chi" \
6-metadata:s:a:1 language="eng" \
7-metadata:s:a:2 language="jpn" \
8-metadata:s:a:0 title="普通话" \
9-metadata:s:a:1 title="英语" \
10-metadata:s:a:2 title="日语" \
11-disposition:a:0 default \
12-disposition:a:1 -default \
13-disposition:a:3 none \
14-c copy out.mkv
命令行结尾的符号 \
是换行符, 在 Linux 的 bash 中是 \
, 在 Windows 的 cmd 中是 ^
, 在 powershell 中是 `
(反引号).
-metadata
选项用来写入元数据, 可为mkv文件或其中封装的流写入元数据, 其语法如下:
1-metadata[:metadata_specifier] key=value
metadata_specifier
可取如下几种值:
g
: 全局元数据, 也就是 mkv 文件的元数据-
s[:stream_spec]
数据流的元数据, 比如 mkv 中音频流的元数据;stream_spec
取值范围同 map 选项的stream_type_specifier
c: chapter_index
章节的元数据p: program_index
节目的元数据
此参数如果不指定, 默认为 g
, 即全局元数据
-
language
的值可参考 ISO 638-1 代码表.
-disposition
选项用来调整文件布局的, 此处用来设置默认音频流. 在上述命令行中将第 1 条音频流设置为默认音频流, -disposition:a:1 -default
与 -disposition:a:3 none
的作用是一样的, 即不要将其设置为默认流(否则会出现所有音频流均是默认流的情况), 其语法如下:
1-disposition[:stream_specifier] value
-
stream_specifier
与 map 选项的stream_type_specifier
类似, 此处不再赘述 - value 可用的值可以使用命令行
ffmpeg -dispositions
查看, 如下:
1default
2dub
3original
4comment
5lyrics
6karaoke
7forced
8hearing_impaired
9visual_impaired
10clean_effects
11attached_pic
12timed_thumbnails
13captions
14descriptions
15metadata
16dependent
17still_image
default
用来设置默认流, attached_pic
可用来为视频或 mp3 设置封面.
使用上述命令行再次生成 mkv 后使用 potplayer 查看:

2. 使用 ffmpeg 将多个视频, 音频, 字幕, 字体封装为MKV
1ffmpeg -i input.mp4 \
2-i input_2.mp4 \
3-i eng.m4a \
4-i jpn.m4a \
5-i chi.ass \
6-i eng.ass \
7-i jpn.ass \
8-attach SmileySans-Oblique.ttf \
9-map 0 -map 1 -map 2 -map 3 -map 4 -map 5 -map 6 \
10-metadata:s:v:0 language="" \
11-metadata:s:v:1 language="" \
12-metadata:s:v:0 title="视频1" \
13-metadata:s:v:1 title="视频2" \
14-disposition:v:0 default \
15-disposition:v:1 none \
16-metadata:s:a:0 language="chi" \
17-metadata:s:a:1 language="eng" \
18-metadata:s:a:2 language="jpn" \
19-metadata:s:a:0 title="普通话" \
20-metadata:s:a:1 title="英语" \
21-metadata:s:a:2 title="日语" \
22-disposition:a:0 default \
23-disposition:a:1 none \
24-disposition:a:3 none \
25-metadata:s:s:0 language="chi" \
26-metadata:s:s:1 language="eng" \
27-metadata:s:s:2 language="jpn" \
28-metadata:s:s:0 title="中文字幕" \
29-metadata:s:s:1 title="英文字幕" \
30-metadata:s:s:2 title="日语字幕" \
31-disposition:s:0 default \
32-disposition:s:1 none \
33-disposition:s:3 none \
34-metadata:s:t:0 mimetype="application/x-truetype-font" \
35-c copy out.mkv
这条命令行将两个视频, 2个音频, 3个字幕和1个在字幕中用到的字体封装为 mkv 文件, 且设置默认视频流为第1个视频流, 默认音频流为第1个音频流, 默认字幕流为第1个 ass 字幕. 为了防止在其它电脑上播放时找不到 ass 字幕的字体, 所以将字体也一并封装到 mkv 文件中.
在命令行中使用 -attach
选项添加字体为附件, 并且使用 -metadata:s:t:0 mimetype="application/x-truetype-font"
为附件指定 mimetype
.
使用 potplayer 查看:
视频流

字幕流

3. 为文件添加封面
默认资源管理器会提取视频中的某一帧来作为缩略图, 如果给视频文件设置了封面,则会使用封面作为文件缩略图.
以上面输入的 out.mkv
为例添加封面:
1 ffmpeg -i out.mkv
2 -attach cover.jpg
3 -map 0
4 -metadata:s:t:1 mimetype="image/jpeg"
5 -disposition:t:1 attached_pic
6 -c copy out2.mkv
这里使用 -attach cover.jpg
添加封面图片, -map 0
的意思是选择第1个输入(out.mkv
)中所有的流. 因为输入文件中已经有了一个附件(字体), 故此为封面设置metadata使用-metadata:s:t:1
.
以上是对 mkv 文件添加封面的方法, 如果要对 MP4 或 MP3 文件添加封面, 由于 MP4 容器不支持附件, 故要使用如下命令行:
1ffmpeg -i input.mp4 \
2-i cover.jpg \
3-map 0 \
4-map 1 \
5-disposition:v:1 attached_pic \
6-c copy
7out.mp4
对于 MP3 文件类似.
(全文完)