blob: 6c9586986b97f9c01a47d00b14f1361e3b0c0897 [file] [log] [blame]
Ruben Brunkfeb50af2014-05-09 19:58:49 -07001/*
2 * Copyright (C) 2014 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
17package android.hardware.camera2.legacy;
18
19import android.graphics.ImageFormat;
Ruben Brunk28c49c92014-06-16 18:43:59 -070020import android.graphics.SurfaceTexture;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070021import android.hardware.Camera;
Igor Murashkindf6242e2014-07-01 18:06:13 -070022import android.hardware.camera2.CameraCharacteristics;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070023import android.hardware.camera2.CaptureRequest;
Igor Murashkin51dcfd652014-09-25 16:55:01 -070024import android.hardware.camera2.impl.CameraDeviceImpl;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070025import android.hardware.camera2.impl.CaptureResultExtras;
26import android.hardware.camera2.ICameraDeviceCallbacks;
Ruben Brunke663cb772014-09-16 13:18:31 -070027import android.hardware.camera2.params.StreamConfigurationMap;
28import android.hardware.camera2.utils.ArrayUtils;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -080029import android.hardware.camera2.utils.SubmitInfo;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070030import android.hardware.camera2.impl.CameraMetadataNative;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070031import android.os.ConditionVariable;
32import android.os.Handler;
33import android.os.HandlerThread;
34import android.os.RemoteException;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -080035import android.os.ServiceSpecificException;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070036import android.util.Log;
Ruben Brunkf4a637d2014-11-20 18:01:36 -080037import android.util.Pair;
Igor Murashkina296fec2014-06-23 14:44:09 -070038import android.util.Size;
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -070039import android.util.SparseArray;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070040import android.view.Surface;
41
42import java.util.ArrayList;
Ruben Brunke663cb772014-09-16 13:18:31 -070043import java.util.Arrays;
Ruben Brunk3c8fa3b2014-06-30 16:45:05 -070044import java.util.Collection;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070045import java.util.List;
Igor Murashkin49b2b132014-06-18 19:03:00 -070046
Ruben Brunkef14da32014-06-24 16:06:54 -070047import static android.hardware.camera2.legacy.LegacyExceptionUtils.*;
Igor Murashkina296fec2014-06-23 14:44:09 -070048import static com.android.internal.util.Preconditions.*;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070049
50/**
51 * This class emulates the functionality of a Camera2 device using a the old Camera class.
52 *
53 * <p>
54 * There are two main components that are used to implement this:
55 * - A state machine containing valid Camera2 device states ({@link CameraDeviceState}).
56 * - A message-queue based pipeline that manages an old Camera class, and executes capture and
57 * configuration requests.
58 * </p>
59 */
60public class LegacyCameraDevice implements AutoCloseable {
Ruben Brunkfeb50af2014-05-09 19:58:49 -070061 private final String TAG;
62
Eino-Ville Talvalaa78791f2015-06-01 12:39:54 -070063 private static final boolean DEBUG = false;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070064 private final int mCameraId;
Ruben Brunke663cb772014-09-16 13:18:31 -070065 private final CameraCharacteristics mStaticCharacteristics;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070066 private final ICameraDeviceCallbacks mDeviceCallbacks;
67 private final CameraDeviceState mDeviceState = new CameraDeviceState();
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -070068 private SparseArray<Surface> mConfiguredSurfaces;
Ruben Brunke663cb772014-09-16 13:18:31 -070069 private boolean mClosed = false;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070070
71 private final ConditionVariable mIdle = new ConditionVariable(/*open*/true);
Ruben Brunkfeb50af2014-05-09 19:58:49 -070072
Ruben Brunkd85e1a62014-06-11 10:35:45 -070073 private final HandlerThread mResultThread = new HandlerThread("ResultThread");
74 private final HandlerThread mCallbackHandlerThread = new HandlerThread("CallbackThread");
Ruben Brunkfeb50af2014-05-09 19:58:49 -070075 private final Handler mCallbackHandler;
Ruben Brunkd85e1a62014-06-11 10:35:45 -070076 private final Handler mResultHandler;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070077 private static final int ILLEGAL_VALUE = -1;
78
Ruben Brunkf4a637d2014-11-20 18:01:36 -080079 // Keep up to date with values in hardware/libhardware/include/hardware/gralloc.h
80 private static final int GRALLOC_USAGE_RENDERSCRIPT = 0x00100000;
81 private static final int GRALLOC_USAGE_SW_READ_OFTEN = 0x00000003;
82 private static final int GRALLOC_USAGE_HW_TEXTURE = 0x00000100;
83 private static final int GRALLOC_USAGE_HW_COMPOSER = 0x00000800;
Zhijun Hea7677722015-06-01 16:36:06 -070084 private static final int GRALLOC_USAGE_HW_RENDER = 0x00000200;
Ruben Brunkf4a637d2014-11-20 18:01:36 -080085 private static final int GRALLOC_USAGE_HW_VIDEO_ENCODER = 0x00010000;
86
Ruben Brunk68e4fc82015-06-12 16:16:42 -070087 public static final int MAX_DIMEN_FOR_ROUNDING = 1920; // maximum allowed width for rounding
Ruben Brunkf4a637d2014-11-20 18:01:36 -080088
Ruben Brunka94c6032015-06-10 16:44:28 -070089 // Keep up to date with values in system/core/include/system/window.h
90 public static final int NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW = 1;
91
Ruben Brunkfeb50af2014-05-09 19:58:49 -070092 private CaptureResultExtras getExtrasFromRequest(RequestHolder holder) {
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -070093 return getExtrasFromRequest(holder,
94 /*errorCode*/CameraDeviceState.NO_CAPTURE_ERROR, /*errorArg*/null);
95 }
96
97 private CaptureResultExtras getExtrasFromRequest(RequestHolder holder,
98 int errorCode, Object errorArg) {
99 int errorStreamId = -1;
100 if (errorCode == CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_BUFFER) {
101 Surface errorTarget = (Surface) errorArg;
102 int indexOfTarget = mConfiguredSurfaces.indexOfValue(errorTarget);
103 if (indexOfTarget < 0) {
104 Log.e(TAG, "Buffer drop error reported for unknown Surface");
105 } else {
106 errorStreamId = mConfiguredSurfaces.keyAt(indexOfTarget);
107 }
108 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700109 if (holder == null) {
110 return new CaptureResultExtras(ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE,
Eino-Ville Talvala3e0023a2016-03-06 18:40:01 -0800111 ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700112 }
113 return new CaptureResultExtras(holder.getRequestId(), holder.getSubsequeceId(),
Zhijun He83159152014-07-16 11:32:59 -0700114 /*afTriggerId*/0, /*precaptureTriggerId*/0, holder.getFrameNumber(),
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700115 /*partialResultCount*/1, errorStreamId);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700116 }
117
118 /**
119 * Listener for the camera device state machine. Calls the appropriate
120 * {@link ICameraDeviceCallbacks} for each state transition.
121 */
122 private final CameraDeviceState.CameraDeviceStateListener mStateListener =
123 new CameraDeviceState.CameraDeviceStateListener() {
124 @Override
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700125 public void onError(final int errorCode, final Object errorArg, final RequestHolder holder) {
Igor Murashkin51dcfd652014-09-25 16:55:01 -0700126 if (DEBUG) {
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700127 Log.d(TAG, "onError called, errorCode = " + errorCode + ", errorArg = " + errorArg);
Igor Murashkin51dcfd652014-09-25 16:55:01 -0700128 }
129 switch (errorCode) {
130 /*
131 * Only be considered idle if we hit a fatal error
132 * and no further requests can be processed.
133 */
134 case CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DISCONNECTED:
135 case CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_SERVICE:
136 case CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE: {
137 mIdle.open();
138
139 if (DEBUG) {
140 Log.d(TAG, "onError - opening idle");
141 }
142 }
143 }
144
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700145 final CaptureResultExtras extras = getExtrasFromRequest(holder, errorCode, errorArg);
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700146 mResultHandler.post(new Runnable() {
147 @Override
148 public void run() {
Ruben Brunk3e4fed22014-06-18 17:08:42 -0700149 if (DEBUG) {
Ruben Brunke663cb772014-09-16 13:18:31 -0700150 Log.d(TAG, "doing onError callback for request " + holder.getRequestId() +
151 ", with error code " + errorCode);
Ruben Brunk3e4fed22014-06-18 17:08:42 -0700152 }
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700153 try {
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700154 mDeviceCallbacks.onDeviceError(errorCode, extras);
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700155 } catch (RemoteException e) {
156 throw new IllegalStateException(
157 "Received remote exception during onCameraError callback: ", e);
158 }
159 }
160 });
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700161 }
162
163 @Override
164 public void onConfiguring() {
165 // Do nothing
Ruben Brunk3e4fed22014-06-18 17:08:42 -0700166 if (DEBUG) {
167 Log.d(TAG, "doing onConfiguring callback.");
168 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700169 }
170
171 @Override
172 public void onIdle() {
Igor Murashkin51dcfd652014-09-25 16:55:01 -0700173 if (DEBUG) {
174 Log.d(TAG, "onIdle called");
175 }
176
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700177 mIdle.open();
178
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700179 mResultHandler.post(new Runnable() {
180 @Override
181 public void run() {
Ruben Brunk3e4fed22014-06-18 17:08:42 -0700182 if (DEBUG) {
183 Log.d(TAG, "doing onIdle callback.");
184 }
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700185 try {
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700186 mDeviceCallbacks.onDeviceIdle();
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700187 } catch (RemoteException e) {
188 throw new IllegalStateException(
189 "Received remote exception during onCameraIdle callback: ", e);
190 }
191 }
192 });
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700193 }
194
195 @Override
Igor Murashkin51dcfd652014-09-25 16:55:01 -0700196 public void onBusy() {
197 mIdle.close();
198
199 if (DEBUG) {
200 Log.d(TAG, "onBusy called");
201 }
202 }
203
204 @Override
Ruben Brunke663cb772014-09-16 13:18:31 -0700205 public void onCaptureStarted(final RequestHolder holder, final long timestamp) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700206 final CaptureResultExtras extras = getExtrasFromRequest(holder);
207
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700208 mResultHandler.post(new Runnable() {
209 @Override
210 public void run() {
Ruben Brunk3e4fed22014-06-18 17:08:42 -0700211 if (DEBUG) {
Ruben Brunke663cb772014-09-16 13:18:31 -0700212 Log.d(TAG, "doing onCaptureStarted callback for request " +
213 holder.getRequestId());
Ruben Brunk3e4fed22014-06-18 17:08:42 -0700214 }
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700215 try {
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700216 mDeviceCallbacks.onCaptureStarted(extras, timestamp);
217 } catch (RemoteException e) {
218 throw new IllegalStateException(
219 "Received remote exception during onCameraError callback: ", e);
220 }
221 }
222 });
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700223 }
224
225 @Override
Ruben Brunke663cb772014-09-16 13:18:31 -0700226 public void onCaptureResult(final CameraMetadataNative result, final RequestHolder holder) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700227 final CaptureResultExtras extras = getExtrasFromRequest(holder);
228
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700229 mResultHandler.post(new Runnable() {
230 @Override
231 public void run() {
Ruben Brunk3e4fed22014-06-18 17:08:42 -0700232 if (DEBUG) {
Ruben Brunke663cb772014-09-16 13:18:31 -0700233 Log.d(TAG, "doing onCaptureResult callback for request " +
234 holder.getRequestId());
Ruben Brunk3e4fed22014-06-18 17:08:42 -0700235 }
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700236 try {
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700237 mDeviceCallbacks.onResultReceived(result, extras);
238 } catch (RemoteException e) {
239 throw new IllegalStateException(
240 "Received remote exception during onCameraError callback: ", e);
241 }
242 }
243 });
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700244 }
245 };
246
247 private final RequestThreadManager mRequestThreadManager;
248
249 /**
Ruben Brunk91b9aab2014-06-20 00:24:56 -0700250 * Check if a given surface uses {@link ImageFormat#YUV_420_888} or format that can be readily
251 * converted to this; YV12 and NV21 are the two currently supported formats.
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700252 *
253 * @param s the surface to check.
Ruben Brunk91b9aab2014-06-20 00:24:56 -0700254 * @return {@code true} if the surfaces uses {@link ImageFormat#YUV_420_888} or a compatible
255 * format.
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700256 */
Ruben Brunkef14da32014-06-24 16:06:54 -0700257 static boolean needsConversion(Surface s) throws BufferQueueAbandonedException {
258 int nativeType = detectSurfaceType(s);
Ruben Brunk91b9aab2014-06-20 00:24:56 -0700259 return nativeType == ImageFormat.YUV_420_888 || nativeType == ImageFormat.YV12 ||
260 nativeType == ImageFormat.NV21;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700261 }
262
263 /**
264 * Create a new emulated camera device from a given Camera 1 API camera.
265 *
266 * <p>
267 * The {@link Camera} provided to this constructor must already have been successfully opened,
268 * and ownership of the provided camera is passed to this object. No further calls to the
269 * camera methods should be made following this constructor.
270 * </p>
271 *
272 * @param cameraId the id of the camera.
273 * @param camera an open {@link Camera} device.
Igor Murashkindf6242e2014-07-01 18:06:13 -0700274 * @param characteristics the static camera characteristics for this camera device
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700275 * @param callbacks {@link ICameraDeviceCallbacks} callbacks to call for Camera2 API operations.
276 */
Igor Murashkindf6242e2014-07-01 18:06:13 -0700277 public LegacyCameraDevice(int cameraId, Camera camera, CameraCharacteristics characteristics,
278 ICameraDeviceCallbacks callbacks) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700279 mCameraId = cameraId;
280 mDeviceCallbacks = callbacks;
281 TAG = String.format("CameraDevice-%d-LE", mCameraId);
282
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700283 mResultThread.start();
284 mResultHandler = new Handler(mResultThread.getLooper());
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700285 mCallbackHandlerThread.start();
286 mCallbackHandler = new Handler(mCallbackHandlerThread.getLooper());
287 mDeviceState.setCameraDeviceCallbacks(mCallbackHandler, mStateListener);
Ruben Brunke663cb772014-09-16 13:18:31 -0700288 mStaticCharacteristics = characteristics;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700289 mRequestThreadManager =
Igor Murashkindf6242e2014-07-01 18:06:13 -0700290 new RequestThreadManager(cameraId, camera, characteristics, mDeviceState);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700291 mRequestThreadManager.start();
292 }
293
294 /**
295 * Configure the device with a set of output surfaces.
296 *
Igor Murashkin49b2b132014-06-18 19:03:00 -0700297 * <p>Using empty or {@code null} {@code outputs} is the same as unconfiguring.</p>
298 *
299 * <p>Every surface in {@code outputs} must be non-{@code null}.</p>
300 *
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700301 * @param outputs a list of surfaces to set. LegacyCameraDevice will take ownership of this
302 * list; it must not be modified by the caller once it's passed in.
Igor Murashkin49b2b132014-06-18 19:03:00 -0700303 * @return an error code for this binder operation, or {@link NO_ERROR}
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700304 * on success.
305 */
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700306 public int configureOutputs(SparseArray<Surface> outputs) {
Ruben Brunkf4a637d2014-11-20 18:01:36 -0800307 List<Pair<Surface, Size>> sizedSurfaces = new ArrayList<>();
Igor Murashkin49b2b132014-06-18 19:03:00 -0700308 if (outputs != null) {
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700309 int count = outputs.size();
310 for (int i = 0; i < count; i++) {
311 Surface output = outputs.valueAt(i);
Igor Murashkin49b2b132014-06-18 19:03:00 -0700312 if (output == null) {
313 Log.e(TAG, "configureOutputs - null outputs are not allowed");
314 return BAD_VALUE;
315 }
Ruben Brunk443ab2c2015-03-12 20:54:03 -0700316 if (!output.isValid()) {
317 Log.e(TAG, "configureOutputs - invalid output surfaces are not allowed");
318 return BAD_VALUE;
319 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700320 StreamConfigurationMap streamConfigurations = mStaticCharacteristics.
321 get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
322
323 // Validate surface size and format.
324 try {
325 Size s = getSurfaceSize(output);
326 int surfaceType = detectSurfaceType(output);
Ruben Brunke663cb772014-09-16 13:18:31 -0700327
Eino-Ville Talvalafa0b9a02015-01-20 12:30:59 -0800328 boolean flexibleConsumer = isFlexibleConsumer(output);
Ruben Brunkf4a637d2014-11-20 18:01:36 -0800329
330 Size[] sizes = streamConfigurations.getOutputSizes(surfaceType);
Ruben Brunke663cb772014-09-16 13:18:31 -0700331 if (sizes == null) {
332 // WAR: Override default format to IMPLEMENTATION_DEFINED for b/9487482
333 if ((surfaceType >= LegacyMetadataMapper.HAL_PIXEL_FORMAT_RGBA_8888 &&
334 surfaceType <= LegacyMetadataMapper.HAL_PIXEL_FORMAT_BGRA_8888)) {
335
Ruben Brunkf4a637d2014-11-20 18:01:36 -0800336 // YUV_420_888 is always present in LEGACY for all
337 // IMPLEMENTATION_DEFINED output sizes, and is publicly visible in the
338 // API (i.e. {@code #getOutputSizes} works here).
Ruben Brunke663cb772014-09-16 13:18:31 -0700339 sizes = streamConfigurations.getOutputSizes(ImageFormat.YUV_420_888);
340 } else if (surfaceType == LegacyMetadataMapper.HAL_PIXEL_FORMAT_BLOB) {
341 sizes = streamConfigurations.getOutputSizes(ImageFormat.JPEG);
342 }
343 }
344
345 if (!ArrayUtils.contains(sizes, s)) {
Ruben Brunkf4a637d2014-11-20 18:01:36 -0800346 if (flexibleConsumer && (s = findClosestSize(s, sizes)) != null) {
347 sizedSurfaces.add(new Pair<>(output, s));
348 } else {
349 String reason = (sizes == null) ? "format is invalid." :
350 ("size not in valid set: " + Arrays.toString(sizes));
351 Log.e(TAG, String.format("Surface with size (w=%d, h=%d) and format " +
352 "0x%x is not valid, %s", s.getWidth(), s.getHeight(),
353 surfaceType, reason));
354 return BAD_VALUE;
355 }
356 } else {
357 sizedSurfaces.add(new Pair<>(output, s));
Ruben Brunke663cb772014-09-16 13:18:31 -0700358 }
Eino-Ville Talvala315bc092015-08-21 16:30:27 -0700359 // Lock down the size before configuration
360 setSurfaceDimens(output, s.getWidth(), s.getHeight());
Ruben Brunke663cb772014-09-16 13:18:31 -0700361 } catch (BufferQueueAbandonedException e) {
362 Log.e(TAG, "Surface bufferqueue is abandoned, cannot configure as output: ", e);
363 return BAD_VALUE;
364 }
365
Igor Murashkin49b2b132014-06-18 19:03:00 -0700366 }
367 }
368
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700369 boolean success = false;
370 if (mDeviceState.setConfiguring()) {
Ruben Brunkf4a637d2014-11-20 18:01:36 -0800371 mRequestThreadManager.configure(sizedSurfaces);
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700372 success = mDeviceState.setIdle();
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700373 }
Igor Murashkin49b2b132014-06-18 19:03:00 -0700374
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700375 if (success) {
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700376 mConfiguredSurfaces = outputs;
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700377 } else {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800378 return LegacyExceptionUtils.INVALID_OPERATION;
Igor Murashkin49b2b132014-06-18 19:03:00 -0700379 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800380 return LegacyExceptionUtils.NO_ERROR;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700381 }
382
383 /**
384 * Submit a burst of capture requests.
385 *
386 * @param requestList a list of capture requests to execute.
387 * @param repeating {@code true} if this burst is repeating.
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800388 * @return the submission info, including the new request id, and the last frame number, which
389 * contains either the frame number of the last frame that will be returned for this request,
390 * or the frame number of the last frame that will be returned for the current repeating
391 * request if this burst is set to be repeating.
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700392 */
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800393 public SubmitInfo submitRequestList(CaptureRequest[] requestList, boolean repeating) {
394 if (requestList == null || requestList.length == 0) {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700395 Log.e(TAG, "submitRequestList - Empty/null requests are not allowed");
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800396 throw new ServiceSpecificException(BAD_VALUE,
397 "submitRequestList - Empty/null requests are not allowed");
Igor Murashkin49b2b132014-06-18 19:03:00 -0700398 }
399
Ruben Brunk3c8fa3b2014-06-30 16:45:05 -0700400 List<Long> surfaceIds = (mConfiguredSurfaces == null) ? new ArrayList<Long>() :
401 getSurfaceIds(mConfiguredSurfaces);
402
Igor Murashkin49b2b132014-06-18 19:03:00 -0700403 // Make sure that there all requests have at least 1 surface; all surfaces are non-null
404 for (CaptureRequest request : requestList) {
405 if (request.getTargets().isEmpty()) {
406 Log.e(TAG, "submitRequestList - "
407 + "Each request must have at least one Surface target");
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800408 throw new ServiceSpecificException(BAD_VALUE,
409 "submitRequestList - "
410 + "Each request must have at least one Surface target");
Igor Murashkin49b2b132014-06-18 19:03:00 -0700411 }
412
413 for (Surface surface : request.getTargets()) {
414 if (surface == null) {
415 Log.e(TAG, "submitRequestList - Null Surface targets are not allowed");
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800416 throw new ServiceSpecificException(BAD_VALUE,
417 "submitRequestList - Null Surface targets are not allowed");
Igor Murashkin49b2b132014-06-18 19:03:00 -0700418 } else if (mConfiguredSurfaces == null) {
419 Log.e(TAG, "submitRequestList - must configure " +
420 " device with valid surfaces before submitting requests");
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800421 throw new ServiceSpecificException(INVALID_OPERATION,
422 "submitRequestList - must configure " +
423 " device with valid surfaces before submitting requests");
Ruben Brunk3c8fa3b2014-06-30 16:45:05 -0700424 } else if (!containsSurfaceId(surface, surfaceIds)) {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700425 Log.e(TAG, "submitRequestList - cannot use a surface that wasn't configured");
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800426 throw new ServiceSpecificException(BAD_VALUE,
427 "submitRequestList - cannot use a surface that wasn't configured");
Igor Murashkin49b2b132014-06-18 19:03:00 -0700428 }
429 }
430 }
431
432 // TODO: further validation of request here
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700433 mIdle.close();
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800434 return mRequestThreadManager.submitCaptureRequests(requestList, repeating);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700435 }
436
437 /**
438 * Submit a single capture request.
439 *
440 * @param request the capture request to execute.
441 * @param repeating {@code true} if this request is repeating.
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800442 * @return the submission info, including the new request id, and the last frame number, which
443 * contains either the frame number of the last frame that will be returned for this request,
444 * or the frame number of the last frame that will be returned for the current repeating
445 * request if this burst is set to be repeating.
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700446 */
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800447 public SubmitInfo submitRequest(CaptureRequest request, boolean repeating) {
448 CaptureRequest[] requestList = { request };
449 return submitRequestList(requestList, repeating);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700450 }
451
452 /**
453 * Cancel the repeating request with the given request id.
454 *
455 * @param requestId the request id of the request to cancel.
456 * @return the last frame number to be returned from the HAL for the given repeating request, or
457 * {@code INVALID_FRAME} if none exists.
458 */
459 public long cancelRequest(int requestId) {
460 return mRequestThreadManager.cancelRepeating(requestId);
461 }
462
463 /**
464 * Block until the {@link ICameraDeviceCallbacks#onCameraIdle()} callback is received.
465 */
466 public void waitUntilIdle() {
467 mIdle.block();
468 }
469
Ruben Brunke663cb772014-09-16 13:18:31 -0700470 /**
471 * Flush any pending requests.
472 *
473 * @return the last frame number.
474 */
475 public long flush() {
476 long lastFrame = mRequestThreadManager.flush();
477 waitUntilIdle();
478 return lastFrame;
479 }
480
481 /**
482 * Return {@code true} if the device has been closed.
483 */
484 public boolean isClosed() {
485 return mClosed;
486 }
487
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700488 @Override
489 public void close() {
490 mRequestThreadManager.quit();
491 mCallbackHandlerThread.quitSafely();
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700492 mResultThread.quitSafely();
493
494 try {
495 mCallbackHandlerThread.join();
496 } catch (InterruptedException e) {
497 Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
498 mCallbackHandlerThread.getName(), mCallbackHandlerThread.getId()));
499 }
500
501 try {
502 mResultThread.join();
503 } catch (InterruptedException e) {
504 Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
505 mResultThread.getName(), mResultThread.getId()));
506 }
507
Ruben Brunke663cb772014-09-16 13:18:31 -0700508 mClosed = true;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700509 }
510
511 @Override
512 protected void finalize() throws Throwable {
513 try {
514 close();
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800515 } catch (ServiceSpecificException e) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700516 Log.e(TAG, "Got error while trying to finalize, ignoring: " + e.getMessage());
517 } finally {
518 super.finalize();
519 }
520 }
521
Ruben Brunkf4a637d2014-11-20 18:01:36 -0800522 static long findEuclidDistSquare(Size a, Size b) {
523 long d0 = a.getWidth() - b.getWidth();
524 long d1 = a.getHeight() - b.getHeight();
525 return d0 * d0 + d1 * d1;
526 }
527
528 // Keep up to date with rounding behavior in
529 // frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
530 static Size findClosestSize(Size size, Size[] supportedSizes) {
531 if (size == null || supportedSizes == null) {
532 return null;
533 }
534 Size bestSize = null;
535 for (Size s : supportedSizes) {
536 if (s.equals(size)) {
537 return size;
538 } else if (s.getWidth() <= MAX_DIMEN_FOR_ROUNDING && (bestSize == null ||
539 LegacyCameraDevice.findEuclidDistSquare(size, s) <
540 LegacyCameraDevice.findEuclidDistSquare(bestSize, s))) {
541 bestSize = s;
542 }
543 }
544 return bestSize;
545 }
546
Igor Murashkina296fec2014-06-23 14:44:09 -0700547 /**
548 * Query the surface for its currently configured default buffer size.
549 * @param surface a non-{@code null} {@code Surface}
550 * @return the width and height of the surface
551 *
552 * @throws NullPointerException if the {@code surface} was {@code null}
Ruben Brunk443ab2c2015-03-12 20:54:03 -0700553 * @throws BufferQueueAbandonedException if the {@code surface} was invalid
Igor Murashkina296fec2014-06-23 14:44:09 -0700554 */
Eino-Ville Talvalafa0b9a02015-01-20 12:30:59 -0800555 public static Size getSurfaceSize(Surface surface) throws BufferQueueAbandonedException {
Igor Murashkina296fec2014-06-23 14:44:09 -0700556 checkNotNull(surface);
557
558 int[] dimens = new int[2];
Ruben Brunkef14da32014-06-24 16:06:54 -0700559 LegacyExceptionUtils.throwOnError(nativeDetectSurfaceDimens(surface, /*out*/dimens));
Igor Murashkina296fec2014-06-23 14:44:09 -0700560
561 return new Size(dimens[0], dimens[1]);
562 }
563
Eino-Ville Talvalafa0b9a02015-01-20 12:30:59 -0800564 public static boolean isFlexibleConsumer(Surface output) {
565 int usageFlags = detectSurfaceUsageFlags(output);
566
567 // Keep up to date with allowed consumer types in
568 // frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
569 int disallowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_RENDERSCRIPT;
570 int allowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_OFTEN |
571 GRALLOC_USAGE_HW_COMPOSER;
572 boolean flexibleConsumer = ((usageFlags & disallowedFlags) == 0 &&
573 (usageFlags & allowedFlags) != 0);
574 return flexibleConsumer;
575 }
576
Zhijun Hea7677722015-06-01 16:36:06 -0700577 public static boolean isPreviewConsumer(Surface output) {
578 int usageFlags = detectSurfaceUsageFlags(output);
579 int disallowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_RENDERSCRIPT |
580 GRALLOC_USAGE_SW_READ_OFTEN;
581 int allowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER |
582 GRALLOC_USAGE_HW_RENDER;
583 boolean previewConsumer = ((usageFlags & disallowedFlags) == 0 &&
584 (usageFlags & allowedFlags) != 0);
585 int surfaceFormat = ImageFormat.UNKNOWN;
586 try {
587 surfaceFormat = detectSurfaceType(output);
588 } catch(BufferQueueAbandonedException e) {
589 throw new IllegalArgumentException("Surface was abandoned", e);
590 }
591
Zhijun He47ac3492015-06-10 14:41:57 -0700592 return previewConsumer;
Zhijun Hea7677722015-06-01 16:36:06 -0700593 }
594
595 public static boolean isVideoEncoderConsumer(Surface output) {
596 int usageFlags = detectSurfaceUsageFlags(output);
597 int disallowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER |
598 GRALLOC_USAGE_RENDERSCRIPT | GRALLOC_USAGE_SW_READ_OFTEN;
599 int allowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER;
600 boolean videoEncoderConsumer = ((usageFlags & disallowedFlags) == 0 &&
601 (usageFlags & allowedFlags) != 0);
602
603 int surfaceFormat = ImageFormat.UNKNOWN;
604 try {
605 surfaceFormat = detectSurfaceType(output);
606 } catch(BufferQueueAbandonedException e) {
607 throw new IllegalArgumentException("Surface was abandoned", e);
608 }
609
Zhijun He47ac3492015-06-10 14:41:57 -0700610 return videoEncoderConsumer;
Zhijun Hea7677722015-06-01 16:36:06 -0700611 }
612
Eino-Ville Talvalafa0b9a02015-01-20 12:30:59 -0800613 /**
614 * Query the surface for its currently configured usage flags
615 */
Ruben Brunkf4a637d2014-11-20 18:01:36 -0800616 static int detectSurfaceUsageFlags(Surface surface) {
617 checkNotNull(surface);
618 return nativeDetectSurfaceUsageFlags(surface);
619 }
620
Eino-Ville Talvalafa0b9a02015-01-20 12:30:59 -0800621 /**
622 * Query the surface for its currently configured format
623 */
624 public static int detectSurfaceType(Surface surface) throws BufferQueueAbandonedException {
Ruben Brunkef14da32014-06-24 16:06:54 -0700625 checkNotNull(surface);
626 return LegacyExceptionUtils.throwOnError(nativeDetectSurfaceType(surface));
627 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700628
Eino-Ville Talvalae3651202015-06-19 17:29:14 -0700629 /**
630 * Query the surface for its currently configured dataspace
631 */
632 public static int detectSurfaceDataspace(Surface surface) throws BufferQueueAbandonedException {
633 checkNotNull(surface);
634 return LegacyExceptionUtils.throwOnError(nativeDetectSurfaceDataspace(surface));
635 }
636
Chien-Yu Chen29c36302016-03-02 15:34:00 -0800637 static void connectSurface(Surface surface) throws BufferQueueAbandonedException {
Ruben Brunkef14da32014-06-24 16:06:54 -0700638 checkNotNull(surface);
Ruben Brunkef14da32014-06-24 16:06:54 -0700639
Chien-Yu Chen29c36302016-03-02 15:34:00 -0800640 LegacyExceptionUtils.throwOnError(nativeConnectSurface(surface));
641 }
642
643 static void disconnectSurface(Surface surface) throws BufferQueueAbandonedException {
644 if (surface == null) return;
645
646 LegacyExceptionUtils.throwOnError(nativeDisconnectSurface(surface));
Ruben Brunkef14da32014-06-24 16:06:54 -0700647 }
648
649 static void produceFrame(Surface surface, byte[] pixelBuffer, int width,
650 int height, int pixelFormat)
651 throws BufferQueueAbandonedException {
652 checkNotNull(surface);
653 checkNotNull(pixelBuffer);
654 checkArgumentPositive(width, "width must be positive.");
655 checkArgumentPositive(height, "height must be positive.");
656
657 LegacyExceptionUtils.throwOnError(nativeProduceFrame(surface, pixelBuffer, width, height,
658 pixelFormat));
659 }
660
661 static void setSurfaceFormat(Surface surface, int pixelFormat)
662 throws BufferQueueAbandonedException {
663 checkNotNull(surface);
664
665 LegacyExceptionUtils.throwOnError(nativeSetSurfaceFormat(surface, pixelFormat));
666 }
667
668 static void setSurfaceDimens(Surface surface, int width, int height)
669 throws BufferQueueAbandonedException {
670 checkNotNull(surface);
671 checkArgumentPositive(width, "width must be positive.");
672 checkArgumentPositive(height, "height must be positive.");
673
674 LegacyExceptionUtils.throwOnError(nativeSetSurfaceDimens(surface, width, height));
675 }
676
Ruben Brunk3c8fa3b2014-06-30 16:45:05 -0700677 static long getSurfaceId(Surface surface) {
678 checkNotNull(surface);
679 return nativeGetSurfaceId(surface);
680 }
681
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700682 static List<Long> getSurfaceIds(SparseArray<Surface> surfaces) {
683 if (surfaces == null) {
684 throw new NullPointerException("Null argument surfaces");
685 }
686 List<Long> surfaceIds = new ArrayList<>();
687 int count = surfaces.size();
688 for (int i = 0; i < count; i++) {
689 long id = getSurfaceId(surfaces.valueAt(i));
690 if (id == 0) {
691 throw new IllegalStateException(
692 "Configured surface had null native GraphicBufferProducer pointer!");
693 }
694 surfaceIds.add(id);
695 }
696 return surfaceIds;
697 }
698
Ruben Brunk3c8fa3b2014-06-30 16:45:05 -0700699 static List<Long> getSurfaceIds(Collection<Surface> surfaces) {
700 if (surfaces == null) {
701 throw new NullPointerException("Null argument surfaces");
702 }
703 List<Long> surfaceIds = new ArrayList<>();
704 for (Surface s : surfaces) {
705 long id = getSurfaceId(s);
706 if (id == 0) {
707 throw new IllegalStateException(
708 "Configured surface had null native GraphicBufferProducer pointer!");
709 }
710 surfaceIds.add(id);
711 }
712 return surfaceIds;
713 }
714
Ruben Brunk0fd198a2014-09-23 23:35:43 -0700715 static boolean containsSurfaceId(Surface s, Collection<Long> ids) {
Ruben Brunk3c8fa3b2014-06-30 16:45:05 -0700716 long id = getSurfaceId(s);
717 return ids.contains(id);
718 }
719
Ruben Brunk28c49c92014-06-16 18:43:59 -0700720 static void setSurfaceOrientation(Surface surface, int facing, int sensorOrientation)
721 throws BufferQueueAbandonedException {
722 checkNotNull(surface);
723 LegacyExceptionUtils.throwOnError(nativeSetSurfaceOrientation(surface, facing,
724 sensorOrientation));
725 }
726
727 static Size getTextureSize(SurfaceTexture surfaceTexture)
728 throws BufferQueueAbandonedException {
729 checkNotNull(surfaceTexture);
730
731 int[] dimens = new int[2];
732 LegacyExceptionUtils.throwOnError(nativeDetectTextureDimens(surfaceTexture,
733 /*out*/dimens));
734
735 return new Size(dimens[0], dimens[1]);
736 }
737
Ruben Brunk91838de2014-07-16 17:24:17 -0700738 static void setNextTimestamp(Surface surface, long timestamp)
739 throws BufferQueueAbandonedException {
740 checkNotNull(surface);
741 LegacyExceptionUtils.throwOnError(nativeSetNextTimestamp(surface, timestamp));
742 }
743
Ruben Brunka94c6032015-06-10 16:44:28 -0700744 static void setScalingMode(Surface surface, int mode)
745 throws BufferQueueAbandonedException {
746 checkNotNull(surface);
747 LegacyExceptionUtils.throwOnError(nativeSetScalingMode(surface, mode));
748 }
749
750
Ruben Brunkef14da32014-06-24 16:06:54 -0700751 private static native int nativeDetectSurfaceType(Surface surface);
752
Eino-Ville Talvalae3651202015-06-19 17:29:14 -0700753 private static native int nativeDetectSurfaceDataspace(Surface surface);
754
Ruben Brunkef14da32014-06-24 16:06:54 -0700755 private static native int nativeDetectSurfaceDimens(Surface surface,
Igor Murashkina296fec2014-06-23 14:44:09 -0700756 /*out*/int[/*2*/] dimens);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700757
Chien-Yu Chen29c36302016-03-02 15:34:00 -0800758 private static native int nativeConnectSurface(Surface surface);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700759
Ruben Brunkef14da32014-06-24 16:06:54 -0700760 private static native int nativeProduceFrame(Surface surface, byte[] pixelBuffer, int width,
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700761 int height, int pixelFormat);
762
Ruben Brunkef14da32014-06-24 16:06:54 -0700763 private static native int nativeSetSurfaceFormat(Surface surface, int pixelFormat);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700764
Ruben Brunkef14da32014-06-24 16:06:54 -0700765 private static native int nativeSetSurfaceDimens(Surface surface, int width, int height);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700766
Ruben Brunk3c8fa3b2014-06-30 16:45:05 -0700767 private static native long nativeGetSurfaceId(Surface surface);
Ruben Brunk28c49c92014-06-16 18:43:59 -0700768
769 private static native int nativeSetSurfaceOrientation(Surface surface, int facing,
770 int sensorOrientation);
771
772 private static native int nativeDetectTextureDimens(SurfaceTexture surfaceTexture,
773 /*out*/int[/*2*/] dimens);
774
Ruben Brunk91838de2014-07-16 17:24:17 -0700775 private static native int nativeSetNextTimestamp(Surface surface, long timestamp);
Ruben Brunk1dc13262014-07-31 11:43:27 -0700776
Ruben Brunkf4a637d2014-11-20 18:01:36 -0800777 private static native int nativeDetectSurfaceUsageFlags(Surface surface);
778
Ruben Brunka94c6032015-06-10 16:44:28 -0700779 private static native int nativeSetScalingMode(Surface surface, int scalingMode);
780
Chien-Yu Chen29c36302016-03-02 15:34:00 -0800781 private static native int nativeDisconnectSurface(Surface surface);
782
Ruben Brunk1dc13262014-07-31 11:43:27 -0700783 static native int nativeGetJpegFooterSize();
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700784}