FFmpeg 核心数据结构关系图

整体架构关系图

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;
}

总结

核心关系:

  • 容器管理 : AVFormatContextAVStream
  • 编解码分离 : AVCodec(算法) + AVCodecContext(状态)
  • 参数抽象 : AVCodecParameters 用于安全传递参数
  • 数据流 : AVPacket(压缩) ↔ AVFrame(原始)

设计原则:

  1. 单一职责: 每个结构体职责明确
  2. 状态分离: 静态信息与运行时状态分离
  3. 引用计数: 高效的内存管理
  4. 向后兼容: 新旧API共存
相关推荐
小龙报13 分钟前
《算法通关指南数据结构和算法篇(2)--- 链表专题》
c语言·数据结构·c++·算法·链表·学习方法·visual studio
万物挽挽18 分钟前
数据结构概述
数据结构
wangwangmoon_light29 分钟前
1.10 数据结构之图
数据结构
星轨初途2 小时前
数据结构排序算法详解(2)——选择排序(附动图)
c语言·数据结构·经验分享·笔记·b树·算法·排序算法
Chance_to_win4 小时前
数据结构之排序
数据结构
小年糕是糕手4 小时前
【C++】类和对象(二) -- 构造函数、析构函数
java·c语言·开发语言·数据结构·c++·算法·leetcode
kupeThinkPoem5 小时前
跳表有哪些算法?
数据结构·算法
前端小L5 小时前
图论专题(二十一):并查集的“工程应用”——拔线重连,修复「连通网络」
数据结构·算法·深度优先·图论·宽度优先
前端小L5 小时前
图论专题(二十三):并查集的“数据清洗”——解决复杂的「账户合并」
数据结构·算法·安全·深度优先·图论