Switch cameras with avcapturesession Switch cameras with avcapturesession ios ios

Switch cameras with avcapturesession


You first need to remove the existing AVCameraInput from the AVCaptureSession and then add a new AVCameraInput to the AVCaptureSession. The following works for me (under ARC):

-(IBAction)switchCameraTapped:(id)sender{    //Change camera source    if(_captureSession)    {        //Indicate that some changes will be made to the session        [_captureSession beginConfiguration];        //Remove existing input        AVCaptureInput* currentCameraInput = [_captureSession.inputs objectAtIndex:0];        [_captureSession removeInput:currentCameraInput];        //Get new input        AVCaptureDevice *newCamera = nil;        if(((AVCaptureDeviceInput*)currentCameraInput).device.position == AVCaptureDevicePositionBack)        {            newCamera = [self cameraWithPosition:AVCaptureDevicePositionFront];        }        else        {            newCamera = [self cameraWithPosition:AVCaptureDevicePositionBack];        }        //Add input to session        NSError *err = nil;        AVCaptureDeviceInput *newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:newCamera error:&err];        if(!newVideoInput || err)        {            NSLog(@"Error creating capture device input: %@", err.localizedDescription);        }        else        {            [_captureSession addInput:newVideoInput];        }        //Commit all the configuration changes at once        [_captureSession commitConfiguration];    }}// Find a camera with the specified AVCaptureDevicePosition, returning nil if one is not found- (AVCaptureDevice *) cameraWithPosition:(AVCaptureDevicePosition) position{    NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];    for (AVCaptureDevice *device in devices)     {        if ([device position] == position) return device;    }    return nil;}


Swift 4/5

@IBAction func switchCameraTapped(sender: Any) {    //Change camera source    if let session = captureSession {        //Remove existing input        guard let currentCameraInput: AVCaptureInput = session.inputs.first else {            return        }        //Indicate that some changes will be made to the session        session.beginConfiguration()        session.removeInput(currentCameraInput)        //Get new input        var newCamera: AVCaptureDevice! = nil        if let input = currentCameraInput as? AVCaptureDeviceInput {            if (input.device.position == .back) {                newCamera = cameraWithPosition(position: .front)            } else {                newCamera = cameraWithPosition(position: .back)            }        }        //Add input to session        var err: NSError?        var newVideoInput: AVCaptureDeviceInput!        do {            newVideoInput = try AVCaptureDeviceInput(device: newCamera)        } catch let err1 as NSError {            err = err1            newVideoInput = nil        }        if newVideoInput == nil || err != nil {            print("Error creating capture device input: \(err?.localizedDescription)")        } else {            session.addInput(newVideoInput)        }        //Commit all the configuration changes at once        session.commitConfiguration()    }}// Find a camera with the specified AVCaptureDevicePosition, returning nil if one is not foundfunc cameraWithPosition(position: AVCaptureDevice.Position) -> AVCaptureDevice? {    let discoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .unspecified)    for device in discoverySession.devices {        if device.position == position {            return device        }    }    return nil}

Swift 3 Edit (Combined with François-Julien Alcaraz answer):

@IBAction func switchCameraTapped(sender: Any) {    //Change camera source    if let session = captureSession {        //Indicate that some changes will be made to the session        session.beginConfiguration()        //Remove existing input        guard let currentCameraInput: AVCaptureInput = session.inputs.first as? AVCaptureInput else {            return        }        session.removeInput(currentCameraInput)        //Get new input        var newCamera: AVCaptureDevice! = nil        if let input = currentCameraInput as? AVCaptureDeviceInput {            if (input.device.position == .back) {                newCamera = cameraWithPosition(position: .front)            } else {                newCamera = cameraWithPosition(position: .back)            }        }        //Add input to session        var err: NSError?        var newVideoInput: AVCaptureDeviceInput!        do {            newVideoInput = try AVCaptureDeviceInput(device: newCamera)        } catch let err1 as NSError {            err = err1            newVideoInput = nil        }        if newVideoInput == nil || err != nil {            print("Error creating capture device input: \(err?.localizedDescription)")        } else {            session.addInput(newVideoInput)        }        //Commit all the configuration changes at once        session.commitConfiguration()    }}// Find a camera with the specified AVCaptureDevicePosition, returning nil if one is not foundfunc cameraWithPosition(position: AVCaptureDevicePosition) -> AVCaptureDevice? {    if let discoverySession = AVCaptureDeviceDiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaTypeVideo, position: .unspecified) {        for device in discoverySession.devices {            if device.position == position {                return device            }        }    }    return nil}

Swift version to @NES_4Life's answer:

@IBAction func switchCameraTapped(sender: AnyObject) {    //Change camera source    if let session = captureSession {        //Indicate that some changes will be made to the session        session.beginConfiguration()        //Remove existing input        let currentCameraInput:AVCaptureInput = session.inputs.first as! AVCaptureInput        session.removeInput(currentCameraInput)        //Get new input        var newCamera:AVCaptureDevice! = nil        if let input = currentCameraInput as? AVCaptureDeviceInput {            if (input.device.position == .Back)            {                newCamera = cameraWithPosition(.Front)            }            else            {                newCamera = cameraWithPosition(.Back)            }        }        //Add input to session        var err: NSError?        var newVideoInput: AVCaptureDeviceInput!        do {            newVideoInput = try AVCaptureDeviceInput(device: newCamera)        } catch let err1 as NSError {            err = err1            newVideoInput = nil        }        if(newVideoInput == nil || err != nil)        {            print("Error creating capture device input: \(err!.localizedDescription)")        }        else        {            session.addInput(newVideoInput)        }        //Commit all the configuration changes at once        session.commitConfiguration()    }}// Find a camera with the specified AVCaptureDevicePosition, returning nil if one is not foundfunc cameraWithPosition(position: AVCaptureDevicePosition) -> AVCaptureDevice?{    let devices = AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo)    for device in devices {        let device = device as! AVCaptureDevice        if device.position == position {            return device        }    }    return nil}


Based on previous answers I made my own version with some validations and one specific change, the current camera input might not be the first object of the capture session's inputs, so I changed this:

//Remove existing inputAVCaptureInput* currentCameraInput = [self.captureSession.inputs objectAtIndex:0];[self.captureSession removeInput:currentCameraInput];

To this (removing all video type inputs):

for (AVCaptureDeviceInput *input in self.captureSession.inputs) {    if ([input.device hasMediaType:AVMediaTypeVideo]) {        [self.captureSession removeInput:input];        break;    }}

Here's the entire code:

if (!self.captureSession) return;[self.captureSession beginConfiguration];AVCaptureDeviceInput *currentCameraInput;// Remove current (video) inputfor (AVCaptureDeviceInput *input in self.captureSession.inputs) {    if ([input.device hasMediaType:AVMediaTypeVideo]) {        [self.captureSession removeInput:input];        currentCameraInput = input;        break;    }}if (!currentCameraInput) return;// Switch device positionAVCaptureDevicePosition captureDevicePosition = AVCaptureDevicePositionUnspecified;if (currentCameraInput.device.position == AVCaptureDevicePositionBack) {    captureDevicePosition = AVCaptureDevicePositionFront;} else {    captureDevicePosition = AVCaptureDevicePositionBack;}// Select new cameraAVCaptureDevice *newCamera;NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];for (AVCaptureDevice *captureDevice in devices) {    if (captureDevice.position == captureDevicePosition) {        newCamera = captureDevice;    }}if (!newCamera) return;// Add new camera inputNSError *error;AVCaptureDeviceInput *newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:newCamera error:&error];if (!error && [self.captureSession canAddInput:newVideoInput]) {    [self.captureSession addInput:newVideoInput];}[self.captureSession commitConfiguration];