Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4560df76 authored by Chien-Yu Chen's avatar Chien-Yu Chen
Browse files

camera2: allow mixing regular/reprocess requests

Allow mixing regular and reprocess requests in burst requests.
Create RequestLastFrameNumbersHolder to store the last regular
frame number and the last reprocess frame number in a capture
request list which can be used to determine if the capture
sequence is completed.

Bug: 20537735
Change-Id: I0880f8c845380e1c7ffe504225a556829dfeccf6
parent 354b70f7
Loading
Loading
Loading
Loading
+2 −5
Original line number Original line Diff line number Diff line
@@ -207,8 +207,7 @@ public abstract class CameraCaptureSession implements AutoCloseable {
     * <p>All capture sessions can be used for capturing images from the camera but only capture
     * <p>All capture sessions can be used for capturing images from the camera but only capture
     * sessions created by
     * sessions created by
     * {@link CameraDevice#createReprocessibleCaptureSession createReprocessibleCaptureSession}
     * {@link CameraDevice#createReprocessibleCaptureSession createReprocessibleCaptureSession}
     * can submit reprocess capture requests. The list of requests must all be capturing images from
     * can submit reprocess capture requests. Submitting a reprocess request to a regular
     * the camera or all be reprocess capture requests. Submitting a reprocess request to a regular
     * capture session will result in an {@link IllegalArgumentException}.</p>
     * capture session will result in an {@link IllegalArgumentException}.</p>
     *
     *
     * @param requests the list of settings for this burst capture
     * @param requests the list of settings for this burst capture
@@ -231,9 +230,7 @@ public abstract class CameraCaptureSession implements AutoCloseable {
     * @throws IllegalArgumentException If the requests target no Surfaces, or the requests target
     * @throws IllegalArgumentException If the requests target no Surfaces, or the requests target
     *                                  Surfaces not currently configured as outputs; or a reprocess
     *                                  Surfaces not currently configured as outputs; or a reprocess
     *                                  capture request is submitted in a non-reprocessible capture
     *                                  capture request is submitted in a non-reprocessible capture
     *                                  session; or the list of requests contains both requests to
     *                                  session; or one of the reprocess capture requests was
     *                                  capture images from the camera and reprocess capture
     *                                  requests; or one of the reprocess capture requests was
     *                                  created with a {@link TotalCaptureResult} from a different
     *                                  created with a {@link TotalCaptureResult} from a different
     *                                  session; or one of the captures targets a Surface in the
     *                                  session; or one of the captures targets a Surface in the
     *                                  middle of being {@link #prepare prepared}; or if the handler
     *                                  middle of being {@link #prepare prepared}; or if the handler
+11 −17
Original line number Original line Diff line number Diff line
@@ -177,28 +177,22 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
    public synchronized int captureBurst(List<CaptureRequest> requests, CaptureCallback callback,
    public synchronized int captureBurst(List<CaptureRequest> requests, CaptureCallback callback,
            Handler handler) throws CameraAccessException {
            Handler handler) throws CameraAccessException {
        if (requests == null) {
        if (requests == null) {
            throw new IllegalArgumentException("requests must not be null");
            throw new IllegalArgumentException("Requests must not be null");
        } else if (requests.isEmpty()) {
        } else if (requests.isEmpty()) {
            throw new IllegalArgumentException("requests must have at least one element");
            throw new IllegalArgumentException("Requests must have at least one element");
        }
        }


        boolean reprocess = requests.get(0).isReprocess();
        for (CaptureRequest request : requests) {
        if (reprocess && !isReprocessible()) {
            if (request.isReprocess()) {
            throw new IllegalArgumentException("this capture session cannot handle reprocess " +
                if (!isReprocessible()) {
                    "requests");
                    throw new IllegalArgumentException("This capture session cannot handle " +
        } else if (reprocess && requests.get(0).getReprocessibleSessionId() != mId) {
                            "reprocess requests");
            throw new IllegalArgumentException("capture request was created for another session");
                } else if (request.getReprocessibleSessionId() != mId) {
        }
                    throw new IllegalArgumentException("Capture request was created for another " +

        for (int i = 1; i < requests.size(); i++) {
            if (requests.get(i).isReprocess() != reprocess) {
                throw new IllegalArgumentException("cannot mix regular and reprocess capture " +
                        " requests");
            } else if (reprocess && requests.get(i).getReprocessibleSessionId() != mId) {
                throw new IllegalArgumentException("capture request was created for another " +
                            "session");
                            "session");
                }
                }
            }
            }
        }


        checkNotClosed();
        checkNotClosed();


+124 −35
Original line number Original line Diff line number Diff line
@@ -94,11 +94,11 @@ public class CameraDeviceImpl extends CameraDevice {
    private final int mTotalPartialCount;
    private final int mTotalPartialCount;


    /**
    /**
     * A list tracking request and its expected last frame.
     * A list tracking request and its expected last regular frame number and last reprocess frame
     * Updated when calling ICameraDeviceUser methods.
     * number. Updated when calling ICameraDeviceUser methods.
     */
     */
    private final List<SimpleEntry</*frameNumber*/Long, /*requestId*/Integer>>
    private final List<RequestLastFrameNumbersHolder> mRequestLastFrameNumbersList =
            mFrameNumberRequestPairs = new ArrayList<SimpleEntry<Long, Integer>>();
            new ArrayList<>();


    /**
    /**
     * An object tracking received frame numbers.
     * An object tracking received frame numbers.
@@ -653,8 +653,8 @@ public class CameraDeviceImpl extends CameraDevice {
     *
     *
     * <p>If lastFrameNumber is NO_FRAMES_CAPTURED, it means that the request was never
     * <p>If lastFrameNumber is NO_FRAMES_CAPTURED, it means that the request was never
     * sent to HAL. Then onCaptureSequenceAborted is immediately triggered.
     * sent to HAL. Then onCaptureSequenceAborted is immediately triggered.
     * If lastFrameNumber is non-negative, then the requestId and lastFrameNumber pair
     * If lastFrameNumber is non-negative, then the requestId and lastFrameNumber as the last
     * is added to the list mFrameNumberRequestPairs.</p>
     * regular frame number will be added to the list mRequestLastFrameNumbersList.</p>
     *
     *
     * @param requestId the request ID of the current repeating request.
     * @param requestId the request ID of the current repeating request.
     *
     *
@@ -693,10 +693,6 @@ public class CameraDeviceImpl extends CameraDevice {
                                        "early trigger sequence complete for request %d",
                                        "early trigger sequence complete for request %d",
                                        requestId));
                                        requestId));
                            }
                            }
                            if (lastFrameNumber < Integer.MIN_VALUE
                                    || lastFrameNumber > Integer.MAX_VALUE) {
                                throw new AssertionError(lastFrameNumber + " cannot be cast to int");
                            }
                            holder.getCallback().onCaptureSequenceAborted(
                            holder.getCallback().onCaptureSequenceAborted(
                                    CameraDeviceImpl.this,
                                    CameraDeviceImpl.this,
                                    requestId);
                                    requestId);
@@ -710,9 +706,11 @@ public class CameraDeviceImpl extends CameraDevice {
                        requestId));
                        requestId));
            }
            }
        } else {
        } else {
            mFrameNumberRequestPairs.add(
            // This function is only called for regular request so lastFrameNumber is the last
                    new SimpleEntry<Long, Integer>(lastFrameNumber,
            // regular frame number.
                            requestId));
            mRequestLastFrameNumbersList.add(new RequestLastFrameNumbersHolder(requestId,
                    lastFrameNumber));

            // It is possible that the last frame has already arrived, so we need to check
            // It is possible that the last frame has already arrived, so we need to check
            // for sequence completion right away
            // for sequence completion right away
            checkAndFireSequenceComplete();
            checkAndFireSequenceComplete();
@@ -779,8 +777,8 @@ public class CameraDeviceImpl extends CameraDevice {
                }
                }
                mRepeatingRequestId = requestId;
                mRepeatingRequestId = requestId;
            } else {
            } else {
                mFrameNumberRequestPairs.add(
                mRequestLastFrameNumbersList.add(new RequestLastFrameNumbersHolder(requestList,
                        new SimpleEntry<Long, Integer>(lastFrameNumber, requestId));
                        requestId, lastFrameNumber));
            }
            }


            if (mIdle) {
            if (mIdle) {
@@ -1146,7 +1144,101 @@ public class CameraDeviceImpl extends CameraDevice {
        public int getSessionId() {
        public int getSessionId() {
            return mSessionId;
            return mSessionId;
        }
        }
    }

    /**
     * This class holds a capture ID and its expected last regular frame number and last reprocess
     * frame number.
     */
    static class RequestLastFrameNumbersHolder {
        // request ID
        private final int mRequestId;
        // The last regular frame number for this request ID. It's
        // CaptureCallback.NO_FRAMES_CAPTURED if the request ID has no regular request.
        private final long mLastRegularFrameNumber;
        // The last reprocess frame number for this request ID. It's
        // CaptureCallback.NO_FRAMES_CAPTURED if the request ID has no reprocess request.
        private final long mLastReprocessFrameNumber;

        /**
         * Create a request-last-frame-numbers holder with a list of requests, request ID, and
         * the last frame number returned by camera service.
         */
        public RequestLastFrameNumbersHolder(List<CaptureRequest> requestList, int requestId,
                long lastFrameNumber) {
            long lastRegularFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
            long lastReprocessFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
            long frameNumber = lastFrameNumber;

            if (lastFrameNumber < requestList.size() - 1) {
                throw new IllegalArgumentException("lastFrameNumber: " + lastFrameNumber +
                        " should be at least " + (requestList.size() - 1) + " for the number of " +
                        " requests in the list: " + requestList.size());
            }

            // find the last regular frame number and the last reprocess frame number
            for (int i = requestList.size() - 1; i >= 0; i--) {
                CaptureRequest request = requestList.get(i);
                if (request.isReprocess() && lastReprocessFrameNumber ==
                        CaptureCallback.NO_FRAMES_CAPTURED) {
                    lastReprocessFrameNumber = frameNumber;
                } else if (!request.isReprocess() && lastRegularFrameNumber ==
                        CaptureCallback.NO_FRAMES_CAPTURED) {
                    lastRegularFrameNumber = frameNumber;
                }

                if (lastReprocessFrameNumber != CaptureCallback.NO_FRAMES_CAPTURED &&
                        lastRegularFrameNumber != CaptureCallback.NO_FRAMES_CAPTURED) {
                    break;
                }

                frameNumber--;
            }


            mLastRegularFrameNumber = lastRegularFrameNumber;
            mLastReprocessFrameNumber = lastReprocessFrameNumber;
            mRequestId = requestId;
        }

        /**
         * Create a request-last-frame-numbers holder with a request ID and last regular frame
         * number.
         */
        public RequestLastFrameNumbersHolder(int requestId, long lastRegularFrameNumber) {
            mLastRegularFrameNumber = lastRegularFrameNumber;
            mLastReprocessFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
            mRequestId = requestId;
        }

        /**
         * Return the last regular frame number. Return CaptureCallback.NO_FRAMES_CAPTURED if
         * it contains no regular request.
         */
        public long getLastRegularFrameNumber() {
            return mLastRegularFrameNumber;
        }

        /**
         * Return the last reprocess frame number. Return CaptureCallback.NO_FRAMES_CAPTURED if
         * it contains no reprocess request.
         */
        public long getLastReprocessFrameNumber() {
            return mLastReprocessFrameNumber;
        }

        /**
         * Return the last frame number overall.
         */
        public long getLastFrameNumber() {
            return Math.max(mLastRegularFrameNumber, mLastReprocessFrameNumber);
        }

        /**
         * Return the request ID.
         */
        public int getRequestId() {
            return mRequestId;
        }
    }
    }


    /**
    /**
@@ -1154,8 +1246,8 @@ public class CameraDeviceImpl extends CameraDevice {
     */
     */
    public class FrameNumberTracker {
    public class FrameNumberTracker {


        private long mCompletedFrameNumber = -1;
        private long mCompletedFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
        private long mCompletedReprocessFrameNumber = -1;
        private long mCompletedReprocessFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
        /** the skipped frame numbers that belong to regular results */
        /** the skipped frame numbers that belong to regular results */
        private final LinkedList<Long> mSkippedRegularFrameNumbers = new LinkedList<Long>();
        private final LinkedList<Long> mSkippedRegularFrameNumbers = new LinkedList<Long>();
        /** the skipped frame numbers that belong to reprocess results */
        /** the skipped frame numbers that belong to reprocess results */
@@ -1360,11 +1452,11 @@ public class CameraDeviceImpl extends CameraDevice {
        long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
        long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
        long completedReprocessFrameNumber = mFrameNumberTracker.getCompletedReprocessFrameNumber();
        long completedReprocessFrameNumber = mFrameNumberTracker.getCompletedReprocessFrameNumber();
        boolean isReprocess = false;
        boolean isReprocess = false;
        Iterator<SimpleEntry<Long, Integer> > iter = mFrameNumberRequestPairs.iterator();
        Iterator<RequestLastFrameNumbersHolder> iter = mRequestLastFrameNumbersList.iterator();
        while (iter.hasNext()) {
        while (iter.hasNext()) {
            final SimpleEntry<Long, Integer> frameNumberRequestPair = iter.next();
            final RequestLastFrameNumbersHolder requestLastFrameNumbers = iter.next();
            boolean sequenceCompleted = false;
            boolean sequenceCompleted = false;
            final int requestId = frameNumberRequestPair.getValue();
            final int requestId = requestLastFrameNumbers.getRequestId();
            final CaptureCallbackHolder holder;
            final CaptureCallbackHolder holder;
            synchronized(mInterfaceLock) {
            synchronized(mInterfaceLock) {
                if (mRemoteDevice == null) {
                if (mRemoteDevice == null) {
@@ -1376,19 +1468,22 @@ public class CameraDeviceImpl extends CameraDevice {
                holder = (index >= 0) ?
                holder = (index >= 0) ?
                        mCaptureCallbackMap.valueAt(index) : null;
                        mCaptureCallbackMap.valueAt(index) : null;
                if (holder != null) {
                if (holder != null) {
                    isReprocess = holder.getRequest().isReprocess();
                    long lastRegularFrameNumber =
                            requestLastFrameNumbers.getLastRegularFrameNumber();
                    long lastReprocessFrameNumber =
                            requestLastFrameNumbers.getLastReprocessFrameNumber();

                    // check if it's okay to remove request from mCaptureCallbackMap
                    // check if it's okay to remove request from mCaptureCallbackMap
                    if ((isReprocess && frameNumberRequestPair.getKey() <=
                    if (lastRegularFrameNumber <= completedFrameNumber &&
                            completedReprocessFrameNumber) || (!isReprocess &&
                            lastReprocessFrameNumber <= completedReprocessFrameNumber) {
                            frameNumberRequestPair.getKey() <= completedFrameNumber)) {
                        sequenceCompleted = true;
                        sequenceCompleted = true;
                        mCaptureCallbackMap.removeAt(index);
                        mCaptureCallbackMap.removeAt(index);
                        if (DEBUG) {
                        if (DEBUG) {
                            Log.v(TAG, String.format(
                            Log.v(TAG, String.format(
                                    "remove holder for requestId %d, "
                                    "Remove holder for requestId %d, because lastRegularFrame %d " +
                                    + "because lastFrame %d is <= %d",
                                    "is <= %d and lastReprocessFrame %d is <= %d", requestId,
                                    requestId, frameNumberRequestPair.getKey(),
                                    lastRegularFrameNumber, completedFrameNumber,
                                    completedFrameNumber));
                                    lastReprocessFrameNumber, completedReprocessFrameNumber));
                        }
                        }
                    }
                    }
                }
                }
@@ -1412,16 +1507,10 @@ public class CameraDeviceImpl extends CameraDevice {
                                        requestId));
                                        requestId));
                            }
                            }


                            long lastFrameNumber = frameNumberRequestPair.getKey();
                            if (lastFrameNumber < Integer.MIN_VALUE
                                    || lastFrameNumber > Integer.MAX_VALUE) {
                                throw new AssertionError(lastFrameNumber
                                        + " cannot be cast to int");
                            }
                            holder.getCallback().onCaptureSequenceCompleted(
                            holder.getCallback().onCaptureSequenceCompleted(
                                CameraDeviceImpl.this,
                                CameraDeviceImpl.this,
                                requestId,
                                requestId,
                                lastFrameNumber);
                                requestLastFrameNumbers.getLastFrameNumber());
                        }
                        }
                    }
                    }
                };
                };