夯实FFmpeg基础:重要数据结构与API


***【在线视频教程】***

好文章,来自【福优学苑@音视频+流媒体】

简介

FFMPEG中结构体很多。

image.png

最关键的结构体可以分成以下几类:


a) 解协议(http,rtsp,rtmp,mms,hls,file,tcp,udp,......)


AVIOContext,URLContext,URLProtocol主要存储视音频使用的协议的类型以及状态。URLProtocol存储输入视音频使用的封装格式。每种协议都对应一个URLProtocol结构。(注意:FFMPEG中文件也被当做一种协议“file”)


b)解封装(flv,avi,rmvb,mp4)


AVFormatContext主要存储视音频封装格式中包含的信息;AVInputFormat存储输入视音频使用的封装格式。每种视音频封装格式都对应一个AVInputFormat 结构。


c)解码(h264,mpeg2,aac,mp3)


每个AVStream存储一个视频/音频流的相关数据;

每个AVStream对应一个AVCodecContext,存储该视频/音频流使用解码方式的相关数据;

每个AVCodecContext中对应一个AVCodec,包含该视频/音频对应的解码器。

每种解码器都对应一个AVCodec结构。


d) 存数据


视频的话,每个结构一般是存一帧;音频可能有好几帧

解码前数据:AVPacket

解码后数据:AVFrame


FFmpeg2.x解码流程

image.png


FFmpeg4.x解码流程图

image.png

描述与分析

FFMpeg中主要数据结构存在包含关系,如下标题显示的就是包含层级的关系。


AVFormatContext ->AVStream-> AVCodecContext -> AVCodec,其中后者是前者的数据成员。


AVFormatContext是一个贯穿始终的数据结构,很多函数都用到它作为参数,是输入输出相关信息的一个容器。

主要成员如下:

1.AVInputFormat和AVOutputFormat,同一时间只能存在一个。当播放视频时AVInputFormat生效,录制视频时则AVOutputFormat生效。


2.AVStream是继AVFormatContext之后第二个贯穿始终的数据结构,它保存于数据流相关的编解码器、数据段等信息,还包含“流”这个概念中的一些信息。


2.1AVCodecContext保存AVCodec指针和与codec相关的数据。

在AVStream初始化后,AVCodecContext的初始化时Codec使用中最重要的一环。

AVCodecContext中的codec_type,codec_id二个变量对于encoder/decoder的匹配来说,最为重要。


AVCodecContext中有两个成员:AVCodec,AVFrame。

2.1.1 AVCodec记录了所要使用的Codec的信息并有5个函数:init,encoder,close,decode,flush来完成编解码工作。

2.1.2 AVFrame中主要包饭了编码后的帧信息。

typedef struct AVFrame {

    FF_COMMON_FRAME

} AVFrame;

其中FF_COMMON_FRAME是以宏出现的,由于编码过程中AVFrame中的数据是要经常存取的,为了加速,采取这样的代码手段。





FFMpeg 中比较重要的函数以及数据结构如下:

数据结构:

(1) AVFormatContext

(2) AVOutputFormat

(3) AVInputFormat

(4) AVCodecContext

(5) AVCodec

(6) AVFrame

(7) AVPacket

(8) AVPicture

(9) AVStream


初始化函数:

(1) av_register_all()

(2) avcodec_open()

(3) avcodec_close()

(4) av_open_input_file()

(5) av_find_input_format()

(6) av_find_stream_info()

(7) av_close_input_file()


音视频编解码函数:

(1) avcodec_find_decoder()

(2) avcodec_alloc_frame()

(3) avpicture_get_size()

(4) avpicture_fill()

(5) img_convert()

(6) avcodec_alloc_context()

(7) avcodec_decode_video()

(8) av_free_packet()

(9) av_free()


文件操作:

(1) avnew_steam()

(2) av_read_frame()

(3) av_write_frame()

(4) dump_format()


其他函数:

(1) avpicture_deinterlace()

(2) ImgReSampleContext()


FFMpeg 中比较重要的函数以及数据结构如下:


1. 数据结构:

(1) AVFormatContext

此结构包含了一个视频流的格式内容。

其中存有了 AVInputFormat(or AVOutputFormat 同一时间 AVFormatContext 内只能存在其中一个),和 AVStream、AVPacket 这几个重要的数据结构以及一些其他的 相关信息,比如 title,author,copyright 等。还有一些可能在编解码中会用到的信息,诸如:duration, file_size, bit_rate 等。参考 avformat.h 头文件。

(2) AVOutputFormat

(3) AVInputFormat

(4) AVCodecContext

此结构在Ffmpeg SDK中的注释是:main external api structure其重要性可见一斑。而且在avcodec它的定义处,对其每个成员变量,都给出了十分详细的介绍。

应该说AVCodecContext的初始化是Codec使用中最重要的一环。

虽然在前面的AVStream中已经有所提及,但是这里还是要在说一遍。AVCodecContext作为 Avstream的一个成员结构,必须要在Avstream初始化後(30)再对其初始化(AVStream的初始化用到 AVFormatContex)。虽然成员变量比较多,但是这里只说一下在output_example.c中用到了,其他的请查阅 avcodec.h文件中介绍。

(5) AVCodec

结构 AVCodec 中成员变量和成员函数比较少,但是很重要。

他包含了 CodecID,也就是用哪个 Codec 像素格式信息。还有前面提到过的 5 个函数(init、encode、close、decoder、flush)。顺便提一下,虽然在 参考代码 output_example.c 中的编码函数用的是 avcodec_encode_video(),我怀疑在其中就是调用了 AVCodec 的 encode 函数,他们传递的参数和返回值都是一致的,当然还没有得到确认,有兴趣可以看看 ffmpeg 源代码。在参考代码中,AVCodec 的初始化後的使用都是依附于 AVCodecContex,前者是后者的成 员。在 AVCodecContext 初始化後(add_video_stream()),AVCodec 也就能很好的初始化了

(6) AVFrame

AVFrame 是作为一个描述“原始图像”(也就是 YUV 或是 RGB…还有其他的吗?)的结构,他的头两 个成员数据,uint8_t *data[4],int linesize[4],第一个存放的是 Y、Cb、Cr(yuv 格式),linesize 是啥?由这 两个数据还能提取处另外一个数据结构。

(7) AVPacket

AVPacket 的存在是作为写入文件的基本单元而存在的。

我们可能会认为直接把编码后的比特流写入文 件不就可以了,为什么还要麻烦设置一个 AVPacket 结构。在我看来这样的编码设置是十分有必要的,特别 是在做视频实时传输,同步、边界问题可以通过 AVPacket 来解决。AVPacket 的成员数据有两个时间戳、 数据 data(通常是编码后数据)、大小 size 等等(参见 avformat.h 48 行)。讲 AVPacket 的用法就不得不提到 编解码函数,因为 AVPacket 的好些信息只有在编解码后才能的知。在参考代码中(ouput_example.c 从 362 到 394 行),做的一个判断分支。如果输出文件格式是 RAW 图像(即 YUV 或 RGB)那么就没有编码函数, 直接写入文件(因为程序本身生成一个 YUV 文件),这里的代码虽然在此看来没什么价值,但是如果是解 码函数解出 yuv 文件(或 rgb)那么基本的写文件操作就是这样的

(8) AVPicture

AVPicture 的存在有以下原因,AVPicture 将 Picture 的概念从 Frame 中提取出来,就只 由Picture(图片)本身的信息,亮度、色度和行大小。而Frame还有如是否是key frame之类的信息。这样的类似“分级”是整个概念更加清晰。

(9) AVStream

AVStream作为继AVFormatContext後第二个贯穿始终的结构是有其理由的。他的成员数据中有 AVCodecContext这基本的上是对所使用的Video Codec的参数进行设定的(包括bit rate、分辨率等重要信息)。 

同时作为“Stream”,它包含了“流”这个概念中的一些数据,比如:帧率(r_frame_rate)、基本时间计量 单位(time_base)、(需要编解码的)首帧位置(start_time)、持续时间(duration)、帧数(nb_frames)以及 一些ip信息。当然后面的这些信息中有些不是必须要初始化的,但是AVCodecContex是一定要初始化的,而 且就是作为初始化AVStream最重要的一个部分。


2. 初始化函数:

(1) av_register_all()

usage: initialize ibavcoded, and register all codecs and formats

每个使用 FFMpeg SDK 的工程都必须调用的函数。进行 codec 和 format 的注册,然后才能使用。声明在 allformats.c 中,都是宏有兴趣看看。

(2) avcodec_open()

(3) avcodec_close()

(4) av_open_input_file()

(5) av_find_input_format()

(6) av_find_stream_info()

(7) av_close_input_file()

3. 音视频编解码函数:

(1) avcodec_find_decoder()

(2) avcodec_alloc_frame()

(3) avpicture_get_size()

(4) avpicture_fill()

(5) img_convert()

(6) avcodec_alloc_context()

(7) avcodec_decode_video()

(8) av_free_packet()

(9) av_free()

4. 文件操作:

(1) avnew_steam()

(2) av_read_frame()

(3) av_write_frame()

(4) dump_format()

5. 其他函数:

(1) avpicture_deinterlace()

(2) ImgReSampleContext()


好文章,来自【福优学苑@音视频+流媒体】
***【在线视频教程】***