2016-11-29 16 views
0

Я пишу код для распаковки потокового потока H.264 нативного приложения B, и я просматриваю процесс разбора потока, создавая CMVideoFormatDescription из SALPS/PPS NALU и обертывая другие NALUs, которые я извлекаю из потока в CMSampleBuffers.Владение CMBlockBuffer в CMSampleBuffer

Я страдаю от умственного блока, как обращаться с памятью CMBlockBuffer и CMSampleBuffer для декодера. Я считаю, что моя проблема связана с недостаточным пониманием того, как CF обрабатывает память, чем что-либо еще, поэтому мой вопрос действительно об этом больше, но я надеюсь, что этот контекст будет полезен.

Если я создаю CMBlockBuffer так:

CMBlockBufferRef blockBuffer; 

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

и добавить его в CMSampleBuffer так:

CMSampleBufferRef sampleBuffer; 

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

Как я должен обрабатывать буфер блока? Сохраняет ли SampleBuffer память блочного буфера или мне нужно что-то сделать, чтобы убедиться, что он не освобожден?

Также, относящийся к процессу асинхронного декодирования, есть ли разумный способ узнать, когда декодер сделан с CMSampleBuffer, чтобы я мог избавиться от него?

Моя интуиция подсказывает мне, что CMSampleBuffer сохранит CMBlockBuffer, а VTDecodeSession сохранит CMSampleBuffer, пока не будет выполнено декодирование, но это недокументированная территория. Я блуждаю в таком поиске какого-то направления. Результаты, которые я получаю, подразумевают, что моя интуиция может быть неправильной, поэтому мне нужно исключить управление памятью как проблему, чтобы сохранить мое здравомыслие ...

ответ

1

CMSampleBuffers и CMBlockBuffers - сами объекты - следуют типичной семантике CF Retain/Release. Вы должны держать удержание, пока вам нужны эти объекты, и предположите, что интерфейсы, которые их принимают, делают то же самое. Это означает, что вы можете бесплатно освободить CMBlockBuffer, как только вы передадите его CMSampleBuffer, и вы можете освободить CMSampleBuffer после передачи его в цепочку рендеринга.

Память, на которую указывает CMBlockBuffer, созданная с помощью CMBlockBufferCreateWithMemoryBlock(), имеет несколько иные правила. Во-первых, этот метод не копирует данные, на которые указывает memoryBlock; он напрямую использует этот указатель. Это означает, что BlockBuffer должен иметь некоторое представление о том, как управлять этой памятью. Это обрабатывается либо четвертым, либо пятым аргументом для CMBlockBufferCreateWithMemoryBlock(): если они не являются kCFAllocatorNull/NULL, BlockBuffer будет вызывать дезактиватор одного из них, когда это делается с памятью. Обычно это делается в Finalize() BlockBuffer's. Если они оба kCFAllocatorNull/NULL (которые у вас есть в фрагменте кода), BlockBuffer просто поместит указатель на пол, когда это будет сделано с памятью.

Это означает, что если вы создадите CMBlockBuffer с помощью CMBlockBufferCreateWithMemoryBlock() и намереваетесь освободить вашу блокировку BlockBuffer после передачи ее вниз по конвейеру рендеринга, вы должны использовать аргументы, отличные от NULL, для распределителя/деаллокаторов, чтобы память могла быть позже восстановлен. Реализации этих распределителей/деаллокаторов, конечно, зависят от источника памяти.

+0

Спасибо, это полезно. Итак, если я использую malloc для выделения CMBlockBuffer, каково будет правильное значение распределителя? –

+0

Еще одно замечание: я получил это для работы, но я обнаружил, что другая структура данных, переданная VTDecompressionSessionCreate, CMVideoFormatDescription, кажется, не копируется сеансом, и мне нужно было убедиться, что я тоже держался на этом блоке, или я получить сбой. Авария для этих условий появляется в сборке в процедуре CFEqual, и если вы посмотрите на один уровень вверх, вы увидите, что в это время пытались прочитать CMVideoFormatDescription. –

+1

Документация для kCFAllocatorMalloc говорит, что она использует malloc, realloc и бесплатно. Если бы я шел по этому маршруту, я бы, вероятно, использовал тот же распределитель, который выделил бы память напрямую, а не предполагал, что мой вызов malloc() соответствует вызову распределителя free(). Кажется более безопасным и более ясным/понятным, хотя документация утверждает, что они одинаковы. – DSaracino