Ich habe einen seltsamen Speicher "Leck" mit AVAssetWriterInput appendSampleBuffer
. Ich schreibe Video und Audio in der gleichen Zeit, also habe ich ein AVAssetWriter
mit zwei Eingängen, eine für Video und einen für Audio:appendSampleBuffer mit einem audio AVAssetWriterInput "leckt" Speicher bis EndeSessionAtSourceTime
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];
Ich fange an zu schreiben und alles funktioniert auf der Oberfläche in Ordnung. Die Video- und Audio erhalten geschrieben und ausgerichtet sind, usw. Aber ich meinen Code durch die Zuteilungen Instrument setzen und bemerkte folgendes:
Die Audio-Bytes werden immer in Erinnerung behalten, wie ich beweisen werde in einer Sekunde. Das ist die Steigerung in Erinnerung. Die Audio-Bytes werden nur freigegeben, nachdem ich [self.videoWriter endSessionAtSourceTime:...]
aufrufen, die Sie als den dramatischen Rückgang der Speichernutzung sehen. Hier ist mein Audio-Schreiben von Code, der als Block auf eine serielle Warteschlange geschickt wird:
@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);
}
Wie Sie sehen, ich bin Loslassen jeden Puffer einmal pro erstellen. Ich habe das „Leck“ bis auf die Linie verfolgt, wo der Audio-Puffer angehängt werden:
[self.audioWriterInput appendSampleBuffer:sampleBuffer]
ich dies, dass die Linie durch Kommentare aus mir bewiesen, nach dem ich die folgenden „leckagefrei“ Belegungen Graph erhalten (obwohl das aufgezeichnete Video jetzt keinen Ton hat jetzt natürlich):
ich habe versucht, eine andere Sache, die die appendSamplebuffer
Zeilen hinzufügen zurück ist und stattdessen Doppelrelease blockBuffer2
:
CFRelease(blockBuffer1);
CFRelease(blockBuffer2);
CFRelease(blockBuffer2); // Double release to test the hypothesis that appendSamplebuffer is retaining this
CFRelease(sampleBuffer);
diese tat Doing nicht Ursache ein zwei frei, was darauf hinweist, dass blockBuffer2
‚s Zahl an diesem Punkt 2. Dies hat die gleichen‚leckagefrei‘Zuteilungen Graph erzeugt wird beibehalten, mit der Ausnahme, dass, wenn ich rief [self.videoWriter endSessionAtSourceTime:...]
, bekomme ich einen Absturz von einem Doppel-Release (zeigt an, dass self.videoWriter
versucht, alle seine Zeiger auf die blockBuffer2
s, die übergeben wurden) zu veröffentlichen.
Wenn stattdessen versuche ich folgendes:
CFRelease(blockBuffer1);
CFRelease(blockBuffer2);
CMSampleBufferInvalidate(sampleBuffer); // Invalidate sample buffer
CFRelease(sampleBuffer);
dann [self.audioWriterInput appendSampleBuffer:sampleBuffer]
und der Anruf Video-Frames zu anhängen beginnen für jeden Anruf danach zum Scheitern verurteilt.
Also meine Schlussfolgerung ist, dass AVAssetWriter
oder AVAssetWriterInput
blockBuffer2
behält, bis das Video die Aufnahme beendet hat. Offensichtlich kann dies zu echten Speicherproblemen führen, wenn das Video lange genug aufnimmt. Mache ich etwas falsch?
Bearbeiten: Die Audio-Bytes, die ich bekomme, sind PCM-Format, während das Video-Format, das ich schreibe, MPEG4 ist und das Audio-Format für dieses Video ist MPEG4AAC. Ist es möglich, dass der Video-Brenner das PCM -> AAC-Format im laufenden Betrieb ausführt, und deshalb wird es gepuffert?
Ich bin sicher, du hast dich umgesehen, aber hast du diese zwei Fragen/Antworten gesehen? Sie könnten hilfreich sein. 1) http://stackoverflow.com/questions/4914853/help-fix-memory-leak-release 2) http://stackoverflow.com/questions/11274652/performance-issues-when-using-avcapturevideodataoutput-and-avcaptureaudiatout – JSuar
Danke für die Vorschläge @JSuar. Ich habe bereits das erste versucht, aber das Aufrufen von CMSampleBufferInvalidate scheint alle zukünftigen Schreibvorgänge in den Video-Writer zu bringen. Die zweite sieht interessant aus, aber ich bin mir nicht sicher, ob gleichzeitige oder serielle Warteschlangen das "Speicherleck" des Speichers erklären würden, das durch das Schreiben der Audioblöcke verursacht wird. – kevlar
Ist es möglich, dass Sie das Audiomaterial viel schneller schreiben als das Video, so dass es gepuffert werden muss, damit das Interleave korrekt bleibt? –