简介:CSDN博客专家、《Android系统多媒体进阶实战》作者
博主新书推荐:《Android系统多媒体进阶实战》🚀
Android Audio工程师专栏地址:Audio工程师进阶系列【原创干货持续更新中……】🚀
Android多媒体专栏地址:多媒体系统工程师系列【原创干货持续更新中……】🚀
专题一 二:AAOS车载系统+AOSP14系统攻城狮入门视频实战课🚀
专题三:Android14 Binder之HIDL与AIDL通信实战课🚀
专题四:Android15快速自定义与集成音效实战课🚀
专题五:Android15音频策略实战课🚀
专题六:Android15音频性能实战课(无声/杂音/断音/爆音实战案例)🚀
人生格言:人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
点击获取二维码
🍉🍉🍉文章目录🍉🍉🍉
- 🌻1.前言
- 🌻2.应用场景和用法
- 2.1遍历输入格式的应用场景
- 2.2函数原型与返回语义
- 🌻3.调用流程剖析
- 3.1从编译生成的格式列表中返回对象
- 3.2在查找和探测流程中的位置
- 🌻4.实战案例
- 4.1准备输入格式枚举程序
- 4.2遍历并检查格式描述
- 4.3完整代码
- 🌻5.总结
🌻1.前言
本篇目的:理解
av_demuxer_iterate()如何遍历当前FFmpeg构建中注册的输入格式,分析迭代状态和返回对象,并通过C程序列出可用的demuxer。
FFmpeg打开媒体时,需要从当前构建可用的输入格式中选择候选项。av_demuxer_iterate()提供逐个遍历这些格式描述对象的接口。
它只负责返回下一个AVInputFormat,不读取媒体数据、不探测文件内容,也不打开输入文件。文件探测和打开由其他API完成。
🌻2.应用场景和用法
2.1遍历输入格式的应用场景
av_demuxer_iterate()适合需要了解或检查当前FFmpeg构建所支持输入格式的场景。
| 场景 | 使用方式 | 能得到什么 |
|---|---|---|
| 列出可用demuxer | 循环调用接口,直到返回NULL | 获取每个AVInputFormat描述对象 |
| 检查定制构建 | 遍历并查看格式名称 | 确认目标格式是否包含在当前构建中 |
| 按名称查找格式 | 遍历并比较AVInputFormat.name | 实现类似av_find_input_format()的查找逻辑 |
| 自定义探测流程 | 遍历格式并按需调用探测回调 | 获取候选格式,探测逻辑仍由调用者负责 |
返回列表取决于FFmpeg构建时启用的组件。被配置排除的demuxer不会出现在列表中。调用者不能把“列表里没有”直接解释成媒体类型不受FFmpeg支持,也要考虑当前二进制的构建配置。
2.2函数原型与返回语义
函数原型如下:
constAVInputFormat*av_demuxer_iterate(void**opaque);| 参数或返回值 | 含义 |
|---|---|
opaque | 由调用者持有的迭代状态指针,开始遍历时必须指向NULL |
| 返回值 | 下一个已注册输入格式的描述对象 |
返回NULL | 当前迭代已经结束 |
最小调用方式如下:
void*iter=NULL;constAVInputFormat*fmt;while((fmt=av_demuxer_iterate(&iter))!=NULL){/* 使用fmt->name、fmt->long_name等描述字段 */}opaque是接口内部使用的迭代状态。调用者应原样传回,不要解引用、修改或释放它。每次独立遍历都要使用新的状态变量,或在开始前重新设为NULL。
返回的AVInputFormat是FFmpeg注册表中的格式描述对象,类型为const指针。它不是新分配给调用者的对象,不需要释放。接口本身不创建AVFormatContext,也不触发文件读取或格式探测。
相邻接口的职责不同:
| 接口 | 作用 |
|---|---|
av_demuxer_iterate() | 逐个返回已注册输入格式 |
av_find_input_format() | 按名称从输入格式中查找对象 |
av_probe_input_format3() | 根据探测数据和候选格式计算匹配结果 |
avformat_open_input() | 打开输入并创建或使用AVFormatContext |
🌻3.调用流程剖析
3.1从编译生成的格式列表中返回对象
FFmpeg构建时会生成demuxer列表。av_demuxer_iterate()把调用者传入的opaque解释为当前遍历位置,再从静态demuxer_list中取出对应的格式描述对象。
核心逻辑如下:
constAVInputFormat*av_demuxer_iterate(void**opaque){staticconstuintptr_tsize=sizeof(demuxer_list)/sizeof(demuxer_list[0])-1;uintptr_ti=(uintptr_t)*opaque;constAVInputFormat*f=NULL;if(i<size){f=demuxer_list[i];}if(f)*opaque=(void*)(i+1);returnf;}每次成功返回一个格式对象,内部位置就前进一项。列表结束后,函数返回NULL,调用者应结束循环。实际源码还会检查是否注册了libavdevice输入设备列表;如果存在,也可以继续从该列表中返回输入设备格式。使用avdevice_register_all()注册输入设备属于libavdevice的职责,不是av_demuxer_iterate()自动完成的。
3.2在查找和探测流程中的位置
av_find_input_format()内部也通过av_demuxer_iterate()遍历格式,再使用格式名称匹配目标项。av_probe_input_format3()则会遍历候选格式,并根据探测数据调用相应格式的探测逻辑,累计匹配分数。
因此,这三个动作处于不同层次:迭代接口提供格式描述对象,查找接口按名称筛选对象,探测接口结合媒体数据判断格式。迭代本身不会判断某个文件究竟是什么格式。
🌻4.实战案例
4.1准备输入格式枚举程序
程序使用一个初始化为NULL的void *保存迭代状态,并通过av_demuxer_iterate()逐个获取输入格式。每次返回的对象都可读取name和long_name,循环以返回NULL结束。
4.2遍历并检查格式描述
观察两个内容:
- 每次调用是否返回一个
AVInputFormat对象。 - 迭代结束时是否返回
NULL,以及遍历期间累计了多少个格式对象。
格式名称来自当前FFmpeg构建中实际生成的列表。若需要同时枚举输入设备,应链接libavdevice并按其接口完成设备注册。
4.3完整代码
#include<libavformat/avformat.h>#include<stdio.h>intmain(void){void*iter=NULL;constAVInputFormat*fmt;unsignedintcount=0;/* 从NULL状态开始,逐个读取当前构建注册的输入格式 */while((fmt=av_demuxer_iterate(&iter))!=NULL){constchar*long_name=fmt->long_name?fmt->long_name:"无描述";/* name是短名称,long_name是可读格式说明 */printf("%-20s %s\n",fmt->name,long_name);count++;}/* count反映本次遍历实际返回的格式对象数量 */printf("demuxer count: %u\n",count);return0;}🌻5.总结
av_demuxer_iterate()根据调用者保存的迭代状态逐个返回当前构建中注册的AVInputFormat对象,供格式枚举、查找或后续探测流程使用。