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

🍉🍉🍉文章目录🍉🍉🍉
-
-
- 🌻1.前言
- 🌻2.应用场景和用法
-
- [🌻2.1 应用场景](#🌻2.1 应用场景)
- [🌻2.2 函数用法](#🌻2.2 函数用法)
- 🌻3.调用流程剖析
-
- [🌻3.1 分发到重采样器和量化器](#🌻3.1 分发到重采样器和量化器)
- [🌻3.2 清除转换历史但保留处理配置](#🌻3.2 清除转换历史但保留处理配置)
- 🌻4.实战案例
-
- [🌻4.1 创建带重采样历史的转换器](#🌻4.1 创建带重采样历史的转换器)
- [🌻4.2 重置后再次处理同一段输入](#🌻4.2 重置后再次处理同一段输入)
- [🌻4.3 验证两次输出一致](#🌻4.3 验证两次输出一致)
- 🌻5.总结
-
🌻1.前言
本篇目的:理解
gst_audio_converter_reset()如何清除GstAudioConverter内部的转换历史,以及它为什么不会重新配置音频格式或重建转换器。
GstAudioConverter用于连接输入音频格式和输出音频格式。创建转换器时,GStreamer会根据输入输出的GstAudioInfo建立一条可选处理链:
text
解包
↓
格式转换
↓
声道混音
↓
重采样
↓
量化
↓
布局转换
↓
打包
其中,重采样和量化可能跨越多次gst_audio_converter_samples()调用保存中间状态:
text
重采样器:滤波器历史、采样位置、可用Sample数量
量化器:误差反馈历史
当发生Seek、Flush、流重新开始或时间戳不连续时,下一段音频不应该继续继承上一段音频的历史。此时需要调用:
cpp
gst_audio_converter_reset(converter);
它解决的是:
text
保留转换配置
+
清除跨Buffer历史
+
让下一次转换从初始处理状态开始
#mermaid-svg-QHt2mMmBhm2MUjwf{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-QHt2mMmBhm2MUjwf .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-QHt2mMmBhm2MUjwf .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-QHt2mMmBhm2MUjwf .error-icon{fill:#552222;}#mermaid-svg-QHt2mMmBhm2MUjwf .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-QHt2mMmBhm2MUjwf .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-QHt2mMmBhm2MUjwf .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-QHt2mMmBhm2MUjwf .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-QHt2mMmBhm2MUjwf .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-QHt2mMmBhm2MUjwf .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-QHt2mMmBhm2MUjwf .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-QHt2mMmBhm2MUjwf .marker{fill:#333333;stroke:#333333;}#mermaid-svg-QHt2mMmBhm2MUjwf .marker.cross{stroke:#333333;}#mermaid-svg-QHt2mMmBhm2MUjwf svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-QHt2mMmBhm2MUjwf p{margin:0;}#mermaid-svg-QHt2mMmBhm2MUjwf .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-QHt2mMmBhm2MUjwf .cluster-label text{fill:#333;}#mermaid-svg-QHt2mMmBhm2MUjwf .cluster-label span{color:#333;}#mermaid-svg-QHt2mMmBhm2MUjwf .cluster-label span p{background-color:transparent;}#mermaid-svg-QHt2mMmBhm2MUjwf .label text,#mermaid-svg-QHt2mMmBhm2MUjwf span{fill:#333;color:#333;}#mermaid-svg-QHt2mMmBhm2MUjwf .node rect,#mermaid-svg-QHt2mMmBhm2MUjwf .node circle,#mermaid-svg-QHt2mMmBhm2MUjwf .node ellipse,#mermaid-svg-QHt2mMmBhm2MUjwf .node polygon,#mermaid-svg-QHt2mMmBhm2MUjwf .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-QHt2mMmBhm2MUjwf .rough-node .label text,#mermaid-svg-QHt2mMmBhm2MUjwf .node .label text,#mermaid-svg-QHt2mMmBhm2MUjwf .image-shape .label,#mermaid-svg-QHt2mMmBhm2MUjwf .icon-shape .label{text-anchor:middle;}#mermaid-svg-QHt2mMmBhm2MUjwf .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-QHt2mMmBhm2MUjwf .rough-node .label,#mermaid-svg-QHt2mMmBhm2MUjwf .node .label,#mermaid-svg-QHt2mMmBhm2MUjwf .image-shape .label,#mermaid-svg-QHt2mMmBhm2MUjwf .icon-shape .label{text-align:center;}#mermaid-svg-QHt2mMmBhm2MUjwf .node.clickable{cursor:pointer;}#mermaid-svg-QHt2mMmBhm2MUjwf .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-QHt2mMmBhm2MUjwf .arrowheadPath{fill:#333333;}#mermaid-svg-QHt2mMmBhm2MUjwf .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-QHt2mMmBhm2MUjwf .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-QHt2mMmBhm2MUjwf .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QHt2mMmBhm2MUjwf .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-QHt2mMmBhm2MUjwf .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QHt2mMmBhm2MUjwf .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-QHt2mMmBhm2MUjwf .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-QHt2mMmBhm2MUjwf .cluster text{fill:#333;}#mermaid-svg-QHt2mMmBhm2MUjwf .cluster span{color:#333;}#mermaid-svg-QHt2mMmBhm2MUjwf 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-QHt2mMmBhm2MUjwf .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-QHt2mMmBhm2MUjwf rect.text{fill:none;stroke-width:0;}#mermaid-svg-QHt2mMmBhm2MUjwf .icon-shape,#mermaid-svg-QHt2mMmBhm2MUjwf .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QHt2mMmBhm2MUjwf .icon-shape p,#mermaid-svg-QHt2mMmBhm2MUjwf .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-QHt2mMmBhm2MUjwf .icon-shape .label rect,#mermaid-svg-QHt2mMmBhm2MUjwf .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QHt2mMmBhm2MUjwf .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-QHt2mMmBhm2MUjwf .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-QHt2mMmBhm2MUjwf :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ① 已创建转换器
② 连续处理音频
③ 内部产生历史
④ reset清除历史
⑤ 新音频重新开始
需要注意:
text
gst_audio_converter_reset()
≠
重新创建GstAudioConverter
它不会改变输入输出格式、采样率、声道数、混音矩阵或已经建立的处理链。
🌻2.应用场景和用法
🌻2.1 应用场景
音频转换器通常会被多个Buffer连续复用。只要转换过程具有跨调用状态,就不能把每个Buffer当成完全独立的数据。
以采样率转换为例,重采样器需要根据前一个Buffer末尾的Sample计算下一个Buffer的输出。如果输入流在中间发生切换,旧流的滤波器历史就不再适用于新流。
gst_audio_converter_reset()主要适合以下场景:
- Seek或Flush之后重新处理音频。
- 输入流发生断点,下一段音频不应继承上一段的滤波状态。
- 处理新的Stream或Segment之前清除旧的转换历史。
- 量化器使用误差反馈时,避免上一段音频的误差影响下一段音频。
GStreamer的audioresampleElement也会在Flush、Stream开始、Segment变化、时间戳不连续或音频格式变化等场景调用该函数。
但上层Element的状态不由它负责。例如audioresample还需要单独清除时间戳、输入输出计数和Discontinuity标记。gst_audio_converter_reset()只负责转换器内部的历史状态。
如果转换器只是执行没有跨Buffer历史的直通或简单格式路径,内部可能没有resampler和quant对象。此时调用该函数不会产生可观察的数据变化。
🌻2.2 函数用法
函数原型:
c
void gst_audio_converter_reset(GstAudioConverter *convert);
参数:
| 参数 | 作用 |
|---|---|
convert |
由gst_audio_converter_new()创建的有效GstAudioConverter对象 |
该函数没有返回值。
调用者必须保证:
text
convert != NULL
当前实现不会在函数内部检查空指针。转换器创建失败时,不能直接调用gst_audio_converter_reset()。
最小调用方式:
cpp
GstAudioConverter *converter;
converter = gst_audio_converter_new(
GST_AUDIO_CONVERTER_FLAG_NONE,
&in_info,
&out_info,
NULL);
if (converter == NULL) {
return FALSE;
}
gst_audio_converter_reset(converter);
调用前后的变化可以概括为:
| 内容 | reset前 | reset后 |
|---|---|---|
| 输入输出格式 | 已配置 | 不变 |
| 输入输出采样率 | 已配置 | 不变 |
| 声道数和布局 | 已配置 | 不变 |
| 转换处理链 | 已创建 | 不变 |
| 重采样历史 | 可能包含旧Sample和相位 | 恢复初始处理状态 |
| 量化误差历史 | 可能存在误差反馈 | 清除误差缓存 |
| 配置结构 | 已保存 | 不变 |
gst_audio_converter_reset()与相邻API的边界如下:
text
gst_audio_converter_new()
创建转换器和处理链
gst_audio_converter_update_config()
更新采样率或额外配置
gst_audio_converter_samples()
使用处理链转换音频并积累历史
gst_audio_converter_reset()
清除重采样器和量化器历史
gst_audio_converter_free()
释放转换器及其资源
因此,如果输入输出格式已经发生变化,不能只调用reset()。格式更新或处理链重建仍然需要由update_config()或重新创建转换器完成。
🌻3.调用流程剖析
🌻3.1 分发到重采样器和量化器
gst_audio_converter_reset()的实现非常短:
cpp
void
gst_audio_converter_reset(GstAudioConverter *convert)
{
if (convert->resampler)
gst_audio_resampler_reset(convert->resampler);
if (convert->quant)
gst_audio_quantize_reset(convert->quant);
}
函数本身不遍历全部转换链,也不释放GstAudioConverter。
执行过程只有两个可选分支:
- 如果转换器包含
GstAudioResampler,调用gst_audio_resampler_reset()。 - 如果转换器包含
GstAudioQuantize,调用gst_audio_quantize_reset()。 - 两个对象都不存在时,函数直接结束。
#mermaid-svg-jpYkCwYINnseLgfo{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-jpYkCwYINnseLgfo .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jpYkCwYINnseLgfo .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jpYkCwYINnseLgfo .error-icon{fill:#552222;}#mermaid-svg-jpYkCwYINnseLgfo .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jpYkCwYINnseLgfo .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jpYkCwYINnseLgfo .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jpYkCwYINnseLgfo .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jpYkCwYINnseLgfo .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jpYkCwYINnseLgfo .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jpYkCwYINnseLgfo .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jpYkCwYINnseLgfo .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jpYkCwYINnseLgfo .marker.cross{stroke:#333333;}#mermaid-svg-jpYkCwYINnseLgfo svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jpYkCwYINnseLgfo p{margin:0;}#mermaid-svg-jpYkCwYINnseLgfo .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-jpYkCwYINnseLgfo .cluster-label text{fill:#333;}#mermaid-svg-jpYkCwYINnseLgfo .cluster-label span{color:#333;}#mermaid-svg-jpYkCwYINnseLgfo .cluster-label span p{background-color:transparent;}#mermaid-svg-jpYkCwYINnseLgfo .label text,#mermaid-svg-jpYkCwYINnseLgfo span{fill:#333;color:#333;}#mermaid-svg-jpYkCwYINnseLgfo .node rect,#mermaid-svg-jpYkCwYINnseLgfo .node circle,#mermaid-svg-jpYkCwYINnseLgfo .node ellipse,#mermaid-svg-jpYkCwYINnseLgfo .node polygon,#mermaid-svg-jpYkCwYINnseLgfo .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jpYkCwYINnseLgfo .rough-node .label text,#mermaid-svg-jpYkCwYINnseLgfo .node .label text,#mermaid-svg-jpYkCwYINnseLgfo .image-shape .label,#mermaid-svg-jpYkCwYINnseLgfo .icon-shape .label{text-anchor:middle;}#mermaid-svg-jpYkCwYINnseLgfo .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-jpYkCwYINnseLgfo .rough-node .label,#mermaid-svg-jpYkCwYINnseLgfo .node .label,#mermaid-svg-jpYkCwYINnseLgfo .image-shape .label,#mermaid-svg-jpYkCwYINnseLgfo .icon-shape .label{text-align:center;}#mermaid-svg-jpYkCwYINnseLgfo .node.clickable{cursor:pointer;}#mermaid-svg-jpYkCwYINnseLgfo .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-jpYkCwYINnseLgfo .arrowheadPath{fill:#333333;}#mermaid-svg-jpYkCwYINnseLgfo .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-jpYkCwYINnseLgfo .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-jpYkCwYINnseLgfo .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jpYkCwYINnseLgfo .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-jpYkCwYINnseLgfo .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jpYkCwYINnseLgfo .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-jpYkCwYINnseLgfo .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jpYkCwYINnseLgfo .cluster text{fill:#333;}#mermaid-svg-jpYkCwYINnseLgfo .cluster span{color:#333;}#mermaid-svg-jpYkCwYINnseLgfo 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-jpYkCwYINnseLgfo .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-jpYkCwYINnseLgfo rect.text{fill:none;stroke-width:0;}#mermaid-svg-jpYkCwYINnseLgfo .icon-shape,#mermaid-svg-jpYkCwYINnseLgfo .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jpYkCwYINnseLgfo .icon-shape p,#mermaid-svg-jpYkCwYINnseLgfo .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-jpYkCwYINnseLgfo .icon-shape .label rect,#mermaid-svg-jpYkCwYINnseLgfo .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jpYkCwYINnseLgfo .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-jpYkCwYINnseLgfo .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-jpYkCwYINnseLgfo :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
是
否
GstAudioConverter
存在resampler?
重置GstAudioResampler
存在quant?
重置GstAudioQuantize
同步返回
该调用是同步的:
text
调用者线程
↓
gst_audio_converter_reset()
↓
重采样器 reset
↓
量化器 reset
↓
函数返回
它不会发送GStreamer事件,不会触发Pad回调,也不会向其他进程发送请求。
🌻3.2 清除转换历史但保留处理配置
gst_audio_resampler_reset()主要清除重采样器在连续处理过程中积累的状态:
text
滤波器需要继承的Sample历史
采样索引
当前可用Sample数量
重置后,下一次输入会按照新的一段音频重新建立重采样上下文。
gst_audio_quantize_reset()则清除量化器的误差缓存:
text
上一段音频的量化误差
这对噪声整形和误差反馈尤其重要。否则新音频开头的量化结果可能受到旧音频尾部误差的影响。
整个关系可以表示为:
#mermaid-svg-PO5hEbsEulZV8Git{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-PO5hEbsEulZV8Git .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PO5hEbsEulZV8Git .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PO5hEbsEulZV8Git .error-icon{fill:#552222;}#mermaid-svg-PO5hEbsEulZV8Git .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PO5hEbsEulZV8Git .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PO5hEbsEulZV8Git .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PO5hEbsEulZV8Git .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PO5hEbsEulZV8Git .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PO5hEbsEulZV8Git .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PO5hEbsEulZV8Git .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PO5hEbsEulZV8Git .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PO5hEbsEulZV8Git .marker.cross{stroke:#333333;}#mermaid-svg-PO5hEbsEulZV8Git svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PO5hEbsEulZV8Git p{margin:0;}#mermaid-svg-PO5hEbsEulZV8Git .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-PO5hEbsEulZV8Git .cluster-label text{fill:#333;}#mermaid-svg-PO5hEbsEulZV8Git .cluster-label span{color:#333;}#mermaid-svg-PO5hEbsEulZV8Git .cluster-label span p{background-color:transparent;}#mermaid-svg-PO5hEbsEulZV8Git .label text,#mermaid-svg-PO5hEbsEulZV8Git span{fill:#333;color:#333;}#mermaid-svg-PO5hEbsEulZV8Git .node rect,#mermaid-svg-PO5hEbsEulZV8Git .node circle,#mermaid-svg-PO5hEbsEulZV8Git .node ellipse,#mermaid-svg-PO5hEbsEulZV8Git .node polygon,#mermaid-svg-PO5hEbsEulZV8Git .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-PO5hEbsEulZV8Git .rough-node .label text,#mermaid-svg-PO5hEbsEulZV8Git .node .label text,#mermaid-svg-PO5hEbsEulZV8Git .image-shape .label,#mermaid-svg-PO5hEbsEulZV8Git .icon-shape .label{text-anchor:middle;}#mermaid-svg-PO5hEbsEulZV8Git .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-PO5hEbsEulZV8Git .rough-node .label,#mermaid-svg-PO5hEbsEulZV8Git .node .label,#mermaid-svg-PO5hEbsEulZV8Git .image-shape .label,#mermaid-svg-PO5hEbsEulZV8Git .icon-shape .label{text-align:center;}#mermaid-svg-PO5hEbsEulZV8Git .node.clickable{cursor:pointer;}#mermaid-svg-PO5hEbsEulZV8Git .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-PO5hEbsEulZV8Git .arrowheadPath{fill:#333333;}#mermaid-svg-PO5hEbsEulZV8Git .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-PO5hEbsEulZV8Git .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-PO5hEbsEulZV8Git .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PO5hEbsEulZV8Git .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-PO5hEbsEulZV8Git .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PO5hEbsEulZV8Git .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-PO5hEbsEulZV8Git .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-PO5hEbsEulZV8Git .cluster text{fill:#333;}#mermaid-svg-PO5hEbsEulZV8Git .cluster span{color:#333;}#mermaid-svg-PO5hEbsEulZV8Git 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-PO5hEbsEulZV8Git .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-PO5hEbsEulZV8Git rect.text{fill:none;stroke-width:0;}#mermaid-svg-PO5hEbsEulZV8Git .icon-shape,#mermaid-svg-PO5hEbsEulZV8Git .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PO5hEbsEulZV8Git .icon-shape p,#mermaid-svg-PO5hEbsEulZV8Git .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-PO5hEbsEulZV8Git .icon-shape .label rect,#mermaid-svg-PO5hEbsEulZV8Git .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PO5hEbsEulZV8Git .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-PO5hEbsEulZV8Git .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-PO5hEbsEulZV8Git :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Buffer N
转换器积累历史
流边界或Discontinuity
gst_audio_converter_reset
Buffer N+1从初始历史开始
重置后仍然保留:
text
convert->in
convert->out
convert->config
convert->chain_end
convert->mix
convert->resampler
convert->quant
这里的"恢复初始状态"指恢复处理历史,不是把对象退化成未配置对象。
如果上层还需要排空重采样延迟,应先处理待输出的历史Sample,再调用reset()。audioresampleElement在相关路径中会先执行Drain,然后再清除转换器状态。
🌻4.实战案例
🌻4.1 创建带重采样历史的转换器
为了让reset()产生可验证的效果,创建一个单声道采样率转换器:
text
输入:S16,48000Hz
输出:S16,44100Hz
输入和输出采样率不同,gst_audio_converter_new()会在内部创建重采样器。
准备一段固定的480个输入Sample:
cpp
gint16 input[480];
for (gsize i = 0; i < G_N_ELEMENTS(input); i++)
input[i] = (gint16)(i % 200);
先处理一次输入数据。此时重采样器会建立自己的Sample历史。
🌻4.2 重置后再次处理同一段输入
第一次转换完成后调用:
cpp
gst_audio_converter_reset(converter);
然后把完全相同的输入数据再次交给同一个转换器。
如果reset()正确清除了重采样历史,那么第二次转换会与第一次转换一样,从同一个初始状态开始。
#mermaid-svg-x8yyNzRJ7jjyMsi2{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-x8yyNzRJ7jjyMsi2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .error-icon{fill:#552222;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .marker.cross{stroke:#333333;}#mermaid-svg-x8yyNzRJ7jjyMsi2 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-x8yyNzRJ7jjyMsi2 p{margin:0;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .cluster-label text{fill:#333;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .cluster-label span{color:#333;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .cluster-label span p{background-color:transparent;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .label text,#mermaid-svg-x8yyNzRJ7jjyMsi2 span{fill:#333;color:#333;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .node rect,#mermaid-svg-x8yyNzRJ7jjyMsi2 .node circle,#mermaid-svg-x8yyNzRJ7jjyMsi2 .node ellipse,#mermaid-svg-x8yyNzRJ7jjyMsi2 .node polygon,#mermaid-svg-x8yyNzRJ7jjyMsi2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .rough-node .label text,#mermaid-svg-x8yyNzRJ7jjyMsi2 .node .label text,#mermaid-svg-x8yyNzRJ7jjyMsi2 .image-shape .label,#mermaid-svg-x8yyNzRJ7jjyMsi2 .icon-shape .label{text-anchor:middle;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .rough-node .label,#mermaid-svg-x8yyNzRJ7jjyMsi2 .node .label,#mermaid-svg-x8yyNzRJ7jjyMsi2 .image-shape .label,#mermaid-svg-x8yyNzRJ7jjyMsi2 .icon-shape .label{text-align:center;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .node.clickable{cursor:pointer;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .arrowheadPath{fill:#333333;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-x8yyNzRJ7jjyMsi2 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-x8yyNzRJ7jjyMsi2 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-x8yyNzRJ7jjyMsi2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .cluster text{fill:#333;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .cluster span{color:#333;}#mermaid-svg-x8yyNzRJ7jjyMsi2 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-x8yyNzRJ7jjyMsi2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-x8yyNzRJ7jjyMsi2 rect.text{fill:none;stroke-width:0;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .icon-shape,#mermaid-svg-x8yyNzRJ7jjyMsi2 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .icon-shape p,#mermaid-svg-x8yyNzRJ7jjyMsi2 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .icon-shape .label rect,#mermaid-svg-x8yyNzRJ7jjyMsi2 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-x8yyNzRJ7jjyMsi2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-x8yyNzRJ7jjyMsi2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-x8yyNzRJ7jjyMsi2 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 创建48000→44100转换器
第一次转换
保存重采样历史
调用reset
第二次转换
重新建立历史
比较两次输出
🌻4.3 验证两次输出一致
完整测试代码:
c
#include <gst/gst.h>
#include <gst/audio/audio.h>
#include <string.h>
int
main(int argc, char *argv[])
{
GstAudioInfo in_info;
GstAudioInfo out_info;
GstAudioConverter *converter = NULL;
gint16 input[480];
gpointer first_output = NULL;
gpointer second_output = NULL;
gsize first_size = 0;
gsize second_size = 0;
gsize i;
gboolean same;
int status = 1;
gst_init(&argc, &argv);
for (i = 0; i < G_N_ELEMENTS(input); i++)
input[i] = (gint16)(i % 200);
gst_audio_info_set_format(
&in_info,
GST_AUDIO_FORMAT_S16,
48000,
1,
NULL);
gst_audio_info_set_format(
&out_info,
GST_AUDIO_FORMAT_S16,
44100,
1,
NULL);
converter = gst_audio_converter_new(
GST_AUDIO_CONVERTER_FLAG_NONE,
&in_info,
&out_info,
NULL);
if (converter == NULL) {
g_printerr("Failed to create audio converter\n");
goto done;
}
if (!gst_audio_converter_convert(
converter,
GST_AUDIO_CONVERTER_FLAG_NONE,
input,
sizeof(input),
&first_output,
&first_size)) {
g_printerr("First conversion failed\n");
goto done;
}
gst_audio_converter_reset(converter);
if (!gst_audio_converter_convert(
converter,
GST_AUDIO_CONVERTER_FLAG_NONE,
input,
sizeof(input),
&second_output,
&second_size)) {
g_printerr("Second conversion failed\n");
goto done;
}
same = first_size == second_size;
if (same && first_size > 0)
same = memcmp(
first_output,
second_output,
first_size) == 0;
g_print(
"First output bytes: %" G_GSIZE_FORMAT "\n",
first_size);
g_print(
"After reset output bytes: %" G_GSIZE_FORMAT "\n",
second_size);
if (!same) {
g_printerr(
"Reset verification failed\n");
goto done;
}
g_print(
"Reset verification passed: "
"outputs are identical\n");
status = 0;
done:
g_free(first_output);
g_free(second_output);
gst_audio_converter_free(converter);
return status;
}
编译:
bash
gcc test_audio_converter_reset.c \
-o test_audio_converter_reset \
$(pkg-config --cflags --libs \
gstreamer-audio-1.0)
运行:
bash
./test_audio_converter_reset
重点观察:
text
First output bytes: N
After reset output bytes: N
Reset verification passed: outputs are identical
这里不要求固定N的具体数值,因为不同版本或重采样配置可能产生不同的输出帧数。
测试真正验证的是:
text
第一次转换:从初始重采样状态处理输入
调用reset:清除重采样历史
第二次转换:再次从初始状态处理同一输入
比较结果:两次输出完全一致
如果省略gst_audio_converter_reset(),第二次转换会继续使用第一次转换留下的重采样历史,输出就不再代表一次全新的音频段处理。
🌻5.总结
gst_audio_converter_reset()就是保留GstAudioConverter配置和处理链,只清除重采样器与量化器的跨调用历史,使下一段音频从初始转换状态开始处理。