Застрял в последовательности до захвата - PullRequest
0 голосов
/ 08 мая 2018

В данный момент я пытаюсь создать фрагмент камеры на основе примера Camera2Basic. Основные отличия заключаются в том, что пользователь может переключаться между режимами вспышки (авто, вкл., Выкл.) И что отображается предварительный просмотр снятого снимка, поэтому пользователь может решить, сохранять или снимать снятый снимок.
Проблемы возникают при использовании вспышки в постоянно включенном режиме. Иногда последовательность предварительного захвата не завершается и приложение зависает. Предварительный просмотр все еще работает, а пользовательский интерфейс отзывчив, но обработка достигает «бесконечного цикла».
Согласно 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 голосов
/ 14 мая 2018

После еще одного исследования я не смог найти причину, почему 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);
}

Может быть, это проблема с устройством, которое я использую, из-за того, что настройка для постоянной вспышки не работает.

...