AVCaptureНастройка устройстваЭкспозиция имеет значение False, но захваченное изображение темное

Приложение Mac OS X, которое я кодирую, делает снимок с помощью встроенной в MacBook камеры FaceTime.

На MacBookAir3,2, MacBookPro8,2 и MacBookPro10,2 работает нормально, но на новых макбуках делает "темные" фото. Я понимаю, что это из-за автоматической экспозиции, но у меня проблемы с ее работой. AVCaptureDevice adjustingExposure установлено на NO, но захваченная фотография все еще полностью темная.

Код: setupCamera вызывается один раз при запуске приложения

-(void) setupCamera
{
    session = [[AVCaptureSession alloc] init];
    session.sessionPreset = AVCaptureSessionPresetPhoto;

    sessionInitialized = YES;

    device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

    [device lockForConfiguration:NULL];
    if ([device isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure])
        [device setExposureMode:AVCaptureExposureModeContinuousAutoExposure];

    if ([device isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus])
        [device setFocusMode:AVCaptureFocusModeContinuousAutoFocus];

    if ([device isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance])
        [device setWhiteBalanceMode:AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance];

    [device unlockForConfiguration];


    NSError *error = nil;
    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
    if(error != nil) {
        // ...
    }

    if([session canAddInput:input]) {
        [session addInput:input];
    } else {
        // ...
    }

    output = [[AVCaptureStillImageOutput alloc] init];
    NSDictionary *outputSettings = @{ AVVideoCodecKey : AVVideoCodecJPEG };
    [output setOutputSettings:outputSettings];

    if([session canAddOutput:output]) {
        [session addOutput:output];
    } else {
        // ...
    }
}

... затем каждый щелчок по кнопке привязки в пользовательском интерфейсе вызывает функцию shootPhoto:

-(void) shootPhoto
{
    [session startRunning];

    if([device lockForConfiguration:NULL]) {
        if ([device isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure])
            [device setExposureMode:AVCaptureExposureModeContinuousAutoExposure];

        if ([device isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus])
            [device setFocusMode:AVCaptureFocusModeContinuousAutoFocus];

        if ([device isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance])
            [device setWhiteBalanceMode:AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance];

        [device unlockForConfiguration];
    }

    if(device.adjustingFocus == NO && device.adjustingExposure == NO && device.adjustingWhiteBalance == NO) {
        [self actuallyCapture];
    } else {
        [device addObserver:self forKeyPath:@"adjustingExposure" options:NSKeyValueObservingOptionNew context:MyAdjustingExposureObservationContext];
        [device addObserver:self forKeyPath:@"adjustingFocus" options:NSKeyValueObservingOptionNew context:MyAdjustingFocusObservationContext];
        [device addObserver:self forKeyPath:@"adjustingWhiteBalance" options:NSKeyValueObservingOptionNew context:MyAdjustingWhiteBalanceObservationContext];
    }
}

-(void) actuallyCapture
{
    if ([session isRunning] == NO)
        return;

    connection = [output connectionWithMediaType:AVMediaTypeVideo];
    [output captureStillImageAsynchronouslyFromConnection:connection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
        // save file etc ...
    }];
}

Идея состоит в том, чтобы проверить, регулирует ли камера фокус, экспозицию или баланс белого. Если нет, позвоните actuallyCapture прямо сейчас. Если корректируется - добавьте наблюдателей и вызовите actuallyCapture из observeValueForKeyPath.

Проблема в том, что вызовы addObserver никогда не вызываются, потому что устройство возвращает все adjustingX==NO, но все равно захваченное фото темное.

В чем может быть причина? Я жду корректировки баланса белого и экспозиции?

Мне сложно отлаживать, потому что у меня есть только те устройства, которые работают нормально.


person grzaks    schedule 02.12.2014    source источник


Ответы (1)


Мне удалось решить эту проблему самостоятельно. Вот как я это сделал:

Установите наблюдателей для adjustingExposure, adjustingFocus и adjustingWhiteBalance:

[self.device addObserver:self forKeyPath:@"adjustingExposure" options:NSKeyValueObservingOptionNew context:MyAdjustingExposureObservationContext];
[self.device addObserver:self forKeyPath:@"adjustingFocus" options:NSKeyValueObservingOptionNew context:MyAdjustingFocusObservationContext];
[self.device addObserver:self forKeyPath:@"adjustingWhiteBalance" options:NSKeyValueObservingOptionNew context:MyAdjustingWhiteBalanceObservationContext];

Чтобы сделать снимок, инициализируйте AVCaptureSession, но установите таймер задержки на 1 секунду и фактически сделайте снимок после того, как он сработает:

-(void) shootPhoto
{
    dispatch_async(self.sessionQueue, ^{
        if([self setupCamera]) {
            self.sessionInitialized = YES;
            [self.session startRunning];

            self.isWaitingToCaptureImage = YES;
            dispatch_async(dispatch_get_main_queue(), ^{
                self.captureDelayTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
                                                                          target:self
                                                                        selector:@selector(actuallyCapture)
                                                                        userInfo:nil
                                                                         repeats:NO];
            });
        }
    });
}

В observeValueForKeyPath:ofObject:change:context проверьте, все ли три настройки уже выполнены, и если да, то отмените установленный выше таймер и сделайте снимок:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if(!self.sessionInitialized || !self.isWaitingToCaptureImage) {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        return;
    }

    if (context != MyAdjustingExposureObservationContext && context != MyAdjustingFocusObservationContext && context != MyAdjustingWhiteBalanceObservationContext) {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        return;
    } else {
        if (self.device.adjustingExposure || self.device.adjustingFocus || self.device.adjustingWhiteBalance) {
            NSLog(@"not ready to capture yet");
            return;
        } else {
            NSLog(@"ready to capture");
            if (self.captureDelayTimer && self.captureDelayTimer.isValid) {
                [self.captureDelayTimer invalidate];
                self.captureDelayTimer = nil;
            }
            [self actuallyCaptureDispatch];
        }
    }
}
person grzaks    schedule 12.01.2015
comment
Что такое MyAdjustingWhiteBalanceObservationContext? - person confile; 19.03.2015