11 2014
20

FFmpeg实用命令
2014年11月20日

FFmpeg是一个开源免费跨平台的视频和音频流方案,属于自由软件。 别看这东西只有几十Mb,但却是个能格式转换、剪辑、播放几乎无所不能的命令行软件。 就如格式工厂,其核心也是FFmpeg。 在专业领域常被部署在服务端,用以做云端视频相关服务。 如七牛云存储就是利用FFmpeg来完成各种格式转换的。 其官方网址为:FFmpeg.org。 在那里可以下载到各种主流电脑平台的FFmpeg程序。

FFmpeg主要包含四个程序:

  • ffmpeg 主要用于对媒体文件的内容进行操作,如格式转换等,是最主要的部件
  • ffplay 简易播放器,虽然没有什么UI,但是能播放各种格式的视频
  • ffprobe 用于探查媒体文件的属性,如meta标签等,可以选择输出JSON或XML格式
  • ffserver 流媒体服务器,不可多得的免费流媒体服务器软件,可用于架设视频直播

FFmpeg除了提供可运行程序,还提供一套libav多媒体处理C库,可集成到别的软件当中提供多媒体文件解码、编码等功能。

对于一些比较专业的命令,本文也不会过多叙述,因为那需要更多的多媒体文件基础知识才能理解。 另外注意,这里讲的是正统的FFmpeg,而不是Debian搞出来的分支LibAV,里面那个ffmpeg(Ubuntu内置的)。

视频篇

以下命令主要针对视频文件操作

格式转换

ffmpeg最常用功能就是格式转换,在这里要特别提的是,音、视频文件格式有两个容器格式(如mov、flv)与编码格式(如H.264)。 很多人知道前者,却不知道后者,二者的关系与异同可在别处查到,不在此赘述。 简单的格式转换如下:

ffmpeg -i input.flv output.mp4

上面的命令就把一个flv文件转换成了一个mp4文件,其中-i xxx.xxx指定的输入文件,单独写的文件名指定输出文件路径。

一般FFmpeg会根据文件格式选择最合适的容器格式与编码格式,也可以手动指定。 常见的用例是需要一个保留alpha通道的视频,通常会使用mov容器格式,png编码格式,但是FFmpeg会默认使用H.264编码格式(不支持透明)。 如此命令如下:

ffmpeg -i input.flv -c:v png output.mov

想要知道自己的FFmpeg都支持哪些容器格式,使用命令ffmpeg -formats。 看都支持哪些编码格式,使用命令ffmpeg -codecs

特别强调,如果处理文件不是图片,不要让输入与输出文件相同

尺寸变换

想把大而高清的视频,变成尺寸较小,文件大小也更小的视频也是个普遍用例。 下面这个命令就可以完成改变尺寸的任务,对图片文件也有效。

ffmpeg -i input.mp4 -s 640x360 output.mp4

上面的命令由-s 640x360定义了输出视频的画面尺寸会是640x360。

剪切

只想取视频的某一部分也有很方便的命令:

ffmpeg -i input.mp4 -ss 5 -t 10 output.mp4

上面的命令-ss 5指定从输入视频第5秒开始截取,-t 10指明最多截取10秒。 但是上面的命令可能会比较慢,更好的命令如下:

ffmpeg -ss 5 -i input.mp4 -t 10 -c:v copy -c:a copy output.mp4

上面的命令把-ss 5放到-i前面,与原来的区别是,这样会先跳转到第5秒在开始解码输入视频,而原来的会从开始解码,只是丢弃掉前5秒的结果。 而-c:v copy -c:a copy标示视频与音频的编码不发生改变,而是直接复制,这样会大大提升速度,因为这样就不需要完全解码视频(视频剪切也不需要完全解码)。

图片序列与视频的互相转换

ffmpeg可以把一组图片转换成一个视频(可以把gif动画也当成一种视频格式),反之亦可。命令如下

ffmpeg -i %04d.jpg output.mp4
ffmpeg -i input.mp4 %04d.jpg

第一行命令是把0001.jpg、0002.jpg、0003.jpg等编码成output.mp4,第二行则是相反把input.mp4变成0001.jpg……。 %04d.jpg表示从1开始用0补全的4位整数为文件名的jpg文件序列。 如果想要序列文件名为hello_00001.png等等的话,就是hello_%05d.png

如果编码视频的时候还想加入声音,则如下这般添加一个输入文件:

ffmpeg -i input.mp3 -i %04d.jpg output.mp4

改变视频FPS

FFmpeg可以用于降低或提高视频的帧率,因为信息丢失不可逆法则,提高帧率只会简单地让某些帧的画面多重复一次或多次,所以提高帧率不会提高画质。

ffmpeg -i input.mp4 -r 30 output.mp4

上面的命令,不论原始视频帧率是多少,输出视频都会是30帧每秒。这种情况之下视频的时间轴不会变化,不会有慢动作或快动作的效果。

ffmpeg -r 30 -i input.mp4 output.mp4

上面这种条换顺序之后的写法比较有意思,-r 30放在输入文件之前表示影响的时输入文件,而非输出文件。 这样的命令表达的是,把输入文件当做30帧每秒,而忽略它的原始帧率。这样如果原来的视频FPS是25,被视作30之后,输出的视频会有快进的效果。 这个命令没有指定输出视频的FPS,默认会与输入文件保持一样,可以与本节第一个命令和在一起,写两个-r参数,第一个指定输入FPS,第二个指定 输出FPS即可既控制播放速度,又控制输出帧率。

H264视频首尾拼接

如果确定输入文件都是H264编码,且尺寸、帧率等都相同,先把源视频转换成用于直播的ts格式。 然后直接对多个ts文件进行文件级的拼接,然后在转换回到目标格式。这个过程中,不会发生格式转换,所以非常迅速。

ffmpeg -i q.mp4 -c copy -bsf h264_mp4toannexb q.ts
ffmpeg -i r.mp4 -c copy -bsf h264_mp4toannexb r.ts
ffmpeg -i "concat:q.ts|r.ts" -c copy -bsf aac_adtstoasc qr.mp4

音频篇

以下命令主要用于音频操作。有许多上面已经给出的视频操作,比如格式转换,剪切等也可适用于音频。大部分视频也都包含音频,所以下面的命令 往往可以与视频命令混合适用。

提取音乐中的封面图片

有些音乐文件包含专辑封面图片在里面,可以用如下命令简单取出。命令从字面意义来讲,就是把MP3格式转换成JPEG格式了。

ffmpeg -i input.mp3 cover.jpg

音乐有损压缩

在某些场合下,比如在给网站做背景音乐,或音乐网站提供预览版音乐时,会选择以牺牲音频质量为代价降低文件大小,让网络播放更顺畅。 一个典型的压缩命令如下:

ffmpeg -i input.mp3 -ac 1 -ar 32k -bit_rate:a 128k output.mp3

上面命令做了三件事情:

  • -ac 1 指定只保留一个声道,所有声道都融合成一个(这里有个FFmpeg的bug,输出音量会变小)。
  • -ar 32k 表示采样率改为32000,通常的高保真音频都是48K左右,这个数值变小,会裁剪掉高音部分,32K会裁掉不少高音,不过普通人如果没个对比,听不出什么问题。 如果音频文件不是音乐,而是人声内容(比如广播),则可以打手一挥设置成22k或16k(电话是16k)
  • -bit_rate:a 128k设置的时音频比特率,如果是-bit_rate:v就成了视频比特率,128K表示,输出文件大概每秒钟的内容会有16KB左右的文件大小,需要至少128kbps的网络才能流畅播放 128K算是比较理想的比特率,文件小,音频质量损失又不是特别明显(对于普通人)

苹果系统的问题

经过FFmpeg处理的音频文件,在苹果的系统(包括OSX、iOS)以及苹果的播放器(iTunes、QuickTime)上往往会显示错误的长度时间。 这是个FFmpeg潜在的Bug,不过可以通过添加参数规避:

ffmpeg -i input.mp3 -write_xing 0 .... output.mp3

这样输出的文件在苹果产品上就会表现正常。原先不正常的文件,亦可以使用这个参数再经过一次ffmpeg处理来解决长度问题。

ffplay

ffplay是FFmpeg家族中的一个媒体文件播放器,可以播放许多种格式,不过与其说它是个完整的播放器,不如说这是个DEMO程序, 用来演示如何使用FFmpeg提供的解码接口来做播放器。它的命令很简单,通常播放一个正常的媒体文件只需要如下

ffplay target.mp4

ffplay可以接受参数,相当于ffmpeg程序里-i之前的参数,用来改变输入文件的输入方式,比如通过改变FPS造成快进或慢镜头的效果。

ffprobe

ffprobe可以非常方便地用于检测媒体文件的一些隐藏信息,通常只有更深层次的专业人员才会用到。一个典型的命令如下:

ffprobe target.mp4 -show_format -show_streams -print_format json -loglevel fatal