Android Camera2 conjunction between requests

Viewed 13

I am currently trying to implement computer vision algorithms on my android device. My idea is to have a camera preview running and draw on top of the preview (in a separate view) edges and other geometric figures. To command the camera, I use the camera2 API.

I start a capture session with two requests with the following targets:

  • Request number 1: target/surface -> an ImageReader for image processing
  • Request number 2: target/surface -> a SurfaceView for camera preview

I burst both requests with setRepeatingBurst. Now a problem occurs when I process the image in the ImageReader callback (onImageAvailable). When I process for let's say 500 ms then the image preview drops to 1 fps. I think the problem is because the image.close() gets delayed and that the second request is somehow connected to that image.

I thought that if I have two requests then there are sent two individual images to each surface. But apparently that's not the case. Well, I could make a quick copy in the ImageReader callback and close the image afterwards. And then start processing the copy. But the thing is that I don't want to copy.

Here is the code:

HandlerThread imageProcessingThread = new HandlerThread("imageProcessingThread");
imageProcessingThread.start();
Handler imageProcessingHandler = new Handler(imageProcessingThread.getLooper());

ImageReader imageReader = ImageReader.newInstance(width, height, format, 1);
imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
    @Override
    public void onImageAvailable(ImageReader reader) {
        Image image = reader.acquireNextImage();
        if(image == null) return;
        
        // simulating processing
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // processing end

        image.close();
    }
}, imageProcessingHandler);


try {

    HandlerThread imageProcessingThread3 = new HandlerThread("imageProcessingThread3");
    imageProcessingThread3.start();
    Handler imageProcessingHandler3 = new Handler(imageProcessingThread3.getLooper());

    camManager.openCamera(cam.second, new CameraDevice.StateCallback() {
        @Override
        public void onOpened(@NonNull CameraDevice cameraDevice) {

            try {

                List<Surface> surfaces = new ArrayList<>();
                surfaces.add(binding.svPreview.getHolder().getSurface());
                surfaces.add(imageReader.getSurface());

                cameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
                    @Override
                    public void onConfigured(@NonNull CameraCaptureSession session) {
                        try {
                            CaptureRequest.Builder requestBuilder1 = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                            requestBuilder1.addTarget(imageReader.getSurface());
                            requestBuilder1.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, new Range<>(30, 30));

                            CaptureRequest.Builder requestBuilder2 = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                            requestBuilder2.addTarget(binding.svPreview.getHolder().getSurface());
                            requestBuilder2.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, new Range<>(30, 30));


                            HandlerThread imageProcessingThread2 = new HandlerThread("imageProcessingThread2");
                            imageProcessingThread2.start();
                            Handler imageProcessingHandler2 = new Handler(imageProcessingThread2.getLooper());


                            List<CaptureRequest> requests = new ArrayList<>();
                            requests.add(requestBuilder1.build());
                            requests.add(requestBuilder2.build());

                            session.setRepeatingBurst(requests, new CameraCaptureSession.CaptureCallback() {
                                @Override
                                public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) {
                                }
                                @Override
                                public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
                                }
                            }, imageProcessingHandler2);



                        } catch (Exception ex) {
                            fatalError(ex.getMessage());
                            return;
                        }
                    }
                    @Override
                    public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
                        fatalError("onConfigureFailed");
                        return;
                    }
                }, null);
            } catch (Exception ex) {
                fatalError(ex.getMessage());
                return;
            }
        }
        @Override
        public void onDisconnected(@NonNull CameraDevice cameraDevice) {
        }
        @Override
        public void onError(@NonNull CameraDevice cameraDevice, int i) {
        }
    }, imageProcessingHandler3);
} catch (Exception ex) {
    fatalError(ex.getMessage());
    return;
}
0 Answers
Related