rakulang, dartlang, nimlang, golang, rustlang, lang lang no see

FFmpeg

焉知非鱼

FFmpeg

概要 #

ffmpeg [global_options] {[input_file_options] -i input_url} ... {[output_file_options] output_url} ...

描述 #

ffmpeg 是一款非常快速的视频和音频转换器,它还可以从实时音频/视频源中抓取。它还可以在任意采样率之间进行转换,并通过高质量的多相滤波器在飞行中调整视频大小。

ffmpeg 从任意数量的输入"文件"(可以是常规文件、管道、网络流、抓取设备等)中读取,由 -i 选项指定,并写入任意数量的输出"文件",由一个普通的输出 url 指定。在命令行中找到的任何不能被解释为选项的东西都被认为是一个输出 url。

原则上,每个输入或输出 url 可以包含任意数量的不同类型的流(视频/音频/字幕/附件/数据)。允许的流的数量和/或类型可能受到容器格式的限制。选择哪些输入的流将进入哪些输出,可以自动完成,也可以使用 -map 选项完成(请参见流选择章节)。

要在选项中引用输入文件,您必须使用它们的索引(基于 0)。例如,第一个输入文件是 0,第二个是 1,等等。同样,一个文件中的流也用它们的索引来表示。例如,2:3 指的是第三个输入文件中的第四个流。也请参见流指定符一章。

一般来说,选项会应用到下一个指定的文件。因此,顺序是很重要的,您可以在命令行中多次出现同一个选项。每次出现都会被应用到下一个输入或输出文件。这条规则的例外是全局选项(例如 verbosity level),应该先指定。

不要混合输入和输出文件-首先指定所有输入文件,然后再指定所有输出文件。也不要混合属于不同文件的选项。所有选项只适用于下一个输入或输出文件,并在文件之间被重置。

  • 要将输出文件的视频比特率设置为 64 kbit/s:
ffmpeg -i input.avi -b:v 64k -bufsize 64k output.avi
  • 要强制输出文件的帧率为24帧/秒:
ffmpeg -i input.avi -r 24 output.avi
  • 强制输入文件的帧率(仅对原始格式有效)为1帧/秒,输出文件的帧率为24帧/秒:
ffmpeg -r 1 -i input.m2v -r 24 output.avi

原始输入文件可能需要格式选项。

详情描述 #

ffmpeg 中每个输出的转码过程可以用下面的图来描述:

 _______              ______________
|       |            |              |
| input |  demuxer   | encoded data |   decoder
| file  | ---------> | packets      | -----+
|_______|            |______________|      |
                                           v
                                       _________
                                      |         |
                                      | decoded |
                                      | frames  |
                                      |_________|
 ________             ______________       |
|        |           |              |      |
| output | <-------- | encoded data | <----+
| file   |   muxer   | packets      |   encoder
|________|           |______________|

ffmpeg 调用 libavformat 库(包含 demuxers)来读取输入文件,并从其中获取包含编码数据的数据包。当有多个输入文件时,ffmpeg 试图通过跟踪任何活动输入流上的最低时间戳来保持它们的同步。

编码后的数据包会被传递给解码器(除非为流选择了 streamcopy,详见下文)。解码器产生未压缩的帧(原始视频/PCM音频/…),这些帧可以通过过滤进一步处理(见下一节)。过滤后,这些帧被传给编码器,编码器对它们进行编码并输出编码数据包。最后,这些帧被传给 muxer,muxer 将编码后的数据包写入输出文件。

滤波 #

在编码之前,ffmpeg 可以使用 libavfilter 库中的过滤器处理原始音频和视频帧。ffmpeg 区分了两种类型的滤波图:简单和复杂。

简单的滤波图 #

简单的滤波图是指那些只有一个输入和输出的滤波图,两者类型相同。在上图中,它们可以通过简单地在解码和编码之间插入一个额外的步骤来表示:

 _________                        ______________
|         |                      |              |
| decoded |                      | encoded data |
| frames  |\                   _ | packets      |
|_________| \                  /||______________|
             \   __________   /
  simple     _\||          | /  encoder
  filtergraph   | filtered |/
                | frames   |
                |__________|

简单的滤波图是用 per-stream -filter 选项配置的(视频和音频分别用 -vf-af 别名)。例如,一个简单的视频滤波图可以是这样的:

 _______        _____________        _______        ________
|       |      |             |      |       |      |        |
| input | ---> | deinterlace | ---> | scale | ---> | output |
|_______|      |_____________|      |_______|      |________|

请注意,有些滤镜会改变帧的属性,但不会改变帧的内容。例如,上面例子中的 fps 过滤器改变了帧数,但没有触及帧内容。另一个例子是 setpts 过滤器,它只设置了时间戳,而在其他方面没有改变帧的内容。

复杂的滤波图 #

复杂的滤波图是那些不能简单地描述为应用于一个流的线性处理链的图。例如,当图形有一个以上的输入和/或输出时,或者当输出流类型与输入不同时,就会出现这种情况。它们可以用下图来表示:

 _________
|         |
| input 0 |\                    __________
|_________| \                  |          |
             \   _________    /| output 0 |
              \ |         |  / |__________|
 _________     \| complex | /
|         |     |         |/
| input 1 |---->| filter  |\
|_________|     |         | \   __________
               /| graph   |  \ |          |
              / |         |   \| output 1 |
 _________   /  |_________|    |__________|
|         | /
| input 2 |/
|_________|

复杂的滤波图是用 -filter_complex 选项配置的。注意这个选项是全局性的,因为复杂的滤波图,就其本质而言,不能明确地与一个单一的流或文件相关联。

-lavfi 选项相当于 -filter_complex

一个简单的例子是 overlay 滤波器,它有两个视频输入和一个视频输出,其中一个视频叠加在另一个视频上。它的音频对应的是 amix 滤波器。

流复制 #

流复制是通过向 -codec 选项提供 copy 参数来选择的模式,它使 ffmpeg 省略了对指定流的解码和编码步骤,因此它只做解复用(demuxing)和混叠(muxing)。它对于改变容器格式或修改容器级元数据非常有用。上面的图,在这种情况下,会简化成这样:

 _______              ______________            ________
|       |            |              |          |        |
| input |  demuxer   | encoded data |  muxer   | output |
| file  | ---------> | packets      | -------> | file   |
|_______|            |______________|          |________|

由于不需要解码或编码,所以速度非常快,而且没有质量损失。但是,由于很多因素的影响,在某些情况下可能无法工作。应用过滤器显然也是不可能的,因为过滤器是在未压缩的数据上工作的。

流选择 #

ffmpeg 提供了 -map 选项来手动控制每个输出文件的流选择。用户可以跳过 -map 选项,让 ffmpeg 执行自动流选择,如下所述。-vn / -an / -sn / -dn 选项可以分别用来跳过视频、音频、字幕和数据流,无论是手动映射还是自动选择,但那些复杂的滤波图输出的流除外。

描述: #

下面的小节描述了涉及到流选择的各种规则。接下来的例子将展示这些规则是如何在实践中应用的。

虽然我们尽力准确地反映了程序的行为,但 FFmpeg 仍在不断地开发中,代码可能会在写这篇文章的时候有所改变。

自动选择流 #

在没有任何特定输出文件的映射选项的情况下,ffmpeg 会检查输出格式,以检查哪些类型的流可以被包含在其中,即视频、音频和/或字幕。对于每一种可接受的流类型,ffmpeg 将从所有输入中选择一个可用的流。

它将根据以下标准选择该流:

  • 对于视频,它是最高分辨率的流,
  • 对于音频来说,它是拥有最多通道的流,
  • 对于字幕,它是第一个找到的字幕流,但有一个注意事项。输出格式的默认字幕编码器可以是基于文本的,也可以是基于图像的,而且只会选择相同类型的字幕流。

在几个相同类型的流速率相同的情况下,会选择指数最低的流。

数据流或附件流不会被自动选择,只能使用 -map 来包含。

手动选择流 #

当使用 -map 时,只有用户映射的流才会被包含在该输出文件中,下面描述的滤波图输出可能是一个例外。

复杂的滤波图 #

如果有任何复杂的滤波图输出流带有未标记的填补(pad),它们将被添加到第一个输出文件中。如果流类型不被输出格式支持,这将导致一个致命的错误。在没有 map 选项的情况下,包含这些流会导致自动选择流的类型被跳过。如果存在 map 选项,这些滤波图流会被包含在映射流之外。

带有标签填补的复杂滤波图输出流必须被映射一次,而且是精确地映射一次。

流处理 #

流处理是独立于流选择的,下面描述的字幕除外。流处理是通过针对特定输出文件中的流的 -codec 选项来设置的。特别是,编解码器选项是在流选择过程之后由 ffmpeg 应用的,因此不会影响后者。如果没有为某个流类型指定 -codec 选项,ffmpeg 将选择输出文件 muxer 注册的默认编码器。

字幕存在一个例外。ffmpeg 不会验证指定的编码器是否可以转换所选的流,也不会验证转换后的流是否可以在输出格式中接受。这通常也适用于:当用户手动设置编码器时,流选择过程不能检查编码后的流是否能被混入输出文件中。如果不能,ffmpeg 将中止,所有的输出文件将无法被处理。

示例 #

下面的例子说明了 ffmpeg 流选择方法的行为、怪癖和限制。

它们假设以下三个输入文件:

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)