闪光灯问题

Flash light issue

我正在努力将相机应用程序从 camera1 迁移到 camera2。我在摩托罗拉 G5 和三星 Galaxy S4 上遇到一个奇怪的问题,闪光灯模式打开时,每次我点击预览视图进行手动对焦时,闪光灯都会闪光。

有人 运行 遇到同样的问题吗? 这是我用于点击聚焦功能的代码:

        val focusAreaTouch = calculateFocusArea(pointOfInterestX, pointOfInterestY, sensorArraySize)

        //cancel any existing AF trigger
        previewRequestBuilder?.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL)
        previewRequestBuilder?.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF)

        try {
            captureSession?.capture(previewRequestBuilder?.build(), captureCallback, null)
        }catch (ex: Exception) {
            Log.e(TAG, "Tap To Focus -> Failed to cancel any existing AF trigger.", ex)
        }

        Log.e(TAG, "AF Regions: " + previewRequestBuilder?.get(CaptureRequest.CONTROL_AF_REGIONS)?.first()?.rect)

        //Then we add a new AF trigger with focus region
        previewRequestBuilder?.set(CaptureRequest.CONTROL_AF_REGIONS, arrayOf(focusAreaTouch))

        previewRequestBuilder?.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO)
        previewRequestBuilder?.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO)
        previewRequestBuilder?.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START)

以下是我检查 AE 状态的方法:

private fun process(result: CaptureResult) {
    when (state) {
        CameraState.STATE_LOCKING -> {
            val af = result.get(CaptureResult.CONTROL_AF_STATE) ?: return
            if (af == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED
                    || af == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED
                    || af == CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED) {
                val ae = result.get(CaptureResult.CONTROL_AE_STATE)
                if (ae == null || ae == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
                    state = CameraState.STATE_CAPTURING
                    onReady()
                } else {
                    state = CameraState.STATE_LOCKED
                    onPreCaptureRequired()
                }
            }
        }
        CameraState.STATE_PRECAPTURE -> {
            val ae = result.get(CaptureResult.CONTROL_AE_STATE)
            if (ae == null || ae == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
                    ae == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED ||
                    ae == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
                state = CameraState.STATE_WAITING
            }
        }
        CameraState.STATE_WAITING -> {
            val ae = result.get(CaptureResult.CONTROL_AE_STATE)
            if (ae == null || ae != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
                state = CameraState.STATE_CAPTURING
                onReady()
            }
        }
    }
}

原因是如果你也设置了AE,那么AE算法会在需要时触发闪光灯,根据当前光线条件适当调整曝光。

要解决此问题,请以不同方式处理预览和照片捕获会话的闪光灯配置。使用下一个函数配置您的 Request Builders


有4个地方需要调用setFlash()。请注意,该方法仅设置给定的构建器闪存配置,您仍然需要将构建器传递给目标会话。预览会话将作为重复请求

  1. 最初配置 Preview 时,isPreviewSession 设置为 True,因此此类操作因为点击对焦不会触发闪光灯。
  2. 拍照时,在用户按下快门按钮的那一刻, 使用 isPreviewSession 集配置 Preview 请求构建器 错误。将其设置为 False 意味着这次 Preview 构建器 实际上将具有所需的目标 Flash 配置,因此 Capture Session Callback知道什么时候Focus, AE 等使用目标闪存配置会聚,这 AE算法可能需要。
  3. 然后,当收敛并准备启动 捕获会话 时,调用 再次 setFlash 传递 Capture Request Builder 从 cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE), 再次将 isPreviewSession 设置为 False.
  4. 最后,当捕获结束时,在通知的回调中 关于捕获完成,必须再次重新配置 Preview 请求构建器 但是这次 isPreviewSession 设置为 True 所以闪光灯 状态再次设置为关闭。

static final int FLASH_MODE_OFF = 0;
static final int FLASH_MODE_AUTO = 1;
static final int FLASH_MODE_ON = 2;
static final int FLASH_MODE_TORCH = 3;


public void setFlash(@NonNull final CaptureRequest.Builder builder, 
                             final boolean isPreviewSession, final int flashMode)
{
    if (isPreviewSession == true)
    {
        // For preview session

        builder.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_ON);

        if (flashMode == FLASH_MODE_TORCH)
        {
            builder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_TORCH);
        }
        else
        {
            builder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_OFF);
        }
    }
    else
    {
        // For capture session

        if (flashMode == FLASH_MODE_OFF)
        {
            builder.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_ON);
            builder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_OFF);
        }
        else if (flashMode == FLASH_MODE_AUTO)
        {
            builder.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH);
            builder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_OFF);
        }
        else if (flashMode == FLASH_MODE_ON)
        {
            builder.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
            builder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_SINGLE);
        }
        else if (flashMode == FLASH_MODE_TORCH)
        {
            builder.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_ON);
            builder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_TORCH);
        }
    }
}