iosswiftuiimagecmsamplebuffer

CMSampleBuffer from AVCaptureVideoDataOutput unexpectedly found nil


I am trying to convert the frames that I'm getting from AVCaptureVideoDataOutput delegate (as CMSampleBuffer) to UIImage. However I'm getting a fatal error: unexpectedly found nil while unwrapping an Optional value Can someone tell me what is wrong with my code? I am assuming that there is something wrong with my sampleBufferToUIImage function.

Function to convert CMSampleBuffer to UIImage:

func sampleBufferToUIImage(sampleBuffer: CMSampleBuffer) -> UIImage{

    let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)

    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)

    let context = CGContext(data: baseAddress, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)

    // *********Getting the error from this line***********
    let quartzImage = context!.makeImage()

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

    let image = UIImage(cgImage: quartzImage!)

    return image

}

delegate where I'm reading frame:

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

    if count <= 0 {
        // Calling my function to convert to UIImage.
        let image = sampleBufferToUIImage(sampleBuffer: sampleBuffer)
        let imageData = UIImagePNGRepresentation(image)
        uploadImage(jpgData: imageData)
    }

    count = count + 1
}

Setting up AVSession:

func setupCameraSession() {

    captureSession.sessionPreset = AVCaptureSessionPresetHigh

    // Declare AVCaptureDevice to default(back camera).  The "as" changes removes the optional?
    let captureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) as AVCaptureDevice

    do {
        let deviceInput = try AVCaptureDeviceInput(device: captureDevice)

        if (captureSession.canAddInput(deviceInput) == true) {
            captureSession.addInput(deviceInput)
        }

        let dataOutput = AVCaptureVideoDataOutput()
        dataOutput.videoSettings = [(kCVPixelBufferPixelFormatTypeKey as NSString) : NSNumber(value: kCVPixelFormatType_420YpCbCr8BiPlanarFullRange as UInt32)]
        dataOutput.alwaysDiscardsLateVideoFrames = true

        if (captureSession.canAddOutput(dataOutput) == true) {
            captureSession.addOutput(dataOutput)
        }


    } catch {

    }

Solution

  • AVCaptureVideoDataOutput's video setting was incorrect. Change kCVPixelFormatType_420YpCbCr8BiPlanarFullRange to kCVPixelFormatType_32BGRA