3

I was creating my custom camera view using swift 3 and xcode.

I have got it to work, but i am facing a small issue. To switch camera device from front/back i stop the session, remove the video preview layer from the view and then create a new session and add a new video preview layer from the front camera. This makes the new camera come on with a jerk. I want smooth transition between the camera devices. How can i do that?

Here my code for loading the camera:

func loadCamera()
{

    session?.stopRunning()
    videoPreviewLayer?.removeFromSuperlayer()

    session = AVCaptureSession()
    session!.sessionPreset = AVCaptureSessionPresetPhoto


    var backCamera = AVCaptureDevice.defaultDevice(withDeviceType: .builtInWideAngleCamera, mediaType: AVMediaTypeVideo, position: .front)

    if cameraPos == "back"
    {
        backCamera = AVCaptureDevice.defaultDevice(withDeviceType: .builtInWideAngleCamera, mediaType: AVMediaTypeVideo, position: .back)
    }

    var error: NSError?
    var input: AVCaptureDeviceInput!
    do {
        input = try AVCaptureDeviceInput(device: backCamera)
    } catch let error1 as NSError {
        error = error1
        input = nil
        print(error!.localizedDescription)
    }

    if error == nil && session!.canAddInput(input) {
        session!.addInput(input)

        stillImageOutput = AVCapturePhotoOutput()


        if session!.canAddOutput(stillImageOutput) {
            session!.addOutput(stillImageOutput)


            videoPreviewLayer = AVCaptureVideoPreviewLayer(session: session)

            videoPreviewLayer?.frame = cameraView.bounds
            videoPreviewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
            videoPreviewLayer?.connection.videoOrientation = AVCaptureVideoOrientation.portrait


            cameraView.layer.addSublayer(videoPreviewLayer!)
            session!.startRunning()

        }   
    }
}

I call this from viewWillAppear

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    loadCamera()
}

and i call load camera when user clicks on change camera

@IBAction func changeCamera(_ sender: UIButton) {

    if cameraPos == "back"
    {cameraPos = "front"}

    else
    {cameraPos = "back"}


    loadCamera()
}
charak
  • 187
  • 3
  • 15

2 Answers2

1

In loadCamera() you'll need to create an AVCaptureInput from the front capture device. It's good practice to hold both the back input and the front input on some camera singleton. The smooth transition between front and back can be done by removing all inputs then assigning another input.

func show(back: Bool) {
  session.beginConfiguration()
  if let inputs = session.inputs as? [AVCaptureDeviceInput] {
    for input in inputs {
      session.removeInput(input)
    }
  }
  if back {
    if session.canAddInput(backInput) {
      session.addInput(backInput)
    }
  } else {
    if session.canAddInput(frontInput) {
      session.addInput(frontInput)
    }
  }
  session.commitConfiguration()
}
jnblanchard
  • 1,182
  • 12
  • 12
0

Call the loadCamera() function inside viewDidAppear instead of viewWillAppear

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(true)
    loadCamera()
}

Background thread:

DispatchQueue.global(qos: .background).async {

    // perform ui updation and web related code
    // background thread

    DispatchQueue.main.async {
        // main thread
    }
}
vaibhav
  • 4,038
  • 1
  • 21
  • 51
  • you can use the background threads also to perform some uicomponents update. – vaibhav Dec 13 '16 at 13:01
  • any suggestion or link you can share i can look at? – charak Dec 13 '16 at 13:03
  • you cant do heavy task inside `viewWillAppear`, see [difference](http://stackoverflow.com/questions/5630649/what-is-the-difference-between-viewwillappear-and-viewdidappear) before you code further please. – vaibhav Dec 13 '16 at 13:26