如何在场景较暗的情况下自动打开手电筒进行视频录制?
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: ");
}
}
我的应用显示预览,按下按钮即可开始录制视频。
我想要实现的是在视频录制开始时自动打开手电筒(手电筒模式)。
但是我找不到这样做的方法。在 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: ");
}
}