简介: CSDN博客专家、《Android系统多媒体进阶实战》作者
博主新书推荐:《Android系统多媒体进阶实战》🚀
Android Audio工程师专栏地址:Audio工程师进阶系列【原创干货持续更新中...... 】🚀
Android多媒体专栏地址:多媒体系统工程师系列【原创干货持续更新中...... 】🚀
专题一 二:AAOS车载系统+AOSP14系统攻城狮入门视频实战课 🚀
专题三:Android14 Binder之HIDL与AIDL通信实战课 🚀
专题四:Android15快速自定义与集成音效实战课 🚀
专题五:Android15音频策略实战课 🚀
专题六:Android15音频性能实战课(无声/杂音/断音/爆音实战案例) 🚀
人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
更多原创,欢迎关注:Android系统攻城狮

🍉🍉🍉文章目录🍉🍉🍉
🌻1.前言
本篇目的:理解
gst_audio_ring_buffer_parse_caps()如何把协商后的音频Caps转换为GstAudioRingBufferSpec,分析格式识别和分段参数计算,并通过C程序检查解析结果。
音频设备需要的不只是audio/x-raw格式。RingBuffer还要知道音频类型、采样率、每帧字节数、缓冲区时长和单段大小。gst_audio_ring_buffer_parse_caps()负责把Caps中的格式信息写入规格对象,并根据预设的缓冲时长计算分段参数。
它只解析Caps并更新GstAudioRingBufferSpec,不申请设备资源、不分配音频缓冲区,也不启动读写。
#mermaid-svg-vPVC3F6W4tLA3s2P{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-vPVC3F6W4tLA3s2P .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-vPVC3F6W4tLA3s2P .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-vPVC3F6W4tLA3s2P .error-icon{fill:#552222;}#mermaid-svg-vPVC3F6W4tLA3s2P .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-vPVC3F6W4tLA3s2P .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-vPVC3F6W4tLA3s2P .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-vPVC3F6W4tLA3s2P .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-vPVC3F6W4tLA3s2P .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-vPVC3F6W4tLA3s2P .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-vPVC3F6W4tLA3s2P .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-vPVC3F6W4tLA3s2P .marker{fill:#333333;stroke:#333333;}#mermaid-svg-vPVC3F6W4tLA3s2P .marker.cross{stroke:#333333;}#mermaid-svg-vPVC3F6W4tLA3s2P svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-vPVC3F6W4tLA3s2P p{margin:0;}#mermaid-svg-vPVC3F6W4tLA3s2P .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-vPVC3F6W4tLA3s2P .cluster-label text{fill:#333;}#mermaid-svg-vPVC3F6W4tLA3s2P .cluster-label span{color:#333;}#mermaid-svg-vPVC3F6W4tLA3s2P .cluster-label span p{background-color:transparent;}#mermaid-svg-vPVC3F6W4tLA3s2P .label text,#mermaid-svg-vPVC3F6W4tLA3s2P span{fill:#333;color:#333;}#mermaid-svg-vPVC3F6W4tLA3s2P .node rect,#mermaid-svg-vPVC3F6W4tLA3s2P .node circle,#mermaid-svg-vPVC3F6W4tLA3s2P .node ellipse,#mermaid-svg-vPVC3F6W4tLA3s2P .node polygon,#mermaid-svg-vPVC3F6W4tLA3s2P .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-vPVC3F6W4tLA3s2P .rough-node .label text,#mermaid-svg-vPVC3F6W4tLA3s2P .node .label text,#mermaid-svg-vPVC3F6W4tLA3s2P .image-shape .label,#mermaid-svg-vPVC3F6W4tLA3s2P .icon-shape .label{text-anchor:middle;}#mermaid-svg-vPVC3F6W4tLA3s2P .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-vPVC3F6W4tLA3s2P .rough-node .label,#mermaid-svg-vPVC3F6W4tLA3s2P .node .label,#mermaid-svg-vPVC3F6W4tLA3s2P .image-shape .label,#mermaid-svg-vPVC3F6W4tLA3s2P .icon-shape .label{text-align:center;}#mermaid-svg-vPVC3F6W4tLA3s2P .node.clickable{cursor:pointer;}#mermaid-svg-vPVC3F6W4tLA3s2P .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-vPVC3F6W4tLA3s2P .arrowheadPath{fill:#333333;}#mermaid-svg-vPVC3F6W4tLA3s2P .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-vPVC3F6W4tLA3s2P .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-vPVC3F6W4tLA3s2P .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vPVC3F6W4tLA3s2P .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-vPVC3F6W4tLA3s2P .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vPVC3F6W4tLA3s2P .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-vPVC3F6W4tLA3s2P .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-vPVC3F6W4tLA3s2P .cluster text{fill:#333;}#mermaid-svg-vPVC3F6W4tLA3s2P .cluster span{color:#333;}#mermaid-svg-vPVC3F6W4tLA3s2P 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-vPVC3F6W4tLA3s2P .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-vPVC3F6W4tLA3s2P rect.text{fill:none;stroke-width:0;}#mermaid-svg-vPVC3F6W4tLA3s2P .icon-shape,#mermaid-svg-vPVC3F6W4tLA3s2P .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vPVC3F6W4tLA3s2P .icon-shape p,#mermaid-svg-vPVC3F6W4tLA3s2P .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-vPVC3F6W4tLA3s2P .icon-shape .label rect,#mermaid-svg-vPVC3F6W4tLA3s2P .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vPVC3F6W4tLA3s2P .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-vPVC3F6W4tLA3s2P .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-vPVC3F6W4tLA3s2P :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 协商后的音频Caps
gst_audio_ring_buffer_parse_caps
已设置的缓冲时长
识别音频类型并填写音频信息
计算分段大小和分段数量
更新GstAudioRingBufferSpec
🌻2.应用场景和用法
2.1从Caps准备RingBuffer规格
GstAudioBaseSink和GstAudioBaseSrc都需要在设置Caps时准备RingBuffer规格。Sink解析新Caps后调用该函数,再申请缓冲资源;Source解析Caps后还会根据采样率、BPF和延迟参数重新计算分段大小。
该函数支持多种音频媒体类型。audio/x-raw分支调用gst_audio_info_from_caps()解析原始音频信息;其他分支根据媒体类型提取所需字段,并设置对应的RingBuffer格式类型和BPF。源码包含A-Law、μ-Law、IEC 958、AC-3、E-AC-3、DTS、MPEG音频、AAC、FLAC和DSD等处理分支。
2.2函数原型与返回语义
函数原型如下:
c
gboolean
gst_audio_ring_buffer_parse_caps (GstAudioRingBufferSpec *spec,
GstCaps *caps);
| 参数或返回值 | 含义 |
|---|---|
spec |
接收解析结果的RingBuffer规格对象 |
caps |
描述已协商音频格式的Caps |
TRUE |
媒体类型及必需字段解析成功,分段参数已写入spec |
FALSE |
Caps类型不支持、必需字段缺失或格式解析失败 |
调用前,spec->buffer_time和spec->latency_time应已设置,其中latency_time不能为0。调用方还应传入有效且已协商为具体格式的Caps。原始音频分支要求Caps符合gst_audio_info_from_caps()的固定Caps条件。
最小调用方式如下:
c
GstAudioRingBufferSpec spec = { 0 };
spec.buffer_time = 200000;
spec.latency_time = 10000;
if (!gst_audio_ring_buffer_parse_caps (&spec, caps)) {
/* 按格式协商失败处理 */
}
成功后,spec中包含音频类型、GstAudioInfo、持有引用的Caps、分段大小、分段总数和待确定的分段延迟。调用者仍需检查返回值;函数没有分配RingBuffer内存,也没有调用设备驱动。
🌻3.调用流程剖析
3.1识别媒体类型并提取音频信息
函数首先读取Caps中的第一个GstStructure,获取媒体类型,并初始化临时GstAudioInfo。
遇到audio/x-raw时,函数把Caps交给gst_audio_info_from_caps()。解析成功后将spec->type设为GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW。
编码格式按对应媒体类型处理。例如,A-Law和μ-Law需要采样率与声道数,并将BPF设为声道数;IEC 958设置固定BPF;MPEG音频和AAC根据版本及stream-format设置对应类型;DSD则根据字格式宽度换算RingBuffer使用的字率和BPF。
不支持的媒体类型、缺失必需字段或底层音频信息解析失败都会进入错误分支并返回FALSE。
#mermaid-svg-ApsRfqdV0yNuh8Us{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-ApsRfqdV0yNuh8Us .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ApsRfqdV0yNuh8Us .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ApsRfqdV0yNuh8Us .error-icon{fill:#552222;}#mermaid-svg-ApsRfqdV0yNuh8Us .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ApsRfqdV0yNuh8Us .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ApsRfqdV0yNuh8Us .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ApsRfqdV0yNuh8Us .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ApsRfqdV0yNuh8Us .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ApsRfqdV0yNuh8Us .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ApsRfqdV0yNuh8Us .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ApsRfqdV0yNuh8Us .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ApsRfqdV0yNuh8Us .marker.cross{stroke:#333333;}#mermaid-svg-ApsRfqdV0yNuh8Us svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ApsRfqdV0yNuh8Us p{margin:0;}#mermaid-svg-ApsRfqdV0yNuh8Us .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ApsRfqdV0yNuh8Us .cluster-label text{fill:#333;}#mermaid-svg-ApsRfqdV0yNuh8Us .cluster-label span{color:#333;}#mermaid-svg-ApsRfqdV0yNuh8Us .cluster-label span p{background-color:transparent;}#mermaid-svg-ApsRfqdV0yNuh8Us .label text,#mermaid-svg-ApsRfqdV0yNuh8Us span{fill:#333;color:#333;}#mermaid-svg-ApsRfqdV0yNuh8Us .node rect,#mermaid-svg-ApsRfqdV0yNuh8Us .node circle,#mermaid-svg-ApsRfqdV0yNuh8Us .node ellipse,#mermaid-svg-ApsRfqdV0yNuh8Us .node polygon,#mermaid-svg-ApsRfqdV0yNuh8Us .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ApsRfqdV0yNuh8Us .rough-node .label text,#mermaid-svg-ApsRfqdV0yNuh8Us .node .label text,#mermaid-svg-ApsRfqdV0yNuh8Us .image-shape .label,#mermaid-svg-ApsRfqdV0yNuh8Us .icon-shape .label{text-anchor:middle;}#mermaid-svg-ApsRfqdV0yNuh8Us .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ApsRfqdV0yNuh8Us .rough-node .label,#mermaid-svg-ApsRfqdV0yNuh8Us .node .label,#mermaid-svg-ApsRfqdV0yNuh8Us .image-shape .label,#mermaid-svg-ApsRfqdV0yNuh8Us .icon-shape .label{text-align:center;}#mermaid-svg-ApsRfqdV0yNuh8Us .node.clickable{cursor:pointer;}#mermaid-svg-ApsRfqdV0yNuh8Us .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ApsRfqdV0yNuh8Us .arrowheadPath{fill:#333333;}#mermaid-svg-ApsRfqdV0yNuh8Us .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ApsRfqdV0yNuh8Us .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ApsRfqdV0yNuh8Us .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ApsRfqdV0yNuh8Us .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ApsRfqdV0yNuh8Us .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ApsRfqdV0yNuh8Us .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ApsRfqdV0yNuh8Us .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ApsRfqdV0yNuh8Us .cluster text{fill:#333;}#mermaid-svg-ApsRfqdV0yNuh8Us .cluster span{color:#333;}#mermaid-svg-ApsRfqdV0yNuh8Us 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-ApsRfqdV0yNuh8Us .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ApsRfqdV0yNuh8Us rect.text{fill:none;stroke-width:0;}#mermaid-svg-ApsRfqdV0yNuh8Us .icon-shape,#mermaid-svg-ApsRfqdV0yNuh8Us .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ApsRfqdV0yNuh8Us .icon-shape p,#mermaid-svg-ApsRfqdV0yNuh8Us .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ApsRfqdV0yNuh8Us .icon-shape .label rect,#mermaid-svg-ApsRfqdV0yNuh8Us .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ApsRfqdV0yNuh8Us .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ApsRfqdV0yNuh8Us .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ApsRfqdV0yNuh8Us :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} audio x raw
编码音频
其他类型
读取Caps首个Structure
媒体类型
调用AudioInfo解析
提取类型字段并设置BPF
返回解析失败
写入RingBuffer格式类型
进入分段参数计算
3.2计算分段参数并更新Spec
格式解析完成后,函数用gst_caps_replace()让spec->caps持有当前Caps,再检查latency_time是否为0。随后使用采样率、BPF和延迟时间计算单段字节数:
c
spec->segsize = gst_util_uint64_scale (
info.rate * info.bpf,
spec->latency_time,
GST_SECOND / GST_USECOND);
/* 将单段大小向下调整到完整Frame边界 */
spec->segsize -= spec->segsize % info.bpf;
spec->segtotal = spec->buffer_time / spec->latency_time;
spec->seglatency = -1;
spec->info = info;
latency_time和buffer_time以微秒计。segsize先按每秒字节率乘单段时长计算,再向下对齐到BPF的整数倍,避免一个音频Frame被切到两个分段中。segtotal是总缓冲时长除以单段时长得到的分段数量。seglatency设为-1表示暂未指定,后续采集资源时可采用默认值。
例如,48kHz、S16LE、双声道音频的BPF为4字节。若latency_time为10000微秒,则单段大小为1920字节。
#mermaid-svg-DmG3bKmnHvM7UFdV{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-DmG3bKmnHvM7UFdV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DmG3bKmnHvM7UFdV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DmG3bKmnHvM7UFdV .error-icon{fill:#552222;}#mermaid-svg-DmG3bKmnHvM7UFdV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DmG3bKmnHvM7UFdV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DmG3bKmnHvM7UFdV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DmG3bKmnHvM7UFdV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DmG3bKmnHvM7UFdV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DmG3bKmnHvM7UFdV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DmG3bKmnHvM7UFdV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DmG3bKmnHvM7UFdV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DmG3bKmnHvM7UFdV .marker.cross{stroke:#333333;}#mermaid-svg-DmG3bKmnHvM7UFdV svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DmG3bKmnHvM7UFdV p{margin:0;}#mermaid-svg-DmG3bKmnHvM7UFdV .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-DmG3bKmnHvM7UFdV .cluster-label text{fill:#333;}#mermaid-svg-DmG3bKmnHvM7UFdV .cluster-label span{color:#333;}#mermaid-svg-DmG3bKmnHvM7UFdV .cluster-label span p{background-color:transparent;}#mermaid-svg-DmG3bKmnHvM7UFdV .label text,#mermaid-svg-DmG3bKmnHvM7UFdV span{fill:#333;color:#333;}#mermaid-svg-DmG3bKmnHvM7UFdV .node rect,#mermaid-svg-DmG3bKmnHvM7UFdV .node circle,#mermaid-svg-DmG3bKmnHvM7UFdV .node ellipse,#mermaid-svg-DmG3bKmnHvM7UFdV .node polygon,#mermaid-svg-DmG3bKmnHvM7UFdV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DmG3bKmnHvM7UFdV .rough-node .label text,#mermaid-svg-DmG3bKmnHvM7UFdV .node .label text,#mermaid-svg-DmG3bKmnHvM7UFdV .image-shape .label,#mermaid-svg-DmG3bKmnHvM7UFdV .icon-shape .label{text-anchor:middle;}#mermaid-svg-DmG3bKmnHvM7UFdV .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-DmG3bKmnHvM7UFdV .rough-node .label,#mermaid-svg-DmG3bKmnHvM7UFdV .node .label,#mermaid-svg-DmG3bKmnHvM7UFdV .image-shape .label,#mermaid-svg-DmG3bKmnHvM7UFdV .icon-shape .label{text-align:center;}#mermaid-svg-DmG3bKmnHvM7UFdV .node.clickable{cursor:pointer;}#mermaid-svg-DmG3bKmnHvM7UFdV .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-DmG3bKmnHvM7UFdV .arrowheadPath{fill:#333333;}#mermaid-svg-DmG3bKmnHvM7UFdV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DmG3bKmnHvM7UFdV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DmG3bKmnHvM7UFdV .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DmG3bKmnHvM7UFdV .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-DmG3bKmnHvM7UFdV .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DmG3bKmnHvM7UFdV .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-DmG3bKmnHvM7UFdV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DmG3bKmnHvM7UFdV .cluster text{fill:#333;}#mermaid-svg-DmG3bKmnHvM7UFdV .cluster span{color:#333;}#mermaid-svg-DmG3bKmnHvM7UFdV 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-DmG3bKmnHvM7UFdV .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-DmG3bKmnHvM7UFdV rect.text{fill:none;stroke-width:0;}#mermaid-svg-DmG3bKmnHvM7UFdV .icon-shape,#mermaid-svg-DmG3bKmnHvM7UFdV .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DmG3bKmnHvM7UFdV .icon-shape p,#mermaid-svg-DmG3bKmnHvM7UFdV .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-DmG3bKmnHvM7UFdV .icon-shape .label rect,#mermaid-svg-DmG3bKmnHvM7UFdV .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DmG3bKmnHvM7UFdV .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-DmG3bKmnHvM7UFdV .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-DmG3bKmnHvM7UFdV :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 解析得到rate和BPF
读取buffer_time和latency_time
计算segsize并按BPF对齐
计算segtotal
设置seglatency为待确定
写回Caps和GstAudioInfo
在Sink调用路径中,GstAudioBaseSink先释放旧RingBuffer资源,再解析新Caps,随后调用gst_audio_ring_buffer_acquire()申请资源。Source调用路径也会先解析Caps,但它还会根据rate、BPF和延迟参数计算分段规格,并在采集成功后更新实际缓冲时长。
🌻4.实战案例
4.1准备48kHz双声道Caps和缓冲时长
案例直接调用gst_audio_ring_buffer_parse_caps(),不打开声卡。Caps描述S16LE、交错布局、48kHz、双声道原始音频;规格设置总缓冲时长200000微秒、单段延迟10000微秒。
按这些输入,预期BPF为4字节,单段大小为1920字节,分段总数为20。这个例子用来检查格式解析和规格计算,不代表任何物理设备的能力。
4.2解析Caps并检查计算结果
程序执行以下步骤:
- 创建固定的
audio/x-rawCaps。 - 初始化
GstAudioRingBufferSpec的缓冲时长参数。 - 调用解析函数。
- 检查音频类型、采样率、声道数、BPF、分段大小和分段数量。
- 释放解析函数为
spec.caps持有的Caps引用。
这里不调用gst_audio_ring_buffer_acquire()。解析完成只表示规格准备好,设备资源申请仍由后续调用者负责。
4.3完整代码
c
#include <gst/gst.h>
#include <gst/audio/audio.h>
#include <string.h>
int
main (int argc, char *argv[])
{
GstAudioRingBufferSpec spec;
GstCaps *caps;
gboolean parsed;
gboolean ok = FALSE;
gst_init (&argc, &argv);
/* 准备48kHz、S16LE、双声道交错音频Caps */
caps = gst_caps_new_simple (
"audio/x-raw",
"format", G_TYPE_STRING, "S16LE",
"layout", G_TYPE_STRING, "interleaved",
"rate", G_TYPE_INT, 48000,
"channels", G_TYPE_INT, 2,
NULL);
/* 清零规格,并设置解析前必须提供的缓冲时长 */
memset (&spec, 0, sizeof (spec));
spec.buffer_time = 200000;
spec.latency_time = 10000;
/* 解析Caps并生成RingBuffer音频与分段规格 */
parsed = gst_audio_ring_buffer_parse_caps (&spec, caps);
if (parsed) {
/* 检查格式识别和分段参数计算结果 */
ok = spec.type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW
&& GST_AUDIO_INFO_RATE (&spec.info) == 48000
&& GST_AUDIO_INFO_CHANNELS (&spec.info) == 2
&& GST_AUDIO_INFO_BPF (&spec.info) == 4
&& spec.segsize == 1920
&& spec.segtotal == 20
&& spec.seglatency == -1;
}
/* parse_caps通过spec.caps持有Caps引用,需要分别释放 */
if (spec.caps != NULL)
gst_caps_unref (spec.caps);
gst_caps_unref (caps);
return ok ? 0 : 1;
}
🌻5.总结
gst_audio_ring_buffer_parse_caps()就是把协商后的音频Caps转换为RingBuffer格式和分段规格,供后续资源采集流程使用。