iphonic
iphonic

Reputation: 12719

iOS - AVCaptureDevice - Autofocus & Exposure with camera capture

I have been implementing Custom Camera using AVCaptureDevice, which require AutoFocus & Exposure to work nicely. I am using the following code to do the camera initialisation

- (void) initializeCamera {

    AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];

    if(status == AVAuthorizationStatusAuthorized) { // authorized
        [self.captureVideoPreviewLayer removeFromSuperlayer];
        self.captureSession = [[AVCaptureSession alloc] init];
        self.captureSession.sessionPreset = AVCaptureSessionPresetPhoto;
        [self removeDeviceObserverForFocus];
        self.captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        [self addDeviceObserverForFocus];

        NSError *error = nil;

        [self.captureDevice lockForConfiguration:nil]; //you must lock before setting torch mode
        [self.captureDevice setSubjectAreaChangeMonitoringEnabled:YES];
        [self.captureDevice unlockForConfiguration];


        //Capture layer
        self.captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession];
        self.captureVideoPreviewLayer.bounds = CGRectMake(0, 0, CGRectGetWidth([UIScreen mainScreen].bounds), CGRectGetHeight([UIScreen mainScreen].bounds));
        self.captureVideoPreviewLayer.position = CGPointMake(CGRectGetMidX(self.captureVideoPreviewLayer.bounds), CGRectGetMidY(self.captureVideoPreviewLayer.bounds));
        [self.captureVideoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
        self.captureVideoPreviewLayer.connection.enabled = YES;
        [self.viewCamera.layer insertSublayer:self.captureVideoPreviewLayer atIndex:0];


        //Capture input

        self.captureInput = [AVCaptureDeviceInput deviceInputWithDevice:self.captureDevice error:&error];
        if (!self.captureInput) {
            [self capturePhoto];
        }
        else {
            if ([self.captureSession canAddInput:self.captureInput]) {
                [self.captureSession addInput:self.captureInput];
            }
        }

        self.captureOutput = [[AVCaptureStillImageOutput alloc] init];
        [self.captureOutput setOutputSettings:@{AVVideoCodecKey : AVVideoCodecJPEG}];
        [self.captureSession addOutput:self.captureOutput];

        //THIS LINE 
        [self.captureSession setSessionPreset:AVCaptureSessionPresetPhoto];

        // setup metadata capture
        AVCaptureMetadataOutput *metadataOutput = [[AVCaptureMetadataOutput alloc] init];
        CGRect visibleMetadataOutputRect = [self.captureVideoPreviewLayer metadataOutputRectOfInterestForRect:self.vwCamera.bounds];
        metadataOutput.rectOfInterest = visibleMetadataOutputRect;
        [self.captureSession addOutput:metadataOutput];

        dispatch_async(dispatch_get_main_queue(), ^{

            [self.captureSession startRunning];
        });

    }
    else if(status == AVAuthorizationStatusNotDetermined){ // not determined

        //Try for getting permission
        [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
            [self performSelectorOnMainThread:@selector(initializeCamera) withObject:nil waitUntilDone:NO];
        }];
    }

}

- (void)removeDeviceObserverForFocus {
    @try {
        while ([self.captureDevice observationInfo] != nil) {
            [self.captureDevice removeObserver:self forKeyPath:@"adjustingFocus"];
        }
    }
    @catch (NSException *exception) {
        NSLog(@"Exception");
    }
    @finally {
    }
}

- (void)addDeviceObserverForFocus {
    [self.captureDevice addObserver:self forKeyPath:@"adjustingFocus" options:NSKeyValueObservingOptionNew context:nil];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if( [keyPath isEqualToString:@"adjustingFocus"] ){
        BOOL adjustingFocus = [ [change objectForKey:NSKeyValueChangeNewKey] isEqualToNumber:[NSNumber numberWithInt:1] ];
        if (adjustingFocus) {
            [self showFocusSquareAtPoint:self.viewCamera.center];
        }
    }
}

To monitor focus by movement of camera I am doing the following..

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(avCaptureDeviceSubjectAreaDidChangeNotification:) name:AVCaptureDeviceSubjectAreaDidChangeNotification object:nil];

#pragma mark - AVCaptureDeviceSubjectAreaDidChangeNotification

-(void)avCaptureDeviceSubjectAreaDidChangeNotification:(NSNotification *)notification{
    CGPoint devicePoint = CGPointMake( 0.5, 0.5 );

    [self focusWithMode:AVCaptureFocusModeContinuousAutoFocus exposeWithMode:AVCaptureExposureModeContinuousAutoExposure atDevicePoint:devicePoint monitorSubjectAreaChange:NO];
    [self showFocusSquareAtPoint:self.vwCamera.center];

}

- (void)focusWithMode:(AVCaptureFocusMode)focusMode exposeWithMode:(AVCaptureExposureMode)exposureMode atDevicePoint:(CGPoint)point monitorSubjectAreaChange:(BOOL)monitorSubjectAreaChange
{
    dispatch_async( dispatch_get_main_queue(), ^{
        AVCaptureDevice *device = self.captureDevice;
        NSError *error = nil;
        if ( [device lockForConfiguration:&error] ) {
            // Setting (focus/exposure)PointOfInterest alone does not initiate a (focus/exposure) operation.
            // Call -set(Focus/Exposure)Mode: to apply the new point of interest.
            if ( device.isFocusPointOfInterestSupported && [device isFocusModeSupported:focusMode] ) {
                device.focusPointOfInterest = point;
                device.focusMode = focusMode;
            }

            if ( device.isExposurePointOfInterestSupported && [device isExposureModeSupported:exposureMode] ) {
                device.exposurePointOfInterest = point;
                device.exposureMode = exposureMode;
            }

            device.subjectAreaChangeMonitoringEnabled = monitorSubjectAreaChange;
            [device unlockForConfiguration];
        }
        else {
            NSLog( @"Could not lock device for configuration: %@", error );
        }
    } );
}

Everything works as expected when I use this [self.captureSession setSessionPreset:AVCaptureSessionPresetPhoto];

If I change the camera preset to something else like AVCaptureSessionPresetHigh AutoFocus and Exposure doesn't work well as expected..

Anyone who has come across such situation?

Thank you for help.

Upvotes: 0

Views: 2015

Answers (1)

Ro4ch
Ro4ch

Reputation: 850

Are you trying to take a picture or record video? Cause the High preset is for video and the exposure and focus work differently(I believe). Here is info on the different presets in the docs - AVCaptureSessionPresets

Upvotes: 1

Related Questions