https://ffmpeg.org/ffmpeg.html
1 Synopsis
ffmpeg [global_options] \
{[input_file_options] -i input_url} ... \
{[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文件,并且会在下个文件处重置。
# 把输出视频的比特率设置为64kbit/s
ffmpeg -i input.avi -b:v 64k -bufsize 64k output.avi
# 将输出视频的帧率固定在24fps
ffmpeg -i input.avi -r 24 output.avi
# 将输入的帧率固定在1fps(只有对raw format有效),并将输出的帧率固定在24fps
ffmpeg -r 1 -i input.m2v -r 24 output.avi
只有row input file才需要指定format option。
3 Detailed description
ffmpeg的转码流程可以用下图描述:
_______ ______________
| | | |
| input | demuxer | encoded data | decoder
| file | ---------> | packets | -----+
|_______| |______________| |
v
_________
| |
| decoded |
| frames |
|_________|
________ ______________ |
| | | | |
| output | <-------- | encoded data | <----+
| file | muxer | packets | encoder
|________| |______________|
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。
_________ ______________
| | | |
| decoded | | encoded data |
| frames |\ _ | packets |
|_________| \ /||______________|
\ __________ /
simple _\|| | / encoder
filtergraph | filtered |/
| frames |
|__________|
SImple filtergraph通过为每个stream指定-filter选项来配置(可以使用-vf和-af简写别名为video和audio指定filter)。一个vidoe的simple filtergraph可能看起来像下面这样:
_______ _____________ _______ ________
| | | | | | | |
| input | ---> | deinterlace | ---> | scale | ---> | output |
|_______| |_____________| |_______| |________|
注意一些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:
_________
| |
| input 0 |\ __________
|_________| \ | |
\ _________ /| output 0 |
\ | | / |__________|
_________ \| complex | /
| | | |/
| input 1 |---->| filter |\
|_________| | | \ __________
/| graph | \ | |
/ | | \| output 1 |
_________ / |_________| |__________|
| | /
| input 2 |/
|_________|
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后,被简化成下面这样:
_______ ______________ ________
| | | | | |
| input | demuxer | encoded data | muxer | output |
| file | ---------> | packets | -------> | file |
|_______| |______________| |________|
因为没有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
。