2

My problem

I am using AVFoundation to capture the frames of the video output every 5 seconds. When the user taps a button, the input camera should switch from the front one to the back one and the opposite. Problem is, every time I switch the back camera to the front camera it freezes (oddly enough, it works the other way around - meaning, front camera to back camera)!

The code I use

To switch between the cameras, I use the exact code taken from Apple's AVCam sample code with a slight change of variable names (so it will match my code):

- (BOOL)toggleCamera
{
    BOOL success = NO;

    if ([self cameraCount] > 1) {
        NSError *error;
        AVCaptureDeviceInput *newVideoInput;
        AVCaptureDevicePosition position = [[self.videoInput device] position];

        if (position == AVCaptureDevicePositionBack)
            newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:[self frontFacingCamera] error:&error];

        else if (position == AVCaptureDevicePositionFront)
            newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:[self backFacingCamera] error:&error];

        else
            goto bail;

        if (newVideoInput != nil) {

            // Start configuring the session.
            [[self captureSession] beginConfiguration];

            // Remove the current video input device.
            [[self captureSession] removeInput:[self videoInput]];

            if ([[self captureSession] canAddInput:newVideoInput]) {
                [[self captureSession] addInput:newVideoInput];
                [self setVideoInput:newVideoInput];
            }

            else {
                [[self captureSession] addInput:[self videoInput]];
            }

            [[self captureSession] commitConfiguration];

            success = YES;
            [newVideoInput release];
        }

        else if (error) {
            NSLog(@"PICTURE TAKER: Failed to toggle cameras."
                  @"\nError: %@", error.localizedDescription);
        }
    }

bail:
    return success;
}

And to setup the AVCaptureSession, again, I use the exact same code from the AVCam sample code, with a slight change in the added output, (to match my needs):

- (BOOL) setupSession
{
    BOOL success = NO;

    // Set torch and flash mode to auto
    if ([[self backFacingCamera] hasFlash]) {
        if ([[self backFacingCamera] lockForConfiguration:nil]) {
            if ([[self backFacingCamera] isFlashModeSupported:AVCaptureFlashModeAuto]) {
                [[self backFacingCamera] setFlashMode:AVCaptureFlashModeAuto];
            }
            [[self backFacingCamera] unlockForConfiguration];
        }
    }
    if ([[self backFacingCamera] hasTorch]) {
        if ([[self backFacingCamera] lockForConfiguration:nil]) {
            if ([[self backFacingCamera] isTorchModeSupported:AVCaptureTorchModeAuto]) {
                [[self backFacingCamera] setTorchMode:AVCaptureTorchModeAuto];
            }
            [[self backFacingCamera] unlockForConfiguration];
        }
    }

    // Init the device inputs
    AVCaptureDeviceInput *newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:[self frontFacingCamera] error:nil];

    // Create a video output & configure it.
    AVCaptureVideoDataOutput *newVideoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
    newVideoDataOutput.videoSettings = @{(NSString *)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA)};

    // Set the output's delegate.
    dispatch_queue_t queue = dispatch_queue_create("MyQueue", NULL);
    [newVideoDataOutput setSampleBufferDelegate:self queue:queue];
    dispatch_release(queue);

    // Create session (use default AVCaptureSessionPresetHigh)
    AVCaptureSession *newCaptureSession = [[AVCaptureSession alloc] init];

    // Add inputs and output to the capture session
    if ([newCaptureSession canAddInput:newVideoInput]) {
        [newCaptureSession addInput:newVideoInput];
    }

    if ([newCaptureSession canAddOutput:newVideoDataOutput]) {
        [newCaptureSession addOutput:newVideoDataOutput];
    }

    [self setVideoOutput:newVideoDataOutput];
    [self setVideoInput:newVideoInput];
    [self setCaptureSession:newCaptureSession];

    [newVideoDataOutput release];
    [newVideoInput release];
    [newCaptureSession release];

    // Get our view's layer.
    CALayer *viewLayer = self.view.layer;

    // Add the the session's preview layer.
    AVCaptureVideoPreviewLayer *captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession];
    captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    captureVideoPreviewLayer.frame = self.view.bounds;
    [viewLayer insertSublayer:captureVideoPreviewLayer below:self.imageViewOverlay.layer];
    [captureVideoPreviewLayer release];

    success = YES;

    return success;
}

*Important note: the camera freezes right after the call to the output's delegate.

Can anyone please help me solve this? It seems as if I had tried almost everything!

Update #1

As requested, self is referring to a view controllers that presented the session's preview layer and manages all things related to the camera. In addition, I'm posting the code the handles the frontFacingCamera part, which is (just like all of the code that I have posted so far) taken from Apple's AVCam sample code:

// Find a camera with the specificed 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;
}

// Find a front facing camera, returning nil if one is not found
- (AVCaptureDevice *) frontFacingCamera
{
    return [self cameraWithPosition:AVCaptureDevicePositionFront];
}
Itamar
  • 1,290
  • 1
  • 18
  • 29
  • Can we get some more code, especially around the setup of the "frontFacingCamera" that you are attaching to the video input in setUpSession? as well as what is "self" is referring to? – Khaled Barazi Feb 15 '13 at 20:16
  • @Spectravideo328 I have updated the question as you requested, thank you for your attention! – Itamar Feb 17 '13 at 07:58

1 Answers1

6
BOOL isUsingFrontFacingCamera;



- (BOOL) swapCameras
{
    if ([self cameraCount] > 1) {
    AVCaptureDevicePosition desiredPosition;
    if (isUsingFrontFacingCamera) {
        desiredPosition = AVCaptureDevicePositionBack;
    } else {
        desiredPosition = AVCaptureDevicePositionFront;
    }

    for (AVCaptureDevice *d in [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo]) {
        if ([d position] == desiredPosition) {
            [[self session] beginConfiguration];
            AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:d error:nil];
            for (AVCaptureInput *oldInput in [[self session] inputs]) {
                [[self session] removeInput:oldInput];
            }
            [[self session] addInput:input];
            [[self session] commitConfiguration];
            break;
        }
    }
    isUsingFrontFacingCamera = !isUsingFrontFacingCamera;
    return YES;
}
return NO;
}

Answer from here

EDITED : This from Square Cam Apple sample code. Works fine. Tested also. http://developer.apple.com/library/ios/#samplecode/SquareCam/Listings/SquareCam_SqareCamViewController_m.html

// use front/back camera

- (IBAction)switchCameras:(id)sender

{

AVCaptureDevicePosition desiredPosition;

if (isUsingFrontFacingCamera)

    desiredPosition = AVCaptureDevicePositionBack;

else

    desiredPosition = AVCaptureDevicePositionFront;



for (AVCaptureDevice *d in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {

    if ([d position] == desiredPosition) {

        [[previewLayer session] beginConfiguration];

        AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:d error:nil];

        for (AVCaptureInput *oldInput in [[previewLayer session] inputs]) {

            [[previewLayer session] removeInput:oldInput];

        }

        [[previewLayer session] addInput:input];

        [[previewLayer session] commitConfiguration];

        break;

    }

}

isUsingFrontFacingCamera = !isUsingFrontFacingCamera;

}
Community
  • 1
  • 1
  • Ok, I've checked your code, it swaps like at should by then again, as I described in the question the camera freezes after swap it to the front facing one. – Itamar Mar 10 '13 at 08:57
  • The camera still freezes upon switching to the front one, any thoughts? – Itamar Mar 10 '13 at 10:48
  • Fixed it! Your code worked perfectly, it was my fault, I had some code that messes with the flashlight and it made some problems while switching the cameras, thank you! – Itamar Mar 10 '13 at 12:38
  • @PushpakNarasimhan this is working fine for me i can record video with front and back camera but while recording front camera the final video is MUTE (without audio) where for back camera its working fine plz help me – mshau Jul 16 '15 at 14:10