Linux Gstreamer深度解析之gst_audio_decoder_set_estimate_rate调用流程与实战(四十五)

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

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

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

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

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

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

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

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

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

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

🍉🍉🍉文章目录🍉🍉🍉

🌻1.前言

本篇目的:理解gst_audio_decoder_set_estimate_rate()如何控制GstAudioDecoder的字节与时间估算能力,并通过最小程序验证开关状态变化。

压缩音频解码器接收的是编码字节,输出的是带采样率和Frame数的原始音频。上游可能使用GST_FORMAT_BYTES发起Segment、Duration或Seek请求,而解码器下游通常使用GST_FORMAT_TIME。

这两种单位之间没有固定换算关系。GstAudioDecoder只能根据已经收到的编码字节数、已经输出的样本数和输出采样率,计算一个平均估算值。

gst_audio_decoder_set_estimate_rate()就是这个能力的开关。它只修改解码器上下文中的布尔字段,不统计码流,不执行字节到时间的换算,也不会直接发送Seek事件。
#mermaid-svg-lxk1GXo9qS3w0rHI{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-lxk1GXo9qS3w0rHI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-lxk1GXo9qS3w0rHI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-lxk1GXo9qS3w0rHI .error-icon{fill:#552222;}#mermaid-svg-lxk1GXo9qS3w0rHI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-lxk1GXo9qS3w0rHI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-lxk1GXo9qS3w0rHI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-lxk1GXo9qS3w0rHI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-lxk1GXo9qS3w0rHI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-lxk1GXo9qS3w0rHI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-lxk1GXo9qS3w0rHI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-lxk1GXo9qS3w0rHI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-lxk1GXo9qS3w0rHI .marker.cross{stroke:#333333;}#mermaid-svg-lxk1GXo9qS3w0rHI svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-lxk1GXo9qS3w0rHI p{margin:0;}#mermaid-svg-lxk1GXo9qS3w0rHI .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-lxk1GXo9qS3w0rHI .cluster-label text{fill:#333;}#mermaid-svg-lxk1GXo9qS3w0rHI .cluster-label span{color:#333;}#mermaid-svg-lxk1GXo9qS3w0rHI .cluster-label span p{background-color:transparent;}#mermaid-svg-lxk1GXo9qS3w0rHI .label text,#mermaid-svg-lxk1GXo9qS3w0rHI span{fill:#333;color:#333;}#mermaid-svg-lxk1GXo9qS3w0rHI .node rect,#mermaid-svg-lxk1GXo9qS3w0rHI .node circle,#mermaid-svg-lxk1GXo9qS3w0rHI .node ellipse,#mermaid-svg-lxk1GXo9qS3w0rHI .node polygon,#mermaid-svg-lxk1GXo9qS3w0rHI .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-lxk1GXo9qS3w0rHI .rough-node .label text,#mermaid-svg-lxk1GXo9qS3w0rHI .node .label text,#mermaid-svg-lxk1GXo9qS3w0rHI .image-shape .label,#mermaid-svg-lxk1GXo9qS3w0rHI .icon-shape .label{text-anchor:middle;}#mermaid-svg-lxk1GXo9qS3w0rHI .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-lxk1GXo9qS3w0rHI .rough-node .label,#mermaid-svg-lxk1GXo9qS3w0rHI .node .label,#mermaid-svg-lxk1GXo9qS3w0rHI .image-shape .label,#mermaid-svg-lxk1GXo9qS3w0rHI .icon-shape .label{text-align:center;}#mermaid-svg-lxk1GXo9qS3w0rHI .node.clickable{cursor:pointer;}#mermaid-svg-lxk1GXo9qS3w0rHI .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-lxk1GXo9qS3w0rHI .arrowheadPath{fill:#333333;}#mermaid-svg-lxk1GXo9qS3w0rHI .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-lxk1GXo9qS3w0rHI .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-lxk1GXo9qS3w0rHI .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-lxk1GXo9qS3w0rHI .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-lxk1GXo9qS3w0rHI .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-lxk1GXo9qS3w0rHI .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-lxk1GXo9qS3w0rHI .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-lxk1GXo9qS3w0rHI .cluster text{fill:#333;}#mermaid-svg-lxk1GXo9qS3w0rHI .cluster span{color:#333;}#mermaid-svg-lxk1GXo9qS3w0rHI 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-lxk1GXo9qS3w0rHI .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-lxk1GXo9qS3w0rHI rect.text{fill:none;stroke-width:0;}#mermaid-svg-lxk1GXo9qS3w0rHI .icon-shape,#mermaid-svg-lxk1GXo9qS3w0rHI .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-lxk1GXo9qS3w0rHI .icon-shape p,#mermaid-svg-lxk1GXo9qS3w0rHI .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-lxk1GXo9qS3w0rHI .icon-shape .label rect,#mermaid-svg-lxk1GXo9qS3w0rHI .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-lxk1GXo9qS3w0rHI .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-lxk1GXo9qS3w0rHI .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-lxk1GXo9qS3w0rHI :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} GstAudioDecoder对象
子类启动阶段设置估算开关
累计编码字节和输出Frame
达到基类估算条件
辅助字节与时间换算

🌻2.应用场景和用法

2.1字节与时间估算场景

gst_audio_decoder_set_estimate_rate()主要用于编码音频解码器需要兼容字节单位上游的场景。

场景 调用目的 实际作用
字节流上游发起时间Seek 允许基类把时间位置估算成字节偏移 向上游发送字节Seek
上游发送非TIME格式Segment 允许基类把字节Segment起点估算成时间 把后续解码流程切换到TIME Segment
上游只能提供字节Duration 允许基类根据平均码率估算时间Duration 回答下游的时间长度查询
传统编码解码器兼容 让解码器继续支持旧式BYTE定位方式 改善Seek和Duration能力

这种换算只适合估算,不能当作精确码率。对于可变码率格式,估算值会随着累计数据变化。

这个函数不负责以下工作:

  • 不修改输入Buffer。
  • 不更新bytes_in和samples_out。
  • 不建立输出音频格式。
  • 不生成时间戳。
  • 不直接调用上游Pad发送Seek。
  • 不保证所有GST_QUERY_CONVERT请求都成功。

输出Buffer的PTS和Duration仍由gst_audio_decoder_finish_frame()等输出接口结合GstAudioInfo完成。

2.2函数原型与返回语义

函数原型如下:

c 复制代码
void
gst_audio_decoder_set_estimate_rate (GstAudioDecoder *dec,
                                     gboolean enabled);
参数 含义
dec 有效的GstAudioDecoder对象
enabled TRUE允许基类执行字节与时间的估算辅助,FALSE关闭该能力
返回值 void

函数实现的核心动作如下:

c 复制代码
g_return_if_fail (GST_IS_AUDIO_DECODER (dec));

dec->priv->ctx.do_estimate_rate = enabled;

最小调用方式通常放在音频解码器子类的start()回调中:

c 复制代码
static gboolean
my_decoder_start (GstAudioDecoder *dec)
{
  gst_audio_decoder_set_estimate_rate (dec, TRUE);
  return TRUE;
}

部分GStreamer解码器,例如alawdec、mulawdec、a52dec和faad,会在启动阶段打开这个开关。

基类完整复位时会清空GstAudioDecoderContext,因此应用或子类不应只在对象创建后设置一次。需要持续生效时,应在子类start()中重新设置。

相邻接口的职责不同:

接口 作用
gst_audio_decoder_set_estimate_rate() 修改估算开关
gst_audio_decoder_get_estimate_rate() 读取当前开关状态
gst_audio_decoder_handle_frame() 累计输入编码字节数
gst_audio_decoder_finish_frame() 累计已输出样本数
gst_pad_query_convert() 触发Pad之间的格式换算请求
gst_audio_decoder_do_byte() 基类内部判断当前是否允许自动字节换算

gst_audio_decoder_set_estimate_rate()只改变策略,不会立即触发后续换算路径。

🌻3.调用流程剖析

3.1设置开关到基类辅助路径

解码器子类通常在启动阶段调用目标函数。目标函数先检查对象类型,再把enabled写入dec->priv->ctx.do_estimate_rate。

之后,基类在处理Segment、Seek和Duration时,会调用内部的gst_audio_decoder_do_byte()判断条件:

c 复制代码
ret = dec->priv->ctx.do_estimate_rate &&
    dec->priv->ctx.info.bpf &&
    dec->priv->ctx.info.rate <= dec->priv->samples_out;

只有三个条件同时满足,基类才会启用自动字节估算:

  1. 子类打开了估算开关。
  2. 输出音频格式已经提供有效BPF。
  3. 已经输出至少接近一秒的音频样本。

条件满足后,基类可以把估算结果用于三类路径:

  • 把上游字节Segment起点转换成TIME。
  • 把时间Seek转换成字节Seek发送给上游。
  • 把上游提供的字节Duration转换成时间Duration。

#mermaid-svg-oMvwCwcznwIUtDfc{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-oMvwCwcznwIUtDfc .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-oMvwCwcznwIUtDfc .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-oMvwCwcznwIUtDfc .error-icon{fill:#552222;}#mermaid-svg-oMvwCwcznwIUtDfc .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-oMvwCwcznwIUtDfc .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-oMvwCwcznwIUtDfc .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-oMvwCwcznwIUtDfc .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-oMvwCwcznwIUtDfc .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-oMvwCwcznwIUtDfc .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-oMvwCwcznwIUtDfc .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-oMvwCwcznwIUtDfc .marker{fill:#333333;stroke:#333333;}#mermaid-svg-oMvwCwcznwIUtDfc .marker.cross{stroke:#333333;}#mermaid-svg-oMvwCwcznwIUtDfc svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-oMvwCwcznwIUtDfc p{margin:0;}#mermaid-svg-oMvwCwcznwIUtDfc .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-oMvwCwcznwIUtDfc .cluster-label text{fill:#333;}#mermaid-svg-oMvwCwcznwIUtDfc .cluster-label span{color:#333;}#mermaid-svg-oMvwCwcznwIUtDfc .cluster-label span p{background-color:transparent;}#mermaid-svg-oMvwCwcznwIUtDfc .label text,#mermaid-svg-oMvwCwcznwIUtDfc span{fill:#333;color:#333;}#mermaid-svg-oMvwCwcznwIUtDfc .node rect,#mermaid-svg-oMvwCwcznwIUtDfc .node circle,#mermaid-svg-oMvwCwcznwIUtDfc .node ellipse,#mermaid-svg-oMvwCwcznwIUtDfc .node polygon,#mermaid-svg-oMvwCwcznwIUtDfc .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-oMvwCwcznwIUtDfc .rough-node .label text,#mermaid-svg-oMvwCwcznwIUtDfc .node .label text,#mermaid-svg-oMvwCwcznwIUtDfc .image-shape .label,#mermaid-svg-oMvwCwcznwIUtDfc .icon-shape .label{text-anchor:middle;}#mermaid-svg-oMvwCwcznwIUtDfc .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-oMvwCwcznwIUtDfc .rough-node .label,#mermaid-svg-oMvwCwcznwIUtDfc .node .label,#mermaid-svg-oMvwCwcznwIUtDfc .image-shape .label,#mermaid-svg-oMvwCwcznwIUtDfc .icon-shape .label{text-align:center;}#mermaid-svg-oMvwCwcznwIUtDfc .node.clickable{cursor:pointer;}#mermaid-svg-oMvwCwcznwIUtDfc .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-oMvwCwcznwIUtDfc .arrowheadPath{fill:#333333;}#mermaid-svg-oMvwCwcznwIUtDfc .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-oMvwCwcznwIUtDfc .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-oMvwCwcznwIUtDfc .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-oMvwCwcznwIUtDfc .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-oMvwCwcznwIUtDfc .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-oMvwCwcznwIUtDfc .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-oMvwCwcznwIUtDfc .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-oMvwCwcznwIUtDfc .cluster text{fill:#333;}#mermaid-svg-oMvwCwcznwIUtDfc .cluster span{color:#333;}#mermaid-svg-oMvwCwcznwIUtDfc 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-oMvwCwcznwIUtDfc .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-oMvwCwcznwIUtDfc rect.text{fill:none;stroke-width:0;}#mermaid-svg-oMvwCwcznwIUtDfc .icon-shape,#mermaid-svg-oMvwCwcznwIUtDfc .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-oMvwCwcznwIUtDfc .icon-shape p,#mermaid-svg-oMvwCwcznwIUtDfc .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-oMvwCwcznwIUtDfc .icon-shape .label rect,#mermaid-svg-oMvwCwcznwIUtDfc .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-oMvwCwcznwIUtDfc .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-oMvwCwcznwIUtDfc .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-oMvwCwcznwIUtDfc :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 解码器子类启动阶段
设置估算开关
基类累计输入和输出统计
检查字节估算条件
执行BYTE到TIME估算
辅助Segment和Seek及Duration

如果开关关闭、输出格式尚未协商或输出样本不足,gst_audio_decoder_do_byte()返回FALSE。此时设置函数本身不会报错,后续查询或Seek路径是否成功由其他Pad和上游组件决定。

3.2累计统计与估算公式

输入编码字节数和输出样本数来自两个不同阶段。

gst_audio_decoder_handle_frame()收到输入Buffer后,会把Buffer大小累加到priv->bytes_in:

c 复制代码
dec->priv->bytes_in += size;

子类调用gst_audio_decoder_finish_frame()或相关输出接口后,基类会把已输出样本数累加到priv->samples_out:

c 复制代码
priv->samples_out += samples;

随后,内部辅助函数使用输出采样率和累计统计值估算平均字节速率。

字节到时间的核心计算可以表示为:

text 复制代码
estimated_time =
    byte_position × GST_SECOND × samples_out
    ÷ (bytes_in × sample_rate)

时间到字节的反向计算可以表示为:

text 复制代码
estimated_bytes =
    time_position × bytes_in × sample_rate
    ÷ (samples_out × GST_SECOND)

这里的bytes_in是累计编码字节数,sample_rate来自已经协商的输出GstAudioInfo,samples_out是已经解码并交给基类的输出样本数。
#mermaid-svg-koDJD0oKRkvimOwX{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-koDJD0oKRkvimOwX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-koDJD0oKRkvimOwX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-koDJD0oKRkvimOwX .error-icon{fill:#552222;}#mermaid-svg-koDJD0oKRkvimOwX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-koDJD0oKRkvimOwX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-koDJD0oKRkvimOwX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-koDJD0oKRkvimOwX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-koDJD0oKRkvimOwX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-koDJD0oKRkvimOwX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-koDJD0oKRkvimOwX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-koDJD0oKRkvimOwX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-koDJD0oKRkvimOwX .marker.cross{stroke:#333333;}#mermaid-svg-koDJD0oKRkvimOwX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-koDJD0oKRkvimOwX p{margin:0;}#mermaid-svg-koDJD0oKRkvimOwX .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-koDJD0oKRkvimOwX .cluster-label text{fill:#333;}#mermaid-svg-koDJD0oKRkvimOwX .cluster-label span{color:#333;}#mermaid-svg-koDJD0oKRkvimOwX .cluster-label span p{background-color:transparent;}#mermaid-svg-koDJD0oKRkvimOwX .label text,#mermaid-svg-koDJD0oKRkvimOwX span{fill:#333;color:#333;}#mermaid-svg-koDJD0oKRkvimOwX .node rect,#mermaid-svg-koDJD0oKRkvimOwX .node circle,#mermaid-svg-koDJD0oKRkvimOwX .node ellipse,#mermaid-svg-koDJD0oKRkvimOwX .node polygon,#mermaid-svg-koDJD0oKRkvimOwX .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-koDJD0oKRkvimOwX .rough-node .label text,#mermaid-svg-koDJD0oKRkvimOwX .node .label text,#mermaid-svg-koDJD0oKRkvimOwX .image-shape .label,#mermaid-svg-koDJD0oKRkvimOwX .icon-shape .label{text-anchor:middle;}#mermaid-svg-koDJD0oKRkvimOwX .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-koDJD0oKRkvimOwX .rough-node .label,#mermaid-svg-koDJD0oKRkvimOwX .node .label,#mermaid-svg-koDJD0oKRkvimOwX .image-shape .label,#mermaid-svg-koDJD0oKRkvimOwX .icon-shape .label{text-align:center;}#mermaid-svg-koDJD0oKRkvimOwX .node.clickable{cursor:pointer;}#mermaid-svg-koDJD0oKRkvimOwX .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-koDJD0oKRkvimOwX .arrowheadPath{fill:#333333;}#mermaid-svg-koDJD0oKRkvimOwX .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-koDJD0oKRkvimOwX .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-koDJD0oKRkvimOwX .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-koDJD0oKRkvimOwX .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-koDJD0oKRkvimOwX .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-koDJD0oKRkvimOwX .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-koDJD0oKRkvimOwX .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-koDJD0oKRkvimOwX .cluster text{fill:#333;}#mermaid-svg-koDJD0oKRkvimOwX .cluster span{color:#333;}#mermaid-svg-koDJD0oKRkvimOwX 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-koDJD0oKRkvimOwX .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-koDJD0oKRkvimOwX rect.text{fill:none;stroke-width:0;}#mermaid-svg-koDJD0oKRkvimOwX .icon-shape,#mermaid-svg-koDJD0oKRkvimOwX .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-koDJD0oKRkvimOwX .icon-shape p,#mermaid-svg-koDJD0oKRkvimOwX .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-koDJD0oKRkvimOwX .icon-shape .label rect,#mermaid-svg-koDJD0oKRkvimOwX .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-koDJD0oKRkvimOwX .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-koDJD0oKRkvimOwX .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-koDJD0oKRkvimOwX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 输入编码字节
累计bytes_in
解码输出Frame
累计samples_out
检查估算条件
计算BYTE和TIME的估算值

因此,刚打开开关时不一定马上可以完成换算。没有有效采样率、BPF为0或输出样本数少于一个采样率周期时,基类会认为统计信息不足。

🌻4.实战案例

4.1准备内置音频解码器

使用GStreamer自带的alawdec作为测试对象。alawdec属于GstAudioDecoder子类,正常启动时会在start()回调中调用:

c 复制代码
gst_audio_decoder_set_estimate_rate (dec, TRUE);

测试程序直接创建该解码器对象,并通过Getter和Setter观察上下文开关。

4.2切换开关并读取状态

程序按以下顺序运行:

  1. 创建alawdec对象,读取初始估算状态。
  2. 调用gst_audio_decoder_set_estimate_rate()传入TRUE,再次读取状态。
  3. 传入FALSE,确认开关能够关闭。

这个实验验证的是Setter的直接职责。它不会产生字节换算结果,因为程序没有建立完整解码链,也没有累计输入字节、输出样本和协商后的音频格式。

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

int
main (int argc, char *argv[])
{
  GstElement *element;
  GstAudioDecoder *decoder;

  gst_init (&argc, &argv);

  element = gst_element_factory_make ("alawdec", "decoder");
  if (element == NULL) {
    g_printerr ("Failed to create alawdec\n");
    return 1;
  }

  decoder = GST_AUDIO_DECODER (element);

  g_print ("Initial estimate rate: %d\n",
      gst_audio_decoder_get_estimate_rate (decoder));

  gst_audio_decoder_set_estimate_rate (decoder, TRUE);
  g_print ("After enabling: %d\n",
      gst_audio_decoder_get_estimate_rate (decoder));

  gst_audio_decoder_set_estimate_rate (decoder, FALSE);
  g_print ("After disabling: %d\n",
      gst_audio_decoder_get_estimate_rate (decoder));

  gst_object_unref (element);

  return 0;
}

编译运行:

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

./test_estimate_rate

运行环境需要安装包含alawdec的GStreamer插件。关键输出:

text 复制代码
Initial estimate rate: 0
After enabling: 1
After disabling: 0

输出证明gst_audio_decoder_set_estimate_rate()只修改GstAudioDecoderContext中的估算开关。真正的字节与时间换算,还需要解码器完成格式协商并累计足够的输入字节和输出样本。

🌻5.总结

gst_audio_decoder_set_estimate_rate()就是为GstAudioDecoder打开或关闭基类的字节与时间估算能力,本身不统计码流、不执行换算,也不直接发起Seek。

相关推荐
FED_AF1 小时前
Linux运维“邪修”功法之通配符
linux·运维
箓维1 小时前
线程的概念和理解
linux
云杂项1 小时前
tmux指南:安装、配置与高效使用(Ubuntu上)
linux·服务器·ubuntu
j7~2 小时前
【Linux网络编程】四十七.《Linux IO 模型详解:阻塞 IO、非阻塞 IO 与 IO 多路转接(select)》
linux·运维·网络·select·非阻塞io·阻塞io·i/o多路连接
GeW2 小时前
智能工厂背后:Linux在跑,数据库在扛,高端制造在加速
linux
qq_394562002 小时前
【在Linux上升级nginx】
linux·服务器·nginx
Tairitsu_H3 小时前
[Linux系统] 基础IO核心 | 系统接口 | 文件描述符 | 重定向
linux·服务器·文件操作
嵌入式-老费3 小时前
esp32开发与应用(用Python+PySide6解决上位机开发)
linux·单片机·嵌入式硬件
事已至此先睡覺吧3 小时前
(三)Linux 基础指令(二):基础常用的一些指令
linux·运维·服务器