191838ded36131525312739c0929913b215519c2aRuben Brunk/*
291838ded36131525312739c0929913b215519c2aRuben Brunk * Copyright (C) 2014 The Android Open Source Project
391838ded36131525312739c0929913b215519c2aRuben Brunk *
491838ded36131525312739c0929913b215519c2aRuben Brunk * Licensed under the Apache License, Version 2.0 (the "License");
591838ded36131525312739c0929913b215519c2aRuben Brunk * you may not use this file except in compliance with the License.
691838ded36131525312739c0929913b215519c2aRuben Brunk * You may obtain a copy of the License at
791838ded36131525312739c0929913b215519c2aRuben Brunk *
891838ded36131525312739c0929913b215519c2aRuben Brunk *      http://www.apache.org/licenses/LICENSE-2.0
991838ded36131525312739c0929913b215519c2aRuben Brunk *
1091838ded36131525312739c0929913b215519c2aRuben Brunk * Unless required by applicable law or agreed to in writing, software
1191838ded36131525312739c0929913b215519c2aRuben Brunk * distributed under the License is distributed on an "AS IS" BASIS,
1291838ded36131525312739c0929913b215519c2aRuben Brunk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1391838ded36131525312739c0929913b215519c2aRuben Brunk * See the License for the specific language governing permissions and
1491838ded36131525312739c0929913b215519c2aRuben Brunk * limitations under the License.
1591838ded36131525312739c0929913b215519c2aRuben Brunk */
1691838ded36131525312739c0929913b215519c2aRuben Brunkpackage android.hardware.camera2.legacy;
1791838ded36131525312739c0929913b215519c2aRuben Brunk
18e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunkimport android.hardware.camera2.impl.CameraDeviceImpl;
1991838ded36131525312739c0929913b215519c2aRuben Brunkimport android.util.Log;
2083d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkinimport android.util.MutableLong;
2191838ded36131525312739c0929913b215519c2aRuben Brunkimport android.util.Pair;
2291838ded36131525312739c0929913b215519c2aRuben Brunk
2391838ded36131525312739c0929913b215519c2aRuben Brunkimport java.util.ArrayDeque;
2483d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkinimport java.util.ArrayList;
25e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunkimport java.util.TreeSet;
2691838ded36131525312739c0929913b215519c2aRuben Brunkimport java.util.concurrent.TimeUnit;
2791838ded36131525312739c0929913b215519c2aRuben Brunkimport java.util.concurrent.locks.Condition;
2891838ded36131525312739c0929913b215519c2aRuben Brunkimport java.util.concurrent.locks.ReentrantLock;
2991838ded36131525312739c0929913b215519c2aRuben Brunk
3091838ded36131525312739c0929913b215519c2aRuben Brunk/**
3191838ded36131525312739c0929913b215519c2aRuben Brunk * Collect timestamps and state for each {@link CaptureRequest} as it passes through
3291838ded36131525312739c0929913b215519c2aRuben Brunk * the Legacy camera pipeline.
3391838ded36131525312739c0929913b215519c2aRuben Brunk */
3491838ded36131525312739c0929913b215519c2aRuben Brunkpublic class CaptureCollector {
3591838ded36131525312739c0929913b215519c2aRuben Brunk    private static final String TAG = "CaptureCollector";
3691838ded36131525312739c0929913b215519c2aRuben Brunk
3791838ded36131525312739c0929913b215519c2aRuben Brunk    private static final boolean DEBUG = Log.isLoggable(LegacyCameraDevice.DEBUG_PROP, Log.DEBUG);
3891838ded36131525312739c0929913b215519c2aRuben Brunk
3991838ded36131525312739c0929913b215519c2aRuben Brunk    private static final int FLAG_RECEIVED_JPEG = 1;
4091838ded36131525312739c0929913b215519c2aRuben Brunk    private static final int FLAG_RECEIVED_JPEG_TS = 2;
4191838ded36131525312739c0929913b215519c2aRuben Brunk    private static final int FLAG_RECEIVED_PREVIEW = 4;
4291838ded36131525312739c0929913b215519c2aRuben Brunk    private static final int FLAG_RECEIVED_PREVIEW_TS = 8;
4391838ded36131525312739c0929913b215519c2aRuben Brunk    private static final int FLAG_RECEIVED_ALL_JPEG = FLAG_RECEIVED_JPEG | FLAG_RECEIVED_JPEG_TS;
4491838ded36131525312739c0929913b215519c2aRuben Brunk    private static final int FLAG_RECEIVED_ALL_PREVIEW = FLAG_RECEIVED_PREVIEW |
4591838ded36131525312739c0929913b215519c2aRuben Brunk            FLAG_RECEIVED_PREVIEW_TS;
4691838ded36131525312739c0929913b215519c2aRuben Brunk
4791838ded36131525312739c0929913b215519c2aRuben Brunk    private static final int MAX_JPEGS_IN_FLIGHT = 1;
4891838ded36131525312739c0929913b215519c2aRuben Brunk
49e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk    private class CaptureHolder implements Comparable<CaptureHolder>{
5091838ded36131525312739c0929913b215519c2aRuben Brunk        private final RequestHolder mRequest;
5191838ded36131525312739c0929913b215519c2aRuben Brunk        private final LegacyRequest mLegacy;
5291838ded36131525312739c0929913b215519c2aRuben Brunk        public final boolean needsJpeg;
5391838ded36131525312739c0929913b215519c2aRuben Brunk        public final boolean needsPreview;
5491838ded36131525312739c0929913b215519c2aRuben Brunk
5591838ded36131525312739c0929913b215519c2aRuben Brunk        private long mTimestamp = 0;
5691838ded36131525312739c0929913b215519c2aRuben Brunk        private int mReceivedFlags = 0;
5791838ded36131525312739c0929913b215519c2aRuben Brunk        private boolean mHasStarted = false;
58e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        private boolean mFailedJpeg = false;
59e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        private boolean mFailedPreview = false;
60e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        private boolean mCompleted = false;
61e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        private boolean mPreviewCompleted = false;
6291838ded36131525312739c0929913b215519c2aRuben Brunk
6391838ded36131525312739c0929913b215519c2aRuben Brunk        public CaptureHolder(RequestHolder request, LegacyRequest legacyHolder) {
6491838ded36131525312739c0929913b215519c2aRuben Brunk            mRequest = request;
6591838ded36131525312739c0929913b215519c2aRuben Brunk            mLegacy = legacyHolder;
6691838ded36131525312739c0929913b215519c2aRuben Brunk            needsJpeg = request.hasJpegTargets();
6791838ded36131525312739c0929913b215519c2aRuben Brunk            needsPreview = request.hasPreviewTargets();
6891838ded36131525312739c0929913b215519c2aRuben Brunk        }
6991838ded36131525312739c0929913b215519c2aRuben Brunk
7091838ded36131525312739c0929913b215519c2aRuben Brunk        public boolean isPreviewCompleted() {
7191838ded36131525312739c0929913b215519c2aRuben Brunk            return (mReceivedFlags & FLAG_RECEIVED_ALL_PREVIEW) == FLAG_RECEIVED_ALL_PREVIEW;
7291838ded36131525312739c0929913b215519c2aRuben Brunk        }
7391838ded36131525312739c0929913b215519c2aRuben Brunk
7491838ded36131525312739c0929913b215519c2aRuben Brunk        public  boolean isJpegCompleted() {
7591838ded36131525312739c0929913b215519c2aRuben Brunk            return (mReceivedFlags & FLAG_RECEIVED_ALL_JPEG) == FLAG_RECEIVED_ALL_JPEG;
7691838ded36131525312739c0929913b215519c2aRuben Brunk        }
7791838ded36131525312739c0929913b215519c2aRuben Brunk
7891838ded36131525312739c0929913b215519c2aRuben Brunk        public boolean isCompleted() {
7991838ded36131525312739c0929913b215519c2aRuben Brunk            return (needsJpeg == isJpegCompleted()) && (needsPreview == isPreviewCompleted());
8091838ded36131525312739c0929913b215519c2aRuben Brunk        }
8191838ded36131525312739c0929913b215519c2aRuben Brunk
8291838ded36131525312739c0929913b215519c2aRuben Brunk        public void tryComplete() {
83e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            if (!mPreviewCompleted && needsPreview && isPreviewCompleted()) {
84e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                CaptureCollector.this.onPreviewCompleted();
85e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                mPreviewCompleted = true;
86e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            }
87e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk
88e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            if (isCompleted() && !mCompleted) {
89e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                if (mFailedPreview || mFailedJpeg) {
90e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                    if (!mHasStarted) {
91e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                        // Send a request error if the capture has not yet started.
92e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                        mRequest.failRequest();
93e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                        CaptureCollector.this.mDeviceState.setCaptureStart(mRequest, mTimestamp,
94e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                                CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_REQUEST);
95e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                    } else {
96e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                        // Send buffer dropped errors for each pending buffer if the request has
97e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                        // started.
98e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                        if (mFailedPreview) {
99e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                            Log.w(TAG, "Preview buffers dropped for request: " +
100e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                                    mRequest.getRequestId());
101e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                            for (int i = 0; i < mRequest.numPreviewTargets(); i++) {
102e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                                CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
103e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                                    /*result*/null,
104e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                                        CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_BUFFER);
105e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                            }
106e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                        }
107e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                        if (mFailedJpeg) {
108e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                            Log.w(TAG, "Jpeg buffers dropped for request: " +
109e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                                    mRequest.getRequestId());
110e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                            for (int i = 0; i < mRequest.numJpegTargets(); i++) {
111e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                                CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
112e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                                    /*result*/null,
113e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                                        CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_BUFFER);
114e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                            }
115e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                        }
116e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                    }
117971251f362410caebe8eeb5b6c13d8912f72d50eRuben Brunk                }
118e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                CaptureCollector.this.onRequestCompleted(CaptureHolder.this);
119e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                mCompleted = true;
12091838ded36131525312739c0929913b215519c2aRuben Brunk            }
12191838ded36131525312739c0929913b215519c2aRuben Brunk        }
12291838ded36131525312739c0929913b215519c2aRuben Brunk
12391838ded36131525312739c0929913b215519c2aRuben Brunk        public void setJpegTimestamp(long timestamp) {
12491838ded36131525312739c0929913b215519c2aRuben Brunk            if (DEBUG) {
12591838ded36131525312739c0929913b215519c2aRuben Brunk                Log.d(TAG, "setJpegTimestamp - called for request " + mRequest.getRequestId());
12691838ded36131525312739c0929913b215519c2aRuben Brunk            }
12791838ded36131525312739c0929913b215519c2aRuben Brunk            if (!needsJpeg) {
12891838ded36131525312739c0929913b215519c2aRuben Brunk                throw new IllegalStateException(
12991838ded36131525312739c0929913b215519c2aRuben Brunk                        "setJpegTimestamp called for capture with no jpeg targets.");
13091838ded36131525312739c0929913b215519c2aRuben Brunk            }
13191838ded36131525312739c0929913b215519c2aRuben Brunk            if (isCompleted()) {
13291838ded36131525312739c0929913b215519c2aRuben Brunk                throw new IllegalStateException(
13391838ded36131525312739c0929913b215519c2aRuben Brunk                        "setJpegTimestamp called on already completed request.");
13491838ded36131525312739c0929913b215519c2aRuben Brunk            }
13591838ded36131525312739c0929913b215519c2aRuben Brunk
13691838ded36131525312739c0929913b215519c2aRuben Brunk            mReceivedFlags |= FLAG_RECEIVED_JPEG_TS;
13791838ded36131525312739c0929913b215519c2aRuben Brunk
13891838ded36131525312739c0929913b215519c2aRuben Brunk            if (mTimestamp == 0) {
13991838ded36131525312739c0929913b215519c2aRuben Brunk                mTimestamp = timestamp;
14091838ded36131525312739c0929913b215519c2aRuben Brunk            }
14191838ded36131525312739c0929913b215519c2aRuben Brunk
14291838ded36131525312739c0929913b215519c2aRuben Brunk            if (!mHasStarted) {
14391838ded36131525312739c0929913b215519c2aRuben Brunk                mHasStarted = true;
144e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                CaptureCollector.this.mDeviceState.setCaptureStart(mRequest, mTimestamp,
145e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                        CameraDeviceState.NO_CAPTURE_ERROR);
14691838ded36131525312739c0929913b215519c2aRuben Brunk            }
14791838ded36131525312739c0929913b215519c2aRuben Brunk
14891838ded36131525312739c0929913b215519c2aRuben Brunk            tryComplete();
14991838ded36131525312739c0929913b215519c2aRuben Brunk        }
15091838ded36131525312739c0929913b215519c2aRuben Brunk
15191838ded36131525312739c0929913b215519c2aRuben Brunk        public void setJpegProduced() {
15291838ded36131525312739c0929913b215519c2aRuben Brunk            if (DEBUG) {
15391838ded36131525312739c0929913b215519c2aRuben Brunk                Log.d(TAG, "setJpegProduced - called for request " + mRequest.getRequestId());
15491838ded36131525312739c0929913b215519c2aRuben Brunk            }
15591838ded36131525312739c0929913b215519c2aRuben Brunk            if (!needsJpeg) {
15691838ded36131525312739c0929913b215519c2aRuben Brunk                throw new IllegalStateException(
15791838ded36131525312739c0929913b215519c2aRuben Brunk                        "setJpegProduced called for capture with no jpeg targets.");
15891838ded36131525312739c0929913b215519c2aRuben Brunk            }
15991838ded36131525312739c0929913b215519c2aRuben Brunk            if (isCompleted()) {
16091838ded36131525312739c0929913b215519c2aRuben Brunk                throw new IllegalStateException(
16191838ded36131525312739c0929913b215519c2aRuben Brunk                        "setJpegProduced called on already completed request.");
16291838ded36131525312739c0929913b215519c2aRuben Brunk            }
16391838ded36131525312739c0929913b215519c2aRuben Brunk
16491838ded36131525312739c0929913b215519c2aRuben Brunk            mReceivedFlags |= FLAG_RECEIVED_JPEG;
16591838ded36131525312739c0929913b215519c2aRuben Brunk            tryComplete();
16691838ded36131525312739c0929913b215519c2aRuben Brunk        }
16791838ded36131525312739c0929913b215519c2aRuben Brunk
168e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        public void setJpegFailed() {
169e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            if (DEBUG) {
170e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                Log.d(TAG, "setJpegFailed - called for request " + mRequest.getRequestId());
171e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            }
172e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            if (!needsJpeg || isJpegCompleted()) {
173e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                return;
174e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            }
175e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            mFailedJpeg = true;
176e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk
177e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            mReceivedFlags |= FLAG_RECEIVED_JPEG;
178e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            mReceivedFlags |= FLAG_RECEIVED_JPEG_TS;
179e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            tryComplete();
180e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        }
181e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk
18291838ded36131525312739c0929913b215519c2aRuben Brunk        public void setPreviewTimestamp(long timestamp) {
18391838ded36131525312739c0929913b215519c2aRuben Brunk            if (DEBUG) {
18491838ded36131525312739c0929913b215519c2aRuben Brunk                Log.d(TAG, "setPreviewTimestamp - called for request " + mRequest.getRequestId());
18591838ded36131525312739c0929913b215519c2aRuben Brunk            }
18691838ded36131525312739c0929913b215519c2aRuben Brunk            if (!needsPreview) {
18791838ded36131525312739c0929913b215519c2aRuben Brunk                throw new IllegalStateException(
18891838ded36131525312739c0929913b215519c2aRuben Brunk                        "setPreviewTimestamp called for capture with no preview targets.");
18991838ded36131525312739c0929913b215519c2aRuben Brunk            }
19091838ded36131525312739c0929913b215519c2aRuben Brunk            if (isCompleted()) {
19191838ded36131525312739c0929913b215519c2aRuben Brunk                throw new IllegalStateException(
19291838ded36131525312739c0929913b215519c2aRuben Brunk                        "setPreviewTimestamp called on already completed request.");
19391838ded36131525312739c0929913b215519c2aRuben Brunk            }
19491838ded36131525312739c0929913b215519c2aRuben Brunk
19591838ded36131525312739c0929913b215519c2aRuben Brunk            mReceivedFlags |= FLAG_RECEIVED_PREVIEW_TS;
19691838ded36131525312739c0929913b215519c2aRuben Brunk
19791838ded36131525312739c0929913b215519c2aRuben Brunk            if (mTimestamp == 0) {
19891838ded36131525312739c0929913b215519c2aRuben Brunk                mTimestamp = timestamp;
19991838ded36131525312739c0929913b215519c2aRuben Brunk            }
20091838ded36131525312739c0929913b215519c2aRuben Brunk
20191838ded36131525312739c0929913b215519c2aRuben Brunk            if (!needsJpeg) {
20291838ded36131525312739c0929913b215519c2aRuben Brunk                if (!mHasStarted) {
20391838ded36131525312739c0929913b215519c2aRuben Brunk                    mHasStarted = true;
204e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                    CaptureCollector.this.mDeviceState.setCaptureStart(mRequest, mTimestamp,
205e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                            CameraDeviceState.NO_CAPTURE_ERROR);
20691838ded36131525312739c0929913b215519c2aRuben Brunk                }
20791838ded36131525312739c0929913b215519c2aRuben Brunk            }
20891838ded36131525312739c0929913b215519c2aRuben Brunk
20991838ded36131525312739c0929913b215519c2aRuben Brunk            tryComplete();
21091838ded36131525312739c0929913b215519c2aRuben Brunk        }
21191838ded36131525312739c0929913b215519c2aRuben Brunk
21291838ded36131525312739c0929913b215519c2aRuben Brunk        public void setPreviewProduced() {
21391838ded36131525312739c0929913b215519c2aRuben Brunk            if (DEBUG) {
21491838ded36131525312739c0929913b215519c2aRuben Brunk                Log.d(TAG, "setPreviewProduced - called for request " + mRequest.getRequestId());
21591838ded36131525312739c0929913b215519c2aRuben Brunk            }
21691838ded36131525312739c0929913b215519c2aRuben Brunk            if (!needsPreview) {
21791838ded36131525312739c0929913b215519c2aRuben Brunk                throw new IllegalStateException(
21891838ded36131525312739c0929913b215519c2aRuben Brunk                        "setPreviewProduced called for capture with no preview targets.");
21991838ded36131525312739c0929913b215519c2aRuben Brunk            }
22091838ded36131525312739c0929913b215519c2aRuben Brunk            if (isCompleted()) {
22191838ded36131525312739c0929913b215519c2aRuben Brunk                throw new IllegalStateException(
22291838ded36131525312739c0929913b215519c2aRuben Brunk                        "setPreviewProduced called on already completed request.");
22391838ded36131525312739c0929913b215519c2aRuben Brunk            }
22491838ded36131525312739c0929913b215519c2aRuben Brunk
22591838ded36131525312739c0929913b215519c2aRuben Brunk            mReceivedFlags |= FLAG_RECEIVED_PREVIEW;
22691838ded36131525312739c0929913b215519c2aRuben Brunk            tryComplete();
22791838ded36131525312739c0929913b215519c2aRuben Brunk        }
228e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk
229e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        public void setPreviewFailed() {
230e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            if (DEBUG) {
231e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                Log.d(TAG, "setPreviewFailed - called for request " + mRequest.getRequestId());
232e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            }
233e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            if (!needsPreview || isPreviewCompleted()) {
234e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                return;
235e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            }
236e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            mFailedPreview = true;
237e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk
238e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            mReceivedFlags |= FLAG_RECEIVED_PREVIEW;
239e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            mReceivedFlags |= FLAG_RECEIVED_PREVIEW_TS;
240e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            tryComplete();
241e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        }
242e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk
243e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        // Comparison and equals based on frame number.
244e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        @Override
245e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        public int compareTo(CaptureHolder captureHolder) {
246e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            return (mRequest.getFrameNumber() > captureHolder.mRequest.getFrameNumber()) ? 1 :
247e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                    ((mRequest.getFrameNumber() == captureHolder.mRequest.getFrameNumber()) ? 0 :
248e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                            -1);
249e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        }
250e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk
251e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        // Comparison and equals based on frame number.
252e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        @Override
253e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        public boolean equals(Object o) {
254e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            return o instanceof CaptureHolder && compareTo((CaptureHolder) o) == 0;
255e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        }
25691838ded36131525312739c0929913b215519c2aRuben Brunk    }
25791838ded36131525312739c0929913b215519c2aRuben Brunk
258e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk    private final TreeSet<CaptureHolder> mActiveRequests;
25991838ded36131525312739c0929913b215519c2aRuben Brunk    private final ArrayDeque<CaptureHolder> mJpegCaptureQueue;
26091838ded36131525312739c0929913b215519c2aRuben Brunk    private final ArrayDeque<CaptureHolder> mJpegProduceQueue;
26191838ded36131525312739c0929913b215519c2aRuben Brunk    private final ArrayDeque<CaptureHolder> mPreviewCaptureQueue;
26291838ded36131525312739c0929913b215519c2aRuben Brunk    private final ArrayDeque<CaptureHolder> mPreviewProduceQueue;
26383d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin    private final ArrayList<CaptureHolder> mCompletedRequests = new ArrayList<>();
26491838ded36131525312739c0929913b215519c2aRuben Brunk
26591838ded36131525312739c0929913b215519c2aRuben Brunk    private final ReentrantLock mLock = new ReentrantLock();
26691838ded36131525312739c0929913b215519c2aRuben Brunk    private final Condition mIsEmpty;
26791838ded36131525312739c0929913b215519c2aRuben Brunk    private final Condition mPreviewsEmpty;
26891838ded36131525312739c0929913b215519c2aRuben Brunk    private final Condition mNotFull;
26991838ded36131525312739c0929913b215519c2aRuben Brunk    private final CameraDeviceState mDeviceState;
27091838ded36131525312739c0929913b215519c2aRuben Brunk    private int mInFlight = 0;
27191838ded36131525312739c0929913b215519c2aRuben Brunk    private int mInFlightPreviews = 0;
27291838ded36131525312739c0929913b215519c2aRuben Brunk    private final int mMaxInFlight;
27391838ded36131525312739c0929913b215519c2aRuben Brunk
27491838ded36131525312739c0929913b215519c2aRuben Brunk    /**
27591838ded36131525312739c0929913b215519c2aRuben Brunk     * Create a new {@link CaptureCollector} that can modify the given {@link CameraDeviceState}.
27691838ded36131525312739c0929913b215519c2aRuben Brunk     *
27791838ded36131525312739c0929913b215519c2aRuben Brunk     * @param maxInFlight max allowed in-flight requests.
27891838ded36131525312739c0929913b215519c2aRuben Brunk     * @param deviceState the {@link CameraDeviceState} to update as requests are processed.
27991838ded36131525312739c0929913b215519c2aRuben Brunk     */
28091838ded36131525312739c0929913b215519c2aRuben Brunk    public CaptureCollector(int maxInFlight, CameraDeviceState deviceState) {
28191838ded36131525312739c0929913b215519c2aRuben Brunk        mMaxInFlight = maxInFlight;
28291838ded36131525312739c0929913b215519c2aRuben Brunk        mJpegCaptureQueue = new ArrayDeque<>(MAX_JPEGS_IN_FLIGHT);
28391838ded36131525312739c0929913b215519c2aRuben Brunk        mJpegProduceQueue = new ArrayDeque<>(MAX_JPEGS_IN_FLIGHT);
28491838ded36131525312739c0929913b215519c2aRuben Brunk        mPreviewCaptureQueue = new ArrayDeque<>(mMaxInFlight);
28591838ded36131525312739c0929913b215519c2aRuben Brunk        mPreviewProduceQueue = new ArrayDeque<>(mMaxInFlight);
286e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        mActiveRequests = new TreeSet<>();
28791838ded36131525312739c0929913b215519c2aRuben Brunk        mIsEmpty = mLock.newCondition();
28891838ded36131525312739c0929913b215519c2aRuben Brunk        mNotFull = mLock.newCondition();
28991838ded36131525312739c0929913b215519c2aRuben Brunk        mPreviewsEmpty = mLock.newCondition();
29091838ded36131525312739c0929913b215519c2aRuben Brunk        mDeviceState = deviceState;
29191838ded36131525312739c0929913b215519c2aRuben Brunk    }
29291838ded36131525312739c0929913b215519c2aRuben Brunk
29391838ded36131525312739c0929913b215519c2aRuben Brunk    /**
29491838ded36131525312739c0929913b215519c2aRuben Brunk     * Queue a new request.
29591838ded36131525312739c0929913b215519c2aRuben Brunk     *
29691838ded36131525312739c0929913b215519c2aRuben Brunk     * <p>
29791838ded36131525312739c0929913b215519c2aRuben Brunk     * For requests that use the Camera1 API preview output stream, this will block if there are
29891838ded36131525312739c0929913b215519c2aRuben Brunk     * already {@code maxInFlight} requests in progress (until at least one prior request has
29991838ded36131525312739c0929913b215519c2aRuben Brunk     * completed). For requests that use the Camera1 API jpeg callbacks, this will block until
30091838ded36131525312739c0929913b215519c2aRuben Brunk     * all prior requests have been completed to avoid stopping preview for
30191838ded36131525312739c0929913b215519c2aRuben Brunk     * {@link android.hardware.Camera#takePicture} before prior preview requests have been
30291838ded36131525312739c0929913b215519c2aRuben Brunk     * completed.
30391838ded36131525312739c0929913b215519c2aRuben Brunk     * </p>
30491838ded36131525312739c0929913b215519c2aRuben Brunk     * @param holder the {@link RequestHolder} for this request.
30591838ded36131525312739c0929913b215519c2aRuben Brunk     * @param legacy the {@link LegacyRequest} for this request; this will not be mutated.
30691838ded36131525312739c0929913b215519c2aRuben Brunk     * @param timeout a timeout to use for this call.
30791838ded36131525312739c0929913b215519c2aRuben Brunk     * @param unit the units to use for the timeout.
30891838ded36131525312739c0929913b215519c2aRuben Brunk     * @return {@code false} if this method timed out.
30991838ded36131525312739c0929913b215519c2aRuben Brunk     * @throws InterruptedException if this thread is interrupted.
31091838ded36131525312739c0929913b215519c2aRuben Brunk     */
31191838ded36131525312739c0929913b215519c2aRuben Brunk    public boolean queueRequest(RequestHolder holder, LegacyRequest legacy, long timeout,
31291838ded36131525312739c0929913b215519c2aRuben Brunk                                TimeUnit unit)
31391838ded36131525312739c0929913b215519c2aRuben Brunk            throws InterruptedException {
31491838ded36131525312739c0929913b215519c2aRuben Brunk        CaptureHolder h = new CaptureHolder(holder, legacy);
31591838ded36131525312739c0929913b215519c2aRuben Brunk        long nanos = unit.toNanos(timeout);
31691838ded36131525312739c0929913b215519c2aRuben Brunk        final ReentrantLock lock = this.mLock;
31791838ded36131525312739c0929913b215519c2aRuben Brunk        lock.lock();
31891838ded36131525312739c0929913b215519c2aRuben Brunk        try {
31991838ded36131525312739c0929913b215519c2aRuben Brunk            if (DEBUG) {
32091838ded36131525312739c0929913b215519c2aRuben Brunk                Log.d(TAG, "queueRequest  for request " + holder.getRequestId() +
32191838ded36131525312739c0929913b215519c2aRuben Brunk                        " - " + mInFlight + " requests remain in flight.");
32291838ded36131525312739c0929913b215519c2aRuben Brunk            }
3233fe9eba9044c0b20ed349a4b9094bf1fa7942cdfRuben Brunk
3243fe9eba9044c0b20ed349a4b9094bf1fa7942cdfRuben Brunk            if (!(h.needsJpeg || h.needsPreview)) {
3253fe9eba9044c0b20ed349a4b9094bf1fa7942cdfRuben Brunk                throw new IllegalStateException("Request must target at least one output surface!");
3263fe9eba9044c0b20ed349a4b9094bf1fa7942cdfRuben Brunk            }
3273fe9eba9044c0b20ed349a4b9094bf1fa7942cdfRuben Brunk
32891838ded36131525312739c0929913b215519c2aRuben Brunk            if (h.needsJpeg) {
32991838ded36131525312739c0929913b215519c2aRuben Brunk                // Wait for all current requests to finish before queueing jpeg.
33091838ded36131525312739c0929913b215519c2aRuben Brunk                while (mInFlight > 0) {
33191838ded36131525312739c0929913b215519c2aRuben Brunk                    if (nanos <= 0) {
33291838ded36131525312739c0929913b215519c2aRuben Brunk                        return false;
33391838ded36131525312739c0929913b215519c2aRuben Brunk                    }
33491838ded36131525312739c0929913b215519c2aRuben Brunk                    nanos = mIsEmpty.awaitNanos(nanos);
33591838ded36131525312739c0929913b215519c2aRuben Brunk                }
33691838ded36131525312739c0929913b215519c2aRuben Brunk                mJpegCaptureQueue.add(h);
33791838ded36131525312739c0929913b215519c2aRuben Brunk                mJpegProduceQueue.add(h);
33891838ded36131525312739c0929913b215519c2aRuben Brunk            }
33991838ded36131525312739c0929913b215519c2aRuben Brunk            if (h.needsPreview) {
34091838ded36131525312739c0929913b215519c2aRuben Brunk                while (mInFlight >= mMaxInFlight) {
34191838ded36131525312739c0929913b215519c2aRuben Brunk                    if (nanos <= 0) {
34291838ded36131525312739c0929913b215519c2aRuben Brunk                        return false;
34391838ded36131525312739c0929913b215519c2aRuben Brunk                    }
34491838ded36131525312739c0929913b215519c2aRuben Brunk                    nanos = mNotFull.awaitNanos(nanos);
34591838ded36131525312739c0929913b215519c2aRuben Brunk                }
34691838ded36131525312739c0929913b215519c2aRuben Brunk                mPreviewCaptureQueue.add(h);
34791838ded36131525312739c0929913b215519c2aRuben Brunk                mPreviewProduceQueue.add(h);
34891838ded36131525312739c0929913b215519c2aRuben Brunk                mInFlightPreviews++;
34991838ded36131525312739c0929913b215519c2aRuben Brunk            }
350e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            mActiveRequests.add(h);
35191838ded36131525312739c0929913b215519c2aRuben Brunk
35291838ded36131525312739c0929913b215519c2aRuben Brunk            mInFlight++;
35391838ded36131525312739c0929913b215519c2aRuben Brunk            return true;
35491838ded36131525312739c0929913b215519c2aRuben Brunk        } finally {
35591838ded36131525312739c0929913b215519c2aRuben Brunk            lock.unlock();
35691838ded36131525312739c0929913b215519c2aRuben Brunk        }
35791838ded36131525312739c0929913b215519c2aRuben Brunk    }
35891838ded36131525312739c0929913b215519c2aRuben Brunk
35991838ded36131525312739c0929913b215519c2aRuben Brunk    /**
36091838ded36131525312739c0929913b215519c2aRuben Brunk     * Wait all queued requests to complete.
36191838ded36131525312739c0929913b215519c2aRuben Brunk     *
36291838ded36131525312739c0929913b215519c2aRuben Brunk     * @param timeout a timeout to use for this call.
36391838ded36131525312739c0929913b215519c2aRuben Brunk     * @param unit the units to use for the timeout.
36491838ded36131525312739c0929913b215519c2aRuben Brunk     * @return {@code false} if this method timed out.
36591838ded36131525312739c0929913b215519c2aRuben Brunk     * @throws InterruptedException if this thread is interrupted.
36691838ded36131525312739c0929913b215519c2aRuben Brunk     */
36791838ded36131525312739c0929913b215519c2aRuben Brunk    public boolean waitForEmpty(long timeout, TimeUnit unit) throws InterruptedException {
36891838ded36131525312739c0929913b215519c2aRuben Brunk        long nanos = unit.toNanos(timeout);
36991838ded36131525312739c0929913b215519c2aRuben Brunk        final ReentrantLock lock = this.mLock;
37091838ded36131525312739c0929913b215519c2aRuben Brunk        lock.lock();
37191838ded36131525312739c0929913b215519c2aRuben Brunk        try {
37291838ded36131525312739c0929913b215519c2aRuben Brunk            while (mInFlight > 0) {
37391838ded36131525312739c0929913b215519c2aRuben Brunk                if (nanos <= 0) {
37491838ded36131525312739c0929913b215519c2aRuben Brunk                    return false;
37591838ded36131525312739c0929913b215519c2aRuben Brunk                }
37691838ded36131525312739c0929913b215519c2aRuben Brunk                nanos = mIsEmpty.awaitNanos(nanos);
37791838ded36131525312739c0929913b215519c2aRuben Brunk            }
37891838ded36131525312739c0929913b215519c2aRuben Brunk            return true;
37991838ded36131525312739c0929913b215519c2aRuben Brunk        } finally {
38091838ded36131525312739c0929913b215519c2aRuben Brunk            lock.unlock();
38191838ded36131525312739c0929913b215519c2aRuben Brunk        }
38291838ded36131525312739c0929913b215519c2aRuben Brunk    }
38391838ded36131525312739c0929913b215519c2aRuben Brunk
38491838ded36131525312739c0929913b215519c2aRuben Brunk    /**
38591838ded36131525312739c0929913b215519c2aRuben Brunk     * Wait all queued requests that use the Camera1 API preview output to complete.
38691838ded36131525312739c0929913b215519c2aRuben Brunk     *
38791838ded36131525312739c0929913b215519c2aRuben Brunk     * @param timeout a timeout to use for this call.
38891838ded36131525312739c0929913b215519c2aRuben Brunk     * @param unit the units to use for the timeout.
38991838ded36131525312739c0929913b215519c2aRuben Brunk     * @return {@code false} if this method timed out.
39091838ded36131525312739c0929913b215519c2aRuben Brunk     * @throws InterruptedException if this thread is interrupted.
39191838ded36131525312739c0929913b215519c2aRuben Brunk     */
39291838ded36131525312739c0929913b215519c2aRuben Brunk    public boolean waitForPreviewsEmpty(long timeout, TimeUnit unit) throws InterruptedException {
39391838ded36131525312739c0929913b215519c2aRuben Brunk        long nanos = unit.toNanos(timeout);
39491838ded36131525312739c0929913b215519c2aRuben Brunk        final ReentrantLock lock = this.mLock;
39591838ded36131525312739c0929913b215519c2aRuben Brunk        lock.lock();
39691838ded36131525312739c0929913b215519c2aRuben Brunk        try {
39791838ded36131525312739c0929913b215519c2aRuben Brunk            while (mInFlightPreviews > 0) {
39891838ded36131525312739c0929913b215519c2aRuben Brunk                if (nanos <= 0) {
39991838ded36131525312739c0929913b215519c2aRuben Brunk                    return false;
40091838ded36131525312739c0929913b215519c2aRuben Brunk                }
40191838ded36131525312739c0929913b215519c2aRuben Brunk                nanos = mPreviewsEmpty.awaitNanos(nanos);
40291838ded36131525312739c0929913b215519c2aRuben Brunk            }
40391838ded36131525312739c0929913b215519c2aRuben Brunk            return true;
40491838ded36131525312739c0929913b215519c2aRuben Brunk        } finally {
40591838ded36131525312739c0929913b215519c2aRuben Brunk            lock.unlock();
40691838ded36131525312739c0929913b215519c2aRuben Brunk        }
40791838ded36131525312739c0929913b215519c2aRuben Brunk    }
40891838ded36131525312739c0929913b215519c2aRuben Brunk
40991838ded36131525312739c0929913b215519c2aRuben Brunk    /**
41083d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin     * Wait for the specified request to be completed (all buffers available).
41183d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin     *
41283d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin     * <p>May not wait for the same request more than once, since a successful wait
41383d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin     * will erase the history of that request.</p>
41483d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin     *
41583d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin     * @param holder the {@link RequestHolder} for this request.
41683d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin     * @param timeout a timeout to use for this call.
41783d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin     * @param unit the units to use for the timeout.
41883d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin     * @param timestamp the timestamp of the request will be written out to here, in ns
41983d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin     *
42083d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin     * @return {@code false} if this method timed out.
42183d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin     *
42283d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin     * @throws InterruptedException if this thread is interrupted.
42383d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin     */
42483d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin    public boolean waitForRequestCompleted(RequestHolder holder, long timeout, TimeUnit unit,
42583d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin            MutableLong timestamp)
42683d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin            throws InterruptedException {
42783d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin        long nanos = unit.toNanos(timeout);
42883d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin        final ReentrantLock lock = this.mLock;
42983d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin        lock.lock();
43083d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin        try {
43183d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin            while (!removeRequestIfCompleted(holder, /*out*/timestamp)) {
43283d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin                if (nanos <= 0) {
43383d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin                    return false;
43483d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin                }
43583d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin                nanos = mNotFull.awaitNanos(nanos);
43683d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin            }
43783d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin            return true;
43883d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin        } finally {
43983d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin            lock.unlock();
44083d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin        }
44183d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin    }
44283d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin
44383d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin    private boolean removeRequestIfCompleted(RequestHolder holder, MutableLong timestamp) {
44483d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin        int i = 0;
44583d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin        for (CaptureHolder h : mCompletedRequests) {
44683d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin            if (h.mRequest.equals(holder)) {
44783d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin                timestamp.value = h.mTimestamp;
44883d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin                mCompletedRequests.remove(i);
44983d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin                return true;
45083d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin            }
45183d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin            i++;
45283d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin        }
45383d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin
45483d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin        return false;
45583d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin    }
45683d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin
45783d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin    /**
45891838ded36131525312739c0929913b215519c2aRuben Brunk     * Called to alert the {@link CaptureCollector} that the jpeg capture has begun.
45991838ded36131525312739c0929913b215519c2aRuben Brunk     *
46091838ded36131525312739c0929913b215519c2aRuben Brunk     * @param timestamp the time of the jpeg capture.
46191838ded36131525312739c0929913b215519c2aRuben Brunk     * @return the {@link RequestHolder} for the request associated with this capture.
46291838ded36131525312739c0929913b215519c2aRuben Brunk     */
46391838ded36131525312739c0929913b215519c2aRuben Brunk    public RequestHolder jpegCaptured(long timestamp) {
46491838ded36131525312739c0929913b215519c2aRuben Brunk        final ReentrantLock lock = this.mLock;
46591838ded36131525312739c0929913b215519c2aRuben Brunk        lock.lock();
46691838ded36131525312739c0929913b215519c2aRuben Brunk        try {
46791838ded36131525312739c0929913b215519c2aRuben Brunk            CaptureHolder h = mJpegCaptureQueue.poll();
46891838ded36131525312739c0929913b215519c2aRuben Brunk            if (h == null) {
46991838ded36131525312739c0929913b215519c2aRuben Brunk                Log.w(TAG, "jpegCaptured called with no jpeg request on queue!");
47091838ded36131525312739c0929913b215519c2aRuben Brunk                return null;
47191838ded36131525312739c0929913b215519c2aRuben Brunk            }
47291838ded36131525312739c0929913b215519c2aRuben Brunk            h.setJpegTimestamp(timestamp);
47391838ded36131525312739c0929913b215519c2aRuben Brunk            return h.mRequest;
47491838ded36131525312739c0929913b215519c2aRuben Brunk        } finally {
47591838ded36131525312739c0929913b215519c2aRuben Brunk            lock.unlock();
47691838ded36131525312739c0929913b215519c2aRuben Brunk        }
47791838ded36131525312739c0929913b215519c2aRuben Brunk    }
47891838ded36131525312739c0929913b215519c2aRuben Brunk
47991838ded36131525312739c0929913b215519c2aRuben Brunk    /**
48091838ded36131525312739c0929913b215519c2aRuben Brunk     * Called to alert the {@link CaptureCollector} that the jpeg capture has completed.
48191838ded36131525312739c0929913b215519c2aRuben Brunk     *
48291838ded36131525312739c0929913b215519c2aRuben Brunk     * @return a pair containing the {@link RequestHolder} and the timestamp of the capture.
48391838ded36131525312739c0929913b215519c2aRuben Brunk     */
48491838ded36131525312739c0929913b215519c2aRuben Brunk    public Pair<RequestHolder, Long> jpegProduced() {
48591838ded36131525312739c0929913b215519c2aRuben Brunk        final ReentrantLock lock = this.mLock;
48691838ded36131525312739c0929913b215519c2aRuben Brunk        lock.lock();
48791838ded36131525312739c0929913b215519c2aRuben Brunk        try {
48891838ded36131525312739c0929913b215519c2aRuben Brunk            CaptureHolder h = mJpegProduceQueue.poll();
48991838ded36131525312739c0929913b215519c2aRuben Brunk            if (h == null) {
49091838ded36131525312739c0929913b215519c2aRuben Brunk                Log.w(TAG, "jpegProduced called with no jpeg request on queue!");
49191838ded36131525312739c0929913b215519c2aRuben Brunk                return null;
49291838ded36131525312739c0929913b215519c2aRuben Brunk            }
49391838ded36131525312739c0929913b215519c2aRuben Brunk            h.setJpegProduced();
49491838ded36131525312739c0929913b215519c2aRuben Brunk            return new Pair<>(h.mRequest, h.mTimestamp);
49591838ded36131525312739c0929913b215519c2aRuben Brunk        } finally {
49691838ded36131525312739c0929913b215519c2aRuben Brunk            lock.unlock();
49791838ded36131525312739c0929913b215519c2aRuben Brunk        }
49891838ded36131525312739c0929913b215519c2aRuben Brunk    }
49991838ded36131525312739c0929913b215519c2aRuben Brunk
50091838ded36131525312739c0929913b215519c2aRuben Brunk    /**
50191838ded36131525312739c0929913b215519c2aRuben Brunk     * Check if there are any pending capture requests that use the Camera1 API preview output.
50291838ded36131525312739c0929913b215519c2aRuben Brunk     *
50391838ded36131525312739c0929913b215519c2aRuben Brunk     * @return {@code true} if there are pending preview requests.
50491838ded36131525312739c0929913b215519c2aRuben Brunk     */
50591838ded36131525312739c0929913b215519c2aRuben Brunk    public boolean hasPendingPreviewCaptures() {
50691838ded36131525312739c0929913b215519c2aRuben Brunk        final ReentrantLock lock = this.mLock;
50791838ded36131525312739c0929913b215519c2aRuben Brunk        lock.lock();
50891838ded36131525312739c0929913b215519c2aRuben Brunk        try {
50991838ded36131525312739c0929913b215519c2aRuben Brunk            return !mPreviewCaptureQueue.isEmpty();
51091838ded36131525312739c0929913b215519c2aRuben Brunk        } finally {
51191838ded36131525312739c0929913b215519c2aRuben Brunk            lock.unlock();
51291838ded36131525312739c0929913b215519c2aRuben Brunk        }
51391838ded36131525312739c0929913b215519c2aRuben Brunk    }
51491838ded36131525312739c0929913b215519c2aRuben Brunk
51591838ded36131525312739c0929913b215519c2aRuben Brunk    /**
51691838ded36131525312739c0929913b215519c2aRuben Brunk     * Called to alert the {@link CaptureCollector} that the preview capture has begun.
51791838ded36131525312739c0929913b215519c2aRuben Brunk     *
51891838ded36131525312739c0929913b215519c2aRuben Brunk     * @param timestamp the time of the preview capture.
51991838ded36131525312739c0929913b215519c2aRuben Brunk     * @return a pair containing the {@link RequestHolder} and the timestamp of the capture.
52091838ded36131525312739c0929913b215519c2aRuben Brunk     */
52191838ded36131525312739c0929913b215519c2aRuben Brunk    public Pair<RequestHolder, Long> previewCaptured(long timestamp) {
52291838ded36131525312739c0929913b215519c2aRuben Brunk        final ReentrantLock lock = this.mLock;
52391838ded36131525312739c0929913b215519c2aRuben Brunk        lock.lock();
52491838ded36131525312739c0929913b215519c2aRuben Brunk        try {
52591838ded36131525312739c0929913b215519c2aRuben Brunk            CaptureHolder h = mPreviewCaptureQueue.poll();
52691838ded36131525312739c0929913b215519c2aRuben Brunk            if (h == null) {
527e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                if (DEBUG) {
528e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                    Log.d(TAG, "previewCaptured called with no preview request on queue!");
529e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                }
53091838ded36131525312739c0929913b215519c2aRuben Brunk                return null;
53191838ded36131525312739c0929913b215519c2aRuben Brunk            }
53291838ded36131525312739c0929913b215519c2aRuben Brunk            h.setPreviewTimestamp(timestamp);
53391838ded36131525312739c0929913b215519c2aRuben Brunk            return new Pair<>(h.mRequest, h.mTimestamp);
53491838ded36131525312739c0929913b215519c2aRuben Brunk        } finally {
53591838ded36131525312739c0929913b215519c2aRuben Brunk            lock.unlock();
53691838ded36131525312739c0929913b215519c2aRuben Brunk        }
53791838ded36131525312739c0929913b215519c2aRuben Brunk    }
53891838ded36131525312739c0929913b215519c2aRuben Brunk
53991838ded36131525312739c0929913b215519c2aRuben Brunk    /**
54091838ded36131525312739c0929913b215519c2aRuben Brunk     * Called to alert the {@link CaptureCollector} that the preview capture has completed.
54191838ded36131525312739c0929913b215519c2aRuben Brunk     *
54291838ded36131525312739c0929913b215519c2aRuben Brunk     * @return the {@link RequestHolder} for the request associated with this capture.
54391838ded36131525312739c0929913b215519c2aRuben Brunk     */
54491838ded36131525312739c0929913b215519c2aRuben Brunk    public RequestHolder previewProduced() {
54591838ded36131525312739c0929913b215519c2aRuben Brunk        final ReentrantLock lock = this.mLock;
54691838ded36131525312739c0929913b215519c2aRuben Brunk        lock.lock();
54791838ded36131525312739c0929913b215519c2aRuben Brunk        try {
54891838ded36131525312739c0929913b215519c2aRuben Brunk            CaptureHolder h = mPreviewProduceQueue.poll();
54991838ded36131525312739c0929913b215519c2aRuben Brunk            if (h == null) {
55091838ded36131525312739c0929913b215519c2aRuben Brunk                Log.w(TAG, "previewProduced called with no preview request on queue!");
55191838ded36131525312739c0929913b215519c2aRuben Brunk                return null;
55291838ded36131525312739c0929913b215519c2aRuben Brunk            }
55391838ded36131525312739c0929913b215519c2aRuben Brunk            h.setPreviewProduced();
55491838ded36131525312739c0929913b215519c2aRuben Brunk            return h.mRequest;
55591838ded36131525312739c0929913b215519c2aRuben Brunk        } finally {
55691838ded36131525312739c0929913b215519c2aRuben Brunk            lock.unlock();
55791838ded36131525312739c0929913b215519c2aRuben Brunk        }
55891838ded36131525312739c0929913b215519c2aRuben Brunk    }
55991838ded36131525312739c0929913b215519c2aRuben Brunk
560e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk    /**
561e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk     * Called to alert the {@link CaptureCollector} that the next pending preview capture has failed.
562e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk     */
563e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk    public void failNextPreview() {
564e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        final ReentrantLock lock = this.mLock;
565e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        lock.lock();
566e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        try {
567e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            CaptureHolder h1 = mPreviewCaptureQueue.peek();
568e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            CaptureHolder h2 = mPreviewProduceQueue.peek();
569e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk
570e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            // Find the request with the lowest frame number.
571e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            CaptureHolder h = (h1 == null) ? h2 :
572e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                              ((h2 == null) ? h1 :
573e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                              ((h1.compareTo(h2) <= 0) ? h1 :
574e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                              h2));
575e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk
576e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            if (h != null) {
577e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                mPreviewCaptureQueue.remove(h);
578e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                mPreviewProduceQueue.remove(h);
579e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                mActiveRequests.remove(h);
580e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                h.setPreviewFailed();
581e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            }
582e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        } finally {
583e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            lock.unlock();
584e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        }
585e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk    }
586e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk
587e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk    /**
588e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk     * Called to alert the {@link CaptureCollector} that the next pending jpeg capture has failed.
589e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk     */
590e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk    public void failNextJpeg() {
591e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        final ReentrantLock lock = this.mLock;
592e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        lock.lock();
593e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        try {
594e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            CaptureHolder h1 = mJpegCaptureQueue.peek();
595e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            CaptureHolder h2 = mJpegProduceQueue.peek();
596e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk
597e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            // Find the request with the lowest frame number.
598e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            CaptureHolder h = (h1 == null) ? h2 :
599e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                              ((h2 == null) ? h1 :
600e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                              ((h1.compareTo(h2) <= 0) ? h1 :
601e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                              h2));
602e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk
603e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            if (h != null) {
604e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                mJpegCaptureQueue.remove(h);
605e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                mJpegProduceQueue.remove(h);
606e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                mActiveRequests.remove(h);
607e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                h.setJpegFailed();
608e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            }
609e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        } finally {
610e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            lock.unlock();
611e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        }
612e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk    }
613e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk
614e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk    /**
615e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk     * Called to alert the {@link CaptureCollector} all pending captures have failed.
616e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk     */
617e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk    public void failAll() {
618e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        final ReentrantLock lock = this.mLock;
619e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        lock.lock();
620e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        try {
621e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            CaptureHolder h;
622e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            while ((h = mActiveRequests.pollFirst()) != null) {
623e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                h.setPreviewFailed();
624e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                h.setJpegFailed();
625e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            }
626e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            mPreviewCaptureQueue.clear();
627e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            mPreviewProduceQueue.clear();
628e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            mJpegCaptureQueue.clear();
629e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            mJpegProduceQueue.clear();
630e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        } finally {
631e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk            lock.unlock();
632e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        }
633e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk    }
634e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk
63591838ded36131525312739c0929913b215519c2aRuben Brunk    private void onPreviewCompleted() {
63691838ded36131525312739c0929913b215519c2aRuben Brunk        mInFlightPreviews--;
63791838ded36131525312739c0929913b215519c2aRuben Brunk        if (mInFlightPreviews < 0) {
63891838ded36131525312739c0929913b215519c2aRuben Brunk            throw new IllegalStateException(
63991838ded36131525312739c0929913b215519c2aRuben Brunk                    "More preview captures completed than requests queued.");
64091838ded36131525312739c0929913b215519c2aRuben Brunk        }
64191838ded36131525312739c0929913b215519c2aRuben Brunk        if (mInFlightPreviews == 0) {
64291838ded36131525312739c0929913b215519c2aRuben Brunk            mPreviewsEmpty.signalAll();
64391838ded36131525312739c0929913b215519c2aRuben Brunk        }
64491838ded36131525312739c0929913b215519c2aRuben Brunk    }
64591838ded36131525312739c0929913b215519c2aRuben Brunk
64683d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin    private void onRequestCompleted(CaptureHolder capture) {
64783d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin        RequestHolder request = capture.mRequest;
64883d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin
64991838ded36131525312739c0929913b215519c2aRuben Brunk        mInFlight--;
65091838ded36131525312739c0929913b215519c2aRuben Brunk        if (DEBUG) {
65191838ded36131525312739c0929913b215519c2aRuben Brunk            Log.d(TAG, "Completed request " + request.getRequestId() +
65291838ded36131525312739c0929913b215519c2aRuben Brunk                    ", " + mInFlight + " requests remain in flight.");
65391838ded36131525312739c0929913b215519c2aRuben Brunk        }
65491838ded36131525312739c0929913b215519c2aRuben Brunk        if (mInFlight < 0) {
65591838ded36131525312739c0929913b215519c2aRuben Brunk            throw new IllegalStateException(
65691838ded36131525312739c0929913b215519c2aRuben Brunk                    "More captures completed than requests queued.");
65791838ded36131525312739c0929913b215519c2aRuben Brunk        }
65883d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin
65983d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin        mCompletedRequests.add(capture);
660e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        mActiveRequests.remove(capture);
66183d8639e901a24e59c9886dd6910faf3ba7adae1Igor Murashkin
66291838ded36131525312739c0929913b215519c2aRuben Brunk        mNotFull.signalAll();
66391838ded36131525312739c0929913b215519c2aRuben Brunk        if (mInFlight == 0) {
66491838ded36131525312739c0929913b215519c2aRuben Brunk            mIsEmpty.signalAll();
66591838ded36131525312739c0929913b215519c2aRuben Brunk        }
66691838ded36131525312739c0929913b215519c2aRuben Brunk    }
66791838ded36131525312739c0929913b215519c2aRuben Brunk}
668