问题
I based my code on the sample from Google Camera2-Basic and added flash always support. But It looks like the picture is taken right after the flash has occur. I (almost) always get non flashed picture, even though the flash is triggered.
The modified preview request builder :
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
And I also added this control mode to captureStillPicture()
captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
and modified the process() switch with :
case STATE_WAITING_PRECAPTURE: {
// CONTROL_AE_STATE can be null on some devices
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
Log.i(TAG, "aeState = " + aeState);
if (aeState == null ||
aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED ||
aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
mState = STATE_WAITING_NON_PRECAPTURE;
}
break;
}
回答1:
I had this exact same problem, also on a Nexus 5. I worked around it by checking CaptureResult.FLASH_STATE
and triggering a capture immediately if it is equal to CaptureResult.FLASH_STATE_FIRED
. Basically, if the flash fires, then you need to do a capture right then and there, regardless of what state you are in, because it's only going to fire once. If the auto-focus/exposure etc hasn't properly converged at that point there's nothing you can do about it.
You can do a check at the start of onCaptureCompleted
like this:
if(mFlashAvailable && mWaitingForFlash)
{
Integer flashState = result.get(CaptureResult.FLASH_STATE);
if(flashState != null && flashState==CaptureResult.FLASH_STATE_FIRED)
{
mWaitingForFlash = false;
// do the capture...
mState = STATE_PICTURE_TAKEN;
captureStillPicture();
return; // don't call process()
}
}
mFlashAvailable
is set from the CameraCharacteristics when opening the camera like this:
mFlashAvailable = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
mWaitingForFlash
is just a flag you can set when you start the precapture, so that you don't capture more than one frame. This might not be necessary in your particular case however.
That will take care of when the flash fires before the state converges (i.e. the picture is after the flash), as you describe in your question. However you also need to handle the case when the flash is firing late (I've never seen this actually happen but just in case). You can do that by setting a flag like mExpectingFlash = true;
when setting the CONTROL_AE_MODE
to CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH
, and not capturing the usual way if it is true (since you will capture when you detect the flash firing state instead). You can also set this flag when you get aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED
if you are using CONTROL_AE_MODE_ON_AUTO_FLASH
. As a safety net I have a timeout so I don't end up waiting for a flash that never comes in case CONTROL_AE_STATE_FLASH_REQUIRED
is detected but the flash doesn't fire.
If you capture multiple frames, you can read the timestamp when you detect the flash firing, like this:
long timestamp = result.get(CaptureResult.SENSOR_TIMESTAMP);
and then cross check it against the timestamp of the image in onImageAvailable
Image image = reader.acquireLatestImage();
if (image != null)
{
long timestamp = image.getTimestamp();
// ....
}
来源:https://stackoverflow.com/questions/33894917/taking-picture-with-flash-on-camera2-gives-picture-after-flash-occured-i-e-wi