【问题标题】:What is the most efficient way to display CVImageBufferRef on iOS在 iOS 上显示 CVImageBufferRef 的最有效方法是什么
【发布时间】:2015-09-29 17:16:39
【问题描述】:

我有 CMSampleBufferRef(s),我使用 VTDecompressionSessionDecodeFrame 解码,这会在帧解码完成后产生 CVImageBufferRef,所以我的问题是..

在 UIView 中显示这些 CVImageBufferRef 的最有效方式是什么?

我已成功将 CVImageBufferRef 转换为 CGImageRef 并通过将 CGImageRef 设置为 CALayer 的内容来显示这些内容,但随后 DecompressionSession 已配置为 @{ (id)kCVPixelBufferPixelFormatTypeKey: [NSNumber numberWithInt:kCVPixelFormatType_32BGRA] };

这是我如何将 CVImageBufferRef 转换为 CGImageRef 的示例/代码(注意:cvpixelbuffer 数据必须采用 32BGRA 格式才能正常工作)

    CVPixelBufferLockBaseAddress(cvImageBuffer,0);
    // get image properties 
    uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(cvImageBuffer);
    size_t bytesPerRow   = CVPixelBufferGetBytesPerRow(cvImageBuffer);
    size_t width         = CVPixelBufferGetWidth(cvImageBuffer);
    size_t height        = CVPixelBufferGetHeight(cvImageBuffer);

    /*Create a CGImageRef from the CVImageBufferRef*/
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef    cgContext  = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
    CGImageRef cgImage = CGBitmapContextCreateImage(cgContext);

    // release context and colorspace 
    CGContextRelease(cgContext);
    CGColorSpaceRelease(colorSpace);

    // now CGImageRef can be displayed either by setting CALayer content
    // or by creating a [UIImage withCGImage:geImage] that can be displayed on
    // UIImageView ...

#WWDC14 会话 513 (https://developer.apple.com/videos/wwdc/2014/#513) 暗示可以避免 YUV -> RGB 颜色空间转换(使用 CPU?),如果使用支持 YUV 的 GLES 魔法 - 想知道这可能是什么以及如何实现?

Apple 的 iOS SampleCode GLCameraRipple 展示了一个示例,该示例使用 2 个 OpenGLES 显示从相机捕获的 YUV CVPixelBufferRef,其中 Y 和 UV 组件具有单独的纹理,以及使用 GPU 执行 YUV 到 RGB 颜色空间转换计算的片段着色器程序 - 这就是真正需要的,还是有更直接的方法可以做到这一点?

注意:在我的用例中,我无法使用 AVSampleBufferDisplayLayer,因为事实上解压缩的输入是可用的。

【问题讨论】:

    标签: ios opengl-es core-graphics avfoundation video-toolbox


    【解决方案1】:

    更新:下面的原始答案不起作用,因为 kCVPixelBufferIOSurfaceCoreAnimationCompatibilityKey 不适用于 iOS。


    UIViewCALayer 支持,其contents 属性支持多种类型的图像。正如my answer 中针对 macOS 的类似问题所详述的那样,可以使用CALayer 来渲染CVPixelBuffer 的支持IOSurface。 (警告:我只在 macOS 上测试过。)

    【讨论】:

      【解决方案2】:

      如果您从CMSampleBufferRef 获取您的CVImageBufferRef,而您从captureOutput:didOutputSampleBuffer:fromConnection: 接收它,则无需进行该转换,并且可以直接从CMSampleBufferRef 获取imageData。代码如下:

      NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:sampleBuffer];
      UIImage *frameImage = [UIImage imageWithData:imageData];
      

      API 描述不提供有关其 32BGRA 是否支持的任何信息,并以 jpeg 格式生成 imageData 以及任何元数据,而无需应用任何压缩。如果您的目标是在屏幕上显示图像或与UIImageView 一起使用,这是快捷方式。

      【讨论】:

      • 谢谢,但是这些帧是在其他地方捕获的,并且编码的 H.264 NALU 在其他应用程序数据中通过网络传输。因此,通过网络接收这些编码帧的应用程序首先需要解码那些在其 CMBlockBuffers 中包含 H.264 的 CMSampleBuffers 以访问解码帧和像素数据,然后它需要显示那些解码的视频帧。现在我正在寻找最有效的方法(减少 CPU 和 GPU 内存之间的内存复制,最佳电池和整体计算效率..)
      猜你喜欢
      • 1970-01-01
      • 2018-06-08
      • 2011-12-07
      • 2021-04-07
      • 2014-02-08
      • 2010-11-17
      • 1970-01-01
      • 2012-06-12
      • 1970-01-01
      相关资源
      最近更新 更多