iOS 7+ 从 BGRA 字节获取 CVPixelBufferRef 的最快方法

Fastest way on iOS 7+ to get CVPixelBufferRef from BGRA bytes

在 iOS 7+ 上将 BGRA / UIImage 数据的原始字节转换为 CVPixelBufferRef 的最快方法是什么?按 BGRA 顺序,字节为每个像素 4 个字节。

这里是否有直接转换与将数据复制到辅助存储的机会?

我考虑过CVPixelBufferCreateWithBytes但我有预感它正在复制内存...

您必须使用 CVPixelBufferCreate,因为 CVPixelBufferCreateWithBytes 不允许使用 Core Video 纹理缓存快速转换为 OpenGL 纹理。我不确定为什么会这样,但至少从 iOS 8 开始就是这样。我用分析器对此进行了测试,CVPixelBufferCreateWithBytes 导致每次调用 texSubImage2D从缓存访问核心视频纹理。

如果宽度不是 16 的倍数,

CVPixelBufferCreate 会做一些有趣的事情,所以如果你计划在 CVPixelBufferGetBaseAddress 上做 CPU 操作,并且你希望它被放置像 CGImageCGBitmapContext 一样,您需要将宽度填充得更高,直到它是 16 的倍数,或者确保您使用 CVPixelBufferGetRowBytes 并将其传递给您创建的任何 CGBitmapContext .

我测试了从16到2048的所有宽高尺寸组合,只要填充到下一个16的最高倍数,内存布局就可以了。

+ (NSInteger) alignmentForPixelBufferDimension:(NSInteger)dim
{
    static const NSInteger modValue = 16;
    NSInteger mod = dim % modValue;
    return (mod == 0 ? dim : (dim + (modValue - mod)));
}

+ (NSDictionary*) pixelBufferSurfaceAttributesOfSize:(CGSize)size
{
    return @{ (NSString*)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA),
              (NSString*)kCVPixelBufferWidthKey: @(size.width),
              (NSString*)kCVPixelBufferHeightKey: @(size.height),
              (NSString*)kCVPixelBufferBytesPerRowAlignmentKey: @(size.width * 4),
              (NSString*)kCVPixelBufferExtendedPixelsLeftKey: @(0),
              (NSString*)kCVPixelBufferExtendedPixelsRightKey: @(0),
              (NSString*)kCVPixelBufferExtendedPixelsTopKey: @(0),
              (NSString*)kCVPixelBufferExtendedPixelsBottomKey: @(0),
              (NSString*)kCVPixelBufferPlaneAlignmentKey: @(0),
              (NSString*)kCVPixelBufferCGImageCompatibilityKey: @(YES),
              (NSString*)kCVPixelBufferCGBitmapContextCompatibilityKey: @(YES),
              (NSString*)kCVPixelBufferOpenGLESCompatibilityKey: @(YES),
              (NSString*)kCVPixelBufferIOSurfacePropertiesKey: @{ @"IOSurfaceCGBitmapContextCompatibility": @(YES), @"IOSurfaceOpenGLESFBOCompatibility": @(YES), @"IOSurfaceOpenGLESTextureCompatibility": @(YES) } };
}

有趣的是,如果您从 Core Video 缓存中请求尺寸小于填充尺寸的纹理,它将立即 return 纹理。以某种方式在它下面可以引用原始纹理,但宽度和高度较小。

总而言之,您无法使用 CVPixelBufferCreateWithBytes 使用 CVPixelBufferRef 包装现有内存并有效地使用 Core Video 纹理缓存。您必须使用 CVPixelBufferCreate 并使用 CVPixelBufferGetBaseAddress.