将CMSampleBuffer转换为UIImage

4
这里有一个函数(来自Apple文档),可以将CMSampleBuffer转换成UIImage:
func imageFromSampleBuffer(sampleBuffer: CMSampleBuffer) -> UIImage {
    // Get a CMSampleBuffer's Core Video image buffer for the media data
    var imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
    // Lock the base address of the pixel buffer
    CVPixelBufferLockBaseAddress(imageBuffer, 0)

    // Get the number of bytes per row for the pixel buffer
    var baseAddress = CVPixelBufferGetBaseAddress(imageBuffer)

    // Get the number of bytes per row for the pixel buffer
    var bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer)
    // Get the pixel buffer width and height
    var width = CVPixelBufferGetWidth(imageBuffer)
    var height = CVPixelBufferGetHeight(imageBuffer)

    // Create a device-dependent RGB color space
    var colorSpace = CGColorSpaceCreateDeviceRGB()

    // Create a bitmap graphics context with the sample buffer data
    let bitmapInfo = CGBitmapInfo(CGImageAlphaInfo.NoneSkipLast.rawValue)
    var context = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, bitmapInfo)
    // Create a Quartz image from the pixel data in the bitmap graphics context
    var quartzImage = CGBitmapContextCreateImage(context);
    // Unlock the pixel buffer
    CVPixelBufferUnlockBaseAddress(imageBuffer,0);

    // Create an image object from the Quartz image
    var image = UIImage(CGImage: quartzImage)!

    return image
}

当我试图使用UIImageView来可视化UIImage时,却什么也看不到。有任何想法吗?

你在 Xcode 输出中遇到了错误吗? - Aaron Bratcher
3个回答

4

我在当前项目中刚刚完成了同样的功能,以下是我是如何使其工作的(经过大量谷歌搜索和一些试错):

let bitmapInfo = CGBitmapInfo(CGImageAlphaInfo.NoneSkipFirst.rawValue | CGBitmapInfo.ByteOrder32Little.rawValue)

同时,确保在主线程中呈现UIImageView(您可能在相机会话线程中获取CMSampleBuffer),因为UIKit只能在主线程中执行。否则,您将不得不等待非常非常长的时间才能显示图像。


如何在最佳实践中从“bitmapInfo”获取UIImage? - Alston

4

@Zigglzworth 需要设置kCVPixelFormatType_32BGRA来捕获视频数据输出。

        let videoOutput = AVCaptureVideoDataOutput()
        videoOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA]

4
这是一个针对Swift 3.0的解决方案,扩展了,创建了一个变量,为您提供可选的。
import AVFoundation

extension CMSampleBuffer {
    var uiImage: UIImage? {
        guard let imageBuffer = CMSampleBufferGetImageBuffer(self) else { return nil }

        CVPixelBufferLockBaseAddress(imageBuffer, CVPixelBufferLockFlags(rawValue: 0))
        let baseAddress = CVPixelBufferGetBaseAddress(imageBuffer)
        let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer)
        let width = CVPixelBufferGetWidth(imageBuffer)
        let height = CVPixelBufferGetHeight(imageBuffer)
        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.noneSkipFirst.rawValue | CGBitmapInfo.byteOrder32Little.rawValue)
        guard let context = CGContext(data: baseAddress,
                                      width: width,
                                      height: height,
                                      bitsPerComponent: 8,
                                      bytesPerRow: bytesPerRow,
                                      space: colorSpace,
                                      bitmapInfo: bitmapInfo.rawValue) else { return nil }
        guard let cgImage = context.makeImage() else { return nil }

        CVPixelBufferUnlockBaseAddress(imageBuffer,CVPixelBufferLockFlags(rawValue: 0));

        return UIImage(cgImage: cgImage)
    }
}

2
我收到以下错误信息:<Error>: CGBitmapContextCreate: invalid data bytes/row: should be at least 5120 for 8 integer bits/component, 3 components, kCGImageAlphaNoneSkipFirst - Zigglzworth
@Zigglzworth 您可能有一张灰度图像。您可以相应地调整值。 - CodeBender
嗯,这不是应该……不确定为什么这对我没用。 - Zigglzworth
你能否把图片发布到某个地方? - CodeBender
@CodeBender 非常感谢 :) - Nikhil Manapure
如何将其转换回 CMSampleBuffer? - famfamfam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接