ios - AvCaptureSession代码提取错误

标签 ios swift avcapturesession

我试图从我的 View Controller 中提取一些代码来清理它,并尽可能将代码保持为 DRY。它在如下情况下工作正常:

class InitialRegistrationViewController: UIViewController, UINavigationControllerDelegate,  UIImagePickerControllerDelegate, NVActivityIndicatorViewable {

    var session: AVCaptureSession?
    var stillImageOutput: AVCaptureStillImageOutput?

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        if Platform.isPhone {
            session = AVCaptureSession()
            session!.sessionPreset = AVCaptureSessionPresetPhoto

            var frontCamera = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
            let availableCameraDevices = AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo)
            for device in availableCameraDevices as! [AVCaptureDevice] {
                if device.position == .front {
                    frontCamera = device
                }
            }

            var error: NSError?
            var input: AVCaptureDeviceInput!
            do {
                input = try AVCaptureDeviceInput(device: frontCamera)
            } catch let error1 as NSError {
                error = error1
                input = nil
                print(error!.localizedDescription)
            }

            if error == nil && session!.canAddInput(input) {
                session!.addInput(input)
                stillImageOutput = AVCaptureStillImageOutput()
                stillImageOutput?.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]

                if session!.canAddOutput(stillImageOutput) {
                    session!.addOutput(stillImageOutput)
                    session!.startRunning()
                }
            }
        }
    }


    func capturePhoto() {
        if let videoConnection = stillImageOutput!.connection(withMediaType: AVMediaTypeVideo) {
            stillImageOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: { (sampleBuffer, error) -> Void in
                if sampleBuffer != nil {
                    let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer)
                    let dataProvider = CGDataProvider(data: imageData as! CFData)
                    let cgImageRef = CGImage(jpegDataProviderSource: dataProvider!, decode: nil, shouldInterpolate: true, intent: CGColorRenderingIntent.defaultIntent)
                    let image = UIImage(cgImage: cgImageRef!, scale: 1.0, orientation: UIImageOrientation.right)
                    self.profileImage.image = image
                }
            })
        }
    }
}

但是当我提取到如下助手时:

导入 UIKit 导入 AVFoundation

class ProfilePhoto {

    var session: AVCaptureSession?
    var stillImageOutput: AVCaptureStillImageOutput?

    func startSession() {

        if Platform.isPhone {
            session = AVCaptureSession()
            session!.sessionPreset = AVCaptureSessionPresetPhoto

            var frontCamera = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
            let availableCameraDevices = AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo)
            for device in availableCameraDevices as! [AVCaptureDevice] {
                if device.position == .front {
                    frontCamera = device
                }
            }

            var error: NSError?
            var input: AVCaptureDeviceInput!
            do {
                input = try AVCaptureDeviceInput(device: frontCamera)
            } catch let error1 as NSError {
                error = error1
                input = nil
                print(error!.localizedDescription)
            }

            if error == nil && session!.canAddInput(input) {
                session!.addInput(input)
                stillImageOutput = AVCaptureStillImageOutput()
                stillImageOutput?.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]

                if session!.canAddOutput(stillImageOutput) {
                    session!.addOutput(stillImageOutput)
                    session!.startRunning()
                }
            }
        }
    }

    func capture() -> UIImage {
        var image: UIImage!

        if let videoConnection = stillImageOutput!.connection(withMediaType: AVMediaTypeVideo) {
            stillImageOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: { (sampleBuffer, error) -> Void in
                if sampleBuffer != nil {
                    let cgImageRef = self.setBufferData(sampleBuffer: sampleBuffer!)
                    image = UIImage(cgImage: cgImageRef, scale: 1.0, orientation: UIImageOrientation.right)
                }
            })
        }
        return image
    }

    func setBufferData(sampleBuffer: CMSampleBuffer ) -> CGImage {
        let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer)
        let dataProvider = CGDataProvider(data: imageData as! CFData)
        let cgImageRef = CGImage(jpegDataProviderSource: dataProvider!, decode: nil, shouldInterpolate: true, intent: CGColorRenderingIntent.defaultIntent)
        return cgImageRef!
    }
}

我调用 InitialRegistrationViewController 的地方:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    profilePhoto.startSession()
}


func capturePhoto() {
    profileImage.image = profilePhoto.capture()
}

在 profilePhoto.capture() 中返回图像时,出现 fatal error :在展开可选值时意外发现 nil

我不明白 session 是如何工作的,因为我是 ios 的新手,但我认为这是因为当我 try catch 图像时 session 正在结束(?)?任何见解都会很棒。谢谢

更新:我赞成给出的答案,因为它足够接近,下面是对我有用的。

    func capture(completion: @escaping (UIImage?) -> Void) {

    if let videoConnection = stillImageOutput!.connection(withMediaType: AVMediaTypeVideo) {
        stillImageOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: { (sampleBuffer, error) -> Void in
            if sampleBuffer != nil {
                let cgImageRef = self.setBufferData(sampleBuffer: sampleBuffer!)
                let image: UIImage! = UIImage(cgImage: cgImageRef, scale: 1.0, orientation: UIImageOrientation.right)
                completion(image)
            } else {
                completion(nil)
            }
        })
    } else {
        completion(nil)
    }
}

最佳答案

您的 capture() 方法进行异步调用以获取 UIImage,因此当它[立即]返回时,返回的值始终为 nil

@dan 建议的文章展示了一种回调模式,可用于将图像返回给调用者,请确保在继续之前了解此机制。

    func capture(result: (image: UIImage?) -> Void) -> UIImage 
    {
        if let videoConnection = stillImageOutput!.connection(withMediaType: AVMediaTypeVideo) 
        {
            stillImageOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler:
            { (sampleBuffer, error) -> Void in

             if sampleBuffer != nil 
             {
                let cgImageRef = self.setBufferData(sampleBuffer: sampleBuffer!)
                var image: UIImage! = UIImage(cgImage: cgImageRef, scale: 1.0, orientation: UIImageOrientation.right)
                result(image: image)
             }
             else
                result(image: nil)   

            })
        }
        else
            result(image: nil)
    }

要调用它,您可以使用

capture(){(image: UIImage?) -> Void in
    //use the image that was just retrieved
}

您现在已将 capture() 方法设为异步,并通过回调报告其返回值。

关于ios - AvCaptureSession代码提取错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42141112/

相关文章:

ios - 在 Swift 中读取 CGPoints 的 NSArray

ios - Swift 以编程方式启动 UILongPressGesture

ios - 如何在 iOS 9 中使用带有 Slide Over 和 Split View 的 AVCaptureSession?

ios - AVCaptureSession 和 AVAudioSession 在背景音乐播放时录制视频只能工作一次

iOS - 从我的应用程序以编程方式进行 WhatsApp 语音/视频通话

iphone - 自定义表格 View 中的图像未按正确顺序显示

iphone - 在 iPhone 中从运营商检索当前时间

swift - 从 NSMutableString 中删除 unicode 符号

ios - 在设备/模拟器中关闭时 Swift App 崩溃?

swift - 如何检查 AVCaptureSession 预设分辨率是否受 Swift 支持