Камера Android 2 api BufferQueue была оставлена

Я тестирую новый Android camera2 API, и я хочу контролировать каждый кадр с камеры. Для этого я создаю ImageReader и настраиваю разрешение и формат изображения.

ImageReader imageReader = ImageReader.newInstance(1280,720,ImageFormat.YUV_420_888,1);
imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
    @Override
    public void onImageAvailable(ImageReader reader) {
        Image image = reader.acquireLatestImage();
        Log.i(MainActivity.LOG_TAG,"imageReader: "+System.currentTimeMillis());
        image.close();
    }
},null);

После этого я создаю новый CaptureRequest с параметром TEMPLATE_PREVIEW и добавляю к нему цель imageReader. Для cameraCaptureSession я создаю новый setRepeatingRequest с этим запросом

 try {
    final CaptureRequest.Builder builder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);

    builder.addTarget(imageReader.getSurface());

    mCameraDevice.createCaptureSession(
            Arrays.asList(imageReader.getSurface()),
            new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(CameraCaptureSession session) {
                    mSession = session;
                    try {
                        mSession.setRepeatingRequest(builder.build(),null,null);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }
                }
                @Override
                public void onConfigureFailed(CameraCaptureSession session) {

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

Когда я открыл камеру и начал просматривать то, что у меня есть с предварительным просмотром, я получаю исключение. Но до исключения я получил предварительный просмотр, и после этого у меня есть исключение

10-30 16:00:32.850    1390-1894/.camera2tutorial E/BufferQueueProducer﹕ [unnamed-1390-1] dequeueBuffer: BufferQueue has been abandoned
10-30 16:00:32.850    1390-1894/.camera2tutorial E/Legacy-CameraDevice-JNI﹕ LegacyCameraDevice_nativeProduceFrame: Error while producing frame No such device (-19).
10-30 16:00:32.850    1390-1894/.camera2tutorial W/SurfaceTextureRenderer﹕ Surface abandoned, dropping frame.
    android.hardware.camera2.legacy.LegacyExceptionUtils$BufferQueueAbandonedException
            at android.hardware.camera2.legacy.LegacyExceptionUtils.throwOnError(LegacyExceptionUtils.java:64)
            at android.hardware.camera2.legacy.LegacyCameraDevice.produceFrame(LegacyCameraDevice.java:516)
            at android.hardware.camera2.legacy.SurfaceTextureRenderer.drawIntoSurfaces(SurfaceTextureRenderer.java:699)
            at android.hardware.camera2.legacy.GLThreadManager$1.handleMessage(GLThreadManager.java:103)
            at android.os.Handler.dispatchMessage(Handler.java:98)
            at android.os.Looper.loop(Looper.java:145)
            at android.os.HandlerThread.run(HandlerThread.java:61)

Как я могу исправить это?

Я использую Samsung Galaxy S5 и Android API 21

Ответ 1

Убедитесь, что вы держите ссылку на созданный ImageReader, вероятно, везде, где вы определили mSession.

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

Ответ 2

У меня была такая же проблема при переключении между действиями в моем приложении, и это было после вызова onSurfaceTextureDestroyed(), который возвращал только false. Но я сделал это, изменив его на

public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
            Log.e(TAG, "onSurfaceTextureDestroyed");
            if(cameraDevice != null){
                closeCamera();

                cameraDevice = null;
            }
            return false;
        }

и это сработало для меня.

Ответ 3

Я нашел решение, это сработало для меня, заразить ошибку в выборе правильного размера, поэтому при использовании MediaRecorder.setVideoSize() используйте этот метод, чтобы выбрать оптимальный размер

private static Size chooseOptimalSize(Size[] choices, int width, int height) {
        Size bigEnough = null;
        int minAreaDiff = Integer.MAX_VALUE;
        for (Size option : choices) {
            int diff = (width*height)-(option.getWidth()*option.getHeight()) ;
            if (diff >=0 && diff < minAreaDiff &&
                    option.getWidth() <= width &&
                    option.getHeight() <= height) {
                minAreaDiff = diff;
                bigEnough = option;
            }
        }
        if (bigEnough != null) {
            return bigEnough;
        } else {
            Arrays.sort(choices,new CompareSizeByArea());
            return choices[0];
        }

    }