)
简介CSDN博客专家、《Android系统多媒体进阶实战》作者博主新书推荐《Android系统多媒体进阶实战》Android Audio工程师专栏地址Audio工程师进阶系列【原创干货持续更新中……】Android多媒体专栏地址多媒体系统工程师系列【原创干货持续更新中……】专题一 二AAOS车载系统AOSP14系统攻城狮入门视频实战课专题三Android14 Binder之HIDL与AIDL通信实战课专题四Android15快速自定义与集成音效实战课专题五Android15音频策略实战课专题六Android15音频性能实战课(无声/杂音/断音/爆音实战案例)人生格言人生从来没有捷径只有行动才是治疗恐惧和懒惰的唯一良药.更多原创,欢迎关注Android系统攻城狮文章目录1.前言2.应用场景和用法2.1为Buffer描述音频布局2.2函数原型与参数语义3.调用流程剖析3.1复制音频信息并登记样本布局3.2音频映射接口读取Meta4.实战案例4.1准备双声道非交错音频Buffer4.2附加Meta并映射平面4.3完整代码5.总结1.前言本篇目的理解gst_buffer_add_audio_meta()如何把音频格式、有效样本数和声道平面偏移附加到GstBuffer并分析后续映射接口如何使用这些信息。GstBuffer提供一段音频数据的内存但仅凭Buffer总大小并不总能判断声道数据的布局。对于非交错音频左右声道分别位于不同的内存区域处理代码还需要知道每个平面从哪里开始以及其中包含多少有效样本。gst_buffer_add_audio_meta()把这些布局信息作为GstAudioMeta附加到可写Buffer上。它不搬运或转换音频样本也不负责分配Buffer数据内存。已分配音频数据的GstBuffergst_buffer_add_audio_metaGstAudioInfo和样本布局附加GstAudioMetagst_audio_buffer_map读取声道平面2.应用场景和用法2.1为Buffer描述音频布局GstAudioMeta主要用于携带单个Buffer内部的音频布局信息尤其是非交错音频场景Buffer数据布局Meta提供的信息非交错音频映射每个声道分别存放各声道平面的起始字节偏移零拷贝裁剪Buffer内存可能保留未使用区域有效样本数和各平面偏移声道重排不移动实际音频数据通过调整平面偏移描述声道次序下游音频处理不能仅从Buffer总大小推断有效数据量音频格式和有效样本数交错音频通常不需要附加GstAudioMeta。非交错音频则需要它配合gst_audio_buffer_map()使用才能正确映射各声道平面。2.2函数原型与参数语义函数原型如下GstAudioMeta*gst_buffer_add_audio_meta(GstBuffer*buffer,constGstAudioInfo*info,gsize samples,gsize offsets[]);参数含义buffer已经包含音频数据、且当前可写的GstBufferinfo音频格式、采样率、声道数和布局等信息samples每个声道平面中的有效样本数offsets非交错布局下各声道平面的字节偏移交错布局必须传NULL返回值是刚添加到Buffer上的GstAudioMeta由Buffer持有。调用者可以读取返回指针但不应单独释放它释放Buffer时Meta随Buffer一起释放。对于非交错布局offsets为NULL时函数按紧密连续的平面计算偏移offsets[channel] channel × samples × 每个样本的字节数如果提供了偏移各声道内存范围不能重叠也不能超出Buffer可访问的内存范围。调用前必须确保Buffer有足够空间。3.调用流程剖析3.1复制音频信息并登记样本布局函数首先检查Buffer、GstAudioInfo和布局参数是否合法然后调用gst_buffer_add_meta()把GstAudioMeta附加到Buffer。Meta中保存的info来自调用者传入的音频信息samples记录每个声道平面的有效样本数。对于非交错布局函数还会保存调用者给出的偏移或者按紧密排列规则生成默认偏移。启用了运行时检查时函数会检测声道平面之间是否重叠以及最后一个平面是否超出Buffer大小。检测到越界或重叠时它会移除刚添加的Meta并返回NULL。否是是否传入Buffer和音频信息检查对象格式与布局向Buffer添加GstAudioMeta复制info并记录samples是否为非交错布局返回Meta保存或计算平面偏移平面重叠或越界移除Meta并返回空指针该接口不会验证音频采样值本身是否正确也不会重新排列Buffer数据。它记录布局供后续处理代码解释内存。3.2音频映射接口读取Metagst_audio_buffer_map()会先查找Buffer上的GstAudioMeta。如果存在Meta映射接口会要求传入的音频布局与Meta中的布局一致并使用Meta里的info和samples描述映射结果。对于非交错音频映射结果包含多个声道平面每个平面对应一个声道的内存区域。没有Meta时音频映射接口只能按Buffer大小和BPF推导样本数而且要求布局为交错格式。因此gst_buffer_add_audio_meta()是布局描述接口gst_audio_buffer_map()是读取布局并建立可访问平面的接口两者职责不同。4.实战案例4.1准备双声道非交错音频Buffer本案例准备4个S16样本的左右声道数据。每个样本占2字节因此每个声道平面占8字节整个Buffer需要16字节。左右声道平面分别从字节偏移0和8开始。Buffer先分配并写入音频数据再附加Meta。4.2附加Meta并映射平面程序按以下顺序执行设置S16、44100Hz、双声道的GstAudioInfo并将布局改为非交错。分配16字节Buffer分别写入左声道和右声道样本。使用偏移0和8附加GstAudioMeta。调用gst_audio_buffer_map()检查有效样本数、平面数和声道首样本。每个声道平面都是8字节两个区间互不重叠也都位于16字节Buffer范围内。4.3完整代码#includegst/gst.h#includegst/audio/audio.h#includestring.hintmain(intargc,char*argv[]){GstAudioInfo info;GstBuffer*bufferNULL;GstAudioMeta*meta;GstAudioBuffer audio_buffer;GstMapInfo map;GstAudioChannelPosition positions[2]{GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT};gsize offsets[2]{0,8};gint16 left_samples[4]{100,200,300,400};gint16 right_samples[4]{500,600,700,800};gint16 first_left;gint16 first_right;gboolean audio_mappedFALSE;gint result1;gst_init(argc,argv);/* 设置双声道S16音频格式并指定声道分别存放 */gst_audio_info_init(info);if(!gst_audio_info_set_format(info,GST_AUDIO_FORMAT_S16,44100,2,positions))gotodone;info.layoutGST_AUDIO_LAYOUT_NON_INTERLEAVED;/* 每个声道4个样本每个样本2字节总容量为16字节 */buffergst_buffer_new_allocate(NULL,16,NULL);if(bufferNULL)gotodone;/* 将左右声道数据写入各自的连续内存平面 */if(!gst_buffer_map(buffer,map,GST_MAP_WRITE))gotodone;memcpy(map.data,left_samples,sizeof(left_samples));memcpy(map.dataoffsets[1],right_samples,sizeof(right_samples));gst_buffer_unmap(buffer,map);/* 为Buffer登记音频格式、样本数和左右声道偏移 */metagst_buffer_add_audio_meta(buffer,info,G_N_ELEMENTS(left_samples),offsets);if(metaNULL)gotodone;/* 按Meta中的平面布局映射音频数据 */if(!gst_audio_buffer_map(audio_buffer,info,buffer,GST_MAP_READ))gotodone;audio_mappedTRUE;if(audio_buffer.n_samples!4||audio_buffer.n_planes!2)gotodone;/* 通过平面指针读取左右声道的首个样本 */memcpy(first_left,audio_buffer.planes[0],sizeof(first_left));memcpy(first_right,audio_buffer.planes[1],sizeof(first_right));if(first_left!left_samples[0]||first_right!right_samples[0])gotodone;result0;done:/* 先结束映射再释放Meta所属的Buffer */if(audio_mapped)gst_audio_buffer_unmap(audio_buffer);if(buffer!NULL)gst_buffer_unref(buffer);returnresult;}5.总结gst_buffer_add_audio_meta()就是把音频格式、有效样本数和声道平面偏移附加到可写GstBuffer供后续音频映射和处理代码正确解释数据布局。