I'm going insane trying to get an AVCaptureSession (in a view controller) to be presented and dismissed in my project. I'm currently on iOS5.1 and have ARC enabled.
I can get it to work fine the first time I present the viewcontroller and start the session but when I dismiss and present a second time the session will not start. I subscribed to the "AVCaptureSessionRuntimeErrorNotification" notification and receive the following error:
"Error Domain=AVFoundationErrorDomain Code=-11819 "Cannot Complete Action" UserInfo=0x1a4020 {NSLocalizedRecoverySuggestion=Try again later., NSLocalizedDescription=Cannot Complete Action}"
I'm assuming that something is not being properly released in my session, but with ARC there are no releases and I instead set everything to be released to nil.
my viewDidLoad methods basically just triggers initCamera
initCamera method:
AVCaptureSession *tmpSession = [[AVCaptureSession alloc] init];
session = tmpSession;
session.sessionPreset = AVCaptureSessionPresetMedium;
captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
captureVideoPreviewLayer.frame = self.vImagePreview.bounds;
[self.vImagePreview.layer addSublayer:captureVideoPreviewLayer];
rearCamera = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error = nil;
input = [AVCaptureDeviceInput deviceInputWithDevice:rearCamera error:&error];
if (!input) {
// Handle the error appropriately.
NSLog(@"ERROR: trying to open camera: %@", error);
}
[session addInput:input];
videoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys: [NSNumber numberWithInt:kCVPixelFormatType_32BGRA], kCVPixelBufferPixelFormatTypeKey, nil];
[videoDataOutput setVideoSettings:outputSettings];
[videoDataOutput setAlwaysDiscardsLateVideoFrames:YES];
queue = dispatch_queue_create("cameraQueue", DISPATCH_QUEUE_SERIAL);
[videoDataOutput setSampleBufferDelegate:self queue:queue];
dispatch_release(queue);
[session addOutput:videoDataOutput];
NSNotificationCenter *notify =
[NSNotificationCenter defaultCenter];
[notify addObserver: self
selector: @selector(onVideoError:)
name: AVCaptureSessionRuntimeErrorNotification
object: session];
[session startRunning];
[rearCamera lockForConfiguration:nil];
rearCamera.whiteBalanceMode = AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance;
rearCamera.exposureMode = AVCaptureExposureModeContinuousAutoExposure;
rearCamera.focusMode = AVCaptureFocusModeContinuousAutoFocus;
[rearCamera unlockForConfiguration];
The method
captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
gets called no problem the first time I present the modal viewcontroller, but on the second attempt this method stops getting called (because the session does not start)
For clean up I'm calling stopSession from my parent viewcontroller before dismissing and that does the following:
if ([session isRunning]) {
[session removeInput:input];
[session stopRunning];
[vImagePreview removeFromSuperview];
vImagePreview = nil;
input = nil;
videoDataOutput = nil;
captureVideoPreviewLayer = nil;
session = nil;
queue = nil;
}
I feel like I've tried all sorts of things such as performing a dispatch_sync(queue, ^{}) on the queue to wait for it to be flushed, but that doesn't seem to make a difference (when calling the dispatch_sync I removed the dispatch_release call in my init camera method). I've also tried using the dispatch_set_finalizer_f(queue, capture_cleanup) method suggested in another question but I don't know what needs to actually go in the capture_cleanup method because all of the examples I find are non-ARC code where they call release on pointer to self. I've also combed through all of the sample code I can find from Apple (SquareCam and AVCam) but these are also non-ARC. Any help would be greatly appreciated.