2

I'm having issues locking the focus point and taking a photo with flash on iPhone X (iOS 12.0) using the AVFoundation kit. How do I lock focus correctly on iOS 10 and up?

I need to take a photo with flash, but prevent auto-focus kicking in. I need a specific lens position during capture.

I've made the simplest app I can that turns Flash on using an AVCapturePhotoSettings object, locks focus on the AVCaptureDevice using [device setFocusMode:AVCaptureFocusModeLocked] and then takes a picture using capturePhotoWithSettings.

Regardless of the focus lock, auto focus still often happens, particularly when the preview is out of focus. Am I missing any settings, or a new way to lock focus?

I also tried adding setFocusModeLockedWithLensPosition which moves the lens position correctly, but it is still followed by an autofocus.

Is there an app on the store than can successfully lock focus during a flash photo?

// ViewController.h
//#import <UIKit/UIKit.h>
//
//@interface ViewController : UIViewController <AVCapturePhotoCaptureDelegate>
//
//@end

#import <AVFoundation/AVFoundation.h>
#import "ViewController.h"

@interface ViewController ()

@property (nonatomic) AVCaptureSession *session;
@property (nonatomic) AVCapturePhotoOutput *stillImageOutput;
@property (nonatomic) AVCaptureVideoPreviewLayer *videoPreviewLayer;

@property (weak, nonatomic) IBOutlet UIView *preview_view;
@property (weak, nonatomic) IBOutlet UIButton *take_picture_btn;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

-(void) viewDidAppear:(BOOL)animated
{
    self.session = [[AVCaptureSession alloc] init];
    self.session.sessionPreset = AVCaptureSessionPresetMedium;

    self.videoPreviewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
    self.videoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspect;
    self.videoPreviewLayer.connection.videoOrientation = AVCaptureVideoOrientationPortrait;
    [self.preview_view.layer addSublayer:self.videoPreviewLayer];

    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    AVCaptureDeviceInput* deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:NULL];
    [self.session addInput:deviceInput];

    self.stillImageOutput = [AVCapturePhotoOutput new];
    [self.session addOutput:self.stillImageOutput];

    [self.session commitConfiguration];

    dispatch_queue_t globalQueue =  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
    dispatch_async(globalQueue, ^{
        [self.session startRunning];
        dispatch_async(dispatch_get_main_queue(), ^{
            self.videoPreviewLayer.frame = self.preview_view.bounds;
        });
    });
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [self.session stopRunning];
}

- (IBAction)take_picture:(id)sender {
    AVCapturePhotoSettings *settings = [AVCapturePhotoSettings photoSettings];
    settings.flashMode = AVCaptureFlashModeOn;
    AVCaptureDevice* device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    [device lockForConfiguration:nil];
    [device setFocusMode:AVCaptureFocusModeLocked];
    [device unlockForConfiguration];
    [self.stillImageOutput capturePhotoWithSettings:settings delegate:self];
}

- (void)captureOutput:(AVCapturePhotoOutput *)output didFinishProcessingPhoto:(AVCapturePhoto *)photo error:(nullable NSError *)error {
    NSData *imageData = photo.fileDataRepresentation;
    if (imageData) {
        UIImage *image = [UIImage imageWithData:imageData];
        UIImageWriteToSavedPhotosAlbum(image,nil,nil,nil);
    }
}

@end

UDPATE: I've gone through Apples technical support. They have recognised this as a bug in the API on iPhone 8 and above. The auto-focus is not bypassed correctly when fixing the lens position. As of iOS 12.1.4 this is still an issue, but hopeful for a fix. No work around found as of yet.

0 Answers0