FFMPEG结构体分析
附录:参考文献
1\] 结构体分析:https://www.cnblogs.com/linuxAndMcu/p/12041578.html#_label2 \[2\] [音视频入门系列](http://mp.weixin.qq.com/s?__biz=Mzg2MzA0NjM3Ng==&mid=2247483963&idx=6&sn=a2fb3dc7516d33a043f0eeb2acc46d92&chksm=ce7fddbcf90854aa4c0054e454346b7ff893adcc8205c053bcf94c5ad50da07477769f1d9cb3&scene=21#wechat_redirect) > FFmpeg结构体主要分为三个层次: > > * 协议层(**Protocol:http, rtsp, rtmp,file** ) > * `AVIOContext,URLProtocol,URLContext `主要存储音视频使用的协议的类型以及状态。**URLProtocol 存储输入音视频使用的封装格式**。每种协议都对应一个 URLProtocol 结构。 > * 封装层(**Format:flv, avi, rmvb, mp4** ) > * AVFormatContext 主要存储音视频封装格式中包含的信息;**AVInputFormat 存储输入音视频使用的封装格式**。每种音视频封装格式都对应一个 AVInputFormat 结构。 > * 解码层(**Codec:h264, mpeg2, aac, mp3** ) > * 每个 AVStream 存储一个视频/音频流的相关数据;**每个 AVStream 对应一个 AVCodecContext** ,存储该视频/音频流使用解码方式的相关数据;**每个 AVCodecContext 中对应一个 AVCodec** ,包含该视频/音频对应的解码器。**每种解码器都对应一个 AVCodec 结构**。  ### 1 `AVFormatContext` > **描述媒体文件或媒体流的构成和基本信息**,贯穿ffmpeg使用整个流程 > > 表示一个多媒体文件或流的全局上下文信息。它包含输入输出格式、媒体流信息,以及操作文件或流所需的状态。 > > * **`avformat_open_input()`** > > * 用于打开媒体文件或流,初始化 `AVFormatContext`。 > * **`avformat_alloc_output_context2()`** > > * 创建一个新的输出 `AVFormatContext`。 > > * `AVFormatContext` 用于描述目标输出文件的格式和流。 > > * \*\*`avformat_find_stream_info()`\*\*获取媒体流信息(如视频流、音频流等)。 > > * `AVFormatContext` 用于存储和返回文件的流信息。 > * \*\*`av_read_frame()`\*\*从媒体文件中读取一个数据包(帧)。 > > * 使用 `AVFormatContext` 来获取流信息和文件数据。 > > ...许多API函数都使用到该结构体 ```c++ //基本信息成员 AVInputFormat *iformat、AVOutputFormat *oformat://输入或者输出流的格式(只能存在一个) char *url://文件名 //IO操作成员 AVIOContext *pb://管理输入输出数据(缓存) //流媒体相关成员 unsigned int nb_streams://音视频流的个数 AVStream **streams://音视频流 //时间和同步 int64_t duration://时长 //其它 int bit_rate://比特率(单位bite/s) AVDictionary *metadata://元数据(查看元数据:ffprobe filename) ``` ### 2 `AVInputFormat` > 表示**输入媒体文件或流的封装格式**。它定义了如何读取、解析、和处理特定格式的媒体文件或流,例如 MP4、MKV、FLV 等。 > > * `av_find_input_format、avformat_open_input` > > * > > ```c++ > AVInputFormat *av_find_input_format(const char *short_name); > ``` > > * 根据指定的格式名称查找\\打开 `AVInputFormat`。 > > * `avformat_find_stream_info` > > * > > ```c++ > int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options); > ``` > > * 函数内部会根据输入格式(通过 `AVInputFormat`)对媒体文件进行处理,提取其中的流信息。 ```c++ char* name://封装格式的名字 char* long_name://封装格式的长名字 char* extensions://文件扩展名,例如 "mp4,mov"。 ``` ### 3 `AVIOContext->URLContext->URLProtocol` #### 3.1 `AVIOContext` > 文件(协议)操作的顶层对象,用于**管理媒体文件或流的输入输出操作**。它提供了一套通用的接口,用于读取和写入文件、网络流、内存缓冲区等数据源或数据目标。 > > * `avio_alloc_context` > * `AVIOContext *avio_alloc_context(...)` > * 分配一个 `AVIOContext`,用来进行 I/O 操作 ```c++ //IO 缓冲区 unsigned char *buffer://缓冲开始位置 int buffer_size://缓冲区大小(默认32768) unsigned char *buf_ptr://当前指针读取到的位置 unsigned char *buf_end://缓存结束的位置 //其它 void *opaque://URLContext结构体,通常传递到回调函数中,允许用户存储自定义上下文信息。 //读写回调函数 (*read_packet)(...)://自定义的读取函数回调。 (*write_packet)(...)://自定义的写入函数回调。 (*read_pause)(...)://网络流媒体协议的暂停或恢复播放函数指针 ``` #### 3.2 `URLContext` > 用于**抽象和管理底层的 I/O 操作**。它为各种协议(如文件系统、网络协议等)提供了统一的访问接口。 > > `URLContext` 是 `AVIOContext` 的底层实现之一。通过 `URLContext`,FFmpeg 可以对文件、网络流、管道等不同类型的数据源或目标进行操作,而用户通常通过更高级别的 `AVIOContext` 接口与之交互。 > > * `url_open` > > * > > ```c++ > int url_open(URLContext **puc, const char *filename, int flags) > ``` > > * 打开一个 URL 或文件。 ```c++ char* name://协议名称 const struct URLProtocol *prot://协议操作对象(ff_file_protocol、ff_librtmp_protocol...) void *priv_data://协议对象(FileContext、LibRTMPContext) ``` #### 3.3 `URLProtocol` > 用于**实现协议层抽象的结构体**,负责定义如何与特定协议(如文件系统、HTTP、RTSP 等)交互。 ### 4 `AVStream` > **存储音频流或视频流的结构体** ```c++ //其它 int index://流的索引值,唯一标识容器中的每个流。 AVRational avg_frame_rate://平均帧率 //元数据相关 AVCodecParameters *codecpar://解码器参数,例如编码类型(音频、视频、字幕),采样率,分辨率等。 int64_t duration://流的持续时间 AVRational time_base://流的时间基,用于将时间戳转换为秒。 ``` ### 5 AVCodecParameter 和 AVCodecContext > * 新的 ffmpeg 中`AVStream.codecpar(struct AVCodecParameter)` > > 代替 `AVStream.codec(struct AVCodecContext)`; > > AVCodecParameter 是由 AVCodecContext 分离出来的,AVCodecParameter中没有函数 > * AVCodecContext 结构体仍然是编解码时不可或缺的结构体:**avcodec_send_packet 和 avcodec_receive_frame 使用 AVCodecContext** #### 5.1 AVCodecContext > 用于**表示编解码器的静态描述信息**。 #### 5.2 AVCodecParameters > 用于**存储与媒体流(如音频、视频或字幕)相关的编码参数**。ffmpeg3.1引入,用来分离编解码器的参数信息与解码器/编码器的具体实现。 ### 6 AVCodec > **表示编解码器的静态描述信息**,每一个解码器对应一个AVCodec结构体 > > ##### **1. 查找编解码器** > > * 使用 `avcodec_find_decoder()` 或 `avcodec_find_encoder()`,通过 `AVCodec` 获取解码器或编码器。 > > ##### **2. 编解码器初始化** > > * 在 `AVCodecContext` 中,通过关联 `AVCodec` 来完成初始化。 ```c++ const char *name://编解码器短名字(形如:"h264") const char *long_name://编解码器全称(形如:"H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10") enum AVMediaType type://媒体类型:视频、音频或字母 enum AVCodecID id://标示特定的编码器 const AVRational *supported_framerates://支持的帧率(仅视频) const enum AVPixelFormat *pix_fmts://支持的像素格式(仅视频) const int *supported_samplerates://支持的采样率(仅音频) const enum AVSampleFormat *sample_fmts://支持的采样格式(仅音频) const uint64_t *channel_layouts://支持的声道数(仅音频) ``` ### 7 AVPacket > **存储压缩编码数据**相关信息的结构体; > > 例如 从解复用器(`av_read_frame`)读取压缩数据包。 > > 将数据包发送到解码器(`avcodec_send_packet`)。 > > 解码器将解码后的帧输出为 `AVFrame`。 ```c++ AVBufferRef *buf://管理data指向的数据 uint8_t *data: //压缩编码的数据 int size: //data的大小 int64_t pts: //显示时间戳 int64_t dts: //解码时间戳 int stream_index://标识该AVPacket所属的视频/音频流 ``` ### 8 AVFrame > 用于**存储原始数据**(即非压缩数据,例如对视频来说是 YUV,RGB,对音频来说是 PCM),此外还包含了一些相关的信息。 > > ##### **1. 初始化和分配** > > * `av_frame_alloc()` > 分配一个新的 `AVFrame`。 > > ##### **2. 释放资源** > > * `av_frame_unref(AVFrame *frame)` > 释放帧数据,清空 `AVFrame` 的内容。 > * `av_frame_free(AVFrame **frame)` > 释放 `AVFrame` 的内存。 > > ##### **3. 数据管理** > > * `av_frame_get_buffer(AVFrame *frame, int align)` > 为 `AVFrame` 分配缓冲区。 > * `av_frame_make_writable(AVFrame *frame)` > 确保 `AVFrame` 可写,如果当前数据不可写,会分配新的缓冲区。 ```c++ uint8_t *data[AV_NUM_DATA_POINTERS]://解码后原始数据(对视频来说是YUV,RGB,对音频来说是PCM) int linesize[AV_NUM_DATA_POINTERS]://data中"一行"数据的大小。注意:未必等于图像的宽,一般大于图像的宽。 int width, height://视频帧宽和高(1920x1080,1280x720...) int nb_samples://音频的一个AVFrame中可能包含多个音频帧,在此标记包含了几个 int format://解码后原始数据类型(YUV420,YUV422,RGB24...) int key_frame://是否是关键帧 enum AVPictureType pict_type://帧类型(I,B,P...) AVRational sample_aspect_ratio://图像宽高比(16:9,4:3...) int64_t pts://显示时间戳 int coded_picture_number://编码帧序号 int display_picture_number://显示帧序号 ```