2013-02-13 5 views
18

У меня странная память «утечка» с AVAssetWriterInput appendSampleBuffer. Я пишу видео и аудио в то же время, так что у меня есть один AVAssetWriter с двумя входами, один для видео и один для аудио:appendSampleBuffer с аудио AVAssetWriterInput «утечка» памяти до концаSessionAtSourceTime

self.videoWriter = [[[AVAssetWriter alloc] initWithURL:[self.currentVideo currentVideoClipLocalURL] 
               fileType:AVFileTypeMPEG4 
               error:&error] autorelease]; 
... 
self.videoWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo 
                  outputSettings:videoSettings]; 
self.videoWriterInput.expectsMediaDataInRealTime = YES; 
[self.videoWriter addInput:self.videoWriterInput]; 
... 
self.audioWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio 
                  outputSettings:audioSettings]; 
self.audioWriterInput.expectsMediaDataInRealTime = YES; 
[self.videoWriter addInput:self.audioWriterInput]; 

Я начинаю писать и все работает отлично на поверхности. Видео и аудио пишутся и выровнены, и т.д. Тем не менее, я положил свой код через Отчисление инструмент и заметили следующее:

CoreMedia allocations

Аудио байт становятся сохраняются в памяти, как я докажу через секунду. Это наращивание памяти. Звуковые байты освобождаются только после того, как я вызываю [self.videoWriter endSessionAtSourceTime:...], что вы видите как резкое падение использования памяти. Вот мой аудио написание кода, который отправляется в виде блока на последовательной очереди:

@autoreleasepool 
{ 
    // The objects that will hold the audio data 
    CMSampleBufferRef sampleBuffer; 
    CMBlockBufferRef blockBuffer1; 
    CMBlockBufferRef blockBuffer2; 

    size_t nbytes = numSamples * asbd_.mBytesPerPacket; 

    OSStatus status = noErr; 
    status = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault, 
               data, 
               nbytes, 
               kCFAllocatorNull, 
               NULL, 
               0, 
               nbytes, 
               kCMBlockBufferAssureMemoryNowFlag, 
               &blockBuffer1); 

    if (status != noErr) 
    { 
     NLog(@"CMBlockBufferCreateWithMemoryBlock error at buffer 1"); 
     return; 
    } 

    status = CMBlockBufferCreateContiguous(kCFAllocatorDefault, 
              blockBuffer1, 
              kCFAllocatorDefault, 
              NULL, 
              0, 
              nbytes, 
              kCMBlockBufferAssureMemoryNowFlag | kCMBlockBufferAlwaysCopyDataFlag, 
              &blockBuffer2); 

    if (status != noErr) 
    { 
     NSLog(@"CMBlockBufferCreateWithMemoryBlock error at buffer 2"); 
     CFRelease(blockBuffer1); 
     return; 
    } 

    // Finally, create the CMSampleBufferRef 
    status = CMAudioSampleBufferCreateWithPacketDescriptions(kCFAllocatorDefault, 
                  blockBuffer2, 
                  YES, // Yes data is ready 
                  NULL, // No callback needed to make data ready 
                  NULL, 
                  audioFormatDescription_, 
                  1, 
                  timestamp, 
                  NULL, 
                  &sampleBuffer); 


    if (status != noErr) 
    { 
     NSLog(@"CMAudioSampleBufferCreateWithPacketDescriptions error."); 
     CFRelease(blockBuffer1); 
     CFRelease(blockBuffer2); 
     return; 
    } 

    if ([self.audioWriterInput isReadyForMoreMediaData]) 
    { 
     if (![self.audioWriterInput appendSampleBuffer:sampleBuffer]) 
     { 
      NSLog(@"Couldn't append audio sample buffer: %d", numAudioCallbacks_); 
     } 
    } else { 
     NSLog(@"AudioWriterInput isn't ready for more data."); 
    } 

    // One release per create 
    CFRelease(blockBuffer1); 
    CFRelease(blockBuffer2); 
    CFRelease(sampleBuffer); 
} 

Как вы можете видеть, я выпускаю каждый буфер один раз в создании. Я проследил «утечки» вниз к линии, где приложенном звуковые буферы:

[self.audioWriterInput appendSampleBuffer:sampleBuffer] 

Я доказал это себе, закомментировав эту строку, после чего я получаю «Герметичные» Отчисления график (хотя запись видео в настоящее время не имеет аудио теперь, конечно):

No leak

Я попробовал еще одну вещь, которая должна добавить обратно appendSamplebuffer строку и вместо двойной релиз blockBuffer2:

CFRelease(blockBuffer1); 
CFRelease(blockBuffer2); 
CFRelease(blockBuffer2); // Double release to test the hypothesis that appendSamplebuffer is retaining this 
CFRelease(sampleBuffer); 

Делать это сделал не причиной двойной свободной, указывая, что blockBuffer2 «ы сохранить счетчик в этой точке равно 2. Это произвело то же самое„утечки“свободные график отчислений, за исключением того, что, когда я звонил [self.videoWriter endSessionAtSourceTime:...], я получаю крах из двойного релиза (указывая, что self.videoWriter пытается освободить все свои указатели до blockBuffer2 s, которые были переданы).

Если вместо этого, я стараюсь следующее:

CFRelease(blockBuffer1); 
CFRelease(blockBuffer2); 
CMSampleBufferInvalidate(sampleBuffer); // Invalidate sample buffer 
CFRelease(sampleBuffer); 

затем [self.audioWriterInput appendSampleBuffer:sampleBuffer]и вызов для добавления видеокадры начнут разрушаться для каждого вызова после этого.

Таким образом, мой вывод состоит в том, что AVAssetWriter или AVAssetWriterInput сохраняет blockBuffer2, пока видео не закончит запись. Очевидно, что это может вызвать проблемы с реальной памятью, если видео записывается достаточно долго. Я делаю что-то неправильно?

Редактировать: Звуковые байты, которые я получаю, представляют собой формат PCM, тогда как формат видео, который я пишу, - MPEG4, а аудиоформат для этого видео - MPEG4AAC. Возможно ли, что видеозаписывающее устройство выполняет формат PCM -> AAC «на лету», и именно поэтому он получает буферизацию?

+0

Я уверен, что вы огляделись, но видели ли вы эти два вопроса/ответы. Они могут быть полезными/связанными. 1) http://stackoverflow.com/questions/4914853/help-fix-memory-leak-release 2) http://stackoverflow.com/questions/11274652/performance-issues-when-using-avcapturevideodataoutput-and-avcaptureaudiodataout – JSuar

+0

Спасибо за предложения @JSuar. Я уже пробовал первый, но вызов CMSampleBufferInvalidate, похоже, разбивает все будущие записи на автора видео. Второй выглядит интересным, но я не уверен, что параллельные или последовательные очереди объяснят «утечку» памяти, которая, по-видимому, вызвана видеозаписью, сохраняющей звуковые блоки. – kevlar

+0

Возможно ли, что вы просто записываете звук намного быстрее, чем видео, поэтому его нужно буферизовать, чтобы сохранить чередование правильно? –

ответ

1

Поскольку вы ждете ответа на месяц, я дам вам менее идеальный, но работоспособный ответ.

Вы можете использовать функции ExtendedAudioFile для записи отдельного файла. Затем вы можете просто воспроизвести видео и аудио вместе с AVComposition. Я думаю, вы могли бы использовать AVFoundation, чтобы комбинировать caf и видео вместе без перекодирования, если вам нужно, чтобы они были составлены в конце записи.

Это приведет вас в бегство, и вы сможете решить проблему утечки памяти на досуге.