FFmpeg 媒体处理规则示例 | 青训营

92 阅读4分钟

假设现在有 3 个输入文件,分别是:

input file 'A.avi'
      stream 0: video 640x360
      stream 1: audio 2 channels

input file 'B.mp4'
      stream 0: video 1920x1080
      stream 1: audio 2 channels
      stream 2: subtitles (text)
      stream 3: audio 5.1 channels
      stream 4: subtitles (text)

input file 'C.mkv'
      stream 0: video 1280x720
      stream 1: audio 2 channels
      stream 2: subtitles (image)

1: 自动流选择

ffmpeg -i A.avi -i B.mp4 out1.mkv out2.wav -map 1:a -c:a copy out3.mov

这条命令指定了三个输出文件,前两个没有-map选项,因此 ffmpeg 会自动为这两个文件选择流。

输出 1.mkv 是一个 Matroska 容器文件,接受视频、音频和字幕流,因此 ffmpeg 将尝试选择每种类型之一。

  • 对于视频,它将选择B.mp4中的 stream 0,因为它在所有输入视频流中具有最高分辨率。
  • 对于音频,它将选择B.mp4 中的 stream 3,因为它拥有最多的通道。
  • 对于字幕,它将选择B.mp4 中的 stream 2,这是A.aviB.mkv 中的第一个字幕流。

输出2.wav仅接受音频流,因此只有来自 B.mp4 中的 stream 3 被选中。

对于输出3.mov,由于设置了 -map 选项,因此不会发生自动流选择。该-map 1:a选项将从第二个输入(即 B.mp4)选择所有音频流。此输出文件中不会包含其他流。

对于前两个输出,所有包含的流都将被转码。选择的编码器将是每个输出格式注册的默认编码器,它可能与所选输入流的编解码器不匹配。

对于第三个输出,音频流的编解码器选项已设置为 copy,因此不会发生或可能发生解码-过滤-编码操作。所选流的数据包应从输入文件传送并在输出文件中复用。

2: 自动的字幕流选择

ffmpeg -i C.mkv out1.mkv -c:s dvdsub -an out2.mkv

这条命令中,虽然 out1.mkv 是一个接受字幕流的 Matroska 容器文件,但是只有音频流和视频流会被选择。因为 mkv 封装格式的字幕是基于图像的,而 Matroska 复用器注册的默认字幕编码器则是基于文本的,对于该字幕流的转码操作预计会失败,因此该字幕流不会被选择。然而,在 out2.mkv 中通过 -c:s 选项设置了字幕编码器为 dvdsub,所以除了视频流以外还选中了字幕流。-an 选项的存在禁止了为 out2.mkv 自动选择音频流。

3: 无标签流的输出

ffmpeg -i A.avi -i C.mkv -i B.mp4 -filter_complex "overlay" out1.mp4 out2.srt

这条命令通过 -filter_complex 选项设置了全局的过滤图,仅有一个视频过滤器 overlay 构成。overlay 过滤器需要两个视频流作为输入,但是这里没有指定,因此在 A.aviB.mp4C.mkv中选择前两个可用的视频流。overlay 过滤器的输出流是无标签流,所以它的输出流将被复用到第一个文件 out1.mp4。同时,无标签流的存在使得视频流的自动选择过程被跳过(本来应该选择分辨率最高的B:stream0作为视频流输出)。根据自动流选择的规则,B:stream3 被选作音频输出流,字幕输出流未选择(因为 MP4封装格式没有注册默认的字幕编码器,命令中也没有手动设置字幕编码器)。

第二个输出文件 out2.srt 是文本字幕格式,因此自动流选择过程选择了 B:stream2 复用到 out2.srt

4: 带标签流的输出

ffmpeg -i A.avi -i B.mp4 -i C.mkv -filter_complex "[1:v]hue=s=0[outv];overlay;aresample" \
       -map '[outv]' -an        out1.mp4 \
                                out2.mkv \
       -map '[outv]' -map 1:a:0 out3.mkv

上述这条命令会失败,因为 [outv] 输出流被映射了两次。所有输出文件都不会被处理。

ffmpeg -i A.avi -i B.mp4 -i C.mkv -filter_complex "[1:v]hue=s=0[outv];overlay;aresample" \
       -an        out1.mp4 \
                  out2.mkv \
       -map 1:a:0 out3.mkv

这条命令也会失败,因为 hue 过滤器的带标签输出流 [outv] 没有被映射。要记住复杂过滤图是一个全局选项,所以前面的命令应该这样修改:

ffmpeg -i A.avi -i B.mp4 -i C.mkv -filter_complex "[1:v]hue=s=0,split=2[outv1][outv2];overlay;aresample" \
        -map '[outv1]' -an        out1.mp4 \
                                  out2.mkv \
        -map '[outv2]' -map 1:a:0 out3.mkv

来自 B.mp4 的视频流将被发送到 hue 过滤器,它的输出流会被复制成两份 [outv1][outv2],它们两个流分别被复用到 out1.mp4out3.mkv

overlay 从没有使用过的流中接收前两个视频流作为输入,即:A.aviC.mkv 中的视频流。overlay 的输出流是无标签流,所以不管是否有 -map 选项存在都将被复用到 out1.mp4

aresample 过滤器也是选择第一个未使用的音频流(即 A.avi),他的输出也是一个无标签流 ,将被复用到第一个输出文件 out1.mp4=an 选项的存在只是禁用了输入流的自动选择过程,作为过滤图的输出流还是不受该选项的影响。overlayaresample 的两个无标签输出流都会排在手动映射的 [outv1] 之前被复用到 out1.mp4

out2.mkv 这个输出文件没有设置任何选项,所以进行完全的自动流选择。

out3.mkv 则包含两个 -map 选项所指定的 [outv2] 流和 B:stream3 的音频流。