CMSampleBuffer 中的 CMBlockBuffer 所有权
CMBlockBuffer ownership in CMSampleBuffer
我正在编写代码来解压缩原生 annex-B H.264 流,我正在经历解析流、从 SPS/PPS NALU 创建 CMVideoFormatDescription 并包装我从 CMSampleBuffers 中的流中提取的其他 NALU。
我对如何为解码器处理 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 直到它完成解码,但这是我正在徘徊的无证领域,因此正在寻找方向。我得到的结果暗示我的直觉可能是错误的,所以我需要排除内存管理问题以保持理智...
CMSampleBuffers 和 CMBlockBuffers - 对象本身 - 遵循典型的 CF Retain/Release 语义。只要您需要这些对象,就应该保持保留,并假设接受它们的接口也是如此。这意味着您可以在将 CMBlockBuffer 传递给 CMSampleBuffer 后立即释放它,并且在将其传递到渲染链后可以自由释放 CMSampleBuffer。
使用 CMBlockBufferCreateWithMemoryBlock() 创建的 CMBlockBuffer 指向的内存遵循稍微不同的规则。首先,该方法不会复制 memoryBlock 指向的数据;它直接使用该指针。这意味着 BlockBuffer 需要了解应该如何管理该内存。这是由 CMBlockBufferCreateWithMemoryBlock() 的第四个或第五个参数处理的:如果其中一个是 non-kCFAllocatorNull/NULL,BlockBuffer 将在完成内存处理后调用其中一个的释放器。这通常在 BlockBuffer 的 Finalize() 中完成。如果它们都是 kCFAllocatorNull/NULL(您的代码片段中有),BlockBuffer 将在完成内存处理后将指针放在地板上。
这意味着如果您使用 CMBlockBufferCreateWithMemoryBlock() 创建一个 CMBlockBuffer 并打算在将其传递到渲染管道后释放对该 BlockBuffer 的保留,则您应该为 allocator/deallocators 使用非 NULL 参数,因此内存可以稍后回收。当然,这些 allocators/deallocators 的实现取决于 memoryBlock 的来源。
我正在编写代码来解压缩原生 annex-B H.264 流,我正在经历解析流、从 SPS/PPS NALU 创建 CMVideoFormatDescription 并包装我从 CMSampleBuffers 中的流中提取的其他 NALU。
我对如何为解码器处理 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 直到它完成解码,但这是我正在徘徊的无证领域,因此正在寻找方向。我得到的结果暗示我的直觉可能是错误的,所以我需要排除内存管理问题以保持理智...
CMSampleBuffers 和 CMBlockBuffers - 对象本身 - 遵循典型的 CF Retain/Release 语义。只要您需要这些对象,就应该保持保留,并假设接受它们的接口也是如此。这意味着您可以在将 CMBlockBuffer 传递给 CMSampleBuffer 后立即释放它,并且在将其传递到渲染链后可以自由释放 CMSampleBuffer。
使用 CMBlockBufferCreateWithMemoryBlock() 创建的 CMBlockBuffer 指向的内存遵循稍微不同的规则。首先,该方法不会复制 memoryBlock 指向的数据;它直接使用该指针。这意味着 BlockBuffer 需要了解应该如何管理该内存。这是由 CMBlockBufferCreateWithMemoryBlock() 的第四个或第五个参数处理的:如果其中一个是 non-kCFAllocatorNull/NULL,BlockBuffer 将在完成内存处理后调用其中一个的释放器。这通常在 BlockBuffer 的 Finalize() 中完成。如果它们都是 kCFAllocatorNull/NULL(您的代码片段中有),BlockBuffer 将在完成内存处理后将指针放在地板上。
这意味着如果您使用 CMBlockBufferCreateWithMemoryBlock() 创建一个 CMBlockBuffer 并打算在将其传递到渲染管道后释放对该 BlockBuffer 的保留,则您应该为 allocator/deallocators 使用非 NULL 参数,因此内存可以稍后回收。当然,这些 allocators/deallocators 的实现取决于 memoryBlock 的来源。