LegacyCameraDevice.java revision 0fd198ad89ec9c600bb1761b10d938146c28bb98
1feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk/*
2feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * Copyright (C) 2014 The Android Open Source Project
3feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk *
4feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * Licensed under the Apache License, Version 2.0 (the "License");
5feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * you may not use this file except in compliance with the License.
6feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * You may obtain a copy of the License at
7feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk *
8feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk *      http://www.apache.org/licenses/LICENSE-2.0
9feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk *
10feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * Unless required by applicable law or agreed to in writing, software
11feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * distributed under the License is distributed on an "AS IS" BASIS,
12feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * See the License for the specific language governing permissions and
14feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * limitations under the License.
15feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk */
16feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
17feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkpackage android.hardware.camera2.legacy;
18feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
19feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.graphics.ImageFormat;
2028c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunkimport android.graphics.SurfaceTexture;
21feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.hardware.Camera;
22df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinimport android.hardware.camera2.CameraCharacteristics;
23feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.hardware.camera2.CaptureRequest;
24feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.hardware.camera2.impl.CaptureResultExtras;
25feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.hardware.camera2.ICameraDeviceCallbacks;
26e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunkimport android.hardware.camera2.params.StreamConfiguration;
27e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunkimport android.hardware.camera2.params.StreamConfigurationMap;
28e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunkimport android.hardware.camera2.utils.ArrayUtils;
294aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunkimport android.hardware.camera2.utils.CameraBinderDecorator;
30feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.hardware.camera2.utils.LongParcelable;
31feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.hardware.camera2.impl.CameraMetadataNative;
32feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.hardware.camera2.utils.CameraRuntimeException;
33feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.os.ConditionVariable;
34feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.os.Handler;
35feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.os.HandlerThread;
36feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.os.RemoteException;
37feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.util.Log;
38a296fece2b974a11bc624fd67b275863f17df867Igor Murashkinimport android.util.Size;
39feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.view.Surface;
40feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
41feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport java.util.ArrayList;
42e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunkimport java.util.Arrays;
433c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunkimport java.util.Collection;
44feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport java.util.List;
4549b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin
46ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunkimport static android.hardware.camera2.legacy.LegacyExceptionUtils.*;
4749b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkinimport static android.hardware.camera2.utils.CameraBinderDecorator.*;
48a296fece2b974a11bc624fd67b275863f17df867Igor Murashkinimport static com.android.internal.util.Preconditions.*;
49feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
50feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk/**
51feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * This class emulates the functionality of a Camera2 device using a the old Camera class.
52feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk *
53feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * <p>
54feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * There are two main components that are used to implement this:
55feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * - A state machine containing valid Camera2 device states ({@link CameraDeviceState}).
56feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * - A message-queue based pipeline that manages an old Camera class, and executes capture and
57feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk *   configuration requests.
58feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * </p>
59feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk */
60feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkpublic class LegacyCameraDevice implements AutoCloseable {
61feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public static final String DEBUG_PROP = "HAL1ShimLogging";
62feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private final String TAG;
63feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
64e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk    private static final boolean DEBUG = Log.isLoggable(LegacyCameraDevice.DEBUG_PROP, Log.DEBUG);
65feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private final int mCameraId;
66e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk    private final CameraCharacteristics mStaticCharacteristics;
67feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private final ICameraDeviceCallbacks mDeviceCallbacks;
68feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private final CameraDeviceState mDeviceState = new CameraDeviceState();
6949b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin    private List<Surface> mConfiguredSurfaces;
70e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk    private boolean mClosed = false;
71feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
72feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private final ConditionVariable mIdle = new ConditionVariable(/*open*/true);
73feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
74d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk    private final HandlerThread mResultThread = new HandlerThread("ResultThread");
75d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk    private final HandlerThread mCallbackHandlerThread = new HandlerThread("CallbackThread");
76feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private final Handler mCallbackHandler;
77d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk    private final Handler mResultHandler;
78feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private static final int ILLEGAL_VALUE = -1;
79feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
80feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private CaptureResultExtras getExtrasFromRequest(RequestHolder holder) {
81feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (holder == null) {
82feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            return new CaptureResultExtras(ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE,
8383159151f618c79040a2e800de8cc78f22bf760bZhijun He                    ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE);
84feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
85feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        return new CaptureResultExtras(holder.getRequestId(), holder.getSubsequeceId(),
8683159151f618c79040a2e800de8cc78f22bf760bZhijun He                /*afTriggerId*/0, /*precaptureTriggerId*/0, holder.getFrameNumber(),
8783159151f618c79040a2e800de8cc78f22bf760bZhijun He                /*partialResultCount*/1);
88feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
89feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
90feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
91feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Listener for the camera device state machine.  Calls the appropriate
92feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * {@link ICameraDeviceCallbacks} for each state transition.
93feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
94feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private final CameraDeviceState.CameraDeviceStateListener mStateListener =
95feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            new CameraDeviceState.CameraDeviceStateListener() {
96feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        @Override
97e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        public void onError(final int errorCode, final RequestHolder holder) {
98feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            mIdle.open();
99feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            final CaptureResultExtras extras = getExtrasFromRequest(holder);
100d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            mResultHandler.post(new Runnable() {
101d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                @Override
102d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                public void run() {
1033e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk                    if (DEBUG) {
104e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                        Log.d(TAG, "doing onError callback for request " + holder.getRequestId() +
105e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                                ", with error code " + errorCode);
1063e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk                    }
107d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    try {
108acc0095bc84914d3ce41ad8298f698c37935b8a8Eino-Ville Talvala                        mDeviceCallbacks.onDeviceError(errorCode, extras);
109d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    } catch (RemoteException e) {
110d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                        throw new IllegalStateException(
111d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                                "Received remote exception during onCameraError callback: ", e);
112d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    }
113d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                }
114d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            });
115feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
116feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
117feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        @Override
118feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        public void onConfiguring() {
119feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            // Do nothing
1203e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk            if (DEBUG) {
1213e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk                Log.d(TAG, "doing onConfiguring callback.");
1223e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk            }
123feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
124feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
125feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        @Override
126feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        public void onIdle() {
127feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            mIdle.open();
128feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
129d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            mResultHandler.post(new Runnable() {
130d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                @Override
131d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                public void run() {
1323e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk                    if (DEBUG) {
1333e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk                        Log.d(TAG, "doing onIdle callback.");
1343e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk                    }
135d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    try {
136acc0095bc84914d3ce41ad8298f698c37935b8a8Eino-Ville Talvala                        mDeviceCallbacks.onDeviceIdle();
137d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    } catch (RemoteException e) {
138d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                        throw new IllegalStateException(
139d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                                "Received remote exception during onCameraIdle callback: ", e);
140d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    }
141d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                }
142d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            });
143feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
144feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
145feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        @Override
146e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        public void onCaptureStarted(final RequestHolder holder, final long timestamp) {
147feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            final CaptureResultExtras extras = getExtrasFromRequest(holder);
148feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
149d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            mResultHandler.post(new Runnable() {
150d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                @Override
151d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                public void run() {
1523e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk                    if (DEBUG) {
153e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                        Log.d(TAG, "doing onCaptureStarted callback for request " +
154e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                                holder.getRequestId());
1553e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk                    }
156d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    try {
157d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                        mDeviceCallbacks.onCaptureStarted(extras, timestamp);
158d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    } catch (RemoteException e) {
159d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                        throw new IllegalStateException(
160d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                                "Received remote exception during onCameraError callback: ", e);
161d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    }
162d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                }
163d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            });
164feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
165feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
166feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        @Override
167e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        public void onCaptureResult(final CameraMetadataNative result, final RequestHolder holder) {
168feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            final CaptureResultExtras extras = getExtrasFromRequest(holder);
169feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
170d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            mResultHandler.post(new Runnable() {
171d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                @Override
172d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                public void run() {
1733e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk                    if (DEBUG) {
174e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                        Log.d(TAG, "doing onCaptureResult callback for request " +
175e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                                holder.getRequestId());
1763e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk                    }
177d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    try {
178d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                        mDeviceCallbacks.onResultReceived(result, extras);
179d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    } catch (RemoteException e) {
180d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                        throw new IllegalStateException(
181d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                                "Received remote exception during onCameraError callback: ", e);
182d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    }
183d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                }
184d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            });
185feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
186feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    };
187feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
188feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private final RequestThreadManager mRequestThreadManager;
189feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
190feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
19191b9aabc9fa0c058ecc4a8b3f486540c28fe1cc0Ruben Brunk     * Check if a given surface uses {@link ImageFormat#YUV_420_888} or format that can be readily
19291b9aabc9fa0c058ecc4a8b3f486540c28fe1cc0Ruben Brunk     * converted to this; YV12 and NV21 are the two currently supported formats.
193feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
194feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param s the surface to check.
19591b9aabc9fa0c058ecc4a8b3f486540c28fe1cc0Ruben Brunk     * @return {@code true} if the surfaces uses {@link ImageFormat#YUV_420_888} or a compatible
19691b9aabc9fa0c058ecc4a8b3f486540c28fe1cc0Ruben Brunk     *          format.
197feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
198ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    static boolean needsConversion(Surface s) throws BufferQueueAbandonedException {
199ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        int nativeType = detectSurfaceType(s);
20091b9aabc9fa0c058ecc4a8b3f486540c28fe1cc0Ruben Brunk        return nativeType == ImageFormat.YUV_420_888 || nativeType == ImageFormat.YV12 ||
20191b9aabc9fa0c058ecc4a8b3f486540c28fe1cc0Ruben Brunk                nativeType == ImageFormat.NV21;
202feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
203feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
204feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
205feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Create a new emulated camera device from a given Camera 1 API camera.
206feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
207feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * <p>
208feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * The {@link Camera} provided to this constructor must already have been successfully opened,
209feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * and ownership of the provided camera is passed to this object.  No further calls to the
210feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * camera methods should be made following this constructor.
211feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * </p>
212feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
213feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param cameraId the id of the camera.
214feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param camera an open {@link Camera} device.
215df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     * @param characteristics the static camera characteristics for this camera device
216feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param callbacks {@link ICameraDeviceCallbacks} callbacks to call for Camera2 API operations.
217feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
218df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin    public LegacyCameraDevice(int cameraId, Camera camera, CameraCharacteristics characteristics,
219df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin            ICameraDeviceCallbacks callbacks) {
220feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mCameraId = cameraId;
221feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mDeviceCallbacks = callbacks;
222feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        TAG = String.format("CameraDevice-%d-LE", mCameraId);
223feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
224d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        mResultThread.start();
225d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        mResultHandler = new Handler(mResultThread.getLooper());
226feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mCallbackHandlerThread.start();
227feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mCallbackHandler = new Handler(mCallbackHandlerThread.getLooper());
228feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mDeviceState.setCameraDeviceCallbacks(mCallbackHandler, mStateListener);
229e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        mStaticCharacteristics = characteristics;
230feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mRequestThreadManager =
231df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin                new RequestThreadManager(cameraId, camera, characteristics, mDeviceState);
232feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mRequestThreadManager.start();
233feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
234feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
235feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
236feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Configure the device with a set of output surfaces.
237feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
23849b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin     * <p>Using empty or {@code null} {@code outputs} is the same as unconfiguring.</p>
23949b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin     *
24049b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin     * <p>Every surface in {@code outputs} must be non-{@code null}.</p>
24149b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin     *
242feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param outputs a list of surfaces to set.
24349b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin     * @return an error code for this binder operation, or {@link NO_ERROR}
244feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *          on success.
245feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
246feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public int configureOutputs(List<Surface> outputs) {
24749b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin        if (outputs != null) {
24849b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin            for (Surface output : outputs) {
24949b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                if (output == null) {
25049b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                    Log.e(TAG, "configureOutputs - null outputs are not allowed");
25149b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                    return BAD_VALUE;
25249b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                }
253e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                StreamConfigurationMap streamConfigurations = mStaticCharacteristics.
254e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                        get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
255e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk
256e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                // Validate surface size and format.
257e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                try {
258e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                    Size s = getSurfaceSize(output);
259e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                    int surfaceType = detectSurfaceType(output);
260e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                    Size[] sizes = streamConfigurations.getOutputSizes(surfaceType);
261e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk
262e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                    if (sizes == null) {
263e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                        // WAR: Override default format to IMPLEMENTATION_DEFINED for b/9487482
264e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                        if ((surfaceType >= LegacyMetadataMapper.HAL_PIXEL_FORMAT_RGBA_8888 &&
265e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                            surfaceType <= LegacyMetadataMapper.HAL_PIXEL_FORMAT_BGRA_8888)) {
266e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk
267e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                            // YUV_420_888 is always present in LEGACY for all IMPLEMENTATION_DEFINED
268e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                            // output sizes, and is publicly visible in the API (i.e.
269e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                            // {@code #getOutputSizes} works here).
270e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                            sizes = streamConfigurations.getOutputSizes(ImageFormat.YUV_420_888);
271e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                        } else if (surfaceType == LegacyMetadataMapper.HAL_PIXEL_FORMAT_BLOB) {
272e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                            sizes = streamConfigurations.getOutputSizes(ImageFormat.JPEG);
273e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                        }
274e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                    }
275e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk
276e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                    if (!ArrayUtils.contains(sizes, s)) {
277e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                        String reason = (sizes == null) ? "format is invalid." :
278e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                                ("size not in valid set: " + Arrays.toString(sizes));
279e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                        Log.e(TAG, String.format("Surface with size (w=%d, h=%d) and format 0x%x is"
280e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                                + " not valid, %s", s.getWidth(), s.getHeight(), surfaceType,
281e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                                reason));
282e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                        return BAD_VALUE;
283e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                    }
284e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                } catch (BufferQueueAbandonedException e) {
285e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                    Log.e(TAG, "Surface bufferqueue is abandoned, cannot configure as output: ", e);
286e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                    return BAD_VALUE;
287e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk                }
288e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk
28949b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin            }
29049b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin        }
29149b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin
2924aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk        boolean success = false;
2934aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk        if (mDeviceState.setConfiguring()) {
294feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            mRequestThreadManager.configure(outputs);
2954aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk            success = mDeviceState.setIdle();
296feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
29749b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin
2984aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk        if (success) {
29949b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin            mConfiguredSurfaces = outputs != null ? new ArrayList<>(outputs) : null;
3004aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk        } else {
3014aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk            return CameraBinderDecorator.INVALID_OPERATION;
30249b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin        }
3034aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk        return CameraBinderDecorator.NO_ERROR;
304feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
305feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
306feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
307feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Submit a burst of capture requests.
308feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
309feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param requestList a list of capture requests to execute.
310feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param repeating {@code true} if this burst is repeating.
311feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param frameNumber an output argument that contains either the frame number of the last frame
312feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *                    that will be returned for this request, or the frame number of the last
313feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *                    frame that will be returned for the current repeating request if this
314feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *                    burst is set to be repeating.
315feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @return the request id.
316feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
317feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public int submitRequestList(List<CaptureRequest> requestList, boolean repeating,
318feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            /*out*/LongParcelable frameNumber) {
31949b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin        if (requestList == null || requestList.isEmpty()) {
32049b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin            Log.e(TAG, "submitRequestList - Empty/null requests are not allowed");
32149b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin            return BAD_VALUE;
32249b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin        }
32349b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin
3243c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk        List<Long> surfaceIds = (mConfiguredSurfaces == null) ? new ArrayList<Long>() :
3253c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk                getSurfaceIds(mConfiguredSurfaces);
3263c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk
32749b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin        // Make sure that there all requests have at least 1 surface; all surfaces are non-null
32849b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin        for (CaptureRequest request : requestList) {
32949b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin            if (request.getTargets().isEmpty()) {
33049b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                Log.e(TAG, "submitRequestList - "
33149b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                        + "Each request must have at least one Surface target");
33249b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                return BAD_VALUE;
33349b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin            }
33449b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin
33549b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin            for (Surface surface : request.getTargets()) {
33649b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                if (surface == null) {
33749b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                    Log.e(TAG, "submitRequestList - Null Surface targets are not allowed");
33849b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                    return BAD_VALUE;
33949b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                } else if (mConfiguredSurfaces == null) {
34049b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                    Log.e(TAG, "submitRequestList - must configure " +
34149b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                            " device with valid surfaces before submitting requests");
34249b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                    return INVALID_OPERATION;
3433c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk                } else if (!containsSurfaceId(surface, surfaceIds)) {
34449b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                    Log.e(TAG, "submitRequestList - cannot use a surface that wasn't configured");
34549b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                    return BAD_VALUE;
34649b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                }
34749b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin            }
34849b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin        }
34949b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin
35049b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin        // TODO: further validation of request here
351feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mIdle.close();
352feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        return mRequestThreadManager.submitCaptureRequests(requestList, repeating,
353feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                frameNumber);
354feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
355feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
356feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
357feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Submit a single capture request.
358feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
359feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param request the capture request to execute.
360feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param repeating {@code true} if this request is repeating.
361feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param frameNumber an output argument that contains either the frame number of the last frame
362feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *                    that will be returned for this request, or the frame number of the last
363feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *                    frame that will be returned for the current repeating request if this
364feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *                    request is set to be repeating.
365feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @return the request id.
366feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
367feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public int submitRequest(CaptureRequest request, boolean repeating,
368feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            /*out*/LongParcelable frameNumber) {
369feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        ArrayList<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
370feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        requestList.add(request);
371feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        return submitRequestList(requestList, repeating, frameNumber);
372feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
373feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
374feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
375feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Cancel the repeating request with the given request id.
376feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
377feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param requestId the request id of the request to cancel.
378feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @return the last frame number to be returned from the HAL for the given repeating request, or
379feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *          {@code INVALID_FRAME} if none exists.
380feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
381feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public long cancelRequest(int requestId) {
382feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        return mRequestThreadManager.cancelRepeating(requestId);
383feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
384feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
385feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
386feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Block until the {@link ICameraDeviceCallbacks#onCameraIdle()} callback is received.
387feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
388feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public void waitUntilIdle()  {
389feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mIdle.block();
390feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
391feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
392e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk    /**
393e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk     * Flush any pending requests.
394e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk     *
395e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk     * @return the last frame number.
396e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk     */
397e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk    public long flush() {
398e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        long lastFrame = mRequestThreadManager.flush();
399e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        waitUntilIdle();
400e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        return lastFrame;
401e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk    }
402e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk
403e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk    /**
404e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk     * Return {@code true} if the device has been closed.
405e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk     */
406e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk    public boolean isClosed() {
407e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        return mClosed;
408e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk    }
409e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk
410feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    @Override
411feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public void close() {
412feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mRequestThreadManager.quit();
413feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mCallbackHandlerThread.quitSafely();
414d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        mResultThread.quitSafely();
415d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk
416d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        try {
417d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            mCallbackHandlerThread.join();
418d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        } catch (InterruptedException e) {
419d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
420d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    mCallbackHandlerThread.getName(), mCallbackHandlerThread.getId()));
421d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        }
422d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk
423d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        try {
424d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            mResultThread.join();
425d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        } catch (InterruptedException e) {
426d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
427d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    mResultThread.getName(), mResultThread.getId()));
428d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        }
429d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk
430e663cb77281c4c76241b820f6126543f1c2d859fRuben Brunk        mClosed = true;
431feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
432feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
433feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    @Override
434feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    protected void finalize() throws Throwable {
435feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        try {
436feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            close();
437feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        } catch (CameraRuntimeException e) {
438feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            Log.e(TAG, "Got error while trying to finalize, ignoring: " + e.getMessage());
439feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        } finally {
440feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            super.finalize();
441feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
442feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
443feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
444a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin    /**
445a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin     * Query the surface for its currently configured default buffer size.
446a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin     * @param surface a non-{@code null} {@code Surface}
447a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin     * @return the width and height of the surface
448a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin     *
449a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin     * @throws NullPointerException if the {@code surface} was {@code null}
450a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin     * @throws IllegalStateException if the {@code surface} was invalid
451a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin     */
452ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    static Size getSurfaceSize(Surface surface) throws BufferQueueAbandonedException {
453a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin        checkNotNull(surface);
454a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin
455a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin        int[] dimens = new int[2];
456ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        LegacyExceptionUtils.throwOnError(nativeDetectSurfaceDimens(surface, /*out*/dimens));
457a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin
458a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin        return new Size(dimens[0], dimens[1]);
459a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin    }
460a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin
461ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    static int detectSurfaceType(Surface surface) throws BufferQueueAbandonedException {
462ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkNotNull(surface);
463ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        return LegacyExceptionUtils.throwOnError(nativeDetectSurfaceType(surface));
464ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    }
465ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk
466ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    static void configureSurface(Surface surface, int width, int height,
467ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                                 int pixelFormat) throws BufferQueueAbandonedException {
468ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkNotNull(surface);
469ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkArgumentPositive(width, "width must be positive.");
470ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkArgumentPositive(height, "height must be positive.");
471ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk
472ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        LegacyExceptionUtils.throwOnError(nativeConfigureSurface(surface, width, height,
473ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                pixelFormat));
474ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    }
475ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk
476ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    static void produceFrame(Surface surface, byte[] pixelBuffer, int width,
477ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                             int height, int pixelFormat)
478ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk            throws BufferQueueAbandonedException {
479ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkNotNull(surface);
480ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkNotNull(pixelBuffer);
481ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkArgumentPositive(width, "width must be positive.");
482ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkArgumentPositive(height, "height must be positive.");
483ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk
484ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        LegacyExceptionUtils.throwOnError(nativeProduceFrame(surface, pixelBuffer, width, height,
485ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                pixelFormat));
486ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    }
487ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk
488ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    static void setSurfaceFormat(Surface surface, int pixelFormat)
489ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk            throws BufferQueueAbandonedException {
490ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkNotNull(surface);
491ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk
492ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        LegacyExceptionUtils.throwOnError(nativeSetSurfaceFormat(surface, pixelFormat));
493ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    }
494ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk
495ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    static void setSurfaceDimens(Surface surface, int width, int height)
496ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk            throws BufferQueueAbandonedException {
497ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkNotNull(surface);
498ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkArgumentPositive(width, "width must be positive.");
499ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkArgumentPositive(height, "height must be positive.");
500ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk
501ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        LegacyExceptionUtils.throwOnError(nativeSetSurfaceDimens(surface, width, height));
502ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    }
503ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk
5043c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk    static long getSurfaceId(Surface surface) {
5053c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk        checkNotNull(surface);
5063c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk        return nativeGetSurfaceId(surface);
5073c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk    }
5083c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk
5093c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk    static List<Long> getSurfaceIds(Collection<Surface> surfaces) {
5103c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk        if (surfaces == null) {
5113c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk            throw new NullPointerException("Null argument surfaces");
5123c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk        }
5133c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk        List<Long> surfaceIds = new ArrayList<>();
5143c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk        for (Surface s : surfaces) {
5153c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk            long id = getSurfaceId(s);
5163c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk            if (id == 0) {
5173c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk                throw new IllegalStateException(
5183c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk                        "Configured surface had null native GraphicBufferProducer pointer!");
5193c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk            }
5203c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk            surfaceIds.add(id);
5213c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk        }
5223c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk        return surfaceIds;
5233c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk    }
5243c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk
5250fd198ad89ec9c600bb1761b10d938146c28bb98Ruben Brunk    static boolean containsSurfaceId(Surface s, Collection<Long> ids) {
5263c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk        long id = getSurfaceId(s);
5273c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk        return ids.contains(id);
5283c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk    }
5293c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk
53028c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk    static void setSurfaceOrientation(Surface surface, int facing, int sensorOrientation)
53128c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            throws BufferQueueAbandonedException {
53228c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        checkNotNull(surface);
53328c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        LegacyExceptionUtils.throwOnError(nativeSetSurfaceOrientation(surface, facing,
53428c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk                sensorOrientation));
53528c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk    }
53628c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
53728c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk    static Size getTextureSize(SurfaceTexture surfaceTexture)
53828c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            throws BufferQueueAbandonedException {
53928c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        checkNotNull(surfaceTexture);
54028c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
54128c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        int[] dimens = new int[2];
54228c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        LegacyExceptionUtils.throwOnError(nativeDetectTextureDimens(surfaceTexture,
54328c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk                /*out*/dimens));
54428c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
54528c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        return new Size(dimens[0], dimens[1]);
54628c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk    }
54728c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
54891838ded36131525312739c0929913b215519c2aRuben Brunk    static void setNextTimestamp(Surface surface, long timestamp)
54991838ded36131525312739c0929913b215519c2aRuben Brunk            throws BufferQueueAbandonedException {
55091838ded36131525312739c0929913b215519c2aRuben Brunk        checkNotNull(surface);
55191838ded36131525312739c0929913b215519c2aRuben Brunk        LegacyExceptionUtils.throwOnError(nativeSetNextTimestamp(surface, timestamp));
55291838ded36131525312739c0929913b215519c2aRuben Brunk    }
55391838ded36131525312739c0929913b215519c2aRuben Brunk
554ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    private static native int nativeDetectSurfaceType(Surface surface);
555feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
556ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    private static native int nativeDetectSurfaceDimens(Surface surface,
557a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin            /*out*/int[/*2*/] dimens);
558feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
559ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    private static native int nativeConfigureSurface(Surface surface, int width, int height,
560feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                                                        int pixelFormat);
561feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
562ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    private static native int nativeProduceFrame(Surface surface, byte[] pixelBuffer, int width,
563feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                                                    int height, int pixelFormat);
564feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
565ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    private static native int nativeSetSurfaceFormat(Surface surface, int pixelFormat);
566feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
567ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    private static native int nativeSetSurfaceDimens(Surface surface, int width, int height);
568feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
5693c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk    private static native long nativeGetSurfaceId(Surface surface);
57028c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
57128c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk    private static native int nativeSetSurfaceOrientation(Surface surface, int facing,
57228c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk                                                             int sensorOrientation);
57328c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
57428c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk    private static native int nativeDetectTextureDimens(SurfaceTexture surfaceTexture,
57528c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            /*out*/int[/*2*/] dimens);
57628c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
57791838ded36131525312739c0929913b215519c2aRuben Brunk    private static native int nativeSetNextTimestamp(Surface surface, long timestamp);
5781dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk
5791dc1326eaedd11ffd8f85927b8f0195f4f7598d3Ruben Brunk    static native int nativeGetJpegFooterSize();
580feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk}
581