卡在预捕获序列中

时间:2018-05-08 08:34:38

标签: android android-camera2

目前,我正在尝试根据Camera2Basic示例创建一个相机Fragment。主要区别在于用户可以在闪光模式(自动,开启,关闭)之间切换以及显示拍摄静止拍摄的预览的可能性,因此用户可以决定是否应该保存或丢弃拍摄的照片。登记/> 在始终开启模式下使用闪光灯时出现问题。有时,预捕获序列无法完成,应用程序卡住了。预览仍然有效,并且UI具有响应性,但处理会达到“无限循环” 根据Camera2Basic,我使用了这个CaptureCallback。

private CameraCaptureSession.CaptureCallback mPreviewCaptureCallback =
    new CameraCaptureSession.CaptureCallback() {
        private int counter = 0; // Counts failed attempts to gain AF or complete precapture
            @Override
            public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
                process(result);
            }

            @Override
            public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) {
                process(partialResult);
            }

            private void process(CaptureResult result) {
                Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
                switch (mState) {
                    case STATE_PREVIEW:
                        // Do nothing
                        break;
                    case STATE_WAIT_LOCK:
                        if (afState == null) {
                            counter = 0;
                            captureStillImage();
                        } else if (afState == CaptureRequest.CONTROL_AF_STATE_FOCUSED_LOCKED ||
                                afState == CaptureRequest.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) {
                            if (aeState == null ||
                                    aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
                                mState = STATE_PICTURE_CAPTURED;
                                captureStillImage();
                            } else {
                                runPrecaptureSequence();
                            }
                            counter = 0;
                        } else if(counter > 50) {
                            counter = 0;
                            restartFocus();
                        } else {
                            counter++;
                            Log.d(TAG, "STATE_WAIT_LOCK - Counter : " + counter);
                        }
                        break;
                    case STATE_WAIT_PRECAPTURE:
                        if (aeState == null ||
                                aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
                                aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
                            mState = STATE_WAIT_NON_PRECAPTURE;
                        }
                        break;
                    case STATE_WAIT_NON_PRECAPTURE:
                        if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
                            mState = STATE_PICTURE_CAPTURED;
                            captureStillImage();
                        } else if (counter > 50) {
                            Log.d(TAG, "STATE_WAIT_NON_PRECAPTURE - Restart");
                            counter = 0;
                            restartPrecapture();
                        } else {
                            counter++;
                            Log.d(TAG, "STATE_WAIT_NON_PRECAPTURE - Counter : " + counter);
                        }
                        break;
                }
            }
        };

由于我在过去遇到一个类似的问题,AF未被锁定,我创建了一种重启AF的方法。

private void restartFocus() {
    try {
        mPreviewRequestBuilder.set(
                CaptureRequest.CONTROL_AF_TRIGGER,
                CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);

        mCaptureSession.capture(
                mPreviewRequestBuilder.build(),
                mPreviewCaptureCallback,
                mBackgroundHandler);

        lockFocus();
    } catch (CameraAccessException cae) {
        cae.printStackTrace();
    }
}

private void lockFocus() {
    try {
        mPreviewRequestBuilder.set(
                CaptureRequest.CONTROL_AF_TRIGGER,
                CaptureRequest.CONTROL_AF_TRIGGER_START);
        mState = STATE_WAIT_LOCK;
        mCaptureSession.capture(
                mPreviewRequestBuilder.build(),
                mPreviewCaptureCallback,
                mBackgroundHandler);
    } catch (CameraAccessException cae) {
        cae.printStackTrace();
    }
}

所以我决定第二次使用这个想法并重新启动预捕获序列。

private void restartPrecapture() {
    try {
        mPreviewRequestBuilder.set(
                CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
                CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL);
        mCaptureSession.capture(mPreviewRequestBuilder.build(),
                mPreviewCaptureCallback,
                mBackgroundHandler);

        runPrecaptureSequence();
    } catch (CameraAccessException cae) {
        cae.printStackTrace();
    }
}

private void runPrecaptureSequence() {
    try {
        setFlash(mPreviewRequestBuilder);
        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
                CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
        mState = STATE_WAIT_PRECAPTURE;
        mCaptureSession.capture(mPreviewRequestBuilder.build(),
                mPreviewCaptureCallback,
                mBackgroundHandler);
    } catch (CameraAccessException cae) {
        cae.printStackTrace();
    }
}

检查Logcat显示,应用程序有时卡在STATE_WAIT_NON_PRECAPTURE中,而aeState仍然是CaptureResult.CONTROL_AE_STATE_PRECAPTURE。如果计数器在此状态下达到50,则按预期调用 restartPrecapture()
目前我在使用CONTROL_AE_MODE_ON_ALWAYS_FLASH时只遇到这个问题,但有时我会在此之前拍摄几十张照片,所以可能使用自动或禁用闪光灯,可能性要小得多。

private void setFlash(CaptureRequest.Builder requestBuilder) {
    switch(mFlashMode) {
        case FLASH_AUTO:
            setFlashAuto(requestBuilder);
            break;
        case FLASH_ON:
            setFlashOn(requestBuilder);
            break;
        case FLASH_OFF:
            setFlashOff(requestBuilder);
            break;
    }
}

private void setFlashAuto(CaptureRequest.Builder requestBuilder) {
    requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
            CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH);
}

private void setFlashOn(CaptureRequest.Builder requestBuilder) {
    requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
            CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
}

private void setFlashOff(CaptureRequest.Builder requestBuilder) {
    requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
            CameraMetadata.CONTROL_AE_MODE_ON);
    requestBuilder.set(CaptureRequest.FLASH_MODE,
            CameraMetadata.FLASH_MODE_OFF);
}

当预捕获序列似乎无法完成时,我该如何处理这种情况?

1 个答案:

答案 0 :(得分:0)

经过一些研究后,我找不到理由,为什么CONTROL_AE_MODE_ON_ALWAYS_FLASH无法正常工作,所以我做了一个解决方法。我像这样改变了我的setFlashOn()方法

private void setFlashOn(CaptureRequest.Builder requestBuilder) {
    requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
            CameraMetadata.CONTROL_AE_MODE_ON);
    requestBuilder.set(CaptureRequest.FLASH_MODE,
            CameraMetadata.FLASH_MODE_SINGLE);
}

也许这是我正在使用的设备的问题,总是闪存的设置不起作用。