ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

Linux FFmpeg深度解析之avdevice_list_devices调用流程与实战(七)

Linux FFmpeg深度解析之avdevice_list_devices调用流程与实战(七)

简介: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从上下文选择设备格式
        • 3.2创建列表并返回所有权
      • 🌻4.实战案例
        • 4.1准备输入设备上下文
        • 4.2调用接口并检查返回值
        • 4.3完整代码
      • 🌻5.总结

🌻1.前言

本篇目的:理解avdevice_list_devices()如何从已有AVFormatContext分派到设备格式的枚举回调,并通过程序检查返回的设备列表。

avdevice_list_devices()用于枚举设备格式能够发现的设备。与avdevice_list_input_sources()不同,它接收调用者准备好的AVFormatContext,从其中的iformat或oformat取得设备格式。它不创建采集流,也不读取音视频帧。

已配置的AVFormatContext

avdevice_list_devices

检查输入或输出格式

调用设备格式枚举回调

返回AVDeviceInfoList

🌻2.应用场景和用法

2.1使用设备上下文枚举设备

avdevice_list_devices()适合调用者已经持有设备格式上下文、需要直接触发该格式设备列表回调的场景。

场景调用方式注意事项
列出输入设备设置AVFormatContext.iformat后调用输入格式必须实现设备枚举回调
列出输出设备设置AVFormatContext.oformat后调用输出格式必须实现设备枚举回调
应用设备私有参数在上下文中准备对应选项回调是否使用这些参数由设备格式决定
检查设备枚举支持观察负错误码不支持枚举时返回AVERROR(ENOSYS)

该接口不会替调用者创建AVFormatContext,也不会选择输入或输出设备格式。上下文中必须至少设置iformat或oformat之一。对输入设备来说,具体设备格式还必须实现get_device_list。

2.2函数原型与返回语义

函数原型如下:

intavdevice_list_devices(AVFormatContext*s,AVDeviceInfoList**device_list);
参数或返回值含义
s已配置输入或输出设备格式的AVFormatContext
device_list接收设备列表的输出参数
非负返回值成功发现的设备数量
负返回值AVERROR错误码

调用成功后,device_list指向新分配的AVDeviceInfoList,调用者需要通过avdevice_free_list_devices()释放列表及内部设备信息。发生回调错误时,函数会释放内部已分配的列表。设备格式没有实现枚举回调时,返回AVERROR(ENOSYS)且列表为空。

与相邻接口相比,avdevice_list_input_sources()会根据输入格式和设备名创建临时上下文,应用选项,调用avdevice_list_devices()后释放上下文。avdevice_list_devices()则直接使用调用者传入的上下文,适合已有上下文的代码路径。

🌻3.调用流程剖析

3.1从上下文选择设备格式

函数首先断言AVFormatContext和输出指针有效,并要求上下文至少包含iformat或oformat。随后检查对应设备格式是否实现了get_device_list回调。

输入设备通过AVInputFormat.get_device_list分派;输出设备则通过AVOutputFormat内部的设备接口分派。缺少回调时,函数将输出列表设为NULL并返回AVERROR(ENOSYS)。

否

是

否

是

AVFormatContext

包含输入或输出格式

调用前置条件不满足

设备格式实现枚举回调

设置空列表并返回ENOSYS

分派到格式回调

3.2创建列表并返回所有权

通过能力检查后,通用层分配并清零AVDeviceInfoList,将default_device初始化为-1,再调用设备格式的枚举回调。

回调返回负值时,通用层释放列表并返回错误码。回调成功时,通用层返回nb_devices,并将列表交给调用者负责释放。返回值是数量或错误码,不是设备索引;默认设备索引需要单独读取列表的default_device字段。

负值

非负值

设备格式枚举回调

创建并初始化AVDeviceInfoList

回调填充设备信息

回调返回值

释放列表并返回错误

返回nb_devices和列表

调用者释放列表

🌻4.实战案例

4.1准备输入设备上下文

下面以ALSA输入格式为例,手动创建AVFormatContext并设置iformat。这个接口只需要上下文能够提供设备格式和枚举回调;这里不调用avformat_open_input(),因此不会开始采集。

4.2调用接口并检查返回值

调用avdevice_list_devices()后,非负返回值表示枚举成功。程序遍历AVDeviceInfoList读取设备名和描述,之后分别释放列表和自己创建的AVFormatContext。

如果当前格式没有设备列表回调,接口返回AVERROR(ENOSYS)。设备列表也可能为空,这表示该后端当前没有发现设备,不等同于函数调用失败。

4.3完整代码
#include<stdio.h>#include<libavdevice/avdevice.h>#include<libavformat/avformat.h>#include<libavutil/error.h>staticvoidprint_error(interror){charmessage[AV_ERROR_MAX_STRING_SIZE];av_strerror(error,message,sizeof(message));fprintf(stderr,"Device enumeration failed: %s\n",message);}intmain(void){AVFormatContext*format_context=NULL;constAVInputFormat*input_format;AVDeviceInfoList*device_list=NULL;intcount;inti;intresult=1;/* 注册设备格式并查找ALSA输入格式 */avdevice_register_all();input_format=av_find_input_format("alsa");if(input_format==NULL){fprintf(stderr,"ALSA input format is unavailable\n");gotodone;}/* 创建上下文,并明确设置输入设备格式 */format_context=avformat_alloc_context();if(format_context==NULL){fprintf(stderr,"Could not allocate AVFormatContext\n");gotodone;}format_context->iformat=input_format;/* 通过已有上下文调用设备枚举接口 */count=avdevice_list_devices(format_context,&device_list);if(count<0){print_error(count);gotodone;}/* 遍历接口返回的设备名称和描述 */for(i=0;device_list!=NULL&&i<device_list->nb_devices;i++){constAVDeviceInfo*device=device_list->devices[i];printf("device: %s\n",device->device_name!=NULL?device->device_name:"(unknown)");printf("description: %s\n",device->device_description!=NULL?device->device_description:"(no description)");}result=0;done:/* 列表和上下文分别由调用者释放 */avdevice_free_list_devices(&device_list);avformat_free_context(format_context);returnresult;}

🌻5.总结

avdevice_list_devices()根据已有AVFormatContext分派设备枚举回调,返回设备数量和由调用者释放的列表,不负责创建采集流。

RELATED READING

延伸阅读

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