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

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

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

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

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

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

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

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

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

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

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

🍉🍉🍉文章目录🍉🍉🍉

🌻1.前言

本篇目的:理解gst_audio_encoder_get_frame_max()读取的配置值是什么,分析它如何影响GstAudioEncoder向子类提交输入数据,并通过最小C程序查询该值。

音频编码器子类可以设置每次交给handle_frame()处理的输入数据大小。固定输入样本数时,如果上游一次送来多个完整编码单元,基类可以把若干单元合并后再交给子类处理。

gst_audio_encoder_get_frame_max()用于查询当前配置的最大处理单元数。它只读取配置,不会设置批量大小,也不会读取或编码PCM数据。
#mermaid-svg-QBzzPliGXyKAvTz1{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-QBzzPliGXyKAvTz1 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-QBzzPliGXyKAvTz1 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-QBzzPliGXyKAvTz1 .error-icon{fill:#552222;}#mermaid-svg-QBzzPliGXyKAvTz1 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-QBzzPliGXyKAvTz1 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-QBzzPliGXyKAvTz1 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-QBzzPliGXyKAvTz1 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-QBzzPliGXyKAvTz1 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-QBzzPliGXyKAvTz1 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-QBzzPliGXyKAvTz1 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-QBzzPliGXyKAvTz1 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-QBzzPliGXyKAvTz1 .marker.cross{stroke:#333333;}#mermaid-svg-QBzzPliGXyKAvTz1 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-QBzzPliGXyKAvTz1 p{margin:0;}#mermaid-svg-QBzzPliGXyKAvTz1 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-QBzzPliGXyKAvTz1 .cluster-label text{fill:#333;}#mermaid-svg-QBzzPliGXyKAvTz1 .cluster-label span{color:#333;}#mermaid-svg-QBzzPliGXyKAvTz1 .cluster-label span p{background-color:transparent;}#mermaid-svg-QBzzPliGXyKAvTz1 .label text,#mermaid-svg-QBzzPliGXyKAvTz1 span{fill:#333;color:#333;}#mermaid-svg-QBzzPliGXyKAvTz1 .node rect,#mermaid-svg-QBzzPliGXyKAvTz1 .node circle,#mermaid-svg-QBzzPliGXyKAvTz1 .node ellipse,#mermaid-svg-QBzzPliGXyKAvTz1 .node polygon,#mermaid-svg-QBzzPliGXyKAvTz1 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-QBzzPliGXyKAvTz1 .rough-node .label text,#mermaid-svg-QBzzPliGXyKAvTz1 .node .label text,#mermaid-svg-QBzzPliGXyKAvTz1 .image-shape .label,#mermaid-svg-QBzzPliGXyKAvTz1 .icon-shape .label{text-anchor:middle;}#mermaid-svg-QBzzPliGXyKAvTz1 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-QBzzPliGXyKAvTz1 .rough-node .label,#mermaid-svg-QBzzPliGXyKAvTz1 .node .label,#mermaid-svg-QBzzPliGXyKAvTz1 .image-shape .label,#mermaid-svg-QBzzPliGXyKAvTz1 .icon-shape .label{text-align:center;}#mermaid-svg-QBzzPliGXyKAvTz1 .node.clickable{cursor:pointer;}#mermaid-svg-QBzzPliGXyKAvTz1 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-QBzzPliGXyKAvTz1 .arrowheadPath{fill:#333333;}#mermaid-svg-QBzzPliGXyKAvTz1 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-QBzzPliGXyKAvTz1 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-QBzzPliGXyKAvTz1 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QBzzPliGXyKAvTz1 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-QBzzPliGXyKAvTz1 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QBzzPliGXyKAvTz1 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-QBzzPliGXyKAvTz1 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-QBzzPliGXyKAvTz1 .cluster text{fill:#333;}#mermaid-svg-QBzzPliGXyKAvTz1 .cluster span{color:#333;}#mermaid-svg-QBzzPliGXyKAvTz1 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-QBzzPliGXyKAvTz1 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-QBzzPliGXyKAvTz1 rect.text{fill:none;stroke-width:0;}#mermaid-svg-QBzzPliGXyKAvTz1 .icon-shape,#mermaid-svg-QBzzPliGXyKAvTz1 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QBzzPliGXyKAvTz1 .icon-shape p,#mermaid-svg-QBzzPliGXyKAvTz1 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-QBzzPliGXyKAvTz1 .icon-shape .label rect,#mermaid-svg-QBzzPliGXyKAvTz1 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QBzzPliGXyKAvTz1 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-QBzzPliGXyKAvTz1 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-QBzzPliGXyKAvTz1 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} GstAudioEncoder对象
读取frame_max配置
返回当前最大处理单元数
基类据此组织输入样本
向handle_frame提交输入

🌻2.应用场景和用法

2.1查询编码器输入批量配置

frame_max用于控制基类一次最多把多少个完整输入单元交给编码器子类处理。它只有在frame_samples_min和frame_samples_max相等时,才参与基类的批量组织逻辑。

场景 查询目的 需要关注的配置
固定帧长编码 确认每次handle_frame()最多收到多少个完整单元 frame_samples_min、frame_samples_max、frame_max
编码器调试 判断多份PCM样本为何被合并后提交 输入缓存中的可用字节数和frame_max
格式重新协商 确认set_format()重新配置后的当前值 在子类设置参数后再次查询
默认配置排查 判断当前是否设置了批量上限 查询结果为0时检查格式配置阶段

frame_max表示可合并处理的单元数量,不是每个单元包含的PCM样本数,也不是编码后的输出帧数。每个单元的样本数由frame_samples_min和frame_samples_max描述。

2.2函数原型与返回语义

函数原型如下:

c 复制代码
gint
gst_audio_encoder_get_frame_max (GstAudioEncoder *enc);
参数或返回值 含义
enc 有效的GstAudioEncoder对象
返回值 当前配置的最大处理单元数

最小调用方式如下:

c 复制代码
gint frame_max;

frame_max = gst_audio_encoder_get_frame_max (encoder);

该函数直接读取编码器私有上下文中的frame_max字段,不修改编码器状态,也不分配对象。传入无效对象时,函数通过参数检查并返回0;有效对象的初始值或尚未配置时也可能是0,因此不能只凭0判断调用失败。

配置通常由编码器子类在set_format()中完成。若要求每个处理单元具有固定样本数,应先将最小和最大样本数设为相同值,再设置最大单元数:

c 复制代码
gst_audio_encoder_set_frame_samples_min (encoder, 1024);
gst_audio_encoder_set_frame_samples_max (encoder, 1024);
gst_audio_encoder_set_frame_max (encoder, 3);

gst_audio_encoder_set_frame_max()的值会在基类调用子类set_format()前重置为0。因此,子类应在每次格式配置时重新设置;需要确认生效值时,再调用gst_audio_encoder_get_frame_max()查询。

相邻接口职责如下:

接口 职责
gst_audio_encoder_set_frame_samples_min() 设置每个处理单元至少需要的每声道样本数
gst_audio_encoder_set_frame_samples_max() 设置每个处理单元最多需要的每声道样本数
gst_audio_encoder_set_frame_max() 设置基类一次最多合并多少个完整处理单元
gst_audio_encoder_get_frame_max() 读取当前最大处理单元数
gst_audio_encoder_finish_frame() 提交编码输出,并告知基类已处理的输入样本数

🌻3.调用流程剖析

3.1读取基类上下文中的配置值

gst_audio_encoder_get_frame_max()的实现很短,核心动作是检查对象类型后返回上下文中的frame_max:

c 复制代码
gint
gst_audio_encoder_get_frame_max (GstAudioEncoder *enc)
{
  g_return_val_if_fail (GST_IS_AUDIO_ENCODER (enc), 0);

  return enc->priv->ctx.frame_max;
}

这里没有计算输入数据大小,也没有对配置值做转换。返回值反映的是当前保存的配置。

基类在处理新的输入格式时,会先把frame_samples_min、frame_samples_max和frame_max等参数重置,再调用子类的set_format()。子类需要在这个回调中重新设置参数,随后查询才能读到新格式对应的值。
#mermaid-svg-BFnr8d4VMlGiImC0{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-BFnr8d4VMlGiImC0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-BFnr8d4VMlGiImC0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-BFnr8d4VMlGiImC0 .error-icon{fill:#552222;}#mermaid-svg-BFnr8d4VMlGiImC0 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-BFnr8d4VMlGiImC0 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-BFnr8d4VMlGiImC0 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-BFnr8d4VMlGiImC0 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-BFnr8d4VMlGiImC0 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-BFnr8d4VMlGiImC0 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-BFnr8d4VMlGiImC0 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-BFnr8d4VMlGiImC0 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-BFnr8d4VMlGiImC0 .marker.cross{stroke:#333333;}#mermaid-svg-BFnr8d4VMlGiImC0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-BFnr8d4VMlGiImC0 p{margin:0;}#mermaid-svg-BFnr8d4VMlGiImC0 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-BFnr8d4VMlGiImC0 .cluster-label text{fill:#333;}#mermaid-svg-BFnr8d4VMlGiImC0 .cluster-label span{color:#333;}#mermaid-svg-BFnr8d4VMlGiImC0 .cluster-label span p{background-color:transparent;}#mermaid-svg-BFnr8d4VMlGiImC0 .label text,#mermaid-svg-BFnr8d4VMlGiImC0 span{fill:#333;color:#333;}#mermaid-svg-BFnr8d4VMlGiImC0 .node rect,#mermaid-svg-BFnr8d4VMlGiImC0 .node circle,#mermaid-svg-BFnr8d4VMlGiImC0 .node ellipse,#mermaid-svg-BFnr8d4VMlGiImC0 .node polygon,#mermaid-svg-BFnr8d4VMlGiImC0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-BFnr8d4VMlGiImC0 .rough-node .label text,#mermaid-svg-BFnr8d4VMlGiImC0 .node .label text,#mermaid-svg-BFnr8d4VMlGiImC0 .image-shape .label,#mermaid-svg-BFnr8d4VMlGiImC0 .icon-shape .label{text-anchor:middle;}#mermaid-svg-BFnr8d4VMlGiImC0 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-BFnr8d4VMlGiImC0 .rough-node .label,#mermaid-svg-BFnr8d4VMlGiImC0 .node .label,#mermaid-svg-BFnr8d4VMlGiImC0 .image-shape .label,#mermaid-svg-BFnr8d4VMlGiImC0 .icon-shape .label{text-align:center;}#mermaid-svg-BFnr8d4VMlGiImC0 .node.clickable{cursor:pointer;}#mermaid-svg-BFnr8d4VMlGiImC0 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-BFnr8d4VMlGiImC0 .arrowheadPath{fill:#333333;}#mermaid-svg-BFnr8d4VMlGiImC0 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-BFnr8d4VMlGiImC0 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-BFnr8d4VMlGiImC0 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BFnr8d4VMlGiImC0 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-BFnr8d4VMlGiImC0 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BFnr8d4VMlGiImC0 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-BFnr8d4VMlGiImC0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-BFnr8d4VMlGiImC0 .cluster text{fill:#333;}#mermaid-svg-BFnr8d4VMlGiImC0 .cluster span{color:#333;}#mermaid-svg-BFnr8d4VMlGiImC0 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-BFnr8d4VMlGiImC0 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-BFnr8d4VMlGiImC0 rect.text{fill:none;stroke-width:0;}#mermaid-svg-BFnr8d4VMlGiImC0 .icon-shape,#mermaid-svg-BFnr8d4VMlGiImC0 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BFnr8d4VMlGiImC0 .icon-shape p,#mermaid-svg-BFnr8d4VMlGiImC0 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-BFnr8d4VMlGiImC0 .icon-shape .label rect,#mermaid-svg-BFnr8d4VMlGiImC0 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BFnr8d4VMlGiImC0 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-BFnr8d4VMlGiImC0 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-BFnr8d4VMlGiImC0 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否
是
调用get_frame_max
检查AudioEncoder对象
对象是否合法
返回0
读取ctx.frame_max
返回配置值

3.2基类使用配置组织输入数据

查询函数本身只读配置。真正使用frame_max的是基类的输入处理逻辑:基类从输入适配器中查看已有数据,并依据每个处理单元的样本数,计算本次交给handle_frame()的数据长度。

当frame_samples_min与frame_samples_max相等且大于0时,输入数据可以按固定大小划分。如果frame_max大于1,基类最多合并指定数量的完整单元;如果frame_max为0,基类可以把当前缓存中可组成的完整单元一起提交。值为1时,每次按一个单元处理。

例如,S16立体声每个样本帧占4字节。若每个处理单元包含1024个每声道样本,则一个单元占:

text 复制代码
1024 × 4 = 4096字节

当frame_max为3且缓存中至少有3个完整单元时,基类最多提交3个单元,即12288字节。子类随后在handle_frame()中处理输入,并通过gst_audio_encoder_finish_frame()提交编码结果。
#mermaid-svg-jQLscbyXeUJ2g9tY{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-jQLscbyXeUJ2g9tY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jQLscbyXeUJ2g9tY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jQLscbyXeUJ2g9tY .error-icon{fill:#552222;}#mermaid-svg-jQLscbyXeUJ2g9tY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jQLscbyXeUJ2g9tY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jQLscbyXeUJ2g9tY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jQLscbyXeUJ2g9tY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jQLscbyXeUJ2g9tY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jQLscbyXeUJ2g9tY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jQLscbyXeUJ2g9tY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jQLscbyXeUJ2g9tY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jQLscbyXeUJ2g9tY .marker.cross{stroke:#333333;}#mermaid-svg-jQLscbyXeUJ2g9tY svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jQLscbyXeUJ2g9tY p{margin:0;}#mermaid-svg-jQLscbyXeUJ2g9tY .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-jQLscbyXeUJ2g9tY .cluster-label text{fill:#333;}#mermaid-svg-jQLscbyXeUJ2g9tY .cluster-label span{color:#333;}#mermaid-svg-jQLscbyXeUJ2g9tY .cluster-label span p{background-color:transparent;}#mermaid-svg-jQLscbyXeUJ2g9tY .label text,#mermaid-svg-jQLscbyXeUJ2g9tY span{fill:#333;color:#333;}#mermaid-svg-jQLscbyXeUJ2g9tY .node rect,#mermaid-svg-jQLscbyXeUJ2g9tY .node circle,#mermaid-svg-jQLscbyXeUJ2g9tY .node ellipse,#mermaid-svg-jQLscbyXeUJ2g9tY .node polygon,#mermaid-svg-jQLscbyXeUJ2g9tY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jQLscbyXeUJ2g9tY .rough-node .label text,#mermaid-svg-jQLscbyXeUJ2g9tY .node .label text,#mermaid-svg-jQLscbyXeUJ2g9tY .image-shape .label,#mermaid-svg-jQLscbyXeUJ2g9tY .icon-shape .label{text-anchor:middle;}#mermaid-svg-jQLscbyXeUJ2g9tY .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-jQLscbyXeUJ2g9tY .rough-node .label,#mermaid-svg-jQLscbyXeUJ2g9tY .node .label,#mermaid-svg-jQLscbyXeUJ2g9tY .image-shape .label,#mermaid-svg-jQLscbyXeUJ2g9tY .icon-shape .label{text-align:center;}#mermaid-svg-jQLscbyXeUJ2g9tY .node.clickable{cursor:pointer;}#mermaid-svg-jQLscbyXeUJ2g9tY .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-jQLscbyXeUJ2g9tY .arrowheadPath{fill:#333333;}#mermaid-svg-jQLscbyXeUJ2g9tY .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-jQLscbyXeUJ2g9tY .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-jQLscbyXeUJ2g9tY .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jQLscbyXeUJ2g9tY .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-jQLscbyXeUJ2g9tY .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jQLscbyXeUJ2g9tY .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-jQLscbyXeUJ2g9tY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jQLscbyXeUJ2g9tY .cluster text{fill:#333;}#mermaid-svg-jQLscbyXeUJ2g9tY .cluster span{color:#333;}#mermaid-svg-jQLscbyXeUJ2g9tY 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-jQLscbyXeUJ2g9tY .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-jQLscbyXeUJ2g9tY rect.text{fill:none;stroke-width:0;}#mermaid-svg-jQLscbyXeUJ2g9tY .icon-shape,#mermaid-svg-jQLscbyXeUJ2g9tY .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jQLscbyXeUJ2g9tY .icon-shape p,#mermaid-svg-jQLscbyXeUJ2g9tY .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-jQLscbyXeUJ2g9tY .icon-shape .label rect,#mermaid-svg-jQLscbyXeUJ2g9tY .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jQLscbyXeUJ2g9tY .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-jQLscbyXeUJ2g9tY .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-jQLscbyXeUJ2g9tY :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
输入数据进入适配器
读取每单元样本数
最小和最大样本数相等
根据frame_max限制完整单元数
按现有样本范围组织输入
向handle_frame提交输入

🌻4.实战案例

4.1准备编码器配置

案例创建一个最小GstAudioEncoder子类,用来观察frame_max的设置和读取。

编码器将每个处理单元配置为1024个每声道样本,并将最大合并单元数设置为3。这样,查询接口应返回3。示例不启动完整音频管线,重点验证配置接口之间的关系。

4.2设置参数并查询

程序创建编码器对象后,依次执行以下操作:

  1. 将每个处理单元的最小样本数和最大样本数都设置为1024。
  2. 调用gst_audio_encoder_set_frame_max()设置最大单元数为3。
  3. 调用gst_audio_encoder_get_frame_max()读取当前值,并与期望值比较。

生产编码器应在set_format()中设置这些参数。示例在对象创建后直接设置,是为了集中展示Getter和Setter读取同一上下文配置的过程。

4.3完整代码
c 复制代码
#include <gst/gst.h>
#include <gst/audio/audio.h>

typedef struct _FrameMaxDemo
{
  GstAudioEncoder parent;
} FrameMaxDemo;

typedef struct _FrameMaxDemoClass
{
  GstAudioEncoderClass parent_class;
} FrameMaxDemoClass;

static void frame_max_demo_class_init (FrameMaxDemoClass *klass);
static void frame_max_demo_init (FrameMaxDemo *self);

G_DEFINE_TYPE (
    FrameMaxDemo,
    frame_max_demo,
    GST_TYPE_AUDIO_ENCODER);

/* 最小处理回调,本案例只查询配置,不执行真实编码 */
static GstFlowReturn
frame_max_demo_handle_frame (GstAudioEncoder *encoder,
                             GstBuffer *buffer)
{
  (void) encoder;
  (void) buffer;

  return GST_FLOW_OK;
}

static void
frame_max_demo_class_init (FrameMaxDemoClass *klass)
{
  GstAudioEncoderClass *encoder_class =
      GST_AUDIO_ENCODER_CLASS (klass);

  /* GstAudioEncoder子类需要提供帧处理回调 */
  encoder_class->handle_frame = frame_max_demo_handle_frame;
}

static void
frame_max_demo_init (FrameMaxDemo *self)
{
  (void) self;
}

int
main (int argc, char *argv[])
{
  GstAudioEncoder *encoder;
  gint frame_samples_min;
  gint frame_samples_max;
  gint frame_max;

  gst_init (&argc, &argv);

  /* 创建自定义GstAudioEncoder对象 */
  encoder = GST_AUDIO_ENCODER (
      g_object_new (frame_max_demo_get_type (), NULL));

  /* 固定每个处理单元的每声道样本数 */
  gst_audio_encoder_set_frame_samples_min (encoder, 1024);
  gst_audio_encoder_set_frame_samples_max (encoder, 1024);

  /* 设置一次最多合并处理3个完整单元 */
  gst_audio_encoder_set_frame_max (encoder, 3);

  /* 读取基类当前保存的三个配置值 */
  frame_samples_min =
      gst_audio_encoder_get_frame_samples_min (encoder);
  frame_samples_max =
      gst_audio_encoder_get_frame_samples_max (encoder);
  frame_max =
      gst_audio_encoder_get_frame_max (encoder);

  g_print ("frame_samples_min: %d\n", frame_samples_min);
  g_print ("frame_samples_max: %d\n", frame_samples_max);
  g_print ("frame_max: %d\n", frame_max);

  /* 最小值和最大值相等时,frame_max才用于固定单元的批量组织 */
  if (frame_samples_min != frame_samples_max || frame_max != 3) {
    gst_object_unref (encoder);
    return 1;
  }

  gst_object_unref (encoder);
  return 0;
}

🌻5.总结

gst_audio_encoder_get_frame_max()就是读取GstAudioEncoder当前配置的最大处理单元数,供子类确认基类的输入批量组织参数。

相关推荐
l1t2 小时前
DeepSeek总结的一个不含数据的 DuckDB 数据库
服务器·数据库·duckdb
忆挽篱笙歌2 小时前
makefil
linux·运维·服务器
菜_小_白3 小时前
codex
linux·vscode·ai
程序员老赵3 小时前
Docker 部署 Dolibarr:轻松搭建开源 ERP/CRM 平台
运维·前端·后端
zhangrelay3 小时前
用ROS2Lyrical实验报告册思路重做蓝桥云课ROS1实验并改进
linux·笔记·学习·ubuntu·机器人
林兴洋3 小时前
linux-mtr命令-ping和traceroute的能力合二为一
linux
cws2004013 小时前
监控摄像头选型指南
运维·网络·监控
变量探索SEQVEC3 小时前
一个网段里 10 个 IP,其实是同一个人:13 天蜜罐日志的攻击者画像
服务器
协皓家具3 小时前
2026年广州岛台吧台椅厂家有啥新变化
大数据·运维·python·devops