CMSampleBuffer 中的 CMBlockBuffer 所有权

Jim*_* B. 1 macos h.264 cmsamplebufferref cmsamplebuffer video-toolbox

我正在编写代码来解压本机附件 B H.264 流,我正在完成解析流的过程,从 SPS/PPS NALU 创建 CMVideoFormatDescription,并包装我从流中提取的其他 NALU在 CMSampleBuffers 中。

我在如何处理解码器的 CMBlockBuffer 和 CMSampleBuffer 内存方面遇到了心理障碍。我相信我的问题更多是缺乏对 CF 如何处理内存的透彻理解,所以我的问题更多的是关于这一点,但我希望上下文有帮助。

如果我像这样创建一个 CMBlockBuffer:

CMBlockBufferRef blockBuffer;

OSStatus status = CMBlockBufferCreateWithMemoryBlock(NULL,
                                                     memoryBlock,                       
                                                     blockBufferLength,
                                                     kCFAllocatorNull,
                                                     NULL,
                                                     0, 
                                                     blockBufferLength,          
                                                     kCMBlockBufferAlwaysCopyDataFlag | kCMBlockBufferAssureMemoryNowFlag,
                                                     &blockBuffer);
Run Code Online (Sandbox Code Playgroud)

并将其添加到 CMSampleBuffer 中,如下所示:

CMSampleBufferRef sampleBuffer;

status = CMSampleBufferCreate(kCFAllocatorDefault,
                              blockBuffer,
                              true,
                              NULL,
                              NULL,
                              formatDescription,
                              1,
                              0,
                              NULL,
                              1,
                              &sampleSize,
                              &sampleBuffer);
Run Code Online (Sandbox Code Playgroud)

我应该如何处理块缓冲区?SampleBuffer 是否保留块缓冲区的内存,或者我是否需要做一些事情来确保它没有被释放?

另外,关于异步解码过程,是否有一种明智的方法可以知道解码器何时使用 CMSampleBuffer 完成以便我可以处理它?

我的直觉告诉我 CMSampleBuffer 会保留 CMBlockBuffer,而 VTDecodeSession 会保留 CMSampleBuffer 直到它完成解码,但这是一个未记录的领域,我正在寻找一些方向。我得到的结果暗示我的直觉可能是错误的,所以我需要排除内存管理作为一个问题来保持我的理智......

DSa*_*ino 5

CMSampleBuffers 和 CMBlockBuffers——对象本身——遵循典型的 CF Retain/Release 语义。只要您需要这些对象,您就应该持有保留,并假设接受它们的接口也这样做。这意味着您可以在将 CMBlockBuffer 交给 CMSampleBuffer 后立即释放它,并且在将其传递到渲染链后可以自由释放 CMSampleBuffer。

使用 CMBlockBufferCreateWithMemoryBlock() 创建的 CMBlockBuffer 指向的内存遵循稍微不同的规则。首先,该方法不会复制 memoryBlock 指向的数据;它直接使用该指针。这意味着 BlockBuffer 需要了解应该如何管理内存。这由 CMBlockBufferCreateWithMemoryBlock() 的第四个或第五个参数处理:如果其中任何一个是非 kCFAllocatorNull/NULL,BlockBuffer 将在完成内存后调用其中一个的解除分配器。这通常在 BlockBuffer 的 Finalize() 中完成。如果它们都是 kCFAllocatorNull/NULL(在您的代码片段中),则 BlockBuffer 将在内存完成后将指针放在地板上。

这意味着,如果您使用 CMBlockBufferCreateWithMemoryBlock() 创建 CMBlockBuffer 并打算在将其传递到渲染管道后释放该 BlockBuffer 上的保留,则应为分配器/释放器使用非 NULL 参数,以便稍后可以回收内存。当然,这些分配器/释放器的实现取决于 memoryBlock 的来源。