AVFoundation: toggle camera fails at CanAddInput

1.7k views Asked by At

I am trying to add a rotate camera function with AVFoundation to allow the user to toggle between the front-facing and back-facing cameras.

As shown in the code below, I've put in some println() statements and all the values seem legit but the code always drops to the failed else-clause when testing CanAddInput().

I've tried setting the sessionPreset (which is in another function that initializes the session beforehand) to various values including AVCaptureSessionPresetHigh and AVCaptureSessionPresetLow but that didn't help.

@IBAction func rotateCameraPressed(sender: AnyObject) {

    // Loop through all the capture devices to find right ones
    var backCameraDevice : AVCaptureDevice?
    var frontCameraDevice : AVCaptureDevice?
    let devices = AVCaptureDevice.devices()
    for device in devices {
        // Make sure this particular device supports video
        if (device.hasMediaType(AVMediaTypeVideo)) {
            // Define devices
            if (device.position == AVCaptureDevicePosition.Back) {
                backCameraDevice = device as? AVCaptureDevice
            } else if (device.position == AVCaptureDevicePosition.Front) {
                frontCameraDevice = device as? AVCaptureDevice
            }
        }
    }

    // Assign found devices to corresponding input
    var backInput : AVCaptureDeviceInput?
    var frontInput : AVCaptureDeviceInput?
    var error: NSError?
    if let backDevice = backCameraDevice {
        println("Back device is \(backDevice)")
        backInput = AVCaptureDeviceInput(device : backDevice, error: &error)
    }
    if let frontDevice = frontCameraDevice {
        println("Front device is \(frontDevice)")
        frontInput = AVCaptureDeviceInput(device : frontDevice, error: &error)
    }

    // Now rotate the camera
    isBackCamera = !isBackCamera  // toggle camera position
    if isBackCamera {
        // remove front and add back
        captureSession!.removeInput(frontInput)
        if let bi = backInput {
            println("Back input is \(bi)")
            if captureSession!.canAddInput(bi) {
                captureSession!.addInput(bi)
            } else {
                println("Cannot add back input!")
            }
        }
    } else {
        // remove back and add front
        captureSession!.removeInput(backInput)
        if let fi = frontInput {
            println("Front input is \(fi)")
            if captureSession!.canAddInput(fi) {
                captureSession!.addInput(fi)
            } else {
                println("Cannot add front input!")
            }
        }
    }
}
1

There are 1 answers

0
hitlad On BEST ANSWER

The problem seems to be the fact that the derived input from the devices found in the iteration do not actually match the input in the captureSession variable. This appears to be a new thing since all the code I've seen posted about this would find and remove the input for the current camera by iterating through the list of devices, as I've done in my code.

This doesn't seem to work anymore - well, at least not in the code I posted, which is based upon all the sources I've been able to dig up (that all happen to be in Objective C). The reason canAddInput() fails is that the removeInput() never succeeds; the fact that it doesn't issue the usual error about not being able to have multiple input devices is strange (since it would have helped with the debugging).

Anyway, the fix is to not remove the input on the derived input from the found device (which used to work). Instead, remove the input device that is actually there by going into the captureSession.inputs variable and doing a removeInput() on that.

To scrunch all that babble to code, here's what I did:

for ii in captureSession!.inputs {
  captureSession!.removeInput(ii as! AVCaptureInput)
}

And that did the trick! :)