Mam dziwny "wyciek" pamięci z AVAssetWriterInput appendSampleBuffer
. Piszę wideo i audio w tym samym czasie, więc mam jeden AVAssetWriter
z dwoma wejściami, jeden dla wideo i jeden dla audio:appendSampleBuffer z dźwiękiem AVAssetWriterInput "wycieka" pamięć do czasu zakończenia endSessionAtSourceTime
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];
zacznę pisać i wszystko działa poprawnie na powierzchni. Wideo i audio uzyskać pisemną i są wyrównane, itd. Jednak Kładę kodu za pośrednictwem instrumentu Allocations i zauważył, co następuje:
Bajty audio są coraz zachowane w pamięci, a ja udowodnię za sekundę. To wzrost w pamięci. Bajty audio są wydawane dopiero po wywołaniu [self.videoWriter endSessionAtSourceTime:...]
, co można uznać za dramatyczny spadek wykorzystania pamięci. Tu jest mój kodu pisanie dźwięku, które jest wysyłane jako blok na kolejce szeregowego:
@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);
}
Jak widać, jestem zwalniając każdy bufor raz utworzyć. Mam prześledzić „przeciek” do linii, gdzie bufory audio załączonym:
[self.audioWriterInput appendSampleBuffer:sampleBuffer]
udowodniłem to sobie przez zakomentowanie tę linię, po której pojawia się następujący „leak-free” przydziały wykres (mimo że nagrany film ma teraz żadnego dźwięku teraz, oczywiście):
próbowałem jedną rzecz, która ma dodać z powrotem linię appendSamplebuffer
i zamiast podwójnego uwalniania blockBuffer2
:
CFRelease(blockBuffer1);
CFRelease(blockBuffer2);
CFRelease(blockBuffer2); // Double release to test the hypothesis that appendSamplebuffer is retaining this
CFRelease(sampleBuffer);
Spowoduje to zrobił nie przyczyną podwójnie za darmo, wskazując, że blockBuffer2
„s zachować liczyć w tym momencie jest 2. produkowane wykres same«szczelny»przydziałów, z tą różnicą, że gdy zadzwoniłem [self.videoWriter endSessionAtSourceTime:...]
, Wystąpił błąd z podwójnego wydania (wskazując, że self.videoWriter
próbuje zwolnić wszystkie swoje wskaźniki do blockBuffer2
s, które zostały przekazane).
Jeśli zamiast tego spróbuj wykonać następujące czynności:
CFRelease(blockBuffer1);
CFRelease(blockBuffer2);
CMSampleBufferInvalidate(sampleBuffer); // Invalidate sample buffer
CFRelease(sampleBuffer);
następnie [self.audioWriterInput appendSampleBuffer:sampleBuffer]
i wezwanie do dołączania klatki wideo rozpocznie się niepowodzeniem dla każdej rozmowy po tym.
Mój wniosek jest taki, że AVAssetWriter
lub AVAssetWriterInput
zachowuje blockBuffer2
, dopóki film nie zakończy nagrania. Oczywiście może to powodować problemy z pamięcią rzeczywistą, jeśli nagranie trwa wystarczająco długo. czy robię coś źle?
Edytuj: Bajt audio, który otrzymuję, jest w formacie PCM, natomiast format wideo, który piszę, to MPEG4, a format audio tego filmu to MPEG4AAC. Czy jest możliwe, że program zapisujący wideo wykonuje w locie format PCM -> AAC, i dlatego jest buforowany?
Jestem pewien, że rozejrzałeś się, ale widziałeś te dwa pytania/odpowiedzi. Mogą być pomocne/powiązane. 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
Dzięki za sugestie @JSuar. Próbowałem już pierwszego, ale wywołanie CMSampleBufferInvalidate wydaje się łamać wszystkie przyszłe zapisy do twórcy filmów. Drugi wygląda interesująco, ale nie jestem pewien, czy współbieżne lub kolejki szeregowe wytłumaczyłyby "wyciek" pamięci, który wydaje się być spowodowany nagrywaniem wideo bloków audio. – kevlar
Czy to możliwe, że po prostu piszesz dźwięk znacznie szybciej niż wideo, więc musi być buforowany, aby zachować prawidłowe przeplatanie? –