整体架构关系图
AVFormatContext AVStream AVCodecParameters AVCodecContext AVCodec AVCodecParserContext AVPacket AVFrame 文件/网络格式解析 编解码算法实现 比特流解析
详细关系解析
1. 容器层 (Container Level)
c
// AVFormatContext - 格式上下文,管理整个媒体文件
typedef struct AVFormatContext {
const AVClass *av_class; // 类信息
struct AVInputFormat *iformat; // 输入格式
struct AVOutputFormat *oformat; // 输出格式
AVIOContext *pb; // I/O上下文
unsigned int nb_streams; // 流数量
AVStream **streams; // 流数组
int64_t duration; // 总时长
int64_t bit_rate; // 比特率
// ... 其他元数据
} AVFormatContext;
关系:
AVFormatContext包含多个AVStream- 负责文件格式解析(MP4, AVI, MKV等)
- 管理媒体文件的全局信息
2. 流层 (Stream Level)
c
// AVStream - 单个媒体流(视频、音频、字幕等)
typedef struct AVStream {
int index; // 流索引
int id; // 流ID
AVCodecParameters *codecpar; // 编解码器参数
AVCodecContext *codecctx; // 编解码器上下文(可选)
AVRational time_base; // 时间基
int64_t start_time; // 开始时间
int64_t duration; // 流时长
// 帧率信息
AVRational avg_frame_rate;
AVRational r_frame_rate;
} AVStream;
关系:
- 每个
AVStream对应一个媒体流 - 包含
AVCodecParameters(必需)和AVCodecContext(可选) - 管理流的时间信息和元数据
3. 编解码参数层 (Codec Parameters)
c
// AVCodecParameters - 编解码器参数(纯数据)
typedef struct AVCodecParameters {
enum AVMediaType codec_type; // 媒体类型
enum AVCodecID codec_id; // 编解码器ID
// 视频参数
int width, height; // 分辨率
AVPixelFormat format; // 像素格式
// 音频参数
int sample_rate; // 采样率
AVChannelLayout ch_layout; // 声道布局
enum AVSampleFormat format; // 采样格式
// 通用参数
int bit_rate; // 比特率
uint8_t *extradata; // 额外数据
int extradata_size; // 额外数据大小
} AVCodecParameters;
关系:
- 存储编解码器的静态参数
- 不包含状态信息,可安全传递
- 新API推荐使用,替代部分AVCodecContext功能
4. 编解码器层 (Codec Level)
c
// AVCodec - 编解码器描述(静态信息)
typedef struct AVCodec {
const char *name; // 编解码器名称
const char *long_name; // 完整名称
enum AVMediaType type; // 媒体类型
enum AVCodecID id; // 编解码器ID
// 支持的格式
const enum AVPixelFormat *pix_fmts; // 像素格式
const enum AVSampleFormat *sample_fmts; // 采样格式
// 能力标志
int capabilities;
// 函数指针
int (*init)(AVCodecContext *); // 初始化
int (*decode)(AVCodecContext *, void *, int *, AVPacket *);
int (*encode2)(AVCodecContext *, AVPacket *, const AVFrame *, int *);
// ... 其他函数
} AVCodec;
// AVCodecContext - 编解码器上下文(动态状态)
typedef struct AVCodecContext {
const AVCodec *codec; // 关联的编解码器
// 运行时参数
int width, height; // 当前分辨率
AVPixelFormat pix_fmt; // 当前像素格式
int sample_rate; // 当前采样率
AVChannelLayout ch_layout; // 当前声道布局
// 状态信息
int frame_number; // 已处理帧数
AVFrame *internal_buffer; // 内部缓冲区
// 函数指针(覆盖默认实现)
int (*get_buffer2)(AVCodecContext *s, AVFrame *frame, int flags);
} AVCodecContext;
关系:
AVCodec描述编解码器的能力(静态)AVCodecContext管理编解码过程的状态(动态)- 一个
AVCodec可对应多个AVCodecContext
5. 解析器层 (Parser Level)
c
// AVCodecParserContext - 解析器上下文
typedef struct AVCodecParserContext {
void *priv_data; // 私有数据
struct AVCodecParser *parser; // 解析器方法
// 解析状态
int64_t cur_offset; // 当前偏移
int64_t next_frame_offset; // 下一帧偏移
// 时间戳信息
int64_t pts; // 显示时间戳
int64_t dts; // 解码时间戳
int64_t last_pts; // 最后pts
int64_t last_dts; // 最后dts
} AVCodecParserContext;
// AVCodecParser - 解析器方法
typedef struct AVCodecParser {
int codec_ids[5]; // 支持的编解码器ID
int priv_data_size; // 私有数据大小
// 解析函数
int (*parser_parse)(AVCodecParserContext *s,
AVCodecContext *avctx,
const uint8_t **poutbuf, int *poutbuf_size,
const uint8_t *buf, int buf_size);
// ... 其他函数
} AVCodecParser;
关系:
- 将原始字节流解析为完整的数据包
- 通常与
AVCodecContext配合使用
6. 数据单元层 (Data Unit Level)
c
// AVPacket - 压缩数据包
typedef struct AVPacket {
AVBufferRef *buf; // 引用计数缓冲区
int64_t pts; // 显示时间戳
int64_t dts; // 解码时间戳
uint8_t *data; // 压缩数据
int size; // 数据大小
int stream_index; // 流索引
int flags; // 标志位
AVPacketSideData *side_data; // 边数据
int side_data_elems; // 边数据元素数
} AVPacket;
// AVFrame - 解码后帧
typedef struct AVFrame {
uint8_t *data[AV_NUM_DATA_POINTERS]; // 数据指针
int linesize[AV_NUM_DATA_POINTERS]; // 行大小
// 视频信息
int width, height; // 分辨率
int format; // 像素格式
int key_frame; // 关键帧标志
// 音频信息
int nb_samples; // 样本数
int sample_rate; // 采样率
AVChannelLayout ch_layout; // 声道布局
int format; // 采样格式
// 时间信息
int64_t pts; // 显示时间戳
int64_t pkt_dts; // 包解码时间戳
int64_t duration; // 持续时间
// 引用计数
AVBufferRef *buf[AV_NUM_DATA_POINTERS];
// ... 其他字段
} AVFrame;
关系:
AVPacket→ 输入到解码器AVFrame← 从解码器输出- 支持引用计数,避免数据拷贝
完整的数据流
解码流程
文件 → AVFormatContext → AVStream → AVPacket →
AVCodecContext → AVFrame → 应用程序
编码流程(反向)
应用程序 → AVFrame → AVCodecContext → AVPacket →
AVStream → AVFormatContext → 文件
使用场景示例
场景1: 媒体文件解码
c
// 1. 打开文件
AVFormatContext *fmt_ctx = NULL;
avformat_open_input(&fmt_ctx, "input.mp4", NULL, NULL);
// 2. 查找流信息
avformat_find_stream_info(fmt_ctx, NULL);
// 3. 查找视频流
int video_stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
AVStream *video_stream = fmt_ctx->streams[video_stream_index];
// 4. 获取编解码器参数
AVCodecParameters *codecpar = video_stream->codecpar;
// 5. 查找解码器
const AVCodec *codec = avcodec_find_decoder(codecpar->codec_id);
// 6. 创建编解码器上下文
AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
avcodec_parameters_to_context(codec_ctx, codecpar);
// 7. 打开解码器
avcodec_open2(codec_ctx, codec, NULL);
// 8. 解码循环
AVPacket *pkt = av_packet_alloc();
AVFrame *frame = av_frame_alloc();
while (av_read_frame(fmt_ctx, pkt) >= 0) {
if (pkt->stream_index == video_stream_index) {
avcodec_send_packet(codec_ctx, pkt);
while (avcodec_receive_frame(codec_ctx, frame) == 0) {
// 处理解码后的帧
process_video_frame(frame);
}
}
av_packet_unref(pkt);
}
场景2: 原始流解析
c
// 解析原始H.264流
const AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_H264);
AVCodecParserContext *parser = av_parser_init(codec->id);
AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
uint8_t *data = inbuf;
size_t data_size = fread(inbuf, 1, INBUF_SIZE, infile);
while (data_size > 0) {
AVPacket *pkt = av_packet_alloc();
// 使用解析器
int ret = av_parser_parse2(parser, codec_ctx,
&pkt->data, &pkt->size,
data, data_size,
AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
if (pkt->size > 0) {
// 解码数据包
avcodec_send_packet(codec_ctx, pkt);
// ... 接收帧
}
av_packet_free(&pkt);
data += ret;
data_size -= ret;
}
总结
核心关系:
- 容器管理 :
AVFormatContext→AVStream - 编解码分离 :
AVCodec(算法) +AVCodecContext(状态) - 参数抽象 :
AVCodecParameters用于安全传递参数 - 数据流 :
AVPacket(压缩) ↔AVFrame(原始)
设计原则:
- 单一职责: 每个结构体职责明确
- 状态分离: 静态信息与运行时状态分离
- 引用计数: 高效的内存管理
- 向后兼容: 新旧API共存