简介:CSDN博客专家、《Android系统多媒体进阶实战》作者
博主新书推荐:《Android系统多媒体进阶实战》🚀
Android Audio工程师专栏地址:Audio工程师进阶系列【原创干货持续更新中……】🚀
Android多媒体专栏地址:多媒体系统工程师系列【原创干货持续更新中……】🚀
专题一 二:AAOS车载系统+AOSP14系统攻城狮入门视频实战课🚀
专题三:Android14 Binder之HIDL与AIDL通信实战课🚀
专题四:Android15快速自定义与集成音效实战课🚀
专题五:Android15音频策略实战课🚀
专题六:Android15音频性能实战课(无声/杂音/断音/爆音实战案例)🚀
人生格言:人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
🍉🍉🍉文章目录🍉🍉🍉
- 🌻1.前言
- 🌻2.应用场景和用法
- 2.1切换AcceptCaps处理路径
- 2.2函数原型与返回语义
- 🌻3.调用流程剖析
- 3.1输入Pad查询与处理分派
- 3.2默认处理与自定义处理的差异
- 🌻4.实战案例
- 4.1准备Opus解码器和宽泛Caps查询
- 4.2切换处理路径并观察查询结果
- 4.3完整代码与关键输出
- 🌻5.总结
🌻1.前言
本篇目的:理解
gst_audio_decoder_set_use_default_pad_acceptcaps()如何改变GstAudioDecoder输入Pad对ACCEPT_CAPS查询的处理路径,并通过实际查询验证默认Pad处理和自定义处理的差异。
GstAudioDecoder创建时会拥有输入Pad、输出Pad以及对应的Pad模板。上游在协商前可能通过GST_QUERY_ACCEPT_CAPS询问输入Pad是否能够接受某组Caps。
gst_audio_decoder_set_use_default_pad_acceptcaps()不直接执行查询,也不修改Caps。它只修改一个内部开关,决定后续ACCEPT_CAPS查询使用GStreamer默认Pad处理逻辑,还是使用GstAudioDecoder自己的兼容处理逻辑。
Pad上的GST_PAD_SET_ACCEPT_TEMPLATE和GST_PAD_SET_ACCEPT_INTERSECT标志,决定默认处理逻辑使用Pad模板还是动态查询结果,以及采用子集判断还是交集判断。
🌻2.应用场景和用法
2.1切换AcceptCaps处理路径
gst_audio_decoder_set_use_default_pad_acceptcaps()主要用于需要调整输入PadCaps接受策略的音频解码器子类。
| 场景 | 使用方式 | 解决的问题 |
|---|---|---|
| 解码器希望使用Pad默认查询逻辑 | 传入TRUE | 由Pad默认处理器决定Caps是否可接受 |
| 解码器需要接受不完整Caps | 配合GST_PAD_SET_ACCEPT_INTERSECT | 使用交集判断,而不是要求查询Caps完全属于允许Caps |
| 解码器希望避免递归查询 | 配合GST_PAD_SET_ACCEPT_TEMPLATE | 直接使用Pad模板Caps,避免再次触发动态Caps查询 |
| 解码器需要自定义模板和动态Caps判断 | 传入FALSE | 继续使用GstAudioDecoder内置的兼容处理逻辑 |
Vorbis和Opus解码器都在实例初始化时调用该函数,并把输入Pad设置为使用模板Caps。说明这个接口通常用于解码器子类初始化阶段,而不是每次收到查询时重复调用。
函数调用时机错误也会产生明显差异:
- 只设置Pad标志而不调用该函数,
GstAudioDecoder仍可能走自定义AcceptCaps路径。 - 只传入
TRUE而不设置交集标志,默认处理仍然可能使用子集判断。 - 把
ACCEPT_CAPS查询当成真正的Caps设置,不会改变当前PadCaps,也不会触发解码器的set_format()。
2.2函数原型与返回语义
函数原型如下:
voidgst_audio_decoder_set_use_default_pad_acceptcaps(GstAudioDecoder*decoder,gboolean use);| 参数 | 含义 |
|---|---|
decoder | 有效的GstAudioDecoder对象,通常是具体解码器子类实例 |
use | 传入TRUE使用默认PadAcceptCaps处理,传入FALSE使用GstAudioDecoder自定义处理 |
函数返回值为void。它只写入内部字段:
decoder->priv->use_default_pad_acceptcaps=use;最小调用方式如下:
gst_audio_decoder_set_use_default_pad_acceptcaps(decoder,TRUE);GST_PAD_SET_ACCEPT_TEMPLATE(GST_AUDIO_DECODER_SINK_PAD(decoder));GST_PAD_SET_ACCEPT_INTERSECT(GST_AUDIO_DECODER_SINK_PAD(decoder));调用前,解码器实例和输入Pad已经由GstAudioDecoder基类创建。调用后,后续输入Pad收到GST_QUERY_ACCEPT_CAPS时会根据内部开关选择处理路径。
这个函数不会:
- 创建或释放Pad。
- 修改Pad模板Caps。
- 发送Caps事件。
- 触发解码器回调。
- 直接返回Caps查询结果。
- 自动设置
GST_PAD_SET_ACCEPT_TEMPLATE或GST_PAD_SET_ACCEPT_INTERSECT。
几个相邻接口的职责不同:
| 接口 | 作用 |
|---|---|
gst_audio_decoder_set_use_default_pad_acceptcaps() | 切换GstAudioDecoder的AcceptCaps处理路径 |
gst_audio_decoder_sink_query_default() | 处理基类输入Pad收到的查询 |
gst_pad_query_default() | 执行Pad默认查询逻辑 |
gst_pad_query_accept_caps() | 由调用者发起AcceptCaps查询并取得布尔结果 |
GST_PAD_SET_ACCEPT_TEMPLATE() | 让默认处理使用Pad模板Caps |
GST_PAD_SET_ACCEPT_INTERSECT() | 让默认处理使用交集判断 |
gst_audio_decoder_proxy_getcaps() | 处理CAPS查询,不等同于ACCEPT_CAPS查询 |
🌻3.调用流程剖析
3.1输入Pad查询与处理分派
GstAudioDecoder初始化时,会为输入Pad注册查询函数。输入Pad收到查询后,首先进入gst_audio_decoder_sink_query(),再调用GstAudioDecoderClass中的sink_query虚函数。
基类默认使用gst_audio_decoder_sink_query_default()。当查询类型为GST_QUERY_ACCEPT_CAPS时,函数读取use_default_pad_acceptcaps字段。
字段为TRUE时,调用gst_pad_query_default()。字段为FALSE时,进入音频解码器自己的模板Caps和允许Caps判断逻辑。
这个函数只影响查询分派。真正发起查询的是上游或应用,真正设置查询结果的是Pad查询处理器。
3.2默认处理与自定义处理的差异
当use为FALSE时,gst_audio_decoder_sink_query_default()会执行自定义逻辑:
gst_query_parse_accept_caps(query,&caps);template_caps=gst_pad_get_pad_template_caps(pad);accept=gst_caps_is_subset(caps,template_caps);gst_caps_unref(template_caps);if(accept){allowed_caps=gst_pad_query_caps(pad,caps);accept=gst_caps_can_intersect(caps,allowed_caps);gst_caps_unref(allowed_caps);}gst_query_set_accept_caps_result(query,accept);这条路径先要求查询Caps属于Pad模板Caps,再查询当前允许Caps并执行交集判断。
当use为TRUE时,函数调用gst_pad_query_default()。默认Pad处理器会先得到一组允许Caps:
- 设置
GST_PAD_SET_ACCEPT_TEMPLATE时,允许Caps来自Pad模板。 - 未设置该标志时,允许Caps来自Pad的动态Caps查询。
得到允许Caps后,比较方式由另一个Pad标志决定:
- 设置
GST_PAD_SET_ACCEPT_INTERSECT时,调用gst_caps_can_intersect()。 - 未设置该标志时,调用
gst_caps_is_subset()。
所以,gst_audio_decoder_set_use_default_pad_acceptcaps()只是处理路径开关。默认路径的最终行为,还要结合两个Pad标志共同决定。
🌻4.实战案例
4.1准备Opus解码器和宽泛Caps查询
本案例使用opusdec作为具体的GstAudioDecoder子类。Opus解码器的输入Pad模板包含多种audio/x-opus格式约束,宽泛的audio/x-opusCaps可以与模板产生交集,但不一定属于模板Caps的子集。
程序创建解码器后,获取输入Pad,并准备一组宽泛Caps:
GstElement*decoder;GstPad*sink_pad;GstCaps*query_caps;decoder=gst_element_factory_make("opusdec",NULL);sink_pad=gst_element_get_static_pad(decoder,"sink");query_caps=gst_caps_from_string("audio/x-opus");系统需要安装包含opusdec的GStreamer插件。插件不存在时,程序会直接提示,不能把缺少插件误判为AcceptCaps失败。
4.2切换处理路径并观察查询结果
程序执行三次查询:
use设置为FALSE,使用GstAudioDecoder自定义逻辑。use设置为TRUE,使用默认Pad逻辑,但关闭交集判断。use设置为TRUE,同时开启模板Caps和交集判断。
第三种配置允许宽泛的audio/x-opus与Pad模板产生交集,能够验证目标函数和Pad标志之间的关系。
4.3完整代码与关键输出
#include<gst/gst.h>#include<gst/audio/audio.h>intmain(intargc,char*argv[]){GstElement*decoder;GstPad*sink_pad;GstCaps*query_caps;gboolean custom_result;gboolean default_subset_result;gboolean default_intersect_result;gst_init(&argc,&argv);decoder=gst_element_factory_make("opusdec",NULL);if(decoder==NULL){g_printerr("opusdec plugin is unavailable\n");return1;}sink_pad=gst_element_get_static_pad(decoder,"sink");if(sink_pad==NULL){g_printerr("Failed to get decoder sink pad\n");gst_object_unref(decoder);return1;}query_caps=gst_caps_from_string("audio/x-opus");if(query_caps==NULL){g_printerr("Failed to create query caps\n");gst_object_unref(sink_pad);gst_object_unref(decoder);return1;}gst_audio_decoder_set_use_default_pad_acceptcaps(GST_AUDIO_DECODER(decoder),FALSE);custom_result=gst_pad_query_accept_caps(sink_pad,query_caps);gst_audio_decoder_set_use_default_pad_acceptcaps(GST_AUDIO_DECODER(decoder),TRUE);GST_PAD_SET_ACCEPT_TEMPLATE(sink_pad);GST_PAD_UNSET_ACCEPT_INTERSECT(sink_pad);default_subset_result=gst_pad_query_accept_caps(sink_pad,query_caps);GST_PAD_SET_ACCEPT_INTERSECT(sink_pad);default_intersect_result=gst_pad_query_accept_caps(sink_pad,query_caps);g_print("Custom handler: %s\n",custom_result?"TRUE":"FALSE");g_print("Default subset handler: %s\n",default_subset_result?"TRUE":"FALSE");g_print("Default intersect handler: %s\n",default_intersect_result?"TRUE":"FALSE");gst_caps_unref(query_caps);gst_object_unref(sink_pad);gst_object_unref(decoder);return0;}编译运行:
gcc test_audio_decoder_acceptcaps.c-otest_audio_decoder_acceptcaps\$(pkg-config--cflags--libsgstreamer-1.0 gstreamer-audio-1.0)./test_audio_decoder_acceptcaps在opusdec插件可用且Pad模板保持当前实现时,关键输出应体现三种处理差异:
Custom handler: FALSE Default subset handler: FALSE Default intersect handler: TRUE这个结果说明,gst_audio_decoder_set_use_default_pad_acceptcaps()本身不决定Caps一定接受或拒绝。它只把查询交给默认Pad处理器,最终结果还取决于Pad模板、允许Caps以及GST_PAD_SET_ACCEPT_INTERSECT等标志。
🌻5.总结
gst_audio_decoder_set_use_default_pad_acceptcaps()就是为GstAudioDecoder输入Pad选择默认或自定义的AcceptCaps查询处理路径,但它不负责设置Caps,最终接受结果仍由Pad模板、动态Caps和Pad标志共同决定。