Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a button to change the camera view in Swift?

I would like to know how I could change the camera view when I press a button. At the moment, I am using a boolean var camera = false and when I press a button, I want to change the value to true and get the other camera. But that is not working. I now have this:

 @IBAction func changeCamera(sender: AnyObject) {

    camera = true

}

override func viewWillAppear(animated: Bool) {

    captureSession = AVCaptureSession()
    captureSession!.sessionPreset = AVCaptureSessionPresetPhoto
    var captureDevice:AVCaptureDevice! = nil
    //var backCamera = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
    if (camera == false){
    let videoDevices = AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo)


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

    }

    var error: NSError?
    var input = AVCaptureDeviceInput(device: captureDevice, error: &error)

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

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

            previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
            previewLayer!.videoGravity = AVLayerVideoGravityResizeAspect
            previewLayer!.connection?.videoOrientation = AVCaptureVideoOrientation.Portrait
            previewView.layer.addSublayer(previewLayer)

            captureSession!.startRunning()
        }
    }

}
like image 962
mindfreek Avatar asked Mar 22 '15 14:03

mindfreek


1 Answers

The problem lies where you are setting the camera source.

You are setting it in viewDidAppear which will only be called when the view appears on the device. This is whenever you navigate to that view controller from another or close a presented view controller that is being presented by this one.

My suggestion would be to move the camera selection code into its own function that is called by both viewDidLoad and also whenever the changeCamera action is called.

@IBAction func changeCamera(sender: AnObject?) {
    camera = !camera

    reloadCamera()
}


func viewDidAppear(animated: Bool) {
    // normal code

    reloadCamera()
}

func reloadCamera() {
    // camera loading code
    captureSession = AVCaptureSession()
    captureSession!.sessionPreset = AVCaptureSessionPresetPhoto
    var captureDevice:AVCaptureDevice! = nil
    // var backCamera = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
    if (camera == false) {
        let videoDevices = AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo)


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

    var error: NSError?
    var input = AVCaptureDeviceInput(device: captureDevice, error: &error)

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

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

        previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
        previewLayer!.videoGravity = AVLayerVideoGravityResizeAspect
        previewLayer!.connection?.videoOrientation = AVCaptureVideoOrientation.Portrait
        previewView.layer.addSublayer(previewLayer)

        captureSession!.startRunning()
    }
}

Also, an additional improvement would be to use a custom enum to store which camera is currently in use rather than a Boolean. This means you can add to it later say if there was ever a third camera. This would look like:

enum CameraType {
    case front
    case back
}

var camera = CameraType.back

I hope this helps, apologies for omitting the full code examples, currently on an iPad but I'll update when I get to a computer.


Update

Make sure you remove the previous preview layer from the view before you change the camera.

func reloadCamera() {
    captureSession?.stopRunning()
    previewLayer?.removeFromSuperlayer()

    // The rest of the camera loading code...

This should fix your camera freezing issue.

like image 107
Elliott Minns Avatar answered Nov 03 '22 01:11

Elliott Minns