blob: 71a361bd00c6b0dd5fd12b5b8817a37225678842 [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;
Shuzhen Wang0960fb42018-01-10 20:35:11 -080026import android.hardware.camera2.impl.PhysicalCaptureResultInfo;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070027import android.hardware.camera2.ICameraDeviceCallbacks;
Ruben Brunke663cb772014-09-16 13:18:31 -070028import android.hardware.camera2.params.StreamConfigurationMap;
29import android.hardware.camera2.utils.ArrayUtils;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -080030import android.hardware.camera2.utils.SubmitInfo;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070031import android.hardware.camera2.impl.CameraMetadataNative;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070032import android.os.ConditionVariable;
33import android.os.Handler;
34import android.os.HandlerThread;
35import android.os.RemoteException;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -080036import android.os.ServiceSpecificException;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070037import android.util.Log;
Ruben Brunkf4a637d2014-11-20 18:01:36 -080038import android.util.Pair;
Igor Murashkina296fec2014-06-23 14:44:09 -070039import android.util.Size;
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -070040import android.util.SparseArray;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070041import android.view.Surface;
42
43import java.util.ArrayList;
Ruben Brunke663cb772014-09-16 13:18:31 -070044import java.util.Arrays;
Ruben Brunk3c8fa3b2014-06-30 16:45:05 -070045import java.util.Collection;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070046import java.util.List;
Igor Murashkin49b2b132014-06-18 19:03:00 -070047
Ruben Brunkef14da32014-06-24 16:06:54 -070048import static android.hardware.camera2.legacy.LegacyExceptionUtils.*;
Igor Murashkina296fec2014-06-23 14:44:09 -070049import static com.android.internal.util.Preconditions.*;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070050
51/**
52 * This class emulates the functionality of a Camera2 device using a the old Camera class.
53 *
54 * <p>
55 * There are two main components that are used to implement this:
56 * - A state machine containing valid Camera2 device states ({@link CameraDeviceState}).
57 * - A message-queue based pipeline that manages an old Camera class, and executes capture and
58 * configuration requests.
59 * </p>
60 */
61public class LegacyCameraDevice implements AutoCloseable {
Ruben Brunkfeb50af2014-05-09 19:58:49 -070062 private final String TAG;
63
Eino-Ville Talvalaa78791f2015-06-01 12:39:54 -070064 private static final boolean DEBUG = false;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070065 private final int mCameraId;
Ruben Brunke663cb772014-09-16 13:18:31 -070066 private final CameraCharacteristics mStaticCharacteristics;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070067 private final ICameraDeviceCallbacks mDeviceCallbacks;
68 private final CameraDeviceState mDeviceState = new CameraDeviceState();
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -070069 private SparseArray<Surface> mConfiguredSurfaces;
Ruben Brunke663cb772014-09-16 13:18:31 -070070 private boolean mClosed = false;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070071
72 private final ConditionVariable mIdle = new ConditionVariable(/*open*/true);
Ruben Brunkfeb50af2014-05-09 19:58:49 -070073
Ruben Brunkd85e1a62014-06-11 10:35:45 -070074 private final HandlerThread mResultThread = new HandlerThread("ResultThread");
75 private final HandlerThread mCallbackHandlerThread = new HandlerThread("CallbackThread");
Ruben Brunkfeb50af2014-05-09 19:58:49 -070076 private final Handler mCallbackHandler;
Ruben Brunkd85e1a62014-06-11 10:35:45 -070077 private final Handler mResultHandler;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070078 private static final int ILLEGAL_VALUE = -1;
79
Ruben Brunkf4a637d2014-11-20 18:01:36 -080080 // Keep up to date with values in hardware/libhardware/include/hardware/gralloc.h
81 private static final int GRALLOC_USAGE_RENDERSCRIPT = 0x00100000;
82 private static final int GRALLOC_USAGE_SW_READ_OFTEN = 0x00000003;
83 private static final int GRALLOC_USAGE_HW_TEXTURE = 0x00000100;
84 private static final int GRALLOC_USAGE_HW_COMPOSER = 0x00000800;
Zhijun Hea7677722015-06-01 16:36:06 -070085 private static final int GRALLOC_USAGE_HW_RENDER = 0x00000200;
Ruben Brunkf4a637d2014-11-20 18:01:36 -080086 private static final int GRALLOC_USAGE_HW_VIDEO_ENCODER = 0x00010000;
87
Ruben Brunk68e4fc82015-06-12 16:16:42 -070088 public static final int MAX_DIMEN_FOR_ROUNDING = 1920; // maximum allowed width for rounding
Ruben Brunkf4a637d2014-11-20 18:01:36 -080089
Ruben Brunka94c6032015-06-10 16:44:28 -070090 // Keep up to date with values in system/core/include/system/window.h
91 public static final int NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW = 1;
92
Ruben Brunkfeb50af2014-05-09 19:58:49 -070093 private CaptureResultExtras getExtrasFromRequest(RequestHolder holder) {
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -070094 return getExtrasFromRequest(holder,
95 /*errorCode*/CameraDeviceState.NO_CAPTURE_ERROR, /*errorArg*/null);
96 }
97
98 private CaptureResultExtras getExtrasFromRequest(RequestHolder holder,
99 int errorCode, Object errorArg) {
100 int errorStreamId = -1;
101 if (errorCode == CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_BUFFER) {
102 Surface errorTarget = (Surface) errorArg;
103 int indexOfTarget = mConfiguredSurfaces.indexOfValue(errorTarget);
104 if (indexOfTarget < 0) {
105 Log.e(TAG, "Buffer drop error reported for unknown Surface");
106 } else {
107 errorStreamId = mConfiguredSurfaces.keyAt(indexOfTarget);
108 }
109 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700110 if (holder == null) {
111 return new CaptureResultExtras(ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE,
Eino-Ville Talvala3e0023a2016-03-06 18:40:01 -0800112 ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700113 }
114 return new CaptureResultExtras(holder.getRequestId(), holder.getSubsequeceId(),
Zhijun He83159152014-07-16 11:32:59 -0700115 /*afTriggerId*/0, /*precaptureTriggerId*/0, holder.getFrameNumber(),
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700116 /*partialResultCount*/1, errorStreamId);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700117 }
118
119 /**
120 * Listener for the camera device state machine. Calls the appropriate
121 * {@link ICameraDeviceCallbacks} for each state transition.
122 */
123 private final CameraDeviceState.CameraDeviceStateListener mStateListener =
124 new CameraDeviceState.CameraDeviceStateListener() {
125 @Override
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700126 public void onError(final int errorCode, final Object errorArg, final RequestHolder holder) {
Igor Murashkin51dcfd652014-09-25 16:55:01 -0700127 if (DEBUG) {
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700128 Log.d(TAG, "onError called, errorCode = " + errorCode + ", errorArg = " + errorArg);
Igor Murashkin51dcfd652014-09-25 16:55:01 -0700129 }
130 switch (errorCode) {
131 /*
132 * Only be considered idle if we hit a fatal error
133 * and no further requests can be processed.
134 */
135 case CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DISCONNECTED:
136 case CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_SERVICE:
137 case CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE: {
138 mIdle.open();
139
140 if (DEBUG) {
141 Log.d(TAG, "onError - opening idle");
142 }
143 }
144 }
145
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700146 final CaptureResultExtras extras = getExtrasFromRequest(holder, errorCode, errorArg);
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700147 mResultHandler.post(new Runnable() {
148 @Override
149 public void run() {
Ruben Brunk3e4fed22014-06-18 17:08:42 -0700150 if (DEBUG) {
Ruben Brunke663cb772014-09-16 13:18:31 -0700151 Log.d(TAG, "doing onError callback for request " + holder.getRequestId() +
152 ", with error code " + errorCode);
Ruben Brunk3e4fed22014-06-18 17:08:42 -0700153 }
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700154 try {
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700155 mDeviceCallbacks.onDeviceError(errorCode, extras);
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700156 } catch (RemoteException e) {
157 throw new IllegalStateException(
158 "Received remote exception during onCameraError callback: ", e);
159 }
160 }
161 });
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700162 }
163
164 @Override
165 public void onConfiguring() {
166 // Do nothing
Ruben Brunk3e4fed22014-06-18 17:08:42 -0700167 if (DEBUG) {
168 Log.d(TAG, "doing onConfiguring callback.");
169 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700170 }
171
172 @Override
173 public void onIdle() {
Igor Murashkin51dcfd652014-09-25 16:55:01 -0700174 if (DEBUG) {
175 Log.d(TAG, "onIdle called");
176 }
177
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700178 mIdle.open();
179
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700180 mResultHandler.post(new Runnable() {
181 @Override
182 public void run() {
Ruben Brunk3e4fed22014-06-18 17:08:42 -0700183 if (DEBUG) {
184 Log.d(TAG, "doing onIdle callback.");
185 }
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700186 try {
Eino-Ville Talvalaacc00952014-08-06 14:31:08 -0700187 mDeviceCallbacks.onDeviceIdle();
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700188 } catch (RemoteException e) {
189 throw new IllegalStateException(
190 "Received remote exception during onCameraIdle callback: ", e);
191 }
192 }
193 });
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700194 }
195
196 @Override
Igor Murashkin51dcfd652014-09-25 16:55:01 -0700197 public void onBusy() {
198 mIdle.close();
199
200 if (DEBUG) {
201 Log.d(TAG, "onBusy called");
202 }
203 }
204
205 @Override
Ruben Brunke663cb772014-09-16 13:18:31 -0700206 public void onCaptureStarted(final RequestHolder holder, final long timestamp) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700207 final CaptureResultExtras extras = getExtrasFromRequest(holder);
208
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700209 mResultHandler.post(new Runnable() {
210 @Override
211 public void run() {
Ruben Brunk3e4fed22014-06-18 17:08:42 -0700212 if (DEBUG) {
Ruben Brunke663cb772014-09-16 13:18:31 -0700213 Log.d(TAG, "doing onCaptureStarted callback for request " +
214 holder.getRequestId());
Ruben Brunk3e4fed22014-06-18 17:08:42 -0700215 }
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700216 try {
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700217 mDeviceCallbacks.onCaptureStarted(extras, timestamp);
218 } catch (RemoteException e) {
219 throw new IllegalStateException(
220 "Received remote exception during onCameraError callback: ", e);
221 }
222 }
223 });
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700224 }
225
226 @Override
Shuzhen Wang234ba3e2017-08-11 09:11:23 -0700227 public void onRequestQueueEmpty() {
228 mResultHandler.post(new Runnable() {
229 @Override
230 public void run() {
231 if (DEBUG) {
232 Log.d(TAG, "doing onRequestQueueEmpty callback");
233 }
234 try {
235 mDeviceCallbacks.onRequestQueueEmpty();
236 } catch (RemoteException e) {
237 throw new IllegalStateException(
238 "Received remote exception during onRequestQueueEmpty callback: ",
239 e);
240 }
241 }
242 });
243 }
244
245 @Override
Ruben Brunke663cb772014-09-16 13:18:31 -0700246 public void onCaptureResult(final CameraMetadataNative result, final RequestHolder holder) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700247 final CaptureResultExtras extras = getExtrasFromRequest(holder);
248
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700249 mResultHandler.post(new Runnable() {
250 @Override
251 public void run() {
Ruben Brunk3e4fed22014-06-18 17:08:42 -0700252 if (DEBUG) {
Ruben Brunke663cb772014-09-16 13:18:31 -0700253 Log.d(TAG, "doing onCaptureResult callback for request " +
254 holder.getRequestId());
Ruben Brunk3e4fed22014-06-18 17:08:42 -0700255 }
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700256 try {
Shuzhen Wang0960fb42018-01-10 20:35:11 -0800257 mDeviceCallbacks.onResultReceived(result, extras,
258 new PhysicalCaptureResultInfo[0]);
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700259 } catch (RemoteException e) {
260 throw new IllegalStateException(
261 "Received remote exception during onCameraError callback: ", e);
262 }
263 }
264 });
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700265 }
Chien-Yu Chen2da496f2016-04-14 13:33:00 -0700266
267 @Override
Yin-Chia Yeh8cd12e92017-09-05 18:14:21 -0700268 public void onRepeatingRequestError(final long lastFrameNumber,
269 final int repeatingRequestId) {
Chien-Yu Chen2da496f2016-04-14 13:33:00 -0700270 mResultHandler.post(new Runnable() {
271 @Override
272 public void run() {
273 if (DEBUG) {
274 Log.d(TAG, "doing onRepeatingRequestError callback.");
275 }
276 try {
Yin-Chia Yeh8cd12e92017-09-05 18:14:21 -0700277 mDeviceCallbacks.onRepeatingRequestError(lastFrameNumber,
278 repeatingRequestId);
Chien-Yu Chen2da496f2016-04-14 13:33:00 -0700279 } catch (RemoteException e) {
280 throw new IllegalStateException(
281 "Received remote exception during onRepeatingRequestError " +
282 "callback: ", e);
283 }
284 }
285 });
286 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700287 };
288
289 private final RequestThreadManager mRequestThreadManager;
290
291 /**
Ruben Brunk91b9aab2014-06-20 00:24:56 -0700292 * Check if a given surface uses {@link ImageFormat#YUV_420_888} or format that can be readily
293 * converted to this; YV12 and NV21 are the two currently supported formats.
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700294 *
295 * @param s the surface to check.
Ruben Brunk91b9aab2014-06-20 00:24:56 -0700296 * @return {@code true} if the surfaces uses {@link ImageFormat#YUV_420_888} or a compatible
297 * format.
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700298 */
Ruben Brunkef14da32014-06-24 16:06:54 -0700299 static boolean needsConversion(Surface s) throws BufferQueueAbandonedException {
300 int nativeType = detectSurfaceType(s);
Ruben Brunk91b9aab2014-06-20 00:24:56 -0700301 return nativeType == ImageFormat.YUV_420_888 || nativeType == ImageFormat.YV12 ||
302 nativeType == ImageFormat.NV21;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700303 }
304
305 /**
306 * Create a new emulated camera device from a given Camera 1 API camera.
307 *
308 * <p>
309 * The {@link Camera} provided to this constructor must already have been successfully opened,
310 * and ownership of the provided camera is passed to this object. No further calls to the
311 * camera methods should be made following this constructor.
312 * </p>
313 *
314 * @param cameraId the id of the camera.
315 * @param camera an open {@link Camera} device.
Igor Murashkindf6242e2014-07-01 18:06:13 -0700316 * @param characteristics the static camera characteristics for this camera device
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700317 * @param callbacks {@link ICameraDeviceCallbacks} callbacks to call for Camera2 API operations.
318 */
Igor Murashkindf6242e2014-07-01 18:06:13 -0700319 public LegacyCameraDevice(int cameraId, Camera camera, CameraCharacteristics characteristics,
320 ICameraDeviceCallbacks callbacks) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700321 mCameraId = cameraId;
322 mDeviceCallbacks = callbacks;
323 TAG = String.format("CameraDevice-%d-LE", mCameraId);
324
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700325 mResultThread.start();
326 mResultHandler = new Handler(mResultThread.getLooper());
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700327 mCallbackHandlerThread.start();
328 mCallbackHandler = new Handler(mCallbackHandlerThread.getLooper());
329 mDeviceState.setCameraDeviceCallbacks(mCallbackHandler, mStateListener);
Ruben Brunke663cb772014-09-16 13:18:31 -0700330 mStaticCharacteristics = characteristics;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700331 mRequestThreadManager =
Igor Murashkindf6242e2014-07-01 18:06:13 -0700332 new RequestThreadManager(cameraId, camera, characteristics, mDeviceState);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700333 mRequestThreadManager.start();
334 }
335
336 /**
337 * Configure the device with a set of output surfaces.
338 *
Igor Murashkin49b2b132014-06-18 19:03:00 -0700339 * <p>Using empty or {@code null} {@code outputs} is the same as unconfiguring.</p>
340 *
341 * <p>Every surface in {@code outputs} must be non-{@code null}.</p>
342 *
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700343 * @param outputs a list of surfaces to set. LegacyCameraDevice will take ownership of this
344 * list; it must not be modified by the caller once it's passed in.
Igor Murashkin49b2b132014-06-18 19:03:00 -0700345 * @return an error code for this binder operation, or {@link NO_ERROR}
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700346 * on success.
347 */
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700348 public int configureOutputs(SparseArray<Surface> outputs) {
Ruben Brunkf4a637d2014-11-20 18:01:36 -0800349 List<Pair<Surface, Size>> sizedSurfaces = new ArrayList<>();
Igor Murashkin49b2b132014-06-18 19:03:00 -0700350 if (outputs != null) {
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700351 int count = outputs.size();
352 for (int i = 0; i < count; i++) {
353 Surface output = outputs.valueAt(i);
Igor Murashkin49b2b132014-06-18 19:03:00 -0700354 if (output == null) {
355 Log.e(TAG, "configureOutputs - null outputs are not allowed");
356 return BAD_VALUE;
357 }
Ruben Brunk443ab2c2015-03-12 20:54:03 -0700358 if (!output.isValid()) {
359 Log.e(TAG, "configureOutputs - invalid output surfaces are not allowed");
360 return BAD_VALUE;
361 }
Ruben Brunke663cb772014-09-16 13:18:31 -0700362 StreamConfigurationMap streamConfigurations = mStaticCharacteristics.
363 get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
364
365 // Validate surface size and format.
366 try {
367 Size s = getSurfaceSize(output);
368 int surfaceType = detectSurfaceType(output);
Ruben Brunke663cb772014-09-16 13:18:31 -0700369
Eino-Ville Talvalafa0b9a02015-01-20 12:30:59 -0800370 boolean flexibleConsumer = isFlexibleConsumer(output);
Ruben Brunkf4a637d2014-11-20 18:01:36 -0800371
372 Size[] sizes = streamConfigurations.getOutputSizes(surfaceType);
Ruben Brunke663cb772014-09-16 13:18:31 -0700373 if (sizes == null) {
Shuzhen Wang71e6d622016-12-07 14:46:30 -0800374 if (surfaceType == ImageFormat.PRIVATE) {
Ruben Brunke663cb772014-09-16 13:18:31 -0700375
Ruben Brunkf4a637d2014-11-20 18:01:36 -0800376 // YUV_420_888 is always present in LEGACY for all
377 // IMPLEMENTATION_DEFINED output sizes, and is publicly visible in the
378 // API (i.e. {@code #getOutputSizes} works here).
Ruben Brunke663cb772014-09-16 13:18:31 -0700379 sizes = streamConfigurations.getOutputSizes(ImageFormat.YUV_420_888);
380 } else if (surfaceType == LegacyMetadataMapper.HAL_PIXEL_FORMAT_BLOB) {
381 sizes = streamConfigurations.getOutputSizes(ImageFormat.JPEG);
382 }
383 }
384
385 if (!ArrayUtils.contains(sizes, s)) {
Ruben Brunkf4a637d2014-11-20 18:01:36 -0800386 if (flexibleConsumer && (s = findClosestSize(s, sizes)) != null) {
387 sizedSurfaces.add(new Pair<>(output, s));
388 } else {
389 String reason = (sizes == null) ? "format is invalid." :
390 ("size not in valid set: " + Arrays.toString(sizes));
391 Log.e(TAG, String.format("Surface with size (w=%d, h=%d) and format " +
392 "0x%x is not valid, %s", s.getWidth(), s.getHeight(),
393 surfaceType, reason));
394 return BAD_VALUE;
395 }
396 } else {
397 sizedSurfaces.add(new Pair<>(output, s));
Ruben Brunke663cb772014-09-16 13:18:31 -0700398 }
Eino-Ville Talvala315bc092015-08-21 16:30:27 -0700399 // Lock down the size before configuration
400 setSurfaceDimens(output, s.getWidth(), s.getHeight());
Ruben Brunke663cb772014-09-16 13:18:31 -0700401 } catch (BufferQueueAbandonedException e) {
402 Log.e(TAG, "Surface bufferqueue is abandoned, cannot configure as output: ", e);
403 return BAD_VALUE;
404 }
405
Igor Murashkin49b2b132014-06-18 19:03:00 -0700406 }
407 }
408
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700409 boolean success = false;
410 if (mDeviceState.setConfiguring()) {
Ruben Brunkf4a637d2014-11-20 18:01:36 -0800411 mRequestThreadManager.configure(sizedSurfaces);
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700412 success = mDeviceState.setIdle();
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700413 }
Igor Murashkin49b2b132014-06-18 19:03:00 -0700414
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700415 if (success) {
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700416 mConfiguredSurfaces = outputs;
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700417 } else {
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800418 return LegacyExceptionUtils.INVALID_OPERATION;
Igor Murashkin49b2b132014-06-18 19:03:00 -0700419 }
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800420 return LegacyExceptionUtils.NO_ERROR;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700421 }
422
423 /**
424 * Submit a burst of capture requests.
425 *
426 * @param requestList a list of capture requests to execute.
427 * @param repeating {@code true} if this burst is repeating.
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800428 * @return the submission info, including the new request id, and the last frame number, which
429 * contains either the frame number of the last frame that will be returned for this request,
430 * or the frame number of the last frame that will be returned for the current repeating
431 * request if this burst is set to be repeating.
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700432 */
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800433 public SubmitInfo submitRequestList(CaptureRequest[] requestList, boolean repeating) {
434 if (requestList == null || requestList.length == 0) {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700435 Log.e(TAG, "submitRequestList - Empty/null requests are not allowed");
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800436 throw new ServiceSpecificException(BAD_VALUE,
437 "submitRequestList - Empty/null requests are not allowed");
Igor Murashkin49b2b132014-06-18 19:03:00 -0700438 }
439
Chien-Yu Chen2da496f2016-04-14 13:33:00 -0700440 List<Long> surfaceIds;
441
442 try {
443 surfaceIds = (mConfiguredSurfaces == null) ? new ArrayList<Long>() :
444 getSurfaceIds(mConfiguredSurfaces);
445 } catch (BufferQueueAbandonedException e) {
446 throw new ServiceSpecificException(BAD_VALUE,
447 "submitRequestList - configured surface is abandoned.");
448 }
Ruben Brunk3c8fa3b2014-06-30 16:45:05 -0700449
Igor Murashkin49b2b132014-06-18 19:03:00 -0700450 // Make sure that there all requests have at least 1 surface; all surfaces are non-null
451 for (CaptureRequest request : requestList) {
452 if (request.getTargets().isEmpty()) {
453 Log.e(TAG, "submitRequestList - "
454 + "Each request must have at least one Surface target");
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800455 throw new ServiceSpecificException(BAD_VALUE,
456 "submitRequestList - "
457 + "Each request must have at least one Surface target");
Igor Murashkin49b2b132014-06-18 19:03:00 -0700458 }
459
460 for (Surface surface : request.getTargets()) {
461 if (surface == null) {
462 Log.e(TAG, "submitRequestList - Null Surface targets are not allowed");
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800463 throw new ServiceSpecificException(BAD_VALUE,
464 "submitRequestList - Null Surface targets are not allowed");
Igor Murashkin49b2b132014-06-18 19:03:00 -0700465 } else if (mConfiguredSurfaces == null) {
466 Log.e(TAG, "submitRequestList - must configure " +
467 " device with valid surfaces before submitting requests");
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800468 throw new ServiceSpecificException(INVALID_OPERATION,
469 "submitRequestList - must configure " +
470 " device with valid surfaces before submitting requests");
Ruben Brunk3c8fa3b2014-06-30 16:45:05 -0700471 } else if (!containsSurfaceId(surface, surfaceIds)) {
Igor Murashkin49b2b132014-06-18 19:03:00 -0700472 Log.e(TAG, "submitRequestList - cannot use a surface that wasn't configured");
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800473 throw new ServiceSpecificException(BAD_VALUE,
474 "submitRequestList - cannot use a surface that wasn't configured");
Igor Murashkin49b2b132014-06-18 19:03:00 -0700475 }
476 }
477 }
478
479 // TODO: further validation of request here
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700480 mIdle.close();
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800481 return mRequestThreadManager.submitCaptureRequests(requestList, repeating);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700482 }
483
484 /**
485 * Submit a single capture request.
486 *
487 * @param request the capture request to execute.
488 * @param repeating {@code true} if this request is repeating.
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800489 * @return the submission info, including the new request id, and the last frame number, which
490 * contains either the frame number of the last frame that will be returned for this request,
491 * or the frame number of the last frame that will be returned for the current repeating
492 * request if this burst is set to be repeating.
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700493 */
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800494 public SubmitInfo submitRequest(CaptureRequest request, boolean repeating) {
495 CaptureRequest[] requestList = { request };
496 return submitRequestList(requestList, repeating);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700497 }
498
499 /**
500 * Cancel the repeating request with the given request id.
501 *
502 * @param requestId the request id of the request to cancel.
503 * @return the last frame number to be returned from the HAL for the given repeating request, or
504 * {@code INVALID_FRAME} if none exists.
505 */
506 public long cancelRequest(int requestId) {
507 return mRequestThreadManager.cancelRepeating(requestId);
508 }
509
510 /**
511 * Block until the {@link ICameraDeviceCallbacks#onCameraIdle()} callback is received.
512 */
513 public void waitUntilIdle() {
514 mIdle.block();
515 }
516
Ruben Brunke663cb772014-09-16 13:18:31 -0700517 /**
518 * Flush any pending requests.
519 *
520 * @return the last frame number.
521 */
522 public long flush() {
523 long lastFrame = mRequestThreadManager.flush();
524 waitUntilIdle();
525 return lastFrame;
526 }
527
528 /**
529 * Return {@code true} if the device has been closed.
530 */
531 public boolean isClosed() {
532 return mClosed;
533 }
534
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700535 @Override
536 public void close() {
537 mRequestThreadManager.quit();
538 mCallbackHandlerThread.quitSafely();
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700539 mResultThread.quitSafely();
540
541 try {
542 mCallbackHandlerThread.join();
543 } catch (InterruptedException e) {
544 Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
545 mCallbackHandlerThread.getName(), mCallbackHandlerThread.getId()));
546 }
547
548 try {
549 mResultThread.join();
550 } catch (InterruptedException e) {
551 Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
552 mResultThread.getName(), mResultThread.getId()));
553 }
554
Ruben Brunke663cb772014-09-16 13:18:31 -0700555 mClosed = true;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700556 }
557
558 @Override
559 protected void finalize() throws Throwable {
560 try {
561 close();
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800562 } catch (ServiceSpecificException e) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700563 Log.e(TAG, "Got error while trying to finalize, ignoring: " + e.getMessage());
564 } finally {
565 super.finalize();
566 }
567 }
568
Ruben Brunkf4a637d2014-11-20 18:01:36 -0800569 static long findEuclidDistSquare(Size a, Size b) {
570 long d0 = a.getWidth() - b.getWidth();
571 long d1 = a.getHeight() - b.getHeight();
572 return d0 * d0 + d1 * d1;
573 }
574
575 // Keep up to date with rounding behavior in
576 // frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
577 static Size findClosestSize(Size size, Size[] supportedSizes) {
578 if (size == null || supportedSizes == null) {
579 return null;
580 }
581 Size bestSize = null;
582 for (Size s : supportedSizes) {
583 if (s.equals(size)) {
584 return size;
585 } else if (s.getWidth() <= MAX_DIMEN_FOR_ROUNDING && (bestSize == null ||
586 LegacyCameraDevice.findEuclidDistSquare(size, s) <
587 LegacyCameraDevice.findEuclidDistSquare(bestSize, s))) {
588 bestSize = s;
589 }
590 }
591 return bestSize;
592 }
593
Igor Murashkina296fec2014-06-23 14:44:09 -0700594 /**
595 * Query the surface for its currently configured default buffer size.
596 * @param surface a non-{@code null} {@code Surface}
597 * @return the width and height of the surface
598 *
599 * @throws NullPointerException if the {@code surface} was {@code null}
Ruben Brunk443ab2c2015-03-12 20:54:03 -0700600 * @throws BufferQueueAbandonedException if the {@code surface} was invalid
Igor Murashkina296fec2014-06-23 14:44:09 -0700601 */
Eino-Ville Talvalafa0b9a02015-01-20 12:30:59 -0800602 public static Size getSurfaceSize(Surface surface) throws BufferQueueAbandonedException {
Igor Murashkina296fec2014-06-23 14:44:09 -0700603 checkNotNull(surface);
604
605 int[] dimens = new int[2];
Ruben Brunkef14da32014-06-24 16:06:54 -0700606 LegacyExceptionUtils.throwOnError(nativeDetectSurfaceDimens(surface, /*out*/dimens));
Igor Murashkina296fec2014-06-23 14:44:09 -0700607
608 return new Size(dimens[0], dimens[1]);
609 }
610
Eino-Ville Talvalafa0b9a02015-01-20 12:30:59 -0800611 public static boolean isFlexibleConsumer(Surface output) {
612 int usageFlags = detectSurfaceUsageFlags(output);
613
614 // Keep up to date with allowed consumer types in
615 // frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
616 int disallowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_RENDERSCRIPT;
617 int allowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_OFTEN |
618 GRALLOC_USAGE_HW_COMPOSER;
619 boolean flexibleConsumer = ((usageFlags & disallowedFlags) == 0 &&
620 (usageFlags & allowedFlags) != 0);
621 return flexibleConsumer;
622 }
623
Zhijun Hea7677722015-06-01 16:36:06 -0700624 public static boolean isPreviewConsumer(Surface output) {
625 int usageFlags = detectSurfaceUsageFlags(output);
626 int disallowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_RENDERSCRIPT |
627 GRALLOC_USAGE_SW_READ_OFTEN;
628 int allowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER |
629 GRALLOC_USAGE_HW_RENDER;
630 boolean previewConsumer = ((usageFlags & disallowedFlags) == 0 &&
631 (usageFlags & allowedFlags) != 0);
632 int surfaceFormat = ImageFormat.UNKNOWN;
633 try {
634 surfaceFormat = detectSurfaceType(output);
635 } catch(BufferQueueAbandonedException e) {
636 throw new IllegalArgumentException("Surface was abandoned", e);
637 }
638
Zhijun He47ac3492015-06-10 14:41:57 -0700639 return previewConsumer;
Zhijun Hea7677722015-06-01 16:36:06 -0700640 }
641
642 public static boolean isVideoEncoderConsumer(Surface output) {
643 int usageFlags = detectSurfaceUsageFlags(output);
644 int disallowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER |
645 GRALLOC_USAGE_RENDERSCRIPT | GRALLOC_USAGE_SW_READ_OFTEN;
646 int allowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER;
647 boolean videoEncoderConsumer = ((usageFlags & disallowedFlags) == 0 &&
648 (usageFlags & allowedFlags) != 0);
649
650 int surfaceFormat = ImageFormat.UNKNOWN;
651 try {
652 surfaceFormat = detectSurfaceType(output);
653 } catch(BufferQueueAbandonedException e) {
654 throw new IllegalArgumentException("Surface was abandoned", e);
655 }
656
Zhijun He47ac3492015-06-10 14:41:57 -0700657 return videoEncoderConsumer;
Zhijun Hea7677722015-06-01 16:36:06 -0700658 }
659
Eino-Ville Talvalafa0b9a02015-01-20 12:30:59 -0800660 /**
661 * Query the surface for its currently configured usage flags
662 */
Ruben Brunkf4a637d2014-11-20 18:01:36 -0800663 static int detectSurfaceUsageFlags(Surface surface) {
664 checkNotNull(surface);
665 return nativeDetectSurfaceUsageFlags(surface);
666 }
667
Eino-Ville Talvalafa0b9a02015-01-20 12:30:59 -0800668 /**
669 * Query the surface for its currently configured format
670 */
671 public static int detectSurfaceType(Surface surface) throws BufferQueueAbandonedException {
Ruben Brunkef14da32014-06-24 16:06:54 -0700672 checkNotNull(surface);
Shuzhen Wang71e6d622016-12-07 14:46:30 -0800673 int surfaceType = nativeDetectSurfaceType(surface);
674
675 // TODO: remove this override since the default format should be
676 // ImageFormat.PRIVATE. b/9487482
677 if ((surfaceType >= LegacyMetadataMapper.HAL_PIXEL_FORMAT_RGBA_8888 &&
678 surfaceType <= LegacyMetadataMapper.HAL_PIXEL_FORMAT_BGRA_8888)) {
679 surfaceType = ImageFormat.PRIVATE;
680 }
681
682 return LegacyExceptionUtils.throwOnError(surfaceType);
Ruben Brunkef14da32014-06-24 16:06:54 -0700683 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700684
Eino-Ville Talvalae3651202015-06-19 17:29:14 -0700685 /**
686 * Query the surface for its currently configured dataspace
687 */
688 public static int detectSurfaceDataspace(Surface surface) throws BufferQueueAbandonedException {
689 checkNotNull(surface);
690 return LegacyExceptionUtils.throwOnError(nativeDetectSurfaceDataspace(surface));
691 }
692
Chien-Yu Chen29c36302016-03-02 15:34:00 -0800693 static void connectSurface(Surface surface) throws BufferQueueAbandonedException {
Ruben Brunkef14da32014-06-24 16:06:54 -0700694 checkNotNull(surface);
Ruben Brunkef14da32014-06-24 16:06:54 -0700695
Chien-Yu Chen29c36302016-03-02 15:34:00 -0800696 LegacyExceptionUtils.throwOnError(nativeConnectSurface(surface));
697 }
698
699 static void disconnectSurface(Surface surface) throws BufferQueueAbandonedException {
700 if (surface == null) return;
701
702 LegacyExceptionUtils.throwOnError(nativeDisconnectSurface(surface));
Ruben Brunkef14da32014-06-24 16:06:54 -0700703 }
704
705 static void produceFrame(Surface surface, byte[] pixelBuffer, int width,
706 int height, int pixelFormat)
707 throws BufferQueueAbandonedException {
708 checkNotNull(surface);
709 checkNotNull(pixelBuffer);
710 checkArgumentPositive(width, "width must be positive.");
711 checkArgumentPositive(height, "height must be positive.");
712
713 LegacyExceptionUtils.throwOnError(nativeProduceFrame(surface, pixelBuffer, width, height,
714 pixelFormat));
715 }
716
717 static void setSurfaceFormat(Surface surface, int pixelFormat)
718 throws BufferQueueAbandonedException {
719 checkNotNull(surface);
720
721 LegacyExceptionUtils.throwOnError(nativeSetSurfaceFormat(surface, pixelFormat));
722 }
723
724 static void setSurfaceDimens(Surface surface, int width, int height)
725 throws BufferQueueAbandonedException {
726 checkNotNull(surface);
727 checkArgumentPositive(width, "width must be positive.");
728 checkArgumentPositive(height, "height must be positive.");
729
730 LegacyExceptionUtils.throwOnError(nativeSetSurfaceDimens(surface, width, height));
731 }
732
Yin-Chia Yeh4f151472018-02-21 12:38:19 -0800733 public static long getSurfaceId(Surface surface) throws BufferQueueAbandonedException {
Ruben Brunk3c8fa3b2014-06-30 16:45:05 -0700734 checkNotNull(surface);
Chien-Yu Chen2da496f2016-04-14 13:33:00 -0700735 try {
736 return nativeGetSurfaceId(surface);
737 } catch (IllegalArgumentException e) {
738 throw new BufferQueueAbandonedException();
739 }
Ruben Brunk3c8fa3b2014-06-30 16:45:05 -0700740 }
741
Chien-Yu Chen2da496f2016-04-14 13:33:00 -0700742 static List<Long> getSurfaceIds(SparseArray<Surface> surfaces)
743 throws BufferQueueAbandonedException {
Eino-Ville Talvala385f9e22016-03-31 16:47:14 -0700744 if (surfaces == null) {
745 throw new NullPointerException("Null argument surfaces");
746 }
747 List<Long> surfaceIds = new ArrayList<>();
748 int count = surfaces.size();
749 for (int i = 0; i < count; i++) {
750 long id = getSurfaceId(surfaces.valueAt(i));
751 if (id == 0) {
752 throw new IllegalStateException(
753 "Configured surface had null native GraphicBufferProducer pointer!");
754 }
755 surfaceIds.add(id);
756 }
757 return surfaceIds;
758 }
759
Chien-Yu Chen2da496f2016-04-14 13:33:00 -0700760 static List<Long> getSurfaceIds(Collection<Surface> surfaces)
761 throws BufferQueueAbandonedException {
Ruben Brunk3c8fa3b2014-06-30 16:45:05 -0700762 if (surfaces == null) {
763 throw new NullPointerException("Null argument surfaces");
764 }
765 List<Long> surfaceIds = new ArrayList<>();
766 for (Surface s : surfaces) {
767 long id = getSurfaceId(s);
768 if (id == 0) {
769 throw new IllegalStateException(
770 "Configured surface had null native GraphicBufferProducer pointer!");
771 }
772 surfaceIds.add(id);
773 }
774 return surfaceIds;
775 }
776
Ruben Brunk0fd198a2014-09-23 23:35:43 -0700777 static boolean containsSurfaceId(Surface s, Collection<Long> ids) {
Chien-Yu Chen2da496f2016-04-14 13:33:00 -0700778 long id = 0;
779 try {
780 id = getSurfaceId(s);
781 } catch (BufferQueueAbandonedException e) {
782 // If surface is abandoned, return false.
783 return false;
784 }
Ruben Brunk3c8fa3b2014-06-30 16:45:05 -0700785 return ids.contains(id);
786 }
787
Ruben Brunk28c49c92014-06-16 18:43:59 -0700788 static void setSurfaceOrientation(Surface surface, int facing, int sensorOrientation)
789 throws BufferQueueAbandonedException {
790 checkNotNull(surface);
791 LegacyExceptionUtils.throwOnError(nativeSetSurfaceOrientation(surface, facing,
792 sensorOrientation));
793 }
794
795 static Size getTextureSize(SurfaceTexture surfaceTexture)
796 throws BufferQueueAbandonedException {
797 checkNotNull(surfaceTexture);
798
799 int[] dimens = new int[2];
800 LegacyExceptionUtils.throwOnError(nativeDetectTextureDimens(surfaceTexture,
801 /*out*/dimens));
802
803 return new Size(dimens[0], dimens[1]);
804 }
805
Ruben Brunk91838de2014-07-16 17:24:17 -0700806 static void setNextTimestamp(Surface surface, long timestamp)
807 throws BufferQueueAbandonedException {
808 checkNotNull(surface);
809 LegacyExceptionUtils.throwOnError(nativeSetNextTimestamp(surface, timestamp));
810 }
811
Ruben Brunka94c6032015-06-10 16:44:28 -0700812 static void setScalingMode(Surface surface, int mode)
813 throws BufferQueueAbandonedException {
814 checkNotNull(surface);
815 LegacyExceptionUtils.throwOnError(nativeSetScalingMode(surface, mode));
816 }
817
818
Ruben Brunkef14da32014-06-24 16:06:54 -0700819 private static native int nativeDetectSurfaceType(Surface surface);
820
Eino-Ville Talvalae3651202015-06-19 17:29:14 -0700821 private static native int nativeDetectSurfaceDataspace(Surface surface);
822
Ruben Brunkef14da32014-06-24 16:06:54 -0700823 private static native int nativeDetectSurfaceDimens(Surface surface,
Igor Murashkina296fec2014-06-23 14:44:09 -0700824 /*out*/int[/*2*/] dimens);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700825
Chien-Yu Chen29c36302016-03-02 15:34:00 -0800826 private static native int nativeConnectSurface(Surface surface);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700827
Ruben Brunkef14da32014-06-24 16:06:54 -0700828 private static native int nativeProduceFrame(Surface surface, byte[] pixelBuffer, int width,
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700829 int height, int pixelFormat);
830
Ruben Brunkef14da32014-06-24 16:06:54 -0700831 private static native int nativeSetSurfaceFormat(Surface surface, int pixelFormat);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700832
Ruben Brunkef14da32014-06-24 16:06:54 -0700833 private static native int nativeSetSurfaceDimens(Surface surface, int width, int height);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700834
Ruben Brunk3c8fa3b2014-06-30 16:45:05 -0700835 private static native long nativeGetSurfaceId(Surface surface);
Ruben Brunk28c49c92014-06-16 18:43:59 -0700836
837 private static native int nativeSetSurfaceOrientation(Surface surface, int facing,
838 int sensorOrientation);
839
840 private static native int nativeDetectTextureDimens(SurfaceTexture surfaceTexture,
841 /*out*/int[/*2*/] dimens);
842
Ruben Brunk91838de2014-07-16 17:24:17 -0700843 private static native int nativeSetNextTimestamp(Surface surface, long timestamp);
Ruben Brunk1dc13262014-07-31 11:43:27 -0700844
Ruben Brunkf4a637d2014-11-20 18:01:36 -0800845 private static native int nativeDetectSurfaceUsageFlags(Surface surface);
846
Ruben Brunka94c6032015-06-10 16:44:28 -0700847 private static native int nativeSetScalingMode(Surface surface, int scalingMode);
848
Chien-Yu Chen29c36302016-03-02 15:34:00 -0800849 private static native int nativeDisconnectSurface(Surface surface);
850
Ruben Brunk1dc13262014-07-31 11:43:27 -0700851 static native int nativeGetJpegFooterSize();
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700852}