iOS Core Audio:如何将双声道AudioBufferList拆分为单声道双Buffer?
音频格式转换实现方案(交错16位PCM → 非交错浮点PCM)
原输入格式参数
mFormatID = kAudioFormatLinearPCM, mFormatFlags = 14, mChannelsPerFrame = 2, mBytesPerPacket = 4, mFramesPerPacket = 1, mBytesPerFrame = 4, mBitsPerChannel = 16, mSampleRate = 44100
原数据为双声道交错式16位有符号整数PCM,对应AudioBufferList仅包含1个Buffer,双声道数据交替存储。目标需转换为双声道非交错式32位浮点PCM,对应AudioBufferList包含2个Buffer,每个Buffer仅存单声道数据,以此匹配流会话enqueueAudioBuffer的要求。
核心转换步骤与代码实现
1. 计算关键参数并初始化目标AudioBufferList
从原CMSampleBuffer提取AudioBufferList,计算总帧数后分配目标结构内存:
// 你的输入样本Buffer CMSampleBufferRef sampleBuffer = ...; AudioBufferList *inputABL = (AudioBufferList *)CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer( sampleBuffer, NULL, NULL, 0, NULL, NULL, kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment, NULL ); // 计算总帧数:原数据总字节数 / 每帧字节数 UInt32 totalFrames = inputABL->mBuffers[0].mDataByteSize / inputABL->mBuffers[0].mBytesPerFrame; // 每个声道的浮点数据字节数:帧数 * Float32字节数 UInt32 perChannelByteSize = totalFrames * sizeof(Float32); // 初始化目标AudioBufferList AudioBufferList *outputABL = (AudioBufferList *)malloc(sizeof(AudioBufferList) + sizeof(AudioBuffer) * 1); outputABL->mNumberBuffers = 2; // 左声道Buffer outputABL->mBuffers[0].mNumberChannels = 1; outputABL->mBuffers[0].mDataByteSize = perChannelByteSize; outputABL->mBuffers[0].mData = malloc(perChannelByteSize); // 右声道Buffer outputABL->mBuffers[1].mNumberChannels = 1; outputABL->mBuffers[1].mDataByteSize = perChannelByteSize; outputABL->mBuffers[1].mData = malloc(perChannelByteSize);
2. 执行交错整数到非交错浮点的转换
遍历每帧数据,拆分左右声道并完成格式转换:
// 原数据指针转为16位有符号整数类型 int16_t *inputData = (int16_t *)inputABL->mBuffers[0].mData; // 目标左右声道浮点指针 Float32 *leftChannelData = (Float32 *)outputABL->mBuffers[0].mData; Float32 *rightChannelData = (Float32 *)outputABL->mBuffers[1].mData; for (UInt32 i = 0; i < totalFrames; i++) { // 交错数据中,左声道是第2i个整数,右声道是第2i+1个整数 int16_t leftInt = inputData[2 * i]; int16_t rightInt = inputData[2 * i + 1]; // 将16位整数转为-1.0~1.0范围的浮点值 leftChannelData[i] = leftInt / 32768.0f; rightChannelData[i] = rightInt / 32768.0f; }
3. 资源释放与后续处理
转换完成后传入流会话处理,使用完毕后释放内存:
// 传入流会话处理 [yourStreamSession enqueueAudioBuffer:outputABL atPresentationTime:presentationTime]; // 释放分配的内存 free(outputABL->mBuffers[0].mData); free(outputABL->mBuffers[1].mData); free(outputABL); CFRelease(inputABL);
杂音原因说明
原数据为双声道交错存储,若直接以非交错格式解析,或未完成整数到浮点的格式转换,会导致音频数据被错误解析(比如将两个16位整数当成一个32位浮点值),最终产生杂音。上述转换严格匹配目标格式要求,可解决声道不匹配问题。
内容的提问来源于stack exchange,提问作者Juan Gil
相关产品推荐
相关产品推荐

