如何在场景较暗的情况下自动打开手电筒进行视频录制?

How to automatically turn on flashlight for video recording when the scene is dark?

我的应用显示预览,按下按钮即可开始录制视频。

我想要实现的是在视频录制开始时自动打开手电筒(手电筒模式)。

但是我找不到这样做的方法。在 Camera2 API 上,我们可以使用 FLASH_MODE_AUTO,它会在场景较暗的情况下拍摄照片时使用手电筒,但这不适用于视频录制。 有这个 FLASH_MODE_TORCH 我可以用它来打开手电筒,就像我想要的那样,但是没有 FLASH_MODE_TORCH_AUTO 可以在场景黑暗时自动打开手电筒..

有一些答案使用设备的环境光传感器 (Sensor.TYPE_LIGHT) 来确定我们是否处于黑暗场景中,但我认为使用前置环境光传感器而不是相机本身。这并不理想,因为环境光可能很低,但后置摄像头能够调整曝光级别,以在不使用闪光灯的情况下获得足够好的图像质量。所以理想情况下,如果相机说 'flash is required' 那么只有应用程序激活 FLASH_MODE_TORCH.

由于应用程序显示预览,设备在按下按钮之前已经知道是否需要闪光灯,有没有办法在预览期间确定是否需要闪光灯?

请在需要的地方试试下面的方法

下面是相机 API

public void switchFlashOnMode() {
        Camera.Parameters p = getCamera().getParameters();
        try {
            //p.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
            p.setFlashMode(Parameters.FLASH_MODE_AUTO);
            getCamera().setParameters(p);
            getCamera().startPreview();
            isFlashTorch = true;
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public void switchFlashOffMode() {
        Camera.Parameters p = getCamera().getParameters();
        try {
            p.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
            getCamera().setParameters(p);
            Thread.sleep(200);
            getCamera().stopPreview();
            isFlashTorch = false;
        }catch (Exception e){
            e.printStackTrace();
        }
    }

下面是 Camera2 API

 void switchFlashMode() {
        if (!flashSupport) return;

        try {
            if (isFlashTorch) {
                isFlashTorch = false;
                requestBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_OFF);
            } else {
                isFlashTorch = true;
                  //requestBuilder.set(CaptureRequest.FLASH_MODE,CameraMetadata.FLASH_MODE_TORCH);
                  requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
            }    

            cameraCaptureSession.setRepeatingRequest(requestBuilder.build(), null, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

希望对您有所帮助

终于弄明白了,gpuser 的回答使用了正确的标志,但还不完整 - 仍然需要编写回调代码并在需要时打开手电筒。

我还发现对于视频录制,我们仍然使用相同的 Camera2 API 初始化和配置步骤,只是一些回调会被触发多次,所以我添加了一个标志来执行闪光只检测一次。

1)相机开始抓拍后,运行这段代码

performAutoTorchDetectionOnce = true; // set this flag first, will be used later
captureRequestBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); // CONTROL_AE_MODE_ON_AUTO_FLASH is important here, to enable flash detection
captureSession.setRepeatingRequest(captureRequestBuilder.build(), captureCallback, null);

2) 这是我的 captureCallback 实现,请根据您的需要进行更改。它的要点是最终相机捕获将陷入两种状态之一,CONTROL_AE_STATE_CONVERGED 或 CONTROL_AE_STATE_FLASH_REQUIRED。这两个状态表示自动曝光算法已经完成运行ning,如果收敛则表示不需要闪光灯,而flash_required则表示我们必须打开闪光灯。在后者中,我们将需要在下一步中手动打开闪光灯。

private CameraCaptureSession.CaptureCallback captureCallback =
    new CameraCaptureSession.CaptureCallback() {
            @Override
            public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request,
                                         long timestamp, long frameNumber) {
                super.onCaptureStarted(session, request, timestamp, frameNumber);
            }

            @Override
            public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
                super.onCaptureCompleted(session, request, result);

                Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                if (aeState != null) {
                    if (performAutoTorchDetectionOnce) {
                        if (aeState == CameraMetadata.CONTROL_AE_STATE_CONVERGED            // CONTROL_AE_STATE_CONVERGED means Auto-exposure has finished
                            || aeState == CameraMetadata.CONTROL_AE_STATE_FLASH_REQUIRED) { // CONTROL_AE_STATE_FLASH_REQUIRED means Auto-exposure has finished, but flash is required
                            performAutoTorchDetectionOnce = false;
                            enableTorch(aeState == CameraMetadata.CONTROL_AE_STATE_FLASH_REQUIRED);
                        }
                    }
                }
            }
    };

3)这是 enableTorch 的实现。我尝试将 CONTROL_AE_MODE 保留为 CONTROL_AE_MODE_ON_AUTO_FLASH 但它不起作用,手电筒灯不亮,所以我必须将其更改为 CONTROL_AE_MODE_ON。

public synchronized void enableTorch(boolean enable) {
        Timber.d("enableTorch(" + enable + ") called");
        try {
            if (isCaptureStarted()) {
                if (enable) {
                    captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
                } else {
                    captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
                }
                captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
                captureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null);
            }
        } catch (CameraAccessException e) {
            Timber.e(e, "enableTorch(" + enable + ") failed: ");
        }
    }