Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing Flash setting of Android Camera 2 at runtime

Basically, what I am trying to do is change the CONTROL_AE_MODE by button click in the app. The user can use AUTO flash(ON_AUTO_FLASH), turn if ON(ON_ALWAYS_FLASH), or OFF(CONTROL_AE_MODE_OFF).

In this example: https://github.com/googlesamples/android-Camera2Basic/blob/master/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java

Line 818, they set the flash once:

// Use the same AE and AF modes as the preview.
            captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            setAutoFlash(captureBuilder);

            // Orientation
            int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
            captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));

            CameraCaptureSession.CaptureCallback CaptureCallback
                    = new CameraCaptureSession.CaptureCallback() {

                @Override
                public void onCaptureCompleted(@NonNull CameraCaptureSession session,
                                               @NonNull CaptureRequest request,
                                               @NonNull TotalCaptureResult result) {
                    showToast("Saved: " + mFile);
                    Log.d(TAG, mFile.toString());
                    unlockFocus();
                }
            };

            mCaptureSession.stopRepeating();
            mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);

And then builds the CaptureSession at line 840.

Is there a way to change the CONTROL_AE_MODE after the preview is made?

I have tried remaking the session, which kinda worked:

if(flashMode == CameraView.CAMERA_FLASH_ON){
            Log.e("CAMERA 2", "FLASH ON");
            mPreviewCaptureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
        }else if(flashMode == CameraView.CAMERA_FLASH_OFF){
            Log.e("CAMERA 2", "FLASH OFF");
            mPreviewCaptureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
        }else if(flashMode == CameraView.CAMERA_FLASH_AUTO){
            Log.e("CAMERA 2", "FLASH AUTO");
            mPreviewCaptureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
        }
        mFlashMode = flashMode;
        if (mCameraCaptureSession != null) {
            mCameraCaptureSession.close();
            mCameraCaptureSession = null;
       }
  createCameraPreviewSession();

For some reason, CONTROL_AE_MODE_OFF would turn the whole preview black. I tried looking in the docs for methods to update but haven't found anything.

Any tutorials or docs is much appreciated.

like image 600
dotfury Avatar asked Feb 25 '16 06:02

dotfury


3 Answers

As mentioned by @cyborg86pl when switching flash modes you should not switch CONTROL_AE_MODE . Instead you can switch between FLASH_MODE´s. Here is a working example for my case:

  when (currentFlashState) {
        FlashState.AUTO -> {
          previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH)
        }
        FlashState.ON -> {
          previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON)
          previewRequestBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_TORCH)
        }
        FlashState.OFF -> {
          previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON)
          previewRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF)
        }
      }
 previewRequest = previewRequestBuilder.build()
 captureSession.setRepeatingRequest(previewRequest, captureCallback, backgroundHandler)
like image 197
iskae Avatar answered Oct 05 '22 18:10

iskae


I don't know why your preview turn black, but you don't need to close capture session manually. From .close() method's docs:

Using createCaptureSession(List , CameraCaptureSession.StateCallback, Handler) directly without closing is the recommended approach for quickly switching to a new session, since unchanged target outputs can be reused more efficiently.

So you can reuse existing CaptureRequest.Builder, set your changed value, build new PreviewRequest and just start new session with this new request, like this:

try {
    // Change some capture settings
    mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
    // Build new request (we can't just edit existing one, as it is immutable)
    mPreviewRequest = mPreviewRequestBuilder.build();
    // Set new repeating request with our changed one
    mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
    e.printStackTrace();
}

It will be much faster (almost without any visible freeze of preview).

like image 33
Robyer Avatar answered Oct 05 '22 18:10

Robyer


What you want is disabling flash, not auto-exposure (AE), thus you want to use CONTROL_AE_MODE_ON rather than CONTROL_AE_MODE_OFF.

As mentioned in the documentation:

CONTROL_AE_MODE_ON

The camera device's autoexposure routine is active, with no flash control.

like image 43
cyborg86pl Avatar answered Oct 05 '22 20:10

cyborg86pl