Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Switch cameras with avcapturesession

Using this tutorial here: http://www.musicalgeometry.com/?p=1297 I have created a custom overlay and image capture with AVCaptureSession.

I am attempting to allow the user to switch between the front and back camera. Here is my code in CaptureSessionManager to switch cameras:

- (void)addVideoInputFrontCamera:(BOOL)front {     NSArray *devices = [AVCaptureDevice devices];     AVCaptureDevice *frontCamera;     AVCaptureDevice *backCamera;      for (AVCaptureDevice *device in devices) {          //NSLog(@"Device name: %@", [device localizedName]);          if ([device hasMediaType:AVMediaTypeVideo]) {              if ([device position] == AVCaptureDevicePositionBack) {                 //NSLog(@"Device position : back");                 backCamera = device;             }             else {                 //NSLog(@"Device position : front");                 frontCamera = device;             }         }     }      NSError *error = nil;      if (front) {         AVCaptureDeviceInput *frontFacingCameraDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:frontCamera error:&error];         if (!error) {             if ([[self captureSession] canAddInput:frontFacingCameraDeviceInput]) {                 [[self captureSession] addInput:frontFacingCameraDeviceInput];             } else {                 NSLog(@"Couldn't add front facing video input");             }         }     } else {         AVCaptureDeviceInput *backFacingCameraDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:backCamera error:&error];         if (!error) {             if ([[self captureSession] canAddInput:backFacingCameraDeviceInput]) {                 [[self captureSession] addInput:backFacingCameraDeviceInput];             } else {                 NSLog(@"Couldn't add back facing video input");             }         }     } } 

Now in my custom overlay controller I initialize everything like so in viewDidLoad:

[self setCaptureManager:[[CaptureSessionManager alloc] init]];  [[self captureManager] addVideoInputFrontCamera:NO]; // set to YES for Front Camera, No for Back camera  [[self captureManager] addStillImageOutput];  [[self captureManager] addVideoPreviewLayer]; CGRect layerRect = [[[self view] layer] bounds]; [[[self captureManager] previewLayer] setBounds:layerRect]; [[[self captureManager] previewLayer] setPosition:CGPointMake(CGRectGetMidX(layerRect),CGRectGetMidY(layerRect))]; [[[self view] layer] addSublayer:[[self captureManager] previewLayer]];  [[_captureManager captureSession] startRunning]; 

The switch camera button is connected to a method called switchCamera. I have tried this:

- (void)switchCameraView:(id)sender {      [[self captureManager] addVideoInputFrontCamera:YES]; // set to YES for Front Camera, No for Back camera  } 

When calling this, I get the error NSLog from the CaptureSessionManager and I cannot figure out why. In viewDidLoad, if I set the fontCamera to YES, it shows the front camera but cannot switch to back, and vice versa.

Any ideas on how to get it to switch properly?

like image 855
Kyle Begeman Avatar asked Dec 31 '13 23:12

Kyle Begeman


2 Answers

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; } 
like image 105
NES_4Life Avatar answered Oct 06 '22 01:10

NES_4Life


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 found func 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 found func 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 found func 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 } 
like image 38
chengsam Avatar answered Oct 06 '22 01:10

chengsam