Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Toggle camera using AVFoundation iOS 6

I want to toggle camera using AVFoundation. Here is my code I have subclass of NSObject as

@interface CaptureSessionManager : NSObject

@property (retain) AVCaptureVideoPreviewLayer *previewLayer;
@property (retain) AVCaptureSession *captureSession;
@property (retain) AVCaptureStillImageOutput *stillImageOutput;
@property (nonatomic, retain) UIImage *stillImage;

In @implementation CaptureSessionManager

    - (id)init {
    if ((self = [super init])) {
        [self setCaptureSession:[[AVCaptureSession alloc] init]];
    }
    return self;
}

- (void)addVideoPreviewLayer {
    [self setPreviewLayer:[[[AVCaptureVideoPreviewLayer alloc] initWithSession:[self captureSession]] autorelease]];
    [[self previewLayer] setVideoGravity:AVLayerVideoGravityResizeAspectFill];

}

- (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");
            }
        }
    }
}

- (void)addStillImageOutput 
{
  [self setStillImageOutput:[[[AVCaptureStillImageOutput alloc] init] autorelease]];
  NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG,AVVideoCodecKey,nil];
  [[self stillImageOutput] setOutputSettings:outputSettings];

  AVCaptureConnection *videoConnection = nil;
  for (AVCaptureConnection *connection in [[self stillImageOutput] connections]) {
    for (AVCaptureInputPort *port in [connection inputPorts]) {
      if ([[port mediaType] isEqual:AVMediaTypeVideo] ) {
        videoConnection = connection;
        break;
      }
    }
    if (videoConnection) { 
      break; 
    }
  }

  [[self captureSession] addOutput:[self stillImageOutput]];
}

- (void)captureStillImage
{  
    AVCaptureConnection *videoConnection = nil;
    for (AVCaptureConnection *connection in [[self stillImageOutput] connections]) {
        for (AVCaptureInputPort *port in [connection inputPorts]) {
            if ([[port mediaType] isEqual:AVMediaTypeVideo]) {
                videoConnection = connection;
                break;
            }
        }
        if (videoConnection) { 
      break; 
    }
    }

    NSLog(@"about to request a capture from: %@", [self stillImageOutput]);
    [[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection 
                                                       completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error) { 
                                                         CFDictionaryRef exifAttachments = CMGetAttachment(imageSampleBuffer, kCGImagePropertyExifDictionary, NULL);
                                                         if (exifAttachments) {
                                                           NSLog(@"attachements: %@", exifAttachments);
                                                         } else { 
                                                           NSLog(@"no attachments");
                                                         }
                                                         NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];    
                                                         UIImage *image = [[UIImage alloc] initWithData:imageData];
                                                         [self setStillImage:image];
                                                         [image release];
                                                         [[NSNotificationCenter defaultCenter] postNotificationName:kImageCapturedSuccessfully object:nil];
                                                       }];
}

- (void)dealloc {

    [[self captureSession] stopRunning];

    [previewLayer release], previewLayer = nil;
    [captureSession release], captureSession = nil;
  [stillImageOutput release], stillImageOutput = nil;
  [stillImage release], stillImage = nil;

    [super dealloc];
}

-(void)toggleCamera:(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;
            }
        }
    }
    [[self captureSession] beginConfiguration];
    NSError *error = nil;
    AVCaptureDeviceInput *frontFacingCameraDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:frontCamera error:&error];
    AVCaptureDeviceInput *backFacingCameraDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:backCamera error:&error];
    if (front)
    {
        [[self captureSession] removeInput:backFacingCameraDeviceInput];
        if (!error) {
            if ([[self captureSession] canAddInput:frontFacingCameraDeviceInput]) {
                [[self captureSession] addInput:frontFacingCameraDeviceInput];
            } else {
                NSLog(@"Couldn't add front facing video input");
            }
            [[self captureSession] addInput:frontFacingCameraDeviceInput];
        }
    } else
    {
        [[self captureSession] removeInput:frontFacingCameraDeviceInput];
        if (!error) {
            if ([[self captureSession] canAddInput:backFacingCameraDeviceInput]) {
                [[self captureSession] addInput:backFacingCameraDeviceInput];
            } else {
                NSLog(@"Couldn't add back facing video input");
            }
            [[self captureSession] addInput:backFacingCameraDeviceInput];
        }
    }

    [[self captureSession] commitConfiguration];
}

In my ViewController , I have

@property (retain) CaptureSessionManager *captureManager;
@property (nonatomic,readwrite) BOOL isFrontCameraSelected;

    - (void)viewDidLoad
{
    self.isFrontCameraSelected = NO;

    [self setCaptureManager:[[[CaptureSessionManager alloc] init] autorelease]];

    [[self captureManager] addVideoInputFrontCamera:self.isFrontCameraSelected]; // set to YES for Front Camera, No for Back camera

    [[self captureManager] addStillImageOutput];

    [[self captureManager] addVideoPreviewLayer];
    CGRect layerRect = [[[self innerview] layer] bounds];
    [[[self captureManager] previewLayer] setBounds:layerRect];
    [[[self captureManager] previewLayer] setPosition:CGPointMake(CGRectGetMidX(layerRect),CGRectGetMidY(layerRect))];
    [[[self innerview] layer] addSublayer:[[self captureManager] previewLayer]];

    UIImageView *overlayImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"overlaygraphic.png"]];
    [overlayImageView setFrame:CGRectMake(30, 60, 260, 260)];
    [[self innerview] addSubview:overlayImageView];
    [overlayImageView release];

    UIButton *overlayButton3 = [UIButton buttonWithType:UIButtonTypeCustom];
    [overlayButton3 setImage:[UIImage imageNamed:@"camera.png"] forState:UIControlStateNormal];
    [overlayButton3 setFrame:CGRectMake(130, 330, 60, 30)];
    [overlayButton3 addTarget:self action:@selector(innerscanButtonPressed) forControlEvents:UIControlEventTouchUpInside];
    [[self innerview] addSubview:overlayButton3];

    UIButton *cameraSelection = [UIButton buttonWithType:UIButtonTypeCustom];
    [cameraSelection setImage:[UIImage imageNamed:@"camera.png"] forState:UIControlStateNormal];
    [cameraSelection setFrame:CGRectMake(260, 30, 60, 30)];
    [cameraSelection addTarget:self action:@selector(cameraSelectionTapped:) forControlEvents:UIControlEventTouchUpInside];
    [[self innerview] addSubview:cameraSelection];

  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(saveImageToPhotoAlbum) name:kImageCapturedSuccessfully object:nil];

    [[captureManager captureSession] startRunning];
}

- (void)innerscanButtonPressed {

    [[self scanningLabel] setHidden:NO];
    [[self captureManager] captureStillImage];

}

-(void)cameraSelectionTapped:(id)sender
{
    [[self captureManager] toggleCamera:self.isFrontCameraSelected];
}

When I click on toggleCamera button , it crashes with below error

Couldn't add back facing video input
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** Multiple audio/video AVCaptureInputs are not currently supported.'
*** First throw call stack:
(0x38f2f2a3 0x3725997f 0x39aff977 0x39aff091 0xe943d 0xe7875 0x3a4de0a5 0x3a4de057 0x3a4de035 0x3a4dd8eb 0x3a4ddde1 0x3a4065f1 0x3a3f3801 0x3a3f311b 0x37cad5a3 0x37cad1d3 0x38f04173 0x38f04117 0x38f02f99 0x38e75ebd 0x38e75d49 0x37cac2eb 0x3a4472f9 0xdf1ab 0x36324b20)

I want to add toggle feature so that user can use front / back camera to click photo.

Any kind of help is highly appreciated. Thanks in advance.

like image 269
iOSAppDev Avatar asked Nov 29 '25 23:11

iOSAppDev


1 Answers

You're trying to add the same device input twice in this code:

if (!error) {
        if ([[self captureSession] canAddInput:frontFacingCameraDeviceInput]) {
            [[self captureSession] addInput:frontFacingCameraDeviceInput];
        } else {
            NSLog(@"Couldn't add front facing video input");
        }
        [[self captureSession] addInput:frontFacingCameraDeviceInput];
    }

Take out that second call to addInput on both the front and back logic.

like image 185
CEarwood Avatar answered Dec 02 '25 18:12

CEarwood



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!