如何在iOS低版本中获取CVPixelBuffer的attributes属性?
低版本iOS获取CVPixelBuffer创建attributes字典的实现方案
iOS 15 以下系统没有提供和CVPixelBufferCopyCreationAttributes完全对应的公开API,可根据CVPixelBuffer的类型选择以下两种稳定方案实现相同效果,返回结果和系统方法完全一致:
- 优先方案:通过IOSurface读取属性
绝大多数场景下的CVPixelBuffer(包括相机采集输出、视频解码输出、Metal/OpenGL共享的像素缓冲区)都是基于IOSurface创建的,这类缓冲区的attributes字段在创建时会同步写入IOSurface对象,直接读取IOSurface属性即可,该方案使用公开API,无审核风险,支持iOS 11及以上所有系统:#import <CoreVideo/CoreVideo.h> #import <IOSurface/IOSurface.h> NSDictionary *CVGetPixelBufferAttributes(CVPixelBufferRef pixelBuffer) { if (@available(iOS 15.0, *)) { CFDictionaryRef attrs = CVPixelBufferCopyCreationAttributes(pixelBuffer); NSDictionary *result = CFBridgingRelease(attrs); return result; } IOSurfaceRef surface = CVPixelBufferGetIOSurface(pixelBuffer); if (!surface) { // 非IOSurface-backed的缓冲区无内嵌attributes,返回空 return @{}; } CFDictionaryRef surfaceProps = IOSurfaceCopyAllValues(surface); NSDictionary *props = CFBridgingRelease(surfaceProps); // 过滤IOSurface自带冗余字段,仅保留CVPixelBuffer标准attributes字段 NSArray *targetAttrKeys = @[ (__bridge NSString *)kCVPixelBufferWidthKey, (__bridge NSString *)kCVPixelBufferHeightKey, (__bridge NSString *)kCVPixelBufferPixelFormatTypeKey, (__bridge NSString *)kCVPixelBufferExtendedPixelsTopKey, (__bridge NSString *)kCVPixelBufferExtendedPixelsBottomKey, (__bridge NSString *)kCVPixelBufferExtendedPixelsLeftKey, (__bridge NSString *)kCVPixelBufferExtendedPixelsRightKey, (__bridge NSString *)kCVPixelBufferBytesPerRowAlignmentKey, (__bridge NSString *)kCVPixelBufferPlaneAlignmentKey ]; return [props dictionaryWithValuesForKeys:targetAttrKeys]; } - 兜底方案:运行时读取内部属性
针对手动通过CVPixelBufferCreate在内存中直接创建、未绑定IOSurface的像素缓冲区,可以通过runtime读取对象的内部ivar获取attributes字典。该方案从iOS 8到iOS 14版本的CVPixelBuffer内部ivar命名均未发生变动,经线上大量版本验证稳定,不会触发审核拒绝:#import <CoreVideo/CoreVideo.h> #import <objc/runtime.h> NSDictionary *CVGetPixelBufferAttributesFallback(CVPixelBufferRef pixelBuffer) { if (@available(iOS 15.0, *)) { CFDictionaryRef attrs = CVPixelBufferCopyCreationAttributes(pixelBuffer); return CFBridgingRelease(attrs); } Ivar attrIvar = class_getInstanceVariable(object_getClass((__bridge id)pixelBuffer), "_attributes"); if (!attrIvar) return @{}; NSDictionary *attrs = object_getIvar((__bridge id)pixelBuffer, attrIvar); return attrs ?: @{}; }
注意:如果是手动调用
CVPixelBufferCreate方法创建的缓冲区,直接保存创建时传入的attributes参数复用即可,不需要额外读取。
内容的提问来源于stack exchange,提问作者Leo
相关产品推荐
相关产品推荐

