Я работал над чтением аудиоустройства с использованием AVAssetReader, чтобы позже я мог воспроизвести аудио с помощью AUGraph с обратным вызовом AudioUnit. У меня работает обратный вызов AUGraph и AudioUnit, но он читает файлы с диска, и если файл слишком большой, он будет занимать слишком много памяти и вылетать из приложения. Поэтому я вместо этого читаю актив напрямую и только в ограниченном размере. Затем я буду управлять им как двойным буфером и получу AUGraph то, что ему нужно, когда это нужно.
(Примечание: я хотел бы знать, могу ли я использовать Audio Queue Services и все еще использовать AUGraph с обратным вызовом AudioUnit, чтобы память управлялась для меня фреймворками 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 плюс количество кадров для позиционирования указателя, куда следует записывать данные. У меня есть пара идей о том, что мне нужно изменить, чтобы заставить это работать.
- Так как указатель void равен 1, а не размеру указателя для AudioUnitSampleType, мне может понадобиться умножить его также на sizeof (AudioUnitSampleType), чтобы получить memcpy в правильном положении
- Возможно, я не использую malloc должным образом для подготовки mData, но так как я не уверен, сколько будет кадров, я не уверен, что делать для его инициализации
В настоящее время, когда я запускаю это приложение, оно завершает эту функцию с неверным указателем для bufferList.
Я ценю вашу помощь, помогающую мне лучше понять, как управлять AudioBufferList.