将ImageReader添加为目标表面的Camera2API滞后于我的相机预览

时间:2017-04-06 11:49:34

标签: android image-processing camera android-camera2

我正在尝试使用ImageReader处理帧,同时还在SurfaceView上显示摄像机预览。如果我添加的唯一目标曲面是SurfaceView,则预览是平滑的,但如果我将ImageReader添加为第二个目标,则预览会开始严重滞后。为什么会这样?我试图创建一个HandlerThread和一个Handler并使用它们,但它并没有改变一件事。我现在唯一想到的就是获取并关闭下一张图像。

public void startBackgroundThread() {
    handlerThread = new HandlerThread("Image Processing Thread");
    handlerThread.start();
    handler = new Handler(handlerThread.getLooper());
}

在此配置相机:

public void configureCamera() {
    try {
        CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
        StreamConfigurationMap configs = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);

        Size[] sizes = configs.getOutputSizes(ImageFormat.YUV_420_888);
        imageReader = ImageReader.newInstance(sizes[0].getWidth(), sizes[0].getHeight(), ImageFormat.YUV_420_888, 1);

        Range<Integer>[] ranges = characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
        fpsRange = ranges[ranges.length - 1];

        imageReader.setOnImageAvailableListener(this, handler);

        cameraSurfaceView.getHolder().setFixedSize(sizes[0].getWidth(), sizes[0].getHeight());
    } catch (CameraAccessException | NullPointerException e) {
        e.printStackTrace();
    }
}

启动相机预览:

private void startCamera() {
    try {
        cameraManager.openCamera("0", new CameraDevice.StateCallback() {
            @Override
            public void onOpened(@NonNull CameraDevice camera) {
                cameraDevice = camera;

                try {
                    cameraDevice.createCaptureSession(Arrays.asList(cameraSurfaceView.getHolder().getSurface(), imageReader.getSurface()),
                            new CameraCaptureSession.StateCallback() {
                                @Override
                                public void onConfigured(@NonNull CameraCaptureSession session) {
                                    captureSession = session;
                                    try {
                                        requestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);

                                        requestBuilder.addTarget(cameraSurfaceView.getHolder().getSurface());
                                        requestBuilder.addTarget(imageReader.getSurface());

                                        requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
                                        requestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fpsRange);

                                        captureRequest = requestBuilder.build();
                                        cameraReady = true;

                                        captureSession.setRepeatingRequest(captureRequest, null, handler);

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

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

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

这里有ImageReader的OnImageAvailableListener(这是我目前的主要活动):

@Override
public void onImageAvailable(ImageReader reader) {
    reader.acquireNextImage().close();
}

这些代码段目前都存在于我的主要活动中。我正在使用的手机是用于测试目的的摩托罗拉Moto X Play。 cameraSurfaceView只是一个简单的SurfaceView,无需任何自定义。

1 个答案:

答案 0 :(得分:0)

有点难以看到缩进形式,但看起来你正在从代码片段中运行当前线程上的相机处理程序。

cameraManager.openCamera中的最后一个参数告诉它使用什么线程 - 如果它为null,它只使用当前线程。来自Android文档:

  

参数   cameraId String:要打开的摄像机设备的唯一标识符

     

callback CameraDevice.StateCallback:打开相机后调用的回调

     

handler Handler:应该在其上调用回调的处理程序,或者为null以使用当前线程的looper。

如果您在GitHub上查看Camera2Basic()的示例,您可以看到它们指定了一个单独的处理程序:

manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);

这是在一个单独的线程上开始的:

    /**
     * Starts a background thread and its {@link Handler}.
     */
    private void startBackgroundThread() {
        mBackgroundThread = new HandlerThread("CameraBackground");
        mBackgroundThread.start();
        mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
    }