【问题标题】:AvCaptureSession code extraction errorAvCaptureSession 代码提取错误
【发布时间】:2017-02-09 15:50:35
【问题描述】:

我试图从我的视图控制器中提取一些代码来清理它并尽可能保持为 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: unexpectedly found nil while unwrapping an Optional value

我不明白会话是如何像 ios 新手一样工作的,但我认为这是因为当我尝试捕获图像时会话正在结束(?)?任何见解都会很棒。谢谢

更新:我赞成给出的答案足够接近,以下对我有用。

    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)
    }
}

【问题讨论】:

  • 正如方法名称所述,图像是异步捕获的。见:stackoverflow.com/questions/31794542/…
  • @dan 我明白了,我也查看了您提供的其他链接,但我不知道如何将它应用到我的代码中?会喜欢另一个提示。谢谢

标签: ios swift avcapturesession


【解决方案1】:

您的 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() 方法设为异步,并通过回调报告其返回值。

【讨论】:

  • 感谢您的回复,我正在努力解决您的回复,尽管尝试了我似乎无法弄清楚如何解决它。似乎有一些缺少/额外的括号?
  • 我想我已经添加了任何缺少的括号,我已经将代码更新到我的问题中,但我仍然收到一个错误,说我没有返回任何东西,当我返回结果时它没有像那样。有什么想法吗?
猜你喜欢
  • 1970-01-01
  • 2015-02-13
  • 1970-01-01
  • 2015-11-15
  • 1970-01-01
  • 1970-01-01
  • 2020-10-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多