1

我会解释我的情况。我正在尝试做一个应用程序,其中每 5 秒拍摄一张图像,一张没有闪光灯,然后在 5 秒后拍摄一张有闪光灯的图像,并且每次都重复此操作。所以它需要一个没有闪光,一个有闪光,一个没有闪光,一个有闪光......无限。

情况是,使用我的代码,我可以在某些设备上执行此操作,但相同的代码在其他设备上无法正常工作。IE:

  • BQ Aquaris X5 Plus:无闪光图像是正确的,但闪光图像将只是白色。
  • BQ Aquaris E5:不会闪光。

这怎么可能,我尝试过的所有设备都是 Camera2 API 的 LEGACY 硬件支持级别。

这是我的代码中的一些重要方法(由于字符限制,我无法发布所有代码)。我从谷歌示例开始:

这个 setAutoFlash 做了上面提到的。

private void setAutoFlash(CaptureRequest.Builder requestBuilder) {
        if (mFlashSupported) {
            if(phototaken) {
                requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
                requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
            }else{
                requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_SINGLE);
            }
        }
    }

另一种适用于某些设备和 bq aquaris e5,但不会在 bq aquaris x5 plus 中触发闪光灯。

private void setAutoFlash(CaptureRequest.Builder requestBuilder) {
        if (mFlashSupported) {
            if(phototaken) {
                requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
                requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
            }else{
                requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
                requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
            }
        }
    }

还有我的 captureStillPicture

private void captureStillPicture() {
        try {
            final Activity activity = getActivity();
            if (null == activity || null == mCameraDevice) {
                return;
            }
            // This is the CaptureRequest.Builder that we use to take a picture.
            final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            captureBuilder.addTarget(mImageReader.getSurface());

            // 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, getOrientation(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);
            phototaken = !phototaken;

        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
}

问题是,我做错了什么,所以它不适用于所有设备?任何帮助都会很棒。

4

1 回答 1

4

闪光灯有两个级别的控制 - 手动和由自动曝光程序控制。您目前正在将它们混合在一起。

如果要手动触发闪光灯,则需要将 AE_MODE 设置为 AE_MODE_OFF 或 AE_MODE_ON;不是任何 FLASH 模式。然后,FLASH_MODE 将控制闪光灯是否处于手电筒模式、关闭或针对给定请求触发一次。

由于您总是将 AE_MODE 置于其中一种 FLASH 状态,因此您对 FLASH_MODE 所做的操作应该无关紧要,除非某些特定设备中出现错误。

如果要保证每隔一张照片都闪光,强制闪光照片需要使用AE_MODE_ON_ALWAYS_FLASH,不闪光照片需要使用AE_MODE_ON;不要触摸 FLASH_MODE。现在,使用 AUTO_FLASH,是否闪光取决于设备,因此您会看到来自不同设备和照明条件的不同行为 - 有些会闪光,有些不会。

您没有做的另一件事是运行预捕获序列。这对于闪光照片至关重要,因为它允许设备触发预闪以确定正确的闪光功率、焦点和白平衡。

要运行预捕获,请根据需要设置 AE_MODE,然后针对一个请求将 AE_PRECAPTURE_TRIGGER 设置为 START。这会将 AE_STATE 转换为 PRECAPTURE,并且会在那里停留若干帧;一旦 AE_STATE 不再是 PRECAPTURE,您就可以发出实际的图像捕获请求。确保在整个过程中保持 AE_MODE 一致。

示例应用程序Camera2Basic实现了预捕获序列,所以看看那里;它还有一些优化可以跳过预捕获,以防场景不够暗而需要闪光灯,但由于您想强制闪光,这与您无关。

于 2017-03-28T21:34:18.407 回答