如何在FFmpeg分支的libavcodec中为视频嵌入自定义元数据
解决FFmpeg Hap编码器全局最大包大小传递到解码器的问题
核心思路
要将编码阶段计算的全局最大编码包大小传递到解码阶段,必须通过编码器的extradata字段——这是FFmpeg中编码器向解码器传递全局元数据的标准通道,其他字段(如priv_data、flags2)要么是实例私有,要么不被容器持久化存储,无法跨编码-解码阶段传递。
具体实现步骤
1. 在编码器私有结构体中存储计算值
在hapenc.c的HapEncContext结构体中新增字段,保存你已经计算好的最大包大小:
typedef struct HapEncContext { // 原有字段(如编码参数、临时缓冲区等) int max_frame_size; // 新增:存储全局最大编码包大小 } HapEncContext;
在编码流程中完成计算后,将结果赋值给s->max_frame_size。
2. 扩展并更新编码器的extradata
在编码器的收尾阶段(比如hap_encode_close函数),将max_frame_size追加到原有extradata的末尾,确保容器能将该数据写入文件元数据:
static int hap_encode_close(AVCodecContext *avctx) { HapEncContext *s = avctx->priv_data; int orig_extradata_size = avctx->extradata_size; int new_extradata_size = orig_extradata_size + sizeof(int32_t); // 重新分配extradata内存,预留空间存储max_frame_size uint8_t *new_extradata = av_realloc(avctx->extradata, new_extradata_size); if (!new_extradata) { // 错误处理 av_freep(&avctx->extradata); return AVERROR(ENOMEM); } // 用大端序写入数值,保证跨平台兼容性 AV_WB32(new_extradata + orig_extradata_size, s->max_frame_size); // 更新AVCodecContext的extradata指针和大小 avctx->extradata = new_extradata; avctx->extradata_size = new_extradata_size; // 原有收尾逻辑... return 0; }
3. 在解码器中读取扩展的extradata
在hapdec.c的解码器初始化函数(比如hap_decode_init)中,读取extradata末尾的max_frame_size:
static int hap_decode_init(AVCodecContext *avctx) { HapDecContext *s = avctx->priv_data; // 检查extradata是否包含我们追加的最大包大小字段 if (avctx->extradata_size >= sizeof(int32_t)) { // 用大端序读取数值,和编码器保持一致 s->max_frame_size = AV_RB32(avctx->extradata + avctx->extradata_size - sizeof(int32_t)); } else { // 未获取到自定义数据时,使用默认值(适配原有逻辑) s->max_frame_size = YOUR_DEFAULT_MAX_SIZE; } // 原有初始化逻辑... return 0; }
为什么之前的方法失效
priv_data:是编码器/解码器各自的私有结构体实例,编码和解码阶段的AVCodecContext完全独立,数据不会自动传递。flags2:属于通用标志位,无预留位存储自定义数值,且容器不会将该字段写入文件元数据,解码阶段无法读取。- 错误的
extradata修改方式:如果之前只是直接修改extradata_size但未正确分配内存、或未在容器持久化的阶段更新,数据会丢失——必须在编码器收尾时重新分配并写入,确保容器能将扩展后的extradata存入文件的轨道元数据(如MOV/MP4的stsdatom)。
内容的提问来源于stack exchange,提问作者leavittx
相关产品推荐
相关产品推荐

