尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Linux Gstreamer深度解析之gst_audio_ring_buffer_prepare_read调用流程与实战(七十四)
简介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准备测试用RingBuffer4.2读取当前分段并推进位置4.3完整代码5.总结1.前言本篇目的理解gst_audio_ring_buffer_prepare_read()如何根据RingBuffer当前位置返回分段索引、数据指针和长度并通过实战观察回调填充与分段推进。GstAudioRingBuffer把音频数据组织成多个固定大小的分段。设备子类需要取得当前分段的地址和长度再把数据交给设备读写。gst_audio_ring_buffer_prepare_read()负责定位分段并返回这组信息它本身不搬运音频数据也不推进分段计数。已采集的RingBuffergst_audio_ring_buffer_prepare_read定位当前分段返回分段地址和长度设备子类处理数据2.应用场景和用法2.1音频设备如何取得当前分段gst_audio_ring_buffer_prepare_read()主要供音频设备子类使用。播放端取得RingBuffer中的一段音频再交给设备写入录音端取得目标分段再让设备把采集到的数据写入该区域。调用者通常先确认RingBuffer已采集并拥有有效内存再调用该接口取得当前分段。设备处理完一个分段后调用gst_audio_ring_buffer_advance()推进完成计数。下一次调用会据此定位新的分段。如果RingBuffer没有设置填充回调函数要求状态已经是GST_AUDIO_RING_BUFFER_STATE_STARTED。设置了回调时函数会调用回调填充本次返回的分段内存。2.2参数、返回值与相邻接口函数原型如下gbooleangst_audio_ring_buffer_prepare_read(GstAudioRingBuffer*buf,gint*segment,guint8**readptr,gint*len);参数含义buf已采集并包含有效分段内存的RingBuffersegment输出参数返回当前分段编号readptr输出参数返回当前分段的内存地址len输出参数返回当前分段的字节数返回TRUE表示分段信息已写入输出参数。返回FALSE通常表示没有填充回调且RingBuffer尚未启动。无论是否设置回调buf、segment、readptr和len都必须有效RingBuffer内存也必须存在。readptr指向RingBuffer内部内存调用者不能释放它。函数返回的len是字节数不是Frame数。相邻接口的分工如下接口职责gst_audio_ring_buffer_set_callback()设置分段填充回调gst_audio_ring_buffer_prepare_read()定位当前分段并返回内存地址和长度gst_audio_ring_buffer_advance()记录设备已处理的分段数gst_audio_ring_buffer_read()从RingBuffer读取指定样本位置的数据3.调用流程剖析3.1根据分段计数计算地址函数先检查buf是否为有效RingBuffer。如果没有设置callback它还会检查状态是否为GST_AUDIO_RING_BUFFER_STATE_STARTED未启动时直接返回FALSE。通过检查后函数读取原子变量segdone用它和spec.segtotal计算当前分段*segmentsegdone%buf-spec.segtotal;*lenbuf-spec.segsize;*readptrbuf-memory*segment**len;segdone表示已经完成处理的分段累计数。取模后得到环形缓冲区中的当前分段编号。分段地址则由RingBuffer起始地址、分段编号和每段字节数共同确定。读取segdone对segtotal取模得到当前segment计算readptr和len3.2回调填充与分段推进如果设置了callback函数会在计算出readptr和len后直接调用该回调if(buf-callback)buf-callback(buf,*readptr,*len,buf-cb_data);回调拿到的是当前分段地址和字节数可以在这块内存中填入音频数据。该调用发生在gst_audio_ring_buffer_prepare_read()返回之前。函数不会在内部递增segdone。设备子类完成一个分段的处理后需调用gst_audio_ring_buffer_advance()更新计数。下一次调用prepare_read()再根据新的计数定位分段。GstAudioSink和GstAudioSrc的处理循环都使用该接口取得分段内存。Sink从分段中读取数据并写入音频设备Src把设备读出的数据写入分段。实际设备读写由各自的设备回调完成。4.实战案例4.1准备测试用RingBuffer下面创建一个内存后端RingBuffer子类。它不连接真实音频设备打开操作直接成功采集操作分配一块内存。RingBuffer包含4个分段每段16字节填充回调会把当前分段写成0x5A。该示例重点观察prepare_read()返回的分段编号、地址、长度和回调效果。4.2读取当前分段并推进位置测试按以下步骤执行创建RingBuffer并设置4段、每段16字节的规格。打开和采集RingBuffer资源再设置分段填充回调。调用prepare_read()检查首段编号为0、长度为16字节且首字节被回调写为0x5A。调用gst_audio_ring_buffer_advance()推进一个分段再次调用prepare_read()检查分段编号变为1地址移动16字节。这组检查可以确认prepare_read()根据segdone定位分段并同步调用填充回调分段计数由advance()单独推进。4.3完整代码#includegst/gst.h#includegst/audio/audio.h#includestring.htypedefstruct_TestRingBuffer{GstAudioRingBuffer parent;}TestRingBuffer;typedefstruct_TestRingBufferClass{GstAudioRingBufferClass parent_class;}TestRingBufferClass;G_DEFINE_TYPE(TestRingBuffer,test_ring_buffer,GST_TYPE_AUDIO_RING_BUFFER);/* 模拟设备打开不连接真实硬件 */staticgbooleantest_open_device(GstAudioRingBuffer*buf){returnTRUE;}/* 为测试RingBuffer分配分段内存 */staticgbooleantest_acquire(GstAudioRingBuffer*buf,GstAudioRingBufferSpec*spec){buf-sizespec-segsize*spec-segtotal;buf-memoryg_malloc0(buf-size);returnTRUE;}/* 释放测试后端申请的内存 */staticgbooleantest_release(GstAudioRingBuffer*buf){g_free(buf-memory);buf-memoryNULL;buf-size0;returnTRUE;}/* 模拟设备关闭 */staticgbooleantest_close_device(GstAudioRingBuffer*buf){returnTRUE;}/* 填充prepare_read返回的当前分段 */staticvoidfill_segment(GstAudioRingBuffer*buf,guint8*data,guint len,gpointer user_data){guint*callback_countuser_data;(*callback_count);memset(data,0x5A,len);}staticvoidtest_ring_buffer_class_init(TestRingBufferClass*klass){GstAudioRingBufferClass*ring_buffer_classGST_AUDIO_RING_BUFFER_CLASS(klass);ring_buffer_class-open_devicetest_open_device;ring_buffer_class-acquiretest_acquire;ring_buffer_class-releasetest_release;ring_buffer_class-close_devicetest_close_device;}staticvoidtest_ring_buffer_init(TestRingBuffer*ring_buffer){}intmain(intargc,char*argv[]){TestRingBuffer*test_buffer;GstAudioRingBuffer*ring_buffer;GstAudioRingBufferSpec*spec;gint segment-1;gint len0;guint8*readptrNULL;guint callback_count0;gboolean openedFALSE;gboolean acquiredFALSE;gboolean okFALSE;gst_init(argc,argv);test_bufferg_object_new(test_ring_buffer_get_type(),NULL);ring_bufferGST_AUDIO_RING_BUFFER(test_buffer);specring_buffer-spec;/* 设置测试规格分段大小为16字节总计4段 */memset(spec,0,sizeof(*spec));gst_audio_info_init(spec-info);if(!gst_audio_info_set_format(spec-info,GST_AUDIO_FORMAT_S16,48000,2,NULL))gotodone;spec-typeGST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW;spec-segsize16;spec-segtotal4;spec-seglatency-1;/* prepare_read需要RingBuffer已经打开并采集资源 */if(!gst_audio_ring_buffer_open_device(ring_buffer))gotodone;openedTRUE;if(!gst_audio_ring_buffer_acquire(ring_buffer,spec))gotodone;acquiredTRUE;/* 设置回调验证每次prepare_read都会填充当前段 */gst_audio_ring_buffer_set_callback(ring_buffer,fill_segment,callback_count);if(!gst_audio_ring_buffer_prepare_read(ring_buffer,segment,readptr,len))gotodone;/* 首次读取应定位第0段回调写入0x5A */if(segment!0||len!16||readptr!ring_buffer-memory||readptr[0]!0x5A||callback_count!1)gotodone;/* 模拟设备处理完一段再检查环形位置向前移动 */gst_audio_ring_buffer_advance(ring_buffer,1);if(!gst_audio_ring_buffer_prepare_read(ring_buffer,segment,readptr,len))gotodone;oksegment1len16readptrring_buffer-memory16readptr[0]0x5Acallback_count2;done:/* 先移除回调再释放其使用的栈上计数器 */if(ring_buffer)gst_audio_ring_buffer_set_callback(ring_buffer,NULL,NULL);if(acquired)gst_audio_ring_buffer_release(ring_buffer);if(opened)gst_audio_ring_buffer_close_device(ring_buffer);if(ring_buffer)gst_object_unref(ring_buffer);returnok?0:1;}5.总结gst_audio_ring_buffer_prepare_read()根据segdone返回当前分段的内存地址和长度并在设置了填充回调时同步填充该分段但不会自行推进分段计数。
RELATED

相关推荐

【机器学习案列-45】基于 XGBoost 的鲍鱼年龄预测

【机器学习案列-45】基于 XGBoost 的鲍鱼年龄预测

🧑 博主简介:曾任某智慧城市类企业算法总监,目前在美国市场的物流公司从事高级算法工程师一职,深耕人工智能领域,精通python数据挖掘、可视化、机器学习等,发表过AI相关的专利并多次在AI类比赛中获奖。CSDN人工智能领域的优质创作者,提供AI相关的技术咨询、项目开发和个…

📅 2026/10/14 21:05:54
智能问数 ChatBI:让每个人都能用自然语言分析数据

智能问数 ChatBI:让每个人都能用自然语言分析数据

过去,业务人员想查询销售额、客户数量或转化率,往往需要向数据团队提需求,再等待开发报表。ChatBI 将自然语言、大语言模型和传统 BI 结合起来,让用户可以直接通过对话完成数据查询、指标分析和图表生成。 文章目录一、什么是 Cha…

📅 2026/10/14 21:05:54
AI论文写作工具实测:专业派与灵感型如何组合使用?

AI论文写作工具实测:专业派与灵感型如何组合使用?

谁再说AI论文写作软件只能拿来“代写”,我第一个不同意。过去这半年,我陆续帮几位写作小白朋友试了两类风格完全不同的AI写作工具:一类走专业论文写作工具的路线,强调结构、模板和格式;另一类主打灵感激发,…

📅 2026/10/14 21:05:54
MORE NEWS

更多资讯

📰

AI专利撰写与布局实战:从可专利性判断到权利要求避坑指南

1. 当“AI专利”四个字摆在面前,真正该拆解的是什么 “AI专利”这个标题乍一看像是一个宏大叙事,但真正落到实操层面,它其实指向一个非常具体的问题: 当一项技术成果同时具备“人工智能”和“可专利性”两个属性时,从…

📰

Tcl脚本驱动FPGA工程自动化:从创建到编译全流程实战

1. 为什么要用Tcl脚本搭建易灵思工程:从痛点说起做FPGA开发有一段时间的朋友,大概率都经历过这种场景:明明只是改了一个引脚约束,结果打开工程GUI,等它加载完,点开约束编辑器,翻半天找到那行配置…

📰

Qt5.13 TCP服务端与客户端开发实战:信号槽与粘包处理

简介:一份基于 QT5.13.0 的 TCP 通信完整示例,面向初学 Qt 网络编程的开发者,用于理解服务端与客户端的建立、多客户端接入以及聊天消息的收发,既适合课程设计参考,也能作为入职前 Qt 网络模块的练手项目。资源内置可运…

📰

论文降重还在同义词替换?Okbiye 带你避开学术双重检测的坑

每年毕业季,总有一批同学在最后关头翻车:查重率降下来了,结果 AIGC 检测却亮起红灯;AI 痕迹消除了,语句又变得生硬不通顺。如今高校普遍实行 "查重 AIGC" 双重审核,单纯靠同义词替换降重的老方法…

📰

AI专利实战指南:从技术方案到专利布局的完整流程

1. 从“AI 专利”这个标题说起:它到底在聊什么“AI 专利”这四个字,乍一看像是一个法律或者知识产权话题,但真正在一线做技术、做产品的人看到它,脑子里浮现的往往不是法条,而是一连串非常具体的问题:我做的…

📰

KKSwarm多机协同框架实践:从架构选型到部署避坑

简介:开源机器人集群项目KKSwarm由易科机器人实验室与阿木实验室联合打造,面向机器人研究者、开发者及高校学生,提供一套基于开源理念的多机器人协同工作系统。项目涵盖群体通信、协调、导航与任务分配等核心技术,适用于工业生产、…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬