简介:CSDN博客专家、《Android系统多媒体进阶实战》作者
博主新书推荐:《Android系统多媒体进阶实战》🚀
Android Audio工程师专栏地址:Audio工程师进阶系列【原创干货持续更新中……】🚀
Android多媒体专栏地址:多媒体系统工程师系列【原创干货持续更新中……】🚀
专题一 二:AAOS车载系统+AOSP14系统攻城狮入门视频实战课🚀
专题三:Android14 Binder之HIDL与AIDL通信实战课🚀
专题四:Android15快速自定义与集成音效实战课🚀
专题五:Android15音频策略实战课🚀
专题六:Android15音频性能实战课(无声/杂音/断音/爆音实战案例)🚀
人生格言:人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
🍉🍉🍉文章目录🍉🍉🍉
- 🌻1.前言
- 🌻2.应用场景和用法
- 2.1处理音频单位换算
- 2.2函数原型与返回语义
- 🌻3.调用流程剖析
- 3.1从RingBuffer读取音频信息
- 3.2底层按采样率和BPF换算
- 🌻4.实战案例
- 4.1准备RingBuffer音频信息
- 4.2执行Frame、时间和字节换算
- 4.3完整代码
- 🌻5.总结
🌻1.前言
本篇目的:理解
gst_audio_ring_buffer_convert()如何依据RingBuffer中的音频格式信息换算时间、Frame和字节数,并通过示例观察不同单位之间的转换关系。
音频元素需要响应GST_QUERY_CONVERT,把调用方提供的一个数值从源单位换算为目标单位。gst_audio_ring_buffer_convert()读取GstAudioRingBuffer中的GstAudioInfo,完成单位换算并返回结果。它只转换数值,不转换PCM数据,也不执行重采样。
🌻2.应用场景和用法
2.1处理音频单位换算
原始音频常用三种单位描述位置或长度:
| 单位 | 含义 | 示例 |
|---|---|---|
GST_FORMAT_DEFAULT | 原始音频Frame数 | 48000个Frame |
GST_FORMAT_BYTES | PCM数据字节数 | 192000字节 |
GST_FORMAT_TIME | 时间长度 | 1秒 |
对于S16LE双声道音频,每个采样点占2字节,每个Frame包含两个声道,因此BPF为4。采样率为48000Hz时,48000个Frame对应1秒,也对应192000字节。
gst_audio_ring_buffer_convert()可用于音频Sink响应格式换算查询。应用或上游元素发起GST_QUERY_CONVERT后,GstAudioBaseSink会从查询中取出源格式和值,调用该接口;换算成功时,再把目标格式和值写回查询。
2.2函数原型与返回语义
gbooleangst_audio_ring_buffer_convert(GstAudioRingBuffer*buf,GstFormat src_fmt,gint64 src_val,GstFormat dest_fmt,gint64*dest_val);| 参数 | 含义 |
|---|---|
buf | 提供音频格式信息的RingBuffer对象 |
src_fmt | 输入数值的单位 |
src_val | 输入数值 |
dest_fmt | 目标单位 |
dest_val | 接收换算结果的输出地址 |
函数会锁住buf,使用buf->spec.info中的采样率和BPF调用gst_audio_info_convert()。成功返回TRUE,失败返回FALSE。调用方必须传入有效的RingBuffer和dest_val地址。
原始音频中,GST_FORMAT_DEFAULT表示Frame数。支持的转换单位为GST_FORMAT_BYTES、GST_FORMAT_TIME和GST_FORMAT_DEFAULT。采样率或BPF尚未配置时,跨单位换算会失败;不支持的单位组合也会返回FALSE。
如果源单位和目标单位相同,或者src_val为-1,函数会把源值直接写入目标地址并返回成功。字节换算为Frame时会按整数除法处理,不能整除的尾部字节不会组成完整Frame。
相邻接口的职责不同:
| 接口 | 职责 |
|---|---|
gst_audio_ring_buffer_convert() | 基于RingBuffer中的音频信息换算数值单位 |
gst_audio_info_convert() | 执行采样率、BPF参与的底层单位换算 |
gst_query_parse_convert() | 从GST_QUERY_CONVERT中读取源单位和值 |
gst_query_set_convert() | 将换算后的目标单位和值写回查询 |
gst_audio_converter_samples() | 对PCM样本执行实际音频转换 |
🌻3.调用流程剖析
3.1从RingBuffer读取音频信息
gst_audio_ring_buffer_convert()本身没有复杂的格式分支。它先获取RingBuffer对象锁,再把buf->spec.info、源单位、源值、目标单位和输出地址传给gst_audio_info_convert(),最后释放对象锁并返回底层结果。
GST_OBJECT_LOCK(buf);res=gst_audio_info_convert(&buf->spec.info,src_fmt,src_val,dest_fmt,dest_val);GST_OBJECT_UNLOCK(buf);这里的GstAudioInfo提供换算所需的采样率和BPF。函数不会检查或改变RingBuffer是否正在采集,也不会访问环形缓冲区中的PCM内存。
3.2底层按采样率和BPF换算
底层换算函数根据源单位选择计算路径:
- Frame转时间:根据采样率换算。
- Frame转字节:Frame数乘以BPF。
- 字节转Frame:字节数除以BPF。
- 时间转Frame:根据采样率换算到整数Frame。
- 时间转字节:先换算成Frame,再乘以BPF。
例如,48kHz、S16LE双声道的音频中,48000个Frame可换算为1秒或192000字节。反向从字节数换算Frame时,如果字节数不是BPF的整数倍,余数字节会被舍去。
底层处理只接受受支持的单位组合。采样率或BPF为0时,跨单位转换失败;源、目标单位相同以及源值为-1则直接传递数值,不需要进行比例计算。
🌻4.实战案例
4.1准备RingBuffer音频信息
示例创建一个测试用的GstAudioRingBuffer子类,只用于承载GstAudioInfo,不连接声卡。音频格式设为48kHz、S16LE、双声道,因此每个Frame占4字节。
4.2执行Frame、时间和字节换算
示例执行两次换算:
- 将48000个Frame转换为时间,结果应为
GST_SECOND。 - 将半秒转换为字节数,结果应为96000字节。
这些计算只验证单位换算关系,不读取或改写PCM数据。
4.3完整代码
#include<gst/gst.h>#include<gst/audio/audio.h>typedefstruct_ConvertTestRingBuffer{GstAudioRingBuffer parent;}ConvertTestRingBuffer;typedefstruct_ConvertTestRingBufferClass{GstAudioRingBufferClass parent_class;}ConvertTestRingBufferClass;G_DEFINE_TYPE(ConvertTestRingBuffer,convert_test_ring_buffer,GST_TYPE_AUDIO_RING_BUFFER);staticvoidconvert_test_ring_buffer_class_init(ConvertTestRingBufferClass*klass){}staticvoidconvert_test_ring_buffer_init(ConvertTestRingBuffer*ring_buffer){}intmain(intargc,char*argv[]){ConvertTestRingBuffer*test_buffer;GstAudioRingBuffer*ring_buffer;GstAudioInfo*info;gint64 time_value=-1;gint64 byte_value=-1;gboolean frames_to_time;gboolean time_to_bytes;gboolean ok;gst_init(&argc,&argv);/* 创建测试RingBuffer,供换算接口读取音频信息 */test_buffer=g_object_new(convert_test_ring_buffer_get_type(),NULL);ring_buffer=GST_AUDIO_RING_BUFFER(test_buffer);info=&ring_buffer->spec.info;/* 设置48kHz、S16LE、双声道音频格式 */gst_audio_info_init(info);if(!gst_audio_info_set_format(info,GST_AUDIO_FORMAT_S16,48000,2,NULL)){gst_object_unref(ring_buffer);return1;}/* 将48000个Frame换算为时间,应得到1秒 */frames_to_time=gst_audio_ring_buffer_convert(ring_buffer,GST_FORMAT_DEFAULT,48000,GST_FORMAT_TIME,&time_value);/* 将半秒换算为字节,应得到96000字节 */time_to_bytes=gst_audio_ring_buffer_convert(ring_buffer,GST_FORMAT_TIME,GST_SECOND/2,GST_FORMAT_BYTES,&byte_value);/* 检查两次换算是否成功,并核对计算结果 */ok=frames_to_time&&time_value==GST_SECOND&&time_to_bytes&&byte_value==96000;gst_object_unref(ring_buffer);returnok?0:1;}🌻5.总结
gst_audio_ring_buffer_convert()根据RingBuffer保存的采样率和BPF换算音频单位数值,不执行PCM转换或重采样。