Search code examples
iosswiftavcapturesession

Begin new captureSession without removing previewLayer


I'm creating a customView for the CameraView, which works fine however i'm now working on changing from the back camera to the front camera. i've at the moment done it by doing below. However this seem to create a bad user experience where it removes the previewLayer (the screen becomes white) and then show the front camera correctly. is there a way to create a better user experience by not making everything white in 1 sec before showing the new session?

switchCamera

func switchCamera() {
    if usingbackCamera == true {
        endSession()
        beginSession(frontCamera!)
        usingbackCamera = false
        self.cameraView.bringSubviewToFront(actionView)

    } else {
        endSession()
        beginSession(backCamera!)
        usingbackCamera = true
        self.cameraView.bringSubviewToFront(actionView)
    }
}

beginSession

func beginSession(device: AVCaptureDevice) {

    do {
        captureSession.addInput(try AVCaptureDeviceInput(device: device))
        self.previewLayer?.removeFromSuperlayer()
        previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)

        self.cameraView.layer.addSublayer(previewLayer!)

        previewLayer?.frame = self.cameraView.bounds
        captureSession.startRunning()

        stillImageOutput.outputSettings = [AVVideoCodecKey:AVVideoCodecJPEG]
        if captureSession.canAddOutput(stillImageOutput) {
            captureSession.addOutput(stillImageOutput)
        }
        if captureSession.canAddOutput(videoOutput) {
            captureSession.addOutput(videoOutput)
        }



    } catch let err as NSError {
        print(err)
    }

}

endSession

func endSession() {
    self.previewLayer?.removeFromSuperlayer()
    captureSession.stopRunning()
    captureSession = AVCaptureSession()

}

Take Picture

func takePicture() {


    if let videoConnection = stillImageOutput.connectionWithMediaType(AVMediaTypeVideo){
        videoConnection.videoOrientation = AVCaptureVideoOrientation.Portrait
        stillImageOutput.captureStillImageAsynchronouslyFromConnection(videoConnection, completionHandler: {
            (sampleBuffer, error) in


                let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer)
                let dataProvider  = CGDataProviderCreateWithCFData(imageData)
                let cgImageRef = CGImageCreateWithJPEGDataProvider(dataProvider, nil, true, CGColorRenderingIntent.RenderingIntentDefault)

                let image = UIImage(CGImage: cgImageRef!, scale: 1.0, orientation: UIImageOrientation.Right)

                self.previewImageView.image = image
                self.previewImageView.hidden = false
                self.cameraView.bringSubviewToFront(self.previewImageView)





        })
    }


}

Solution

  • You don't need to stop the captureSession and start it again when switching from back to front camera and vice versa.

    All you need to do is remove the old capture session inputs, add the new one and all that in between a begin/commit session configuration block.

    Here is a rough example:

      func switchCamera() {
        //begin configuration changes
        captureSession.beginConfiguration()
    
        //remove the previous inputs
        let inputs = captureSession.inputs as! [AVCaptureInput]
        for oldInput:AVCaptureInput in inputs {
            captureSession.removeInput(oldInput)
        }
    
        //add the new input
        if usingbackCamera == true {
            addInput(frontCamera!)
            usingbackCamera = false
            self.cameraView.bringSubviewToFront(actionView)
    
        }
        else {
            addInput(backCamera!)
            usingbackCamera = true
            self.cameraView.bringSubviewToFront(actionView)
        }
    
        //end the configuration
        captureSession.commitConfiguration()
    }
    
    
    func addInput(device: AVCaptureDevice) {
    
        do {
            captureSession.addInput(try AVCaptureDeviceInput(device: device))
    
        } catch let err as NSError {
            print(err)
        }
    
    }