blob: f422289355793204ca2e6dc41d736ffff7bacc89 [file] [log] [blame]
Igor Murashkin70725502013-06-25 20:27:06 +00001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -070017package android.hardware.camera2.impl;
Igor Murashkin70725502013-06-25 20:27:06 +000018
Svet Ganov82f09bc2018-01-12 22:08:40 -080019import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070020
Emilian Peevb9a51942018-03-14 17:18:49 +000021import android.annotation.NonNull;
Shuzhen Wang23d29382017-11-26 17:24:56 -080022import android.hardware.ICameraService;
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -070023import android.hardware.camera2.CameraAccessException;
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -070024import android.hardware.camera2.CameraCaptureSession;
Ruben Brunk57493682014-05-27 18:58:08 -070025import android.hardware.camera2.CameraCharacteristics;
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -070026import android.hardware.camera2.CameraDevice;
Shuzhen Wang23d29382017-11-26 17:24:56 -080027import android.hardware.camera2.CaptureFailure;
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -070028import android.hardware.camera2.CaptureRequest;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070029import android.hardware.camera2.CaptureResult;
30import android.hardware.camera2.ICameraDeviceCallbacks;
31import android.hardware.camera2.ICameraDeviceUser;
Igor Murashkindb075af2014-05-21 10:07:08 -070032import android.hardware.camera2.TotalCaptureResult;
Chien-Yu Chen5398a672015-03-19 14:48:43 -070033import android.hardware.camera2.params.InputConfiguration;
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -070034import android.hardware.camera2.params.OutputConfiguration;
Emilian Peev75a55702017-11-07 16:09:59 +000035import android.hardware.camera2.params.SessionConfiguration;
Chien-Yu Chen5398a672015-03-19 14:48:43 -070036import android.hardware.camera2.params.StreamConfigurationMap;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -080037import android.hardware.camera2.utils.SubmitInfo;
Zhijun Hea7677722015-06-01 16:36:06 -070038import android.hardware.camera2.utils.SurfaceUtils;
Emilian Peev77ca8662018-03-14 17:12:13 +000039import android.os.Binder;
Chien-Yu Chen3d2b5fe2017-04-05 16:42:31 -070040import android.os.Build;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070041import android.os.Handler;
Ruben Brunkdecfe952013-10-29 11:00:32 -070042import android.os.IBinder;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070043import android.os.Looper;
Ruben Brunkdecfe952013-10-29 11:00:32 -070044import android.os.RemoteException;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -080045import android.os.ServiceSpecificException;
Igor Murashkin70725502013-06-25 20:27:06 +000046import android.util.Log;
Zhijun Hea7677722015-06-01 16:36:06 -070047import android.util.Range;
Chien-Yu Chen5398a672015-03-19 14:48:43 -070048import android.util.Size;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070049import android.util.SparseArray;
Igor Murashkin70725502013-06-25 20:27:06 +000050import android.view.Surface;
51
Emilian Peevb9a51942018-03-14 17:18:49 +000052import com.android.internal.util.Preconditions;
53
Jianing Weid2c3a822014-03-27 18:27:43 -070054import java.util.AbstractMap.SimpleEntry;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070055import java.util.ArrayList;
Zhijun Hea7677722015-06-01 16:36:06 -070056import java.util.Collection;
Igor Murashkin1e854c52014-08-28 15:21:49 -070057import java.util.HashMap;
Igor Murashkin57ea59b2013-08-23 16:55:57 -070058import java.util.HashSet;
Ruben Brunkdecfe952013-10-29 11:00:32 -070059import java.util.Iterator;
Chien-Yu Chen5398a672015-03-19 14:48:43 -070060import java.util.LinkedList;
Shuzhen Wang23d29382017-11-26 17:24:56 -080061import java.util.List;
Emilian Peev2100ae72018-01-12 16:56:25 +000062import java.util.Set;
Chien-Yu Chen5398a672015-03-19 14:48:43 -070063import java.util.TreeMap;
Shuzhen Wang23d29382017-11-26 17:24:56 -080064import java.util.concurrent.atomic.AtomicBoolean;
Emilian Peev77ca8662018-03-14 17:12:13 +000065import java.util.concurrent.Executor;
Igor Murashkin70725502013-06-25 20:27:06 +000066
Emilian Peev9a0ec8c2018-02-28 14:53:30 +000067
Igor Murashkin70725502013-06-25 20:27:06 +000068/**
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070069 * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
Igor Murashkin70725502013-06-25 20:27:06 +000070 */
Shuzhen Wang78392932016-03-04 15:26:01 -080071public class CameraDeviceImpl extends CameraDevice
72 implements IBinder.DeathRecipient {
Igor Murashkin70725502013-06-25 20:27:06 +000073 private final String TAG;
Eino-Ville Talvalaa78791f2015-06-01 12:39:54 -070074 private final boolean DEBUG = false;
Igor Murashkin70725502013-06-25 20:27:06 +000075
Ruben Brunkdecfe952013-10-29 11:00:32 -070076 private static final int REQUEST_ID_NONE = -1;
77
Igor Murashkin70725502013-06-25 20:27:06 +000078 // TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -080079 private ICameraDeviceUserWrapper mRemoteDevice;
Igor Murashkin70725502013-06-25 20:27:06 +000080
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -070081 // Lock to synchronize cross-thread access to device public interface
Igor Murashkin51dcfd652014-09-25 16:55:01 -070082 final Object mInterfaceLock = new Object(); // access from this class and Session only!
Igor Murashkin70725502013-06-25 20:27:06 +000083 private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
84
Eino-Ville Talvalafd887432014-09-04 13:07:40 -070085 private final StateCallback mDeviceCallback;
86 private volatile StateCallbackKK mSessionStateCallback;
Emilian Peev9a0ec8c2018-02-28 14:53:30 +000087 private final Executor mDeviceExecutor;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070088
Ruben Brunk0953b642015-06-11 16:12:35 -070089 private final AtomicBoolean mClosing = new AtomicBoolean();
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -070090 private boolean mInError = false;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -070091 private boolean mIdle = true;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -070092
Eino-Ville Talvalafd887432014-09-04 13:07:40 -070093 /** map request IDs to callback/request data */
94 private final SparseArray<CaptureCallbackHolder> mCaptureCallbackMap =
95 new SparseArray<CaptureCallbackHolder>();
Igor Murashkin70725502013-06-25 20:27:06 +000096
Ruben Brunkdecfe952013-10-29 11:00:32 -070097 private int mRepeatingRequestId = REQUEST_ID_NONE;
Shuzhen Wangb45449b2019-04-17 13:32:03 -070098 // Latest repeating request list's types
99 private int[] mRepeatingRequestTypes;
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700100 // Map stream IDs to input/output configurations
101 private SimpleEntry<Integer, InputConfiguration> mConfiguredInput =
102 new SimpleEntry<>(REQUEST_ID_NONE, null);
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700103 private final SparseArray<OutputConfiguration> mConfiguredOutputs =
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700104 new SparseArray<>();
Igor Murashkin70725502013-06-25 20:27:06 +0000105
106 private final String mCameraId;
Ruben Brunk57493682014-05-27 18:58:08 -0700107 private final CameraCharacteristics mCharacteristics;
Zhijun He83159152014-07-16 11:32:59 -0700108 private final int mTotalPartialCount;
Igor Murashkin70725502013-06-25 20:27:06 +0000109
Shuzhen Wangae10eb92017-03-01 12:58:04 -0800110 private static final long NANO_PER_SECOND = 1000000000; //ns
111
Jianing Weid2c3a822014-03-27 18:27:43 -0700112 /**
Shuzhen Wangb45449b2019-04-17 13:32:03 -0700113 * A list tracking request and its expected last regular/reprocess/zslStill frame
Chien-Yu Chen4560df72015-04-27 17:21:31 -0700114 * number. Updated when calling ICameraDeviceUser methods.
Jianing Weid2c3a822014-03-27 18:27:43 -0700115 */
Chien-Yu Chen4560df72015-04-27 17:21:31 -0700116 private final List<RequestLastFrameNumbersHolder> mRequestLastFrameNumbersList =
117 new ArrayList<>();
Jianing Weid2c3a822014-03-27 18:27:43 -0700118
119 /**
120 * An object tracking received frame numbers.
121 * Updated when receiving callbacks from ICameraDeviceCallbacks.
122 */
123 private final FrameNumberTracker mFrameNumberTracker = new FrameNumberTracker();
124
Eino-Ville Talvala639fffe2015-06-30 10:34:48 -0700125 private CameraCaptureSessionCore mCurrentSession;
Eino-Ville Talvala95037852014-09-14 14:07:05 -0700126 private int mNextSessionId = 0;
Igor Murashkin0b27d342014-05-30 09:45:05 -0700127
Chien-Yu Chen3d2b5fe2017-04-05 16:42:31 -0700128 private final int mAppTargetSdkVersion;
129
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700130 // Runnables for all state transitions, except error, which needs the
131 // error code argument
132
133 private final Runnable mCallOnOpened = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700134 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700135 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700136 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700137 synchronized(mInterfaceLock) {
138 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700139
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700140 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700141 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700142 if (sessionCallback != null) {
143 sessionCallback.onOpened(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700144 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700145 mDeviceCallback.onOpened(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700146 }
147 };
148
149 private final Runnable mCallOnUnconfigured = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700150 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700151 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700152 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700153 synchronized(mInterfaceLock) {
154 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700155
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700156 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700157 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700158 if (sessionCallback != null) {
159 sessionCallback.onUnconfigured(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700160 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700161 }
162 };
163
164 private final Runnable mCallOnActive = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700165 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700166 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700167 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700168 synchronized(mInterfaceLock) {
169 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700170
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700171 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700172 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700173 if (sessionCallback != null) {
174 sessionCallback.onActive(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700175 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700176 }
177 };
178
179 private final Runnable mCallOnBusy = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700180 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700181 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700182 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700183 synchronized(mInterfaceLock) {
184 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700185
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700186 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700187 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700188 if (sessionCallback != null) {
189 sessionCallback.onBusy(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700190 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700191 }
192 };
193
194 private final Runnable mCallOnClosed = new Runnable() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700195 private boolean mClosedOnce = false;
196
Jianing Weid2c3a822014-03-27 18:27:43 -0700197 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700198 public void run() {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700199 if (mClosedOnce) {
200 throw new AssertionError("Don't post #onClosed more than once");
201 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700202 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700203 synchronized(mInterfaceLock) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700204 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700205 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700206 if (sessionCallback != null) {
207 sessionCallback.onClosed(CameraDeviceImpl.this);
Igor Murashkin0b27d342014-05-30 09:45:05 -0700208 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700209 mDeviceCallback.onClosed(CameraDeviceImpl.this);
Igor Murashkin49b2b132014-06-18 19:03:00 -0700210 mClosedOnce = true;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700211 }
212 };
213
214 private final Runnable mCallOnIdle = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700215 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700216 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700217 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700218 synchronized(mInterfaceLock) {
219 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700220
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700221 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700222 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700223 if (sessionCallback != null) {
224 sessionCallback.onIdle(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700225 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700226 }
227 };
228
229 private final Runnable mCallOnDisconnected = new Runnable() {
Jianing Weid2c3a822014-03-27 18:27:43 -0700230 @Override
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700231 public void run() {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700232 StateCallbackKK sessionCallback = null;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700233 synchronized(mInterfaceLock) {
234 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -0700235
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700236 sessionCallback = mSessionStateCallback;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700237 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700238 if (sessionCallback != null) {
239 sessionCallback.onDisconnected(CameraDeviceImpl.this);
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700240 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700241 mDeviceCallback.onDisconnected(CameraDeviceImpl.this);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700242 }
243 };
244
Emilian Peev9129aa22018-03-20 15:39:34 +0000245 public CameraDeviceImpl(String cameraId, StateCallback callback, Executor executor,
Chien-Yu Chen3d2b5fe2017-04-05 16:42:31 -0700246 CameraCharacteristics characteristics, int appTargetSdkVersion) {
Emilian Peev9129aa22018-03-20 15:39:34 +0000247 if (cameraId == null || callback == null || executor == null || characteristics == null) {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700248 throw new IllegalArgumentException("Null argument given");
249 }
Igor Murashkin70725502013-06-25 20:27:06 +0000250 mCameraId = cameraId;
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700251 mDeviceCallback = callback;
Emilian Peev9129aa22018-03-20 15:39:34 +0000252 mDeviceExecutor = executor;
Ruben Brunk57493682014-05-27 18:58:08 -0700253 mCharacteristics = characteristics;
Chien-Yu Chen3d2b5fe2017-04-05 16:42:31 -0700254 mAppTargetSdkVersion = appTargetSdkVersion;
Eino-Ville Talvalab72d1ef2014-04-28 13:21:18 -0700255
256 final int MAX_TAG_LEN = 23;
257 String tag = String.format("CameraDevice-JV-%s", mCameraId);
258 if (tag.length() > MAX_TAG_LEN) {
259 tag = tag.substring(0, MAX_TAG_LEN);
260 }
261 TAG = tag;
Zhijun He83159152014-07-16 11:32:59 -0700262
263 Integer partialCount =
264 mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT);
265 if (partialCount == null) {
266 // 1 means partial result is not supported.
267 mTotalPartialCount = 1;
268 } else {
269 mTotalPartialCount = partialCount;
270 }
Igor Murashkin70725502013-06-25 20:27:06 +0000271 }
272
273 public CameraDeviceCallbacks getCallbacks() {
274 return mCallbacks;
275 }
276
Shuzhen Wang78392932016-03-04 15:26:01 -0800277 /**
278 * Set remote device, which triggers initial onOpened/onUnconfigured callbacks
279 *
280 * <p>This function may post onDisconnected and throw CAMERA_DISCONNECTED if remoteDevice dies
281 * during setup.</p>
282 *
283 */
284 public void setRemoteDevice(ICameraDeviceUser remoteDevice) throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700285 synchronized(mInterfaceLock) {
286 // TODO: Move from decorator to direct binder-mediated exceptions
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700287 // If setRemoteFailure already called, do nothing
288 if (mInError) return;
289
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800290 mRemoteDevice = new ICameraDeviceUserWrapper(remoteDevice);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700291
Shuzhen Wang78392932016-03-04 15:26:01 -0800292 IBinder remoteDeviceBinder = remoteDevice.asBinder();
293 // For legacy camera device, remoteDevice is in the same process, and
294 // asBinder returns NULL.
295 if (remoteDeviceBinder != null) {
296 try {
297 remoteDeviceBinder.linkToDeath(this, /*flag*/ 0);
298 } catch (RemoteException e) {
Emilian Peev9a0ec8c2018-02-28 14:53:30 +0000299 CameraDeviceImpl.this.mDeviceExecutor.execute(mCallOnDisconnected);
Shuzhen Wang78392932016-03-04 15:26:01 -0800300
301 throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
302 "The camera device has encountered a serious error");
303 }
304 }
305
Emilian Peev9a0ec8c2018-02-28 14:53:30 +0000306 mDeviceExecutor.execute(mCallOnOpened);
307 mDeviceExecutor.execute(mCallOnUnconfigured);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700308 }
Igor Murashkin70725502013-06-25 20:27:06 +0000309 }
310
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700311 /**
312 * Call to indicate failed connection to a remote camera device.
313 *
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700314 * <p>This places the camera device in the error state and informs the callback.
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700315 * Use in place of setRemoteDevice() when startup fails.</p>
316 */
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800317 public void setRemoteFailure(final ServiceSpecificException failure) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700318 int failureCode = StateCallback.ERROR_CAMERA_DEVICE;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700319 boolean failureIsError = true;
320
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800321 switch (failure.errorCode) {
322 case ICameraService.ERROR_CAMERA_IN_USE:
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700323 failureCode = StateCallback.ERROR_CAMERA_IN_USE;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700324 break;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800325 case ICameraService.ERROR_MAX_CAMERAS_IN_USE:
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700326 failureCode = StateCallback.ERROR_MAX_CAMERAS_IN_USE;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700327 break;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800328 case ICameraService.ERROR_DISABLED:
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700329 failureCode = StateCallback.ERROR_CAMERA_DISABLED;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700330 break;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800331 case ICameraService.ERROR_DISCONNECTED:
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700332 failureIsError = false;
333 break;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800334 case ICameraService.ERROR_INVALID_OPERATION:
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700335 failureCode = StateCallback.ERROR_CAMERA_DEVICE;
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700336 break;
337 default:
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800338 Log.e(TAG, "Unexpected failure in opening camera device: " + failure.errorCode +
339 failure.getMessage());
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700340 break;
341 }
342 final int code = failureCode;
343 final boolean isError = failureIsError;
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700344 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700345 mInError = true;
Emilian Peev9a0ec8c2018-02-28 14:53:30 +0000346 mDeviceExecutor.execute(new Runnable() {
Igor Murashkine1442202014-06-09 17:51:24 -0700347 @Override
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700348 public void run() {
349 if (isError) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700350 mDeviceCallback.onError(CameraDeviceImpl.this, code);
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700351 } else {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700352 mDeviceCallback.onDisconnected(CameraDeviceImpl.this);
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700353 }
354 }
355 });
356 }
357 }
358
Igor Murashkin70725502013-06-25 20:27:06 +0000359 @Override
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -0700360 public String getId() {
361 return mCameraId;
362 }
363
Igor Murashkin70725502013-06-25 20:27:06 +0000364 public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700365 // Leave this here for backwards compatibility with older code using this directly
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700366 ArrayList<OutputConfiguration> outputConfigs = new ArrayList<>(outputs.size());
367 for (Surface s : outputs) {
368 outputConfigs.add(new OutputConfiguration(s));
369 }
Zhijun Hea7677722015-06-01 16:36:06 -0700370 configureStreamsChecked(/*inputConfig*/null, outputConfigs,
Emilian Peev75a55702017-11-07 16:09:59 +0000371 /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/ null);
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700372
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700373 }
374
375 /**
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700376 * Attempt to configure the input and outputs; the device goes to idle and then configures the
377 * new input and outputs if possible.
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700378 *
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700379 * <p>The configuration may gracefully fail, if input configuration is not supported,
380 * if there are too many outputs, if the formats are not supported, or if the sizes for that
381 * format is not supported. In this case this function will return {@code false} and the
382 * unconfigured callback will be fired.</p>
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700383 *
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700384 * <p>If the configuration succeeds (with 1 or more outputs with or without an input),
385 * then the idle callback is fired. Unconfiguring the device always fires the idle callback.</p>
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700386 *
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700387 * @param inputConfig input configuration or {@code null} for no input
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700388 * @param outputs a list of one or more surfaces, or {@code null} to unconfigure
Eino-Ville Talvala0e04e912017-02-28 17:49:41 -0800389 * @param operatingMode If the stream configuration is for a normal session,
390 * a constrained high speed session, or something else.
Emilian Peev75a55702017-11-07 16:09:59 +0000391 * @param sessionParams Session parameters.
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700392 * @return whether or not the configuration was successful
393 *
394 * @throws CameraAccessException if there were any unexpected problems during configuration
395 */
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700396 public boolean configureStreamsChecked(InputConfiguration inputConfig,
Emilian Peev75a55702017-11-07 16:09:59 +0000397 List<OutputConfiguration> outputs, int operatingMode, CaptureRequest sessionParams)
Zhijun Hea7677722015-06-01 16:36:06 -0700398 throws CameraAccessException {
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700399 // Treat a null input the same an empty list
400 if (outputs == null) {
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700401 outputs = new ArrayList<OutputConfiguration>();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700402 }
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700403 if (outputs.size() == 0 && inputConfig != null) {
404 throw new IllegalArgumentException("cannot configure an input stream without " +
405 "any output streams");
406 }
407
408 checkInputConfiguration(inputConfig);
409
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700410 boolean success = false;
411
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700412 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700413 checkIfCameraClosedOrInError();
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700414 // Streams to create
415 HashSet<OutputConfiguration> addSet = new HashSet<OutputConfiguration>(outputs);
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700416 // Streams to delete
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700417 List<Integer> deleteList = new ArrayList<Integer>();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700418
419 // Determine which streams need to be created, which to be deleted
420 for (int i = 0; i < mConfiguredOutputs.size(); ++i) {
421 int streamId = mConfiguredOutputs.keyAt(i);
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700422 OutputConfiguration outConfig = mConfiguredOutputs.valueAt(i);
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700423
Zhijun Hec8b181e2016-05-30 14:54:39 -0700424 if (!outputs.contains(outConfig) || outConfig.isDeferredConfiguration()) {
425 // Always delete the deferred output configuration when the session
426 // is created, as the deferred output configuration doesn't have unique surface
427 // related identifies.
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700428 deleteList.add(streamId);
429 } else {
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700430 addSet.remove(outConfig); // Don't create a stream previously created
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700431 }
432 }
433
Emilian Peev9a0ec8c2018-02-28 14:53:30 +0000434 mDeviceExecutor.execute(mCallOnBusy);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700435 stopRepeating();
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700436
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700437 try {
Ruben Brunkdecfe952013-10-29 11:00:32 -0700438 waitUntilIdle();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700439
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700440 mRemoteDevice.beginConfigure();
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700441
442 // reconfigure the input stream if the input configuration is different.
443 InputConfiguration currentInputConfig = mConfiguredInput.getValue();
444 if (inputConfig != currentInputConfig &&
445 (inputConfig == null || !inputConfig.equals(currentInputConfig))) {
446 if (currentInputConfig != null) {
447 mRemoteDevice.deleteStream(mConfiguredInput.getKey());
448 mConfiguredInput = new SimpleEntry<Integer, InputConfiguration>(
449 REQUEST_ID_NONE, null);
450 }
451 if (inputConfig != null) {
452 int streamId = mRemoteDevice.createInputStream(inputConfig.getWidth(),
453 inputConfig.getHeight(), inputConfig.getFormat());
454 mConfiguredInput = new SimpleEntry<Integer, InputConfiguration>(
455 streamId, inputConfig);
456 }
457 }
458
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700459 // Delete all streams first (to free up HW resources)
460 for (Integer streamId : deleteList) {
461 mRemoteDevice.deleteStream(streamId);
462 mConfiguredOutputs.delete(streamId);
463 }
464
465 // Add all new streams
Yin-Chia Yehbfbbee72015-03-12 13:39:26 -0700466 for (OutputConfiguration outConfig : outputs) {
467 if (addSet.contains(outConfig)) {
468 int streamId = mRemoteDevice.createStream(outConfig);
469 mConfiguredOutputs.put(streamId, outConfig);
470 }
Igor Murashkin70725502013-06-25 20:27:06 +0000471 }
Igor Murashkin57ea59b2013-08-23 16:55:57 -0700472
Emilian Peev75a55702017-11-07 16:09:59 +0000473 if (sessionParams != null) {
474 mRemoteDevice.endConfigure(operatingMode, sessionParams.getNativeCopy());
475 } else {
476 mRemoteDevice.endConfigure(operatingMode, null);
477 }
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700478
479 success = true;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800480 } catch (IllegalArgumentException e) {
481 // OK. camera service can reject stream config if it's not supported by HAL
482 // This is only the result of a programmer misusing the camera2 api.
483 Log.w(TAG, "Stream configuration failed due to: " + e.getMessage());
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700484 return false;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800485 } catch (CameraAccessException e) {
486 if (e.getReason() == CameraAccessException.CAMERA_IN_USE) {
487 throw new IllegalStateException("The camera is currently busy." +
488 " You must wait until the previous operation completes.", e);
489 }
490 throw e;
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700491 } finally {
492 if (success && outputs.size() > 0) {
Emilian Peev9a0ec8c2018-02-28 14:53:30 +0000493 mDeviceExecutor.execute(mCallOnIdle);
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700494 } else {
495 // Always return to the 'unconfigured' state if we didn't hit a fatal error
Emilian Peev9a0ec8c2018-02-28 14:53:30 +0000496 mDeviceExecutor.execute(mCallOnUnconfigured);
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700497 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -0700498 }
Igor Murashkin70725502013-06-25 20:27:06 +0000499 }
Igor Murashkin10fbbbb2014-08-19 16:19:30 -0700500
501 return success;
Igor Murashkin70725502013-06-25 20:27:06 +0000502 }
503
504 @Override
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700505 public void createCaptureSession(List<Surface> outputs,
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700506 CameraCaptureSession.StateCallback callback, Handler handler)
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700507 throws CameraAccessException {
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700508 List<OutputConfiguration> outConfigurations = new ArrayList<>(outputs.size());
509 for (Surface surface : outputs) {
510 outConfigurations.add(new OutputConfiguration(surface));
511 }
Emilian Peev77ca8662018-03-14 17:12:13 +0000512 createCaptureSessionInternal(null, outConfigurations, callback,
513 checkAndWrapHandler(handler), /*operatingMode*/ICameraDeviceUser.NORMAL_MODE,
514 /*sessionParams*/ null);
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700515 }
516
517 @Override
Zhijun He00347432016-04-07 17:34:10 -0700518 public void createCaptureSessionByOutputConfigurations(
Yin-Chia Yeh49ea6ae2015-03-09 16:53:14 -0700519 List<OutputConfiguration> outputConfigurations,
520 CameraCaptureSession.StateCallback callback, Handler handler)
521 throws CameraAccessException {
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700522 if (DEBUG) {
Shuzhen Wang9c663d42016-10-28 23:25:02 -0700523 Log.d(TAG, "createCaptureSessionByOutputConfigurations");
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700524 }
525
Eino-Ville Talvalafa5e2a12016-04-11 12:49:17 -0700526 // OutputConfiguration objects are immutable, but need to have our own array
527 List<OutputConfiguration> currentOutputs = new ArrayList<>(outputConfigurations);
Zhijun He445b3162016-01-18 15:34:28 -0800528
Emilian Peev77ca8662018-03-14 17:12:13 +0000529 createCaptureSessionInternal(null, currentOutputs, callback, checkAndWrapHandler(handler),
Emilian Peev75a55702017-11-07 16:09:59 +0000530 /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/null);
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700531 }
532
533 @Override
Chien-Yu Chen8062d312015-05-12 14:24:10 -0700534 public void createReprocessableCaptureSession(InputConfiguration inputConfig,
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700535 List<Surface> outputs, CameraCaptureSession.StateCallback callback, Handler handler)
536 throws CameraAccessException {
537 if (DEBUG) {
Chien-Yu Chen8062d312015-05-12 14:24:10 -0700538 Log.d(TAG, "createReprocessableCaptureSession");
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700539 }
540
541 if (inputConfig == null) {
542 throw new IllegalArgumentException("inputConfig cannot be null when creating a " +
Chien-Yu Chen8062d312015-05-12 14:24:10 -0700543 "reprocessable capture session");
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700544 }
545 List<OutputConfiguration> outConfigurations = new ArrayList<>(outputs.size());
546 for (Surface surface : outputs) {
547 outConfigurations.add(new OutputConfiguration(surface));
548 }
Emilian Peev77ca8662018-03-14 17:12:13 +0000549 createCaptureSessionInternal(inputConfig, outConfigurations, callback,
550 checkAndWrapHandler(handler), /*operatingMode*/ICameraDeviceUser.NORMAL_MODE,
551 /*sessionParams*/ null);
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700552 }
553
Eino-Ville Talvala639fffe2015-06-30 10:34:48 -0700554 @Override
Zhijun He00347432016-04-07 17:34:10 -0700555 public void createReprocessableCaptureSessionByConfigurations(InputConfiguration inputConfig,
Zhijun He445b3162016-01-18 15:34:28 -0800556 List<OutputConfiguration> outputs,
557 android.hardware.camera2.CameraCaptureSession.StateCallback callback, Handler handler)
558 throws CameraAccessException {
559 if (DEBUG) {
560 Log.d(TAG, "createReprocessableCaptureSessionWithConfigurations");
561 }
562
563 if (inputConfig == null) {
564 throw new IllegalArgumentException("inputConfig cannot be null when creating a " +
565 "reprocessable capture session");
566 }
567
568 if (outputs == null) {
569 throw new IllegalArgumentException("Output configurations cannot be null when " +
570 "creating a reprocessable capture session");
571 }
572
573 // OutputConfiguration objects aren't immutable, make a copy before using.
574 List<OutputConfiguration> currentOutputs = new ArrayList<OutputConfiguration>();
575 for (OutputConfiguration output : outputs) {
576 currentOutputs.add(new OutputConfiguration(output));
577 }
578 createCaptureSessionInternal(inputConfig, currentOutputs,
Emilian Peev77ca8662018-03-14 17:12:13 +0000579 callback, checkAndWrapHandler(handler),
580 /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/ null);
Zhijun He445b3162016-01-18 15:34:28 -0800581 }
582
583 @Override
Eino-Ville Talvala639fffe2015-06-30 10:34:48 -0700584 public void createConstrainedHighSpeedCaptureSession(List<Surface> outputs,
585 android.hardware.camera2.CameraCaptureSession.StateCallback callback, Handler handler)
586 throws CameraAccessException {
587 if (outputs == null || outputs.size() == 0 || outputs.size() > 2) {
588 throw new IllegalArgumentException(
589 "Output surface list must not be null and the size must be no more than 2");
590 }
Eino-Ville Talvala639fffe2015-06-30 10:34:48 -0700591 List<OutputConfiguration> outConfigurations = new ArrayList<>(outputs.size());
592 for (Surface surface : outputs) {
593 outConfigurations.add(new OutputConfiguration(surface));
594 }
Emilian Peev77ca8662018-03-14 17:12:13 +0000595 createCaptureSessionInternal(null, outConfigurations, callback,
596 checkAndWrapHandler(handler),
Emilian Peev75a55702017-11-07 16:09:59 +0000597 /*operatingMode*/ICameraDeviceUser.CONSTRAINED_HIGH_SPEED_MODE,
598 /*sessionParams*/ null);
Eino-Ville Talvala0e04e912017-02-28 17:49:41 -0800599 }
600
601 @Override
602 public void createCustomCaptureSession(InputConfiguration inputConfig,
603 List<OutputConfiguration> outputs,
604 int operatingMode,
605 android.hardware.camera2.CameraCaptureSession.StateCallback callback,
606 Handler handler) throws CameraAccessException {
607 List<OutputConfiguration> currentOutputs = new ArrayList<OutputConfiguration>();
608 for (OutputConfiguration output : outputs) {
609 currentOutputs.add(new OutputConfiguration(output));
610 }
Emilian Peev77ca8662018-03-14 17:12:13 +0000611 createCaptureSessionInternal(inputConfig, currentOutputs, callback,
612 checkAndWrapHandler(handler), operatingMode, /*sessionParams*/ null);
Emilian Peev75a55702017-11-07 16:09:59 +0000613 }
614
615 @Override
616 public void createCaptureSession(SessionConfiguration config)
617 throws CameraAccessException {
618 if (config == null) {
619 throw new IllegalArgumentException("Invalid session configuration");
620 }
621
622 List<OutputConfiguration> outputConfigs = config.getOutputConfigurations();
623 if (outputConfigs == null) {
624 throw new IllegalArgumentException("Invalid output configurations");
625 }
Emilian Peev77ca8662018-03-14 17:12:13 +0000626 if (config.getExecutor() == null) {
627 throw new IllegalArgumentException("Invalid executor");
628 }
Emilian Peev75a55702017-11-07 16:09:59 +0000629 createCaptureSessionInternal(config.getInputConfiguration(), outputConfigs,
Emilian Peev77ca8662018-03-14 17:12:13 +0000630 config.getStateCallback(), config.getExecutor(), config.getSessionType(),
Emilian Peev75a55702017-11-07 16:09:59 +0000631 config.getSessionParameters());
Eino-Ville Talvala639fffe2015-06-30 10:34:48 -0700632 }
633
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700634 private void createCaptureSessionInternal(InputConfiguration inputConfig,
635 List<OutputConfiguration> outputConfigurations,
Emilian Peev77ca8662018-03-14 17:12:13 +0000636 CameraCaptureSession.StateCallback callback, Executor executor,
Emilian Peev75a55702017-11-07 16:09:59 +0000637 int operatingMode, CaptureRequest sessionParams) throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700638 synchronized(mInterfaceLock) {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700639 if (DEBUG) {
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700640 Log.d(TAG, "createCaptureSessionInternal");
Igor Murashkin0b27d342014-05-30 09:45:05 -0700641 }
642
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700643 checkIfCameraClosedOrInError();
Igor Murashkin0b27d342014-05-30 09:45:05 -0700644
Eino-Ville Talvala0e04e912017-02-28 17:49:41 -0800645 boolean isConstrainedHighSpeed =
646 (operatingMode == ICameraDeviceUser.CONSTRAINED_HIGH_SPEED_MODE);
Zhijun Hea7677722015-06-01 16:36:06 -0700647 if (isConstrainedHighSpeed && inputConfig != null) {
648 throw new IllegalArgumentException("Constrained high speed session doesn't support"
649 + " input configuration yet.");
650 }
651
Eino-Ville Talvalad3b85f62014-08-05 15:02:31 -0700652 // Notify current session that it's going away, before starting camera operations
653 // After this call completes, the session is not allowed to call into CameraDeviceImpl
654 if (mCurrentSession != null) {
655 mCurrentSession.replaceSessionClose();
656 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700657
658 // TODO: dont block for this
659 boolean configureSuccess = true;
660 CameraAccessException pendingException = null;
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700661 Surface input = null;
Igor Murashkin0b27d342014-05-30 09:45:05 -0700662 try {
Chien-Yu Chenc58a6022015-06-16 11:13:48 -0700663 // configure streams and then block until IDLE
Zhijun Hea7677722015-06-01 16:36:06 -0700664 configureSuccess = configureStreamsChecked(inputConfig, outputConfigurations,
Emilian Peev75a55702017-11-07 16:09:59 +0000665 operatingMode, sessionParams);
Chien-Yu Chenc58a6022015-06-16 11:13:48 -0700666 if (configureSuccess == true && inputConfig != null) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800667 input = mRemoteDevice.getInputSurface();
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700668 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700669 } catch (CameraAccessException e) {
670 configureSuccess = false;
671 pendingException = e;
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700672 input = null;
Igor Murashkine1442202014-06-09 17:51:24 -0700673 if (DEBUG) {
674 Log.v(TAG, "createCaptureSession - failed with exception ", e);
675 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700676 }
677
678 // Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
Eino-Ville Talvala639fffe2015-06-30 10:34:48 -0700679 CameraCaptureSessionCore newSession = null;
680 if (isConstrainedHighSpeed) {
Emilian Peev75a55702017-11-07 16:09:59 +0000681 ArrayList<Surface> surfaces = new ArrayList<>(outputConfigurations.size());
682 for (OutputConfiguration outConfig : outputConfigurations) {
683 surfaces.add(outConfig.getSurface());
684 }
685 StreamConfigurationMap config =
686 getCharacteristics().get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
687 SurfaceUtils.checkConstrainedHighSpeedSurfaces(surfaces, /*fpsRange*/null, config);
688
Eino-Ville Talvala639fffe2015-06-30 10:34:48 -0700689 newSession = new CameraConstrainedHighSpeedCaptureSessionImpl(mNextSessionId++,
Emilian Peev9a0ec8c2018-02-28 14:53:30 +0000690 callback, executor, this, mDeviceExecutor, configureSuccess,
Eino-Ville Talvala639fffe2015-06-30 10:34:48 -0700691 mCharacteristics);
692 } else {
693 newSession = new CameraCaptureSessionImpl(mNextSessionId++, input,
Emilian Peev9a0ec8c2018-02-28 14:53:30 +0000694 callback, executor, this, mDeviceExecutor, configureSuccess);
Eino-Ville Talvala639fffe2015-06-30 10:34:48 -0700695 }
Igor Murashkin0b27d342014-05-30 09:45:05 -0700696
Igor Murashkin0b27d342014-05-30 09:45:05 -0700697 // TODO: wait until current session closes, then create the new session
698 mCurrentSession = newSession;
699
700 if (pendingException != null) {
701 throw pendingException;
702 }
703
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700704 mSessionStateCallback = mCurrentSession.getDeviceStateCallback();
Igor Murashkin0b27d342014-05-30 09:45:05 -0700705 }
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700706 }
707
Emilian Peev277de172018-11-06 16:15:59 +0000708 @Override
709 public boolean isSessionConfigurationSupported(
710 @NonNull SessionConfiguration sessionConfig) throws CameraAccessException,
711 UnsupportedOperationException, IllegalArgumentException {
712 synchronized(mInterfaceLock) {
713 checkIfCameraClosedOrInError();
714
715 return mRemoteDevice.isSessionConfigurationSupported(sessionConfig);
716 }
717 }
718
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700719 /**
720 * For use by backwards-compatibility code only.
721 */
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700722 public void setSessionListener(StateCallbackKK sessionCallback) {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700723 synchronized(mInterfaceLock) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700724 mSessionStateCallback = sessionCallback;
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -0700725 }
726 }
727
Chien-Yu Chen3d2b5fe2017-04-05 16:42:31 -0700728 private void overrideEnableZsl(CameraMetadataNative request, boolean newValue) {
729 Boolean enableZsl = request.get(CaptureRequest.CONTROL_ENABLE_ZSL);
730 if (enableZsl == null) {
731 // If enableZsl is not available, don't override.
732 return;
733 }
734
735 request.set(CaptureRequest.CONTROL_ENABLE_ZSL, newValue);
736 }
737
Eino-Ville Talvalacca00c62014-05-14 10:53:20 -0700738 @Override
Emilian Peev2100ae72018-01-12 16:56:25 +0000739 public CaptureRequest.Builder createCaptureRequest(int templateType,
740 Set<String> physicalCameraIdSet)
741 throws CameraAccessException {
742 synchronized(mInterfaceLock) {
743 checkIfCameraClosedOrInError();
744
745 for (String physicalId : physicalCameraIdSet) {
746 if (physicalId == getId()) {
747 throw new IllegalStateException("Physical id matches the logical id!");
748 }
749 }
750
751 CameraMetadataNative templatedRequest = null;
752
753 templatedRequest = mRemoteDevice.createDefaultRequest(templateType);
754
755 // If app target SDK is older than O, or it's not a still capture template, enableZsl
756 // must be false in the default request.
757 if (mAppTargetSdkVersion < Build.VERSION_CODES.O ||
758 templateType != TEMPLATE_STILL_CAPTURE) {
759 overrideEnableZsl(templatedRequest, false);
760 }
761
762 CaptureRequest.Builder builder = new CaptureRequest.Builder(
763 templatedRequest, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE,
764 getId(), physicalCameraIdSet);
765
766 return builder;
767 }
768 }
769
770 @Override
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700771 public CaptureRequest.Builder createCaptureRequest(int templateType)
772 throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -0700773 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -0700774 checkIfCameraClosedOrInError();
Igor Murashkin70725502013-06-25 20:27:06 +0000775
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800776 CameraMetadataNative templatedRequest = null;
Igor Murashkin70725502013-06-25 20:27:06 +0000777
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800778 templatedRequest = mRemoteDevice.createDefaultRequest(templateType);
Igor Murashkin70725502013-06-25 20:27:06 +0000779
Chien-Yu Chen3d2b5fe2017-04-05 16:42:31 -0700780 // If app target SDK is older than O, or it's not a still capture template, enableZsl
781 // must be false in the default request.
782 if (mAppTargetSdkVersion < Build.VERSION_CODES.O ||
783 templateType != TEMPLATE_STILL_CAPTURE) {
784 overrideEnableZsl(templatedRequest, false);
785 }
786
Chien-Yu Chen7a316f6b2015-04-13 14:31:45 -0700787 CaptureRequest.Builder builder = new CaptureRequest.Builder(
Emilian Peev2100ae72018-01-12 16:56:25 +0000788 templatedRequest, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE,
789 getId(), /*physicalCameraIdSet*/ null);
Igor Murashkin70725502013-06-25 20:27:06 +0000790
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700791 return builder;
Igor Murashkin70725502013-06-25 20:27:06 +0000792 }
793 }
794
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700795 @Override
796 public CaptureRequest.Builder createReprocessCaptureRequest(TotalCaptureResult inputResult)
797 throws CameraAccessException {
798 synchronized(mInterfaceLock) {
799 checkIfCameraClosedOrInError();
800
801 CameraMetadataNative resultMetadata = new
802 CameraMetadataNative(inputResult.getNativeCopy());
803
Chien-Yu Chen7a316f6b2015-04-13 14:31:45 -0700804 return new CaptureRequest.Builder(resultMetadata, /*reprocess*/true,
Emilian Peev2100ae72018-01-12 16:56:25 +0000805 inputResult.getSessionId(), getId(), /*physicalCameraIdSet*/ null);
Chien-Yu Chen5398a672015-03-19 14:48:43 -0700806 }
807 }
808
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -0700809 public void prepare(Surface surface) throws CameraAccessException {
Eino-Ville Talvala8b905572015-05-14 15:43:01 -0700810 if (surface == null) throw new IllegalArgumentException("Surface is null");
811
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -0700812 synchronized(mInterfaceLock) {
813 int streamId = -1;
814 for (int i = 0; i < mConfiguredOutputs.size(); i++) {
Shuzhen Wange0a66672017-03-21 12:05:14 -0700815 final List<Surface> surfaces = mConfiguredOutputs.valueAt(i).getSurfaces();
816 if (surfaces.contains(surface)) {
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -0700817 streamId = mConfiguredOutputs.keyAt(i);
818 break;
819 }
820 }
821 if (streamId == -1) {
822 throw new IllegalArgumentException("Surface is not part of this session");
823 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800824
825 mRemoteDevice.prepare(streamId);
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -0700826 }
827 }
828
Ruben Brunk7ed1aaa2015-08-13 17:57:14 -0700829 public void prepare(int maxCount, Surface surface) throws CameraAccessException {
830 if (surface == null) throw new IllegalArgumentException("Surface is null");
831 if (maxCount <= 0) throw new IllegalArgumentException("Invalid maxCount given: " +
832 maxCount);
833
834 synchronized(mInterfaceLock) {
835 int streamId = -1;
836 for (int i = 0; i < mConfiguredOutputs.size(); i++) {
837 if (surface == mConfiguredOutputs.valueAt(i).getSurface()) {
838 streamId = mConfiguredOutputs.keyAt(i);
839 break;
840 }
841 }
842 if (streamId == -1) {
843 throw new IllegalArgumentException("Surface is not part of this session");
844 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800845
846 mRemoteDevice.prepare2(maxCount, streamId);
Ruben Brunk7ed1aaa2015-08-13 17:57:14 -0700847 }
848 }
849
Emilian Peev03233152017-10-27 16:01:20 +0100850 public void updateOutputConfiguration(OutputConfiguration config)
851 throws CameraAccessException {
852 synchronized(mInterfaceLock) {
853 int streamId = -1;
854 for (int i = 0; i < mConfiguredOutputs.size(); i++) {
855 if (config.getSurface() == mConfiguredOutputs.valueAt(i).getSurface()) {
856 streamId = mConfiguredOutputs.keyAt(i);
857 break;
858 }
859 }
860 if (streamId == -1) {
861 throw new IllegalArgumentException("Invalid output configuration");
862 }
863
864 mRemoteDevice.updateOutputConfiguration(streamId, config);
Yin-Chia Yehc60af902017-11-10 20:02:29 -0800865 mConfiguredOutputs.put(streamId, config);
Emilian Peev03233152017-10-27 16:01:20 +0100866 }
867 }
868
Eino-Ville Talvala14c09fa2015-07-15 16:04:04 -0700869 public void tearDown(Surface surface) throws CameraAccessException {
870 if (surface == null) throw new IllegalArgumentException("Surface is null");
871
872 synchronized(mInterfaceLock) {
873 int streamId = -1;
874 for (int i = 0; i < mConfiguredOutputs.size(); i++) {
875 if (surface == mConfiguredOutputs.valueAt(i).getSurface()) {
876 streamId = mConfiguredOutputs.keyAt(i);
877 break;
878 }
879 }
880 if (streamId == -1) {
881 throw new IllegalArgumentException("Surface is not part of this session");
882 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800883
884 mRemoteDevice.tearDown(streamId);
Eino-Ville Talvala14c09fa2015-07-15 16:04:04 -0700885 }
886 }
887
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800888 public void finalizeOutputConfigs(List<OutputConfiguration> outputConfigs)
Zhijun Hec8b181e2016-05-30 14:54:39 -0700889 throws CameraAccessException {
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800890 if (outputConfigs == null || outputConfigs.size() == 0) {
Zhijun Hec8b181e2016-05-30 14:54:39 -0700891 throw new IllegalArgumentException("deferred config is null or empty");
892 }
893
894 synchronized(mInterfaceLock) {
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800895 for (OutputConfiguration config : outputConfigs) {
Zhijun Hec8b181e2016-05-30 14:54:39 -0700896 int streamId = -1;
897 for (int i = 0; i < mConfiguredOutputs.size(); i++) {
898 // Have to use equal here, as createCaptureSessionByOutputConfigurations() and
899 // createReprocessableCaptureSessionByConfigurations() do a copy of the configs.
900 if (config.equals(mConfiguredOutputs.valueAt(i))) {
901 streamId = mConfiguredOutputs.keyAt(i);
902 break;
903 }
904 }
905 if (streamId == -1) {
906 throw new IllegalArgumentException("Deferred config is not part of this "
907 + "session");
908 }
909
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800910 if (config.getSurfaces().size() == 0) {
911 throw new IllegalArgumentException("The final config for stream " + streamId
912 + " must have at least 1 surface");
Zhijun Hec8b181e2016-05-30 14:54:39 -0700913 }
Shuzhen Wang4bd7abe2017-01-11 09:58:58 -0800914 mRemoteDevice.finalizeOutputConfigurations(streamId, config);
Yin-Chia Yehc60af902017-11-10 20:02:29 -0800915 mConfiguredOutputs.put(streamId, config);
Zhijun Hec8b181e2016-05-30 14:54:39 -0700916 }
917 }
918 }
919
Emilian Peev9a0ec8c2018-02-28 14:53:30 +0000920 public int capture(CaptureRequest request, CaptureCallback callback, Executor executor)
Igor Murashkin70725502013-06-25 20:27:06 +0000921 throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -0700922 if (DEBUG) {
923 Log.d(TAG, "calling capture");
924 }
925 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
926 requestList.add(request);
Emilian Peev9a0ec8c2018-02-28 14:53:30 +0000927 return submitCaptureRequest(requestList, callback, executor, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000928 }
929
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700930 public int captureBurst(List<CaptureRequest> requests, CaptureCallback callback,
Emilian Peev9a0ec8c2018-02-28 14:53:30 +0000931 Executor executor) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -0700932 if (requests == null || requests.isEmpty()) {
933 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -0700934 }
Emilian Peev9a0ec8c2018-02-28 14:53:30 +0000935 return submitCaptureRequest(requests, callback, executor, /*streaming*/false);
Igor Murashkin70725502013-06-25 20:27:06 +0000936 }
937
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700938 /**
939 * This method checks lastFrameNumber returned from ICameraDeviceUser methods for
940 * starting and stopping repeating request and flushing.
941 *
942 * <p>If lastFrameNumber is NO_FRAMES_CAPTURED, it means that the request was never
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700943 * sent to HAL. Then onCaptureSequenceAborted is immediately triggered.
Chien-Yu Chen4560df72015-04-27 17:21:31 -0700944 * If lastFrameNumber is non-negative, then the requestId and lastFrameNumber as the last
945 * regular frame number will be added to the list mRequestLastFrameNumbersList.</p>
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700946 *
947 * @param requestId the request ID of the current repeating request.
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700948 * @param lastFrameNumber last frame number returned from binder.
Shuzhen Wangb45449b2019-04-17 13:32:03 -0700949 * @param repeatingRequestTypes the repeating requests' types.
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700950 */
951 private void checkEarlyTriggerSequenceComplete(
Shuzhen Wangb45449b2019-04-17 13:32:03 -0700952 final int requestId, final long lastFrameNumber,
953 final int[] repeatingRequestTypes) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700954 // lastFrameNumber being equal to NO_FRAMES_CAPTURED means that the request
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700955 // was never sent to HAL. Should trigger onCaptureSequenceAborted immediately.
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700956 if (lastFrameNumber == CaptureCallback.NO_FRAMES_CAPTURED) {
957 final CaptureCallbackHolder holder;
958 int index = mCaptureCallbackMap.indexOfKey(requestId);
959 holder = (index >= 0) ? mCaptureCallbackMap.valueAt(index) : null;
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700960 if (holder != null) {
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700961 mCaptureCallbackMap.removeAt(index);
Jianing Weibaf0c652014-04-18 17:35:00 -0700962 if (DEBUG) {
963 Log.v(TAG, String.format(
964 "remove holder for requestId %d, "
965 + "because lastFrame is %d.",
966 requestId, lastFrameNumber));
967 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700968 }
969
970 if (holder != null) {
971 if (DEBUG) {
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700972 Log.v(TAG, "immediately trigger onCaptureSequenceAborted because"
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700973 + " request did not reach HAL");
974 }
975
976 Runnable resultDispatch = new Runnable() {
977 @Override
978 public void run() {
Igor Murashkin21547d62014-06-04 15:21:42 -0700979 if (!CameraDeviceImpl.this.isClosed()) {
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700980 if (DEBUG) {
981 Log.d(TAG, String.format(
982 "early trigger sequence complete for request %d",
983 requestId));
984 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700985 holder.getCallback().onCaptureSequenceAborted(
Igor Murashkin21547d62014-06-04 15:21:42 -0700986 CameraDeviceImpl.this,
Eino-Ville Talvalaee37e302014-06-10 15:24:26 -0700987 requestId);
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700988 }
989 }
990 };
Emilian Peev77ca8662018-03-14 17:12:13 +0000991 final long ident = Binder.clearCallingIdentity();
992 try {
993 holder.getExecutor().execute(resultDispatch);
994 } finally {
995 Binder.restoreCallingIdentity(ident);
996 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -0700997 } else {
998 Log.w(TAG, String.format(
Eino-Ville Talvalafd887432014-09-04 13:07:40 -0700999 "did not register callback to request %d",
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001000 requestId));
1001 }
1002 } else {
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001003 // This function is only called for regular/ZslStill request so lastFrameNumber is the
1004 // last regular/ZslStill frame number.
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001005 mRequestLastFrameNumbersList.add(new RequestLastFrameNumbersHolder(requestId,
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001006 lastFrameNumber, repeatingRequestTypes));
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001007
Eino-Ville Talvala848fe732014-09-15 16:24:08 -07001008 // It is possible that the last frame has already arrived, so we need to check
1009 // for sequence completion right away
1010 checkAndFireSequenceComplete();
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001011 }
1012 }
1013
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001014 private int[] getRequestTypes(final CaptureRequest[] requestArray) {
1015 int[] requestTypes = new int[requestArray.length];
1016 for (int i = 0; i < requestArray.length; i++) {
1017 requestTypes[i] = requestArray[i].getRequestType();
1018 }
1019 return requestTypes;
1020 }
1021
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001022 private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureCallback callback,
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001023 Executor executor, boolean repeating) throws CameraAccessException {
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -07001024
Emilian Peev77ca8662018-03-14 17:12:13 +00001025 // Need a valid executor, or current thread needs to have a looper, if
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001026 // callback is valid
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001027 executor = checkExecutor(executor, callback);
Igor Murashkin70725502013-06-25 20:27:06 +00001028
Yin-Chia Yeh3b93a852019-09-09 14:59:59 -07001029 synchronized(mInterfaceLock) {
1030 checkIfCameraClosedOrInError();
Ruben Brunk7f2372b2014-07-02 11:05:08 -07001031
Yin-Chia Yeh3b93a852019-09-09 14:59:59 -07001032 // Make sure that there all requests have at least 1 surface; all surfaces are non-null;
1033 // the surface isn't a physical stream surface for reprocessing request
1034 for (CaptureRequest request : requestList) {
1035 if (request.getTargets().isEmpty()) {
1036 throw new IllegalArgumentException(
1037 "Each request must have at least one Surface target");
Ruben Brunk7f2372b2014-07-02 11:05:08 -07001038 }
Shuzhen Wang23d29382017-11-26 17:24:56 -08001039
Yin-Chia Yeh3b93a852019-09-09 14:59:59 -07001040 for (Surface surface : request.getTargets()) {
1041 if (surface == null) {
1042 throw new IllegalArgumentException("Null Surface targets are not allowed");
1043 }
1044
1045 for (int i = 0; i < mConfiguredOutputs.size(); i++) {
1046 OutputConfiguration configuration = mConfiguredOutputs.valueAt(i);
1047 if (configuration.isForPhysicalCamera()
1048 && configuration.getSurfaces().contains(surface)) {
1049 if (request.isReprocess()) {
1050 throw new IllegalArgumentException(
1051 "Reprocess request on physical stream is not allowed");
1052 }
Shuzhen Wang0960fb42018-01-10 20:35:11 -08001053 }
Shuzhen Wang23d29382017-11-26 17:24:56 -08001054 }
1055 }
Ruben Brunk7f2372b2014-07-02 11:05:08 -07001056 }
Ruben Brunk7f2372b2014-07-02 11:05:08 -07001057
Ruben Brunke73b41b2013-11-07 19:30:43 -08001058 if (repeating) {
1059 stopRepeating();
1060 }
1061
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001062 SubmitInfo requestInfo;
1063
1064 CaptureRequest[] requestArray = requestList.toArray(new CaptureRequest[requestList.size()]);
Yin-Chia Yehc60af902017-11-10 20:02:29 -08001065 // Convert Surface to streamIdx and surfaceIdx
1066 for (CaptureRequest request : requestArray) {
1067 request.convertSurfaceToStreamId(mConfiguredOutputs);
1068 }
1069
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001070 requestInfo = mRemoteDevice.submitRequestList(requestArray, repeating);
1071 if (DEBUG) {
1072 Log.v(TAG, "last frame number " + requestInfo.getLastFrameNumber());
Igor Murashkin70725502013-06-25 20:27:06 +00001073 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001074
Yin-Chia Yehc60af902017-11-10 20:02:29 -08001075 for (CaptureRequest request : requestArray) {
1076 request.recoverStreamIdToSurface();
1077 }
1078
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001079 if (callback != null) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001080 mCaptureCallbackMap.put(requestInfo.getRequestId(),
1081 new CaptureCallbackHolder(
Emilian Peev77ca8662018-03-14 17:12:13 +00001082 callback, requestList, executor, repeating, mNextSessionId - 1));
Jianing Weibaf0c652014-04-18 17:35:00 -07001083 } else {
1084 if (DEBUG) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001085 Log.d(TAG, "Listen for request " + requestInfo.getRequestId() + " is null");
Jianing Weibaf0c652014-04-18 17:35:00 -07001086 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -07001087 }
Igor Murashkin70725502013-06-25 20:27:06 +00001088
1089 if (repeating) {
Jianing Weid2c3a822014-03-27 18:27:43 -07001090 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001091 checkEarlyTriggerSequenceComplete(mRepeatingRequestId,
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001092 requestInfo.getLastFrameNumber(),
1093 mRepeatingRequestTypes);
Jianing Weid2c3a822014-03-27 18:27:43 -07001094 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001095 mRepeatingRequestId = requestInfo.getRequestId();
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001096 mRepeatingRequestTypes = getRequestTypes(requestArray);
Jianing Weid2c3a822014-03-27 18:27:43 -07001097 } else {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001098 mRequestLastFrameNumbersList.add(
1099 new RequestLastFrameNumbersHolder(requestList, requestInfo));
Igor Murashkin70725502013-06-25 20:27:06 +00001100 }
1101
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001102 if (mIdle) {
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001103 mDeviceExecutor.execute(mCallOnActive);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001104 }
1105 mIdle = false;
1106
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001107 return requestInfo.getRequestId();
Igor Murashkin70725502013-06-25 20:27:06 +00001108 }
1109 }
1110
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001111 public int setRepeatingRequest(CaptureRequest request, CaptureCallback callback,
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001112 Executor executor) throws CameraAccessException {
Jianing Weid2c3a822014-03-27 18:27:43 -07001113 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
1114 requestList.add(request);
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001115 return submitCaptureRequest(requestList, callback, executor, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +00001116 }
1117
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001118 public int setRepeatingBurst(List<CaptureRequest> requests, CaptureCallback callback,
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001119 Executor executor) throws CameraAccessException {
Igor Murashkin0b27d342014-05-30 09:45:05 -07001120 if (requests == null || requests.isEmpty()) {
1121 throw new IllegalArgumentException("At least one request must be given");
Zhijun Hefc19e2c2013-08-22 14:43:07 -07001122 }
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001123 return submitCaptureRequest(requests, callback, executor, /*streaming*/true);
Igor Murashkin70725502013-06-25 20:27:06 +00001124 }
1125
Igor Murashkin70725502013-06-25 20:27:06 +00001126 public void stopRepeating() throws CameraAccessException {
1127
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001128 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -07001129 checkIfCameraClosedOrInError();
Ruben Brunkdecfe952013-10-29 11:00:32 -07001130 if (mRepeatingRequestId != REQUEST_ID_NONE) {
1131
1132 int requestId = mRepeatingRequestId;
1133 mRepeatingRequestId = REQUEST_ID_NONE;
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001134 int[] requestTypes = mRepeatingRequestTypes;
1135 mRepeatingRequestTypes = null;
Ruben Brunkdecfe952013-10-29 11:00:32 -07001136
Chien-Yu Chen2da496f2016-04-14 13:33:00 -07001137 long lastFrameNumber;
1138 try {
1139 lastFrameNumber = mRemoteDevice.cancelRequest(requestId);
1140 } catch (IllegalArgumentException e) {
1141 if (DEBUG) {
1142 Log.v(TAG, "Repeating request was already stopped for request " + requestId);
1143 }
1144 // Repeating request was already stopped. Nothing more to do.
1145 return;
1146 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001147
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001148 checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber, requestTypes);
Igor Murashkin70725502013-06-25 20:27:06 +00001149 }
1150 }
1151 }
1152
Zhijun Hed842fcd2013-12-26 14:14:04 -08001153 private void waitUntilIdle() throws CameraAccessException {
Zhijun He7f4d3142013-07-23 07:54:38 -07001154
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001155 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -07001156 checkIfCameraClosedOrInError();
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001157
Ruben Brunkdecfe952013-10-29 11:00:32 -07001158 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Zhijun He7f4d3142013-07-23 07:54:38 -07001159 throw new IllegalStateException("Active repeating request ongoing");
1160 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001161
1162 mRemoteDevice.waitUntilIdle();
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001163 }
Igor Murashkin70725502013-06-25 20:27:06 +00001164 }
1165
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -07001166 public void flush() throws CameraAccessException {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001167 synchronized(mInterfaceLock) {
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -07001168 checkIfCameraClosedOrInError();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001169
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001170 mDeviceExecutor.execute(mCallOnBusy);
Eino-Ville Talvalac346bbf2014-08-27 17:05:29 -07001171
1172 // If already idle, just do a busy->idle transition immediately, don't actually
1173 // flush.
1174 if (mIdle) {
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001175 mDeviceExecutor.execute(mCallOnIdle);
Eino-Ville Talvalac346bbf2014-08-27 17:05:29 -07001176 return;
1177 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001178
1179 long lastFrameNumber = mRemoteDevice.flush();
1180 if (mRepeatingRequestId != REQUEST_ID_NONE) {
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001181 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber,
1182 mRepeatingRequestTypes);
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001183 mRepeatingRequestId = REQUEST_ID_NONE;
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001184 mRepeatingRequestTypes = null;
Eino-Ville Talvala8ebd52b2013-08-13 12:09:44 -07001185 }
1186 }
1187 }
1188
1189 @Override
Igor Murashkin5c9eaf62013-09-10 19:35:24 -07001190 public void close() {
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001191 synchronized (mInterfaceLock) {
Ruben Brunk0953b642015-06-11 16:12:35 -07001192 if (mClosing.getAndSet(true)) {
1193 return;
1194 }
1195
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001196 if (mRemoteDevice != null) {
1197 mRemoteDevice.disconnect();
Eino-Ville Talvalaee46b582016-04-04 12:26:40 -07001198 mRemoteDevice.unlinkToDeath(this, /*flags*/0);
Igor Murashkin70725502013-06-25 20:27:06 +00001199 }
1200
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -07001201 // Only want to fire the onClosed callback once;
1202 // either a normal close where the remote device is valid
1203 // or a close after a startup error (no remote device but in error state)
1204 if (mRemoteDevice != null || mInError) {
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001205 mDeviceExecutor.execute(mCallOnClosed);
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001206 }
Igor Murashkin70725502013-06-25 20:27:06 +00001207
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001208 mRemoteDevice = null;
Igor Murashkin70725502013-06-25 20:27:06 +00001209 }
1210 }
1211
1212 @Override
1213 protected void finalize() throws Throwable {
1214 try {
1215 close();
Igor Murashkin70725502013-06-25 20:27:06 +00001216 }
1217 finally {
1218 super.finalize();
1219 }
1220 }
1221
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001222 private void checkInputConfiguration(InputConfiguration inputConfig) {
1223 if (inputConfig != null) {
1224 StreamConfigurationMap configMap = mCharacteristics.get(
1225 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
1226
1227 int[] inputFormats = configMap.getInputFormats();
1228 boolean validFormat = false;
1229 for (int format : inputFormats) {
1230 if (format == inputConfig.getFormat()) {
1231 validFormat = true;
1232 }
1233 }
1234
1235 if (validFormat == false) {
1236 throw new IllegalArgumentException("input format " + inputConfig.getFormat() +
1237 " is not valid");
1238 }
1239
1240 boolean validSize = false;
1241 Size[] inputSizes = configMap.getInputSizes(inputConfig.getFormat());
1242 for (Size s : inputSizes) {
1243 if (inputConfig.getWidth() == s.getWidth() &&
1244 inputConfig.getHeight() == s.getHeight()) {
1245 validSize = true;
1246 }
1247 }
1248
1249 if (validSize == false) {
1250 throw new IllegalArgumentException("input size " + inputConfig.getWidth() + "x" +
1251 inputConfig.getHeight() + " is not valid");
1252 }
1253 }
1254 }
1255
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -07001256 /**
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001257 * <p>A callback for tracking the progress of a {@link CaptureRequest}
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -07001258 * submitted to the camera device.</p>
1259 *
Eino-Ville Talvalacad1bfe2017-05-23 14:10:49 -07001260 * An interface instead of an abstract class because this is internal and
1261 * we want to make sure we always implement all its callbacks until we reach
1262 * the public layer.
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -07001263 */
Eino-Ville Talvalacad1bfe2017-05-23 14:10:49 -07001264 public interface CaptureCallback {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -07001265
1266 /**
1267 * This constant is used to indicate that no images were captured for
1268 * the request.
1269 *
1270 * @hide
1271 */
1272 public static final int NO_FRAMES_CAPTURED = -1;
1273
1274 /**
1275 * This method is called when the camera device has started capturing
1276 * the output image for the request, at the beginning of image exposure.
1277 *
1278 * @see android.media.MediaActionSound
1279 */
1280 public void onCaptureStarted(CameraDevice camera,
Eino-Ville Talvalacad1bfe2017-05-23 14:10:49 -07001281 CaptureRequest request, long timestamp, long frameNumber);
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -07001282
1283 /**
1284 * This method is called when some results from an image capture are
1285 * available.
1286 *
1287 * @hide
1288 */
1289 public void onCapturePartial(CameraDevice camera,
Eino-Ville Talvalacad1bfe2017-05-23 14:10:49 -07001290 CaptureRequest request, CaptureResult result);
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -07001291
1292 /**
1293 * This method is called when an image capture makes partial forward progress; some
1294 * (but not all) results from an image capture are available.
1295 *
1296 */
1297 public void onCaptureProgressed(CameraDevice camera,
Eino-Ville Talvalacad1bfe2017-05-23 14:10:49 -07001298 CaptureRequest request, CaptureResult partialResult);
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -07001299
1300 /**
1301 * This method is called when an image capture has fully completed and all the
1302 * result metadata is available.
1303 */
1304 public void onCaptureCompleted(CameraDevice camera,
Eino-Ville Talvalacad1bfe2017-05-23 14:10:49 -07001305 CaptureRequest request, TotalCaptureResult result);
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -07001306
1307 /**
1308 * This method is called instead of {@link #onCaptureCompleted} when the
1309 * camera device failed to produce a {@link CaptureResult} for the
1310 * request.
1311 */
1312 public void onCaptureFailed(CameraDevice camera,
Eino-Ville Talvalacad1bfe2017-05-23 14:10:49 -07001313 CaptureRequest request, CaptureFailure failure);
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -07001314
1315 /**
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001316 * This method is called independently of the others in CaptureCallback,
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -07001317 * when a capture sequence finishes and all {@link CaptureResult}
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001318 * or {@link CaptureFailure} for it have been returned via this callback.
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -07001319 */
1320 public void onCaptureSequenceCompleted(CameraDevice camera,
Eino-Ville Talvalacad1bfe2017-05-23 14:10:49 -07001321 int sequenceId, long frameNumber);
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -07001322
1323 /**
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001324 * This method is called independently of the others in CaptureCallback,
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -07001325 * when a capture sequence aborts before any {@link CaptureResult}
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001326 * or {@link CaptureFailure} for it have been returned via this callback.
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -07001327 */
1328 public void onCaptureSequenceAborted(CameraDevice camera,
Eino-Ville Talvalacad1bfe2017-05-23 14:10:49 -07001329 int sequenceId);
Eino-Ville Talvala3e0023a2016-03-06 18:40:01 -08001330
Eino-Ville Talvalacad1bfe2017-05-23 14:10:49 -07001331 /**
1332 * This method is called independently of the others in CaptureCallback, if an output buffer
1333 * is dropped for a particular capture request.
1334 *
1335 * Loss of metadata is communicated via onCaptureFailed, independently of any buffer loss.
1336 */
Eino-Ville Talvala3e0023a2016-03-06 18:40:01 -08001337 public void onCaptureBufferLost(CameraDevice camera,
Eino-Ville Talvalacad1bfe2017-05-23 14:10:49 -07001338 CaptureRequest request, Surface target, long frameNumber);
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -07001339 }
1340
1341 /**
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001342 * A callback for notifications about the state of a camera device, adding in the callbacks that
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -07001343 * were part of the earlier KK API design, but now only used internally.
1344 */
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001345 public static abstract class StateCallbackKK extends StateCallback {
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -07001346 /**
1347 * The method called when a camera device has no outputs configured.
1348 *
1349 */
1350 public void onUnconfigured(CameraDevice camera) {
1351 // Default empty implementation
1352 }
1353
1354 /**
1355 * The method called when a camera device begins processing
1356 * {@link CaptureRequest capture requests}.
1357 *
1358 */
1359 public void onActive(CameraDevice camera) {
1360 // Default empty implementation
1361 }
1362
1363 /**
1364 * The method called when a camera device is busy.
1365 *
1366 */
1367 public void onBusy(CameraDevice camera) {
1368 // Default empty implementation
1369 }
1370
1371 /**
1372 * The method called when a camera device has finished processing all
1373 * submitted capture requests and has reached an idle state.
1374 *
1375 */
1376 public void onIdle(CameraDevice camera) {
1377 // Default empty implementation
1378 }
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -07001379
1380 /**
Shuzhen Wang88f1af22016-09-30 10:29:28 -07001381 * This method is called when camera device's non-repeating request queue is empty,
1382 * and is ready to start capturing next image.
1383 */
1384 public void onRequestQueueEmpty() {
1385 // Default empty implementation
1386 }
1387
1388 /**
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -07001389 * The method called when the camera device has finished preparing
1390 * an output Surface
1391 */
1392 public void onSurfacePrepared(Surface surface) {
1393 // Default empty implementation
1394 }
Eino-Ville Talvalaa6b5ba52014-07-02 16:30:53 -07001395 }
1396
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001397 static class CaptureCallbackHolder {
Igor Murashkin70725502013-06-25 20:27:06 +00001398
1399 private final boolean mRepeating;
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001400 private final CaptureCallback mCallback;
Jianing Weid2c3a822014-03-27 18:27:43 -07001401 private final List<CaptureRequest> mRequestList;
Emilian Peev77ca8662018-03-14 17:12:13 +00001402 private final Executor mExecutor;
Chien-Yu Chen7a316f6b2015-04-13 14:31:45 -07001403 private final int mSessionId;
Shuzhen Wangae10eb92017-03-01 12:58:04 -08001404 /**
1405 * <p>Determine if the callback holder is for a constrained high speed request list that
1406 * expects batched capture results. Capture results will be batched if the request list
1407 * is interleaved with preview and video requests. Capture results won't be batched if the
1408 * request list only contains preview requests, or if the request doesn't belong to a
1409 * constrained high speed list.
1410 */
1411 private final boolean mHasBatchedOutputs;
Igor Murashkin70725502013-06-25 20:27:06 +00001412
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001413 CaptureCallbackHolder(CaptureCallback callback, List<CaptureRequest> requestList,
Emilian Peev77ca8662018-03-14 17:12:13 +00001414 Executor executor, boolean repeating, int sessionId) {
1415 if (callback == null || executor == null) {
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -07001416 throw new UnsupportedOperationException(
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001417 "Must have a valid handler and a valid callback");
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -07001418 }
Igor Murashkin70725502013-06-25 20:27:06 +00001419 mRepeating = repeating;
Emilian Peev77ca8662018-03-14 17:12:13 +00001420 mExecutor = executor;
Jianing Weid2c3a822014-03-27 18:27:43 -07001421 mRequestList = new ArrayList<CaptureRequest>(requestList);
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001422 mCallback = callback;
Chien-Yu Chen7a316f6b2015-04-13 14:31:45 -07001423 mSessionId = sessionId;
Shuzhen Wangae10eb92017-03-01 12:58:04 -08001424
1425 // Check whether this callback holder is for batched outputs.
1426 // The logic here should match createHighSpeedRequestList.
1427 boolean hasBatchedOutputs = true;
1428 for (int i = 0; i < requestList.size(); i++) {
1429 CaptureRequest request = requestList.get(i);
1430 if (!request.isPartOfCRequestList()) {
1431 hasBatchedOutputs = false;
1432 break;
1433 }
1434 if (i == 0) {
1435 Collection<Surface> targets = request.getTargets();
1436 if (targets.size() != 2) {
1437 hasBatchedOutputs = false;
1438 break;
1439 }
1440 }
1441 }
1442 mHasBatchedOutputs = hasBatchedOutputs;
Igor Murashkin70725502013-06-25 20:27:06 +00001443 }
1444
1445 public boolean isRepeating() {
1446 return mRepeating;
1447 }
1448
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001449 public CaptureCallback getCallback() {
1450 return mCallback;
Igor Murashkin70725502013-06-25 20:27:06 +00001451 }
1452
Jianing Weid2c3a822014-03-27 18:27:43 -07001453 public CaptureRequest getRequest(int subsequenceId) {
1454 if (subsequenceId >= mRequestList.size()) {
1455 throw new IllegalArgumentException(
1456 String.format(
1457 "Requested subsequenceId %d is larger than request list size %d.",
1458 subsequenceId, mRequestList.size()));
1459 } else {
1460 if (subsequenceId < 0) {
1461 throw new IllegalArgumentException(String.format(
1462 "Requested subsequenceId %d is negative", subsequenceId));
1463 } else {
1464 return mRequestList.get(subsequenceId);
1465 }
1466 }
1467 }
1468
Igor Murashkin70725502013-06-25 20:27:06 +00001469 public CaptureRequest getRequest() {
Jianing Weid2c3a822014-03-27 18:27:43 -07001470 return getRequest(0);
Igor Murashkin70725502013-06-25 20:27:06 +00001471 }
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -07001472
Emilian Peev77ca8662018-03-14 17:12:13 +00001473 public Executor getExecutor() {
1474 return mExecutor;
Eino-Ville Talvala4af73c22013-08-14 10:35:46 -07001475 }
1476
Chien-Yu Chen7a316f6b2015-04-13 14:31:45 -07001477 public int getSessionId() {
1478 return mSessionId;
1479 }
Shuzhen Wangae10eb92017-03-01 12:58:04 -08001480
1481 public int getRequestCount() {
1482 return mRequestList.size();
1483 }
1484
1485 public boolean hasBatchedOutputs() {
1486 return mHasBatchedOutputs;
1487 }
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001488 }
Chien-Yu Chen7a316f6b2015-04-13 14:31:45 -07001489
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001490 /**
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001491 * This class holds a capture ID and its expected last regular, zslStill, and reprocess
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001492 * frame number.
1493 */
1494 static class RequestLastFrameNumbersHolder {
1495 // request ID
1496 private final int mRequestId;
1497 // The last regular frame number for this request ID. It's
1498 // CaptureCallback.NO_FRAMES_CAPTURED if the request ID has no regular request.
1499 private final long mLastRegularFrameNumber;
1500 // The last reprocess frame number for this request ID. It's
1501 // CaptureCallback.NO_FRAMES_CAPTURED if the request ID has no reprocess request.
1502 private final long mLastReprocessFrameNumber;
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001503 // The last ZSL still capture frame number for this request ID. It's
1504 // CaptureCallback.NO_FRAMES_CAPTURED if the request ID has no zsl request.
1505 private final long mLastZslStillFrameNumber;
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001506
1507 /**
1508 * Create a request-last-frame-numbers holder with a list of requests, request ID, and
1509 * the last frame number returned by camera service.
1510 */
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001511 public RequestLastFrameNumbersHolder(List<CaptureRequest> requestList, SubmitInfo requestInfo) {
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001512 long lastRegularFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
1513 long lastReprocessFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001514 long lastZslStillFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001515 long frameNumber = requestInfo.getLastFrameNumber();
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001516
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001517 if (requestInfo.getLastFrameNumber() < requestList.size() - 1) {
1518 throw new IllegalArgumentException(
1519 "lastFrameNumber: " + requestInfo.getLastFrameNumber() +
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001520 " should be at least " + (requestList.size() - 1) + " for the number of " +
1521 " requests in the list: " + requestList.size());
1522 }
1523
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001524 // find the last regular, zslStill, and reprocess frame number
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001525 for (int i = requestList.size() - 1; i >= 0; i--) {
1526 CaptureRequest request = requestList.get(i);
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001527 int requestType = request.getRequestType();
1528 if (requestType == CaptureRequest.REQUEST_TYPE_REPROCESS
1529 && lastReprocessFrameNumber == CaptureCallback.NO_FRAMES_CAPTURED) {
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001530 lastReprocessFrameNumber = frameNumber;
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001531 } else if (requestType == CaptureRequest.REQUEST_TYPE_ZSL_STILL
1532 && lastZslStillFrameNumber == CaptureCallback.NO_FRAMES_CAPTURED) {
1533 lastZslStillFrameNumber = frameNumber;
1534 } else if (requestType == CaptureRequest.REQUEST_TYPE_REGULAR
1535 && lastRegularFrameNumber == CaptureCallback.NO_FRAMES_CAPTURED) {
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001536 lastRegularFrameNumber = frameNumber;
1537 }
1538
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001539 if (lastReprocessFrameNumber != CaptureCallback.NO_FRAMES_CAPTURED
1540 && lastZslStillFrameNumber != CaptureCallback.NO_FRAMES_CAPTURED
1541 && lastRegularFrameNumber != CaptureCallback.NO_FRAMES_CAPTURED) {
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001542 break;
1543 }
1544
1545 frameNumber--;
1546 }
1547
1548 mLastRegularFrameNumber = lastRegularFrameNumber;
1549 mLastReprocessFrameNumber = lastReprocessFrameNumber;
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001550 mLastZslStillFrameNumber = lastZslStillFrameNumber;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -08001551 mRequestId = requestInfo.getRequestId();
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001552 }
1553
1554 /**
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001555 * Create a request-last-frame-numbers holder with a request ID and last regular/ZslStill
1556 * frame number.
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001557 */
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001558 RequestLastFrameNumbersHolder(int requestId, long lastFrameNumber,
1559 int[] repeatingRequestTypes) {
1560 long lastRegularFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
1561 long lastZslStillFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
1562
1563 if (repeatingRequestTypes == null) {
1564 throw new IllegalArgumentException(
1565 "repeatingRequest list must not be null");
1566 }
1567 if (lastFrameNumber < repeatingRequestTypes.length - 1) {
1568 throw new IllegalArgumentException(
1569 "lastFrameNumber: " + lastFrameNumber + " should be at least "
1570 + (repeatingRequestTypes.length - 1)
1571 + " for the number of requests in the list: "
1572 + repeatingRequestTypes.length);
1573 }
1574
1575 long frameNumber = lastFrameNumber;
1576 for (int i = repeatingRequestTypes.length - 1; i >= 0; i--) {
1577 if (repeatingRequestTypes[i] == CaptureRequest.REQUEST_TYPE_ZSL_STILL
1578 && lastZslStillFrameNumber == CaptureCallback.NO_FRAMES_CAPTURED) {
1579 lastZslStillFrameNumber = frameNumber;
1580 } else if (repeatingRequestTypes[i] == CaptureRequest.REQUEST_TYPE_REGULAR
1581 && lastRegularFrameNumber == CaptureCallback.NO_FRAMES_CAPTURED) {
1582 lastRegularFrameNumber = frameNumber;
1583 }
1584
1585 if (lastZslStillFrameNumber != CaptureCallback.NO_FRAMES_CAPTURED
1586 && lastRegularFrameNumber != CaptureCallback.NO_FRAMES_CAPTURED) {
1587 break;
1588 }
1589
1590 frameNumber--;
1591 }
1592
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001593 mLastRegularFrameNumber = lastRegularFrameNumber;
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001594 mLastZslStillFrameNumber = lastZslStillFrameNumber;
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001595 mLastReprocessFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
1596 mRequestId = requestId;
1597 }
1598
1599 /**
1600 * Return the last regular frame number. Return CaptureCallback.NO_FRAMES_CAPTURED if
1601 * it contains no regular request.
1602 */
1603 public long getLastRegularFrameNumber() {
1604 return mLastRegularFrameNumber;
1605 }
1606
1607 /**
1608 * Return the last reprocess frame number. Return CaptureCallback.NO_FRAMES_CAPTURED if
1609 * it contains no reprocess request.
1610 */
1611 public long getLastReprocessFrameNumber() {
1612 return mLastReprocessFrameNumber;
1613 }
1614
1615 /**
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001616 * Return the last ZslStill frame number. Return CaptureCallback.NO_FRAMES_CAPTURED if
1617 * it contains no Zsl request.
1618 */
1619 public long getLastZslStillFrameNumber() {
1620 return mLastZslStillFrameNumber;
1621 }
1622
1623 /**
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001624 * Return the last frame number overall.
1625 */
1626 public long getLastFrameNumber() {
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001627 return Math.max(mLastZslStillFrameNumber,
1628 Math.max(mLastRegularFrameNumber, mLastReprocessFrameNumber));
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001629 }
1630
1631 /**
1632 * Return the request ID.
1633 */
1634 public int getRequestId() {
1635 return mRequestId;
1636 }
Igor Murashkin70725502013-06-25 20:27:06 +00001637 }
1638
Jianing Weid2c3a822014-03-27 18:27:43 -07001639 /**
1640 * This class tracks the last frame number for submitted requests.
1641 */
1642 public class FrameNumberTracker {
1643
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001644 /** the completed frame number for each type of capture results */
1645 private long[] mCompletedFrameNumber = new long[CaptureRequest.REQUEST_TYPE_COUNT];
1646
1647 /** the skipped frame numbers that don't belong to each type of capture results */
1648 private final LinkedList<Long>[] mSkippedOtherFrameNumbers =
1649 new LinkedList[CaptureRequest.REQUEST_TYPE_COUNT];
1650
1651 /** the skipped frame numbers that belong to each type of capture results */
1652 private final LinkedList<Long>[] mSkippedFrameNumbers =
1653 new LinkedList[CaptureRequest.REQUEST_TYPE_COUNT];
1654
1655 /** frame number -> request type */
1656 private final TreeMap<Long, Integer> mFutureErrorMap = new TreeMap<Long, Integer>();
Igor Murashkin1e854c52014-08-28 15:21:49 -07001657 /** Map frame numbers to list of partial results */
1658 private final HashMap<Long, List<CaptureResult>> mPartialResults = new HashMap<>();
Jianing Weid2c3a822014-03-27 18:27:43 -07001659
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001660 public FrameNumberTracker() {
1661 for (int i = 0; i < CaptureRequest.REQUEST_TYPE_COUNT; i++) {
1662 mCompletedFrameNumber[i] = CaptureCallback.NO_FRAMES_CAPTURED;
1663 mSkippedOtherFrameNumbers[i] = new LinkedList<Long>();
1664 mSkippedFrameNumbers[i] = new LinkedList<Long>();
1665 }
1666 }
1667
Jianing Weid2c3a822014-03-27 18:27:43 -07001668 private void update() {
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001669 Iterator iter = mFutureErrorMap.entrySet().iterator();
Jianing Weid2c3a822014-03-27 18:27:43 -07001670 while (iter.hasNext()) {
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001671 TreeMap.Entry pair = (TreeMap.Entry)iter.next();
1672 Long errorFrameNumber = (Long)pair.getKey();
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001673 int requestType = (int) pair.getValue();
1674 Boolean removeError = false;
1675 if (errorFrameNumber == mCompletedFrameNumber[requestType] + 1) {
1676 mCompletedFrameNumber[requestType] = errorFrameNumber;
1677 removeError = true;
Jianing Weid2c3a822014-03-27 18:27:43 -07001678 } else {
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001679 if (!mSkippedFrameNumbers[requestType].isEmpty()) {
1680 if (errorFrameNumber == mSkippedFrameNumbers[requestType].element()) {
1681 mCompletedFrameNumber[requestType] = errorFrameNumber;
1682 mSkippedFrameNumbers[requestType].remove();
1683 removeError = true;
1684 }
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001685 } else {
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001686 for (int i = 1; i < CaptureRequest.REQUEST_TYPE_COUNT; i++) {
1687 int otherType = (requestType + i) % CaptureRequest.REQUEST_TYPE_COUNT;
1688 if (!mSkippedOtherFrameNumbers[otherType].isEmpty() && errorFrameNumber
1689 == mSkippedOtherFrameNumbers[otherType].element()) {
1690 mCompletedFrameNumber[requestType] = errorFrameNumber;
1691 mSkippedOtherFrameNumbers[otherType].remove();
1692 removeError = true;
1693 break;
1694 }
1695 }
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001696 }
1697 }
1698 if (removeError) {
1699 iter.remove();
Jianing Weid2c3a822014-03-27 18:27:43 -07001700 }
1701 }
1702 }
1703
1704 /**
1705 * This function is called every time when a result or an error is received.
Igor Murashkin1e854c52014-08-28 15:21:49 -07001706 * @param frameNumber the frame number corresponding to the result or error
1707 * @param isError true if it is an error, false if it is not an error
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001708 * @param requestType the type of capture request: Reprocess, ZslStill, or Regular.
Jianing Weid2c3a822014-03-27 18:27:43 -07001709 */
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001710 public void updateTracker(long frameNumber, boolean isError, int requestType) {
Jianing Weid2c3a822014-03-27 18:27:43 -07001711 if (isError) {
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001712 mFutureErrorMap.put(frameNumber, requestType);
Jianing Weid2c3a822014-03-27 18:27:43 -07001713 } else {
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001714 try {
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001715 updateCompletedFrameNumber(frameNumber, requestType);
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001716 } catch (IllegalArgumentException e) {
1717 Log.e(TAG, e.getMessage());
Jianing Weid2c3a822014-03-27 18:27:43 -07001718 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001719 }
1720 update();
1721 }
1722
Igor Murashkin1e854c52014-08-28 15:21:49 -07001723 /**
1724 * This function is called every time a result has been completed.
1725 *
1726 * <p>It keeps a track of all the partial results already created for a particular
1727 * frame number.</p>
1728 *
1729 * @param frameNumber the frame number corresponding to the result
1730 * @param result the total or partial result
1731 * @param partial {@true} if the result is partial, {@code false} if total
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001732 * @param requestType the type of capture request: Reprocess, ZslStill, or Regular.
Igor Murashkin1e854c52014-08-28 15:21:49 -07001733 */
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001734 public void updateTracker(long frameNumber, CaptureResult result, boolean partial,
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001735 int requestType) {
Igor Murashkin1e854c52014-08-28 15:21:49 -07001736 if (!partial) {
1737 // Update the total result's frame status as being successful
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001738 updateTracker(frameNumber, /*isError*/false, requestType);
Igor Murashkin1e854c52014-08-28 15:21:49 -07001739 // Don't keep a list of total results, we don't need to track them
1740 return;
1741 }
1742
1743 if (result == null) {
1744 // Do not record blank results; this also means there will be no total result
1745 // so it doesn't matter that the partials were not recorded
1746 return;
1747 }
1748
1749 // Partial results must be aggregated in-order for that frame number
1750 List<CaptureResult> partials = mPartialResults.get(frameNumber);
1751 if (partials == null) {
1752 partials = new ArrayList<>();
1753 mPartialResults.put(frameNumber, partials);
1754 }
1755
1756 partials.add(result);
1757 }
1758
1759 /**
1760 * Attempt to pop off all of the partial results seen so far for the {@code frameNumber}.
1761 *
1762 * <p>Once popped-off, the partial results are forgotten (unless {@code updateTracker}
1763 * is called again with new partials for that frame number).</p>
1764 *
1765 * @param frameNumber the frame number corresponding to the result
1766 * @return a list of partial results for that frame with at least 1 element,
1767 * or {@code null} if there were no partials recorded for that frame
1768 */
1769 public List<CaptureResult> popPartialResults(long frameNumber) {
1770 return mPartialResults.remove(frameNumber);
1771 }
1772
Jianing Weid2c3a822014-03-27 18:27:43 -07001773 public long getCompletedFrameNumber() {
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001774 return mCompletedFrameNumber[CaptureRequest.REQUEST_TYPE_REGULAR];
Jianing Weid2c3a822014-03-27 18:27:43 -07001775 }
1776
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001777 public long getCompletedReprocessFrameNumber() {
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001778 return mCompletedFrameNumber[CaptureRequest.REQUEST_TYPE_REPROCESS];
1779 }
1780
1781 public long getCompletedZslStillFrameNumber() {
1782 return mCompletedFrameNumber[CaptureRequest.REQUEST_TYPE_ZSL_STILL];
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001783 }
1784
1785 /**
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001786 * Update the completed frame number for results of 3 categories
1787 * (Regular/Reprocess/ZslStill).
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001788 *
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001789 * It validates that all previous frames of the same category have arrived.
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001790 *
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001791 * If there is a gap since previous frame number of the same category, assume the frames in
1792 * the gap are other categories and store them in the skipped frame number queue to check
1793 * against when frames of those categories arrive.
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001794 */
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001795 private void updateCompletedFrameNumber(long frameNumber,
1796 int requestType) throws IllegalArgumentException {
1797 if (frameNumber <= mCompletedFrameNumber[requestType]) {
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001798 throw new IllegalArgumentException("frame number " + frameNumber + " is a repeat");
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001799 }
1800
1801 // Assume there are only 3 different types of capture requests.
1802 int otherType1 = (requestType + 1) % CaptureRequest.REQUEST_TYPE_COUNT;
1803 int otherType2 = (requestType + 2) % CaptureRequest.REQUEST_TYPE_COUNT;
1804 long maxOtherFrameNumberSeen =
1805 Math.max(mCompletedFrameNumber[otherType1], mCompletedFrameNumber[otherType2]);
1806 if (frameNumber < maxOtherFrameNumberSeen) {
1807 // if frame number is smaller than completed frame numbers of other categories,
1808 // it must be:
1809 // - the head of mSkippedFrameNumbers for this category, or
1810 // - in one of other mSkippedOtherFrameNumbers
1811 if (!mSkippedFrameNumbers[requestType].isEmpty()) {
1812 // frame number must be head of current type of mSkippedFrameNumbers if
1813 // mSkippedFrameNumbers isn't empty.
1814 if (frameNumber < mSkippedFrameNumbers[requestType].element()) {
1815 throw new IllegalArgumentException("frame number " + frameNumber
1816 + " is a repeat");
1817 } else if (frameNumber > mSkippedFrameNumbers[requestType].element()) {
1818 throw new IllegalArgumentException("frame number " + frameNumber
1819 + " comes out of order. Expecting "
1820 + mSkippedFrameNumbers[requestType].element());
1821 }
1822 // frame number matches the head of the skipped frame number queue.
1823 mSkippedFrameNumbers[requestType].remove();
1824 } else {
1825 // frame number must be in one of the other mSkippedOtherFrameNumbers.
1826 int index1 = mSkippedOtherFrameNumbers[otherType1].indexOf(frameNumber);
1827 int index2 = mSkippedOtherFrameNumbers[otherType2].indexOf(frameNumber);
1828 boolean inSkippedOther1 = index1 != -1;
1829 boolean inSkippedOther2 = index2 != -1;
1830 if (!(inSkippedOther1 ^ inSkippedOther2)) {
1831 throw new IllegalArgumentException("frame number " + frameNumber
1832 + " is a repeat or invalid");
1833 }
1834
1835 // We know the category of frame numbers in skippedOtherFrameNumbers leading up
1836 // to the current frame number. Move them into the correct skippedFrameNumbers.
1837 LinkedList<Long> srcList, dstList;
1838 int index;
1839 if (inSkippedOther1) {
1840 srcList = mSkippedOtherFrameNumbers[otherType1];
1841 dstList = mSkippedFrameNumbers[otherType2];
1842 index = index1;
1843 } else {
1844 srcList = mSkippedOtherFrameNumbers[otherType2];
1845 dstList = mSkippedFrameNumbers[otherType1];
1846 index = index2;
1847 }
1848 for (int i = 0; i < index; i++) {
1849 dstList.add(srcList.removeFirst());
1850 }
1851
1852 // Remove current frame number from skippedOtherFrameNumbers
1853 srcList.remove();
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001854 }
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001855 } else {
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001856 // there is a gap of unseen frame numbers which should belong to the other
1857 // 2 categories. Put all the skipped frame numbers in the queue.
1858 for (long i =
1859 Math.max(maxOtherFrameNumberSeen, mCompletedFrameNumber[requestType]) + 1;
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001860 i < frameNumber; i++) {
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001861 mSkippedOtherFrameNumbers[requestType].add(i);
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001862 }
1863 }
1864
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001865 mCompletedFrameNumber[requestType] = frameNumber;
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001866 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001867 }
1868
1869 private void checkAndFireSequenceComplete() {
1870 long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001871 long completedReprocessFrameNumber = mFrameNumberTracker.getCompletedReprocessFrameNumber();
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001872 long completedZslStillFrameNumber = mFrameNumberTracker.getCompletedZslStillFrameNumber();
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001873 boolean isReprocess = false;
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001874 Iterator<RequestLastFrameNumbersHolder> iter = mRequestLastFrameNumbersList.iterator();
Jianing Weid2c3a822014-03-27 18:27:43 -07001875 while (iter.hasNext()) {
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001876 final RequestLastFrameNumbersHolder requestLastFrameNumbers = iter.next();
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001877 boolean sequenceCompleted = false;
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001878 final int requestId = requestLastFrameNumbers.getRequestId();
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001879 final CaptureCallbackHolder holder;
1880 synchronized(mInterfaceLock) {
1881 if (mRemoteDevice == null) {
1882 Log.w(TAG, "Camera closed while checking sequences");
1883 return;
1884 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001885
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001886 int index = mCaptureCallbackMap.indexOfKey(requestId);
1887 holder = (index >= 0) ?
1888 mCaptureCallbackMap.valueAt(index) : null;
1889 if (holder != null) {
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001890 long lastRegularFrameNumber =
1891 requestLastFrameNumbers.getLastRegularFrameNumber();
1892 long lastReprocessFrameNumber =
1893 requestLastFrameNumbers.getLastReprocessFrameNumber();
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001894 long lastZslStillFrameNumber =
1895 requestLastFrameNumbers.getLastZslStillFrameNumber();
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001896 // check if it's okay to remove request from mCaptureCallbackMap
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001897 if (lastRegularFrameNumber <= completedFrameNumber
1898 && lastReprocessFrameNumber <= completedReprocessFrameNumber
1899 && lastZslStillFrameNumber <= completedZslStillFrameNumber) {
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001900 sequenceCompleted = true;
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07001901 mCaptureCallbackMap.removeAt(index);
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001902 if (DEBUG) {
1903 Log.v(TAG, String.format(
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001904 "Remove holder for requestId %d, because lastRegularFrame %d "
1905 + "is <= %d, lastReprocessFrame %d is <= %d, "
1906 + "lastZslStillFrame %d is <= %d", requestId,
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001907 lastRegularFrameNumber, completedFrameNumber,
Shuzhen Wangb45449b2019-04-17 13:32:03 -07001908 lastReprocessFrameNumber, completedReprocessFrameNumber,
1909 lastZslStillFrameNumber, completedZslStillFrameNumber));
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001910 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001911 }
1912 }
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001913 }
1914
1915 // If no callback is registered for this requestId or sequence completed, remove it
1916 // from the frame number->request pair because it's not needed anymore.
1917 if (holder == null || sequenceCompleted) {
Jianing Weid2c3a822014-03-27 18:27:43 -07001918 iter.remove();
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001919 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001920
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001921 // Call onCaptureSequenceCompleted
1922 if (sequenceCompleted) {
1923 Runnable resultDispatch = new Runnable() {
1924 @Override
1925 public void run() {
1926 if (!CameraDeviceImpl.this.isClosed()){
1927 if (DEBUG) {
1928 Log.d(TAG, String.format(
1929 "fire sequence complete for request %d",
1930 requestId));
Jianing Weid2c3a822014-03-27 18:27:43 -07001931 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001932
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001933 holder.getCallback().onCaptureSequenceCompleted(
1934 CameraDeviceImpl.this,
1935 requestId,
Chien-Yu Chen4560df72015-04-27 17:21:31 -07001936 requestLastFrameNumbers.getLastFrameNumber());
Chien-Yu Chen5398a672015-03-19 14:48:43 -07001937 }
1938 }
1939 };
Emilian Peev77ca8662018-03-14 17:12:13 +00001940 final long ident = Binder.clearCallingIdentity();
1941 try {
1942 holder.getExecutor().execute(resultDispatch);
1943 } finally {
1944 Binder.restoreCallingIdentity(ident);
1945 }
Jianing Weid2c3a822014-03-27 18:27:43 -07001946 }
1947 }
1948 }
1949
Zhijun Heecb323e2013-07-31 09:40:27 -07001950 public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001951
Igor Murashkin70725502013-06-25 20:27:06 +00001952 @Override
1953 public IBinder asBinder() {
1954 return this;
1955 }
1956
Igor Murashkin70725502013-06-25 20:27:06 +00001957 @Override
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001958 public void onDeviceError(final int errorCode, CaptureResultExtras resultExtras) {
1959 if (DEBUG) {
1960 Log.d(TAG, String.format(
Ruben Brunke663cb772014-09-16 13:18:31 -07001961 "Device error received, code %d, frame number %d, request ID %d, subseq ID %d",
1962 errorCode, resultExtras.getFrameNumber(), resultExtras.getRequestId(),
1963 resultExtras.getSubsequenceId()));
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001964 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07001965
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07001966 synchronized(mInterfaceLock) {
1967 if (mRemoteDevice == null) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07001968 return; // Camera already closed
1969 }
1970
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001971 switch (errorCode) {
1972 case ERROR_CAMERA_DISCONNECTED:
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00001973 final long ident = Binder.clearCallingIdentity();
1974 try {
1975 CameraDeviceImpl.this.mDeviceExecutor.execute(mCallOnDisconnected);
1976 } finally {
1977 Binder.restoreCallingIdentity(ident);
1978 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001979 break;
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07001980 case ERROR_CAMERA_REQUEST:
1981 case ERROR_CAMERA_RESULT:
1982 case ERROR_CAMERA_BUFFER:
1983 onCaptureErrorLocked(errorCode, resultExtras);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001984 break;
Svet Ganov82f09bc2018-01-12 22:08:40 -08001985 case ERROR_CAMERA_DEVICE:
1986 scheduleNotifyError(StateCallback.ERROR_CAMERA_DEVICE);
1987 break;
1988 case ERROR_CAMERA_DISABLED:
1989 scheduleNotifyError(StateCallback.ERROR_CAMERA_DISABLED);
1990 break;
1991 default:
1992 Log.e(TAG, "Unknown error from camera device: " + errorCode);
1993 scheduleNotifyError(StateCallback.ERROR_CAMERA_SERVICE);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001994 }
Jianing Wei5a4b02b2014-04-11 09:59:24 -07001995 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07001996 }
1997
Svet Ganov82f09bc2018-01-12 22:08:40 -08001998 private void scheduleNotifyError(int code) {
1999 mInError = true;
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00002000 final long ident = Binder.clearCallingIdentity();
2001 try {
2002 CameraDeviceImpl.this.mDeviceExecutor.execute(obtainRunnable(
Yohei Yukawabfcf9a82018-09-22 13:36:47 -07002003 CameraDeviceCallbacks::notifyError, this, code).recycleOnUse());
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00002004 } finally {
2005 Binder.restoreCallingIdentity(ident);
2006 }
Svet Ganov82f09bc2018-01-12 22:08:40 -08002007 }
2008
2009 private void notifyError(int code) {
2010 if (!CameraDeviceImpl.this.isClosed()) {
2011 mDeviceCallback.onError(CameraDeviceImpl.this, code);
2012 }
2013 }
2014
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07002015 @Override
Yin-Chia Yeh8cd12e92017-09-05 18:14:21 -07002016 public void onRepeatingRequestError(long lastFrameNumber, int repeatingRequestId) {
Chien-Yu Chen2da496f2016-04-14 13:33:00 -07002017 if (DEBUG) {
2018 Log.d(TAG, "Repeating request error received. Last frame number is " +
2019 lastFrameNumber);
2020 }
2021
2022 synchronized(mInterfaceLock) {
2023 // Camera is already closed or no repeating request is present.
2024 if (mRemoteDevice == null || mRepeatingRequestId == REQUEST_ID_NONE) {
2025 return; // Camera already closed
2026 }
2027
Shuzhen Wangb45449b2019-04-17 13:32:03 -07002028 checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber,
2029 mRepeatingRequestTypes);
Yin-Chia Yeh8cd12e92017-09-05 18:14:21 -07002030 // Check if there is already a new repeating request
2031 if (mRepeatingRequestId == repeatingRequestId) {
2032 mRepeatingRequestId = REQUEST_ID_NONE;
Shuzhen Wangb45449b2019-04-17 13:32:03 -07002033 mRepeatingRequestTypes = null;
Yin-Chia Yeh8cd12e92017-09-05 18:14:21 -07002034 }
Chien-Yu Chen2da496f2016-04-14 13:33:00 -07002035 }
2036 }
2037
2038 @Override
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07002039 public void onDeviceIdle() {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07002040 if (DEBUG) {
2041 Log.d(TAG, "Camera now idle");
2042 }
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07002043 synchronized(mInterfaceLock) {
2044 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -07002045
Igor Murashkin21547d62014-06-04 15:21:42 -07002046 if (!CameraDeviceImpl.this.mIdle) {
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00002047 final long ident = Binder.clearCallingIdentity();
2048 try {
2049 CameraDeviceImpl.this.mDeviceExecutor.execute(mCallOnIdle);
2050 } finally {
2051 Binder.restoreCallingIdentity(ident);
2052 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07002053 }
Igor Murashkin21547d62014-06-04 15:21:42 -07002054 CameraDeviceImpl.this.mIdle = true;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07002055 }
2056 }
2057
2058 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -07002059 public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
2060 int requestId = resultExtras.getRequestId();
Eino-Ville Talvalae8df3092014-09-08 14:30:50 -07002061 final long frameNumber = resultExtras.getFrameNumber();
2062
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07002063 if (DEBUG) {
Eino-Ville Talvalae8df3092014-09-08 14:30:50 -07002064 Log.d(TAG, "Capture started for id " + requestId + " frame number " + frameNumber);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07002065 }
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07002066 final CaptureCallbackHolder holder;
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07002067
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07002068 synchronized(mInterfaceLock) {
2069 if (mRemoteDevice == null) return; // Camera already closed
Igor Murashkin49b2b132014-06-18 19:03:00 -07002070
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07002071 // Get the callback for this frame ID, if there is one
2072 holder = CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId);
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07002073
Igor Murashkin49b2b132014-06-18 19:03:00 -07002074 if (holder == null) {
2075 return;
2076 }
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07002077
Igor Murashkin49b2b132014-06-18 19:03:00 -07002078 if (isClosed()) return;
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07002079
Igor Murashkin49b2b132014-06-18 19:03:00 -07002080 // Dispatch capture start notice
Emilian Peev77ca8662018-03-14 17:12:13 +00002081 final long ident = Binder.clearCallingIdentity();
2082 try {
2083 holder.getExecutor().execute(
2084 new Runnable() {
2085 @Override
2086 public void run() {
2087 if (!CameraDeviceImpl.this.isClosed()) {
2088 final int subsequenceId = resultExtras.getSubsequenceId();
2089 final CaptureRequest request = holder.getRequest(subsequenceId);
Shuzhen Wangae10eb92017-03-01 12:58:04 -08002090
Emilian Peev77ca8662018-03-14 17:12:13 +00002091 if (holder.hasBatchedOutputs()) {
2092 // Send derived onCaptureStarted for requests within the
2093 // batch
2094 final Range<Integer> fpsRange =
2095 request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
2096 for (int i = 0; i < holder.getRequestCount(); i++) {
2097 holder.getCallback().onCaptureStarted(
2098 CameraDeviceImpl.this,
2099 holder.getRequest(i),
2100 timestamp - (subsequenceId - i) *
2101 NANO_PER_SECOND/fpsRange.getUpper(),
2102 frameNumber - (subsequenceId - i));
2103 }
2104 } else {
Shuzhen Wangae10eb92017-03-01 12:58:04 -08002105 holder.getCallback().onCaptureStarted(
2106 CameraDeviceImpl.this,
Emilian Peev77ca8662018-03-14 17:12:13 +00002107 holder.getRequest(resultExtras.getSubsequenceId()),
2108 timestamp, frameNumber);
Shuzhen Wangae10eb92017-03-01 12:58:04 -08002109 }
Shuzhen Wangae10eb92017-03-01 12:58:04 -08002110 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07002111 }
Emilian Peev77ca8662018-03-14 17:12:13 +00002112 });
2113 } finally {
2114 Binder.restoreCallingIdentity(ident);
2115 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07002116 }
Igor Murashkin70725502013-06-25 20:27:06 +00002117 }
2118
2119 @Override
Jianing Weid2c3a822014-03-27 18:27:43 -07002120 public void onResultReceived(CameraMetadataNative result,
Shuzhen Wang0960fb42018-01-10 20:35:11 -08002121 CaptureResultExtras resultExtras, PhysicalCaptureResultInfo physicalResults[])
2122 throws RemoteException {
Ruben Brunk57493682014-05-27 18:58:08 -07002123
Jianing Weid2c3a822014-03-27 18:27:43 -07002124 int requestId = resultExtras.getRequestId();
Igor Murashkinbdf366c2014-07-25 16:54:20 -07002125 long frameNumber = resultExtras.getFrameNumber();
2126
Zhijun Heecb323e2013-07-31 09:40:27 -07002127 if (DEBUG) {
Igor Murashkinbdf366c2014-07-25 16:54:20 -07002128 Log.v(TAG, "Received result frame " + frameNumber + " for id "
Jianing Weibaf0c652014-04-18 17:35:00 -07002129 + requestId);
Zhijun Heecb323e2013-07-31 09:40:27 -07002130 }
Ruben Brunk57493682014-05-27 18:58:08 -07002131
Eino-Ville Talvala2f75e7d2014-07-15 10:31:54 -07002132 synchronized(mInterfaceLock) {
2133 if (mRemoteDevice == null) return; // Camera already closed
Ruben Brunk57493682014-05-27 18:58:08 -07002134
Igor Murashkin49b2b132014-06-18 19:03:00 -07002135 // TODO: Handle CameraCharacteristics access from CaptureResult correctly.
2136 result.set(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE,
2137 getCharacteristics().get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE));
Ruben Brunk57493682014-05-27 18:58:08 -07002138
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07002139 final CaptureCallbackHolder holder =
2140 CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId);
Chien-Yu Chen5398a672015-03-19 14:48:43 -07002141 final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
Igor Murashkin70725502013-06-25 20:27:06 +00002142
Zhijun He83159152014-07-16 11:32:59 -07002143 boolean isPartialResult =
2144 (resultExtras.getPartialResultCount() < mTotalPartialCount);
Shuzhen Wangb45449b2019-04-17 13:32:03 -07002145 int requestType = request.getRequestType();
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08002146
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07002147 // Check if we have a callback for this
Igor Murashkin49b2b132014-06-18 19:03:00 -07002148 if (holder == null) {
2149 if (DEBUG) {
2150 Log.d(TAG,
2151 "holder is null, early return at frame "
Igor Murashkinbdf366c2014-07-25 16:54:20 -07002152 + frameNumber);
Igor Murashkin49b2b132014-06-18 19:03:00 -07002153 }
Igor Murashkin1e854c52014-08-28 15:21:49 -07002154
Chien-Yu Chen5398a672015-03-19 14:48:43 -07002155 mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult,
Shuzhen Wangb45449b2019-04-17 13:32:03 -07002156 requestType);
Igor Murashkin1e854c52014-08-28 15:21:49 -07002157
Igor Murashkin49b2b132014-06-18 19:03:00 -07002158 return;
Jianing Wei5a4b02b2014-04-11 09:59:24 -07002159 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07002160
Igor Murashkin49b2b132014-06-18 19:03:00 -07002161 if (isClosed()) {
2162 if (DEBUG) {
2163 Log.d(TAG,
2164 "camera is closed, early return at frame "
Igor Murashkinbdf366c2014-07-25 16:54:20 -07002165 + frameNumber);
Eino-Ville Talvala7a313102013-11-07 14:45:06 -08002166 }
Igor Murashkin1e854c52014-08-28 15:21:49 -07002167
Chien-Yu Chen5398a672015-03-19 14:48:43 -07002168 mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult,
Shuzhen Wangb45449b2019-04-17 13:32:03 -07002169 requestType);
Igor Murashkin49b2b132014-06-18 19:03:00 -07002170 return;
2171 }
Igor Murashkindb075af2014-05-21 10:07:08 -07002172
Igor Murashkin49b2b132014-06-18 19:03:00 -07002173
Igor Murashkin49b2b132014-06-18 19:03:00 -07002174 Runnable resultDispatch = null;
2175
Igor Murashkin1e854c52014-08-28 15:21:49 -07002176 CaptureResult finalResult;
Shuzhen Wangae10eb92017-03-01 12:58:04 -08002177 // Make a copy of the native metadata before it gets moved to a CaptureResult
2178 // object.
2179 final CameraMetadataNative resultCopy;
2180 if (holder.hasBatchedOutputs()) {
2181 resultCopy = new CameraMetadataNative(result);
2182 } else {
2183 resultCopy = null;
2184 }
Igor Murashkin1e854c52014-08-28 15:21:49 -07002185
Igor Murashkin49b2b132014-06-18 19:03:00 -07002186 // Either send a partial result or the final capture completed result
Zhijun He83159152014-07-16 11:32:59 -07002187 if (isPartialResult) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07002188 final CaptureResult resultAsCapture =
Igor Murashkinbdf366c2014-07-25 16:54:20 -07002189 new CaptureResult(result, request, resultExtras);
Igor Murashkin49b2b132014-06-18 19:03:00 -07002190 // Partial result
2191 resultDispatch = new Runnable() {
2192 @Override
2193 public void run() {
Shuzhen Wangae10eb92017-03-01 12:58:04 -08002194 if (!CameraDeviceImpl.this.isClosed()) {
2195 if (holder.hasBatchedOutputs()) {
2196 // Send derived onCaptureProgressed for requests within
2197 // the batch.
2198 for (int i = 0; i < holder.getRequestCount(); i++) {
2199 CameraMetadataNative resultLocal =
2200 new CameraMetadataNative(resultCopy);
2201 CaptureResult resultInBatch = new CaptureResult(
2202 resultLocal, holder.getRequest(i), resultExtras);
2203
2204 holder.getCallback().onCaptureProgressed(
2205 CameraDeviceImpl.this,
2206 holder.getRequest(i),
2207 resultInBatch);
2208 }
2209 } else {
2210 holder.getCallback().onCaptureProgressed(
2211 CameraDeviceImpl.this,
2212 request,
2213 resultAsCapture);
2214 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07002215 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07002216 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07002217 };
Igor Murashkin1e854c52014-08-28 15:21:49 -07002218 finalResult = resultAsCapture;
Igor Murashkin49b2b132014-06-18 19:03:00 -07002219 } else {
Igor Murashkin1e854c52014-08-28 15:21:49 -07002220 List<CaptureResult> partialResults =
2221 mFrameNumberTracker.popPartialResults(frameNumber);
2222
Shuzhen Wangae10eb92017-03-01 12:58:04 -08002223 final long sensorTimestamp =
2224 result.get(CaptureResult.SENSOR_TIMESTAMP);
2225 final Range<Integer> fpsRange =
2226 request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
2227 final int subsequenceId = resultExtras.getSubsequenceId();
Chien-Yu Chen7a316f6b2015-04-13 14:31:45 -07002228 final TotalCaptureResult resultAsCapture = new TotalCaptureResult(result,
Shuzhen Wang0960fb42018-01-10 20:35:11 -08002229 request, resultExtras, partialResults, holder.getSessionId(),
2230 physicalResults);
Igor Murashkin49b2b132014-06-18 19:03:00 -07002231 // Final capture result
2232 resultDispatch = new Runnable() {
2233 @Override
2234 public void run() {
2235 if (!CameraDeviceImpl.this.isClosed()){
Shuzhen Wangae10eb92017-03-01 12:58:04 -08002236 if (holder.hasBatchedOutputs()) {
2237 // Send derived onCaptureCompleted for requests within
2238 // the batch.
2239 for (int i = 0; i < holder.getRequestCount(); i++) {
2240 resultCopy.set(CaptureResult.SENSOR_TIMESTAMP,
2241 sensorTimestamp - (subsequenceId - i) *
2242 NANO_PER_SECOND/fpsRange.getUpper());
2243 CameraMetadataNative resultLocal =
2244 new CameraMetadataNative(resultCopy);
Shuzhen Wang0960fb42018-01-10 20:35:11 -08002245 // No logical multi-camera support for batched output mode.
Shuzhen Wangae10eb92017-03-01 12:58:04 -08002246 TotalCaptureResult resultInBatch = new TotalCaptureResult(
2247 resultLocal, holder.getRequest(i), resultExtras,
Shuzhen Wang0960fb42018-01-10 20:35:11 -08002248 partialResults, holder.getSessionId(),
2249 new PhysicalCaptureResultInfo[0]);
Shuzhen Wangae10eb92017-03-01 12:58:04 -08002250
2251 holder.getCallback().onCaptureCompleted(
2252 CameraDeviceImpl.this,
2253 holder.getRequest(i),
2254 resultInBatch);
2255 }
2256 } else {
2257 holder.getCallback().onCaptureCompleted(
2258 CameraDeviceImpl.this,
2259 request,
2260 resultAsCapture);
2261 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07002262 }
2263 }
2264 };
Igor Murashkin1e854c52014-08-28 15:21:49 -07002265 finalResult = resultAsCapture;
Igor Murashkin49b2b132014-06-18 19:03:00 -07002266 }
Jianing Weid2c3a822014-03-27 18:27:43 -07002267
Emilian Peev77ca8662018-03-14 17:12:13 +00002268 final long ident = Binder.clearCallingIdentity();
2269 try {
2270 holder.getExecutor().execute(resultDispatch);
2271 } finally {
2272 Binder.restoreCallingIdentity(ident);
2273 }
Igor Murashkin49b2b132014-06-18 19:03:00 -07002274
Igor Murashkin1e854c52014-08-28 15:21:49 -07002275 // Collect the partials for a total result; or mark the frame as totally completed
Chien-Yu Chen7a316f6b2015-04-13 14:31:45 -07002276 mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult,
Shuzhen Wangb45449b2019-04-17 13:32:03 -07002277 requestType);
Igor Murashkin1e854c52014-08-28 15:21:49 -07002278
Igor Murashkin49b2b132014-06-18 19:03:00 -07002279 // Fire onCaptureSequenceCompleted
Zhijun He83159152014-07-16 11:32:59 -07002280 if (!isPartialResult) {
Igor Murashkin49b2b132014-06-18 19:03:00 -07002281 checkAndFireSequenceComplete();
2282 }
Jianing Weid2c3a822014-03-27 18:27:43 -07002283 }
Igor Murashkin70725502013-06-25 20:27:06 +00002284 }
2285
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -07002286 @Override
2287 public void onPrepared(int streamId) {
2288 final OutputConfiguration output;
2289 final StateCallbackKK sessionCallback;
2290
2291 if (DEBUG) {
2292 Log.v(TAG, "Stream " + streamId + " is prepared");
2293 }
2294
2295 synchronized(mInterfaceLock) {
2296 output = mConfiguredOutputs.get(streamId);
2297 sessionCallback = mSessionStateCallback;
2298 }
2299
2300 if (sessionCallback == null) return;
2301
2302 if (output == null) {
2303 Log.w(TAG, "onPrepared invoked for unknown output Surface");
2304 return;
2305 }
Shuzhen Wange0a66672017-03-21 12:05:14 -07002306 final List<Surface> surfaces = output.getSurfaces();
2307 for (Surface surface : surfaces) {
2308 sessionCallback.onSurfacePrepared(surface);
2309 }
Eino-Ville Talvalaad916f72015-04-11 12:09:11 -07002310 }
2311
Shuzhen Wang88f1af22016-09-30 10:29:28 -07002312 @Override
2313 public void onRequestQueueEmpty() {
2314 final StateCallbackKK sessionCallback;
2315
2316 if (DEBUG) {
2317 Log.v(TAG, "Request queue becomes empty");
2318 }
2319
2320 synchronized(mInterfaceLock) {
2321 sessionCallback = mSessionStateCallback;
2322 }
2323
2324 if (sessionCallback == null) return;
2325
2326 sessionCallback.onRequestQueueEmpty();
2327 }
2328
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07002329 /**
2330 * Called by onDeviceError for handling single-capture failures.
2331 */
2332 private void onCaptureErrorLocked(int errorCode, CaptureResultExtras resultExtras) {
2333
2334 final int requestId = resultExtras.getRequestId();
2335 final int subsequenceId = resultExtras.getSubsequenceId();
2336 final long frameNumber = resultExtras.getFrameNumber();
Emilian Peevd0e96e32019-03-19 17:54:33 -07002337 final String errorPhysicalCameraId = resultExtras.getErrorPhysicalCameraId();
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07002338 final CaptureCallbackHolder holder =
2339 CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId);
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07002340
Yin-Chia Yehf83a9662019-06-17 14:44:35 -07002341 if (holder == null) {
2342 Log.e(TAG, String.format("Receive capture error on unknown request ID %d",
2343 requestId));
2344 return;
2345 }
2346
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07002347 final CaptureRequest request = holder.getRequest(subsequenceId);
2348
Eino-Ville Talvala3e0023a2016-03-06 18:40:01 -08002349 Runnable failureDispatch = null;
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07002350 if (errorCode == ERROR_CAMERA_BUFFER) {
Shuzhen Wang9c663d42016-10-28 23:25:02 -07002351 // Because 1 stream id could map to multiple surfaces, we need to specify both
2352 // streamId and surfaceId.
Yin-Chia Yeh3b93a852019-09-09 14:59:59 -07002353 OutputConfiguration config = mConfiguredOutputs.get(
2354 resultExtras.getErrorStreamId());
2355 if (config == null) {
2356 Log.v(TAG, String.format(
2357 "Stream %d has been removed. Skipping buffer lost callback",
2358 resultExtras.getErrorStreamId()));
2359 return;
2360 }
2361 for (Surface surface : config.getSurfaces()) {
Shuzhen Wang9c663d42016-10-28 23:25:02 -07002362 if (!request.containsTarget(surface)) {
2363 continue;
Eino-Ville Talvala3e0023a2016-03-06 18:40:01 -08002364 }
Shuzhen Wang9c663d42016-10-28 23:25:02 -07002365 if (DEBUG) {
Yin-Chia Yeh3b93a852019-09-09 14:59:59 -07002366 Log.v(TAG, String.format(
2367 "Lost output buffer reported for frame %d, target %s",
Shuzhen Wang9c663d42016-10-28 23:25:02 -07002368 frameNumber, surface));
2369 }
2370 failureDispatch = new Runnable() {
2371 @Override
2372 public void run() {
2373 if (!CameraDeviceImpl.this.isClosed()){
2374 holder.getCallback().onCaptureBufferLost(
2375 CameraDeviceImpl.this,
2376 request,
2377 surface,
2378 frameNumber);
2379 }
2380 }
2381 };
2382 // Dispatch the failure callback
Emilian Peev77ca8662018-03-14 17:12:13 +00002383 final long ident = Binder.clearCallingIdentity();
2384 try {
2385 holder.getExecutor().execute(failureDispatch);
2386 } finally {
2387 Binder.restoreCallingIdentity(ident);
2388 }
Shuzhen Wang9c663d42016-10-28 23:25:02 -07002389 }
Eino-Ville Talvala3e0023a2016-03-06 18:40:01 -08002390 } else {
2391 boolean mayHaveBuffers = (errorCode == ERROR_CAMERA_RESULT);
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07002392
Eino-Ville Talvala3e0023a2016-03-06 18:40:01 -08002393 // This is only approximate - exact handling needs the camera service and HAL to
2394 // disambiguate between request failures to due abort and due to real errors. For
2395 // now, assume that if the session believes we're mid-abort, then the error is due
2396 // to abort.
2397 int reason = (mCurrentSession != null && mCurrentSession.isAborting()) ?
2398 CaptureFailure.REASON_FLUSHED :
2399 CaptureFailure.REASON_ERROR;
2400
2401 final CaptureFailure failure = new CaptureFailure(
2402 request,
2403 reason,
2404 /*dropped*/ mayHaveBuffers,
2405 requestId,
Emilian Peevd0e96e32019-03-19 17:54:33 -07002406 frameNumber,
2407 errorPhysicalCameraId);
Eino-Ville Talvala3e0023a2016-03-06 18:40:01 -08002408
2409 failureDispatch = new Runnable() {
2410 @Override
2411 public void run() {
2412 if (!CameraDeviceImpl.this.isClosed()){
2413 holder.getCallback().onCaptureFailed(
2414 CameraDeviceImpl.this,
2415 request,
2416 failure);
2417 }
2418 }
2419 };
2420
2421 // Fire onCaptureSequenceCompleted if appropriate
2422 if (DEBUG) {
2423 Log.v(TAG, String.format("got error frame %d", frameNumber));
2424 }
Shuzhen Wangb45449b2019-04-17 13:32:03 -07002425 mFrameNumberTracker.updateTracker(frameNumber,
2426 /*error*/true, request.getRequestType());
Eino-Ville Talvala3e0023a2016-03-06 18:40:01 -08002427 checkAndFireSequenceComplete();
Shuzhen Wang9c663d42016-10-28 23:25:02 -07002428
2429 // Dispatch the failure callback
Emilian Peev77ca8662018-03-14 17:12:13 +00002430 final long ident = Binder.clearCallingIdentity();
2431 try {
2432 holder.getExecutor().execute(failureDispatch);
2433 } finally {
2434 Binder.restoreCallingIdentity(ident);
2435 }
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07002436 }
Eino-Ville Talvala3e0023a2016-03-06 18:40:01 -08002437
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -07002438 }
2439
2440 } // public class CameraDeviceCallbacks
Igor Murashkin70725502013-06-25 20:27:06 +00002441
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07002442 /**
Emilian Peevb9a51942018-03-14 17:18:49 +00002443 * A camera specific adapter {@link Executor} that posts all executed tasks onto the given
2444 * {@link Handler}.
2445 *
2446 * @hide
2447 */
2448 private static class CameraHandlerExecutor implements Executor {
2449 private final Handler mHandler;
2450
2451 public CameraHandlerExecutor(@NonNull Handler handler) {
2452 mHandler = Preconditions.checkNotNull(handler);
2453 }
2454
2455 @Override
2456 public void execute(Runnable command) {
2457 // Return value of 'post()' will be ignored in order to keep the
2458 // same camera behavior. For further details see b/74605221 .
2459 mHandler.post(command);
2460 }
2461 }
2462
2463 /**
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00002464 * Default executor management.
Emilian Peev77ca8662018-03-14 17:12:13 +00002465 *
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00002466 * <p>
2467 * If executor is null, get the current thread's
2468 * Looper to create a Executor with. If no looper exists, throw
2469 * {@code IllegalArgumentException}.
2470 * </p>
Emilian Peev77ca8662018-03-14 17:12:13 +00002471 */
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00002472 static Executor checkExecutor(Executor executor) {
2473 return (executor == null) ? checkAndWrapHandler(null) : executor;
2474 }
Emilian Peev77ca8662018-03-14 17:12:13 +00002475
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00002476 /**
2477 * Default executor management.
2478 *
2479 * <p>If the callback isn't null, check the executor, otherwise pass it through.</p>
2480 */
Emilian Peev2f0184f2018-03-21 11:57:33 +00002481 public static <T> Executor checkExecutor(Executor executor, T callback) {
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00002482 return (callback != null) ? checkExecutor(executor) : executor;
Emilian Peev77ca8662018-03-14 17:12:13 +00002483 }
2484
2485 /**
2486 * Wrap Handler in Executor.
2487 *
2488 * <p>
2489 * If handler is null, get the current thread's
2490 * Looper to create a Executor with. If no looper exists, throw
2491 * {@code IllegalArgumentException}.
2492 * </p>
2493 */
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00002494 public static Executor checkAndWrapHandler(Handler handler) {
Emilian Peevb9a51942018-03-14 17:18:49 +00002495 return new CameraHandlerExecutor(checkHandler(handler));
Emilian Peev77ca8662018-03-14 17:12:13 +00002496 }
2497
2498 /**
Igor Murashkin0b27d342014-05-30 09:45:05 -07002499 * Default handler management.
2500 *
2501 * <p>
2502 * If handler is null, get the current thread's
2503 * Looper to create a Handler with. If no looper exists, throw {@code IllegalArgumentException}.
2504 * </p>
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07002505 */
Igor Murashkin0b27d342014-05-30 09:45:05 -07002506 static Handler checkHandler(Handler handler) {
Eino-Ville Talvalae841d4e2013-09-05 09:04:08 -07002507 if (handler == null) {
2508 Looper looper = Looper.myLooper();
2509 if (looper == null) {
2510 throw new IllegalArgumentException(
2511 "No handler given, and current thread has no looper!");
2512 }
2513 handler = new Handler(looper);
2514 }
2515 return handler;
2516 }
2517
Eino-Ville Talvala7875a882014-07-31 12:47:07 -07002518 /**
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07002519 * Default handler management, conditional on there being a callback.
Eino-Ville Talvala7875a882014-07-31 12:47:07 -07002520 *
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07002521 * <p>If the callback isn't null, check the handler, otherwise pass it through.</p>
Eino-Ville Talvala7875a882014-07-31 12:47:07 -07002522 */
Eino-Ville Talvalafd887432014-09-04 13:07:40 -07002523 static <T> Handler checkHandler(Handler handler, T callback) {
2524 if (callback != null) {
Eino-Ville Talvala7875a882014-07-31 12:47:07 -07002525 return checkHandler(handler);
2526 }
2527 return handler;
2528 }
2529
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -07002530 private void checkIfCameraClosedOrInError() throws CameraAccessException {
Ruben Brunka45aa0d2015-06-03 19:40:22 -07002531 if (mRemoteDevice == null) {
2532 throw new IllegalStateException("CameraDevice was already closed");
2533 }
Eino-Ville Talvala7fcb35782014-06-03 18:30:27 -07002534 if (mInError) {
2535 throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
2536 "The camera device has encountered a serious error");
2537 }
Zhijun He7f4d3142013-07-23 07:54:38 -07002538 }
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07002539
Igor Murashkin49b2b132014-06-18 19:03:00 -07002540 /** Whether the camera device has started to close (may not yet have finished) */
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07002541 private boolean isClosed() {
Ruben Brunk0953b642015-06-11 16:12:35 -07002542 return mClosing.get();
Eino-Ville Talvala868d9042013-10-03 11:15:21 -07002543 }
Ruben Brunk57493682014-05-27 18:58:08 -07002544
2545 private CameraCharacteristics getCharacteristics() {
2546 return mCharacteristics;
2547 }
Zhijun Heb1300e32015-05-28 12:51:52 -07002548
Shuzhen Wang78392932016-03-04 15:26:01 -08002549 /**
2550 * Listener for binder death.
2551 *
2552 * <p> Handle binder death for ICameraDeviceUser. Trigger onError.</p>
2553 */
Zhijun Hec8b181e2016-05-30 14:54:39 -07002554 @Override
Shuzhen Wang78392932016-03-04 15:26:01 -08002555 public void binderDied() {
2556 Log.w(TAG, "CameraDevice " + mCameraId + " died unexpectedly");
2557
2558 if (mRemoteDevice == null) {
2559 return; // Camera already closed
2560 }
2561
2562 mInError = true;
2563 Runnable r = new Runnable() {
2564 @Override
2565 public void run() {
2566 if (!isClosed()) {
2567 mDeviceCallback.onError(CameraDeviceImpl.this,
Eino-Ville Talvala50eebe02016-06-09 17:07:13 -07002568 StateCallback.ERROR_CAMERA_SERVICE);
Shuzhen Wang78392932016-03-04 15:26:01 -08002569 }
2570 }
2571 };
Emilian Peev9a0ec8c2018-02-28 14:53:30 +00002572 final long ident = Binder.clearCallingIdentity();
2573 try {
2574 CameraDeviceImpl.this.mDeviceExecutor.execute(r);
2575 } finally {
2576 Binder.restoreCallingIdentity(ident);
2577 }
Shuzhen Wang78392932016-03-04 15:26:01 -08002578 }
Igor Murashkin70725502013-06-25 20:27:06 +00002579}