1. AVCodec
c
typedef struct AVCodec {
const char *name; // 编解码器名称(如 "aac", "libfdk_aac")
const char *long_name; // 完整描述名称
enum AVMediaType type; // 媒体类型(AVMEDIA_TYPE_AUDIO/VIDEO等)
enum AVCodecID id; // 编解码器ID(AV_CODEC_ID_AAC等)
// 支持的采样格式列表(以AV_SAMPLE_FMT_NONE结尾)
const enum AVSampleFormat *sample_fmts;
// 支持的采样率列表(以0结尾)
const int *supported_samplerates;
// 支持的声道布局列表(以0结尾,新版FFmpeg已废弃)
const uint64_t *channel_layouts;
// 支持的像素格式(视频编解码器使用)
const enum AVPixelFormat *pix_fmts;
// 编解码器能力标志
int capabilities;
} AVCodec;
2. AVCodecContext
c
typedef struct AVCodecContext {
// 基本信息
enum AVMediaType codec_type; // 媒体类型
const struct AVCodec *codec; // 关联的编解码器
enum AVCodecID codec_id; // 编解码器ID
// 音频相关参数
int bit_rate; // 比特率(bits/sec)
int sample_rate; // 采样率(Hz)
enum AVSampleFormat sample_fmt; // 采样格式(AV_SAMPLE_FMT_S16/FLTP等)
int frame_size; // 每帧采样点数(单个通道)
// 新版本:声道布局(替代channel_layout和channels)
AVChannelLayout ch_layout; // 声道布局结构
// 旧版本(已废弃,但兼容性保留):
// uint64_t channel_layout; // 声道布局(位掩码)
// int channels; // 通道数
// 编解码器特定参数
int profile; // 编码配置文件(如FF_PROFILE_AAC_LOW)
int level; // 编码级别
// 标志位
int flags; // 编解码器标志
// AV_CODEC_FLAG_GLOBAL_HEADER: 全局头信息
// 时间相关
AVRational time_base; // 时间基(用于PTS/DTS计算)
// 私有数据
void *priv_data; // 编解码器私有数据
} AVCodecContext;
3. AVFrame
c
typedef struct AVFrame {
// 数据平面
uint8_t *data[AV_NUM_DATA_POINTERS]; // 数据指针数组
int linesize[AV_NUM_DATA_POINTERS]; // 每行字节数
// 音频相关
int nb_samples; // 本帧中的采样点数(单个通道)
enum AVSampleFormat format; // 采样格式
int sample_rate; // 采样率
// 新版本:声道布局
AVChannelLayout ch_layout; // 声道布局结构
// 时间戳
int64_t pts; // 显示时间戳(以time_base为单位)
int64_t pkt_dts; // 解码时间戳
// 质量指标
int quality; // 质量值(编码器使用)
// 引用计数
int width, height; // 图像尺寸(视频用)
int key_frame; // 是否为关键帧(视频用)
enum AVPictureType pict_type; // 图像类型(视频用)
// 扩展数据
AVDictionary *metadata; // 元数据
} AVFrame;
4. AVPacket
c
typedef struct AVPacket {
// 数据缓冲区
uint8_t *data; // 压缩数据
int size; // 数据大小
// 时间信息
int64_t pts; // 显示时间戳
int64_t dts; // 解码时间戳
int64_t duration; // 数据持续时间
AVRational time_base; // 时间基
// 流索引
int stream_index; // 所属流的索引
// 标志位
int flags; // 包标志
// AV_PKT_FLAG_KEY: 关键帧
// 编解码器私有数据
void *opaque; // 私有数据指针
void *opaque_ref; // 引用计数私有数据
// 缓冲区管理
AVBufferRef *buf; // 缓冲区引用(引用计数管理)
// 扩展数据
AVDictionary *metadata; // 元数据
} AVPacket;
5. AVChannelLayout(新版本FFmpeg,≥5.0)
c
typedef struct AVChannelLayout {
// 布局类型
enum AVChannelOrder order; // 声道顺序类型:
// AV_CHANNEL_ORDER_UNSPEC: 未指定
// AV_CHANNEL_ORDER_NATIVE: 原生顺序
// AV_CHANNEL_ORDER_CUSTOM: 自定义
// 声道数量
int nb_channels; // 声道数
union {
// 当order == AV_CHANNEL_ORDER_NATIVE时使用
uint64_t mask; // 声道掩码(兼容旧API)
// 当order == AV_CHANNEL_ORDER_CUSTOM时使用
struct {
AVChannelCustom *map; // 自定义声道映射
int nb_channels; // 声道数
} custom;
} u;
// 布局名称
char *name; // 布局描述名称
} AVChannelLayout;
6. AVDictionary(选项字典)
c
typedef struct AVDictionaryEntry {
char *key; // 键名
char *value; // 键值
} AVDictionaryEntry;
typedef struct AVDictionary AVDictionary; // 不透明结构
7. 重要枚举类型
AVSampleFormat(采样格式)
c
enum AVSampleFormat {
AV_SAMPLE_FMT_NONE = -1,
AV_SAMPLE_FMT_U8, ///< 无符号8位整数
AV_SAMPLE_FMT_S16, ///< 有符号16位整数(常用)
AV_SAMPLE_FMT_S32, ///< 有符号32位整数
AV_SAMPLE_FMT_FLT, ///< 单精度浮点数(packed)
AV_SAMPLE_FMT_DBL, ///< 双精度浮点数
AV_SAMPLE_FMT_U8P, ///< 无符号8位整数(planar)
AV_SAMPLE_FMT_S16P, ///< 有符号16位整数(planar)
AV_SAMPLE_FMT_S32P, ///< 有符号32位整数(planar)
AV_SAMPLE_FMT_FLTP, ///< 单精度浮点数(planar,AAC编码器常用)
AV_SAMPLE_FMT_DBLP, ///< 双精度浮点数(planar)
AV_SAMPLE_FMT_NB ///< 格式数量
};
AVMediaType(媒体类型)
c
enum AVMediaType {
AVMEDIA_TYPE_UNKNOWN = -1, ///< 未知类型
AVMEDIA_TYPE_VIDEO, ///< 视频
AVMEDIA_TYPE_AUDIO, ///< 音频
AVMEDIA_TYPE_DATA, ///< 数据
AVMEDIA_TYPE_SUBTITLE, ///< 字幕
AVMEDIA_TYPE_ATTACHMENT, ///< 附件
AVMEDIA_TYPE_NB ///< 类型数量
};
AVCodecID(编解码器ID)
c
enum AVCodecID {
AV_CODEC_ID_NONE,
// 音频编解码器
AV_CODEC_ID_MP2,
AV_CODEC_ID_MP3,
AV_CODEC_ID_AAC,
AV_CODEC_ID_AC3,
AV_CODEC_ID_DTS,
AV_CODEC_ID_VORBIS,
AV_CODEC_ID_OPUS,
AV_CODEC_ID_FLAC,
// 视频编解码器...
};
8. 关键API函数
编解码器相关
c
// 查找编解码器
const AVCodec *avcodec_find_encoder(enum AVCodecID id);
const AVCodec *avcodec_find_encoder_by_name(const char *name);
// 分配编解码器上下文
AVCodecContext *avcodec_alloc_context3(const AVCodec *codec);
// 打开编解码器
int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
// 发送帧到编码器
int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame);
// 从编码器接收包
int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt);
// 释放资源
void avcodec_free_context(AVCodecContext **avctx);
帧和包管理
c
// 分配帧
AVFrame *av_frame_alloc(void);
// 分配包
AVPacket *av_packet_alloc(void);
// 为帧分配数据缓冲区
int av_frame_get_buffer(AVFrame *frame, int align);
// 确保帧可写
int av_frame_make_writable(AVFrame *frame);
// 填充音频样本数组
int av_samples_fill_arrays(uint8_t **audio_data, int *linesize,
const uint8_t *buf, int nb_channels,
int nb_samples, enum AVSampleFormat sample_fmt,
int align);
// 释放帧
void av_frame_free(AVFrame **frame);
// 释放包
void av_packet_free(AVPacket **pkt);
// 取消包的引用
void av_packet_unref(AVPacket *pkt);
声道布局相关(新API)
c
// 初始化默认声道布局
int av_channel_layout_default(AVChannelLayout *ch_layout, int nb_channels);
// 复制声道布局
int av_channel_layout_copy(AVChannelLayout *dst, const AVChannelLayout *src);
// 获取声道布局描述
int av_channel_layout_describe(const AVChannelLayout *ch_layout,
char *buf, size_t buf_size);
// 释放声道布局资源
void av_channel_layout_uninit(AVChannelLayout *ch_layout);
// 获取声道数
int av_get_channel_layout_nb_channels(uint64_t channel_layout); // 旧API
采样格式相关
c
// 获取采样格式名称
const char *av_get_sample_fmt_name(enum AVSampleFormat sample_fmt);
// 获取采样格式的字节数
int av_get_bytes_per_sample(enum AVSampleFormat sample_fmt);
// 检查采样格式是否为planar
int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt);
9. 数据结构关系图
AVCodec
↓ (avcodec_find_encoder)
↓
AVCodecContext ←─ 编码参数配置
↓ (avcodec_open2)
↓
AVFrame ←─ 原始音频数据
↓ (avcodec_send_frame)
↓
编码器内部处理
↓
AVPacket ←─ 编码后数据
↓ (avcodec_receive_packet)
↓
输出文件/网络
10. 内存管理原则
-
分配与释放配对:
avcodec_alloc_context3()↔avcodec_free_context()av_frame_alloc()↔av_frame_free()av_packet_alloc()↔av_packet_free()
-
引用计数:
AVPacket使用buf字段管理引用计数- 调用
av_packet_unref()减少引用计数
-
深度复制:
- 使用
av_packet_ref()复制数据 - 使用
av_frame_ref()复制帧数据
- 使用
-
RAII原则(C++中):
- 使用智能指针包装FFmpeg资源
- 在析构函数中自动释放资源
11. 常见问题与解决方案
采样格式不匹配
c
// AAC编码器通常需要FLTP格式
if (strcmp(codec->name, "aac") == 0) {
ctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
}
// libfdk_aac通常需要S16格式
else if (strcmp(codec->name, "libfdk_aac") == 0) {
ctx->sample_fmt = AV_SAMPLE_FMT_S16;
}
声道布局兼容性
c
// 新旧API兼容处理
#if LIBAVUTIL_VERSION_MAJOR >= 57
// 使用AVChannelLayout
AVChannelLayout layout = AV_CHANNEL_LAYOUT_STEREO;
av_channel_layout_copy(&ctx->ch_layout, &layout);
#else
// 使用旧API
ctx->channel_layout = AV_CH_LAYOUT_STEREO;
ctx->channels = 2;
#endif
全局头标志
c
// 设置全局头标志
ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
// 编码AAC时,需要手动添加ADTS头
if (ctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
// 添加ADTS头
write_adts_header(ctx, packet);
}