Ошибка с API-интерфейсом Camera2 при вызове session.setRepeatingRequest (captureRequestBuilder.build (), null, backgroundHandler) - PullRequest
0 голосов
/ 08 марта 2019

Я пытаюсь сделать приложение предварительного просмотра камеры. Когда я звоню

session.setRepeatingRequest(captureRequestBuilder.build(), null, backgroundHandler)

Я получаю эту ошибку:

E/HandlerDispatcher: IllegalArgumentException while invoking public abstract void android.hardware.camera2.CameraCaptureSession$StateCallback.onConfigured(android.hardware.camera2.CameraCaptureSession)
    java.lang.IllegalArgumentException: Each request must have at least one Surface target
        at android.hardware.camera2.impl.CameraDeviceImpl.submitCaptureRequest(CameraDeviceImpl.java:934)
        at android.hardware.camera2.impl.CameraDeviceImpl.setRepeatingRequest(CameraDeviceImpl.java:993)
        at android.hardware.camera2.impl.CameraCaptureSessionImpl.setRepeatingRequest(CameraCaptureSessionImpl.java:239)
        at anthe.rwca.org.robocup19.MainActivity$3.onConfigured(MainActivity.java:147)
        at java.lang.reflect.Method.invoke(Native Method)
        at android.hardware.camera2.dispatch.InvokeDispatcher.dispatch(InvokeDispatcher.java:39)
        at android.hardware.camera2.dispatch.HandlerDispatcher$1.run(HandlerDispatcher.java:65)
        at android.os.Handler.handleCallback(Handler.java:789)
        at android.os.Handler.dispatchMessage(Handler.java:98)
        at android.os.Looper.loop(Looper.java:164)
        at android.os.HandlerThread.run(HandlerThread.java:65)

Это мой код:

CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(@NonNull CameraDevice camera) {
            cameraDevice = camera;
            createCaptureSession();
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice camera) {

        }

        @Override
        public void onError(@NonNull CameraDevice camera, int error) {

        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textureView = findViewById(R.id.textureView);
    }

    @Override
    protected void onResume() {
        super.onResume();
        textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
            @Override
            public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
                openBackgroundHandler();
                setupCamera();
                openCamera();
            }

            @Override
            public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

            }

            @Override
            public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
                return false;
            }

            @Override
            public void onSurfaceTextureUpdated(SurfaceTexture surface) {

            }
        });
    }

    @Override
    protected void onPause() {
        super.onPause();
        closeBackgroundHandler();
    }

    private void setupCamera() {
        cameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);
        try {
            cameraIDs = cameraManager.getCameraIdList();
            cameraID = cameraIDs[0];
            Log.i(TAG, String.valueOf(cameraIDs.length));
            Log.i(TAG, cameraID);
            CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraID);
            StreamConfigurationMap streamConfigurationMap = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
            size = streamConfigurationMap.getOutputSizes(SurfaceTexture.class)[0];
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    @SuppressLint("MissingPermission")
    private void openCamera() {
        try {
            cameraManager.openCamera(cameraID, stateCallback, backgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private void openBackgroundHandler() {
        handlerThread = new HandlerThread("camera_app");
        handlerThread.start();
        backgroundHandler = new Handler(handlerThread.getLooper());
    }

    private void closeBackgroundHandler() {
        handlerThread.quit();
        handlerThread = null;
        backgroundHandler = null;
    }

    private void createCaptureSession() {
        SurfaceTexture surfaceTexture = textureView.getSurfaceTexture();
        surfaceTexture.setDefaultBufferSize(size.getWidth(), size.getHeight());
        Surface surface = new Surface(surfaceTexture);
        try {
            cameraDevice.createCaptureSession(Collections.singletonList(surface), new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession session) {
                    try {
                        CaptureRequest.Builder captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                        session.setRepeatingRequest(captureRequestBuilder.build(), null, backgroundHandler);

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

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession session) {

                }
            }, backgroundHandler);
        } catch (CameraAccessException e1) {
            e1.printStackTrace();
        }
    }

Я новичок в Camera2 API, поэтому понятия не имею, что означает ошибка. Я посмотрел в интернете, но не смог найти подобную проблему.

Я также хотел бы знать, как получить предварительно просматриваемый кадр в растровом изображении или в байтовом массиве nv21, чтобы я мог выполнить на нем некоторую обработку изображения и отобразить обработанное изображение в виде растрового изображения (или есть способ напрямую применить некоторую обработку изображения к предварительно просмотренному кадру? Заранее спасибо.

1 Ответ

1 голос
/ 08 марта 2019

Взгляните на образец Camera2Basic , чтобы помочь с общим потоком вещей.

В данном конкретном случае - сеанс захвата может иметь несколько целевых выходных поверхностей (например, одну для предварительного просмотра, одну для неподвижного захвата JPEG). Каждый запрос захвата может быть нацелен на любое подмножество этих выходных данных (поэтому повторяющийся запрос нацелен на выходные данные предварительного просмотра, в то же время захватывает целевые выходные данные JPEG и т. Д.).

Таким образом, ваш запрос захвата должен иметь одну или несколько Поверхностей, добавленных в качестве целей, и Поверхности должны быть одной из тех, которые включены в создание сеанса.

Поскольку у вас есть только одна поверхность в вашей сессии, просто добавьте

 captureRequestBuilder.addTarget(surface)

до вызова setRepeatingRequest.

Если вы хотите получить Java ByteBuffer данных YUV, вы можете добавить ImageReader в качестве выходной цели, как для сеанса, так и для запроса захвата. Обратите внимание, что гарантированно поддерживается только гибкий формат YUV YUV_420_888, поэтому вам придется вручную настроить его, если вам действительно нужно что-то в компоновке NV21 (на любом данном устройстве YUV_420_888 может быть NV21 под капотом, но нет гарантии об этом).

...