ffmpeg 使用指南

本文档翻译自: https://ffmpeg.org/ffmpeg.html 中间加入了部分笔者的个人理解。有翻译生硬之处,难登“信、达、雅”之境界。望读者不吝指正。

语法

1
ffmpeg [global_options] {[input_file_options] -i input_file} ... {[output_file_options] output_file} ...

概述

ffmpeg 是一个快速的音视频转换工具,它能在任意的采样率和视频大小之间转换并且获得高质量多态的过滤。

ffmpeg 根据 -i 选项读取任意数量的输入文件(普通文件、管道流、网络流、可抓取设备等等),将转换结果写入到指定的多个输出 文件。命令行参数中不能被解析为选项的所有参数都被视为一个输出文件名。

理论上讲,每个输入或输出文件都可以包含任意数量的多媒体流(视频、音频、字幕、附件及额外信息),但实际允许的多媒体流数量可能受限于转换格式。 通过 map 选项(参考流筛选章节)可自动地从某个输入文件的某个多媒体流映射到某个输出文件。

为了指定输入文件,你必须遵从从 0 开始的索引规律,第一个输入文件的索引为 0,第二个输入文件的索引为 1,以此类推。类似的,文件内的多媒体流也是从 0 开始计数,比如 2:3 指第三个输入文件的第四个多媒体流。

一般来说,参数选项都将应用于下一个文件。因此,命令行参数都顺序非常重要,你可以在命令行中多次使用同一个参数,将它用于不同的文件,每个参数都会应用于下一个输入或输出文件。除非是全局选项,它们必须在命令行中的最前面。

切勿混合使用输入和输出文件:首先指定输入文件选项,然后再指定输出文件选项。同样地,不要在不同文件间混合使用参数,所有的选项都只会应用于紧挨着它都下一个输入或输出文件。

  • 将输出文件的比特率置为 64 kbit/s:
    1
    ffmpeg -i input.avi -b:v 64k -bufsize 64k output.avi
  • 强制输出文件的帧率为 24 fps:

    1
    ffmpeg -i input.avi -r 24 output.avi
  • 强制输入文件(仅限于原始格式)的帧率为 1 fps,输出文件的帧率为 24 fps:

    1
    ffmpeg -r 1 -i input.m2v -r 24 output.avi

详细说明

ffmpeg 的转码过程可以用如下图表示:

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

ffmpeg 调用 libavformat库来读取输入文件,从中获得压缩数据包,如果输入文件为多个,ffmpeg 尝试在每一个有效的输入流中将它们同步并记录最小时间戳。

然后,压缩数据包传递给相应的流解码器,输出原始的未压缩的数据流(原始视频或者 pcm 音频……),这些数据流经过过滤后传递给相应的编码器,对其进行编码、压缩,最后将压缩数据包写入到输出文件。

过滤

在编码之前,ffmpeg 能通过 libavfilter库对原始音视频流进行过滤,多个过滤器构成了一幅过滤图,ffmpeg识别简单复杂的两种过滤图。

简单过滤

只有一种类型的输入和输出,如上图中,可在解码和编码之间插入一个简单过滤:

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

简单过滤根据每一个流的过滤选项(-vf-af)来配置,一个简单的视频过滤示例如下:

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

复杂过滤

当输入或输出为多个,或者输入和输出文件的媒体流类型不同时,不能对流进行简单地进行线性过程处理,这个过程如下图:

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

通过 -filter_complex 全局选项指定,-lavfi 等同于 -filter_complex.

流拷贝

流拷贝是提供给 -codec 选项的一种流筛选模式,它让 ffmpeg 跳过解码和编码步骤,因此它只有解复用步骤。流拷贝对于修改容器格式或容器级别的元数据是很实用的。

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

少了解码和编码步骤,拷贝过程是很快并且无损的。但是,受多种因素影响,在某些情况下它可能无法应用。流过滤因此也显然不可用,因为过滤必须工作于未压缩的原始数据上。

流筛选

ffmpeg 默认只从输入文件中选择一个同种流媒体类型(音频、视频、字幕等),将它们包装到输出文件中。基于如下标准,它挑选出最 的那个流:

  • 对于视频,它是最高分辨率的那个流;
  • 对于音频,它是通道数最大的那个流;
  • 对于字幕,它是第一个字幕流。
  • 如果有多个同类型流都符合标准,那么选择索引最小的那个流。

你可以通过 -vn/-an/-sn 等选项移除默认筛选的这些流,若要人工控制选择哪些流,可用 -map选项。

参数选项

所有数值选项,如果没有另外的规定,表示接受数字作为输入,其可以随后 SI单位 前缀之一的字符串,例如:KM,或G

如果i被附加在SI单位前缀,则完整的前缀将被解释为一个以 1024 (而非 1000 )为基数的二进制倍数的单元前缀,将 B 附加到SI单位后缀将乘以 8。这允许使用,例如:“KB”,“MIB”,“G”和“B”为数字后缀。

选项不带参数的布尔选项,并设置相应的值设置为 true, 它们可以通过与no的前缀选项名称设置为 false。例如使用-nofoo将设置名称为fooflalse的布尔选项。

流选择器

有些选项适用于每个媒体流,比如 bitratcodec。流选择器用于精确指定给定的选项适用于哪个流。

一个流选择器是一个字符串,它被追加到一个选项中并且用 :分隔,比如 -codec:a:1 ac3 包含流 a:1, 它匹配第二个音频流,因此,这个流选择器将在第二个音频流上采用 ac3编码器。

一个流选择器可以匹配多个流,因此选项将默认用于所有的流。比如 -b:a 128k将所有的音频流的比特率置为 128k。

一个空的流选择器匹配所有流,比如 -codec copy-codec:copy 将拷贝所有的流。

流选择器的形式有:

  • stream_index
    匹配中这个索引指代的流,比如,-threads:1 4将会把第二个流的线程数设置为 4.

  • stream_type[:stream_index]
    stream_type可以是:v or V for video, afor audio, sfor subtitle, dfor data, and tfor attachments。v 匹配所有的视频流,V之匹配没有附加图片、视频缩略图或者封面的视频流。如果指定了stream_index,那么它指定该stream_index 索引对应的那个流,否则,它匹配该类型的所有流。

  • p:program_id[:stream_index]
    If stream_index is given, then it matches the stream with number stream_index in the program with the id program_id. Otherwise, it matches all streams in the program.

  • stream_id or i:stream_id
    Match the stream by stream id (e.g. PID in MPEG-TS container).

  • m:key[:value]
    Matches streams with the metadata tag key having the specified value. If value is not given, matches streams that contain the given tag with any value.

  • u
    Matches streams with usable configuration, the codec must be defined and the essential information such as video dimension or audio sample rate must be present.
    Note that in ffmpeg, matching by metadata will only work properly for input files.

时间戳格式

1
[-][HH:]MM:SS[.m...]

或者

1
[-]S[.m...]

示例:55,12:03:45,23.189, 适用于 -t,-ss,-sseof,-t等选项。

常用选项

  • -f fmt (input/output)

    强制输入/输出的媒体格式。一般情况下,ffmpeg 会自动从输入文件中识别出媒体格式,并且从输出文件名后缀猜测出输出格式,因此,大多数情况下,不需要此选项。

  • -y (global)

    不提示,覆盖同名的输出文件。

  • -n (global)

    不准覆盖输出文件,如果存在同名文件,则立即退出程序。

  • -c[:stream_specifier] codec (input/output,per-stream)

  • -codec[:stream_specifier] codec (input/output,per-stream)

    ffmpeg -i INPUT -map 0 -c:v libx264 -c:a copy OUTPUT
    

    将所有视频流以 libx264 编码并且拷贝所有的音频流。
    对每个流,起作用的是最后一个-c选项。

    ffmpeg -i INPUT -map 0 -c copy -c:v:1 libx264 -c:a:137 libvorbis OUTPUT
    

    将拷贝所有的流,除了第二个视频流以 libx264 编码,第 138 个音频流以 libvorbis 编码。

  • -t duration (input/output)

    当用于输入选项(-i 之前),限制从输入文件中最多读取的时长。
    当用于输出选项(output_file 之前),当写入时长超过该时长时,将停止写入。
    -to-t不允许同时存在,-t优先。

  • -to position (output)

    指定在何时停止写入,必须以 ffmpeg 允许的时间格式表示。

  • -ss position (input/output)

    当用于输入选项时,定位到该文件的这个位置开始解码。
    当用于输出选项时,解码当前位置前面的媒体但是忽略这些输入直到读取到该时间戳。

  • -sseof position (input/output)

    -ss类似,但是相对于文件尾部而言,它是距离文件尾部的非正值,0 代表 EOF

    ffmpeg -sseof -00:06 -t 00:05 -i input output
    

    将从距离 input 末尾 6 秒的地方开始,解码 5 秒。

视频选项

  • -vframes number (output)

    指定输出多少视频帧,等同于-frames:v

  • -r[:stream_specifier] fps (input/output,per-stream)

    指定帧率 fps
    作为输入,忽略原有的时间戳并且用新生成的时间戳代替。

    它和用于某些输入媒体的格式如 image2v4l2-framerate 选项不同,如有疑问,请用 -framerate代替-r选项。

    作为输出,复制或丢弃某些帧以达到指定的帧率。

  • -s[:stream_specifier] size (input/output,per-stream)

    指定帧尺寸, w*hwxh

  • -aspect[:stream_specifier] aspect (output,per-stream)

    指定视频的显示宽高比,4:3, 16:9, 1.3333, 1.7777等。

  • -vn (output)

    不输出视频内容

  • -vcodec codec (output)

    指定视频编码器,等同于 -codec:v

音频选项

  • -aframes number (output)

    指定输出多少音频帧,等同于-frames:a

  • -ar[:stream_specifier] freq (input/output,per-stream)

    指定音频采样率。

  • -ac[:stream_specifier] channels (input/output,per-stream)

    指定音频声道数。

  • -an (output)

    不输出音频内容

  • -acodec codec (input/output)

    设置音频编解码器,等同于 -codec:a .

  • -sample_fmt[:stream_specifier] sample_fmt (output,per-stream)

    指定音频采样格式。

高级选项

  • -map [-]input_file_id[:stream_specifier][,sync_file_id[:stream_specifier]] | [linklabel] (output)

    指定一个或多个输入流作为输出源。
    每个输入流根据输入文件索引、输入文件id和输入流索引来标示。所有的索引从 0 开始。第一个 -map选项确定输出流 0, 第二个 -map 选项确定输出流 1, 以此类推。
    -符号表示不对该输入流进行映射。

示例:

  • 将第一个输入文件的所有流映射至输出:

    ffmpeg -i INPUT -map 0 -f FORMAT output
    ffmpeg -i INPUT -map 0 output.mp4
    
  • 假设你有一个输入文件,其中含有两个音频流,分别以0:0,0:1标示,只将第二个音频流输出:

    ffmpeg -i INPUT -map 0:1 out.wav
    
  • 选取输入文件 a.mov中第三个输入流,标示为0:2 ,和输入文件 b.mov 中第 7 个输入,流标示为1:6 ,将它们拷贝到输出文件out.mov

    ffmpeg -i a.mov -i b.mov -c copy -map 0:2 -map 1:6 out.mov
    
  • 从输入文件中选中所有的视频流和第三个音频流:

    ffmpeg -i INPUT -map 0:v -map 0:a:2 OUTPUT
    
  • 将所有流,除了第二个音频流,映射至输出:

    ffmpeg -i INPUT -map 0 -map -0:a:1 OUTPUT
    

音视频转换

  • 视频 ==> yuv

    ffmpeg -i 2.mp4 2.yuv
    ffmpeg -i input.mp4 -f rawvideo -vcodec rawvideo -pix_fmt yuv420p -s 1920x1080 -r 25 rawvideo.yuv
    
  • yuv ==> 视频

    必须指定输入的 yuv 分辨率 -s

    ffmpeg -s 320x240 -i 2.yuv -c:v mpeg4 output.mp4
    ffmpeg -f rawvideo -vcodec rawvideo -s 1920x1080 -r 25 -pix_fmt yuv420p -i inputfile.yuv -s 320x240 -c:v libx264  -qp 0 output.mp4
    
  • audio + yuv ==> 视频

    ffmpeg -i /tmp/a.wav -s 640x480 -i /tmp/a.yuv /tmp/a.mpg
    
  • 音频转换

    ffmpeg -i /tmp/a.wav -ar 22050 /tmp/a.mp2
    
  • 通过映射流,将输入同时编码成多种格式到不同输出:

    ffmpeg -i /tmp/a.wav -map 0:a -b:a 64k /tmp/a.mp2 -map 0:a -b:a 128k /tmp/b.mp2
    
  • 从视频中抽取图像

    foo.avi 中每一秒抽取一张大小为 320x240 的图像到 foo-001.jpeg, foo-002.jpeg

    ffmpeg -i foo.avi -r 1 -s 320x240 -f image2 foo-%03d.jpeg
    

    如果只想抽取指定数量的图像帧,可搭配使用 -vframes`-t-ss`等选项。

  • 根据图像序列生成视频

    ffmpeg -f image2 -framerate 12 -i foo-%03d.jpeg -s 480x240 foo.avi
    
  • 将多个 同类型 的输入媒体映射至输出

    ffmpeg -i test1.avi -i test2.avi -map 1:1 -map 1:0 -map 0:1 -map 0:0 -c copy -y test12.nut
    

    test1.avitest2.avi 的音视频流逆序映射至 test12.nt 。(注意:这不是拼接视频,用 ffplay 播放的话,可以看出只播放了前面的 test.avi 部分)

  • 从视频中生成 GIF

    ffmpeg -ss 00:10:00 -t 10 -i capx.mp4  -s 320x240  jilu.gif
    

拼接视频

前提条件

  • 视频图像尺寸一样

编码格式相同

  • protocol

    支持文件级别拼接(MPEG-1, MPEG-2 PS, DV),媒体类型必须一致。

    ffmpeg -i 'concat:input1|input2' -codec copy output

在 `OS X 10.11` 下 `ffmpeg 2.8.2` 用该方式拼接后,只有 `input1`  部分。
  • demuxer

    推荐使用此方法

    支持媒体流级别拼接,比 protocol 更灵活,可用于不同的媒体类型。

    1
    2
    3
    4
    5
    6
    $ cat mylist.txt
    file '/path/to/file1'
    file '/path/to/file2'
    file '/path/to/file3'

    $ ffmpeg -f concat -i mylist.txt -c copy output

编码格式不同

  • video filter
    适用于不同编码格式、不同媒体类型的文件拼接。

    1
    ffmpeg -i opening.mkv -i episode.mkv -i ending.mkv -filter_complex '[0:0] [0:1] [1:0] [1:1] [2:0] [2:1] concat=n=3:v=1:a=1 [v] [a]' -map '[v]' -map '[a]' output.mkv

参考

  1. https://ffmpeg.org/ffmpeg.html
  2. http://stackoverflow.com/questions/15778774/using-ffmpeg-to-losslessly-convert-yuv-to-another-format-for-editing-in-adobe-pr
  3. https://trac.ffmpeg.org/wiki/Concatenate
彦祖老师 wechat