CMSampleBuffer的MTLTexture有0个字节的PerRow

时间:2017-04-20 22:40:53

标签: ios swift video-streaming avfoundation metal

我正在将AVCaptureVideoDataOuput委托的captureOutput函数中的CMSampleBuffer参数转换为类似的MTLTexture(旁注,我已将视频输出的像素格式设置为kCVPixelFormatType_32BGRA):

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 个答案:

答案 0 :(得分:1)

bufferBytesPerRow属性仅对使用makeTexture(descriptor:offset:bytesPerRow:)的{​​{1}}方法创建的纹理有意义。如您所见,每行字节数是该方法的输入,以告诉Metal如何解释缓冲区中的数据。 (当然,纹理描述符也提供了额外的信息。)这种方法只是让它退出的一种方法。

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

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

如果/当您想要将纹理中的数据提供给Metal缓冲区或普通旧字节数组时,可以自由选择每行字节数为&#39 ;对于你的目的是有用的,只要它至少纹理像素格式的每像素字节乘以纹理的宽度。 (压缩格式更复杂。)getBytes(_:bytesPerRow:from:mipmapLevel:)copy(from:sourceSlice:sourceLevel:sourceOrigin:sourceSize:to:destinationOffset:destinationBytesPerRow:destinationBytesPerImage:)的文档进一步解释。