前一篇的简单命令假设输入只有一条视频和一条音频。真实文件常常有多条音轨、字幕或封面。这时要把两件事分开:

-map 从输入里挑选哪些 Stream 放进输出
-c 挑出来的 Stream 是 Stream Copy,还是重新编码

-map 不会把视频自动转成 H.264,-c 也不会替你改选另一条音轨。

flowchart LR
I0[输入 0<br/>视频 / 多条音频 / 字幕] --> P[ffprobe<br/>index · 类型 · 语言]
I1[输入 1<br/>旁白或 Logo] --> P
P --> S[-map<br/>挑选轨道]
S --> T[当前输出里的流]
T --> C[-c:v / -c:a<br/>copy 或编码]
C --> M[Muxer]
M --> O[一个输出文件]

先查看再选择

Terminal window
ffprobe -v error -show_entries "stream=index,codec_type,codec_name:stream_tags=language,title" -of json input.mkv

下面用一个有双语音轨的文件示意编号关系。这是结构示意,实际 JSON 字段和值以自己的查询结果为准:

Stream #0:0 video h264
Stream #0:1 audio aac language=chi
Stream #0:2 audio aac language=eng
Stream #0:3 subtitle ass language=chi

编号来自当前输入,不能靠后缀或经验猜。

不写 -map:自动选择

Terminal window
ffmpeg -i input.mkv output.mp4

没有 -map、也没有复杂 Filtergraph 输出影响选择时,FFmpeg 从全部输入中,为输出格式支持的类型各选一条流:

  • 视频:分辨率最高的那条;并列时取索引更小的;
  • 音频:声道数最多的那条;并列时取索引更小的;
  • 字幕:第一条类型匹配的字幕(文本字幕和图像字幕不会随便混用);
  • 数据流、附件:不会自动选,只能用 -map 显式带上。

因此,多音轨文件也可能只输出一条音频。要保留指定语言或多条轨道,就写出 -map。它会关闭该输出的默认自动选流,但无标签的复杂 Filtergraph 输出仍会加入第一个输出文件。

字幕还有例外:手动指定字幕编码器时,自动选择可能纳入第一条字幕,而不预先检查文本/图像类型是否能转换。选中字幕不代表一定能编码成功。详见官方 Stream handling。

最基本的 -map

选择第 0 个输入的第一条视频和第一条音频:

Terminal window
ffmpeg -i input.mkv -map 0:v:0 -map 0:a:0 -c copy output.mkv

常见写法是 输入编号:类型:该类型内的序号,也可直接用输入内的流索引:

写法含义
0第 0 个输入的全部流
0:v第 0 个输入的全部视频
0:a第 0 个输入的全部音频
0:v:0第 0 个输入里匹配到的第一条视频
0:a:1第 0 个输入里匹配到的第二条音频
0:s:0第 0 个输入里匹配到的第一条字幕
0:2第 0 个输入中索引为 2 的流,不限定类型

在下面这个示意文件中,0:a:1 和 0:2 指向同一条流。其他文件的排列可能不同:

Stream #0:0 video 0:v:0 0:0
Stream #0:1 audio chi 0:a:0 0:1
Stream #0:2 audio eng 0:a:1 0:2 ← 类型内第 2 条音频,输入内索引 2
Stream #0:3 subtitle 0:s:0 0:3

多个 -map 的顺序,就是输出里轨道的顺序。

不存在时是否失败

普通映射要求流必须存在:

Terminal window
ffmpeg -i silent.mp4 -map 0:v:0 -map 0:a:0 -c copy output.mp4

输入没有音频时,这条命令会失败。末尾加 ? 表示可选:

Terminal window
ffmpeg -i silent.mp4 -map 0:v:0 -map 0:a:0? -c copy output.mp4

适合输入结构确实不一致的批处理。如果业务要求“必须有声音”,就不要用 ? 把缺失变成静默成功。

选择全部或排除部分流

保留输入中的全部流:

Terminal window
ffmpeg -i input.mkv -map 0 -c copy output.mkv

全部选中后再排除字幕(负向映射):

Terminal window
ffmpeg -i input.mkv -map 0 -map -0:s -c copy output.mkv

排除第二条音频:

Terminal window
ffmpeg -i input.mkv -map 0 -map -0:a:1 -c copy output.mkv

目标容器不一定支持附件、数据或某种字幕。-map 0 失败时,按目标容器的能力重新选择。带封面的文件还要区分 v 与 V:小写 v 包括封面等视频流,大写 V 排除附加图片、缩略图和封面。

只输出音频或视频

-vn、-an、-sn 分别禁止视频、音频和字幕输出:

Terminal window
ffmpeg -i input.mkv -map 0:a:0 -vn -c:a aac -b:a 192k audio.m4a
ffmpeg -i input.mkv -map 0:v:0 -an -c:v libx264 video.mp4

上面两个例子的 -map 已经限定了类型,-vn / -an 进一步明确输出意图。复杂 Filtergraph 带标签的输出必须用 -map "[outv]" 映射一次;无标签输出的规则不同,见Filter 篇。

按语言标签选择

语言是元数据,不是所有文件都有,也不保证都用同一套代码。官方支持按元数据匹配:

Terminal window
ffmpeg -i input.mkv -map 0:m:language:eng -c copy english.mkv

这会选中语言标签为 eng 的流,但不会自动区分音频还是字幕。同一语言两种都有时,先 ffprobe 看结果,再写成明确索引:

Terminal window
ffmpeg -i input.mkv -map 0:v:0 -map 0:a:1 -map 0:s:0? -c copy selected.mkv

chi、zho、zh 可能同时出现,以探测结果为准。

两个输入合成一个输出

视频来自输入 0,旁白来自输入 1:

Terminal window
ffmpeg -i video.mp4 -i narration.wav -map 0:v:0 -map 1:a:0 -c:v copy -c:a aac -b:a 192k -shortest output.mp4

输入编号按 -i 出现顺序从 0 开始。-shortest 在最短的输出流结束时停止,不会自动修好两个输入的起点延迟或音画同步。

一个输出对应一组映射

同一条命令生成视频文件和音频文件时,每个输出都要重新声明自己的映射和编码:

Terminal window
ffmpeg -i input.mkv -map 0:v:0 -c:v libx264 -an video.mp4 -map 0:a:0 -c:a aac -vn audio.m4a

第一个输出的 -map、-c 不会自动延续到第二个。输出文件是参数作用域的边界,第 05 篇会把这件事画清楚。

选择和处理不要混淆

Terminal window
ffmpeg -i input.mkv -map 0:v:0 -map 0:a:1 -c:v libx264 -c:a copy output.mkv

这条命令先挑选第一条视频和第二条音频,再分别决定视频重编码、音频复制。-c:v libx264 不会改已经选中的流。

要把选中的画面送进 scale、overlay 或多个 Filter 分支,先保持 -map 关系清楚,再看第 05 篇。输出仍缺轨道时,回到 ffprobe 检查 index、类型和语言标签。

依据:FFmpeg Stream selection 官方文档;FFmpeg -map 选项。