Search code examples
javaandroidandroid-camera2

Android Camera 2 Api locking focus


i am making camera app in that i am showing preview and then there is two option auto focus and second manual seekbar to adjust focus, new here is my problem when i press capture i have to capture 10 image with diffrent value of ISO.I have added loop with counter to capture 10 image with value adjusted after first image it is losing focus and rest of my image are getting blur and out of focus ho can i lock focus in case user chooses auto focus because in manual i am just feeding value during capture but in case of auto focus how can i lock focus , for all 10 image

Unfortunately, I'm unable to share my code, but I'd greatly appreciate any general guidance or examples you could provide to help me address this challenge. Thank you for your assistance!

when user touch on preview i am calling

    public void autoFocus() {
        try {
            focusSeekBar.setCurrentValue(0);
            setFocusMode(Mode.AUTO);
            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            Log.v(TAG, "autoFocus()");
            mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, null);
            // set seekbar  to focus distance
        } catch (CameraAccessException e) {
            OnCameraErrorListener.handle(mCameraErrorCallback, e);
        }
    }

this is during capture process i have one flag when user press auto focus i am setting focused to true

        if (focusMode == Mode.MANUAL) {
            captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF);
            captureBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE, focusDistance);
        } else if (focusMode == Mode.AUTO && !focused) {
            captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
        }

Solution

  • Basically, what you want to do is get the AF state to be in FOCUSED_LOCKED.

    And as the documentation says, you need to do an explicit AF trigger which is done by setting the CaptureRequest#CONTROL_AF_TRIGGER to CONTROL_AF_TRIGGER_START. (Note that the CONTROL_AF_TRIGGER value should be set in a non-repeating request, not a repeating capture request, to avoid triggering repeatedly)

    So your capture process should be something like the following:

    1. Before starting a capture, send a single (non-repeating) capture request with CONTROL_AF_TRIGGER_START.
    2. Wait until the AF state is in FOCUSED_LOCKED (or NOT_FOCUSED_LOCKED in case it fails) in the repeating capture request callback.
    3. Do your usual capture flow i.e. the main capture part.
    4. Cancel the AF trigger with CONTROL_AF_TRIGGER_CANCEL so that AF is no longer locked.
    void preCapture() {
        startAfTrigger(); // triggers AF which will eventually lead to locking the lens
        awaitFocusLock(); // wait for the locking to be completed
    
        invokeMainCapture(); // this is where you do the 10 captures you were originally doing
    
        cancelAfTrigger(); // release the lens lock
    }
    
    void startAfTrigger() {
        requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); // keeping the same as in repeating request
        requestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START); // explicit AF trigger start
        mCaptureSession.capture(requestBuilder.build(), captureCallback, null); // non-repeating request
    
        // waits until the capture request has been processed by framework, basically wait until CaptureCallback#onCaptureCompleted is called once
        captureCallback.await();
    }
    
    void awaitFocusLock() {
        // waits until the capture request has a CaptureResult that satisfies the condition in CaptureResultVerifier#isVerified()
        mCaptureCallback.await(new CaptureResultVerifier { // the mCaptureCallback should be the callback instance set for repeating request
            boolean isVerified(TotalCaptureResult captureResult) {
                int afState = captureResult.get(CaptureResult.CONTROL_AF_STATE);
    
                return afState == CameraMetadata.CONTROL_AF_STATE_FOCUSED_LOCKED || // lens locked and focus succeeded
                 afState == CameraMetadata.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED; // lens locked, but failed to get good focus
            }
        })
    }
    
    void cancelAfTrigger() {
        requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); // keeping the same as in repeating request
        requestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
        mCaptureSession.capture(requestBuilder.build(), captureCallback, null); // non-repeating request
    
        // waits until the capture request has been processed by framework, basically wait until CaptureCallback#onCaptureCompleted is called once
        captureCallback.await();
    }
    

    For more details on the AF state and related transitions, take a look at https://source.android.com/docs/core/camera/camera3_3Amodes#af-state too.