Linux Gstreamer深度解析之gst_audio_aggregator_set_sink_caps调用流程与实战(九十一)

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

博主新书推荐:《Android系统多媒体进阶实战》🚀

Android Audio工程师专栏地址:Audio工程师进阶系列【原创干货持续更新中...... 】🚀

Android多媒体专栏地址:多媒体系统工程师系列【原创干货持续更新中...... 】🚀

专题一 二:AAOS车载系统+AOSP14系统攻城狮入门视频实战课 🚀

专题三:Android14 Binder之HIDL与AIDL通信实战课 🚀

专题四:Android15快速自定义与集成音效实战课 🚀

专题五:Android15音频策略实战课 🚀

专题六:Android15音频性能实战课(无声/杂音/断音/爆音实战案例) 🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
更多原创,欢迎关注:Android系统攻城狮

🍉🍉🍉文章目录🍉🍉🍉

🌻1.前言

本篇目的:理解gst_audio_aggregator_set_sink_caps()如何把输入Caps解析成GstAudioAggregatorPad的音频信息,并梳理它在interleave接收端Caps处理中的位置。

聚合类音频元素需要知道每个Sink Pad收到的音频格式,后续才能按Pad的格式处理输入数据。gst_audio_aggregator_set_sink_caps()负责把Caps解析并写入指定Pad的info字段。它不负责Caps协商,也不负责检查不同输入Pad的格式是否兼容。
#mermaid-svg-5IwCZdLoFPlV3tA0{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-5IwCZdLoFPlV3tA0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5IwCZdLoFPlV3tA0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5IwCZdLoFPlV3tA0 .error-icon{fill:#552222;}#mermaid-svg-5IwCZdLoFPlV3tA0 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5IwCZdLoFPlV3tA0 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5IwCZdLoFPlV3tA0 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5IwCZdLoFPlV3tA0 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5IwCZdLoFPlV3tA0 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5IwCZdLoFPlV3tA0 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5IwCZdLoFPlV3tA0 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5IwCZdLoFPlV3tA0 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5IwCZdLoFPlV3tA0 .marker.cross{stroke:#333333;}#mermaid-svg-5IwCZdLoFPlV3tA0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5IwCZdLoFPlV3tA0 p{margin:0;}#mermaid-svg-5IwCZdLoFPlV3tA0 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5IwCZdLoFPlV3tA0 .cluster-label text{fill:#333;}#mermaid-svg-5IwCZdLoFPlV3tA0 .cluster-label span{color:#333;}#mermaid-svg-5IwCZdLoFPlV3tA0 .cluster-label span p{background-color:transparent;}#mermaid-svg-5IwCZdLoFPlV3tA0 .label text,#mermaid-svg-5IwCZdLoFPlV3tA0 span{fill:#333;color:#333;}#mermaid-svg-5IwCZdLoFPlV3tA0 .node rect,#mermaid-svg-5IwCZdLoFPlV3tA0 .node circle,#mermaid-svg-5IwCZdLoFPlV3tA0 .node ellipse,#mermaid-svg-5IwCZdLoFPlV3tA0 .node polygon,#mermaid-svg-5IwCZdLoFPlV3tA0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5IwCZdLoFPlV3tA0 .rough-node .label text,#mermaid-svg-5IwCZdLoFPlV3tA0 .node .label text,#mermaid-svg-5IwCZdLoFPlV3tA0 .image-shape .label,#mermaid-svg-5IwCZdLoFPlV3tA0 .icon-shape .label{text-anchor:middle;}#mermaid-svg-5IwCZdLoFPlV3tA0 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5IwCZdLoFPlV3tA0 .rough-node .label,#mermaid-svg-5IwCZdLoFPlV3tA0 .node .label,#mermaid-svg-5IwCZdLoFPlV3tA0 .image-shape .label,#mermaid-svg-5IwCZdLoFPlV3tA0 .icon-shape .label{text-align:center;}#mermaid-svg-5IwCZdLoFPlV3tA0 .node.clickable{cursor:pointer;}#mermaid-svg-5IwCZdLoFPlV3tA0 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5IwCZdLoFPlV3tA0 .arrowheadPath{fill:#333333;}#mermaid-svg-5IwCZdLoFPlV3tA0 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5IwCZdLoFPlV3tA0 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5IwCZdLoFPlV3tA0 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5IwCZdLoFPlV3tA0 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5IwCZdLoFPlV3tA0 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5IwCZdLoFPlV3tA0 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5IwCZdLoFPlV3tA0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5IwCZdLoFPlV3tA0 .cluster text{fill:#333;}#mermaid-svg-5IwCZdLoFPlV3tA0 .cluster span{color:#333;}#mermaid-svg-5IwCZdLoFPlV3tA0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5IwCZdLoFPlV3tA0 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5IwCZdLoFPlV3tA0 rect.text{fill:none;stroke-width:0;}#mermaid-svg-5IwCZdLoFPlV3tA0 .icon-shape,#mermaid-svg-5IwCZdLoFPlV3tA0 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5IwCZdLoFPlV3tA0 .icon-shape p,#mermaid-svg-5IwCZdLoFPlV3tA0 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5IwCZdLoFPlV3tA0 .icon-shape .label rect,#mermaid-svg-5IwCZdLoFPlV3tA0 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5IwCZdLoFPlV3tA0 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5IwCZdLoFPlV3tA0 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5IwCZdLoFPlV3tA0 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Sink Pad收到Caps
元素检查Caps有效性
gst_audio_aggregator_set_sink_caps
解析Caps并更新Pad音频信息
聚合流程读取Pad信息

🌻2.应用场景和用法

2.1保存每个输入Pad的音频格式

GstAudioAggregatorPad包含一个GstAudioInfo成员,用于记录这个输入Pad当前对应的音频格式。gst_audio_aggregator_set_sink_caps()把Caps转换成该成员,供聚合器后续读取。

场景 调用前的处理 调用后的作用
interleave收到输入Caps 检查音频格式是否有效 保存Pad的采样率、声道数和格式
聚合器准备处理输入Buffer 已有Pad级音频信息 按Pad格式解释输入数据
输入格式变化 元素确认新Caps可以接受 更新Pad的音频信息
自定义GstAudioAggregator子类 确认Caps与自身策略兼容 将输入Caps写入聚合Pad状态

不能把这个接口当作Caps协商入口。它不会向上游查询Caps,也不会决定Src Pad输出Caps。调用者应先检查Caps,再调用此函数。

2.2函数原型与状态变化

函数原型如下:

c 复制代码
void
gst_audio_aggregator_set_sink_caps (GstAudioAggregator *aagg,
                                    GstAudioAggregatorPad *pad,
                                    GstCaps *caps);
参数 含义
aagg 所属的GstAudioAggregator对象
pad 需要更新音频信息的聚合器Sink Pad
caps 描述该Pad输入音频格式的Caps

函数返回类型为void。它会锁定Pad对象,调用gst_audio_info_from_caps()解析Caps并写入pad->info,随后解锁。

在启用断言的构建中,解析结果会通过g_assert()检查。禁用断言时,函数仍然尝试解析,但不处理失败结果。因此调用者需要在调用前确保Caps有效。函数本身不返回成功或失败状态。

相邻接口的职责不同:

接口或操作 职责
gst_audio_info_from_caps() 将Caps解析成GstAudioInfo
gst_audio_aggregator_set_sink_caps() 将解析结果写入聚合器Pad的info字段
聚合器的Caps处理函数 检查输入Caps是否符合元素策略
聚合器输出Caps协商 确定Src Pad对下游提供的格式

🌻3.调用流程剖析

3.1从输入Caps处理函数进入Pad信息更新

gst_audio_aggregator_set_sink_caps()在gstaudioaggregator.c中实现。一个实际调用者是GstAudioInterleave的Sink Pad Caps处理路径。

interleave先用gst_audio_info_from_caps()解析输入Caps,并检查输入格式以及它与已有Sink Pad格式的关系。通过这些检查后,才调用gst_audio_aggregator_set_sink_caps()更新对应Pad的信息。
#mermaid-svg-MgoA8QXCCrQPnMT1{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MgoA8QXCCrQPnMT1 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MgoA8QXCCrQPnMT1 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MgoA8QXCCrQPnMT1 .error-icon{fill:#552222;}#mermaid-svg-MgoA8QXCCrQPnMT1 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MgoA8QXCCrQPnMT1 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MgoA8QXCCrQPnMT1 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MgoA8QXCCrQPnMT1 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MgoA8QXCCrQPnMT1 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MgoA8QXCCrQPnMT1 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MgoA8QXCCrQPnMT1 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MgoA8QXCCrQPnMT1 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MgoA8QXCCrQPnMT1 .marker.cross{stroke:#333333;}#mermaid-svg-MgoA8QXCCrQPnMT1 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MgoA8QXCCrQPnMT1 p{margin:0;}#mermaid-svg-MgoA8QXCCrQPnMT1 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-MgoA8QXCCrQPnMT1 .cluster-label text{fill:#333;}#mermaid-svg-MgoA8QXCCrQPnMT1 .cluster-label span{color:#333;}#mermaid-svg-MgoA8QXCCrQPnMT1 .cluster-label span p{background-color:transparent;}#mermaid-svg-MgoA8QXCCrQPnMT1 .label text,#mermaid-svg-MgoA8QXCCrQPnMT1 span{fill:#333;color:#333;}#mermaid-svg-MgoA8QXCCrQPnMT1 .node rect,#mermaid-svg-MgoA8QXCCrQPnMT1 .node circle,#mermaid-svg-MgoA8QXCCrQPnMT1 .node ellipse,#mermaid-svg-MgoA8QXCCrQPnMT1 .node polygon,#mermaid-svg-MgoA8QXCCrQPnMT1 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MgoA8QXCCrQPnMT1 .rough-node .label text,#mermaid-svg-MgoA8QXCCrQPnMT1 .node .label text,#mermaid-svg-MgoA8QXCCrQPnMT1 .image-shape .label,#mermaid-svg-MgoA8QXCCrQPnMT1 .icon-shape .label{text-anchor:middle;}#mermaid-svg-MgoA8QXCCrQPnMT1 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MgoA8QXCCrQPnMT1 .rough-node .label,#mermaid-svg-MgoA8QXCCrQPnMT1 .node .label,#mermaid-svg-MgoA8QXCCrQPnMT1 .image-shape .label,#mermaid-svg-MgoA8QXCCrQPnMT1 .icon-shape .label{text-align:center;}#mermaid-svg-MgoA8QXCCrQPnMT1 .node.clickable{cursor:pointer;}#mermaid-svg-MgoA8QXCCrQPnMT1 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MgoA8QXCCrQPnMT1 .arrowheadPath{fill:#333333;}#mermaid-svg-MgoA8QXCCrQPnMT1 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MgoA8QXCCrQPnMT1 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MgoA8QXCCrQPnMT1 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MgoA8QXCCrQPnMT1 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MgoA8QXCCrQPnMT1 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MgoA8QXCCrQPnMT1 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MgoA8QXCCrQPnMT1 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MgoA8QXCCrQPnMT1 .cluster text{fill:#333;}#mermaid-svg-MgoA8QXCCrQPnMT1 .cluster span{color:#333;}#mermaid-svg-MgoA8QXCCrQPnMT1 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MgoA8QXCCrQPnMT1 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MgoA8QXCCrQPnMT1 rect.text{fill:none;stroke-width:0;}#mermaid-svg-MgoA8QXCCrQPnMT1 .icon-shape,#mermaid-svg-MgoA8QXCCrQPnMT1 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MgoA8QXCCrQPnMT1 .icon-shape p,#mermaid-svg-MgoA8QXCCrQPnMT1 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MgoA8QXCCrQPnMT1 .icon-shape .label rect,#mermaid-svg-MgoA8QXCCrQPnMT1 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MgoA8QXCCrQPnMT1 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MgoA8QXCCrQPnMT1 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MgoA8QXCCrQPnMT1 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否
是
interleave收到Sink Caps
解析并检查音频格式
Caps符合元素策略
拒绝本次Caps处理
更新interleave内部状态
调用聚合器Pad信息接口
Pad保存GstAudioInfo

调用者的预检查很重要:interleave可能需要确保多个Sink Pad的输入格式能用于同一个输出格式。这个策略由元素自身完成,不是gst_audio_aggregator_set_sink_caps()完成。

3.2在Pad锁内更新GstAudioInfo

函数的主体只做一件事:在Pad对象锁保护下解析Caps并更新pad->info。

核心逻辑如下:

c 复制代码
GST_OBJECT_LOCK (pad);
valid = gst_audio_info_from_caps (&pad->info, caps);
g_assert (valid);
GST_OBJECT_UNLOCK (pad);

在禁用断言的编译分支中,源码仍会执行gst_audio_info_from_caps(),但会忽略布尔返回值。由于函数返回void,调用者无法从函数返回值判断Caps解析结果。

pad->info表示单个Sink Pad的输入格式。它不是聚合器的输出格式,也不代表Caps已经成功发送给下游。输出格式仍由聚合器自己的Caps协商流程确定。

🌻4.实战案例

4.1准备interleave和请求Pad

本例创建interleave元素,请求一个Sink Pad,再准备一组合法的单声道S16LE音频Caps。

这里直接调用gst_audio_aggregator_set_sink_caps(),观察它对Pad音频信息的更新。这个最小例子只检查Pad字段,不运行完整的音频聚合管线。

4.2调用接口并检查Pad信息

调用前,先确认interleave元素和请求到的Sink Pad都创建成功。调用接口后,在Pad对象锁内检查采样率、声道数和音频格式是否与Caps一致。

Caps由调用者持有,因此检查完成后由调用者释放。请求Pad也应通过元素释放,再解除调用者持有的Pad引用。

4.3完整代码
c 复制代码
#include <gst/gst.h>
#include <gst/audio/audio.h>

int
main (int argc, char *argv[])
{
  GstElement *interleave;
  GstPad *sink_pad;
  GstCaps *caps;
  GstAudioAggregatorPad *audio_pad;
  gboolean valid;

  gst_init (&argc, &argv);

  /* 创建实际使用GstAudioAggregatorPad的interleave元素 */
  interleave = gst_element_factory_make ("interleave", NULL);
  if (interleave == NULL)
    return 1;

  /* 请求一个聚合器Sink Pad */
  sink_pad = gst_element_request_pad_simple (interleave, "sink_%u");
  if (sink_pad == NULL) {
    gst_object_unref (interleave);
    return 1;
  }

  /* 准备有效的单声道S16LE输入Caps */
  caps = gst_caps_new_simple (
      "audio/x-raw",
      "format", G_TYPE_STRING, "S16LE",
      "rate", G_TYPE_INT, 48000,
      "channels", G_TYPE_INT, 1,
      "layout", G_TYPE_STRING, "interleaved",
      NULL);

  audio_pad = GST_AUDIO_AGGREGATOR_PAD (sink_pad);

  /* 将Caps解析结果写入该Sink Pad的音频信息 */
  gst_audio_aggregator_set_sink_caps (
      GST_AUDIO_AGGREGATOR (interleave),
      audio_pad,
      caps);

  /* 按Pad对象锁要求读取公开的只读info字段 */
  GST_OBJECT_LOCK (audio_pad);
  valid =
      GST_AUDIO_INFO_FORMAT (&audio_pad->info) == GST_AUDIO_FORMAT_S16
      && GST_AUDIO_INFO_RATE (&audio_pad->info) == 48000
      && GST_AUDIO_INFO_CHANNELS (&audio_pad->info) == 1;
  GST_OBJECT_UNLOCK (audio_pad);

  /* 释放Caps、请求Pad和元素 */
  gst_caps_unref (caps);
  gst_element_release_request_pad (interleave, sink_pad);
  gst_object_unref (sink_pad);
  gst_object_unref (interleave);

  return valid ? 0 : 1;
}

🌻5.总结

gst_audio_aggregator_set_sink_caps()在Pad对象锁保护下把有效Caps解析为GstAudioInfo并保存到指定的GstAudioAggregatorPad中。

相关推荐
kkkkkkkkkk_Z1 小时前
新手自学嵌入式 | 学习日记: Linux驱动进阶 —— Platform总线与I2C子系统实战
linux·运维·学习
‎ദ്ദിᵔ.˛.ᵔ₎1 小时前
Linux线程:this指针在pthread中的解决方案
linux
tedcloud1231 小时前
Docker Compose 部署 Memos:从安装到备份恢复
linux·开发语言·jvm·后端·docker·容器·rust
qq_377572771 小时前
typora install linux ubuntu
linux·ubuntu
John_Hui1 小时前
CentOS7安装Nginx
linux·服务器·nginx
qetfw1 小时前
Bash 基础:脚本执行、引号与命令替换验证
linux·开发语言·chrome·bash
怪力左手1 小时前
cuda-toolkit离线安装
linux·运维·人工智能
Gauss松鼠会1 小时前
GaussDB 内存相关参数及故障诊断
运维·数据库·sql·oracle·性能优化·架构·gaussdb
鬼手点金1 小时前
带工具调用的多轮交互:Agent 的核心循环
服务器·人工智能·windows·深度学习·microsoft·机器学习·交互