FFmpeg是一个用于音视频处理的自由软件,被普遍用于音视频开发。FFmpeg功能强大,本文主要介绍如何使用FFmpeg命令行工具进行简单的视频处理。html
安装FFmpeg能够在官网下载各平台软件包或者静态编译版本,也可使用包管理工具安装。算法
容器shell
咱们熟悉的mp4
,rmvb
,mkv
,avi
是多媒体容器文件格式(或称多媒体封装格式),所谓容器是指将不一样的数据流(视频流,音频流,字幕流等)封装在一个文件(载体)中。json
播放时各类流分别进行解码等处理后,而后输出到显示器和音响等设备进行播放。多媒体容器格式不一样于编码格式,一个容器中能够封装多种编码格式的媒体流。bash
流封装了实际的媒体数据,如视频流,音频流和字幕流等。通常状况下,流中的数据只能使用一种编码格式。ide
帧率工具
帧率(frames per second, fps)是每秒画面刷新的次数,帧率越高视频越流畅。通常来讲30fps就是能够接受的,60fps则能够明显提高交互感和逼真感,可是通常超过75fps通常就不容易察觉到有明显的流畅度提高了。oop
分辨率布局
分辨率表示画面的精细程度,一般用像素密度来表示,经常使用的单位为ppi(像素每英寸)。一般像素密度越高画面越精细,模糊程度越低。性能
对于视频文件而言,像素密度是没法控制的(由播放器和显示设备决定)。咱们一般用视频的像素数来表示它的分辨率如1080x640, 640x320等。
比特率
比特率(bit rate)又称码率,表示多媒体流每秒输出的字节数,单位为KB/s, Kbps等。一样的压缩算法下,比特率越高音视频的质量越好。
可变码率(Variable Bitrate, VBR)指的是编码器的输出码率能够根据输入源信号的复杂度进行自适应调整,以在输出质量保持不变的条件下尽量减小数据量。VBR适用于存储,不太适用流式传输。
固定码率(Constant Bitrate, CBR)指的是编码器输出码率固定,CBR不适合存储,对于复杂内容可能没有足够码率进行编码,从而致使质量降低,同时会在简单内容部分浪费一些码率。
采样率
每秒钟对音频信号的采样次数,采样频率越高声音还原度越高,声音更加天然,单位是赫兹 Hz。
音频文件通常使用的采样率是 44.1 kHz,也就是一秒钟采样44100次,实验发现低于这个值就会有较明显的损失,而高于这个值人的耳朵已经很难分辨,并且增大了数字音频所占用的空间。
视频编码
视频流能够看作图片的序列,咱们把这个序列中的一张图片称为一帧。若存储视频中全部帧则会数据量过大,不便于存储和传输。
所幸统计代表大多数视频相邻帧之间的区别并不大,因此对于一段变化不大的视频,咱们能够先完整编码帧A,其后的B帧只须要编码与A帧不一样的部分,B帧后的C帧则只编码与B帧的差别。如此递推,将一段视频编码为一个序列。
当某个图像与以前的图像变化很大没法参考前面的帧来生成,咱们就结束上一个序列将该帧完整编码开始一个新的序列。
H264是目前流行的一种视频编码算法,它定义了三种帧:完整编码的I帧,参考I帧生成只包含差别的P帧,以及以及参考先后帧编码的B帧。
H264采用的核心算法是帧内压缩和帧间压缩,帧内压缩是生成I帧的算法,帧间压缩是生成B帧和P帧的算法。
一般,咱们也把完整编码的I帧称为关键帧。由于解码非关键帧须要解码其参考的帧,所以在截图等不须要所有解码的操做中,常常截取关键帧以提高性能。
ffprobe是FFmpeg项目提供的用于分析视频信息的命令行工具。
随意下载一个测试视频testmp4
, 而后终端中输入指令:
ffprobe -v quiet -print_format json -show_format -show_streams test.mp4
能够得到json格式输出的视频信息:
{ "streams": [ // 文件中包含的流 { "index": 0, // 流的序号 "codec_name": "h264", // 流的编码格式 "codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10", // 编码格式的全名 "profile": "High", "codec_type": "video", // video表示这是一个视频流 "codec_time_base": "1/60", "codec_tag_string": "avc1", "codec_tag": "0x31637661", "width": 1080, // 视频宽为1080像素 "height": 614, // 视频高为614像素 "coded_width": 1080, "coded_height": 614, "has_b_frames": 2, "sample_aspect_ratio": "0:1", "display_aspect_ratio": "0:1", "pix_fmt": "yuv420p", "level": 31, "chroma_location": "left", "refs": 1, "is_avc": "true", "nal_length_size": "4", "r_frame_rate": "30/1", // 实际帧率 "avg_frame_rate": "30/1", "time_base": "1/15360", "start_pts": 0, "start_time": "0.000000", "duration_ts": 153093, "duration": "9.966992", // 以秒为单位的视频时间 "bit_rate": "2077265", // 视频的比特率 "bits_per_raw_sample": "8", "nb_frames": "299", "tags": { // 流中的附加信息,其中的字段可能为空 "rotate": 90, // 视频旋转的角度 "language": "und", "handler_name": "VideoHandler" } }, { "index": 1, // 流编号 "codec_name": "aac", // 流的编码格式 "codec_long_name": "AAC (Advanced Audio Coding)", // 编码格式的全名 "profile": "LC", "codec_type": "audio", // 这是一个音频流 "codec_time_base": "1/44100", "codec_tag_string": "mp4a", "codec_tag": "0x6134706d", "sample_fmt": "fltp", "sample_rate": "44100", // 采样率 "channels": 2, // 声道数 "channel_layout": "stereo", // 声道布局,stereo为立体双声道 "bits_per_sample": 0, "r_frame_rate": "0/0", "avg_frame_rate": "0/0", "time_base": "1/44100", // 每帧时长 "start_pts": 0, "start_time": "0.000000", // 流开始播放时间 "duration_ts": 442367, "duration": "10.030998", // 流时长 "bit_rate": "129341", // 比特率 "max_bit_rate": "129341", "nb_frames": "433", "tags": { "language": "und", "handler_name": "SoundHandler" } } ], "format": { // 容器信息 "filename": "test.mp4", // 文件名 "nb_streams": 2, "nb_programs": 0, "format_name": "mov,mp4,m4a,3gp,3g2,mj2", // 封装格式名 "format_long_name": "QuickTime / MOV", "start_time": "0.000000", "duration": "10.055000", "size": "2762615", // 文件字节数 "bit_rate": "2198002", // 比特率 "probe_score": 100, "tags": { "major_brand": "isom", "minor_version": "512", "compatible_brands": "isomiso2avc1mp41", "encoder": "Lavf57.71.100" } } }
示例中使用-v quiet
选项将日志级别设为quiet
避免日志信息污染json,-show_format
显示文件的容器信息,-show_stream
显示容器中流的信息,-show_frames
则能够显示视频中每一帧的信息。
更多关于ffprobe的内容能够参考官方文档
ffmpeg的命令格式:
ffmpeg \ [global_options] \ [input_file_options] -i input_url \ [actions] \ [output_file_options] output_url
咱们能够将ffmpeg的选项分为全局选项和局部选项,局部选项用于设置输入输出或者滤镜等,一般位于被修饰的指令前面。
ffmpeg的基本流程为将容器中的各流进行解码,而后从新编码为指定的格式。在编码以前,可使用filter对视频进行处理。
选项的详细内容请参考官方文档
-y
/ -n
-y
/-n
为全局选项, -y
表示直接覆盖已经存在的输出文件, -n
表示若某个输出文件已经存在则退出。
若没有设置-y
或-n
选项,且某个输出文件已经存在ffmpeg会询问是否要覆盖输出文件。
ffmpeg -y -i test.mp4 test.mkv
-codec
(-c
)指定输入输出的解码编码器, 可用的编解码器能够参考官方文档:
fmpeg -y -i test.mp4 -c:v libx264 -c:a copy test.mov
codec指定为copy
则将输入流直接复制到输出流不进行编解码操做。
使用-c:STREAM_INDEX
方式能够指定某一个流的解码器,STREAM_INDEX
为stream对象的index属性。
-c:v
或-vcodec
能够为全部视频流指定编码器,-c:v:1
为第2个视频流指定编解码器。
-c:a
或-acodec
能够为全部音频流指定编码器,-c:a:12
为第13个视频流指定编解码器。
-ss
-ss
选项用于设置流的开始时间,能够设置输入输出或者滤镜。在开始时间以前的帧将被跳过不被处理(输入不被解码,输出不被编码,滤镜不被处理)。
ffmpeg -ss 2 -t 10 -i test.mp4 test.mov
时长有两种方式来表示:
-t 10
, -t 23.167
-t 10:23
, -t 21:31:00.233
-t
-t
选项用于用于设置输入输出,-t
在-i
前能够限制输入时长,-t
在输出文件前能够限制输出时长。
读入test.mp4文件2s开始10s内的数据,转码后输出到test.mov:
ffmpeg -ss 2 -t 10 -i test.mp4 test.mov
读入test.mp4所有数据,所有转码后输出从第2s开始1min10s内的数据到test.mov:
ffmpeg -i test.mp4 -ss 2 -t 01:10 test.mov
-to
-to
选项相似于-t
选项,不一样的是-to
指定结束时刻,-t
指定持续时间。
读入test.mp4文件2s到12s内的数据,转码后输出到test.mov:
ffmpeg -ss 2 -to 12 -i test.mp4 test.mov
读入test.mp4所有数据,所有转码后输出从01:00到01:30内的数据到test.mov:
ffmpeg -i test.mp4 -ss 01:00 -to 01:30 test.mov
-f
强制设置输入输出的文件格式,默认状况下ffmpeg会根据文件后缀名判断文件格式。
ffmpeg -formats
命令会显示全部支持的编码格式。
-filter
/ -filter_complex
使用过滤器对流进行处理,下文将简要介绍filter的相关内容。
可使用-vf
代替-filter:v
处理视频流, -af
代替-filter:a
处理音频流。
-vframes
设置输出文件中包含的总帧数:
ffmpeg -i test.mp4 -vframes 1 test.mov
-vn
不将视频流写到输出文件中
ffmpeg -i test.mp4 -vn -a:c copy out.mp3
-r
设置某个流的帧率:
ffmpeg -i test.mp4 -r:v 30 test.mov
-s
设置帧的大小:
ffmpeg -i test.mp4 -s 1080x680 out.mp4
-an
不将音频流写到输出文件中:
ffmpeg -i test.mp4 -v:c copy -an out.mp4
-threads
设置处理线程数:
ffmpeg -threads 8 -i test.mp4 out.mp4
能够设置处理
-shortest
当最短的输入流结束后即中止编码和输出。
ffmpeg -i bgm.mp3 -i test.mp4 -shortest output.mp4
过滤器会对已解码的帧进行处理,处理后的帧会被从新编码输出,整个流程能够归纳为:
Input -> DecodedFrames -> FilteredFrames -> EncodedData
简单过滤器是单输入单输出的(只能处理一个流),而复杂过滤器(filter_complex)是多输入多输出的能够进行更复杂的操做。
ffmpeg支持的各类滤镜能够参考官方文档-滤镜。
ffmpeg -y -i test.mp4 -vf "scale=2*in_w:2*in_h" test.mov
scale滤镜用于缩放视频, in_w
和in_h
表明输入的宽和高。
ffmpeg -y -i test.mp4 -vf "crop=w=100:h=100:x=in_w/2:y=in_h,scale=400:400" test.mov
crop滤镜用于截取视频中的一个区域。
ffmpeg -y -i test.mp4 -i logo.png -filter_complex 'overlay=10:main_h-overlay_h-10' out.mp4
overlay滤镜将一个视频叠放在另外一个视频上,可用于在视频中添加水印和动画等操做。
overlay的第一个输入为底层视频流,第二个输入为叠加视频流。main_w
和main_h
为底层视频的宽和高,overlay_w
和overlay_h
为叠加视频的宽和高。
ffmpeg -y -i test.mp4 -vf "drawtext=fontfile=CourierNew.ttf:text='hello world':x=100:y=50:fontsize=24" out.mp4
drawtext滤镜用于在视频上添加文字。
ffmpeg -y -i test.mp4 -vf "fade=in:st=0:d=5" out.mp4
fade滤镜能够制做淡入淡出效果
ffmpeg -y -i test.mp4 -vf "fps=60" out.mp4
fps滤镜经过删除帧或者复制帧的方法强制设置帧率。
ffmpeg -y -i test.mp4 -vf "fps=1" img%3d.png ffmpeg -y -i test.mp4 -r 1 img%3d.png
上面两条指令均可以对视频每秒截取一帧图像,-r
选项会截取关键帧并不必定截取0s、1s...处的帧,fps滤镜处理的是已经解码的帧所以能够精确的按照时间截取。
由于fps滤镜会解码要截图的视频片断,所以这种方式截图会慢不少。
ffmpeg -y \ -i test.mp4 \ -vcodec copy \ -acodec copy \ out.mkv
这条指令将容器格式由MP4转换到MKV,使用ffprobe
检查输出文件能够发现,视频流没有发生变化,可是封装格式改变为mkv格式。
-vcodec
是一个简单过滤器用于处理视频编码,copy
表示将视频流复制到输出文件中。-acodec
是处理音频编码的过滤器。
ffmpeg -y \ -i test.mp4 \ -vcodec copy \ -an \ out.mp4
-an
表示不保留音频流。
ffmpeg -y \ -i test.mp4 \ -ar 44100 -ac 2 -ab 192 \ -f mp3 \ output.mp3
分析:
-ar
: 指定输出音频采样率-ac
: 指定输出音频通道(channel)数, 这里设置为双声道-ab
: 指定输出音频比特率,单位kb/s截取第2s开始的10帧图像, 伸缩为352x240:
ffmpeg -y \ -ss 2 -i test.mp4 \ -vframes 10 \ -f image2 \ -s 352x240 \ img%03d.png
分析:
-ss 2 -i test.mp4
: ss
为开始时间,用秒数或者hh:mm:ss[.xxx]格式表示。-i test.mp4
表示输入源-vframes
: 指定截取的帧数, 这里是截取前10帧(从-ss
指定开始时间算起)-f
: 指定输出文件的格式,如: image2, mjpeg, gif-s
: 对输出画面进行缩放img%03d.png
: 格式化输出文件名,本示例中输出img001.png, img002.png等。-ss
参数也能够放在vframes
前:
ffmpeg -y \ -i test.mp4 \ -ss 2 -vframes 1 \ -f image2 \ -s 352x240 \ img.png
-ss
参数是局部选项用于设置其后的一个命令,-ss 2 -i test.mp4
表示从输入视频的第2s开始处理,忽略前两秒的内容。
而-ss 2 -vframes 1
表示从第2s开始截取,此时前2s的内容已经进行了解码。
对不须要处理的部分进行解码会浪费大量时间,所以建议使用-ss 2 -i test.mp4
来表示截图开始时间。
从第2s到第12s内,每秒截取1帧图像:
ffmpeg -y \ -ss 2 -i test.mp4 \ -r 1 -t 10 \ -f image2 \ -s 352x240 \ img%03d.png
分析:
-t
: 指定截取时长,这里截取10s-r 1
: -t
的局部选项设置每秒截取的帧数(截取帧率),若不设置则截取所有帧和-vframe
同样-t
的开始时间也有两种设置方式,基于一样的理由一样建议将-ss
放在输入前。
截取视频片断的方法与截图方法相似,只是将输出格式变为视频:
按时间截取:
ffmpeg -y \ -ss 2 -i test.mp4 \ -r 20 -t 10 \ -s 352x240 \ clip.mp4
由于输出为视频,-r
指定的截取帧率即为输出视频帧率。
按帧数截取:
ffmpeg -y \ -ss 2 -i test.mp4 \ -vframes 120 \ -s 352x240 \ clip.mp4
截取视频区域:
ffmpeg -y \ -ss 2 -i test.mp4 \ -r 1 \ -t 10 \ -filter_complex "[0:v]crop=w=100:h=100:x=12:y=34,scale='400:400'[v]" \ -map "[v]" \ img%03d.png
crop
滤镜能够截取视频部分区域,[0:v]crop=w=100:h=100:x=12:y=34,scale='400:400'[v]
截取了左上角在(12,34)处,宽为100,高为100的矩形框中的内容,并将截图放大到400x400。
ffmpeg -i "concat:1.mp4|2.mp4|3.mp4" -c copy output.mp4
ffmpeg -i img%3d.png output.gif ffmpeg -i img%3d.png output.mp4
ffmpeg -i bgm.mp3 -i test.mp4 output.mp4
ffmpeg -y \ -i test.mp4 \ -i 1.png \ -filter_complex "[1]scale=w=480:h=280[s];[0][s]overlay=x=main_w-overlay_w-10:y=main_h-overlay_h-10[ov]" \ -map "[ov]" \ output.mp4
使用filter_complex
先将水印图片(输入1)放大到480x280, 而后使用overlay滤镜将放大后的流[s]覆盖到视频(输入0)上。
若不须要使用scale进行缩放,则能够简化filter_complex
表达式:
ffmpeg -y \ -i test.mp4 \ -i 1.png \ -filter_complex "overlay=x=main_w-overlay_w-10:y=main_h-overlay_h-10" output.mp4
ffmpeg -y -i test.mp4 -t 10 -loop 1 -framerate 6 -i ani%3d.png -filter_complex 'overlay=10:main_h-overlay_h-10' out.mp4
将多张图片(ani001.png, ani002.png...)组成动画, 而后将这个动画叠加在视频的左下角。-t 10 -loop 1
会循环播放动画,持续10s。
该方式也支持gif格式的动画。
ffmpeg -y -i test.mp4 -vf "drawtext=fontfile=CourierNew.ttf:text='hello world':x=100:y=50:fontsize=24" out.mp4
添加字幕有两种方式:
添加字幕流:
ffmpeg -i video.mp4 -vf subtitles=subtitle.srt out.mp4
叠加字幕:
ffmpeg -i test.mp4 -i sub.srt -filter_complex "[0][1]overlay[v]" -map "[v]" out.mp4
HowToBurnSubtitlesIntoVideo详细介绍了烧录字幕的方法,做者建议尽可能使用字幕流的方法添加字幕。
旋转视频有两种方式:
添加元信息:
ffmpeg -i test.mp4 -metadata:s:v rotate="90" -codec copy out.mp4
逐帧旋转:
ffmpeg -i test.mp4 -vf "transpose=1" out.mp4
transpose
滤镜的文档