|
|
@ -42,8 +42,8 @@ public class Snapshot2PictureRecorder extends SnapshotGlPictureRecorder { |
|
|
|
|
|
|
|
|
|
|
|
private final static int STATE_IDLE = 0; |
|
|
|
private final static int STATE_IDLE = 0; |
|
|
|
private final static int STATE_WAITING_FIRST_FRAME = 1; |
|
|
|
private final static int STATE_WAITING_FIRST_FRAME = 1; |
|
|
|
private final static int STATE_WAITING_TORCH = 2; |
|
|
|
private final static int STATE_WAITING_LOCK = 2; |
|
|
|
private final static int STATE_WAITING_TORCH_EXPOSURE = 3; |
|
|
|
private final static int STATE_WAITING_TORCH = 3; |
|
|
|
private final static int STATE_WAITING_IMAGE = 4; |
|
|
|
private final static int STATE_WAITING_IMAGE = 4; |
|
|
|
|
|
|
|
|
|
|
|
private final Camera2Engine mEngine; |
|
|
|
private final Camera2Engine mEngine; |
|
|
@ -53,6 +53,8 @@ public class Snapshot2PictureRecorder extends SnapshotGlPictureRecorder { |
|
|
|
private int mState = STATE_IDLE; |
|
|
|
private int mState = STATE_IDLE; |
|
|
|
private Integer mOriginalAeMode; |
|
|
|
private Integer mOriginalAeMode; |
|
|
|
private Integer mOriginalFlashMode; |
|
|
|
private Integer mOriginalFlashMode; |
|
|
|
|
|
|
|
private Integer mOriginalAfMode; |
|
|
|
|
|
|
|
private boolean mNeedsFlash; |
|
|
|
|
|
|
|
|
|
|
|
public Snapshot2PictureRecorder(@NonNull PictureResult.Stub stub, |
|
|
|
public Snapshot2PictureRecorder(@NonNull PictureResult.Stub stub, |
|
|
|
@NonNull Camera2Engine engine, |
|
|
|
@NonNull Camera2Engine engine, |
|
|
@ -78,6 +80,17 @@ public class Snapshot2PictureRecorder extends SnapshotGlPictureRecorder { |
|
|
|
mState = STATE_WAITING_FIRST_FRAME; |
|
|
|
mState = STATE_WAITING_FIRST_FRAME; |
|
|
|
mOriginalAeMode = mBuilder.get(CaptureRequest.CONTROL_AE_MODE); |
|
|
|
mOriginalAeMode = mBuilder.get(CaptureRequest.CONTROL_AE_MODE); |
|
|
|
mOriginalFlashMode = mBuilder.get(CaptureRequest.FLASH_MODE); |
|
|
|
mOriginalFlashMode = mBuilder.get(CaptureRequest.FLASH_MODE); |
|
|
|
|
|
|
|
mOriginalAfMode = mBuilder.get(CaptureRequest.CONTROL_AF_MODE); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void applyBuilder() { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
mSession.setRepeatingRequest(mBuilder.build(), mCallback, null); |
|
|
|
|
|
|
|
} catch (CameraAccessException e) { |
|
|
|
|
|
|
|
mResult = null; |
|
|
|
|
|
|
|
mError = e; |
|
|
|
|
|
|
|
dispatchResult(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -96,81 +109,64 @@ public class Snapshot2PictureRecorder extends SnapshotGlPictureRecorder { |
|
|
|
public void onCaptureCompleted(@NonNull TotalCaptureResult result) { |
|
|
|
public void onCaptureCompleted(@NonNull TotalCaptureResult result) { |
|
|
|
if (mState == STATE_WAITING_FIRST_FRAME) { |
|
|
|
if (mState == STATE_WAITING_FIRST_FRAME) { |
|
|
|
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE); |
|
|
|
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE); |
|
|
|
if (aeState == null) { |
|
|
|
mNeedsFlash = aeState != null && aeState == CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED; |
|
|
|
LOG.w("onCaptureCompleted:", "aeState is null! This should never happen.", |
|
|
|
LOG.i("onCaptureCompleted:", "aeState:", aeState, "needsFlash:", mNeedsFlash); |
|
|
|
"Taking snapshot."); |
|
|
|
mState = STATE_WAITING_LOCK; |
|
|
|
mState = STATE_WAITING_IMAGE; |
|
|
|
// Removing any ongoing precapture or trigger. This should not be needed.
|
|
|
|
super.take(); |
|
|
|
// if (Build.VERSION.SDK_INT >= 23) {
|
|
|
|
} else if (aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) { |
|
|
|
// mBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL);
|
|
|
|
LOG.i("onCaptureCompleted:", "aeState is optimal. Taking snapshot."); |
|
|
|
// }
|
|
|
|
mState = STATE_WAITING_IMAGE; |
|
|
|
// mBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);
|
|
|
|
super.take(); |
|
|
|
// Lock AE, AWB, AF to their current values
|
|
|
|
} else if (aeState == CaptureResult.CONTROL_AE_STATE_LOCKED) { |
|
|
|
mBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true); |
|
|
|
LOG.i("onCaptureCompleted:", "aeState is locked. There's nothing we can do.", |
|
|
|
mBuilder.set(CaptureRequest.CONTROL_AWB_LOCK, true); |
|
|
|
"Taking snapshot with no flash."); |
|
|
|
mBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO); |
|
|
|
mState = STATE_WAITING_IMAGE; |
|
|
|
applyBuilder(); |
|
|
|
super.take(); |
|
|
|
return; |
|
|
|
} else if (aeState != CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) { |
|
|
|
} |
|
|
|
LOG.w("onCaptureCompleted:", "aeState is not CONVERGED, FLASH_REQUIRED or LOCKED.", aeState, |
|
|
|
|
|
|
|
"This seems to say that metering did not complete before. Let's take the snapshot."); |
|
|
|
if (mState == STATE_WAITING_LOCK) { |
|
|
|
mState = STATE_WAITING_IMAGE; |
|
|
|
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE); |
|
|
|
super.take(); |
|
|
|
Integer awbState = result.get(CaptureResult.CONTROL_AWB_STATE); |
|
|
|
} else { |
|
|
|
boolean aeLocked = aeState != null && aeState == CaptureResult.CONTROL_AE_STATE_LOCKED; |
|
|
|
// Open the torch. AE_MODE_ON is guaranteed to be supported.
|
|
|
|
boolean awbLocked = awbState != null && awbState == CaptureResult.CONTROL_AWB_STATE_LOCKED; |
|
|
|
LOG.w("onCaptureCompleted:", "aeState is FLASH_REQUIRED. Opening torch."); |
|
|
|
if (aeLocked && awbLocked) { |
|
|
|
|
|
|
|
if (mNeedsFlash) { |
|
|
|
|
|
|
|
LOG.i("onCaptureCompleted:", "AE/AWB locked!", "Flash needed, opening torch."); |
|
|
|
mState = STATE_WAITING_TORCH; |
|
|
|
mState = STATE_WAITING_TORCH; |
|
|
|
mBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH); |
|
|
|
mBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH); |
|
|
|
mBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); |
|
|
|
mBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); |
|
|
|
try { |
|
|
|
applyBuilder(); |
|
|
|
mSession.setRepeatingRequest(mBuilder.build(), mCallback, null); |
|
|
|
} else { |
|
|
|
} catch (CameraAccessException e) { |
|
|
|
LOG.i("onCaptureCompleted:", "AE/AWB locked!", "No flash needed, taking picture."); |
|
|
|
mResult = null; |
|
|
|
mState = STATE_WAITING_IMAGE; |
|
|
|
mError = e; |
|
|
|
super.take(); |
|
|
|
dispatchResult(); |
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
LOG.i("onCaptureCompleted:", "Waiting for AE/AWB locks...", |
|
|
|
|
|
|
|
"aeState:", aeState, "aeLocked:", aeLocked, |
|
|
|
|
|
|
|
"awbState:", awbState, "awbLocked:", awbLocked); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} else if (mState == STATE_WAITING_TORCH) { |
|
|
|
|
|
|
|
|
|
|
|
if (mState == STATE_WAITING_TORCH) { |
|
|
|
Integer flashState = result.get(CaptureResult.FLASH_STATE); |
|
|
|
Integer flashState = result.get(CaptureResult.FLASH_STATE); |
|
|
|
if (flashState == null) { |
|
|
|
if (flashState == null) { |
|
|
|
LOG.w("onCaptureCompleted:", "Waiting flash, but flashState is null! Taking snapshot."); |
|
|
|
LOG.w("onCaptureCompleted:", "Waiting flash, but flashState is null! Taking snapshot."); |
|
|
|
mState = STATE_WAITING_IMAGE; |
|
|
|
mState = STATE_WAITING_IMAGE; |
|
|
|
super.take(); |
|
|
|
super.take(); |
|
|
|
} else if (flashState == CaptureResult.FLASH_STATE_FIRED) { |
|
|
|
} else if (flashState == CaptureResult.FLASH_STATE_FIRED) { |
|
|
|
LOG.i("onCaptureCompleted:", "Waiting flash and we have FIRED state! Waiting exposure."); |
|
|
|
LOG.i("onCaptureCompleted:", "Waiting flash and we have FIRED state! Taking snapshot."); |
|
|
|
mState = STATE_WAITING_TORCH_EXPOSURE; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
LOG.i("onCaptureCompleted:", "aeState is FLASH_REQUIRED but flashState is", |
|
|
|
|
|
|
|
flashState, ". Waiting..."); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else if (mState == STATE_WAITING_TORCH_EXPOSURE) { |
|
|
|
|
|
|
|
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE); |
|
|
|
|
|
|
|
if (aeState == null) { |
|
|
|
|
|
|
|
LOG.w("onCaptureCompleted:", "aeState is null! Taking snasphot."); |
|
|
|
|
|
|
|
mState = STATE_WAITING_IMAGE; |
|
|
|
mState = STATE_WAITING_IMAGE; |
|
|
|
super.take(); |
|
|
|
super.take(); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
switch (aeState) { |
|
|
|
LOG.i("onCaptureCompleted:", "aeState is FLASH_REQUIRED but flashState is", |
|
|
|
case CaptureResult.CONTROL_AE_STATE_CONVERGED: |
|
|
|
flashState, ". Waiting..."); |
|
|
|
case CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED: { |
|
|
|
|
|
|
|
LOG.i("onCaptureCompleted:", "We have torch and good torch exposure.", aeState); |
|
|
|
|
|
|
|
mState = STATE_WAITING_IMAGE; |
|
|
|
|
|
|
|
super.take(); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case CaptureResult.CONTROL_AE_STATE_LOCKED: { |
|
|
|
|
|
|
|
LOG.w("onCaptureCompleted:", "Final aeState is LOCKED. Should not happen."); |
|
|
|
|
|
|
|
mState = STATE_WAITING_IMAGE; |
|
|
|
|
|
|
|
super.take(); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
default: { |
|
|
|
|
|
|
|
LOG.i("onCaptureCompleted:", "Waiting for torch exposure...:", aeState); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//noinspection UnnecessaryReturnStatement
|
|
|
|
|
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -184,6 +180,8 @@ public class Snapshot2PictureRecorder extends SnapshotGlPictureRecorder { |
|
|
|
mBuilder.set(CaptureRequest.CONTROL_AE_MODE, mOriginalAeMode); |
|
|
|
mBuilder.set(CaptureRequest.CONTROL_AE_MODE, mOriginalAeMode); |
|
|
|
mSession.capture(mBuilder.build(), mCallback, null); |
|
|
|
mSession.capture(mBuilder.build(), mCallback, null); |
|
|
|
mBuilder.set(CaptureRequest.FLASH_MODE, mOriginalFlashMode); |
|
|
|
mBuilder.set(CaptureRequest.FLASH_MODE, mOriginalFlashMode); |
|
|
|
|
|
|
|
mSession.capture(mBuilder.build(), mCallback, null); |
|
|
|
|
|
|
|
mBuilder.set(CaptureRequest.CONTROL_AF_MODE, mOriginalAfMode); |
|
|
|
mSession.setRepeatingRequest(mBuilder.build(), mCallback, null); |
|
|
|
mSession.setRepeatingRequest(mBuilder.build(), mCallback, null); |
|
|
|
} catch (CameraAccessException ignore) {} |
|
|
|
} catch (CameraAccessException ignore) {} |
|
|
|
} |
|
|
|
} |
|
|
|