2017-04-20 78 views
0

我转换CMSampleBuffer说法在我AVCaptureVideoDataOuput委托的captureOutput功能为MTLTexture像这样(侧面说明,我已经设置了视频输出kCVPixelFormatType_32BGRA的像素格式):MTLTexture有0 bytesPerRow

func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) { 

    let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)! 
    let width = CVPixelBufferGetWidth(imageBuffer) 
    let height = CVPixelBufferGetHeight(imageBuffer) 
    var outTexture: CVMetalTexture? = nil 

    var textCache : CVMetalTextureCache? 
    CVMetalTextureCacheCreate(kCFAllocatorDefault, nil, metalDevice, nil, &textCache) 

    var textureRef : CVMetalTexture? 
    CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, textCache!, imageBuffer, nil, MTLPixelFormat.bgra8Unorm, width, height, 0, &textureRef) 
    let texture = CVMetalTextureGetTexture(textureRef!)! 

    print(texture.bufferBytesPerRow) 
} 

问题是,当我打印每行纹理的字节数时,它总是打印0,这是有问题的,因为我稍后尝试使用本文中的方法将纹理转换回UIImage:https://www.invasivecode.com/weblog/metal-image-processing。为什么我收到的纹理看起来是空的?我知道CMSampleBuffer属性是很好,因为我可以将其转换成一个UIImage并绘制它像这样:

let myPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) 
    let myCIimage = CIImage(cvPixelBuffer: myPixelBuffer!) 
    let image = UIImage(ciImage: myCIimage) 
    self.imageView.image = image 

回答

1

bufferBytesPerRow属性是仅适用于使用一个MTLBuffermakeTexture(descriptor:offset:bytesPerRow:)方法创建一个纹理有意义。正如你所看到的,每行字节是该方法的一个输入,以告诉Metal如何解释缓冲区中的数据。 (当然,纹理描述符也提供了额外的信息。)这种方法只是一种方法,可以让它恢复。

请注意,从缓冲区创建的纹理也可以报告它们创建的缓冲区以及提供给上述方法的偏移量。

以其他方式创建的纹理不具有该信息。这些纹理没有固有的每行字节数。他们的数据不一定是内部组织在一个简单的光栅缓冲区中。

如果您希望从纹理中获取数据到金属缓冲区或普通旧字节数组,您有可自由选择对您有用的每行字节数值只要它至少是纹理像素格式的每像素字节乘以纹理宽度即可。 (压缩格式更复杂。)getBytes(_:bytesPerRow:from:mipmapLevel:)copy(from:sourceSlice:sourceLevel:sourceOrigin:sourceSize:to:destinationOffset:destinationBytesPerRow:destinationBytesPerImage:)的文档将进一步解释。