简介: 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;
只有三个条件同时满足,基类才会启用自动字节估算:
- 子类打开了估算开关。
- 输出音频格式已经提供有效BPF。
- 已经输出至少接近一秒的音频样本。
条件满足后,基类可以把估算结果用于三类路径:
- 把上游字节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切换开关并读取状态
程序按以下顺序运行:
- 创建
alawdec对象,读取初始估算状态。 - 调用
gst_audio_decoder_set_estimate_rate()传入TRUE,再次读取状态。 - 传入
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。