6

I'm using Android's Camera2 API and I currently want the camera to perform a certain action whenever it prepares to flash.

When building the CaptureRequest, the following line:

captureRequest.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);

allows the camera to flash under low-lighting conditions. However, I am at a loss as to how I can detect whether the camera is prepped to flash or not. It seems like the literature online about this particular action is pretty sparse.

I have tried checking if FLASH_STATE is in FLASH_STATE_READY while processing a partialresult in the camera's CaptureCallback, but it seems like the key wasn't available - it kept returning null. Perhaps I'm not checking in the right place?

The camera's CaptureCallback, shown below (based off Google's Camera2Basic code sample):

private CameraCaptureSession.CaptureCallback mCaptureCallback
        = new CameraCaptureSession.CaptureCallback()    {
    private void process(CaptureResult result)  {
        switch(mState)  {
            case STATE_PREVIEW: break;
            case STATE_WAITING_LOCK:
                // checking if result.get(CaptureResult.FLASH_STATE) == 
                // CaptureResult.FLASH_READY over here didn't work because
                // null was returned
                int afState = result.get(CaptureResult.CONTROL_AF_STATE);
                if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
                        CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
                    Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                    if (aeState == null ||
                            aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
                        mState = STATE_WAITING_NON_PRECAPTURE;
                        captureStillPicture();
                    } else {
                        runPrecaptureSequence();
                    }
                }
                break;
            case STATE_WAITING_PRECAPTURE:
                Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                if (aeState == null ||
                        aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
                        aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
                    mState = STATE_WAITING_NON_PRECAPTURE;
                }
                break;
            case STATE_WAITING_NON_PRECAPTURE:
                Integer aeState1 = result.get(CaptureResult.CONTROL_AE_STATE);
                if (aeState1 == null || aeState1 != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
                    mState = STATE_PICTURE_TAKEN;
                    captureStillPicture();
                }
                break;
        }
    }

    @Override
    public void onCaptureProgressed(CameraCaptureSession session,
                                    CaptureRequest request, CaptureResult partialResult) {
        super.onCaptureProgressed(session, request, partialResult);
        process(partialResult);
    }

    @Override
    public void onCaptureCompleted(CameraCaptureSession session,
                                   CaptureRequest request, TotalCaptureResult result) {
        super.onCaptureCompleted(session, request, result);
        process(result);
    }
};
Mauker
  • 11,237
  • 7
  • 58
  • 76
rfblue2
  • 73
  • 9
  • Check following class to for Flash in Camera2 API, http://stackoverflow.com/questions/27420594/android-5-camera2-use-only-flash/31289731#31289731 – Umang Kothari Aug 05 '15 at 07:25
  • To read the flash state, wait for the total capture result instead and check the flash state there; the partials may not have all the fields yet (typically they have the necessary fields to finish AF, etc, for speed). – Eddy Talvala Aug 05 '15 at 23:30

4 Answers4

4

In the documentation you can read the following statement for the FLASH_STATE key:

Optional - This value may be null on some devices.

Basically even if you are using a Lollipop device you can't be sure all functions of the Camera2 APi are supported. Devices with limited functions are called "limited devices".

For more informations take a look at this page. This describes it pretty well.

EDIT: To answer the comment which is basically wrong: The documentations say:

When the camera device doesn't have flash unit (i.e. android.flash.info.available == false), this state will always be UNAVAILABLE. Other states indicate the current flash status.

So if there is no flash on the device the FLASH_STATE is also present and will return UNAVAILABLE.

The documentation say pretty much everything you have to know. The most importand fact is, that it depends on the hardware-level/hardware mode.


Lets summarize it

For LEGACY devices

It will return the following

  • FIRED if the AE mode is set to ON_ALWAYS_FLASH
  • FIRED if the flash mode is set to TORCH
  • UNAVAILABLE if the camera has no flash.

When the device is at least LEVEL_LIMITED:

These values are possible, but there is no guarantee that they all work:

  • UNAVAILABLE
  • CHARGING
  • READY
  • FIRED
  • PARTIAL
daemmie
  • 6,361
  • 3
  • 29
  • 45
  • Thanks for the quick response and the resources. So I suppose one solution is to implement checking the `FLASH_STATE` key and use it for those devices that support it, but if the device doesn't support it, is it still possible to check in some other fashion? – rfblue2 Aug 05 '15 at 15:37
  • 1
    You are right, the usual way is to check the values you are requesting. I am not sure if there is an other way, but i guess not. Because the smartphone manufacturer itself has to implement a hardware abstaction layer to support the functions of the camera2 api. So i guess if you can't request the STATE in this way, the communication interface between hardware and program is missing for this feature. – daemmie Aug 05 '15 at 17:11
  • FLASH_STATE will be present if the device has a flash unit. – Eddy Talvala Aug 05 '15 at 23:30
1

There is no current way to know for sure if the flash will fire - the decision is made by the camera device at the last moment before the full-resolution capture. Once the final capture result for the full-resolution capture is available, its flash state should be FIRED if the flash did fire, but you'll get this after the fact. Make sure you wait for the total capture result from onCaptureCompleted to check for this field, not a partial from onCaptureProgressed; the partial results may be missing various fields.

That said, if the AE state field before starting the precapture sequence is FLASH_REQUIRED, it's quite likely that the flash will be fired if the AE mode allows for flash (AE_MODE_ON_AUTO_FLASH / ALWAYS_FLASH / AUTO_FLASH_REDEYE). It's not a 100% guarantee, since the scene may change in the few frames between the start of the precapture sequence (which will execute a precapture flash to estimate necessary flash power) and the actual final picture capture. But I suspect 95% of the time it'll be the final outcome.

Eddy Talvala
  • 17,243
  • 2
  • 42
  • 47
  • Seems promising, but even CONTROL_AE_STATE is optional! (i.e. if you check the documentation it says `Optional - This value may be null on some devices.`). This is true on my particular device, which always outputs `null`. I guess the only guaranteed check for flash is after it already happens? – rfblue2 Aug 06 '15 at 16:30
  • 1
    Is your device a LEGACY-level device? If so, yes, then there's nothing much to reveal that information. LEGACY devices are effectively running the camera2 API on top of the old API, due to lack of direct hardware support, so they are fairly limited in what information they can produce. Note that 'optional' doesn't mean it's completely arbitrary as to whether the field is present. It means that configurations exist where it's not there so care should be taken, but most entries have well-defined existence requirements. AE_STATE must be present on LIMITED or above devices. – Eddy Talvala Aug 06 '15 at 19:44
0

Problem

You are trying to detect whether the picture taken by your app used flash or not.

Solution

You can use Camera.Parameters to check the state of the flash while using camera whether flash is AUTO, ON, or OFF.

Code

You can use the following code sample in order to check the flash state for the camera.

Camera.Parameters p = mCamera.getParameters();

if(p.getFlashMode().equals(android.hardware.Camera.Parameters.FLASH_MODE_ON))
{
 //DO STUFF
}
else if(p.getFlashMode().equals(android.hardware.Camera.Parameters.FLASH_MODE_OFF))
{
//DO STUFF
}
else if(p.getFlashMode().equals(android.hardware.Camera.Parameters.FLASH_MODE_TORCH))
{
//DO STUFF
}
else if(p.getFlashMode().equals(android.hardware.Camera.Parameters.FLASH_MODE_AUTO))
{
//DO STUFF
}
else
{
//DO STUFF
}
Karan Sharma
  • 2,353
  • 4
  • 28
  • 46
  • 1
    Camera.Parameters is deprecated since API 21. Is it a good idea to use it in combination with Camera API2 ? – daemmie Aug 05 '15 at 07:23
  • Thanks for the quick response - question though - if the camera is set to AUTO, how can I check if the camera is indeed about to flash? Because sometimes in AUTO it will flash and other times it won't. – rfblue2 Aug 05 '15 at 15:32
  • @rfblue2 In case of AUTO, you should check the FLASH_STATE which is fired after capturing the image. Hope this helps. You might want to refer this official documentation before you start writing code: https://developer.android.com/reference/android/hardware/camera2/CaptureResult.html#FLASH_STATE – Karan Sharma Aug 06 '15 at 07:14
0

Camera API is not deprecated, Following code snippet from Camera2 API to check flash is available or not,

CameraManager mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
//here to judge if flash is available

CameraCharacteristics cameraCharacteristics = mCameraManager.getCameraCharacteristics("0");
boolean flashAvailable = cameraCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
if (flashAvailable) {
         mCameraManager.openCamera("0", new MyCameraDeviceStateCallback(), null);
} else {
       //todo: throw Exception
}
Umang Kothari
  • 3,674
  • 27
  • 36
  • Thanks for the quick response. I'm not looking for whether or not the camera has flash (which has been answered in other questions) but rather whether the flash is about to fire when it is set to AUTO flash, because in the AUTO mode, flash sometimes fires and sometimes doesn't – rfblue2 Aug 05 '15 at 15:38