Camera2 ImageReader зависает через некоторое время с сообщением «Не удалось освободить буфер»

#java #android #android-camera2

#java #Android #android-camera2

Вопрос:

У меня проблема с API camera2 для Android. Моя конечная цель здесь — иметь массив байтов, который я могу редактировать с помощью opencv, одновременно отображая предварительный просмотр пользователю (например, OCR с предварительным просмотром). Я создал запрос на захват и добавил ImageReader в качестве цели. Затем в OnImageAvailableListener я получаю изображение, преобразую его в растровое изображение, а затем отображаю его в ImageView (и поворачиваю его).

Моя проблема в том, что через несколько секунд предварительный просмотр останавливается (после постепенного замедления) и в журнале om появляется следующая ошибка: E / BufferItemConsumer: [ImageReader-1225x1057f100m2-18869-0] Не удалось освободить буфер: неизвестная ошибка -1 (1)

Как вы можете видеть в моем коде, я уже пытался закрыть img после получения из него моего byte[] . Я также попытался очистить буфер. Я попытался закрыть ImageReader, но это, конечно, помешало мне получить какие-либо дополнительные изображения (выдает исключение).

Может кто-нибудь, пожалуйста, помочь мне понять, что я делаю не так? Я безрезультатно просматривал Google.

Это мой OnImageAvailableListener, дайте мне знать, если вам понадобится больше моего кода для помощи:

 private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
            = new ImageReader.OnImageAvailableListener() {
        @Override
        public void onImageAvailable(ImageReader reader) {

            Image img = reader.acquireLatestImage();
            final ImageView iv = findViewById(R.id.camPrev);

            try{

                if (img==null) throw new NullPointerException("null img");
                ByteBuffer buffer = img.getPlanes()[0].getBuffer();
                byte[] data = new byte[buffer.remaining()];
                buffer.get(data);
                final Bitmap b = BitmapFactory.decodeByteArray(data, 0, data.length);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        iv.setImageBitmap(b);
                        iv.setRotation(90);
                    }
                });
            } catch (NullPointerException ex){
                showToast("img is null");
            }finally {
                if(img!=null)
                    img.close();
            }
        }
    };
 

Редактировать — добавление cameraStateCallback

 private CameraDevice.StateCallback mCameraDeviceStateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(CameraDevice cameraDevice) {
            mCameraDevice = cameraDevice;
            showToast("Connected to camera!");
            createCameraPreviewSession();
        }

        @Override
        public void onDisconnected(CameraDevice cameraDevice) {
            closeCamera();
        }

        @Override
        public void onError(CameraDevice cameraDevice, int i) {
            closeCamera();
        }
    };

    private void closeCamera() {
        if (mCameraDevice != null) {
            mCameraDevice.close();
            mCameraDevice = null;
        }

    }
 

Комментарии:

1. Кажется, ваш код для этой части правильный, но можете ли вы изменить buffer.remaining() buffer.capacity() и сообщить мне результаты? Я уже однажды реализовал camera2 и использовал емкость, насколько я помню.

2. Также вы закрываете CameraDevice после достижения onPause () ?

3. Можете ли вы опубликовать свой код части stateCallBack?

4. Конечно, добавив обратный вызов состояния cameradevice вместе с closeCamera относительно onPause, я вызываю ту же функцию closeCamera вместе с stopBackgroundThread, которая должна позже выполнять саму обработку. Кстати, может быть, важно упомянуть, что я ОТКРЫВАЮ устройство камеры только на onWindowDocusChanged, а не на onResume или onCreate (поскольку я обнаружил, что оба они иногда пытаются загрузить, когда ImageView по-прежнему имеет значение null и не может выяснить, как создать какой-то прослушиватель состояния для ImageView (например, одинвид текстуры имеет)).

5. Я также пытался перейти на buffer.capacity, но, к сожалению, это не помогло..

Ответ №1:

Похоже, вы использовали setRepeatingRequest() формат Jpeg. Это может не полностью поддерживаться на вашем устройстве, также зависит от выбранного вами разрешения изображения. Обычно мы используем createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) в этих случаях и получаем формат YUV или raw из ImageReader.

Я бы попытался выбрать низкое разрешение для Jpeg: возможно, этого будет достаточно, чтобы ImageReader продолжал работать.

Комментарии:

1. Спасибо. Дело в том, что я хочу, чтобы камера непрерывно передавала изображения в программу чтения изображений для создания обрабатываемого предварительного просмотра, пока не произойдет событие. Ответит ли ваше решение на эту потребность?

2. Так и должно быть. Что вы подразумеваете под словами обрабатываемый предварительный просмотр , я не совсем понимаю.

3. Допустим, я хочу получить изображение с камеры, перевести его в оттенки серого и только затем показать его на ImageView. Просто предварительно обработайте его перед отображением пользователю.

4. Если вы хотите преобразовать входные данные камеры в оттенки серого, YUV должен быть вашим выбором.

5. Есть несколько других шагов обработки, которые я хочу выполнить. Я протестирую ваше решение и обновлю. Спасибо!