我一直在使用AVAssetReader讀取音頻資產,以便稍後可以使用帶有AudioUnit回調的AUGraph播放音頻。我有AUGraph和AudioUnit回調工作,但它從磁盤讀取文件,如果文件太大,它會佔用太多內存並導致應用程序崩潰。所以我直接閱讀資產,只有有限的尺寸。然後,我將把它作爲一個雙緩衝區來管理,並在需要時獲得AUGraph所需的內容。如何使用AVAssetReader添加到AudioBufferList?
(注:我很想知道我是否可以使用音頻隊列服務,並仍然使用與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位置加上幀的數量的數據的值,將指針在它應該寫入數據的位置。我對我需要改變的一些想法有所瞭解。
- 由於空指針僅僅是1,而不是指針的AudioUnitSampleType我可能需要通過的sizeof(AudioUnitSampleType)也乘以它的大小來獲得的memcpy到正確的位置
- 我可能不使用malloc妥善準備MDATA但因爲我不知道有多少幀會有我不知道做初始化
什麼目前,當我運行這個程序,結束該功能與bufferList無效指針。
感謝您的幫助,讓我更好地理解如何管理AudioBufferList。
我一直在學習更多關於void指針,以及如何使用malloc和memcpy,這似乎是理解AudioBufferList結構的關鍵部分。我需要知道一種方法來將值保存到C中的一個動態數組中。我正在閱讀的這些功能可能已添加到C99中。我正在繼續閱讀它。 – Brennan 2011-04-11 08:09:09
我在想,我會積累從AudioBuffer到一個數組與ralloc增長,但我可以做到這一點與100塊,所以realloc不會與每次迭代調用。然後我可以在循環之後創建一個動態調整大小的數組,使用memcpy使用累加值填充該數組,然後使用該數組在緩衝區上設置mData。 – Brennan 2011-04-11 08:21:42