简介: 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设置参数并查询
程序创建编码器对象后,依次执行以下操作:
- 将每个处理单元的最小样本数和最大样本数都设置为1024。
- 调用
gst_audio_encoder_set_frame_max()设置最大单元数为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当前配置的最大处理单元数,供子类确认基类的输入批量组织参数。