如何使用FFmpeg解码uint8_t*缓冲区中的编码流数据
场景支持性结论
完全支持。FFmpeg解码器的输入只要求是符合对应编码标准(H.264/H.265/AAC等)的合法编码二进制数据,不要求数据必须来自本地文件、网络流的解封装输出,你持有的uint8_t*类型编码缓冲区只要存储的是合法编码数据,就可以直接送入解码器完成解码。
uint8_t*缓冲区转AVPacket的具体方法
你不需要手动逐字段给AVPacket赋值,根据你的内存管理需求选以下两种方案即可:
- 方案1:拷贝模式(兼容性最高,无内存管理坑)
- 调用
AVPacket* pkt = av_packet_alloc();分配空的AVPacket结构 - 调用
av_new_packet(pkt, buffer_size);给pkt分配和你的编码数据等长的内部缓冲区 - 调用
memcpy(pkt->data, encoded_data, buffer_size);把你的缓冲区内容拷贝到pkt的内部缓冲区中
这种方案下AVPacket自己持有独立的内存副本,你的原编码缓冲区在拷贝完成后可以随时释放,不需要关心解码器的消费时机,适合绝大多数场景。
- 调用
- 方案2:零拷贝模式(性能更好,需严格遵守内存生命周期要求)
- 调用
AVPacket* pkt = av_packet_alloc();分配空的AVPacket结构 - 调用
av_packet_from_data(pkt, encoded_data, buffer_size);直接将你的编码缓冲区挂载到pkt结构上,无额外内存拷贝
注意:这个接口默认你的encoded_data是通过av_malloc()系列FFmpeg内存接口分配的,pkt销毁时会自动调用av_free()释放该缓冲区。如果你的缓冲区是通过malloc/new等其他方式分配的,不要直接用这个接口,否则会触发非法内存释放导致崩溃。
- 调用
需初始化的元数据参数说明
元数据配置分两种场景处理:
- 场景1:缓冲区存储的是自包含格式的裸码流
比如带AnnexB头(起始码0x00000001)的H.264/H.265码流、带ADTS头的AAC码流,这类码流本身已经把解码必需的参数集(SPS/PPS/VPS/音频配置信息)打包在码流里,你只需要给pkt填两个基础字段即可:pkt->pts:显示时间戳,没有时间戳信息填AV_NOPTS_VALUE即可pkt->dts:解码时间戳,没有时间戳信息填AV_NOPTS_VALUE即可
如果你明确知道当前包是关键帧,可以给pkt加标记pkt->flags |= AV_PKT_FLAG_KEY,不填也不影响解码器正常识别。
- 场景2:缓冲区存储的是不带参数集的裸编码帧
比如从MP4/FLV等封装里提取的AVCC格式H.264帧、不带ADTS头的AAC原始帧,这类数据的解码参数集存在封装头中、不在帧数据里,你不能只配置pkt,必须在初始化解码器上下文AVCodecContext的时候,提前把参数集数据填充到AVCodecContext->extradata字段,同时设置extradata_size为参数集的长度,否则解码器会因为缺少必要参数报解码失败。
构造完成的AVPacket可以直接传给avcodec_send_packet()接口走标准解码流程,pkt使用完成后记得调用av_packet_free(&pkt);释放资源避免泄漏。
内容的提问来源于stack exchange,提问作者K. Srikar
相关产品推荐
相关产品推荐

