Linux Gstreamer深度解析之gst_audio_resampler_update调用流程与实战(三十)

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

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

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

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

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

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

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

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

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

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

🍉🍉🍉文章目录🍉🍉🍉

🌻1.前言

本篇目的:理解gst_audio_resampler_update()如何更新重采样器的采样率和滤波配置,分析它为什么会保留运行状态,并通过最小程序验证更新前后的输出Frame数变化。

GstAudioResampler创建后会保存输入输出采样率、滤波器参数、采样相位和历史Frame。

实时音频场景中,采样率可能动态变化,滤波质量也可能需要调整。如果每次变化都销毁并重新创建对象,会丢失现有配置和处理上下文。

gst_audio_resampler_update()负责在保留重采样器对象的前提下更新采样参数。它会重新计算有效采样率、相位增量和滤波器配置,但不会直接产生PCM输出,也不会自动清空样本历史。
#mermaid-svg-V8PG8NPTZsgpRdBV{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-V8PG8NPTZsgpRdBV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-V8PG8NPTZsgpRdBV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-V8PG8NPTZsgpRdBV .error-icon{fill:#552222;}#mermaid-svg-V8PG8NPTZsgpRdBV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-V8PG8NPTZsgpRdBV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-V8PG8NPTZsgpRdBV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-V8PG8NPTZsgpRdBV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-V8PG8NPTZsgpRdBV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-V8PG8NPTZsgpRdBV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-V8PG8NPTZsgpRdBV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-V8PG8NPTZsgpRdBV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-V8PG8NPTZsgpRdBV .marker.cross{stroke:#333333;}#mermaid-svg-V8PG8NPTZsgpRdBV svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-V8PG8NPTZsgpRdBV p{margin:0;}#mermaid-svg-V8PG8NPTZsgpRdBV .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-V8PG8NPTZsgpRdBV .cluster-label text{fill:#333;}#mermaid-svg-V8PG8NPTZsgpRdBV .cluster-label span{color:#333;}#mermaid-svg-V8PG8NPTZsgpRdBV .cluster-label span p{background-color:transparent;}#mermaid-svg-V8PG8NPTZsgpRdBV .label text,#mermaid-svg-V8PG8NPTZsgpRdBV span{fill:#333;color:#333;}#mermaid-svg-V8PG8NPTZsgpRdBV .node rect,#mermaid-svg-V8PG8NPTZsgpRdBV .node circle,#mermaid-svg-V8PG8NPTZsgpRdBV .node ellipse,#mermaid-svg-V8PG8NPTZsgpRdBV .node polygon,#mermaid-svg-V8PG8NPTZsgpRdBV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-V8PG8NPTZsgpRdBV .rough-node .label text,#mermaid-svg-V8PG8NPTZsgpRdBV .node .label text,#mermaid-svg-V8PG8NPTZsgpRdBV .image-shape .label,#mermaid-svg-V8PG8NPTZsgpRdBV .icon-shape .label{text-anchor:middle;}#mermaid-svg-V8PG8NPTZsgpRdBV .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-V8PG8NPTZsgpRdBV .rough-node .label,#mermaid-svg-V8PG8NPTZsgpRdBV .node .label,#mermaid-svg-V8PG8NPTZsgpRdBV .image-shape .label,#mermaid-svg-V8PG8NPTZsgpRdBV .icon-shape .label{text-align:center;}#mermaid-svg-V8PG8NPTZsgpRdBV .node.clickable{cursor:pointer;}#mermaid-svg-V8PG8NPTZsgpRdBV .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-V8PG8NPTZsgpRdBV .arrowheadPath{fill:#333333;}#mermaid-svg-V8PG8NPTZsgpRdBV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-V8PG8NPTZsgpRdBV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-V8PG8NPTZsgpRdBV .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-V8PG8NPTZsgpRdBV .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-V8PG8NPTZsgpRdBV .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-V8PG8NPTZsgpRdBV .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-V8PG8NPTZsgpRdBV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-V8PG8NPTZsgpRdBV .cluster text{fill:#333;}#mermaid-svg-V8PG8NPTZsgpRdBV .cluster span{color:#333;}#mermaid-svg-V8PG8NPTZsgpRdBV 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-V8PG8NPTZsgpRdBV .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-V8PG8NPTZsgpRdBV rect.text{fill:none;stroke-width:0;}#mermaid-svg-V8PG8NPTZsgpRdBV .icon-shape,#mermaid-svg-V8PG8NPTZsgpRdBV .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-V8PG8NPTZsgpRdBV .icon-shape p,#mermaid-svg-V8PG8NPTZsgpRdBV .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-V8PG8NPTZsgpRdBV .icon-shape .label rect,#mermaid-svg-V8PG8NPTZsgpRdBV .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-V8PG8NPTZsgpRdBV .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-V8PG8NPTZsgpRdBV .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-V8PG8NPTZsgpRdBV :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 已有GstAudioResampler和当前配置
gst_audio_resampler_update
约分采样率并更新相位参数
按新配置调整滤波路径
保留对象继续重采样

🌻2.应用场景和用法

2.1动态采样率和滤波配置更新

gst_audio_resampler_update()主要用于以下场景:

场景 调用方式 更新结果 注意事项
输入输出采样率变化 传入新的in_rateout_rate 重新计算采样率比例和相位增量 不能继续使用旧采样率推导Frame数
可变采样率处理 创建对象时设置GST_AUDIO_RESAMPLER_FLAG_VARIABLE_RATE 适合重复调用更新接口 更新过程必须与其他重采样操作串行
滤波器抽头数量变化 通过options传入新的滤波配置 重新计算n_taps并调整历史缓冲区 抽头变化可能引起内存移动
滤波截止频率变化 通过options修改滤波参数 重新生成或更新滤波器参数 不会自动输出新的PCM数据
实时音频时钟漂移修正 周期性更新目标采样率 让后续输入使用新的采样比例 更新前后的相位会被重新换算
长时间音频流处理 复用同一个重采样器 避免频繁销毁和创建对象 对象释放仍由调用者负责
新流完全重新开始 先调用gst_audio_resampler_reset(),再决定是否更新 清除旧样本后处理新流 update()本身不会清空历史
只想清理历史样本 调用gst_audio_resampler_reset() 保留当前采样率和滤波配置 不能用update()代替复位
需要改变重采样方法 重新创建重采样器 使用新的method建立对象 update()不修改对象的重采样方法
需要查询更新结果 检查gboolean返回值并调用查询接口 确认新参数已经生效 不能只依赖调用前的配置记录

gst_audio_resampler_update()不会创建新的GstAudioResampler,也不会改变对象所有权。更新时如果仍然保留历史样本,函数会尝试按照新的滤波窗口调整历史数据。

2.2函数原型与返回语义

函数原型如下:

c 复制代码
gboolean
gst_audio_resampler_update (GstAudioResampler *resampler,
                            gint in_rate,
                            gint out_rate,
                            GstStructure *options);
参数或返回值 含义
resampler 已经创建的有效重采样器
in_rate 新的输入采样率,传入0表示保持当前值
out_rate 新的输出采样率,传入0表示保持当前值
options 新的滤波配置,传入NULL表示沿用当前配置
返回值 TRUE表示更新路径完成,FALSE表示参数检查失败

最小调用方式如下:

c 复制代码
gboolean updated;

updated = gst_audio_resampler_update (
    resampler,
    48000,
    44100,
    NULL);

options不为NULL时,函数会复制传入的GstStructure,调用者仍然负责释放原始配置对象。

调用前,重采样器已经拥有一组采样率、滤波器和运行状态。调用过程中,函数同步完成参数计算、滤波器调整和处理函数设置,不进入其他线程,不触发回调,也不产生输出Frame。

调用后:

  • in_rateout_rate被更新为新的有效采样率。
  • samp_incsamp_frac重新描述输入输出采样比例。
  • 旧相位会按照新的输出采样率重新换算。
  • 传入新配置时,滤波器参数和历史缓冲区可能发生变化。
  • 已有样本历史不会因为update()自动清空。

gst_audio_resampler_update()不能与gst_audio_resampler_resample()或其他重采样器操作并发调用。需要清空历史时,应使用gst_audio_resampler_reset()。需要释放对象时,应使用gst_audio_resampler_free()

🌻3.调用流程剖析

3.1采样率参数更新主链路

gst_audio_resampler_update()首先处理采样率参数。传入值小于等于0时,源码继续使用对象中的当前采样率。

如果对象已经处理过数据,函数会先把旧的samp_phase按照新的输出采样率进行缩放。随后使用最大公约数约分输入输出采样率,得到内部使用的有效比例。

例如48000Hz和44100Hz会约分为160和147。之后函数写入:

c 复制代码
resampler->samp_phase = samp_phase / gcd;
resampler->in_rate = in_rate / gcd;
resampler->out_rate = out_rate / gcd;

resampler->samp_inc = in_rate / out_rate;
resampler->samp_frac = in_rate % out_rate;

这些字段会被后续滤波和Frame数量计算使用。
#mermaid-svg-7oNbzFwY7RmW5xDt{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-7oNbzFwY7RmW5xDt .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7oNbzFwY7RmW5xDt .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7oNbzFwY7RmW5xDt .error-icon{fill:#552222;}#mermaid-svg-7oNbzFwY7RmW5xDt .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7oNbzFwY7RmW5xDt .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7oNbzFwY7RmW5xDt .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7oNbzFwY7RmW5xDt .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7oNbzFwY7RmW5xDt .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7oNbzFwY7RmW5xDt .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7oNbzFwY7RmW5xDt .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7oNbzFwY7RmW5xDt .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7oNbzFwY7RmW5xDt .marker.cross{stroke:#333333;}#mermaid-svg-7oNbzFwY7RmW5xDt svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7oNbzFwY7RmW5xDt p{margin:0;}#mermaid-svg-7oNbzFwY7RmW5xDt .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-7oNbzFwY7RmW5xDt .cluster-label text{fill:#333;}#mermaid-svg-7oNbzFwY7RmW5xDt .cluster-label span{color:#333;}#mermaid-svg-7oNbzFwY7RmW5xDt .cluster-label span p{background-color:transparent;}#mermaid-svg-7oNbzFwY7RmW5xDt .label text,#mermaid-svg-7oNbzFwY7RmW5xDt span{fill:#333;color:#333;}#mermaid-svg-7oNbzFwY7RmW5xDt .node rect,#mermaid-svg-7oNbzFwY7RmW5xDt .node circle,#mermaid-svg-7oNbzFwY7RmW5xDt .node ellipse,#mermaid-svg-7oNbzFwY7RmW5xDt .node polygon,#mermaid-svg-7oNbzFwY7RmW5xDt .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-7oNbzFwY7RmW5xDt .rough-node .label text,#mermaid-svg-7oNbzFwY7RmW5xDt .node .label text,#mermaid-svg-7oNbzFwY7RmW5xDt .image-shape .label,#mermaid-svg-7oNbzFwY7RmW5xDt .icon-shape .label{text-anchor:middle;}#mermaid-svg-7oNbzFwY7RmW5xDt .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-7oNbzFwY7RmW5xDt .rough-node .label,#mermaid-svg-7oNbzFwY7RmW5xDt .node .label,#mermaid-svg-7oNbzFwY7RmW5xDt .image-shape .label,#mermaid-svg-7oNbzFwY7RmW5xDt .icon-shape .label{text-align:center;}#mermaid-svg-7oNbzFwY7RmW5xDt .node.clickable{cursor:pointer;}#mermaid-svg-7oNbzFwY7RmW5xDt .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-7oNbzFwY7RmW5xDt .arrowheadPath{fill:#333333;}#mermaid-svg-7oNbzFwY7RmW5xDt .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-7oNbzFwY7RmW5xDt .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-7oNbzFwY7RmW5xDt .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7oNbzFwY7RmW5xDt .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-7oNbzFwY7RmW5xDt .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7oNbzFwY7RmW5xDt .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-7oNbzFwY7RmW5xDt .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-7oNbzFwY7RmW5xDt .cluster text{fill:#333;}#mermaid-svg-7oNbzFwY7RmW5xDt .cluster span{color:#333;}#mermaid-svg-7oNbzFwY7RmW5xDt 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-7oNbzFwY7RmW5xDt .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-7oNbzFwY7RmW5xDt rect.text{fill:none;stroke-width:0;}#mermaid-svg-7oNbzFwY7RmW5xDt .icon-shape,#mermaid-svg-7oNbzFwY7RmW5xDt .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7oNbzFwY7RmW5xDt .icon-shape p,#mermaid-svg-7oNbzFwY7RmW5xDt .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-7oNbzFwY7RmW5xDt .icon-shape .label rect,#mermaid-svg-7oNbzFwY7RmW5xDt .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7oNbzFwY7RmW5xDt .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-7oNbzFwY7RmW5xDt .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-7oNbzFwY7RmW5xDt :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是

新采样率和options
规范化速率与旧相位
约分并写入采样参数
是否提供新options
重算滤波器并调整历史
复用配置并准备滤波路径

optionsNULL时,函数复用现有配置。对于完整滤波表模式,它会根据新的输出采样率准备滤波缓存。

options不为NULL时,函数会复制新配置,保存旧的n_taps,重新计算滤波器参数,并根据新旧抽头数量调整历史缓冲区。

3.2滤波器重建与历史数据迁移

传入新options后,源码会执行以下处理:

c 复制代码
old_n_taps = resampler->n_taps;

resampler->options = gst_structure_copy (options);
resampler_calculate_taps (resampler);

diff = ((gint) resampler->n_taps - old_n_taps) / 2;

如果n_taps发生变化,函数会确保历史缓冲区容量满足新的滤波窗口要求,然后使用memmove()移动已有历史数据,并按照抽头数量差异修正samples_avail

这个过程不是简单地把滤波器指针替换掉。历史数据必须调整到新滤波窗口对应的位置,否则下一次重采样会从错误的样本位置开始。

如果抽头数量没有变化,历史数据不需要移动。无论配置是否变化,函数最后都会调用setup_functions(),根据当前方法、格式、布局和滤波模式选择处理函数。
#mermaid-svg-ptXnfJY5PwD6rkMp{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-ptXnfJY5PwD6rkMp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ptXnfJY5PwD6rkMp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ptXnfJY5PwD6rkMp .error-icon{fill:#552222;}#mermaid-svg-ptXnfJY5PwD6rkMp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ptXnfJY5PwD6rkMp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ptXnfJY5PwD6rkMp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ptXnfJY5PwD6rkMp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ptXnfJY5PwD6rkMp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ptXnfJY5PwD6rkMp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ptXnfJY5PwD6rkMp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ptXnfJY5PwD6rkMp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ptXnfJY5PwD6rkMp .marker.cross{stroke:#333333;}#mermaid-svg-ptXnfJY5PwD6rkMp svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ptXnfJY5PwD6rkMp p{margin:0;}#mermaid-svg-ptXnfJY5PwD6rkMp .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ptXnfJY5PwD6rkMp .cluster-label text{fill:#333;}#mermaid-svg-ptXnfJY5PwD6rkMp .cluster-label span{color:#333;}#mermaid-svg-ptXnfJY5PwD6rkMp .cluster-label span p{background-color:transparent;}#mermaid-svg-ptXnfJY5PwD6rkMp .label text,#mermaid-svg-ptXnfJY5PwD6rkMp span{fill:#333;color:#333;}#mermaid-svg-ptXnfJY5PwD6rkMp .node rect,#mermaid-svg-ptXnfJY5PwD6rkMp .node circle,#mermaid-svg-ptXnfJY5PwD6rkMp .node ellipse,#mermaid-svg-ptXnfJY5PwD6rkMp .node polygon,#mermaid-svg-ptXnfJY5PwD6rkMp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ptXnfJY5PwD6rkMp .rough-node .label text,#mermaid-svg-ptXnfJY5PwD6rkMp .node .label text,#mermaid-svg-ptXnfJY5PwD6rkMp .image-shape .label,#mermaid-svg-ptXnfJY5PwD6rkMp .icon-shape .label{text-anchor:middle;}#mermaid-svg-ptXnfJY5PwD6rkMp .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ptXnfJY5PwD6rkMp .rough-node .label,#mermaid-svg-ptXnfJY5PwD6rkMp .node .label,#mermaid-svg-ptXnfJY5PwD6rkMp .image-shape .label,#mermaid-svg-ptXnfJY5PwD6rkMp .icon-shape .label{text-align:center;}#mermaid-svg-ptXnfJY5PwD6rkMp .node.clickable{cursor:pointer;}#mermaid-svg-ptXnfJY5PwD6rkMp .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ptXnfJY5PwD6rkMp .arrowheadPath{fill:#333333;}#mermaid-svg-ptXnfJY5PwD6rkMp .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ptXnfJY5PwD6rkMp .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ptXnfJY5PwD6rkMp .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ptXnfJY5PwD6rkMp .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ptXnfJY5PwD6rkMp .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ptXnfJY5PwD6rkMp .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ptXnfJY5PwD6rkMp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ptXnfJY5PwD6rkMp .cluster text{fill:#333;}#mermaid-svg-ptXnfJY5PwD6rkMp .cluster span{color:#333;}#mermaid-svg-ptXnfJY5PwD6rkMp 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-ptXnfJY5PwD6rkMp .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ptXnfJY5PwD6rkMp rect.text{fill:none;stroke-width:0;}#mermaid-svg-ptXnfJY5PwD6rkMp .icon-shape,#mermaid-svg-ptXnfJY5PwD6rkMp .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ptXnfJY5PwD6rkMp .icon-shape p,#mermaid-svg-ptXnfJY5PwD6rkMp .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ptXnfJY5PwD6rkMp .icon-shape .label rect,#mermaid-svg-ptXnfJY5PwD6rkMp .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ptXnfJY5PwD6rkMp .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ptXnfJY5PwD6rkMp .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ptXnfJY5PwD6rkMp :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是

旧n_taps和历史缓冲
计算新滤波器参数
n_taps是否变化
移动历史并修正可用Frame
保留历史布局
使用新配置继续重采样

gst_audio_resampler_update()不会调用gst_audio_resampler_reset()。因此,采样率更新和历史清理是两种不同动作:

  • 只改变采样率或滤波配置,使用gst_audio_resampler_update()
  • 只丢弃旧样本,使用gst_audio_resampler_reset()
  • 新流同时改变参数和历史,先根据数据边界决定是否复位,再调用更新接口。

🌻4.实战案例

4.1创建可更新的重采样器

本案例创建一个S16单声道重采样器,初始输入采样率为48000Hz,输出采样率为24000Hz,使用最近邻方法。

最近邻方法使用2个抽头。创建完成后,输入480个Frame时:

text 复制代码
内部输入采样率 = 2
内部输出采样率 = 1
n_taps = 2
输出Frame数 = ((480 - 2) × 1) ÷ 2 + 1 = 240

创建对象时设置GST_AUDIO_RESAMPLER_FLAG_VARIABLE_RATE,表示后续允许动态更新采样率。

4.2更新采样率并验证输出规模

程序先查询48000Hz到24000Hz配置下的输出Frame数,再调用:

c 复制代码
gst_audio_resampler_update (resampler, 48000, 44100, NULL);

更新成功后,内部采样率约分为160和147。再次查询480个输入Frame时:

text 复制代码
输出Frame数 = ((480 - 2) × 147) ÷ 160 + 1 = 440

这个案例没有先写入历史样本,因此可以直接观察采样率更新对输出规模的影响。gst_audio_resampler_get_max_latency()在更新前后都返回1,说明滤波器抽头数量没有改变。

4.3完整代码与关键输出
c 复制代码
#include <gst/gst.h>
#include <gst/audio/audio.h>

int
main (int argc, char *argv[])
{
  GstAudioResampler *resampler;
  gboolean updated;
  gsize before_update;
  gsize after_update;
  gsize latency;

  gst_init (&argc, &argv);

  resampler = gst_audio_resampler_new (
      GST_AUDIO_RESAMPLER_METHOD_NEAREST,
      GST_AUDIO_RESAMPLER_FLAG_VARIABLE_RATE,
      GST_AUDIO_FORMAT_S16,
      1,
      48000,
      24000,
      NULL);

  if (resampler == NULL) {
    g_printerr ("Failed to create audio resampler\n");
    return 1;
  }

  before_update =
      gst_audio_resampler_get_out_frames (resampler, 480);

  latency =
      gst_audio_resampler_get_max_latency (resampler);

  updated = gst_audio_resampler_update (
      resampler,
      48000,
      44100,
      NULL);

  if (!updated) {
    g_printerr ("Failed to update audio resampler\n");
    gst_audio_resampler_free (resampler);
    return 1;
  }

  after_update =
      gst_audio_resampler_get_out_frames (resampler, 480);

  g_print ("Before update output frames: %"
      G_GSIZE_FORMAT "\n", before_update);
  g_print ("Update result: %s\n",
      updated ? "TRUE" : "FALSE");
  g_print ("After update output frames: %"
      G_GSIZE_FORMAT "\n", after_update);
  g_print ("Max latency: %" G_GSIZE_FORMAT "\n",
      latency);

  gst_audio_resampler_free (resampler);

  return 0;
}

编译运行:

bash 复制代码
gcc test_resampler_update.c -o test_resampler_update \
  $(pkg-config --cflags --libs gstreamer-1.0 gstreamer-audio-1.0)

./test_resampler_update

关键输出:

text 复制代码
Before update output frames: 240
Update result: TRUE
After update output frames: 440
Max latency: 1

🌻5.总结

gst_audio_resampler_update()就是在保留重采样器对象和历史处理上下文的前提下,更新采样率及可选滤波配置,让后续重采样使用新的参数。

相关推荐
qetfw1 小时前
Linux tcpdump 抓包实战:网卡、主机、端口过滤与 PCAP 分析
linux·tcpdump
微信ipad协议开发1 小时前
微信视频号自动化:内容发布与互动的 API 实现
运维·微信
pilifeng11 小时前
Ubuntu Linux 目录结构详解
linux·ubuntu
电棍2332 小时前
ubuntu网卡失效
linux
律宏阔2 小时前
VMware 能识别 USB 设备,但无法连接(灰色)
linux
Rabitebla2 小时前
【Linux系统编程】指令(三):创建、删除、复制、移动、看内容
linux·数据结构·c++·算法
AR-26710-2 小时前
Linux Day9——复习第一部分(实操产出)
linux
一木 之林2 小时前
手搓家庭服务器:二手装机、Docker部署、端口映射与frp内网穿透
服务器·人工智能·git·编辑器
Methy3 小时前
IoTHub半个月崩了五次?都是裸rethrow惹的祸
服务器·c++·后端