【问题标题】:Create CVPixelBuffer from YUV with IOSurface backed使用支持 IOSurface 的 YUV 创建 CVPixelBuffer
【发布时间】:2015-10-27 16:59:00
【问题描述】:

所以我从网络回调(voip 应用程序)获取了 3 个单独数组中的原始 YUV 数据。据我了解,根据here,您无法使用CVPixelBufferCreateWithPlanarBytes 创建支持IOSurface 的像素缓冲区

重要提示:您不能使用 CVPixelBufferCreateWithBytes() 或 CVPixelBufferCreateWithPlanarBytes() 与 kCVPixelBufferIOSurfacePropertiesKey。打电话 CVPixelBufferCreateWithBytes() 或 CVPixelBufferCreateWithPlanarBytes() 将导致不支持 IOSurface 的 CVPixelBuffers

因此您必须使用CVPixelBufferCreate 创建它,但是如何将数据从调用传输回您创建的CVPixelBufferRef

- (void)videoCallBack(uint8_t *yPlane, uint8_t *uPlane, uint8_t *vPlane, size_t width, size_t height, size_t stride yStride,
                      size_t uStride, size_t vStride)
    NSDictionary *pixelAttributes = @{(id)kCVPixelBufferIOSurfacePropertiesKey : @{}};
    CVPixelBufferRef pixelBuffer = NULL;
    CVReturn result = CVPixelBufferCreate(kCFAllocatorDefault,
                                          width,
                                          height,
                                          kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,
                                          (__bridge CFDictionaryRef)(pixelAttributes),
                                          &pixelBuffer);

我不确定接下来该做什么?最终我想把它变成一个 CIImage ,然后我可以使用我的 GLKView 来渲染视频。人们如何从您创建数据时将数据“放入”缓冲区?

【问题讨论】:

    标签: ios objective-c video opengl-es glkit


    【解决方案1】:

    我想通了,这是相当微不足道的。这是下面的完整代码。唯一的问题是我收到了BSXPCMessage received error for message: Connection interrupted,视频显示需要一段时间。

    NSDictionary *pixelAttributes = @{(id)kCVPixelBufferIOSurfacePropertiesKey : @{}};
    CVPixelBufferRef pixelBuffer = NULL;
    CVReturn result = CVPixelBufferCreate(kCFAllocatorDefault,
                                          width,
                                          height,
                                          kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,
                                          (__bridge CFDictionaryRef)(pixelAttributes),
                                          &pixelBuffer);
    
    CVPixelBufferLockBaseAddress(pixelBuffer, 0);
    uint8_t *yDestPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
    memcpy(yDestPlane, yPlane, width * height);
    uint8_t *uvDestPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
    memcpy(uvDestPlane, uvPlane, numberOfElementsForChroma);
    CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
    
    if (result != kCVReturnSuccess) {
        DDLogWarn(@"Unable to create cvpixelbuffer %d", result);
    }
    
    CIImage *coreImage = [CIImage imageWithCVPixelBuffer:pixelBuffer]; //success!
    CVPixelBufferRelease(pixelBuffer);
    

    我忘了添加代码来交错两个 U 和 V 平面,但这应该不会太糟糕。

    【讨论】:

    • 请提供 U 面和 V 面的代码和 numberOfElementsForChroma
    • @JULIIncognito 我相信 uvPlane 只是一个 uint_8 数组。这是很久以前的对不起。 numberOfElementsForChroma 将是您需要的任何固定大小。
    • @JULIIncognito numberOfElementsForChroma 是否与 width * height 相同?因为它不起作用。
    • @lilouch 这对我也不起作用。所以,我刚刚将颜色格式更改为 kCVPixelFormatType_32BGRA 并进行了另一次转换
    • 对于 Y420 或 NV12,numberOfElementsForChroma 为 width*height/2。因为 U 面和 V 面都是 Y 面的四分之一。
    【解决方案2】:

    我有一个类似的问题,以下是我在 SWIFT 2.0 中的内容,其中包含我从其他问题的答案或链接中获得的信息。

    func generatePixelBufferFromYUV2(inout yuvFrame: YUVFrame) -> CVPixelBufferRef?
    {
        var uIndex: Int
        var vIndex: Int
        var uvDataIndex: Int
        var pixelBuffer: CVPixelBufferRef? = nil
        var err: CVReturn;
    
        if (m_pixelBuffer == nil)
        {
            err = CVPixelBufferCreate(kCFAllocatorDefault, yuvFrame.width, yuvFrame.height, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, nil, &pixelBuffer)
            if (err != 0) {
                NSLog("Error at CVPixelBufferCreate %d", err)
                return nil
            }
        }
    
        if (pixelBuffer != nil)
        {
            CVPixelBufferLockBaseAddress(pixelBuffer!, 0)
            let yBaseAddress = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer!, 0)
            if (yBaseAddress != nil)
            {
                let yData = UnsafeMutablePointer<UInt8>(yBaseAddress)
                let yDataPtr = UnsafePointer<UInt8>(yuvFrame.luma.bytes)
    
                // Y-plane data
                memcpy(yData, yDataPtr, yuvFrame.luma.length)
            }
    
            let uvBaseAddress = CVPixelBufferGetBaseAddressOfPlane(m_pixelBuffer!, 1)
            if (uvBaseAddress != nil)
            {
                let uvData = UnsafeMutablePointer<UInt8>(uvBaseAddress)
                let pUPointer = UnsafePointer<UInt8>(yuvFrame.chromaB.bytes)
                let pVPointer = UnsafePointer<UInt8>(yuvFrame.chromaR.bytes)
    
                // For the uv data, we need to interleave them as uvuvuvuv....
                let iuvRow = (yuvFrame.chromaB.length*2/yuvFrame.width)
                let iHalfWidth = yuvFrame.width/2
    
                for i in 0..<iuvRow
                {
                    for j in 0..<(iHalfWidth)
                    {
                        // UV data for original frame.  Just interleave them.
                        uvDataIndex = i*iHalfWidth+j
                        uIndex = (i*yuvFrame.width) + (j*2)
                        vIndex = uIndex + 1
                        uvData[uIndex] = pUPointer[uvDataIndex]
                        uvData[vIndex] = pVPointer[uvDataIndex]
                    }
                }
            }
            CVPixelBufferUnlockBaseAddress(pixelBuffer!, 0)
        }
    
        return pixelBuffer
    }
    

    注意:yuvFrame 是一个具有 y、u 和 v 计划缓冲区以及宽度和高度的结构。另外,我有 CFDictionary? CVPixelBufferCreate(...) 中的参数设置为 nil。如果我给它 IOSurface 属性,它将失败并抱怨它不是 IOSurface-backed 或错误 -6683。

    访问以下链接了解更多信息: 此链接是关于 UV 交错的: How to convert from YUV to CIImage for iOS

    及相关问题:CVOpenGLESTextureCacheCreateTextureFromImage returns error 6683

    【讨论】:

    • 我有一些类似的任务要执行,我能否了解 YUVFrame 结构和转换代码。从这里我无法获得将 Y-U-V 指针转换为像素缓冲区的结果。谢谢
    • 我的代码是 Objective-c 和 SWIFT 的混合体。我拥有的结构在objective-c中。它由三个 NSData 和两个 NSInteger 组成: property (strong, nonatomic) NSData *luma;属性(强,非原子) NSData *chromaB;属性(强,非原子) NSData *chromaR;属性 NSInteger 宽度;属性 NSInteger 高度; // @'s before 属性被移除
    【解决方案3】:

    这是 obj-c 中的完整转换。 同样对于那些说:“这是微不足道的”的天才,不要光顾任何人!如果你来这里是为了帮助,帮助,如果你来这里是为了展示你有多“聪明”,那就去别的地方做吧。 这里是YUV处理详细解释的链接:www.glebsoft.com

        /// method to convert YUV buffers to pixelBuffer in otder to feed it to face unity methods
    -(CVPixelBufferRef*)pixelBufferFromYUV:(uint8_t *)yBuffer vBuffer:(uint8_t *)uBuffer uBuffer:(uint8_t *)vBuffer width:(int)width height:(int)height  {
        NSDictionary *pixelAttributes = @{(id)kCVPixelBufferIOSurfacePropertiesKey : @{}};
        CVPixelBufferRef pixelBuffer;
        /// NumberOfElementsForChroma is width*height/4 because both U plane and V plane are quarter size of Y plane
        CGFloat uPlaneSize =  width * height / 4;
        CGFloat vPlaneSize = width * height / 4;
        CGFloat numberOfElementsForChroma = uPlaneSize + vPlaneSize;
    
        CVReturn result = CVPixelBufferCreate(kCFAllocatorDefault,
                                              width,
                                              height,
                                              kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,
                                              (__bridge CFDictionaryRef)(pixelAttributes),
                                              &pixelBuffer);
    
        ///for simplicity and speed create a combined UV panel to hold the pixels
        uint8_t *uvPlane = calloc(numberOfElementsForChroma, sizeof(uint8_t));
        memcpy(uvPlane, uBuffer, uPlaneSize);
        memcpy(uvPlane += (uint8_t)(uPlaneSize), vBuffer, vPlaneSize);
        
        
        CVPixelBufferLockBaseAddress(pixelBuffer, 0);
        uint8_t *yDestPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
        memcpy(yDestPlane, yBuffer, width * height);
        
        uint8_t *uvDestPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
        memcpy(uvDestPlane, uvPlane, numberOfElementsForChroma);
        CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
        CVPixelBufferRelease(pixelBuffer);
        free(uvPlane);
        return pixelBuffer;
    }
    

    【讨论】:

      猜你喜欢
      • 2016-09-23
      • 2021-02-28
      • 1970-01-01
      • 2016-11-16
      • 1970-01-01
      • 2018-06-08
      • 2014-02-01
      • 1970-01-01
      • 2016-11-08
      相关资源
      最近更新 更多