当我尝试使用ImageReader获取每个Camera2帧时,出现“图像已关闭”的错误提示。

5
我尝试使用Camera2 API获取摄像头的每一帧进行图像处理,但是遇到一个致命错误,提示:

FATAL EXCEPTION: main Process: com.example.avoor.camera2api, PID: 2831 java.lang.IllegalStateException: Image is already closed

我成功地打开了相机并将其发送到TextureView进行预览,但是当涉及到OnImageAvailableListener时,应用程序会崩溃。

这是使用的代码:

protected void createCameraPreview() {
    try {
        SurfaceTexture texture = textureView.getSurfaceTexture();
        assert texture != null;
        texture.setDefaultBufferSize(imageDimension.getWidth(), imageDimension.getHeight());
        Surface surface = new Surface(texture);
        ImageReader reader = ImageReader.newInstance(640, 480, ImageFormat.YUV_420_888, 3);
        //reader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);
        captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        captureRequestBuilder.addTarget(surface);
        captureRequestBuilder.addTarget(reader.getSurface());
        List<Surface> outputSurfaces = new ArrayList<>();
        outputSurfaces.add(reader.getSurface());
        outputSurfaces.add(surface);
        ///////////////////////////////////////////////////////////////////
        ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() {
            @Override
            public void onImageAvailable(ImageReader reader) {
                Image image = null;
                try {
                    image = reader.acquireLatestImage();
                    final byte[] bytes;
bytes = convertYUV420888ToNV21(image);
                                Log.d(TAG,"Height:"+String.valueOf(image.getHeight())+
                                        " Width: "+String.valueOf(image.getWidth()));
                                Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
                                imageView.setImageBitmap(bitmap);

                            }
                        }
                    });
                }
                catch (IllegalStateException e) {
                    Log.e(TAG, "Too many images queued for saving, dropping image for request: ");
return;
                }
                finally {
                    if (image != null) {
                        image.close();
                    }
                }
            }
        };
        reader.setOnImageAvailableListener(readerListener, mBackgroundHandler);

        ///////////////////////////////////////////////////////////////////
        cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback(){
            @Override
            public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                //The camera is already closed
                if (null == cameraDevice) {
                    return;
                }
                // When the session is ready, we start displaying the preview.
                cameraCaptureSessions = cameraCaptureSession;
                updatePreview();
            }
            @Override
            public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
                Toast.makeText(MainActivity.this, "Configuration change", Toast.LENGTH_SHORT).show();
            }
        }, mBackgroundHandler);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

并且在这里:

protected void updatePreview() {
    if(null == cameraDevice) {
        Log.e(TAG, "updatePreview error, return");
    }
    captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
    try {
        cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(), null, mBackgroundHandler);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

当相机打开时,我已经启动了BackgroundThread

1个回答

4

你的读者可能被垃圾回收了;你没有将它保存在任何地方,在createCameraPreview结束时就超出了范围。

虽然你从中得到了一个Surface,但是Surface就像一个弱引用;它不能阻止ImageReader被回收。


1
将ImageReader放置在你的活动类中,例如。 - Eddy Talvala
谢谢!我刚刚这样做了,不再出现异常了!但是我的ImageView中也没有显示任何图像。虽然这只是一个测试应用程序,但是我该如何在ImageView中显示接收到的帧呢?我所做的方式有问题吗? - Reza Hosseini
Bitmap.decodeByteArray无法解码原始YUV(NV21或YUV_420_888)。所以我认为您的Bitmap实际上是空的。如果需要,您需要自行将其转换为位图,不幸的是。 - Eddy Talvala
是的,它是空的,我想知道为什么,因为每次在字节中我都会得到空异常。 - Reza Hosseini
@EddyTalvala 我也遇到了同样的错误。但我不太明白你说的话。你能给我展示一些代码吗? - Vikas Acharya

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接