Я пишу приложение для iPhone, где мне нужно захватить звук с микрофона и передать его потоковому серверу в формате AAC. Поэтому я сначала фиксирую звук, а затем используюЯ застрял между утечкой памяти или чрезмерным статическим звуком в аудио во время захвата звука с микрофона
AudioConverterFillComplexBuffer
метод преобразования аудио в AAC.
Ниже приведен код
- (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
NSArray *audioChannels = connection.audioChannels;
if (audioChannels == nil || [audioChannels count]==0) {
// NSLog(@"We have Video Frame");
[_encoder encodeFrame:sampleBuffer];
}else{
// NSLog(@"We have Audio Frame");
if (hasAudio) {
CMTime prestime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
double dPTS = (double)(prestime.value)/prestime.timescale;
[self getAudioBufferDataFromCMSampleBufferRef:sampleBuffer];
// describe output data buffers into which we can receive data.
AudioBufferList outputBufferList;
outputBufferList.mNumberBuffers = 1;
outputBufferList.mBuffers[0].mNumberChannels = _aacASBD.mChannelsPerFrame;
outputBufferList.mBuffers[0].mDataByteSize = _aacBufferSize;
outputBufferList.mBuffers[0].mData = _aacBuffer;
OSStatus st = AudioConverterFillComplexBuffer(_converter, &putPcmSamplesInBufferList, (__bridge void *) self, &_numOutputPackets, &outputBufferList, NULL);
if (0 == st) {
[_rtsp onAudioData:_aacBuffer :outputBufferList.mBuffers[0].mDataByteSize :dPTS];
}else{
NSLog(@"Error converting Buffer");
NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:st userInfo:nil];
NSLog([self OSStatusToStr :st]);
char * str = new char[3];
FormatError(str, st);
}
if (_blockBuffer) // Double check that what you are releasing actually exists!
{
CFRelease(_blockBuffer);
}
}
}
Код для getAudioBufferDataFromCMSampleBufferRef как ниже
- (AudioBuffer) getAudioBufferDataFromCMSampleBufferRef: (CMSampleBufferRef)audioSampleBuffer{
AudioBufferList audioBufferList;
OSStatus err = CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(audioSampleBuffer, NULL, &audioBufferList, sizeof(audioBufferList), NULL, NULL, 0, &_blockBuffer);
AudioBuffer audioBuffer ;
if (!err && _blockBuffer && audioBufferList.mBuffers[0].mData && (audioBufferList.mBuffers[0].mDataByteSize > 0))
{
for(int y=0; y<audioBufferList.mNumberBuffers; y++)
{
audioBuffer = audioBufferList.mBuffers[y];
break;
}
}
inputBuffer.mData=audioBuffer.mData;
inputBuffer.mDataByteSize=audioBuffer.mDataByteSize;
inputBuffer.mNumberChannels=1;
return audioBuffer;
}
В приведенной выше версии кода я получаю сообщение об ошибке BAD_ACCESS. Если вместо этого я удаляю код, который освобождает blockBuffer, происходит утечка памяти, и приложение в конечном итоге завершается из-за давления памяти.
Если я не сохранить blockBuffer и написать код
getAudioBufferDataFromCMSampleBufferRef
по-разному, как указано ниже
- (AudioBuffer) getAudioBufferDataFromCMSampleBufferRef: (CMSampleBufferRef)audioSampleBuffer
{
_blockBuffer = CMSampleBufferGetDataBuffer(audioSampleBuffer);
int audioBufferByteSize = CMSampleBufferGetTotalSampleSize(audioSampleBuffer);
CMBlockBufferCopyDataBytes(_blockBuffer,0,audioBufferByteSize,inputBuffer.mData);
inputBuffer.mDataByteSize=audioBuffer.mDataByteSize;
inputBuffer.mNumberChannels=1;
}
В этой версии blockbuffer не не сохраняется, так нет необходимости, чтобы освободить его. Однако теперь я получаю ужасную статичность в аудио.
У кого-нибудь есть идея, как решить эту проблему?
Спасибо, Ozgur
Во второй (альтернативной) реализации getAudioBufferDataFromCMSampleBufferRef я использовал CMBlockBufferCopyDataBytes (_blockBuffer, 0, audioBufferByteSize, inputBuffer.mData); чтобы скопировать blockBuffer в свой собственный буфер inputBuffer.mData. Однако в этом случае в звуке присутствует сильная статичность. inputBuffer имеет тип AudioBuffer. Вы хоть представляете, как я могу избавиться от статики? – ozguronur
Является ли ваш собственный буфер замкнутым кольцевым буфером в несколько раз больше, чем один AudioBuffer? Если нет, вы можете перезаписать данные, прежде чем закончите использовать их. – hotpaw2
Это путь, особенно если данные кодируются. Кодексу потребуется определенное количество кадров для каждого пакета. Если осталось недостаточно образцов для завершения пакета, то AudioConverterFillComplexBuffer должен выйти из строя, а затем свернуть оставшиеся образцы в следующий пакет, если в вашем буфере больше образцов. – dave234