需配对设置aom_codec_iface_t*(如aom_codec_av1_cx()),否则aom_codec_enc_init_ver返回AOM_CODEC_INVALID_PARAM;必须用aom_img_alloc分配图像内存,aom_img_wrap封装YUV数据,解码后逐plane按stride复制,且需循环调用aom_codec_get_frame获取延迟帧。

怎么用 libaom 在 C++ 里做 AV1 编码
直接调 aom_codec_enc_init_ver 初始化编码器,但必须配对设置 aom_codec_iface_t*(比如 aom_codec_av1_cx()),否则返回 AOM_CODEC_INVALID_PARAM。常见错误是传了 NULL 或错的接口指针,结果 aom_codec_err_to_string 报 “Invalid parameter”,其实根本没进初始化逻辑。
关键步骤:
- 调
aom_codec_enc_config_default拿默认配置,再改g_w/g_h、g_timebase、rc_target_bitrate -
g_usage设成AOM_USAGE_GOOD_QUALITY(非实时)或AOM_USAGE_REALTIME(低延迟),影响编码策略和线程行为 - 编码前要调
aom_img_alloc分配符合img_fmt(如AOM_IMG_FMT_I420)的图像内存,不能直接塞 OpenCV 的cv::Mat.data - 每次
aom_codec_encode前,用aom_img_wrap把原始 YUV 数据包一层,别反复 alloc/free
解码时怎么拿到可用的 YUV 帧
解码器输出的 aom_image_t* 默认是 planar YUV,但内存布局不一定是连续的——img->planes[0] 到 img->planes[2] 可能分散在不同地址,且 stride 不等于宽度。直接 memcpy 整块内存会出错。
正确做法:
立即学习“C++免费学习笔记(深入)”;
- 检查
img->fmt,确保是预期格式(如AOM_IMG_FMT_I420),不是AOM_IMG_FMT_I444或带 alpha 的变种 - 逐 plane 复制:
memcpy(dst_y, img->planes[0], img->d_h * img->stride[0]),注意用stride[n]而非d_w - YUV 尺寸不是固定 4:2:0 下采样:
img->d_w/img->d_h是可见尺寸,img->r_w/img->r_h是重建尺寸(可能有 padding),解码后帧应按d_*渲染
aom_codec_decode 返回 AOM_CODEC_OK 却没输出帧?
这是最常被忽略的点:AV1 解码有“延迟帧”机制,尤其在 B-frame 或多参考场景下,输入 N 帧,可能第 N−2 帧才吐出第一帧。调完 aom_codec_decode 后必须循环调 aom_codec_get_frame,直到它返回 NULL。
典型误操作:
- 只 decode 一次就以为完事,结果首帧丢失
- 没检查
aom_codec_iter_t迭代器是否为 NULL,直接传给aom_codec_get_frame导致 segfault - 把
aom_codec_decode的返回值当帧数用,其实它只表示解析状态,不反映输出帧数量
编解码性能和线程配置要注意什么
libaom 默认单线程,但实际性能差很多。编码侧靠 cfg->g_threads 控制 worker 数量,解码侧靠 dec_cfg.threads;两者都建议设为 CPU 逻辑核数,但别超 aom_codec_get_caps 返回的 AOM_CODEC_CAP_DECODER / AOM_CODEC_CAP_ENCODER 支持上限。
几个硬限制:
- 编码时
g_threads > 1要求g_usage == AOM_USAGE_GOOD_QUALITY,REALTIME模式下多线程无效 - 解码启用多线程后,
aom_codec_get_frame可能并发返回不同帧,需自行加锁保护输出队列 - Windows 上若用 MSVC 编译,务必链接
libaom-md.lib(多线程版),静态链接libaom-s.lib会崩溃
AV1 编解码链路里,内存对齐、帧边界判断、线程安全这几处最容易漏查,一跑就是黑屏或卡死,而不是报错。



















