开源神器 | 底层逻辑 | 作品分析 | 咨询解答
004期
开源神器

FFmpeg
使用FFMPEG作为内核视频播放器:射手播放器,暴风影音,KMPlayer,QQ影音,Mplayer,ffplay,...
使用FFMPEG作为内核的转码工具:格式工厂...
事实上,FFMPEG的视音频编解码功能确实太强大了,几乎囊括了现存所有的视音频编码标准,因此只要做视音频开发,几乎离不开它。
也意味着,你懂了FFmpeg如果使用代码操作,像格式工厂、QQ影音……,你都可以卸载了!
1.FFmpeg的简介:
功能完整:FFmpeg是领先的多媒体框架,能够解码(decode)、编码(encode)、转码(transcode)、复用(mux)、解复用(demux)、流(stream)、过滤(filter)和播放(play)人类和机器创建的几乎所有内容。
几乎支持所有格式:FFmpeg支持最模糊的古代格式直至最前沿。无论是由某些标准委员会、社区还是公司设计的。
跨平台高度可移植性:FFmpeg可以在各种构建环境:机器体系结构和配置下,跨Linux、Mac OS X、Microsoft Windows、BSD、Solaris等编译,运行并通过测试基础架构 FATE。
每日更新的文档:各种在线每晚更新一次,并且对应于最新的FFmpeg版本。
2. FFmpeg播放流程:
2.1 播放流程:
video.avi(Container) -> 打开得到 Video_Stream -> 读取Packet -> 解析到 Frame -> 显示Frame。
2.2 相关术语:
2.2.1 「封装格式(Container Format)」
封装格式(Container Format),可看作是编码流(Stream)(音频、视频等)数据的一层外壳,将编码后的数据,存储于此封装格式的文件之内。
封装又称容器(Container),容器的用词更为形象。容器就是存放内容的器具。
例如:饮料是内容,那么装饮料的瓶子就是容器。
对视频来说,封装格式是MP4、AVI、MKV、RMVB等格式。
2.2.2 「流(Stream)」
流(Stream)是一种音视频数据信息的传输方式。
有五种流:视频流(Video Stream)、音频流(Audio Stream)、字幕(Subtitle)、附件(t)、数据(d)。
例如:曾经多年前使用VCD看港片,可以选择粤语或国语声音,是视频文件中存放了两路音频流,可供用户选择其中一路进行播放。
2.2.3 「帧(Frame)」
帧(Frame)本意代表一幅静止的图像。
在流(Stream)中,帧代表最小数据单元,也是编解码器真正处理的最小处理单元。
数字视频处理的帧,通常不是说原始图像,而是被编码器编码后的一个图像。
对于视频来说,帧(Frame)是编码器编码后的一个图像;
对于音频来说,帧(Frame)是编码器编码后的一个声音。
帧(Frame)分为:I帧:关键帧;P帧:预测帧;B帧:双向预测帧。
2.2.4 「编解码(Codec)」
每路音视频流(Stream)都会以帧(Frame)为最小单位,被相应的编/解码器(Codec)进行编码或解码,以实现原始数据和压缩数据之间的相互转换。
编码(Codec)是对原始数据的加工,是对输入源进行处理,然后输出的过程。简单说,就是对图像和声音的压缩方法。
视频编码主要有:H263、H264、H265、MPEG系列等。
编码(Codec)其实是编码(COde)和解码(DECode)的合称。
CODEC = COde(编码) + DECode(解码)
解码就是把编码后的东西还原为原来的状态。
对于视频来说,就是把压缩的图像和声音还原为正常可以播放的图像和声音。
编码可以改变文件格式,或者文件格式不变,只更改其他数据。
FFmpeg编解码是基于比特流进行的。
2.2.5 「数据包(Packet)」
数据包(Packet)是从流(Stream)中读取的原始Raw数据片段,这些数据片段中,包含的是解码后能被应用程序处理的原始帧(Raw Frame)数据。
分开的数据流在送往编解码器(Codec)处理之前,要先放于缓存中,添加一些附属信息(例如:打上时间戳)以便后续处理,这个缓存空间就是数据包(Packet);
由于数据流是在时间轴上交错放置,所有的视频、音频、字幕都被分割成一段一段的数据,这些一段段的数据从数据流中解析出来之后,就是存放在各自的数据包(Packet)。
单纯的视频数据包来说,一个视频数据包可以存放一个视频帧;
单纯的音频帧来说,如果抽样率(sample-rate)是固定不变的,一个音频数据包可以存放几个音频帧;若是抽样率是可变的,则一个数据包就只能存放一个音频帧。
3. FFmpeg转码流程:
3.1 文件转码流程:
解封装Demux —> 解码Decode —> 编码Encode —> 封装Mux

3.2 相关术语:
3.2.1 封装格式转换:解封装Demux与封装Mux(无编解码/转码)
封装(Container)见上文2.2.1称为容器。
3.2.1.1 封装,还称为多路复用(Mux)。
封装的目的:
1. 是为了在一个文件流(Stream)中能同时存储视频流(Video Stream)、音频流(Audio Stream)、字幕(Subtitle)、附件(t)、数据(d)等内容。这正是“复用”的含义所在(分时复用)。
2. 是在网络环境下确保数据的可靠快速传输。
3.2.1.2 封装格式转换:
包括封装与解封装,即「复用(Mux)」与「解复用(Demux)」。
封装格式转换,就是在AVI,FLV,MKV,MP4这些格式之间进行转换(对应.avi/.flv/.mkv/.mp4后缀文件)。
「复用(Mux)」又称为封装
将多路流(视频、音频、字幕等),按照某种容器规则,混入一路输出中(普通文件、流等)。是multiplex的缩写。
「解复用(Demux)」又称为解封装
复用(Mux) 的反操作。从一路输入中,解析分离出多路流(视频、音频、字幕等)。
「复用(Mux)」处理的是输入格式,「解复用(Demux)」处理的输出格式。
3.2.1.3 封装格式转换工作原理图:

封装格式转换并不进行视音频的编码和解码工作。而是直接将视音频压缩码流,从一种封装格式文件中获取出来,然后打包成另外一种封装格式的文件。
3.2.1.4 封装格式转换特点:
处理速度极快。视音频编解码算法十分复杂,占据了转码的绝大部分时间。因为不需要进行视音频的编码和解码,所以节约了大量的时间。
视音频质量无损。因为不需要进行视音频的编码和解码,所以不会有视音频的压缩损伤。
3.2.2 编解码转换(转码)
使用FFmpeg对输入源处理,然后输出的过程叫做转码。转码可以改变文件格式,或者文件格式不变,只是更改其他数据。
编码的目的:
是为了压缩媒体数据。有别于通用文件数据的压缩,在图像或音频压缩的时候,可以借助图像特性(如前后关联、相邻图块关联)或声音特性(听觉模型)进行压缩,可以达到比通用压缩技术更高的压缩比。
传统的编码转换程序工作原理图:

3.3 转码步骤:
1. Demuxer 解复用器 进行Demuxing 解封装:
FFmpeg根据输入源的文件扩展名来选择最佳的解封装器:调用libavformat库(包含解复用器)读取 [输入文件(Input file)] ,解封装后生成 [包含编码数据的数据包(Encoded data packets)],即压缩状态的数据包。(文件file → 数据包data packets)
2. Decoder 解码器 进行Decoding解码 :
通过适当的解码器将步骤1里面的数据包解码为[未压缩的数据帧](原始视频/PCM音频/...),可以通过 ※过滤Optional filtering※ 进一步处理。(数据包data packages ——> 数据帧frames)
※ Optional filtering可选的滤镜:通过指定的滤镜修改解码后的数据帧。(修改数据帧)
如果使用-c copy或-codec copy,将不会有解码这个步骤,也就不会有下面的编码步骤。
3. Encoder 编码器 进行Encoding编码:
通过指定编码器,对其进行编码,将数据帧编码输出为[编码后的数据包(Encoded data packets)]。(数据帧frames ——> 数据包data packages)
4. Muxer 复用器 进行Muxing封装:
将[编码的数据包]封装为指定的媒体格式[输出文件(Output file)]。(数据包data packages ——> 文件file)
FFmpeg播放流程及相关术语中易混淆的概念:
1.「文件格式(File Format)」与「封装格式(Container Format)」的区别:
「文件格式(File Format)」
由文件扩展名标识,主要起提示作用。通过扩展名提示文件类型(或封装格式)信息。
「封装格式/容器(Container Format)」
是存储媒体内容的实际容器格式。不同的封装格式对应不同的文件扩展名,很多时候也用文件格式代指封装格式。
例如:常用ts格式(文件格式)代指mpegts格式(封装格式)。修改后缀把test.ts改名为test.mkv。mkv扩展名提示了此文件封装格式为Matroska,但文件内容并无任何变化,使用ffprobe工具仍能正确探测出封装格式为mpegts。
2.「封装格式(Container Format)」与「编解码(Codec)」的区别:
封装的步骤:打开输入文件、打开输出文件、从输入文件读取编码帧、往输出文件写入编码帧。这些都不涉及编码解码层面。
不同封装格式适用于不同的场合,支持的编码格式不一样。
主要封装格式一览表

「封装格式(Container Format)」与「编解码格式(Codec Format)」一览表[21]

如果只是容器改变,编码没改变。
可使用-c copy参数或-c:a copy参数或-c:v copy参数
ffmpeg转码最基本操作:
将.avi转为.mov
ffmpeg -i input.avi output.mov

相关命令行操作使用步骤:
▲
Sometimes ever, sometimes never.
相聚有时,后会无期。
本文向年仅25岁猝然离世的资深程序员雷霄骅致敬!

编辑、排版|青泉石上
本文为原创,未经许可请勿转载





