Monica Das
Monica Das

Reputation: 157

Possible way to capture a picture from the camera preview in background without blocking the preview camera2 api?

So, here is the thing. I am trying to get a picture from the camera preview as soon as the autofocus is locked. I am able to do that now and it works just fine. Now, while capturing the picture, it sort of blocks the preview for a moment. I wanted to do the whole process of capturing without blocking the preview at all. Is there a way to go about it ?

This is my current code which is built on the Google Sample Camera 2 code.

         boolean areWeFocused = false;
                int counter =0;

                /**
                 * A {@link CameraCaptureSession.CaptureCallback} that handles events related to JPEG capture.
                 */
                private CameraCaptureSession.CaptureCallback mCaptureCallback
                        = new CameraCaptureSession.CaptureCallback() {

                    private void process(CaptureResult result) {
                        Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);

                        switch (mState) {
                            case STATE_PREVIEW: {
                                // We have nothing to do when the camera preview is working normally.
                                if (CaptureResult.CONTROL_AF_TRIGGER_START == afState) {
                                    if (areWeFocused) {
                                        //Run specific task here
                                        counter++;



                                        takePicture();
                                        Log.d("FocussedState","I am focussed now");
                                    }
                                }
                                if (CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED == afState) {
                                    areWeFocused = true;
                                } else {
                                    areWeFocused = false;
                                    Log.d("FocussedState","I am not focussed now");

                                }
                                break;
                            }
        }
        private void takePicture() {
                lockFocus();
            }

            /**
             * Lock the focus as the first step for a still image capture.
             */
            private void lockFocus() {
                try {
                    // This is how to tell the camera to lock focus.
                    mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
                            CameraMetadata.CONTROL_AF_TRIGGER_START);
                    // Tell #mCaptureCallback to wait for the lock.
                    mState = STATE_WAITING_LOCK;
                    mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
                            mBackgroundHandler);
                } catch (CameraAccessException e) {
                    e.printStackTrace();
                }
            }
    private void captureStillPicture() {
            try {
                final Activity activity = getActivity();
                if (null == activity || null == mCameraDevice) {
                    return;
                }
                // This is the CaptureRequest.Builder that we use to take a picture.
                final CaptureRequest.Builder captureBuilder =
                        mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
                captureBuilder.addTarget(mImageReader.getSurface());

                // Use the same AE and AF modes as the preview.
                captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                        CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
               // setAutoFlash(captureBuilder);

                // Orientation
                int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
                captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));

                CameraCaptureSession.CaptureCallback CaptureCallback
                        = new CameraCaptureSession.CaptureCallback() {

                    @Override
                    public void onCaptureCompleted(@NonNull CameraCaptureSession session,
                                                   @NonNull CaptureRequest request,
                                                   @NonNull TotalCaptureResult result) {
                        showToast("Saved: " + mFile);
                        Log.d(TAG, mFile.toString());
                        unlockFocus();
                    }
                };

                mCaptureSession.stopRepeating();
                mCaptureSession.abortCaptures();
                mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }

  private ImageReader mImageReader;

    /**
     * This is the output file for our picture.
     */
    private File mFile;

    /**
     * This a callback object for the {@link ImageReader}. "onImageAvailable" will be called when a
     * still image is ready to be saved.
     */
    private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
            = new ImageReader.OnImageAvailableListener() {

        @Override
        public void onImageAvailable(ImageReader reader) {
            mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), mFile));
        }

    };

  private static class ImageSaver implements Runnable {

        /**
         * The JPEG image
         */
        private final Image mImage;
        /**
         * The file we save the image into.
         */
        private final File mFile;

        ImageSaver(Image image, File file) {
            mImage = image;
            mFile = file;
        }

        @Override
        public void run() {
            ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
            byte[] bytes = new byte[buffer.remaining()];
            buffer.get(bytes);
            FileOutputStream output = null;
            try {
                output = new FileOutputStream(mFile);
                output.write(bytes);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                mImage.close();
                if (null != output) {
                    try {
                        output.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

    }

    /**
     * Compares two {@code Size}s based on their areas.
     */
    static class CompareSizesByArea implements Comparator<Size> {

        @Override
        public int compare(Size lhs, Size rhs) {
            // We cast here to ensure the multiplications won't overflow
            return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
                    (long) rhs.getWidth() * rhs.getHeight());
        }

    }

Upvotes: 2

Views: 558

Answers (1)

Eddy Talvala
Eddy Talvala

Reputation: 18097

Try removing 'mCaptureSession.stopRepeating()' and 'abortCaptures' in the end of captureStillPicture.

Those would stop the preview from running until it's restarted, and abort can cause a glitch in the output. It can slightly speed up the time to capture, though, which is probably why it's in there.

Upvotes: 2

Related Questions