ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Linux FFmpeg深度解析之av_parser_init调用流程与实战(二十一)

Linux FFmpeg深度解析之av_parser_init调用流程与实战(二十一)

简介:CSDN博客专家、《Android系统多媒体进阶实战》作者

博主新书推荐:《Android系统多媒体进阶实战》🚀
Android Audio工程师专栏地址:Audio工程师进阶系列【原创干货持续更新中……】🚀
Android多媒体专栏地址:多媒体系统工程师系列【原创干货持续更新中……】🚀
专题一 二:AAOS车载系统+AOSP14系统攻城狮入门视频实战课🚀
专题三:Android14 Binder之HIDL与AIDL通信实战课🚀
专题四:Android15快速自定义与集成音效实战课🚀
专题五:Android15音频策略实战课🚀
专题六:Android15音频性能实战课(无声/杂音/断音/爆音实战案例)🚀

人生格言:人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮

点击获取二维码


🍉🍉🍉文章目录🍉🍉🍉

      • 🌻1.前言
      • 🌻2.应用场景和用法
        • 2.1按编码格式选择解析器
        • 2.2函数原型与返回语义
      • 🌻3.调用流程剖析
        • 3.1遍历注册表并匹配编码ID
        • 3.2初始化上下文并管理私有数据
      • 🌻4.实战案例
        • 4.1准备编码格式
        • 4.2创建解析器并验证生命周期
        • 4.3完整代码
      • 🌻5.总结

🌻1.前言

本篇目的:理解av_parser_init()如何根据AVCodecID查找并创建解析器上下文,分析解析器注册表、私有状态和av_parser_parse2()之间的关系。

压缩码流可能以任意字节块到达,输入块边界不一定与视频帧或音频帧边界重合。av_parser_init()按编码格式创建对应的AVCodecParserContext,供后续解析调用使用。它只创建解析器状态,不读取输入数据,也不拆分数据包。

编码格式AVCodecID

av_parser_init

查找已注册解析器

创建解析器上下文

交给后续parse2调用

🌻2.应用场景和用法

2.1按编码格式选择解析器

当应用读取的是裸H.264、MPEG视频或某些需要边界识别的音频码流时,可以为对应编码格式创建解析器,再把字节流交给av_parser_parse2()。解析器负责识别码流中的帧边界,供解码器逐帧处理。

使用场景调用动作结果
裸视频码流解码使用视频AVCodecID创建解析器后续按帧边界提交压缩数据
音频码流拆帧使用音频AVCodecID创建解析器识别连续码流中的音频帧
读取容器中的压缩包根据包边界和解码器要求判断是否需要解析器避免不必要的二次拆包
当前构建没有对应解析器检查创建结果处理NULL,不能继续调用parse接口

容器Demuxer已经提供完整压缩包时,通常不需要应用再创建解析器。是否需要解析器取决于输入数据是否已经具备解码器需要的边界。

2.2函数原型与返回语义

函数原型如下:

AVCodecParserContext*av_parser_init(intcodec_id);
参数或返回值含义
codec_id目标压缩格式对应的AVCodecID
返回AVCodecParserContext *创建成功的解析器上下文
返回NULL编码ID无效、没有匹配解析器或上下文分配失败

最小调用方式如下:

AVCodecParserContext*parser;parser=av_parser_init(AV_CODEC_ID_H264);if(parser==NULL){/* 当前构建没有可用的H.264解析器,或创建失败 */returnAVERROR_DECODER_NOT_FOUND;}/* 后续将parser传给av_parser_parse2 */av_parser_close(parser);

解析器上下文由av_parser_init()分配,使用结束后必须调用av_parser_close()释放。这个函数不会创建AVCodecContext,也不会打开解码器;解析阶段需要调用者另行准备与解析器编码ID匹配的AVCodecContext。

🌻3.调用流程剖析

3.1遍历注册表并匹配编码ID

av_parser_init()首先检查codec_id是否为AV_CODEC_ID_NONE。随后通过av_parser_iterate()遍历当前构建注册的解析器列表,逐个检查解析器支持的编码ID数组。找到匹配项后停止遍历;遍历结束仍未匹配则返回NULL。

否

是

传入codec_id

遍历解析器注册表

解析器是否支持该ID

继续查找或返回NULL

分配解析器上下文

3.2初始化上下文并管理私有数据

匹配成功后,函数分配并清零AVCodecParserContext,保存找到的解析器对象,再按解析器要求分配priv_data。随后设置时间戳获取状态、图像类型、帧格式等初始字段。

如果解析器实现了parser_init回调,函数会调用它初始化解析器私有状态。私有内存分配或初始化失败时,函数释放已分配对象并返回NULL。

创建成功后,AVCodecParserContext保存解析器实现和流解析状态。之后av_parser_parse2()会更新帧偏移、时间戳和解析进度;av_parser_close()则调用解析器关闭回调并释放私有数据和上下文。

🌻4.实战案例

4.1准备编码格式

示例选择H.264编码ID。解析器是否可用取决于当前FFmpeg构建中是否包含对应解析器,因此程序必须检查av_parser_init()的返回值。

4.2创建解析器并验证生命周期

创建成功后,程序检查上下文非空,再调用av_parser_close()释放资源。此处只验证解析器查找和上下文创建,不读取码流;码流切帧属于av_parser_parse2()的职责。

4.3完整代码
#include<libavcodec/avcodec.h>#include<libavutil/error.h>intmain(void){AVCodecParserContext*parser=NULL;intret=1;/* 根据H.264编码ID查找并创建解析器上下文 */parser=av_parser_init(AV_CODEC_ID_H264);if(parser==NULL)gotodone;/* 上下文创建成功,解析器可交给parse2使用 */ret=0;done:/* 释放av_parser_init创建的解析器上下文 */av_parser_close(parser);returnret;}

🌻5.总结

av_parser_init()根据AVCodecID查找已注册的解析器并创建AVCodecParserContext,供后续码流解析使用。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进