ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Linux Gstreamer深度解析之gst_audio_ring_buffer_convert调用流程与实战(八十一)

Linux Gstreamer深度解析之gst_audio_ring_buffer_convert调用流程与实战(八十一)

简介: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从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数据,也不执行重采样。

源单位和值

gst_audio_ring_buffer_convert

RingBuffer中的GstAudioInfo

按采样率和BPF换算

目标单位和值或失败状态

🌻2.应用场景和用法

2.1处理音频单位换算

原始音频常用三种单位描述位置或长度:

单位含义示例
GST_FORMAT_DEFAULT原始音频Frame数48000个Frame
GST_FORMAT_BYTESPCM数据字节数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内存。

传入RingBuffer与单位参数

获取对象锁

读取spec中的GstAudioInfo

调用音频信息换算

释放对象锁并返回结果

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、时间和字节换算

示例执行两次换算:

  1. 将48000个Frame转换为时间,结果应为GST_SECOND。
  2. 将半秒转换为字节数,结果应为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转换或重采样。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进