为啥在 AVCapturePhotoOutput 上调用 .capturePhoto(with:,delegate:) 会导致崩溃

Posted

技术标签:

【中文标题】为啥在 AVCapturePhotoOutput 上调用 .capturePhoto(with:,delegate:) 会导致崩溃【英文标题】:Why does calling .capturePhoto(with:,delegate:) on AVCapturePhotoOutput cause a crash为什么在 AVCapturePhotoOutput 上调用 .capturePhoto(with:,delegate:) 会导致崩溃 【发布时间】:2018-02-16 23:56:34 【问题描述】:

这几天我一直在为这个错误而苦苦挣扎,如果我拍摄画面连续屏幕,关闭当前屏幕翻转相机并拍照,应用程序会因错误而崩溃。

[AVCapturePhotoOutput capturePhotoWithSettings:delegate:] 没有活动和启用的视频连接'

我已将错误缩小到三行代码,虽然我不知道如何修复它我相信解决方案与我的AVCapturePhotoSettings有关

这是我将故障代码缩小到的地方:

@IBAction func cameraButton_TouchUpInside(_ sender: Any) 
    let settings = AVCapturePhotoSettings()
    photoOutPut?.capturePhoto(with: settings, delegate: self as AVCapturePhotoCaptureDelegate)

我是否设置错误。谢谢

这是完整的代码

import UIKit
import AVFoundation


protocol previewSegueDelegate 
func previewSegueDelegate(image:UIImage,device:AVCaptureDevice)


class MainCameraCollectionViewCell: UICollectionViewCell 

var gdelegate: gestureDelegate?
var pdelegate: previewSegueDelegate?


@IBOutlet weak var myView: UIView!

var captureSession = AVCaptureSession()
private var sessionQueue: DispatchQueue!
var captureConnection = AVCaptureConnection()
var currentCamera: AVCaptureDevice?

var photoOutPut: AVCapturePhotoOutput?

var cameraPreviewLayer: AVCaptureVideoPreviewLayer?

var image: UIImage?

 var usingFrontCamera = false

override func awakeFromNib() 
    super.awakeFromNib()
    setupCaptureSession()
    setupDevice()
    setupInput()
    setupPreviewLayer()
    startRunningCaptureSession()
    print("Inside of camera cell")


func setupCaptureSession()
    captureSession.sessionPreset = AVCaptureSession.Preset.photo
    sessionQueue = DispatchQueue(label: "session queue")


func setupDevice(usingFrontCamera:Bool = false)
    sessionQueue.async 
    let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [AVCaptureDevice.DeviceType.builtInWideAngleCamera], mediaType: AVMediaType.video, position: AVCaptureDevice.Position.unspecified)
    let devices = deviceDiscoverySession.devices

    for device in devices
        if usingFrontCamera && device.position == AVCaptureDevice.Position.front 
            self.currentCamera = device
         else if device.position == AVCaptureDevice.Position.back 
            self.currentCamera = device
        
    
    


func setupInput() 
    sessionQueue.async 
        do 
            let captureDeviceInput = try AVCaptureDeviceInput(device: self.currentCamera!)
            if self.captureSession.canAddInput(captureDeviceInput) 
                self.captureSession.addInput(captureDeviceInput)
            
            self.photoOutPut = AVCapturePhotoOutput()
            self.photoOutPut?.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format:[AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil)
            if self.captureSession.canAddOutput(self.photoOutPut!) 
                self.captureSession.addOutput(self.photoOutPut!)
            
         catch 
            print(error)
        
    

func setupPreviewLayer()
    cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
    cameraPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
    cameraPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
    cameraPreviewLayer?.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
    self.layer.insertSublayer(cameraPreviewLayer!, at: 0)


func startRunningCaptureSession()
    captureSession.startRunning()



@IBAction func cameraButton_TouchUpInside(_ sender: Any) 
    let settings = AVCapturePhotoSettings()
    photoOutPut?.capturePhoto(with: settings, delegate: self as AVCapturePhotoCaptureDelegate)
    print("camera button touched")


@IBAction func FlipThe_camera(_ sender: UIButton) 
print("Flip Touched")
    captureSession.beginConfiguration()
    if let inputs = captureSession.inputs as? [AVCaptureDeviceInput] 
        for input in inputs 
            captureSession.removeInput(input)
        
    
    usingFrontCamera = !usingFrontCamera
    setupCaptureSession()
    setupDevice(usingFrontCamera: usingFrontCamera)
    setupInput()
    captureSession.commitConfiguration()
    startRunningCaptureSession()





 extension MainCameraCollectionViewCell: AVCapturePhotoCaptureDelegate
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) 
    if let imageData = photo.fileDataRepresentation()
        print(imageData)
        image = UIImage(data: imageData)
        if(self.image == nil)
            print("The image is empty")
        
        pdelegate?.previewSegueDelegate(image: self.image!, device: currentCamera!)
    


【问题讨论】:

【参考方案1】:

相机切换逻辑错误。

@IBAction func FlipThe_camera(_ sender: UIButton) 
     print("Flip Touched")
    captureSession.beginConfiguration()
    if let inputs = captureSession.inputs as? [AVCaptureDeviceInput] 
        for input in inputs 
            captureSession.removeInput(input)
        
    
    usingFrontCamera = !usingFrontCamera
    setupCaptureSession()
    setupDevice(usingFrontCamera: usingFrontCamera)
    setupInput()
    captureSession.commitConfiguration()
    startRunningCaptureSession()


您不应在 setupInput() 中再次添加输出。 并且不应在startRunningCaptureSession() 中再次开始运行会话

【讨论】:

以上是关于为啥在 AVCapturePhotoOutput 上调用 .capturePhoto(with:,delegate:) 会导致崩溃的主要内容,如果未能解决你的问题,请参考以下文章

无法仅获取在 Swift 中显示相机(AVCapturePhotoOutput)的 UIView 的屏幕截图

如何使用 AVCapturePhotoOutput

AVCapturePhotoOutput - Xcode 9 Beta 5 中的更改

使用 AVCapturePhotoOutput 使用闪光灯拍照时出现问题

AVCapturePhotoOutput 颜色与预览层不同

iOS拍照定制之AVCapturePhotoOutput