2017-05-05 72 views
0

我需要转换YUV帧到CVPixelBuffer我从OTVideoFrame如何YUV帧(从OTVideoFrame)转换为CVPixelBuffer

该类提供平面的,其中包含三个元素为y中的视频帧的阵列得到,u,v每帧索引号为0,1,2

@属性(非原子,保留)NSPointerArray *平面

和所述视频帧的format

@属性(非原子,保留)OTVideoFormat *格式

包含框架的属性,如宽度,高度,bytesPerRow等

我需要过滤器添加到我收到的OTVideoFrame形式的形象,我已经尝试过这些问题的答案:

这两个环节上有在Objective-C中的解决方案,但我想迅速做到这一点。第二个链接中的答案之一很快,但它缺少一些关于结构的信息,答案提到了这个结构。

,我收到的格式是NV12

这是我一直在努力做的到现在,但我不知道如何下一步继续: -

/** 
* Calcualte the size of each plane from OTVideoFrame. 
* 
* @param frame The frame to render. 
* @return tuple containing three elements for size of each plane 
*/ 
fileprivate func calculatePlaneSize(forFrame frame: OTVideoFrame) 
     -> (ySize: Int, uSize: Int, vSize: Int){ 
      guard let frameFormat = frame.format 
       else { 
        return (0, 0 ,0) 
      } 
      let baseSize = Int(frameFormat.imageWidth * frameFormat.imageHeight) * MemoryLayout<GLubyte>.size 
      return (baseSize, baseSize/4, baseSize/4) 
    } 

/** 
* Renders a frame to the video renderer. 
* 
* @param frame The frame to render. 
*/ 
func renderVideoFrame(_ frame: OTVideoFrame) { 


    let planeSize = calculatePlaneSize(forFrame: frame) 
    let yPlane = UnsafeMutablePointer<GLubyte>.allocate(capacity: planeSize.ySize) 
    let uPlane = UnsafeMutablePointer<GLubyte>.allocate(capacity: planeSize.uSize) 
    let vPlane = UnsafeMutablePointer<GLubyte>.allocate(capacity: planeSize.vSize) 

    memcpy(yPlane, frame.planes?.pointer(at: 0), planeSize.ySize) 
    memcpy(uPlane, frame.planes?.pointer(at: 1), planeSize.uSize) 
    memcpy(vPlane, frame.planes?.pointer(at: 2), planeSize.vSize) 

    let yStride = frame.format!.bytesPerRow.object(at: 0) as! Int 
    // multiply chroma strides by 2 as bytesPerRow represents 2x2 subsample 
    let uStride = frame.format!.bytesPerRow.object(at: 1) as! Int 
    let vStride = frame.format!.bytesPerRow.object(at: 2) as! Int 

    let width = frame.format!.imageWidth 
    let height = frame.format!.imageHeight 

    var pixelBuffer: CVPixelBuffer? = nil 
    var err: CVReturn; 


    err = CVPixelBufferCreate(kCFAllocatorDefault, Int(width), Int(height), kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, nil, &pixelBuffer) 
    if (err != 0) { 
     NSLog("Error at CVPixelBufferCreate %d", err) 
     fatalError() 
    } 

} 

从以指导这两个链接我试图创建像素缓冲区,但我被困每次在这一点上,因为在此之后,Objective-C代码的转换不是类似于我们在斯威夫特3.

回答

0

下面是我工作(我有 采取你的功能,并改变了一下):

func createPixelBufferWithVideoFrame(_ frame: OTVideoFrame) -> CVPixelBuffer? { 
    if let fLock = frameLock { 
     fLock.lock() 

     let planeSize = calculatePlaneSize(forFrame: frame) 

     let yPlane = UnsafeMutablePointer<GLubyte>.allocate(capacity: planeSize.ySize) 
     let uPlane = UnsafeMutablePointer<GLubyte>.allocate(capacity: planeSize.uSize) 
     let vPlane = UnsafeMutablePointer<GLubyte>.allocate(capacity: planeSize.vSize) 

     memcpy(yPlane, frame.planes?.pointer(at: 0), planeSize.ySize) 
     memcpy(uPlane, frame.planes?.pointer(at: 1), planeSize.uSize) 
     memcpy(vPlane, frame.planes?.pointer(at: 2), planeSize.vSize) 

     let width = frame.format!.imageWidth 
     let height = frame.format!.imageHeight 

     var pixelBuffer: CVPixelBuffer? = nil 
     var err: CVReturn; 

     err = CVPixelBufferCreate(kCFAllocatorDefault, Int(width), Int(height), kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, nil, &pixelBuffer) 
     if (err != 0) { 
      NSLog("Error at CVPixelBufferCreate %d", err) 
      return nil 
     } 

     if let pixelBuffer = pixelBuffer { 
      CVPixelBufferLockBaseAddress(pixelBuffer, .readOnly) 
      let yPlaneTo = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0) 
      memcpy(yPlaneTo, yPlane, planeSize.ySize) 

      let uvRow: Int = planeSize.uSize*2/Int(width) 

      let halfWidth: Int = Int(width)/2 

      if let uPlaneTo = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1) { 
       let uvPlaneTo = uPlaneTo.bindMemory(to: GLubyte.self, capacity: Int(uvRow*halfWidth*2)) 

       for i in 0..<uvRow { 
        for j in 0..<halfWidth { 
         let dataIndex: Int = Int(i) * Int(halfWidth) + Int(j) 
         let uIndex: Int = (i * Int(width)) + Int(j) * 2 
         let vIndex: Int = uIndex + 1 

         uvPlaneTo[uIndex] = uPlane[dataIndex] 
         uvPlaneTo[vIndex] = vPlane[dataIndex] 

        } 
       } 

      } 

     } 

     fLock.unlock() 

     return pixelBuffer 
    } 
    return nil 
}