我一直在使用AVAssetReader读取音频资产,以便稍后我可以使用带有AudioUnit回调的AUGraph来播放音频。我有AUGraph和AudioUnit回调工作但它从磁盘读取文件,如果文件太大,它将占用太多内存并使应用程序崩溃。所以我反而直接阅读资产,只是有限的尺寸。然后我将它作为双缓冲区进行管理,并在需要时获得AUGraph所需的内容。
(注意:我很想知道我是否可以使用音频队列服务并仍使用带有AudioUnit回调的AUGraph,因此iOS框架可以为我管理内存。)
我的问题是我对C中的数组,结构和指针没有很好的理解。我需要帮助的部分是将单个AudioBufferList保存到单个AudioBuffer并将该数据添加到另一个AudioBufferList中。以后要使用的所有数据。我相信我需要使用memcpy,但不清楚如何使用它,甚至为我的目的初始化AudioBufferList。我使用MixerHost作为参考,这是Apple的示例项目,它从磁盘读取文件。
如果您想在Xcode中加载它,我已经上传了我正在进行的工作。我已经找到了完成这项工作所需的大部分内容,一旦我将数据收集到一个地方,我就应该好好去。
示例项目:MyAssetReader.zip
在标题中,您可以看到我将bufferList声明为指向结构的指针。
@interface MyAssetReader : NSObject {
BOOL reading;
signed long sampleTotal;
Float64 totalDuration;
AudioBufferList *bufferList; // How should this be handled?
}
然后我用这种方式分配bufferList,主要是借用MixerHost ......
UInt32 channelCount = [asset.tracks count];
if (channelCount > 1) {
NSLog(@"We have more than 1 channel!");
}
bufferList = (AudioBufferList *) malloc (
sizeof (AudioBufferList) + sizeof (AudioBuffer) * (channelCount - 1)
);
if (NULL == bufferList) {NSLog (@"*** malloc failure for allocating bufferList memory"); return;}
// initialize the mNumberBuffers member
bufferList->mNumberBuffers = channelCount;
// initialize the mBuffers member to 0
AudioBuffer emptyBuffer = {0};
size_t arrayIndex;
for (arrayIndex = 0; arrayIndex < channelCount; arrayIndex++) {
// set up the AudioBuffer structs in the buffer list
bufferList->mBuffers[arrayIndex] = emptyBuffer;
bufferList->mBuffers[arrayIndex].mNumberChannels = 1;
// How should mData be initialized???
bufferList->mBuffers[arrayIndex].mData = malloc(sizeof(AudioUnitSampleType));
}
最后,我循环阅读。
int frameCount = 0;
CMSampleBufferRef nextBuffer;
while (assetReader.status == AVAssetReaderStatusReading) {
nextBuffer = [assetReaderOutput copyNextSampleBuffer];
AudioBufferList localBufferList;
CMBlockBufferRef blockBuffer;
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(nextBuffer, NULL, &localBufferList, sizeof(localBufferList), NULL, NULL,
kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment, &blockBuffer);
// increase the number of total bites
bufferList->mBuffers[0].mDataByteSize += localBufferList.mBuffers[0].mDataByteSize;
// carefully copy the data into the buffer list
memcpy(bufferList->mBuffers[0].mData + frameCount, localBufferList.mBuffers[0].mData, sizeof(AudioUnitSampleType));
// get information about duration and position
//CMSampleBufferGet
CMItemCount sampleCount = CMSampleBufferGetNumSamples(nextBuffer);
Float64 duration = CMTimeGetSeconds(CMSampleBufferGetDuration(nextBuffer));
Float64 presTime = CMTimeGetSeconds(CMSampleBufferGetPresentationTimeStamp(nextBuffer));
if (isnan(duration)) duration = 0.0;
if (isnan(presTime)) presTime = 0.0;
//NSLog(@"sampleCount: %ld", sampleCount);
//NSLog(@"duration: %f", duration);
//NSLog(@"presTime: %f", presTime);
self.sampleTotal += sampleCount;
self.totalDuration += duration;
frameCount++;
free(nextBuffer);
}
我不确定我处理mDataByteSize和mData的内容,特别是对于memcpy。由于mData是一个空指针,因此这是一个额外棘手的区域。
memcpy(bufferList->mBuffers[0].mData + frameCount, localBufferList.mBuffers[0].mData, sizeof(AudioUnitSampleType));
在这一行中我认为应该将localBufferList中数据的值复制到bufferList中的位置加上将指针放在应该写入数据的位置的帧数。关于我需要改变什么以使其发挥作用,我有几个想法。
目前,当我运行此应用程序时,它使用无效的bufferList指针结束此函数。
感谢您帮助我更好地了解如何管理AudioBufferList。
答案 0 :(得分:3)
我想出了自己的答案。我决定使用一个NSMutableData对象,它允许我在调用CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer之后从CMSampleBufferRef中追加Bin来获取AudioBufferList。
[data appendBytes:localBufferList.mBuffers[0].mData length:localBufferList.mBuffers[0].mDataByteSize];
读取循环完成后,我的NSMutableData对象中包含了所有数据。然后我以这种方式创建并填充AudioBufferList。
audioBufferList = (AudioBufferList *)malloc(sizeof(AudioBufferList));
if (NULL == audioBufferList) {
NSLog (@"*** malloc failure for allocating audioBufferList memory");
[data release];
return;
}
audioBufferList->mNumberBuffers = 1;
audioBufferList->mBuffers[0].mNumberChannels = channelCount;
audioBufferList->mBuffers[0].mDataByteSize = [data length];
audioBufferList->mBuffers[0].mData = (AudioUnitSampleType *)malloc([data length]);
if (NULL == audioBufferList->mBuffers[0].mData) {
NSLog (@"*** malloc failure for allocating mData memory");
[data release];
return;
}
memcpy(audioBufferList->mBuffers[0].mData, [data mutableBytes], [data length]);
[data release];
我很感激我对如何使用malloc创建结构并填充它进行了一些代码审查。我偶尔会收到EXC_BAD_ACCESS错误,但我无法确定错误的位置。因为我在struct上使用malloc,所以我不应该在任何地方保留它。我称之为“free”来释放struct中的子元素,最后是我使用malloc的结构本身。