https://ffmpeg.org/ffmpeg.html

1 Synopsis

  1. ffmpeg [global_options] \
  2. {[input_file_options] -i input_url} ... \
  3. {[output_file_options] output_url} ...

2 Description

ffmpeg是高效音视频转换器,可用于处理在线音视频源。使用ffmpeg可以任意改变视频的sample rate和size,同时应用高质量的polyphase filter。
ffmepg从任意数量的输入“文件”(包括pope、network stream、grabbing device)读取输入,输入文件通过 -i 指定;然后将输出写到任意数量的输出“文件”,输出文件通过output url指定。一切无法被解析为输入文件或其他cmd option的都会被当作output url处理。
每个input/output url都可以包含任意数量、任意类型的不同的stream(video, audio, subtitle, attachment, data)。数量或类型受container format限制。具体选择哪个输入文件的stream、输出到哪个输出文件,要么是由ffmpeg自动决定的,要么是由 -map 选项指定的(参考 Stream Selection 章节)。
要引用cmd options中的input文件,必须指定它们的索引(作为一个C开发的库,索引自然是从0开始)。第一个输入文件通过 0 引用,第二个输入文件通过 1 引用。类似的,文件中的stream也是由索引指定的,如 2:3 用于指定第三个输入文件的第四个stream。
ffmpeg应用一个普遍的规则:options作用于下一个被指定的文件。因此命令参数和文件的顺序很重要,当需要为多个文件指定同样的option时就需要写多次option。global option属于这个规则的例外,必须在一开始指定。
不要将input和output文件混杂 - 首先指定input文件,然后指定output文件。同样也别把不同文件的option混杂。所有的option都仅作用于下一个input/output文件,并且会在下个文件处重置。

  1. # 把输出视频的比特率设置为64kbit/s
  2. ffmpeg -i input.avi -b:v 64k -bufsize 64k output.avi
  3. # 将输出视频的帧率固定在24fps
  4. ffmpeg -i input.avi -r 24 output.avi
  5. # 将输入的帧率固定在1fps(只有对raw format有效),并将输出的帧率固定在24fps
  6. ffmpeg -r 1 -i input.m2v -r 24 output.avi

只有row input file才需要指定format option。

3 Detailed description

ffmpeg的转码流程可以用下图描述:

  1. _______ ______________
  2. | | | |
  3. | input | demuxer | encoded data | decoder
  4. | file | ---------> | packets | -----+
  5. |_______| |______________| |
  6. v
  7. _________
  8. | |
  9. | decoded |
  10. | frames |
  11. |_________|
  12. ________ ______________ |
  13. | | | | |
  14. | output | <-------- | encoded data | <----+
  15. | file | muxer | packets | encoder
  16. |________| |______________|

ffmpeg使用libavformat库(包含demuxer)读取输入文件并获取包含encoded data的packet。当存在多个input file时,ffmpeg会尝试通过追踪最小时间戳来对它们进行同步。
encoded packet随后被传入decoder(除非为stream选择了streamcopy,见后面的描述)。decoder生成原始未压缩的帧(raw video/PCM audio/…),可以通过filter进行进一步的处理(见下一节)。在filter之后,frame被传入encoder,被编码成encoded packet输出。最终这些packet会被送入muxer,把encoded packet写入output file。

3.1 Filtering

在encoding之前,ffmpeg会使用libavfilter库的filter对原始音频或视频帧进行处理。多个filter可以串联起来组成一个filter图。ffmpeg定义了两种filtergraph:simple, complex.

3.1.1 SImple filtergraph

Simple filtergraph有一个输入和输出,并且类型都一样。能够在encoding和decoding之间直接插入的filtergraph就是simple filtergraph。

  1. _________ ______________
  2. | | | |
  3. | decoded | | encoded data |
  4. | frames |\ _ | packets |
  5. |_________| \ /||______________|
  6. \ __________ /
  7. simple _\|| | / encoder
  8. filtergraph | filtered |/
  9. | frames |
  10. |__________|

SImple filtergraph通过为每个stream指定-filter选项来配置(可以使用-vf和-af简写别名为video和audio指定filter)。一个vidoe的simple filtergraph可能看起来像下面这样:

  1. _______ _____________ _______ ________
  2. | | | | | | | |
  3. | input | ---> | deinterlace | ---> | scale | ---> | output |
  4. |_______| |_____________| |_______| |________|

注意一些filter会改变frame属性而不是frame内容。例如,fps filter会改变帧率,但并不会改变任何一帧的内容。另一个例子是setpts filter,它只会设置timestamp或者将frame保持原样。

3.1.2 Complex filtergraph

Complex filtergraph是无法由上面的针对某个stream的线性simple filtergraph表示的filtergraph。当一个filtergraph有多个输入或输出,或者输入和输出类型不同,那么它就是一个complex filtergraph。下图就是一个complex filtergraph:

  1. _________
  2. | |
  3. | input 0 |\ __________
  4. |_________| \ | |
  5. \ _________ /| output 0 |
  6. \ | | / |__________|
  7. _________ \| complex | /
  8. | | | |/
  9. | input 1 |---->| filter |\
  10. |_________| | | \ __________
  11. /| graph | \ | |
  12. / | | \| output 1 |
  13. _________ / |_________| |__________|
  14. | | /
  15. | input 2 |/
  16. |_________|

complex filtergraph是通过-filter_complex option来配置的。注意这个option是global的,毕竟complex filtergraph从定义上就是不是针对某一个特定文件或流的。
-lavfi和-filter_complex是等价的。
一个complex filtergraph的基础例子是overlay filter,它有两个video input和一个video output,output是一个input video盖在另一个input video上的视频。和overlay对应的audio filter是amix filter。

3.2 Stream copy

stream copy是将copy作为参数提供给-codec option时的模式。ffmpeg为特定stream省略decoding和encoding过程,这个stream只会被demuxing和muxing。当需要改变封装格式,或者改变封装元数据时会用到。前面的ffmpeg处理流程在省略了decoding和encoding后,被简化成下面这样:

  1. _______ ______________ ________
  2. | | | | | |
  3. | input | demuxer | encoded data | muxer | output |
  4. | file | ---------> | packets | -------> | file |
  5. |_______| |______________| |________|

因为没有decoding和encoding,copy模式非常快速并且不会导致质量损失。然后某些情况下不可以使用copy模式,比如,当需要应用filter时,因为filter是作用在decoded frame上的,省略了decoding,就没有decoded frame。

4 Stream selection

ffmpeg提供-map option允许手动控制输出文件的哪些流是被选中的。省略-map可以让ffmpeg自动决定。-vn/-an/-sn/-dn选项分别用于指定在输出文件中略过video, audio, subtitle, data流,不论这些流是手工指定的还是自动选定的,只有complex filtergraph的输出流是不会被略过的。

4.1 Description

下面的章节描述和stream selection有关的各种规则。随后的例子展示规则如何被实际使用。
我们尽量保证代码的正确性,但ffmpeg正出于持续开发中,因此实际的代码可能在你看到这些文字时已经需要更新了。

4.1.1 Automatic stream selection

在不指定-map选项时,ffmpeg检查输出文件格式来确定哪些类型的流可以被输出,即video、audio、subtitles。对于每一个可选的stream类型,ffmpeg会从所有input的有效stream中选取一个stream:

  • 针对video,选取最高分辨率的stream;
  • 针对audio,选取拥有最多channel的stream;
  • 针对subtitle,选取第一个subtitle stream,不过有个额外的规则,output的默认subtitle encoder可能是text-based或者是image-based,只有和subtitle stream类型匹配的subtitle stream才会称为候选。

当存在多个无法分出胜负的候选时,索引小的胜出。
data或者attachment stream不会被自动选定,必须通过-map指定。

4.1.2 Manual stream selection

-map option存在时,只有用于指定的流会被包含在输出文件中,但针对filtergraph有个例外,参考下面的描述:

4.1.3 Complex filtergraphs

如果存在任何complex filtergraph output stream with unlabeled pads ,它们就会被加到第一个output file。如果output file的stream类型不匹配就会被错。当没有-map option时,complex filtergraph output会导致其他同类型的流被忽略,如果map option存在,filtergraph stream会和-map选项指定的流一块被包含到output file中。
complex filtergraph output stream如果有labeled pads,必须被map指定一次且仅指定一次。

4.1.4 Stream handling

Stream handling独立于stream selection,除了subtitle以外。通过-codec选项设置作用于某个output file的stream handling。具体来说codec选项在ffmpeg处理完stream selection流程后生效,并且仅针对后面的特定output file。如果没有通过-codec为某个stream类型指定stream handling,ffmpeg会使用otuput file muxer注册的默认encoder