ffmpeg介绍

描述

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

参数同上

参考

http://ffmpeg.org/ffmpeg.html