代码之家  ›  专栏  ›  技术社区  ›  Pruthivi Raj

切换到前置摄像头时应用程序崩溃

  •  0
  • Pruthivi Raj  · 技术社区  · 8 年前

    我正在创建一个类似snapchat的摄像头应用程序,以便在屏幕上双击切换摄像头。代码编译时没有错误,但当我双击屏幕到达前摄像头时,我遇到了一个错误。以下是错误:

    2018-03-30 18:44:46.717257+0530摄像头[369:36651] *正在终止应用程序 由于未捕获异常“NSInvalidArgumentException”,原因:'* -[AVCaptureSession addOutput:]无法将输出添加到捕获会话 -&燃气轮机; 因为 不支持相同类型' ***第一次抛出调用堆栈:(0x18564ed8c 0x1848085ec 0x18b13ca74 0x104b3c140 0x104b3b75c 0x104b3b794 0x18f3fe750 0x18f96b2a4 0x18f560e6c 0x18f3fd7a8 0x18f95cac4 0x18f3f7540 0x18f3f7078 0x18f3f68dc 0x18f3f5238 0x18fbd6c0c 0x18fbd91b8 0x18fbd2258 0x1855F74040x1855F6C2C 0x1855f479c 0x185514da8 0x1874f7020 0x18f4f578c 0x104b40ca8 0x184fa5fc0)libc++abi。动态库:终止于 NSException类型的未捕获异常

    这是我的ViewController文件:

    import UIKit
    import AVFoundation
    
    class ViewController: UIViewController, AVCapturePhotoCaptureDelegate {
    
    @IBOutlet weak var previewView: UIView!
    override var prefersStatusBarHidden: Bool { return true }
    var session = AVCaptureSession()
    var device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)
    var frontCameraMode = false
    var photoOutput : AVCapturePhotoOutput?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    
        loadCamera()
        let tap = UITapGestureRecognizer(target: self, action: #selector(swapCamera))
        tap.numberOfTapsRequired = 2
        previewView.addGestureRecognizer(tap)
    }
    
    @objc func swapCamera() {
        if(frontCameraMode == true){
            frontCameraMode = false
        }
        else if(frontCameraMode == false){
            frontCameraMode = true
        }
        loadCamera()
    }
    
    func loadCamera() {
    
        if(frontCameraMode == false){
            var device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)
        }
        else if (frontCameraMode == true){
            var device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .front)
        }
        do{
            var deviceInput = try AVCaptureDeviceInput(device: device!)
            print(deviceInput)
            session.sessionPreset = AVCaptureSession.Preset.high
            /*if let inputs = session.inputs as? [AVCaptureDeviceInput] {
                for input in inputs {
                    session.removeInput(input)
                }
            }*/
    
            if session.inputs.isEmpty {
                session.addInput(deviceInput)
            }
    
            var previewLayer = AVCaptureVideoPreviewLayer(session: session)
    
            previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
            previewLayer.frame = view.layer.bounds
    
            previewView.layer.addSublayer(previewLayer)
    
            session.startRunning()
    
            photoOutput = AVCapturePhotoOutput()
            session.addOutput(photoOutput!)
        }
        catch{
            print(error)
        }
    }
    
    @IBAction func onShootButtonTap(_ sender: Any) {
        // Make sure capturePhotoOutput is valid
        guard let photoOutput = self.photoOutput else { return }
        // Get an instance of AVCapturePhotoSettings class
    
        let photoSettings = AVCapturePhotoSettings()
        // Set photo settings for our need
    
        photoSettings.isAutoStillImageStabilizationEnabled = true
    
        //photoSettings.isHighResolutionPhotoEnabled = true
        photoSettings.flashMode = .auto
        // Call capturePhoto method by passing our photo settings and a
        // delegate implementing AVCapturePhotoCaptureDelegate
    
        photoOutput.capturePhoto(with: photoSettings, delegate: self)
    
    }
    
    
    @available(iOS 11.0, *)
    func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
        let imageData = photo.fileDataRepresentation()
    
        let capturedImage = UIImage.init(data: imageData! , scale: 1.0)
        if let image = capturedImage {
            // Save our captured image to photos album
            UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
        }
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    
    }
    
    3 回复  |  直到 8 年前
        1
  •  1
  •   iOS Developer    8 年前

    在添加输入和输出之前,需要检查会话的canAddInput和canAddOutput

    session.beginConfiguration()
    session.sessionPreset = AVCaptureSession.Preset.photo
    let cameraPosition: AVCaptureDevice.Position = self.configuration.usesFrontCamera ? .front : .back
    let aDevice = deviceForPosition(cameraPosition)
    if let d = aDevice {
       videoInput = try? AVCaptureDeviceInput(device: d)
    }
    if let videoInput = videoInput {
       if session.canAddInput(videoInput) {
          session.addInput(videoInput)
       }
       if session.canAddOutput(imageOutput) {
          session.addOutput(imageOutput)
       }
    }
    session.commitConfiguration()
    
    //A helper function for device position
    func deviceForPosition(_ p: AVCaptureDevice.Position) -> AVCaptureDevice? {
        for device in AVCaptureDevice.devices(for: AVMediaType.video) where device.position == p {
            return device
        }
        return nil
    }
    

    我建议您不要重新发明轮子,而是使用此资源- https://github.com/Yummypets/YPImagePicker

        2
  •  0
  •   Jabson    8 年前

    每次按“交换”按钮时,都会使用已使用的摄影机会话创建新的摄影机预览层,这会导致崩溃。要修复:

    为当前设备输入声明新变量

    var deviceInput: AVCaptureDeviceInput?
    

    更改swapCamera函数以更改设备的前后输入,并将输入保存在上面声明的变量中,以便在第二次交换中删除。

    @objc func swapCamera() {
        frontCameraMode = !frontCameraMode
        let newDeviceInput = try! AVCaptureDeviceInput(device: device!)
    
        session.beginConfiguration()
        if(frontCameraMode == false){
            device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)
            session.removeInput(deviceInput!)
            session.addInput(newDeviceInput)
        }
        else if (frontCameraMode == true){
            device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .front)
            session.removeInput(deviceInput!)
            session.addInput(newDeviceInput)
        }
        session.commitConfiguration();
    
        deviceInput = newDeviceInput
    }
    

    删除loadCamera函数中的局部let变量

    改变

    let deviceInput = try AVCaptureDeviceInput(device: device!)
    

    deviceInput = try AVCaptureDeviceInput(device: device!)
    
        3
  •  0
  •   Aleem    8 年前

    确保为 Privacy - Camera Usage Description 输入您的 Info.plist 请求摄像头访问时的文件。