描述
ffmpeg 是一个非常高效的音视频转换器, 也能从一个音视频流里抓取数据. 它还可以在任意采样率之间转换, 并使用高质量的多相滤波器动态调整视频大小.
ffmpeg 通过指定 -i 参数, 可以从任意多的”文件”中读取(如常规文件, 管道, 网络流, 抓取设备等等). 通过指定一个文本输出 url, 也能写入任意数量的输出文件. 在命令行中找到的, 任何不能解释为选项的内容都被视为输出url.
每个输入或者输出 url 原则上可以包含任意多的不同类型(video/audio/subtitle字幕/attachment)的流. container format(封装格式) 能限制允许使用流的数量和类型.
要在选项中引用输入文件, 必须使用它们的索引(从0开始计算). 如第一个输入文件是 0, 第二个是 1, 等等. 类似地, 文件中的流通过其索引来引用. 如 2:3 表示第三个输入文件中的第四个流. 更多详细另请参阅流说明符一章.
作为一般性规则, 参数选项会被应用到下一个指定的文件. 因此, 顺序是很重要的, 在同一个命令里, 你可以输入多次, 多个相同的参数选项. 每次出现的选项都将应用于下一个输入或输出文件. 除此之外, 还有全局的选项(如verbosity level), 则要在最开始时指定.
不要搞混输入和输出文件, 建议优先指定所有输入文件, 再指定所有的输出问题件. 也不要弄混属于不同文件的选项. 所有的选项都仅适用于下一个输入或输出文件, 在不同文件直接将会被重置.
ffmpeg语法
ffmpeg的语法格式如下,
ffmpeg [global_options] {[input_file_options] -i input_url} ... {[output_file_options] output_url} ...
简单的例子如,要设置输出视频文件的比特率为 64kbit/s:
ffmpeg -i input.avi -b:v 64k -bufsize 64k output.avi
强制设置输出文件的帧率(frame rate)为24fps:
ffmpeg -i input.avi -r 24 output.avi
强制设置输入文件的帧率(只限合法的raw format)为 1 fps,设置输出文件的帧率为 24fps:
ffmpeg -r 1 -i input.m2v -r 24 output.avi
raw input files 则可能需要 format 选项.
原理描述
FFMpeg 的工作流程
在 ffmpeg 里,转码的工作流程可以描述为如下的图表:
_______ ______________
| | | |
| input | demuxer | encoded data | decoder
| file | ---------> | packets | -----+
|_______| |______________| |
v
_________
| |
| decoded |
| frames |
|_________|
________ ______________ |
| | | | |
| output | <-------- | encoded data | <----+
| file | muxer | packets | encoder
|________| |______________|
如图所描述的,
ffmpeg 调用 the libavformat 库 (包含分解复用器 demuxers) 去读取输入文件,获取 packet 数据,包含已编码的数据. 当有多个输入文件时,ffmpeg 会在任何 active 状态的输入流上,通过最低的时间戳,尝试去让它们保持同步。
之后,已编码的 packet 数据传递给 decoder。解码器 decoder 处理解压后的帧数据(raw video/PCM audio/…), 使用filter,帧数据可以进一步处理.
在过滤器过滤后, 帧数据会传递给 encoder 编码器,做编码处理输出编码后的 packet 数据. 最后,这些数据都会传递给 muxer(复用器), 将编码后的 packet 数据写入输出文件.
Filtering
在编码之前,libavfilter库提供了各种各样的 filters 让 ffmpeg 可以处理 raw 音频帧和视频帧。几个链式过滤器可以构成 filter 图. ffmpeg
区分两种不同类型的过滤器图: 简单图与复杂图.
Simple filtergraphs
简单过滤器图是那些有明确的一个同种类型的输入与输出. 在下面的图表,在解码和编码之间插入一个附加的步骤来表示:
_________ ______________
| | | |
| decoded | | encoded data |
| frames |\ _ | packets |
|_________| \ /||______________|
\ __________ /
simple _\|| | / encoder
filtergraph | filtered |/
| frames |
|__________|
简单 filtergraphs 通过 per-stream -filter 选项来配置(-vf 和 -af)
视频的一个简单 filtergraphs 可以看做如下图表,
_______ _____________ _______ ________
| | | | | | | |
| input | ---> | deinterlace | ---> | scale | ---> | output |
|_______| |_____________| |_______| |________|
注意,一些过滤器改变帧属性而不是帧内容。如,fps 过滤器,在上面的例子中,改变了帧的数量,但没有改变帧的内容。 另外一个例子是,setpts 过滤器,只设置了时间戳,而不更改地传递帧。
Complex filtergraphs
复杂的filtergraph,不能简单地描述为应用于一个流的线性处理链. 举个例子, 当一个图里有超过一个的输入或者输出,或者输出的类型与输入是不同。它们可以用以下的图表来表示:
_________
| |
| input 0 |\ __________
|_________| \ | |
\ _________ /| output 0 |
\ | | / |__________|
_________ \| complex | /
| | | |/
| input 1 |---->| filter |\
|_________| | | \ __________
/| graph | \ | |
/ | | \| output 1 |
_________ / |_________| |__________|
| | /
| input 2 |/
|_________|
复杂 filtergraphs 通过 -filter_complex 选项来配置. 注意, 这个选项是全局的, 因为一个复杂的 filtergraph, 本质上, 不能明确的跟一个流或文件相关联.
-lavfi 选项等同于 -filter_complex.
复杂filtergraph,一个不是很重要的例子,overlay 过滤器,有两个视频输入和一个视频输出,在另一个视频的顶部包含一个视频 overlaid。 它的音频对应的是 amix 过滤器
Stream copy
Stream 拷贝通过提供拷贝参数给 -codec选项 来实现. 它使得在指定的流上,ffmpeg 省略解码和编码的步骤。 所以,它只有分解和复用. 在改变封装格式(container format) 或修改 container-level metadata数据时是很有用的. 在这个例子里,可以简化成如下的图表:
_______ ______________ ________
| | | | | |
| input | demuxer | encoded data | muxer | output |
| file | ---------> | packets | -------> | file |
|_______| |______________| |________|
由于没有解码和编码步骤,它是非常高速的,并且不会有质量的损失。 然而,stream copy在一些场景下,出于各种因素,可能不会起作用。 显然的,在这个过程中是无法使用过滤器的,因为过滤器是在解压后的数据上工作的。
ffmpeg 命令分类
了解了上面的基础知识后,我们先来看看 ffmpeg 的命令,可以将命令大概分为八大类,
- 基本信息查询命令
- 录制命令
- 分解/复用命令
- 处理原始数据命令
- 剪裁与合并命令
- 图片/视频互转命令
- 直播相关命令
- 各种滤镜命令
命令对应的代码实现方式将在后续的文章中做介绍,待我先准备准备,感谢各位大佬继续关注。
FFmpeg基本信息查询命令
指令 | 描述 | 指令 | 描述 |
---|---|---|---|
-version | 显示版本信息 | -formats | 显示可用的格式 |
-demuxers | 显示可用的 demuxers | -protocols | 显示可用的协议 |
-muxers | 显示可用的 muxers | -filters | 显示可用的过滤器 |
-devices | 显示可用的设备 | -pix_fmts | 显示可用的像素格式 |
-codecs | 显示所有编解码器 | -sample_fmts | 显示可用的采样格式 |
-decoders | 显示可用的解码器 | -layouts | 显示 channel名称 |
-encoders | 显示所有的编码器 | -colors | 显示识别的颜色名称 |
-bsfs | 显示比特流 filter |
example
如,
➜ FFmpeg git:(master) ffmpeg -version
ffmpeg version N-96315-g94cdf82d53 Copyright (c) 2000-2020 the FFmpeg developers
built with Apple clang version 11.0.0 (clang-1100.0.33.16)
configuration: --prefix=/usr/local/ffmpeg --enable-gpl --enable-nonfree --enable-libfdk-aac --enable-libx264 --enable-libx265 --enable-filter=delogo --enable-debug --disable-optimizations --enable-libspeex --enable-videotoolbox --enable-shared --enable-pthreads --enable-version3 --enable-hardcoded-tables --cc=clang --host-cflags= --host-ldflags=
libavutil 56. 38.100 / 56. 38.100
libavcodec 58. 65.102 / 58. 65.102
libavformat 58. 35.101 / 58. 35.101
libavdevice 58. 9.103 / 58. 9.103
libavfilter 7. 70.101 / 7. 70.101
libswscale 5. 6.100 / 5. 6.100
libswresample 3. 6.100 / 3. 6.100
libpostproc 55. 6.100 / 55. 6.100
录制命令
ffmpeg -f avfoundation -i 1:0 -r 30 out.yuv
-f: 指定使用mac 上 avfoundation 采集数据
-i: 指定从哪里采集数据,它是一个文件索引号,”:” 前面指定视频的采集方式,如 1 表示屏幕,0 表示摄像头,”:” 后面指定音频的采集方式
-r: 指定帧率
out.yuv:输出文件路径,文件名
-i 的索引参数可通过如下命令查询,
➜ FFmpeg git:(master) ffmpeg -f avfoundation -list_devices true -i ""
[AVFoundation indev @ 0x7fbacf7002c0] AVFoundation video devices:
[AVFoundation indev @ 0x7fbacf7002c0] [0] FaceTime HD Camera
[AVFoundation indev @ 0x7fbacf7002c0] [1] Capture screen 0
[AVFoundation indev @ 0x7fbacf7002c0] AVFoundation audio devices:
[AVFoundation indev @ 0x7fbacf7002c0] [0] Built-in Microphone
[AVFoundation indev @ 0x7fbacf7002c0] [1] xxx 的 BeatsX
使用 ffplay 播放,
ffplay -video_size 2560x1600 -pixel_format uyvy422 out.yuv
或者直接 ffplay out.mp4
-s: 指定播放的分辨率
-pix_fmt: 指定播放的像素格式
直接播放时,需要注意封装格式,如果是 YUV 数据的必须要指定分辨率大小,像素格式。其中 out.h264 格式中,已包含 SPS(Sequence Parameter Sets ) 和PPS(Picture Parameter Set), 宽高已有可直接播放
ffmpeg -f avfoundation -list_devices true -i ""
分解/复用命令
封装格式转换
分解复用也就是我们常见的格式转换,MP4 -> flv 等等,这个格式在音视频开发中是指 音视频数据的封装格式,不是数据的采集后的格式。
ffmpeg -i out.mp4 -vcodec copy -acodec copy out.flv
-i: 输入文件
-vcodec copy: 视频编码处理方式
-acodec copy: 音频编码处理方式
音视频抽取
ffmpeg -i test.mp4 -an -vcodec copy out.h264
-an: 不抽取音频
ffmpeg -i test.mp4 -acodec copy -vn out.aac
-vn: 不抽取视频
原始数据处理命令
提取YUV数据
提取视频里的 YUV 数据
ffmpeg -i input.mp4 -an -c:v rawvideo -pix_fmt yuv420p out.yuv
-c:v : 对视频进行编码,编码方式 rawvideo
-pix_fmt: 像素编码格式,常用格式 YUV420
播放 YUV 数据,参考前面的 ffplay
PCM 数据提取
提取视频原始里的 PCM 音频数据
ffmpeg -i input.mp4 -vn -ar 44100 -ac 2 -f s16le out.pcm
-ar: 音频采样率, 常用 44.1k, 48k, 32k等
-ac: audio channel, 2 表示双声道
-f: pcm数据存储格式,
s16le: s即有符号,16指16位, le(little end)
out.pcm: 输出文件名
播放 pcm 音频文件时,也是使用 ffplay, 不同的是我们需要指定音频的一些参数才能播放,
ffplay -ar 441000 -ac 2 -f s16le out.pcm
滤镜
crop滤镜
ffmpeg -i input.mp4 -vf crop=in_w-200:in_h-200 -c:v libx264 -c:a copy out.mp4
-i:输入文件
-vf: 视频滤镜
crop: 剪裁滤镜,in_w-200 视频宽度减200, in_h-200,视频宽度减200
-c:v: 视频编码器, libx264,使用x264进行编码
-c:a: 音频编码器,copy,这里不做处理
裁剪/合并
ffmpeg -i input.mp4 -ss 00:00:00 -t 10 out.ts
-ss: 裁剪的起始时间
-t: 裁剪的时长
out.ts: 输出文件
ffmpeg -f concat -i input.txt out.flv
input.txt: 合并文件的路径内容,每一行格式为: file $fileName
图片视频互转
视频截取图片
ffmpeg -i input.flv -r 1 -f image2 image-%3d.jpeg
-r: 频率,每秒 1 张
image-%3d.jpeg: 输出文件名
图片合成视频
ffmpeg -i image-%3d.jpeg out.mp4
直播推/拉流
推流
ffmpeg -re -i out.mp4 -c copy -f flv rtmp://server/live/streamName
-re: 同步帧率
-c: 编解码器 copy
-f: 推流的文件格式
rtmp://server/live/streamName: 服务器地址
拉流
ffmpeg -i rtmp://server/live/streamName -c copy dump.flv
参数同上