I have one camera app in which i am providing user with 2 option manual focus and auto focus and then capturing 6 image back to back but my issue is when i call auto focus and then capture image it is getting stuck , but if i start capture without calling auto focus it is working fine
state: STATE_WAITING_LOCK
17:55:14.621 com....extureView V Current afState: 4
17:55:14.626 com....extureView V state: STATE_WAITING_LOCK
17:55:14.626 com....extureView V Current afState: 4
17:55:14.651 com....extureView V state: STATE_WAITING_LOCK
17:55:14.651 com....extureView V Current afState: 4
17:55:14.674 com....extureView V state: STATE_WAITING_LOCK
17:55:14.674 com....extureView V Current afState: 4
17:55:14.688 com....extureView V state: STATE_WAITING_LOCK
17:55:14.688 com....extureView V Current afState: 4
Auto Focus
protected CameraCaptureSession.CaptureCallback mCaptureCallback = new CameraCaptureSession.CaptureCallback() {
@SuppressWarnings("ConstantConditions")
private void process(CaptureResult result) {
switch (mState) {
case STATE_STREAMING: {
break;
}
case STATE_WAITING_LOCK: {
Log.v(TAG, "state: STATE_WAITING_LOCK");
final int afState = result.get(CaptureResult.CONTROL_AF_STATE);
Log.v(TAG, "Current afState: " + afState); // Add this line
if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
// Check if focusLockLatch is null before calling countDown()
if (focusLockLatch == null) {
focusLockLatch = new CountDownLatch(1);
}
focusLockLatch.countDown();
}
break;
}
case STATE_WAITING_PRECAPTURE: {
Log.v(TAG, "state: STATE_WAITING_PRECAPTURE");
mState = STATE_WAITING_NON_PRECAPTURE;
break;
}
}
}
@Override
public void onCaptureStarted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, long timestamp, long frameNumber) {
super.onCaptureStarted(session, request, timestamp, frameNumber);
//Log.v( TAG, "onCaptureStarted( session, request, timestamp, frameNumber )" );
}
@Override
public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) {
super.onCaptureProgressed(session, request, partialResult);
process(partialResult);
}
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
process(result);
}
@Override
public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) {
super.onCaptureFailed(session, request, failure);
Log.v(TAG, "onCaptureFailed( session, request, failure )");
}
};
public void autoFocus() {
try {
focusSeekBar.setCurrentValue(0);
setFocusMode(Mode.AUTO);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MODE_AUTO);
// Trigger an autofocus scan
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
Log.v(TAG, "autoFocus()");
mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, null);
// set seekbar to focus distance
} catch (CameraAccessException e) {
OnCameraErrorListener.handle(mCameraErrorCallback, e);
}
}
protected void lockFocus() {
Log.v(TAG, "lockFocus()");
if (mCaptureSession == null) {
return;
}
try {
if (focusMode == Mode.AUTO) {
// This is how to tell the camera to lock focus.
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
mState = STATE_WAITING_LOCK;
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
// check fo focus state
// if focus is locked call start capture
// if focus is not locked call unlock focus
if (focusLockLatch.await(500, TimeUnit.MILLISECONDS)) {
startCapture();
} else {
unlockFocus();
}
} else {
startCapture();
}
} catch (CameraAccessException e) {
OnCameraErrorListener.handle(mCameraErrorCallback, e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
protected void unlockFocus() {
Log.v(TAG, "unlockFocus()");
try {
// Reset the auto-focus trigger
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
mCaptureSession.capture(mPreviewRequestBuilder.build(), null, null);
// After this, the camera will go back to the normal state of preview.
mState = STATE_STREAMING;
//resume Zoom effect after taking a picture
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
if (mZoom != null) {
mPreviewRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, mZoom);
}
mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
OnCameraErrorListener.handle(mCameraErrorCallback, e);
}
}
protected void unlockFocus() {
Log.v(TAG, "unlockFocus()");
try {
// Reset the auto-focus trigger
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
mCaptureSession.capture(mPreviewRequestBuilder.build(), null, null);
// After this, the camera will go back to the normal state of preview.
mState = STATE_STREAMING;
//resume Zoom effect after taking a picture
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
if (mZoom != null) {
mPreviewRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, mZoom);
}
mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
OnCameraErrorListener.handle(mCameraErrorCallback, e);
}
}
Auto Focus
protected CameraCaptureSession.CaptureCallback mCaptureCallback = new CameraCaptureSession.CaptureCallback() {
@SuppressWarnings("ConstantConditions")
private void process(CaptureResult result) {
switch (mState) {
case STATE_STREAMING: {
break;
}
case STATE_WAITING_LOCK: {
Log.v(TAG, "state: STATE_WAITING_LOCK");
final int afState = result.get(CaptureResult.CONTROL_AF_STATE);
Log.v(TAG, "Current afState: " + afState); // Add this line
if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
// Check if focusLockLatch is null before calling countDown()
if (focusLockLatch == null) {
focusLockLatch = new CountDownLatch(1);
}
focusLockLatch.countDown();
}
break;
}
case STATE_WAITING_PRECAPTURE: {
Log.v(TAG, "state: STATE_WAITING_PRECAPTURE");
mState = STATE_WAITING_NON_PRECAPTURE;
break;
}
}
}
@Override
public void onCaptureStarted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, long timestamp, long frameNumber) {
super.onCaptureStarted(session, request, timestamp, frameNumber);
//Log.v( TAG, "onCaptureStarted( session, request, timestamp, frameNumber )" );
}
@Override
public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) {
super.onCaptureProgressed(session, request, partialResult);
process(partialResult);
}
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
process(result);
}
@Override
public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) {
super.onCaptureFailed(session, request, failure);
Log.v(TAG, "onCaptureFailed( session, request, failure )");
}
};
public void autoFocus() {
try {
focusSeekBar.setCurrentValue(0);
setFocusMode(Mode.AUTO);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MODE_AUTO);
// Trigger an autofocus scan
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
Log.v(TAG, "autoFocus()");
mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, null);
// set seekbar to focus distance
} catch (CameraAccessException e) {
OnCameraErrorListener.handle(mCameraErrorCallback, e);
}
}
protected void lockFocus() {
Log.v(TAG, "lockFocus()");
if (mCaptureSession == null) {
return;
}
try {
if (focusMode == Mode.AUTO) {
// This is how to tell the camera to lock focus.
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
mState = STATE_WAITING_LOCK;
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
// check fo focus state
// if focus is locked call start capture
// if focus is not locked call unlock focus
if (focusLockLatch.await(500, TimeUnit.MILLISECONDS)) {
startCapture();
} else {
unlockFocus();
}
} else {
startCapture();
}
} catch (CameraAccessException e) {
OnCameraErrorListener.handle(mCameraErrorCallback, e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
protected void unlockFocus() {
Log.v(TAG, "unlockFocus()");
try {
// Reset the auto-focus trigger
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
mCaptureSession.capture(mPreviewRequestBuilder.build(), null, null);
// After this, the camera will go back to the normal state of preview.
mState = STATE_STREAMING;
//resume Zoom effect after taking a picture
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
if (mZoom != null) {
mPreviewRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, mZoom);
}
mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
OnCameraErrorListener.handle(mCameraErrorCallback, e);
}
}
protected void unlockFocus() {
Log.v(TAG, "unlockFocus()");
try {
// Reset the auto-focus trigger
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
mCaptureSession.capture(mPreviewRequestBuilder.build(), null, null);
// After this, the camera will go back to the normal state of preview.
mState = STATE_STREAMING;
//resume Zoom effect after taking a picture
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
if (mZoom != null) {
mPreviewRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, mZoom);
}
mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
OnCameraErrorListener.handle(mCameraErrorCallback, e);
}
}
You are using the same thread for focusLockLatch
await()
and countdown()
invocations. So if await
is invoked first, the thread is already and waiting until countdown
is called, but countdown
can no longer be invoked to release the thread.
The reason same thread is being for callback is mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, null);
Since you are setting null to the handler
i.e. 3rd parameter here, current thread's looper is being used and thus the callback is executed on the current thread. I see that you are already using a mBackgroundHandler
in other places, simply use that here as well i.e. mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
.
Also, since your mBackgroundHandler
initialization is not here, maybe double-check that the mBackgroundHandler does indeed execute on a background thread, not the same thread (add some logs to check it if needed).