diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraOptions.java b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraOptions.java index 43be7394..a0b44053 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraOptions.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraOptions.java @@ -180,6 +180,12 @@ public class CameraOptions { Flash value = mapper.unmapFlash(aeMode); if (value != null) supportedFlash.add(value); } + // Check for torch specifically since the Mapper flash support is not so good. + // If OFF works, it means we have AE_MODE_OFF or AE_MODE_ON. This means we can use + // the torch control. + if (supportedFlash.contains(Flash.OFF)) { + supportedFlash.add(Flash.TORCH); + } } // HDR diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java index 3bdd26d2..82259965 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java @@ -55,6 +55,8 @@ public class Camera1Engine extends CameraEngine implements Camera.PreviewCallbac private Camera mCamera; @VisibleForTesting int mCameraId; + private int mPreviewStreamFormat; + private Runnable mFocusEndRunnable; private final Runnable mFocusResetRunnable = new Runnable() { @@ -196,6 +198,7 @@ public class Camera1Engine extends CameraEngine implements Camera.PreviewCallbac mVideoRecorder.stop(); mVideoRecorder = null; } + mPictureRecorder = null; mPreviewStreamFormat = 0; getFrameManager().release(); mCamera.setPreviewCallbackWithBuffer(null); // Release anything left @@ -763,6 +766,10 @@ public class Camera1Engine extends CameraEngine implements Camera.PreviewCallbac // ----------------- // Size stuff. + public final int getPreviewStreamFormat() { + return mPreviewStreamFormat; + } + @NonNull @Override diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java index 6e7dadab..22df2dd8 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java @@ -2,6 +2,7 @@ package com.otaliastudios.cameraview.engine; import android.annotation.SuppressLint; import android.content.Context; +import android.graphics.ImageFormat; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.SurfaceTexture; @@ -52,11 +53,11 @@ import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.annotation.WorkerThread; -// TODO fix flash, it's not that simple // TODO zoom // TODO exposure correction // TODO autofocus // TODO pictures +// TODO frame processor @RequiresApi(Build.VERSION_CODES.LOLLIPOP) public class Camera2Engine extends CameraEngine { @@ -330,7 +331,6 @@ public class Camera2Engine extends CameraEngine { // Set the preview rotation. mPreview.setDrawRotation(mDisplayOffset); - // TODO mPreviewStreamFormat = params.getPreviewFormat(); // TODO mCamera.setPreviewCallbackWithBuffer(null); // Release anything left // TODO mCamera.setPreviewCallbackWithBuffer(this); // Add ourselves // TODO mFrameManager.setUp(ImageFormat.getBitsPerPixel(mPreviewStreamFormat), mPreviewStreamSize); @@ -365,7 +365,7 @@ public class Camera2Engine extends CameraEngine { mVideoRecorder.stop(); mVideoRecorder = null; } - mPreviewStreamFormat = 0; + mPictureRecorder = null; getFrameManager().release(); // TODO mCamera.setPreviewCallbackWithBuffer(null); // Release anything left try { @@ -610,6 +610,17 @@ public class Camera2Engine extends CameraEngine { * - {@link CaptureRequest#CONTROL_AE_MODE_ON} * - {@link CaptureRequest#CONTROL_AE_MODE_ON_AUTO_FLASH} * - {@link CaptureRequest#CONTROL_AE_MODE_ON_ALWAYS_FLASH} + * + * The API offers a high level control through {@link CaptureRequest#CONTROL_AE_MODE}, + * which is what the mapper looks at. It will trigger (if specified) flash only for still captures + * which is exactly what we want. + * + * However, we set CONTROL_AE_MODE to ON/OFF (depending + * on which is available) with both {@link Flash#OFF} and {@link Flash#TORCH}. + * + * When CONTROL_AE_MODE is ON or OFF, the low level control, called {@link CaptureRequest#FLASH_MODE}, + * becomes effective, and that's where we can actually distinguish between a turned off flash + * and a torch flash. */ private boolean applyFlash(@NonNull CaptureRequest.Builder builder, @NonNull Flash oldFlash) { @@ -620,6 +631,11 @@ public class Camera2Engine extends CameraEngine { for (int availableMode : availableModes) { if (mode == availableMode) { builder.set(CaptureRequest.CONTROL_AE_MODE, mode); + if (mFlash == Flash.TORCH) { + builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH); + } else if (mFlash == Flash.OFF) { + builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); + } return true; } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java index 65a5f961..689dbd4d 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java @@ -184,7 +184,6 @@ public abstract class CameraEngine implements protected int mAudioBitRate; protected Size mCaptureSize; protected Size mPreviewStreamSize; - protected int mPreviewStreamFormat; protected long mAutoFocusResetDelayMillis; protected int mSensorOffset; @@ -1064,10 +1063,6 @@ public abstract class CameraEngine implements return mFrameManager; } - public final int getPreviewStreamFormat() { - return mPreviewStreamFormat; - } - @Nullable public final CameraOptions getCameraOptions() { return mCameraOptions; diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Mapper.java b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Mapper.java index b1f2261c..d3a60d4d 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Mapper.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Mapper.java @@ -160,7 +160,10 @@ public abstract class Mapper { private static final HashMap HDR = new HashMap<>(); static { + // OFF and TORCH have also a second condition - to CameraCharacteristics.CONTROL_FLASH_MODE - but that does not + // fit into the Mapper interface. TODO review this FLASH.put(Flash.OFF, Arrays.asList(CameraCharacteristics.CONTROL_AE_MODE_ON, CameraCharacteristics.CONTROL_AE_MODE_OFF)); + FLASH.put(Flash.TORCH, Arrays.asList(CameraCharacteristics.CONTROL_AE_MODE_ON, CameraCharacteristics.CONTROL_AE_MODE_OFF)); FLASH.put(Flash.AUTO, Arrays.asList(CameraCharacteristics.CONTROL_AE_MODE_ON_AUTO_FLASH, CameraCharacteristics.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE)); FLASH.put(Flash.ON, Collections.singletonList(CameraCharacteristics.CONTROL_AE_MODE_ON_ALWAYS_FLASH)); FACING.put(Facing.BACK, CameraCharacteristics.LENS_FACING_BACK);