前言
本文介绍 FFmpeg 骨架:“八大金刚” 核心开发库,重要数据结构与 API
一、FFmpeg 核心开发库
- libavformat(重要)
avformat
:用于各种音视频封装格式的生成和解析,包括获取解码所需信息以生成解码上下文结构和读取音视频帧等功能,包含 demuxers 和 muxer 库;
- libavcodec(重要)
avcodec
:用于各种类型声音/图像编解码;
- libavutil
avutil
:包含一些公共的工具函数;
- libswscale(重要)
swscale
:用于视频场景比例缩放、 色彩映射转换;
- libpostproc
postproc
:用于后期效果处理;
- libavdevice
avdevice
:和多媒体设备交互的类库,使用这个库可以读取电脑(或者其他设备上)的多媒体设备的数据,或者输出数据到指定的多媒体设备上;
- libswresmaple(重要)
swresample
:主要包括高度优化的音频重采样、rematrixing 和样本格式转换操作;
- libavfilter
avfilter
: 过滤器(Filter),在多媒体处理中,filter 的意思是被编码到输出文件之前用来修改输入文件内容的一个软件工具;
二、FFmpeg 重要数据结构与 API
1、简介
FFmpeg 中结构体很多,其中下图所涉及的结构体需要熟记:
上图后者是前者的数据成员,Format Layer 除了 AVInputFormat 外还有一个 AVOutputFormat
AVFormatContext 是一个贯穿始终的数据结构,很多函数都用到它作为参数,是输入输出相关信息的一个容器。
最关键的结构体可以分为以下几类:
- 解协议(http,rtsp,rtmp,mms,hls,file,tcp,udp,…)
AVIOContext
,URLContext
,URLProtocol
主要存储视音频使用的协议的类型以及状态。URLProtocol 存储输入视音频使用的封装格式。每种协议都对应一个 URLProtocol 结构。(注意:FFMPEG 中文件也被当做一种协议“file” )
- 解封装(flv,avi,rmvb,mp4)
AVFormatContext
主要存储视音频封装格式中包含的信息;AVInputFormat
存储输入音视频使用的封装格式。 每种视音频封装格式都对应一个AVInputFormat
结构。AVInputFormat
和AVOutputFormat
,同一时间只能存在一个。当播放视频时AVInputFormat
生效,录制视频时则AVOutputFormat
生效;
- 解码
AVStream
是继AVFormatContext
之后第二个贯穿始终的数据结构,它保存于数据流相关的编解码器、数据段等信息,还包含“流” 这个概念中的一些信息;- 每个
AVStream
存储一个视频/音频流的相关数据; - 每个
AVStream
对应一个AVCodecContext
,存储该视频/音频流使用解码方式的相关数据; - 每个
AVCodecContext
中对应一个AVCodec
,包含该视频/音频对应的解码器; - 每种解码器都对应一个
AVCodec
结构。AVCodec
记录了所要使用的 Codec 的信息并有 5 个函数: init, encoder, close, decode, flush 来完成编解码工作。
- 存数据
- 视频的话,每个结构一般是存一帧;音频可能有好几帧 ;
- 解码前数据:
AVPacket
; - 解码后数据:
AVFrame
。
2、FFmpeg 解码流程
①、FFmpeg2.x 解码流程
av_register_all();
//注册所有文件格式和编解码库avformat_network_init();
//打开网络视频流av_open_input_file();
//读取文件头部把信息保存到 AVFormatContext 结构体av_find_stream_info();
//为 pFormatCtx->streams 填充上正确的信息CODEC_TYPE_VIDEO;
//通过判断得到视频流类型avcodec_find_decoder();
//查找解码器avcodec_open();
//打开编解码器avcodec_alloc_frame();
//分配空间保存帧数据av_read_frame();
//不断从流中提取帧数据avcodec_decode_video();
//解码视频流avcodec_close();
//关闭解码器avformat_close_input_file();
//关闭输入文件
②、FFmpeg4.x 解码流程
3、FFMpeg 中比较重要的函数以及数据结构
①、数据结构
- AVFormatContext
- AVOutputFormat
- AVInputFormat
- AVCodecContext
- AVCodec
- AVFrame
- AVPacket
- AVPicture
- AVStream
②、初始化函数
- av_register_all()
- avcodec_open()
- avcodec_close()
- av_open_input_file()
- av_find_input_format()
- av_find_stream_info()
- av_close_input_file()
③、音视频解码函数
- avcodec_find_decoder()
- avcodec_alloc_frame()
- avpicture_get_size()
- avpicture_fill()
- img_convert()
- avcodec_alloc_context()
- avcodec_decode_video()
- av_free_packet()
- av_free()
④、文件操作
- avnew_steam()
- av_read_frame()
- av_write_frame()
- dump_format()
⑤、其他函数
- avpicture_deinterlace()
- ImgReSampleContext()
三、FFmpeg 流程
1、FFmpeg 主要框架
2、文件处理基本流程(转码流程)
- demuxer:解复用;即将音视频分离出来,上图中的视频流是 AVC(H264)格式,音频流是 AAC 格式;
- decoder:解码器;
- filter: 帧处理,这里将原始 19201080 转换为 1280720;
- encoder:编码器,这里是 H265 的视频格式;
- muxer:复用,将音频和视频进行重新封装。
ffmpeg 对一个媒体文件进行解码的主要流程是:
解码流程图
①、解复用(Demux)
视频文件的音频和视频都是分开进行压缩的,因为音频和视频的压缩算法不一样,所以解码也不一样,所以需要对音频和视频分别进行解码。虽然音频和视频是分别进行压缩的,但是为了传输过程的方便,降压所过的音频和视频捆绑在一起进行传输。所以解复用这一步就是将文件中捆绑的音频流和视频流分开来以方便后面分别对它们进行解码。
②、解码(Decode)
一个音视频文件肯定是经过某种格式压缩的(h264、h265 等),也就是通常所说的音视频编码,编码是为了减少数据量,否则的话对于音视频数据的存储和网络传输将是很难完成的,所以我们必须对音视频文件进行尽可能的压缩。