Linux Gstreamer深度解析之gst_audio_encoder_set_hard_min调用流程与实战(六十二)
简介CSDN博客专家、《Android系统多媒体进阶实战》作者博主新书推荐《Android系统多媒体进阶实战》Android Audio工程师专栏地址Audio工程师进阶系列【原创干货持续更新中……】Android多媒体专栏地址多媒体系统工程师系列【原创干货持续更新中……】专题一 二AAOS车载系统AOSP14系统攻城狮入门视频实战课专题三Android14 Binder之HIDL与AIDL通信实战课专题四Android15快速自定义与集成音效实战课专题五Android15音频策略实战课专题六Android15音频性能实战课(无声/杂音/断音/爆音实战案例)人生格言人生从来没有捷径只有行动才是治疗恐惧和懒惰的唯一良药.更多原创,欢迎关注Android系统攻城狮文章目录1.前言2.应用场景和用法2.1处理不足最小样本数的尾部数据2.2函数原型与状态变化3.调用流程剖析3.1设置硬性最小值状态3.2强制处理时选择丢弃或交给子类4.实战案例4.1准备测试编码器4.2观察子类收到的数据4.3完整代码5.总结1.前言本篇目的理解gst_audio_encoder_set_hard_min()如何控制GstAudioEncoder在强制处理尾部数据时是否把不足最小样本数的数据交给编码器子类。编码器子类可以通过gst_audio_encoder_set_frame_samples_min()声明每次处理至少需要多少个样本。正常编码时如果累积数据还没达到这个下限基类会继续等待。到了EOS等需要排空数据的时机剩余数据可能仍然不足最小样本数。gst_audio_encoder_set_hard_min()决定这时如何处理启用后基类会跳过子类的handle_frame()丢弃这段尾部数据未启用时子类可能收到不足下限的数据。否是是否编码器子类设置最小样本数基类累积输入音频是否进入强制处理继续等待足够样本hard_min是否启用基类丢弃不足下限的尾部数据子类处理剩余数据2.应用场景和用法2.1处理不足最小样本数的尾部数据gst_audio_encoder_set_hard_min()适用于每次编码必须满足固定样本数的编码器。例如编码器每帧要求1024个样本而流结束时只剩下300个样本。场景hard_min设置EOS处理时的行为编码器支持短帧FALSE子类可以收到不足最小值的尾部数据编码器要求固定帧长TRUE基类跳过子类处理并丢弃尾部数据输入尚未结束任意值未进入强制处理时基类继续等待达到最小值启用该选项会丢失不足最小样本数的尾部音频。只有编码格式或子类实现确实不能处理短帧时才适合启用。2.2函数原型与状态变化函数原型如下voidgst_audio_encoder_set_hard_min(GstAudioEncoder*enc,gboolean enabled);参数含义enc已创建的GstAudioEncoder对象enabled是否启用硬性最小样本数处理该函数没有返回值。调用时会先检查enc是否为有效的GstAudioEncoder对象再通过对象锁更新私有字段hard_min。初始值为FALSE。最小调用方式如下/* 编码器不接受短帧时启用硬性最小样本数 */gst_audio_encoder_set_hard_min(GST_AUDIO_ENCODER(encoder),TRUE);它与相邻接口的职责不同接口职责gst_audio_encoder_set_frame_samples_min()设置子类每次至少需要的样本数gst_audio_encoder_set_hard_min()决定强制处理时如何处理不足下限的剩余数据gst_audio_encoder_get_hard_min()查询当前硬性最小值处理状态gst_audio_encoder_finish_frame()提交子类产生的编码数据及其对应样本数hard_min不会设置帧长也不会改变最小样本数。它只影响基类进入强制处理路径后的分支。3.调用流程剖析3.1设置硬性最小值状态gst_audio_encoder_set_hard_min()本身只更新一个布尔字段不会立即处理音频Buffer。voidgst_audio_encoder_set_hard_min(GstAudioEncoder*enc,gboolean enabled){g_return_if_fail(GST_IS_AUDIO_ENCODER(enc));GST_OBJECT_LOCK(enc);enc-priv-hard_minenabled;GST_OBJECT_UNLOCK(enc);}设置状态的过程是检查传入对象是否为GstAudioEncoder。获取对象锁更新enc-priv-hard_min。释放对象锁并返回。基类初始化时hard_min默认为FALSE。因此如果编码器子类没有主动设置尾部数据会沿默认处理策略进入后续流程。传入编码器和enabled检查GstAudioEncoder对象获取对象锁更新priv hard_min释放对象锁并返回3.2强制处理时选择丢弃或交给子类正常输入过程中基类会把输入数据放入Adapter并根据frame_samples_min判断是否满足子类要求。如果可用样本不足且当前没有强制处理基类会退出这轮处理等待更多输入。EOS等需要排空数据的路径会调用gst_audio_encoder_drain()再通过gst_audio_encoder_push_buffers()强制处理剩余数据。此时如果剩余样本仍然不足最小值基类会设置内部force状态。处理分支如下if(priv-forcepriv-hard_minbuf){retgst_audio_encoder_finish_frame(enc,NULL,-1);}else{retklass-handle_frame(enc,buf);}当force和hard_min同时为真且存在剩余Buffer时基类直接调用gst_audio_encoder_finish_frame()处理这段剩余数据不再调用子类的handle_frame()。这就是硬性最小值模式下丢弃不足下限尾部数据的路径。如果hard_min为FALSE上述条件不成立子类的handle_frame()会收到剩余Buffer。子类是否能正确编码短帧取决于自身实现和编码格式要求。是否是否EOS触发排空基类强制处理剩余数据剩余数据达到最小值调用子类handle_framehard_min是否启用基类跳过子类并丢弃尾部子类接收不足下限的数据4.实战案例4.1准备测试编码器下面的测试编码器把最小样本数设为4个样本/声道。测试输入为S16立体声格式每个音频Frame包含左右声道各一个样本。测试时只提交3个Frame也就是每声道3个样本。普通输入阶段还达不到4个样本因此子类不会立即收到数据。随后发送EOS基类开始强制排空。程序分别测试hard_minTRUE和hard_minFALSE两种情况。4.2观察子类收到的数据测试子类在handle_frame()中记录调用次数和输入Buffer大小hard_minTRUE时EOS排空阶段由基类丢弃不足下限的尾部子类的处理次数保持为0。hard_minFALSE时子类收到12字节输入也就是3个S16立体声Frame。这里的Demo用于观察GstAudioEncoder的分支行为不实现真实音频压缩算法。4.3完整代码#includegst/gst.h#includegst/audio/audio.h#includegst/check/gstharness.htypedefstruct_HardMinEncoder{GstAudioEncoder parent;guint handle_calls;gsize last_input_bytes;}HardMinEncoder;typedefstruct_HardMinEncoderClass{GstAudioEncoderClass parent_class;}HardMinEncoderClass;G_DEFINE_TYPE(HardMinEncoder,hard_min_encoder,GST_TYPE_AUDIO_ENCODER);staticGstStaticPadTemplate encoder_sink_templateGST_STATIC_PAD_TEMPLATE(sink,GST_PAD_SINK,GST_PAD_ALWAYS,GST_STATIC_CAPS(audio/x-raw));staticGstStaticPadTemplate encoder_src_templateGST_STATIC_PAD_TEMPLATE(src,GST_PAD_SRC,GST_PAD_ALWAYS,GST_STATIC_CAPS(audio/x-test-custom));staticgbooleanhard_min_encoder_set_format(GstAudioEncoder*enc,GstAudioInfo*info){GstCaps*caps;/* 子类需要每声道至少4个样本再设置测试用输出Caps */gst_audio_encoder_set_frame_samples_min(enc,4);capsgst_caps_new_empty_simple(audio/x-test-custom);gst_audio_encoder_set_output_format(enc,caps);gst_caps_unref(caps);returnTRUE;}staticGstFlowReturnhard_min_encoder_handle_frame(GstAudioEncoder*enc,GstBuffer*input){HardMinEncoder*self(HardMinEncoder*)enc;GstBuffer*output;/* 记录基类是否把尾部输入交给了子类 */self-handle_calls;if(inputNULL)returnGST_FLOW_OK;self-last_input_bytesgst_buffer_get_size(input);/* 测试编码器只输出一个字节不代表真实压缩算法 */outputgst_buffer_new_allocate(NULL,1,NULL);/* 输入包含3个立体声Frame即每声道3个样本 */returngst_audio_encoder_finish_frame(enc,output,3);}staticvoidhard_min_encoder_class_init(HardMinEncoderClass*klass){GstElementClass*element_classGST_ELEMENT_CLASS(klass);GstAudioEncoderClass*encoder_classGST_AUDIO_ENCODER_CLASS(klass);gst_element_class_add_static_pad_template(element_class,encoder_sink_template);gst_element_class_add_static_pad_template(element_class,encoder_src_template);gst_element_class_set_metadata(element_class,HardMinEncoder,Encoder/Audio,Test hard minimum handling,Example);encoder_class-set_formathard_min_encoder_set_format;encoder_class-handle_framehard_min_encoder_handle_frame;}staticvoidhard_min_encoder_init(HardMinEncoder*self){}staticGstStaticPadTemplate harness_src_templateGST_STATIC_PAD_TEMPLATE(harness-src,GST_PAD_SRC,GST_PAD_ALWAYS,GST_STATIC_CAPS(audio/x-raw));staticGstStaticPadTemplate harness_sink_templateGST_STATIC_PAD_TEMPLATE(harness-sink,GST_PAD_SINK,GST_PAD_ALWAYS,GST_STATIC_CAPS(audio/x-test-custom));typedefstruct{guint handle_calls;gsize input_bytes;}TestResult;staticTestResultrun_case(gboolean hard_min){GstElement*element;GstHarness*harness;GstBuffer*input;HardMinEncoder*encoder;TestResult result{0,0};/* 创建编码器并设置本次测试的硬性最小值开关 */elementg_object_new(hard_min_encoder_get_type(),NULL);gst_audio_encoder_set_hard_min(GST_AUDIO_ENCODER(element),hard_min);harnessgst_harness_new_full(element,harness_src_template,sink,harness_sink_template,src);gst_object_unref(element);/* 配置S16立体声输入采样率为48000Hz */gst_harness_set_src_caps(harness,gst_caps_new_simple(audio/x-raw,format,G_TYPE_STRING,S16LE,rate,G_TYPE_INT,48000,channels,G_TYPE_INT,2,layout,G_TYPE_STRING,interleaved,NULL));/* 输入3个Frame每个Frame为左右声道各一个S16样本 */inputgst_buffer_new_allocate(NULL,3*2*sizeof(gint16),NULL);g_assert_cmpint(gst_harness_push(harness,input),,GST_FLOW_OK);/* EOS使基类强制处理Adapter中不足4个样本的尾部 */g_assert(gst_harness_push_event(harness,gst_event_new_eos()));encoder(HardMinEncoder*)harness-element;result.handle_callsencoder-handle_calls;result.input_bytesencoder-last_input_bytes;gst_harness_teardown(harness);returnresult;}intmain(intargc,char*argv[]){TestResult hard_result;TestResult soft_result;gst_init(argc,argv);hard_resultrun_case(TRUE);soft_resultrun_case(FALSE);/* 启用hard_min后尾部被基类丢弃子类没有收到handle_frame调用 */g_assert_cmpuint(hard_result.handle_calls,,0);/* 未启用hard_min时子类收到3个立体声Frame共12字节 */g_assert_cmpuint(soft_result.handle_calls,,1);g_assert_cmpuint(soft_result.input_bytes,,12);return0;}5.总结gst_audio_encoder_set_hard_min()用于控制GstAudioEncoder在强制排空时如何处理不足最小样本数的尾部数据启用后基类会跳过子类并丢弃这段数据。

相关新闻

【基于 Swoole+Hyperf 的微服务实战】第九周·周四:实现订单服务并通过网关聚合下单接口

【基于 Swoole+Hyperf 的微服务实战】第九周·周四:实现订单服务并通过网关聚合下单接口

【基于 SwooleHyperf 的微服务实战】第九周周四:实现订单服务并通过网关聚合下单接口今天我们进入第九周周四,核心目标是 实现订单服务并通过网关聚合下单接口,完成从客户端到订单、库存、商品服务的全链路贯通。昨天我们已经有了商品和库存服…

2026/10/12 13:22:17 阅读更多 →
Hyperf Translation 国际化组件实战指南:语言文件、占位符与复数规则的完整实现

Hyperf Translation 国际化组件实战指南:语言文件、占位符与复数规则的完整实现

后端微服务 【免费下载链接】hyperf 🚀 A coroutine framework that focuses on hyperspeed and flexibility. Building microservice or middleware with ease. 项目地址: https://gitcode.com/gh_mirrors/hy/hyperf 点击查看 免费下载 Hyperf 的翻译&…

2026/10/12 8:32:55 阅读更多 →
ORA-01623 无法删除redo

ORA-01623 无法删除redo

这个是线程2的redo,当前环境是单机,关闭线程2即可删除关闭集群模式(重启生效) ALTER SYSTEM SET cluster_databaseFALSE SCOPESPFILE;关闭线程2(如果可以直接关闭) ALTER DATABASE DISABLE THREAD 2;

2026/10/12 13:22:49 阅读更多 →

最新新闻

多智能体电梯群控:基于目的楼层预约与PPO的深度强化学习实现

多智能体电梯群控:基于目的楼层预约与PPO的深度强化学习实现

简介:本资源是一套面向计算机、人工智能、自动化等专业学生的毕业设计与课程设计实践项目,聚焦于多智能体协同下的电梯群控优化问题,采用深度强化学习实现目的楼层预约调度算法,解决传统电梯响应延迟高、能耗大、乘客等待时间长等…

2026/10/13 19:14:30 阅读更多 →
语义分割环境搭建:PyTorch CPU与GPU版本安装及验证全攻略

语义分割环境搭建:PyTorch CPU与GPU版本安装及验证全攻略

1. 系列前情回顾与本期核心目标语义分割学习系列写到第四篇,前面几篇我分别梳理了语义分割的基本概念、常见数据集的组织方式、以及几个主流分割模型的结构差异。按照正常的学习路线,理论铺垫到这一步,接下来就该动手了。动手的第一步就是装环…

2026/10/13 19:14:30 阅读更多 →
Spring Boot配置绑定实战:@ConfigurationProperties原理与避坑

Spring Boot配置绑定实战:@ConfigurationProperties原理与避坑

接触Spring Boot这些年,我做得最多的一个动作就是替同事定位“配置不生效”的诡异问题。排查到最后,十有八九都落在同一个注解上——ConfigurationProperties。它看起来只是给配置类加个前缀声明,实际牵扯到数据绑定、松散命名、第三方注册、…

2026/10/13 19:14:30 阅读更多 →
语义分割必备:PyTorch CPU/GPU版本安装全攻略

语义分割必备:PyTorch CPU/GPU版本安装全攻略

废话不多说,直接进入正题。这一篇是这个系列的第四篇,主题是很多人在语义分割学习中绕不过去的第一道坎——CPU和GPU版本的PyTorch及其环境安装。前几篇我们聊了语义分割的数据标注、模型结构、评价指标,但真正动手跑代码的时候,你…

2026/10/13 19:14:29 阅读更多 →
Java核心知识点全解析:从JVM到并发编程的底层原理

Java核心知识点全解析:从JVM到并发编程的底层原理

做Java开发这些年,我有一个很深的感受:真正拉开水平差距的,不是谁背的框架更多、API记得更熟,而是对底层那批核心知识点有没有吃透。所谓“Java重要知识点”,不是让你背八股文,而是帮你在遇到线上问题时&am…

2026/10/13 19:14:29 阅读更多 →
Go监听MySQL binlog实战:轻量级数据变更捕获与生产避坑指南

Go监听MySQL binlog实战:轻量级数据变更捕获与生产避坑指南

1. 这不是“监听MySQL”,而是重建一套轻量级数据变更管道很多人第一次看到“用Go监听binlog”这个说法,第一反应是:“MySQL自己不就有mysqlbinlog命令吗?再不济写个Python脚本调用一下不就完了?”——我试过&#xff0…

2026/10/13 19:13:29 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →