Pergunta

I am cloning Apple's camera app using AVCaptureSession based on Apple's AppCam app sample. The problem is I cannot see focus rectangle in the video preview screen. I used following code for setting focus, but still focus rectangle is not shown.

  AVCaptureDevice *device = [[self videoInput] device];
if ([device isFocusModeSupported:focusMode] && [device focusMode] != focusMode) {
    NSError *error;

      printf(" setFocusMode    \n");
    if ([device lockForConfiguration:&error]) {
        [device setFocusMode:focusMode];
        [device unlockForConfiguration];
    } else {
        id delegate = [self delegate];
        if ([delegate respondsToSelector:@selector(acquiringDeviceLockFailedWithError:)]) {
            [delegate acquiringDeviceLockFailedWithError:error];
        }
    }    
}

When I use UIImagePickerController, auto focus, tap focus are supported by default, and can see focus rectangle. Is there no way to show focus rectangle in the video preview layer using AVCaptureSession?

Foi útil?

Solução

The focus animation is a complete custom animation which you have to create by your own. I am currently having exact the same problem like you: I want to show a rectangle as a feedback for the user after he tapped the preview layer.

The first thing you want to do is implementing the tap-to-focus, probably where you initiate the preview layer:

UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapToFocus:)];
[tapGR setNumberOfTapsRequired:1];
[tapGR setNumberOfTouchesRequired:1];
[self.captureVideoPreviewView addGestureRecognizer:tapGR];

Now implement the tap-to-focus method itself:

-(void)tapToFocus:(UITapGestureRecognizer *)singleTap{
    CGPoint touchPoint = [singleTap locationInView:self.captureVideoPreviewView];
    CGPoint convertedPoint = [self.captureVideoPreviewLayer captureDevicePointOfInterestForPoint:touchPoint];
    AVCaptureDevice *currentDevice = currentInput.device;

    if([currentDevice isFocusPointOfInterestSupported] && [currentDevice isFocusModeSupported:AVCaptureFocusModeAutoFocus]){
        NSError *error = nil;
        [currentDevice lockForConfiguration:&error];
        if(!error){
            [currentDevice setFocusPointOfInterest:convertedPoint];
            [currentDevice setFocusMode:AVCaptureFocusModeAutoFocus];
            [currentDevice unlockForConfiguration];
        }    
    }
}

The last thing, which i haven't implemented by myself yet, is to add the focusing animation to the preview layer or rather the view controller which is holding the preview layer. I believe that could be done in tapToFocus:. There you already have the touch point. Simply add a animated image view or some other view which has the touch position as its center. After the animation has finished, remove the image view.

Outras dicas

Swift implementation

Gesture:

 private func focusGesture() -> UITapGestureRecognizer {

    let tapRec: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(kTapToFocus))
    tapRec.cancelsTouchesInView = false
    tapRec.numberOfTapsRequired = 1
    tapRec.numberOfTouchesRequired = 1

    return tapRec
}

Action:

  private func tapToFocus(gesture : UITapGestureRecognizer) {

    let touchPoint:CGPoint = gesture.locationInView(self.previewView)
    let convertedPoint:CGPoint = previewLayer!.captureDevicePointOfInterestForPoint(touchPoint)

    let currentDevice:AVCaptureDevice = videoDeviceInput!.device

    if currentDevice.focusPointOfInterestSupported && currentDevice.isFocusModeSupported(AVCaptureFocusMode.AutoFocus){
        do {
            try currentDevice.lockForConfiguration()
            currentDevice.focusPointOfInterest = convertedPoint
            currentDevice.focusMode = AVCaptureFocusMode.AutoFocus
            currentDevice.unlockForConfiguration()
        } catch {

        }
    }

}

swift3 implementation

lazy var focusGesture: UITapGestureRecognizer = {
    let instance = UITapGestureRecognizer(target: self, action: #selector(tapToFocus(_:)))
    instance.cancelsTouchesInView = false
    instance.numberOfTapsRequired = 1
    instance.numberOfTouchesRequired = 1
    return instance
}()

func tapToFocus(_ gesture: UITapGestureRecognizer) {
    guard let previewLayer = previewLayer else {
        print("Expected a previewLayer")
        return
    }
    guard let device = device else {
        print("Expected a device")
        return
    }
    
    let touchPoint: CGPoint = gesture.location(in: cameraView)
    let convertedPoint: CGPoint = previewLayer.captureDevicePointOfInterest(for: touchPoint)
    if device.isFocusPointOfInterestSupported && device.isFocusModeSupported(AVCaptureFocusMode.autoFocus) {
        do {
            try device.lockForConfiguration()
            device.focusPointOfInterest = convertedPoint
            device.focusMode = AVCaptureFocusMode.autoFocus
            device.unlockForConfiguration()
        } catch {
            print("unable to focus")
        }
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top