appendicsamplebuffer avec une mémoire audio AVAssetWriterInput "leaks" jusqu'à la finsessionats sourcetime
j'ai un étrange fuite de mémoire" avec AVAssetWriterInput appendSampleBuffer
. J'écris vidéo et audio en même temps, donc j'en ai un AVAssetWriter
avec deux entrées, une pour la vidéo et un pour l'audio:
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];
je commence à écrire et tout fonctionne bien sur la surface. La vidéo et l'audio s'écrivent et sont alignés, etc. Cependant, j'ai mis mon code dans L'instrument des Allocations et j'ai remarqué ce qui suit:
les octets audio sont retenus mémoire, comme je le prouverai dans une seconde. C'est la montée en puissance de la mémoire. Les octets audio ne sont libérés qu'après que j'ai appelé [self.videoWriter endSessionAtSourceTime:...]
, que vous voyez comme la chute dramatique dans l'utilisation de la mémoire. Voici mon code d'écriture audio, qui est envoyé comme un bloc sur une file d'attente série:
@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);
}
comme vous pouvez le voir, je libère chaque tampon une fois par création. J'ai tracé la "fuite" jusqu'à la ligne où les tampons audio sont ajoutés:
[self.audioWriterInput appendSampleBuffer:sampleBuffer]
je me le suis prouvé en commentant que line, après quoi j'obtiens le graphique D'Allocations "sans fuite" suivant (bien que la vidéo enregistrée n'ait plus de son maintenant, bien sûr):
j'ai essayé une autre chose, qui est de rajouter de la appendSamplebuffer
ligne et au lieu de double-release blockBuffer2
:
CFRelease(blockBuffer1);
CFRelease(blockBuffer2);
CFRelease(blockBuffer2); // Double release to test the hypothesis that appendSamplebuffer is retaining this
CFRelease(sampleBuffer);
en Faisant cela n' cause un double-free, indiquant que blockBuffer2
conserver compter à ce point est de 2. Cela a produit le même" répartition graphique, à l'exception que lorsque j'ai appelé [self.videoWriter endSessionAtSourceTime:...]
, j'obtiens un crash d'une double libération (indiquant que self.videoWriter
essaie de libérer tous ses pointeurs à l' blockBuffer2
s qui ont été passés).
Si au lieu de cela, j'ai essayer le code suivant:
CFRelease(blockBuffer1);
CFRelease(blockBuffer2);
CMSampleBufferInvalidate(sampleBuffer); // Invalidate sample buffer
CFRelease(sampleBuffer);
[self.audioWriterInput appendSampleBuffer:sampleBuffer]
et l'appel pour ajouter des images vidéo commencent à échouer pour chaque appel après que.
Donc ma conclusion est que AVAssetWriter
ou AVAssetWriterInput
est en conservant blockBuffer2
jusqu'à ce que la vidéo a terminé l'enregistrement. Évidemment, cela peut causer de vrais problèmes de mémoire si la vidéo enregistre assez longtemps. Suis-je en train de faire quelque chose de mal?
Edit: les octets audio que je reçois sont en format PCM, alors que le format vidéo que j'écris est MPEG4 et le format audio pour cette vidéo est MPEG4AAC. Est-il possible que le rédacteur de vidéo exécute le format PCM --> AAC à la volée, et c'est pour cela qu'il est tamponné?
1 réponses
puisque vous attendez depuis un mois une réponse, je vais vous donner une réponse Moins qu'idéale mais réalisable.
vous pouvez utiliser les fonctions ExtendedAudioFile pour écrire un fichier séparé. Ensuite, vous pouvez simplement lire la vidéo et l'audio avec un AVComposition. Je pense que vous pourriez être en mesure d'utiliser AVFoundation pour composer le caf et la vidéo ensemble sans réencodage si vous avez besoin d'eux compostés à la fin de l'enregistrement.
cela vous permettra de sortir et de courir, ensuite, vous pouvez résoudre la fuite de mémoire à votre guise.