-->

Switch between front and back camera

2019-07-10 16:18发布

问题:

I'm trying to make a custom cameraView, which works so far. However i've reached an issue with switching between front and back camera. I've tried to handle it through a custom enum. However when the switchCamera method is called. it just seem to freeze the camera? How come is that?

Camera Variable

var camera = CameraType.Back

viewDidLoad

    switchButton = UIButton(frame: CGRectMake(rightButtonXPoint, 35, 30, 30))
    switchButton.setImage(UIImage(named: "Switch"), forState: UIControlState.Normal)
    switchButton.addTarget(self, action: "switchCamera", forControlEvents: UIControlEvents.TouchUpInside)
    actionView.addSubview(switchButton)

ViewWillAppear

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

    reloadCamera()


}

SwitchCamera

func switchCamera() {

    if camera == CameraType.Back {
        camera = CameraType.Front
    } else {
        camera = CameraType.Back
    }
    reloadCamera()
}

ReloadCamera

func reloadCamera() {

    captureSession = AVCaptureSession()


   // let backCamera = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
    var captureDevice:AVCaptureDevice! = nil
    if (camera == CameraType.Front) {
        let videoDevices = AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo)

        for device in videoDevices{
            let device = device as! AVCaptureDevice
            if device.position == AVCaptureDevicePosition.Front {
                captureDevice = device
                break
            }
        }
    } else {
        captureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
    }

    do {
        let input = try? AVCaptureDeviceInput(device: captureDevice)

        if (captureSession?.canAddInput(input) != nil){

            captureSession?.addInput(input)

            stillImageOutput = AVCaptureStillImageOutput()
            stillImageOutput?.outputSettings = [AVVideoCodecKey : AVVideoCodecJPEG]

            if (captureSession?.canAddOutput(stillImageOutput) != nil){
                captureSession?.addOutput(stillImageOutput)

                previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)

                previewLayer?.videoGravity = AVLayerVideoGravityResizeAspect
                previewLayer?.connection.videoOrientation = AVCaptureVideoOrientation.Portrait
                cameraView.layer.addSublayer(previewLayer!)
                captureSession?.startRunning()

            }

            cameraView.bringSubviewToFront(actionView)
            previewImageView.bringSubviewToFront(actionView)
            self.previewImageView.hidden = true


        }
    }







}

回答1:

Without knowing the exact specifics, it's hard to guess, but looking at your code, I think the problem you're running into is that you're trying to add more than one camera to the session (each time you switch, you're actually trying to add a new device).

Test to see if the capture session is running, then if it is, then REMOVE the existing device (back / front camera) before adding the new device. Make sure you wrap it as a transaction like so:

func beginSession(captureDevice : AVCaptureDevice?) {        

    if captureSession.running {
        captureSession.beginConfiguration()

        let currentInput : AVCaptureInput = captureSession.inputs[0] as! AVCaptureInput
        captureSession.removeInput(currentInput)

        do {
            try captureSession.addInput(AVCaptureDeviceInput(device: captureDevice))
        } catch {
            print("Error adding video input device")
        }

        captureSession.commitConfiguration()

    } else {
        // Setup the camera and layer for the first time.
        do {
            try captureSession.addInput(AVCaptureDeviceInput(device: captureDevice))
        } catch {
            print("Error adding video input device")
        }


        previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
        self.view.layer.insertSublayer(previewLayer!, atIndex: 0)
        previewLayer?.frame = self.view.layer.frame
        captureSession.startRunning()
    }
}

This is a fairly simple, but functional example. I just pass the capture device in each time (Front / Back camera as needed) and it works well enough in my code. Very prototype implementation, but hopefully this gives you the missing steps:

  1. .beginConfiguration() BEFORE changing a running session.
  2. Remove the existing device then add the new one.
  3. .commitConfiguration() to make it all work.

No need to remove the preview layer as it's already hooked up to your currentSession anyway.