0

J'écris du code pour décompresser un flux H.264 natif de l'annexe B, et je suis en train d'analyser le flux, de créer une CMVideoFormatDescription à partir des NALU SPS/PPS, et d'envelopper le autres NALUs que j'extrais du flux dans CMSampleBuffers.Propriété CMBlockBuffer dans CMSampleBuffer

Je souffre d'un blocage mental sur la façon de gérer la mémoire CMBlockBuffer et CMSampleBuffer pour le décodeur. Je crois que mon problème est plus un manque de compréhension approfondie de la façon dont les FC traitent la mémoire que toute autre chose, alors ma question est vraiment plus à ce sujet, mais j'espère que le contexte est utile.

Si je crée un CMBlockBuffer comme ceci:

CMBlockBufferRef blockBuffer; 

OSStatus status = CMBlockBufferCreateWithMemoryBlock(NULL, 
                memoryBlock,      
                blockBufferLength, 
                kCFAllocatorNull, 
                NULL, 
                0, 
                blockBufferLength,   
                kCMBlockBufferAlwaysCopyDataFlag | kCMBlockBufferAssureMemoryNowFlag, 
                &blockBuffer); 

et l'ajouter à un CMSampleBuffer comme ceci:

CMSampleBufferRef sampleBuffer; 

status = CMSampleBufferCreate(kCFAllocatorDefault, 
           blockBuffer, 
           true, 
           NULL, 
           NULL, 
           formatDescription, 
           1, 
           0, 
           NULL, 
           1, 
           &sampleSize, 
           &sampleBuffer); 

Comment dois-je gérer la mémoire tampon de bloc? Est-ce que le SampleBuffer conserve la mémoire du tampon de bloc, ou dois-je faire quelque chose pour m'assurer qu'il n'est pas libéré?

En ce qui concerne le processus de décodage asynchrone, y a-t-il un moyen judicieux de savoir quand le décodeur est fait avec le CMSampleBuffer pour que je puisse en disposer? Mon intuition me dit que le CMSampleBuffer conserverait le CMBlockBuffer, et que le VTDecodeSession conserverait le CMSampleBuffer jusqu'à ce qu'il ait terminé le décodage, mais c'est un territoire non documenté dans lequel je suis en train d'errer pour trouver une direction. Les résultats que j'obtiens impliquent que mon intuition pourrait être fausse, donc j'ai besoin d'exclure la gestion de la mémoire comme problème pour garder ma santé mentale ...

Répondre

1

CMSampleBuffers et CMBlockBuffers - les objets eux-mêmes - suivent la sémantique typique CF Retain/Release. Vous devez conserver une conservation tant que vous avez besoin de ces objets et supposer que les interfaces qui les acceptent font de même. Cela signifie que vous êtes libre de libérer le CMBlockBuffer dès que vous le transmettez à un CMSampleBuffer, et vous êtes libre de libérer le CMSampleBuffer après l'avoir transmis dans la chaîne de rendu.

La mémoire pointée par un CMBlockBuffer créé avec CMBlockBufferCreateWithMemoryBlock() suit des règles légèrement différentes. Premièrement, cette méthode ne copie pas les données pointées par memoryBlock; il utilise directement ce pointeur. Cela signifie que le BlockBuffer doit avoir une certaine connaissance de la façon dont cette mémoire doit être gérée. Ceci est géré par le quatrième ou le cinquième argument de CMBlockBufferCreateWithMemoryBlock(): si l'un ou l'autre est non-kCFAllocatorNull/NULL, le BlockBuffer appellera le deallocator de l'un de ceux quand il aura fini avec la mémoire. Ceci est typiquement fait dans Finalize() du BlockBuffer. Si elles sont toutes les deux kCFAllocatorNull/NULL (que vous avez dans votre extrait de code), le BlockBuffer laissera simplement tomber le pointeur sur le sol quand c'est fait avec de la mémoire. Cela signifie que si vous créez un CMBlockBuffer en utilisant CMBlockBufferCreateWithMemoryBlock() et avez l'intention de libérer votre retainBuffer après le passage dans le pipeline de rendu, vous devez utiliser des arguments non-NULL pour l'allocator/deallocators afin que la mémoire puisse être récupéré plus tard. Les implémentations de ces allocateurs/désallocateurs, bien sûr, dépendent de l'origine du memoryBlock.

+0

Merci, ceci est utile. Donc, si j'utilise malloc pour allouer le CMBlockBuffer, quelle serait la bonne valeur d'allocateur? –

+0

Une note supplémentaire, je l'ai fait fonctionner, mais j'ai découvert qu'une autre structure de données transmise à VTDecompressionSessionCreate, la CMVideoFormatDescription, ne semble pas être copiée par la session, et je devais m'assurer que je tenais sur ce bloc aussi bien avoir un accident. Le plantage de ces conditions apparaît dans l'assembly de la routine CFEqual, et si vous regardez un niveau, vous voyez qu'il essayait de lire la CMVideoFormatDescription à ce moment-là. –

+1

La documentation de kCFAllocatorMalloc indique qu'il utilise malloc, realloc et free. Si je devais suivre cette route, cependant, j'utiliserais probablement le même allocateur allouer la mémoire directement plutôt que de supposer que mon appel à malloc() correspondait à l'appel de l'allocateur à free(). Semble plus sûr et plus explicite/plus facile à comprendre, même si la documentation prétend qu'ils sont identiques. – DSaracino