媒体处理流程
ffmpeg 命令的基本语法为:
ffmpeg [global_options] {[input_file_options] -i input_url} ... {[output_file_options] output_url} ...
ffmpeg 中的视频文件是一个容器,容器有不同的封装格式。根据封装格式的不同,视频文件可以支持不同数量的视频、音频、字幕、附件等媒体流。
ffmpeg 处理视频媒体文件时,先从容器格式中抽取编码的媒体流,再根据不同媒体格式协议解码成裸流,这个过程就是“解复用=>解码”。针对裸流处理完成后,将其编码成媒体流,再放进输出的容器格式中,就得到输出的视频文件。整个处理过程就是“解复用=>解码=>流处理=>编码=>复用”:
_______ ______________
| | | |
| input | demuxer | encoded data | decoder
| file | ---------> | packets | -----+
|_______| |______________| |
v
_________
| |
| decoded |
| frames |
|_________|
________ ______________ |
| | | | |
| output | <-------- | encoded data | <----+
| file | muxer | packets | encoder
|________| |______________|
ffmpeg调用 libavformat 库(包含解复用器)来读取输入文件并从中获取包含编码数据的数据包。当有多个输入文件时,ffmpeg尝试通过跟踪任何活动输入流上的最低时间戳来保持它们同步。
然后,编码的数据包被传递到解码器(除非为流选择了流复制,请参阅进一步的描述)。解码器生成未压缩的帧(原始视频/PCM 音频/...),可以通过过滤进一步处理(参见下一节)。过滤后,帧被传递到编码器,编码器对它们进行编码并输出编码后的数据包。最后,这些数据被传递到复用器,复用器将编码后的数据包写入输出文件。
过滤器
在上述媒体处理过程中,把原始未编码的媒体流进行编码之前,通常会有一个过滤操作。任何媒体处理都是通过过滤器在过滤阶段对无编码的原始媒体流操作的。
在编码前, ffmpeg 可以对raw(真实/原)音频和视频使用 libavfilter 库中的过滤器进行处理。多个过滤器按照前后依赖关系形成过滤图(filtergraph),过滤图又有简单过滤图和复杂过滤图之分。
- 简单过滤图是仅有一个输入和一个输出,并且输入和输出的类型相同
- 其他不属于简单过滤图的都是复杂过滤图
简单过滤图
通过 -filter 或者 -vf -af 设置视频流和音频流的过滤器。这个选项是一个输出选项,即针对单个输出文件设置的。
_________ ______________
| | | |
| decoded | | encoded data |
| frames |\ _ | packets |
|_________| \ /||______________|
\ __________ /
simple _\|| | / encoder
filtergraph | filtered |/
| frames |
|__________|
复杂过滤图
复杂的过滤图配置为-filter_complex选项,也可以使用等价的 -lavfi 选项。请注意,此选项是全局的,因为复杂的过滤器图本质上不能与单个流或文件明确关联。
_________
| |
| input 0 |\ __________
|_________| \ | |
\ _________ /| output 0 |
\ | | / |__________|
_________ \| complex | /
| | | |/
| input 1 |---->| filter |\
|_________| | | \ __________
/| graph | \ | |
/ |_________| \| output 1 |
_________ / |__________|
| | /
| input 2 |/
|_________|
流复制
当提供了-c|-codec copy 选项时,ffmpeg 的工作流程是一个特殊情况。由于不需要解码、编码,ffmpeg 就会省略这两个过程,只改变容器层面的信息:例如改变容器(封装)格式、修改容器元数据等。