blob: 1cdf23530ddc44bc2457111f36a400a5ac6aa949 [file] [log] [blame]
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001/*
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
17package android.hardware.camera2.impl;
18
Mathew Inwoodbcbe4402018-08-08 15:42:59 +010019import android.annotation.UnsupportedAppUsage;
Zhijun Heb7bfdc72013-10-02 11:39:43 -070020import android.graphics.ImageFormat;
21import android.graphics.Point;
22import android.graphics.Rect;
23import android.hardware.camera2.CameraCharacteristics;
Emilian Peev2776ca32018-09-18 14:00:39 +010024import android.hardware.camera2.CameraDevice;
Igor Murashkind6d65152014-05-19 16:31:02 -070025import android.hardware.camera2.CaptureRequest;
Zhijun Heb7bfdc72013-10-02 11:39:43 -070026import android.hardware.camera2.CaptureResult;
Igor Murashkin3c40a042014-04-22 15:05:50 -070027import android.hardware.camera2.marshal.MarshalQueryable;
28import android.hardware.camera2.marshal.MarshalRegistry;
Chien-Yu Chenc804d1c2018-02-15 12:44:19 -080029import android.hardware.camera2.marshal.Marshaler;
Igor Murashkin3c40a042014-04-22 15:05:50 -070030import android.hardware.camera2.marshal.impl.MarshalQueryableArray;
Ruben Brunk52842e72014-06-05 13:16:45 -070031import android.hardware.camera2.marshal.impl.MarshalQueryableBlackLevelPattern;
Chien-Yu Chenc804d1c2018-02-15 12:44:19 -080032import android.hardware.camera2.marshal.impl.MarshalQueryableBoolean;
Igor Murashkin3c40a042014-04-22 15:05:50 -070033import android.hardware.camera2.marshal.impl.MarshalQueryableColorSpaceTransform;
34import android.hardware.camera2.marshal.impl.MarshalQueryableEnum;
Yin-Chia Yeh12da1402014-07-15 10:37:31 -070035import android.hardware.camera2.marshal.impl.MarshalQueryableHighSpeedVideoConfiguration;
Igor Murashkin3c40a042014-04-22 15:05:50 -070036import android.hardware.camera2.marshal.impl.MarshalQueryableMeteringRectangle;
37import android.hardware.camera2.marshal.impl.MarshalQueryableNativeByteToInteger;
Igor Murashkin57438682014-05-30 10:49:00 -070038import android.hardware.camera2.marshal.impl.MarshalQueryablePair;
Igor Murashkin3c40a042014-04-22 15:05:50 -070039import android.hardware.camera2.marshal.impl.MarshalQueryableParcelable;
40import android.hardware.camera2.marshal.impl.MarshalQueryablePrimitive;
41import android.hardware.camera2.marshal.impl.MarshalQueryableRange;
Emilian Peev2776ca32018-09-18 14:00:39 +010042import android.hardware.camera2.marshal.impl.MarshalQueryableRecommendedStreamConfiguration;
Igor Murashkin3c40a042014-04-22 15:05:50 -070043import android.hardware.camera2.marshal.impl.MarshalQueryableRect;
44import android.hardware.camera2.marshal.impl.MarshalQueryableReprocessFormatsMap;
45import android.hardware.camera2.marshal.impl.MarshalQueryableRggbChannelVector;
46import android.hardware.camera2.marshal.impl.MarshalQueryableSize;
47import android.hardware.camera2.marshal.impl.MarshalQueryableSizeF;
48import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfiguration;
49import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration;
50import android.hardware.camera2.marshal.impl.MarshalQueryableString;
Igor Murashkin72f9f0a2014-05-14 15:46:10 -070051import android.hardware.camera2.params.Face;
Yin-Chia Yeh12da1402014-07-15 10:37:31 -070052import android.hardware.camera2.params.HighSpeedVideoConfiguration;
Ruben Brunk57493682014-05-27 18:58:08 -070053import android.hardware.camera2.params.LensShadingMap;
Emilian Peev423cbd72018-11-10 18:37:45 +000054import android.hardware.camera2.params.MandatoryStreamCombination;
55import android.hardware.camera2.params.MandatoryStreamCombination.MandatoryStreamInformation;
Chien-Yu Chenc804d1c2018-02-15 12:44:19 -080056import android.hardware.camera2.params.OisSample;
Emilian Peev2776ca32018-09-18 14:00:39 +010057import android.hardware.camera2.params.RecommendedStreamConfiguration;
58import android.hardware.camera2.params.RecommendedStreamConfigurationMap;
Chien-Yu Chen0a551f12015-04-03 17:57:35 -070059import android.hardware.camera2.params.ReprocessFormatsMap;
Igor Murashkin9c595172014-05-12 13:56:20 -070060import android.hardware.camera2.params.StreamConfiguration;
61import android.hardware.camera2.params.StreamConfigurationDuration;
62import android.hardware.camera2.params.StreamConfigurationMap;
Yin-Chia Yeh8490ace2014-05-27 10:04:54 -070063import android.hardware.camera2.params.TonemapCurve;
Igor Murashkind6d65152014-05-19 16:31:02 -070064import android.hardware.camera2.utils.TypeReference;
Ruben Brunk57493682014-05-27 18:58:08 -070065import android.location.Location;
66import android.location.LocationManager;
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070067import android.os.Parcel;
Chien-Yu Chenc804d1c2018-02-15 12:44:19 -080068import android.os.Parcelable;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -080069import android.os.ServiceSpecificException;
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070070import android.util.Log;
Ruben Brunk57493682014-05-27 18:58:08 -070071import android.util.Size;
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070072
Igor Murashkind6d65152014-05-19 16:31:02 -070073import com.android.internal.util.Preconditions;
74
75import java.io.IOException;
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070076import java.nio.ByteBuffer;
77import java.nio.ByteOrder;
78import java.util.ArrayList;
Ruben Brunk57493682014-05-27 18:58:08 -070079import java.util.HashMap;
Emilian Peev423cbd72018-11-10 18:37:45 +000080import java.util.List;
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070081
82/**
83 * Implementation of camera metadata marshal/unmarshal across Binder to
84 * the camera service
85 */
Igor Murashkind6d65152014-05-19 16:31:02 -070086public class CameraMetadataNative implements Parcelable {
87
88 public static class Key<T> {
89 private boolean mHasTag;
90 private int mTag;
Emilian Peevde62d842017-03-23 19:20:40 +000091 private long mVendorId = Long.MAX_VALUE;
Igor Murashkind6d65152014-05-19 16:31:02 -070092 private final Class<T> mType;
93 private final TypeReference<T> mTypeReference;
94 private final String mName;
Justin Yunf01e40c2018-05-18 20:39:45 +090095 private final String mFallbackName;
Ruben Brunkd1f113d2014-07-11 11:46:20 -070096 private final int mHash;
Emilian Peevde62d842017-03-23 19:20:40 +000097
98 /**
99 * @hide
100 */
101 public Key(String name, Class<T> type, long vendorId) {
102 if (name == null) {
103 throw new NullPointerException("Key needs a valid name");
104 } else if (type == null) {
105 throw new NullPointerException("Type needs to be non-null");
106 }
107 mName = name;
Justin Yunf01e40c2018-05-18 20:39:45 +0900108 mFallbackName = null;
Emilian Peevde62d842017-03-23 19:20:40 +0000109 mType = type;
110 mVendorId = vendorId;
111 mTypeReference = TypeReference.createSpecializedTypeReference(type);
112 mHash = mName.hashCode() ^ mTypeReference.hashCode();
113 }
114
Igor Murashkind6d65152014-05-19 16:31:02 -0700115 /**
Justin Yunf01e40c2018-05-18 20:39:45 +0900116 * @hide
117 */
118 public Key(String name, String fallbackName, Class<T> type) {
119 if (name == null) {
120 throw new NullPointerException("Key needs a valid name");
121 } else if (type == null) {
122 throw new NullPointerException("Type needs to be non-null");
123 }
124 mName = name;
125 mFallbackName = fallbackName;
126 mType = type;
127 mTypeReference = TypeReference.createSpecializedTypeReference(type);
128 mHash = mName.hashCode() ^ mTypeReference.hashCode();
129 }
130
131 /**
Igor Murashkind6d65152014-05-19 16:31:02 -0700132 * Visible for testing only.
133 *
134 * <p>Use the CameraCharacteristics.Key, CaptureResult.Key, or CaptureRequest.Key
135 * for application code or vendor-extended keys.</p>
136 */
137 public Key(String name, Class<T> type) {
138 if (name == null) {
139 throw new NullPointerException("Key needs a valid name");
140 } else if (type == null) {
141 throw new NullPointerException("Type needs to be non-null");
142 }
143 mName = name;
Justin Yunf01e40c2018-05-18 20:39:45 +0900144 mFallbackName = null;
Igor Murashkind6d65152014-05-19 16:31:02 -0700145 mType = type;
146 mTypeReference = TypeReference.createSpecializedTypeReference(type);
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700147 mHash = mName.hashCode() ^ mTypeReference.hashCode();
Igor Murashkind6d65152014-05-19 16:31:02 -0700148 }
149
150 /**
151 * Visible for testing only.
152 *
153 * <p>Use the CameraCharacteristics.Key, CaptureResult.Key, or CaptureRequest.Key
154 * for application code or vendor-extended keys.</p>
155 */
156 @SuppressWarnings("unchecked")
157 public Key(String name, TypeReference<T> typeReference) {
158 if (name == null) {
159 throw new NullPointerException("Key needs a valid name");
160 } else if (typeReference == null) {
161 throw new NullPointerException("TypeReference needs to be non-null");
162 }
163 mName = name;
Justin Yunf01e40c2018-05-18 20:39:45 +0900164 mFallbackName = null;
Igor Murashkind6d65152014-05-19 16:31:02 -0700165 mType = (Class<T>)typeReference.getRawType();
166 mTypeReference = typeReference;
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700167 mHash = mName.hashCode() ^ mTypeReference.hashCode();
Igor Murashkind6d65152014-05-19 16:31:02 -0700168 }
169
170 /**
171 * Return a camelCase, period separated name formatted like:
172 * {@code "root.section[.subsections].name"}.
173 *
174 * <p>Built-in keys exposed by the Android SDK are always prefixed with {@code "android."};
175 * keys that are device/platform-specific are prefixed with {@code "com."}.</p>
176 *
177 * <p>For example, {@code CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP} would
178 * have a name of {@code "android.scaler.streamConfigurationMap"}; whereas a device
179 * specific key might look like {@code "com.google.nexus.data.private"}.</p>
180 *
181 * @return String representation of the key name
182 */
183 public final String getName() {
184 return mName;
185 }
186
187 /**
188 * {@inheritDoc}
189 */
190 @Override
191 public final int hashCode() {
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700192 return mHash;
Igor Murashkind6d65152014-05-19 16:31:02 -0700193 }
194
195 /**
196 * Compare this key against other native keys, request keys, result keys, and
197 * characteristics keys.
198 *
199 * <p>Two keys are considered equal if their name and type reference are equal.</p>
200 *
201 * <p>Note that the equality against non-native keys is one-way. A native key may be equal
202 * to a result key; but that same result key will not be equal to a native key.</p>
203 */
204 @SuppressWarnings("rawtypes")
205 @Override
206 public final boolean equals(Object o) {
207 if (this == o) {
208 return true;
209 }
210
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700211 if (o == null || this.hashCode() != o.hashCode()) {
212 return false;
213 }
214
Igor Murashkind6d65152014-05-19 16:31:02 -0700215 Key<?> lhs;
216
217 if (o instanceof CaptureResult.Key) {
218 lhs = ((CaptureResult.Key)o).getNativeKey();
219 } else if (o instanceof CaptureRequest.Key) {
220 lhs = ((CaptureRequest.Key)o).getNativeKey();
221 } else if (o instanceof CameraCharacteristics.Key) {
222 lhs = ((CameraCharacteristics.Key)o).getNativeKey();
223 } else if ((o instanceof Key)) {
224 lhs = (Key<?>)o;
225 } else {
226 return false;
227 }
228
229 return mName.equals(lhs.mName) && mTypeReference.equals(lhs.mTypeReference);
230 }
231
232 /**
233 * <p>
234 * Get the tag corresponding to this key. This enables insertion into the
235 * native metadata.
236 * </p>
237 *
238 * <p>This value is looked up the first time, and cached subsequently.</p>
239 *
240 * @return The tag numeric value corresponding to the string
241 */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100242 @UnsupportedAppUsage
Igor Murashkind6d65152014-05-19 16:31:02 -0700243 public final int getTag() {
244 if (!mHasTag) {
Emilian Peevde62d842017-03-23 19:20:40 +0000245 mTag = CameraMetadataNative.getTag(mName, mVendorId);
Igor Murashkind6d65152014-05-19 16:31:02 -0700246 mHasTag = true;
247 }
248 return mTag;
249 }
250
251 /**
252 * Get the raw class backing the type {@code T} for this key.
253 *
254 * <p>The distinction is only important if {@code T} is a generic, e.g.
255 * {@code Range<Integer>} since the nested type will be erased.</p>
256 */
257 public final Class<T> getType() {
258 // TODO: remove this; other places should use #getTypeReference() instead
259 return mType;
260 }
261
262 /**
Emilian Peevde62d842017-03-23 19:20:40 +0000263 * Get the vendor tag provider id.
264 *
265 * @hide
266 */
267 public final long getVendorId() {
268 return mVendorId;
269 }
270
271 /**
Igor Murashkind6d65152014-05-19 16:31:02 -0700272 * Get the type reference backing the type {@code T} for this key.
273 *
274 * <p>The distinction is only important if {@code T} is a generic, e.g.
275 * {@code Range<Integer>} since the nested type will be retained.</p>
276 */
277 public final TypeReference<T> getTypeReference() {
278 return mTypeReference;
279 }
280 }
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700281
282 private static final String TAG = "CameraMetadataJV";
Eino-Ville Talvalaa78791f2015-06-01 12:39:54 -0700283 private static final boolean DEBUG = false;
284
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700285 // this should be in sync with HAL_PIXEL_FORMAT_BLOB defined in graphics.h
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700286 public static final int NATIVE_JPEG_FORMAT = 0x21;
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700287
Ruben Brunk57493682014-05-27 18:58:08 -0700288 private static final String CELLID_PROCESS = "CELLID";
289 private static final String GPS_PROCESS = "GPS";
Igor Murashkin0a1ef4d2014-07-31 15:53:34 -0700290 private static final int FACE_LANDMARK_SIZE = 6;
Ruben Brunk57493682014-05-27 18:58:08 -0700291
292 private static String translateLocationProviderToProcess(final String provider) {
293 if (provider == null) {
294 return null;
295 }
296 switch(provider) {
297 case LocationManager.GPS_PROVIDER:
298 return GPS_PROCESS;
299 case LocationManager.NETWORK_PROVIDER:
300 return CELLID_PROCESS;
301 default:
302 return null;
303 }
304 }
305
306 private static String translateProcessToLocationProvider(final String process) {
307 if (process == null) {
308 return null;
309 }
310 switch(process) {
311 case GPS_PROCESS:
312 return LocationManager.GPS_PROVIDER;
313 case CELLID_PROCESS:
314 return LocationManager.NETWORK_PROVIDER;
315 default:
316 return null;
317 }
318 }
319
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700320 public CameraMetadataNative() {
321 super();
322 mMetadataPtr = nativeAllocate();
323 if (mMetadataPtr == 0) {
324 throw new OutOfMemoryError("Failed to allocate native CameraMetadata");
325 }
326 }
327
328 /**
329 * Copy constructor - clone metadata
330 */
331 public CameraMetadataNative(CameraMetadataNative other) {
332 super();
333 mMetadataPtr = nativeAllocateCopy(other);
334 if (mMetadataPtr == 0) {
335 throw new OutOfMemoryError("Failed to allocate native CameraMetadata");
336 }
337 }
338
Igor Murashkind6d65152014-05-19 16:31:02 -0700339 /**
340 * Move the contents from {@code other} into a new camera metadata instance.</p>
341 *
342 * <p>After this call, {@code other} will become empty.</p>
343 *
344 * @param other the previous metadata instance which will get pilfered
345 * @return a new metadata instance with the values from {@code other} moved into it
346 */
347 public static CameraMetadataNative move(CameraMetadataNative other) {
348 CameraMetadataNative newObject = new CameraMetadataNative();
349 newObject.swap(other);
350 return newObject;
351 }
352
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700353 public static final @android.annotation.NonNull Parcelable.Creator<CameraMetadataNative> CREATOR =
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700354 new Parcelable.Creator<CameraMetadataNative>() {
355 @Override
356 public CameraMetadataNative createFromParcel(Parcel in) {
357 CameraMetadataNative metadata = new CameraMetadataNative();
358 metadata.readFromParcel(in);
359 return metadata;
360 }
361
362 @Override
363 public CameraMetadataNative[] newArray(int size) {
364 return new CameraMetadataNative[size];
365 }
366 };
367
368 @Override
369 public int describeContents() {
370 return 0;
371 }
372
373 @Override
374 public void writeToParcel(Parcel dest, int flags) {
375 nativeWriteToParcel(dest);
376 }
377
Igor Murashkind6d65152014-05-19 16:31:02 -0700378 /**
379 * @hide
380 */
381 public <T> T get(CameraCharacteristics.Key<T> key) {
382 return get(key.getNativeKey());
383 }
384
385 /**
386 * @hide
387 */
388 public <T> T get(CaptureResult.Key<T> key) {
389 return get(key.getNativeKey());
390 }
391
392 /**
393 * @hide
394 */
395 public <T> T get(CaptureRequest.Key<T> key) {
396 return get(key.getNativeKey());
397 }
398
399 /**
400 * Look-up a metadata field value by its key.
401 *
402 * @param key a non-{@code null} key instance
403 * @return the field corresponding to the {@code key}, or {@code null} if no value was set
404 */
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700405 public <T> T get(Key<T> key) {
Igor Murashkind6d65152014-05-19 16:31:02 -0700406 Preconditions.checkNotNull(key, "key must not be null");
407
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700408 // Check if key has been overridden to use a wrapper class on the java side.
409 GetCommand g = sGetCommandMap.get(key);
410 if (g != null) {
Igor Murashkin0a1ef4d2014-07-31 15:53:34 -0700411 return g.getValue(this, key);
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700412 }
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700413 return getBase(key);
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700414 }
415
416 public void readFromParcel(Parcel in) {
417 nativeReadFromParcel(in);
418 }
419
420 /**
Ruben Brunk85c43882014-02-21 17:40:51 -0800421 * Set the global client-side vendor tag descriptor to allow use of vendor
422 * tags in camera applications.
423 *
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800424 * @throws ServiceSpecificException
Ruben Brunk85c43882014-02-21 17:40:51 -0800425 * @hide
426 */
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800427 public static void setupGlobalVendorTagDescriptor() throws ServiceSpecificException {
428 int err = nativeSetupGlobalVendorTagDescriptor();
429 if (err != 0) {
430 throw new ServiceSpecificException(err, "Failure to set up global vendor tags");
431 }
432 }
433
434 /**
435 * Set the global client-side vendor tag descriptor to allow use of vendor
436 * tags in camera applications.
437 *
438 * @return int An error code corresponding to one of the
439 * {@link ICameraService} error constants, or 0 on success.
440 */
441 private static native int nativeSetupGlobalVendorTagDescriptor();
Ruben Brunk85c43882014-02-21 17:40:51 -0800442
443 /**
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700444 * Set a camera metadata field to a value. The field definitions can be
Igor Murashkin68f40062013-09-10 12:15:54 -0700445 * found in {@link CameraCharacteristics}, {@link CaptureResult}, and
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700446 * {@link CaptureRequest}.
447 *
448 * @param key The metadata field to write.
449 * @param value The value to set the field to, which must be of a matching
450 * type to the key.
451 */
452 public <T> void set(Key<T> key, T value) {
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700453 SetCommand s = sSetCommandMap.get(key);
454 if (s != null) {
455 s.setValue(this, value);
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700456 return;
457 }
458
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700459 setBase(key, value);
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700460 }
461
Igor Murashkind6d65152014-05-19 16:31:02 -0700462 public <T> void set(CaptureRequest.Key<T> key, T value) {
463 set(key.getNativeKey(), value);
464 }
465
466 public <T> void set(CaptureResult.Key<T> key, T value) {
467 set(key.getNativeKey(), value);
468 }
469
470 public <T> void set(CameraCharacteristics.Key<T> key, T value) {
471 set(key.getNativeKey(), value);
472 }
473
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700474 // Keep up-to-date with camera_metadata.h
475 /**
476 * @hide
477 */
478 public static final int TYPE_BYTE = 0;
479 /**
480 * @hide
481 */
482 public static final int TYPE_INT32 = 1;
483 /**
484 * @hide
485 */
486 public static final int TYPE_FLOAT = 2;
487 /**
488 * @hide
489 */
490 public static final int TYPE_INT64 = 3;
491 /**
492 * @hide
493 */
494 public static final int TYPE_DOUBLE = 4;
495 /**
496 * @hide
497 */
498 public static final int TYPE_RATIONAL = 5;
499 /**
500 * @hide
501 */
502 public static final int NUM_TYPES = 6;
503
504 private void close() {
505 // this sets mMetadataPtr to 0
506 nativeClose();
507 mMetadataPtr = 0; // set it to 0 again to prevent eclipse from making this field final
508 }
509
Igor Murashkind6d65152014-05-19 16:31:02 -0700510 private <T> T getBase(CameraCharacteristics.Key<T> key) {
511 return getBase(key.getNativeKey());
512 }
513
514 private <T> T getBase(CaptureResult.Key<T> key) {
515 return getBase(key.getNativeKey());
516 }
517
518 private <T> T getBase(CaptureRequest.Key<T> key) {
519 return getBase(key.getNativeKey());
520 }
521
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700522 private <T> T getBase(Key<T> key) {
Emilian Peevde62d842017-03-23 19:20:40 +0000523 int tag = nativeGetTagFromKeyLocal(key.getName());
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700524 byte[] values = readValues(tag);
525 if (values == null) {
Justin Yunf01e40c2018-05-18 20:39:45 +0900526 // If the key returns null, use the fallback key if exists.
527 // This is to support old key names for the newly published keys.
528 if (key.mFallbackName == null) {
529 return null;
530 }
531 tag = nativeGetTagFromKeyLocal(key.mFallbackName);
532 values = readValues(tag);
533 if (values == null) {
534 return null;
535 }
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700536 }
537
Emilian Peevde62d842017-03-23 19:20:40 +0000538 int nativeType = nativeGetTypeFromTagLocal(tag);
539 Marshaler<T> marshaler = getMarshalerForKey(key, nativeType);
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700540 ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
Igor Murashkin3c40a042014-04-22 15:05:50 -0700541 return marshaler.unmarshal(buffer);
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700542 }
Igor Murashkin78712a82014-05-27 18:32:18 -0700543
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700544 // Use Command pattern here to avoid lots of expensive if/equals checks in get for overridden
545 // metadata.
546 private static final HashMap<Key<?>, GetCommand> sGetCommandMap =
547 new HashMap<Key<?>, GetCommand>();
548 static {
549 sGetCommandMap.put(
550 CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey(), new GetCommand() {
551 @Override
552 @SuppressWarnings("unchecked")
553 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
554 return (T) metadata.getAvailableFormats();
555 }
556 });
557 sGetCommandMap.put(
558 CaptureResult.STATISTICS_FACES.getNativeKey(), new GetCommand() {
559 @Override
560 @SuppressWarnings("unchecked")
561 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
Ruben Brunk40001f52014-07-17 11:02:28 -0700562 return (T) metadata.getFaces();
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700563 }
564 });
565 sGetCommandMap.put(
566 CaptureResult.STATISTICS_FACE_RECTANGLES.getNativeKey(), new GetCommand() {
567 @Override
568 @SuppressWarnings("unchecked")
569 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
Ruben Brunk40001f52014-07-17 11:02:28 -0700570 return (T) metadata.getFaceRectangles();
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700571 }
572 });
573 sGetCommandMap.put(
574 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP.getNativeKey(),
575 new GetCommand() {
576 @Override
577 @SuppressWarnings("unchecked")
578 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
579 return (T) metadata.getStreamConfigurationMap();
580 }
581 });
582 sGetCommandMap.put(
Emilian Peev423cbd72018-11-10 18:37:45 +0000583 CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS.getNativeKey(),
584 new GetCommand() {
585 @Override
586 @SuppressWarnings("unchecked")
587 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
588 return (T) metadata.getMandatoryStreamCombinations();
589 }
590 });
591 sGetCommandMap.put(
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700592 CameraCharacteristics.CONTROL_MAX_REGIONS_AE.getNativeKey(), new GetCommand() {
593 @Override
594 @SuppressWarnings("unchecked")
595 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
596 return (T) metadata.getMaxRegions(key);
597 }
598 });
599 sGetCommandMap.put(
600 CameraCharacteristics.CONTROL_MAX_REGIONS_AWB.getNativeKey(), new GetCommand() {
601 @Override
602 @SuppressWarnings("unchecked")
603 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
604 return (T) metadata.getMaxRegions(key);
605 }
606 });
607 sGetCommandMap.put(
608 CameraCharacteristics.CONTROL_MAX_REGIONS_AF.getNativeKey(), new GetCommand() {
609 @Override
610 @SuppressWarnings("unchecked")
611 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
612 return (T) metadata.getMaxRegions(key);
613 }
614 });
615 sGetCommandMap.put(
616 CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW.getNativeKey(), new GetCommand() {
617 @Override
618 @SuppressWarnings("unchecked")
619 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
620 return (T) metadata.getMaxNumOutputs(key);
621 }
622 });
623 sGetCommandMap.put(
624 CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC.getNativeKey(), new GetCommand() {
625 @Override
626 @SuppressWarnings("unchecked")
627 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
628 return (T) metadata.getMaxNumOutputs(key);
629 }
630 });
631 sGetCommandMap.put(
632 CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING.getNativeKey(),
633 new GetCommand() {
634 @Override
635 @SuppressWarnings("unchecked")
636 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
637 return (T) metadata.getMaxNumOutputs(key);
638 }
639 });
640 sGetCommandMap.put(
641 CaptureRequest.TONEMAP_CURVE.getNativeKey(), new GetCommand() {
642 @Override
643 @SuppressWarnings("unchecked")
644 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
645 return (T) metadata.getTonemapCurve();
646 }
647 });
648 sGetCommandMap.put(
649 CaptureResult.JPEG_GPS_LOCATION.getNativeKey(), new GetCommand() {
650 @Override
651 @SuppressWarnings("unchecked")
652 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
653 return (T) metadata.getGpsLocation();
654 }
655 });
656 sGetCommandMap.put(
657 CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP.getNativeKey(),
658 new GetCommand() {
659 @Override
660 @SuppressWarnings("unchecked")
661 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
662 return (T) metadata.getLensShadingMap();
663 }
664 });
Chien-Yu Chenc804d1c2018-02-15 12:44:19 -0800665 sGetCommandMap.put(
666 CaptureResult.STATISTICS_OIS_SAMPLES.getNativeKey(),
667 new GetCommand() {
668 @Override
669 @SuppressWarnings("unchecked")
670 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
671 return (T) metadata.getOisSamples();
672 }
673 });
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700674 }
675
676 private int[] getAvailableFormats() {
677 int[] availableFormats = getBase(CameraCharacteristics.SCALER_AVAILABLE_FORMATS);
Zhijun He2f1680b2013-11-13 13:16:56 -0800678 if (availableFormats != null) {
679 for (int i = 0; i < availableFormats.length; i++) {
680 // JPEG has different value between native and managed side, need override.
681 if (availableFormats[i] == NATIVE_JPEG_FORMAT) {
682 availableFormats[i] = ImageFormat.JPEG;
683 }
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700684 }
685 }
Zhijun He2f1680b2013-11-13 13:16:56 -0800686
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700687 return availableFormats;
688 }
689
Igor Murashkin0a1ef4d2014-07-31 15:53:34 -0700690 private boolean setFaces(Face[] faces) {
691 if (faces == null) {
692 return false;
693 }
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700694
Igor Murashkin0a1ef4d2014-07-31 15:53:34 -0700695 int numFaces = faces.length;
696
697 // Detect if all faces are SIMPLE or not; count # of valid faces
698 boolean fullMode = true;
699 for (Face face : faces) {
700 if (face == null) {
701 numFaces--;
702 Log.w(TAG, "setFaces - null face detected, skipping");
703 continue;
704 }
705
706 if (face.getId() == Face.ID_UNSUPPORTED) {
707 fullMode = false;
708 }
709 }
710
711 Rect[] faceRectangles = new Rect[numFaces];
712 byte[] faceScores = new byte[numFaces];
713 int[] faceIds = null;
714 int[] faceLandmarks = null;
715
716 if (fullMode) {
717 faceIds = new int[numFaces];
718 faceLandmarks = new int[numFaces * FACE_LANDMARK_SIZE];
719 }
720
721 int i = 0;
722 for (Face face : faces) {
723 if (face == null) {
724 continue;
725 }
726
727 faceRectangles[i] = face.getBounds();
728 faceScores[i] = (byte)face.getScore();
729
730 if (fullMode) {
731 faceIds[i] = face.getId();
732
733 int j = 0;
734
735 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getLeftEyePosition().x;
736 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getLeftEyePosition().y;
737 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getRightEyePosition().x;
738 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getRightEyePosition().y;
739 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getMouthPosition().x;
740 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getMouthPosition().y;
741 }
742
743 i++;
744 }
745
746 set(CaptureResult.STATISTICS_FACE_RECTANGLES, faceRectangles);
747 set(CaptureResult.STATISTICS_FACE_IDS, faceIds);
748 set(CaptureResult.STATISTICS_FACE_LANDMARKS, faceLandmarks);
749 set(CaptureResult.STATISTICS_FACE_SCORES, faceScores);
750
751 return true;
752 }
753
754 private Face[] getFaces() {
Zhijun He58216c22013-10-14 15:29:37 -0700755 Integer faceDetectMode = get(CaptureResult.STATISTICS_FACE_DETECT_MODE);
Yin-Chia Yehd47699a2014-08-28 10:35:37 -0700756 byte[] faceScores = get(CaptureResult.STATISTICS_FACE_SCORES);
757 Rect[] faceRectangles = get(CaptureResult.STATISTICS_FACE_RECTANGLES);
758 int[] faceIds = get(CaptureResult.STATISTICS_FACE_IDS);
759 int[] faceLandmarks = get(CaptureResult.STATISTICS_FACE_LANDMARKS);
760
761 if (areValuesAllNull(faceDetectMode, faceScores, faceRectangles, faceIds, faceLandmarks)) {
762 return null;
763 }
764
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700765 if (faceDetectMode == null) {
Zhijun He58216c22013-10-14 15:29:37 -0700766 Log.w(TAG, "Face detect mode metadata is null, assuming the mode is SIMPLE");
767 faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE;
Donghui Han5f967a32018-07-10 16:32:39 -0700768 } else if (faceDetectMode > CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) {
769 // Face detect mode is larger than FULL, assuming the mode is FULL
770 faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL;
Zhijun He58216c22013-10-14 15:29:37 -0700771 } else {
772 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_OFF) {
773 return new Face[0];
774 }
775 if (faceDetectMode != CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE &&
776 faceDetectMode != CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) {
777 Log.w(TAG, "Unknown face detect mode: " + faceDetectMode);
778 return new Face[0];
779 }
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700780 }
781
782 // Face scores and rectangles are required by SIMPLE and FULL mode.
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700783 if (faceScores == null || faceRectangles == null) {
Zhijun He58216c22013-10-14 15:29:37 -0700784 Log.w(TAG, "Expect face scores and rectangles to be non-null");
785 return new Face[0];
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700786 } else if (faceScores.length != faceRectangles.length) {
Zhijun He58216c22013-10-14 15:29:37 -0700787 Log.w(TAG, String.format("Face score size(%d) doesn match face rectangle size(%d)!",
788 faceScores.length, faceRectangles.length));
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700789 }
790
Zhijun He58216c22013-10-14 15:29:37 -0700791 // To be safe, make number of faces is the minimal of all face info metadata length.
792 int numFaces = Math.min(faceScores.length, faceRectangles.length);
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700793 // Face id and landmarks are only required by FULL mode.
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700794 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) {
795 if (faceIds == null || faceLandmarks == null) {
Zhijun He58216c22013-10-14 15:29:37 -0700796 Log.w(TAG, "Expect face ids and landmarks to be non-null for FULL mode," +
797 "fallback to SIMPLE mode");
798 faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE;
799 } else {
800 if (faceIds.length != numFaces ||
801 faceLandmarks.length != numFaces * FACE_LANDMARK_SIZE) {
802 Log.w(TAG, String.format("Face id size(%d), or face landmark size(%d) don't" +
803 "match face number(%d)!",
804 faceIds.length, faceLandmarks.length * FACE_LANDMARK_SIZE, numFaces));
805 }
806 // To be safe, make number of faces is the minimal of all face info metadata length.
807 numFaces = Math.min(numFaces, faceIds.length);
808 numFaces = Math.min(numFaces, faceLandmarks.length / FACE_LANDMARK_SIZE);
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700809 }
810 }
811
Zhijun He844b3522013-10-16 16:13:50 -0700812 ArrayList<Face> faceList = new ArrayList<Face>();
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700813 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE) {
814 for (int i = 0; i < numFaces; i++) {
Zhijun He844b3522013-10-16 16:13:50 -0700815 if (faceScores[i] <= Face.SCORE_MAX &&
816 faceScores[i] >= Face.SCORE_MIN) {
817 faceList.add(new Face(faceRectangles[i], faceScores[i]));
818 }
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700819 }
820 } else {
821 // CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL
822 for (int i = 0; i < numFaces; i++) {
Zhijun He844b3522013-10-16 16:13:50 -0700823 if (faceScores[i] <= Face.SCORE_MAX &&
824 faceScores[i] >= Face.SCORE_MIN &&
825 faceIds[i] >= 0) {
Igor Murashkin0a1ef4d2014-07-31 15:53:34 -0700826 Point leftEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE],
827 faceLandmarks[i*FACE_LANDMARK_SIZE+1]);
828 Point rightEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+2],
829 faceLandmarks[i*FACE_LANDMARK_SIZE+3]);
830 Point mouth = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+4],
831 faceLandmarks[i*FACE_LANDMARK_SIZE+5]);
Zhijun He844b3522013-10-16 16:13:50 -0700832 Face face = new Face(faceRectangles[i], faceScores[i], faceIds[i],
833 leftEye, rightEye, mouth);
834 faceList.add(face);
835 }
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700836 }
837 }
Zhijun He844b3522013-10-16 16:13:50 -0700838 Face[] faces = new Face[faceList.size()];
839 faceList.toArray(faces);
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700840 return faces;
841 }
842
Eino-Ville Talvala615b75f2013-10-14 18:20:43 -0700843 // Face rectangles are defined as (left, top, right, bottom) instead of
844 // (left, top, width, height) at the native level, so the normal Rect
845 // conversion that does (l, t, w, h) -> (l, t, r, b) is unnecessary. Undo
846 // that conversion here for just the faces.
Zhijun He2f1680b2013-11-13 13:16:56 -0800847 private Rect[] getFaceRectangles() {
Eino-Ville Talvala615b75f2013-10-14 18:20:43 -0700848 Rect[] faceRectangles = getBase(CaptureResult.STATISTICS_FACE_RECTANGLES);
849 if (faceRectangles == null) return null;
850
851 Rect[] fixedFaceRectangles = new Rect[faceRectangles.length];
852 for (int i = 0; i < faceRectangles.length; i++) {
853 fixedFaceRectangles[i] = new Rect(
854 faceRectangles[i].left,
855 faceRectangles[i].top,
856 faceRectangles[i].right - faceRectangles[i].left,
857 faceRectangles[i].bottom - faceRectangles[i].top);
858 }
859 return fixedFaceRectangles;
860 }
861
Ruben Brunk57493682014-05-27 18:58:08 -0700862 private LensShadingMap getLensShadingMap() {
863 float[] lsmArray = getBase(CaptureResult.STATISTICS_LENS_SHADING_MAP);
Yin-Chia Yehd47699a2014-08-28 10:35:37 -0700864 Size s = get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE);
865
866 // Do not warn if lsmArray is null while s is not. This is valid.
Ruben Brunk57493682014-05-27 18:58:08 -0700867 if (lsmArray == null) {
Ruben Brunk57493682014-05-27 18:58:08 -0700868 return null;
869 }
Yin-Chia Yehd47699a2014-08-28 10:35:37 -0700870
871 if (s == null) {
872 Log.w(TAG, "getLensShadingMap - Lens shading map size was null.");
873 return null;
874 }
875
Ruben Brunk57493682014-05-27 18:58:08 -0700876 LensShadingMap map = new LensShadingMap(lsmArray, s.getHeight(), s.getWidth());
877 return map;
878 }
879
880 private Location getGpsLocation() {
881 String processingMethod = get(CaptureResult.JPEG_GPS_PROCESSING_METHOD);
Ruben Brunk57493682014-05-27 18:58:08 -0700882 double[] coords = get(CaptureResult.JPEG_GPS_COORDINATES);
Emilian Peevd0084792017-01-31 15:29:20 +0000883 Long timeStamp = get(CaptureResult.JPEG_GPS_TIMESTAMP);
Ruben Brunk57493682014-05-27 18:58:08 -0700884
Yin-Chia Yehd47699a2014-08-28 10:35:37 -0700885 if (areValuesAllNull(processingMethod, coords, timeStamp)) {
886 return null;
887 }
888
889 Location l = new Location(translateProcessToLocationProvider(processingMethod));
Ruben Brunk57493682014-05-27 18:58:08 -0700890 if (timeStamp != null) {
Emilian Peevd0084792017-01-31 15:29:20 +0000891 // Location expects timestamp in [ms.]
892 l.setTime(timeStamp * 1000);
Ruben Brunk57493682014-05-27 18:58:08 -0700893 } else {
894 Log.w(TAG, "getGpsLocation - No timestamp for GPS location.");
895 }
896
897 if (coords != null) {
898 l.setLatitude(coords[0]);
899 l.setLongitude(coords[1]);
900 l.setAltitude(coords[2]);
901 } else {
902 Log.w(TAG, "getGpsLocation - No coordinates for GPS location");
903 }
904
905 return l;
906 }
907
908 private boolean setGpsLocation(Location l) {
909 if (l == null) {
910 return false;
911 }
912
913 double[] coords = { l.getLatitude(), l.getLongitude(), l.getAltitude() };
914 String processMethod = translateLocationProviderToProcess(l.getProvider());
Emilian Peev8f240962017-01-26 08:39:54 -0800915 //JPEG_GPS_TIMESTAMP expects sec. instead of msec.
916 long timestamp = l.getTime() / 1000;
Ruben Brunk57493682014-05-27 18:58:08 -0700917
918 set(CaptureRequest.JPEG_GPS_TIMESTAMP, timestamp);
919 set(CaptureRequest.JPEG_GPS_COORDINATES, coords);
920
921 if (processMethod == null) {
922 Log.w(TAG, "setGpsLocation - No process method, Location is not from a GPS or NETWORK" +
923 "provider");
924 } else {
925 setBase(CaptureRequest.JPEG_GPS_PROCESSING_METHOD, processMethod);
926 }
927 return true;
928 }
929
Emilian Peev2776ca32018-09-18 14:00:39 +0100930 private void parseRecommendedConfigurations(RecommendedStreamConfiguration[] configurations,
931 StreamConfigurationMap fullMap, boolean isDepth,
932 ArrayList<ArrayList<StreamConfiguration>> /*out*/streamConfigList,
933 ArrayList<ArrayList<StreamConfigurationDuration>> /*out*/streamDurationList,
934 ArrayList<ArrayList<StreamConfigurationDuration>> /*out*/streamStallList,
935 boolean[] /*out*/supportsPrivate) {
936
937 streamConfigList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT);
938 streamDurationList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT);
939 streamStallList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT);
940 for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) {
941 streamConfigList.add(new ArrayList<StreamConfiguration> ());
942 streamDurationList.add(new ArrayList<StreamConfigurationDuration> ());
943 streamStallList.add(new ArrayList<StreamConfigurationDuration> ());
944 }
945
946 for (RecommendedStreamConfiguration c : configurations) {
947 int width = c.getWidth();
948 int height = c.getHeight();
949 int internalFormat = c.getFormat();
950 int publicFormat =
951 (isDepth) ? StreamConfigurationMap.depthFormatToPublic(internalFormat) :
952 StreamConfigurationMap.imageFormatToPublic(internalFormat);
953 Size sz = new Size(width, height);
954 int usecaseBitmap = c.getUsecaseBitmap();
955
956 if (!c.isInput()) {
957 StreamConfigurationDuration minDurationConfiguration = null;
958 StreamConfigurationDuration stallDurationConfiguration = null;
959
960 StreamConfiguration streamConfiguration = new StreamConfiguration(internalFormat,
961 width, height, /*input*/ false);
962
963 long minFrameDuration = fullMap.getOutputMinFrameDuration(publicFormat, sz);
964 if (minFrameDuration > 0) {
965 minDurationConfiguration = new StreamConfigurationDuration(internalFormat,
966 width, height, minFrameDuration);
967 }
968
969 long stallDuration = fullMap.getOutputStallDuration(publicFormat, sz);
970 if (stallDuration > 0) {
971 stallDurationConfiguration = new StreamConfigurationDuration(internalFormat,
972 width, height, stallDuration);
973 }
974
975 for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) {
976 if ((usecaseBitmap & (1 << i)) != 0) {
977 ArrayList<StreamConfiguration> sc = streamConfigList.get(i);
978 sc.add(streamConfiguration);
979
980 if (minFrameDuration > 0) {
981 ArrayList<StreamConfigurationDuration> scd = streamDurationList.get(i);
982 scd.add(minDurationConfiguration);
983 }
984
985 if (stallDuration > 0) {
986 ArrayList<StreamConfigurationDuration> scs = streamStallList.get(i);
987 scs.add(stallDurationConfiguration);
988 }
989
990 if ((supportsPrivate != null) && !supportsPrivate[i] &&
991 (publicFormat == ImageFormat.PRIVATE)) {
992 supportsPrivate[i] = true;
993 }
994 }
995 }
996 } else {
997 if (usecaseBitmap != (1 << RecommendedStreamConfigurationMap.USECASE_ZSL)) {
998 throw new IllegalArgumentException("Recommended input stream configurations " +
999 "should only be advertised in the ZSL use case!");
1000 }
1001
1002 ArrayList<StreamConfiguration> sc = streamConfigList.get(
1003 RecommendedStreamConfigurationMap.USECASE_ZSL);
1004 sc.add(new StreamConfiguration(internalFormat,
1005 width, height, /*input*/ true));
1006 }
1007 }
1008 }
1009
1010 private class StreamConfigurationData {
1011 StreamConfiguration [] streamConfigurationArray = null;
1012 StreamConfigurationDuration [] minDurationArray = null;
1013 StreamConfigurationDuration [] stallDurationArray = null;
1014 }
1015
1016 public void initializeStreamConfigurationData(ArrayList<StreamConfiguration> sc,
1017 ArrayList<StreamConfigurationDuration> scd, ArrayList<StreamConfigurationDuration> scs,
1018 StreamConfigurationData /*out*/scData) {
1019 if ((scData == null) || (sc == null)) {
1020 return;
1021 }
1022
1023 scData.streamConfigurationArray = new StreamConfiguration[sc.size()];
1024 scData.streamConfigurationArray = sc.toArray(scData.streamConfigurationArray);
1025
1026 if ((scd != null) && !scd.isEmpty()) {
1027 scData.minDurationArray = new StreamConfigurationDuration[scd.size()];
1028 scData.minDurationArray = scd.toArray(scData.minDurationArray);
1029 } else {
1030 scData.minDurationArray = new StreamConfigurationDuration[0];
1031 }
1032
1033 if ((scs != null) && !scs.isEmpty()) {
1034 scData.stallDurationArray = new StreamConfigurationDuration[scs.size()];
1035 scData.stallDurationArray = scs.toArray(scData.stallDurationArray);
1036 } else {
1037 scData.stallDurationArray = new StreamConfigurationDuration[0];
1038 }
1039 }
1040
1041 /**
1042 * Retrieve the list of recommended stream configurations.
1043 *
1044 * @return A list of recommended stream configuration maps for each common use case or null
1045 * in case the recommended stream configurations are invalid or incomplete.
1046 * @hide
1047 */
1048 public ArrayList<RecommendedStreamConfigurationMap> getRecommendedStreamConfigurations() {
1049 RecommendedStreamConfiguration[] configurations = getBase(
1050 CameraCharacteristics.SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS);
1051 RecommendedStreamConfiguration[] depthConfigurations = getBase(
1052 CameraCharacteristics.DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS);
1053 if ((configurations == null) && (depthConfigurations == null)) {
1054 return null;
1055 }
1056
1057 StreamConfigurationMap fullMap = getStreamConfigurationMap();
1058 ArrayList<RecommendedStreamConfigurationMap> recommendedConfigurations =
1059 new ArrayList<RecommendedStreamConfigurationMap> ();
1060
1061 ArrayList<ArrayList<StreamConfiguration>> streamConfigList =
1062 new ArrayList<ArrayList<StreamConfiguration>>();
1063 ArrayList<ArrayList<StreamConfigurationDuration>> streamDurationList =
1064 new ArrayList<ArrayList<StreamConfigurationDuration>>();
1065 ArrayList<ArrayList<StreamConfigurationDuration>> streamStallList =
1066 new ArrayList<ArrayList<StreamConfigurationDuration>>();
1067 boolean[] supportsPrivate =
1068 new boolean[RecommendedStreamConfigurationMap.MAX_USECASE_COUNT];
1069 try {
1070 if (configurations != null) {
1071 parseRecommendedConfigurations(configurations, fullMap, /*isDepth*/ false,
1072 streamConfigList, streamDurationList, streamStallList, supportsPrivate);
1073 }
1074 } catch (IllegalArgumentException e) {
1075 Log.e(TAG, "Failed parsing the recommended stream configurations!");
1076 return null;
1077 }
1078
1079 ArrayList<ArrayList<StreamConfiguration>> depthStreamConfigList =
1080 new ArrayList<ArrayList<StreamConfiguration>>();
1081 ArrayList<ArrayList<StreamConfigurationDuration>> depthStreamDurationList =
1082 new ArrayList<ArrayList<StreamConfigurationDuration>>();
1083 ArrayList<ArrayList<StreamConfigurationDuration>> depthStreamStallList =
1084 new ArrayList<ArrayList<StreamConfigurationDuration>>();
1085 if (depthConfigurations != null) {
1086 try {
1087 parseRecommendedConfigurations(depthConfigurations, fullMap, /*isDepth*/ true,
1088 depthStreamConfigList, depthStreamDurationList, depthStreamStallList,
1089 /*supportsPrivate*/ null);
1090 } catch (IllegalArgumentException e) {
1091 Log.e(TAG, "Failed parsing the recommended depth stream configurations!");
1092 return null;
1093 }
1094 }
1095
1096 ReprocessFormatsMap inputOutputFormatsMap = getBase(
1097 CameraCharacteristics.SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP);
1098 HighSpeedVideoConfiguration[] highSpeedVideoConfigurations = getBase(
1099 CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
1100 boolean listHighResolution = isBurstSupported();
1101 recommendedConfigurations.ensureCapacity(
1102 RecommendedStreamConfigurationMap.MAX_USECASE_COUNT);
1103 for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) {
1104 StreamConfigurationData scData = new StreamConfigurationData();
1105 if (configurations != null) {
1106 initializeStreamConfigurationData(streamConfigList.get(i),
1107 streamDurationList.get(i), streamStallList.get(i), scData);
1108 }
1109
1110 StreamConfigurationData depthScData = new StreamConfigurationData();
1111 if (depthConfigurations != null) {
1112 initializeStreamConfigurationData(depthStreamConfigList.get(i),
1113 depthStreamDurationList.get(i), depthStreamStallList.get(i), depthScData);
1114 }
1115
1116 if ((scData.streamConfigurationArray == null) &&
1117 (depthScData.streamConfigurationArray == null)) {
1118 recommendedConfigurations.add(null);
1119 continue;
1120 }
1121
Emilian Peev934ffa62019-01-04 17:48:31 +00001122 // Dynamic depth streams involve alot of SW processing and currently cannot be
1123 // recommended.
Emilian Peev2776ca32018-09-18 14:00:39 +01001124 StreamConfigurationMap map = null;
1125 switch (i) {
1126 case RecommendedStreamConfigurationMap.USECASE_PREVIEW:
1127 case RecommendedStreamConfigurationMap.USECASE_RAW:
1128 case RecommendedStreamConfigurationMap.USECASE_VIDEO_SNAPSHOT:
1129 map = new StreamConfigurationMap(scData.streamConfigurationArray,
1130 scData.minDurationArray, scData.stallDurationArray,
1131 /*depthconfiguration*/ null, /*depthminduration*/ null,
Emilian Peev934ffa62019-01-04 17:48:31 +00001132 /*depthstallduration*/ null,
1133 /*dynamicDepthConfigurations*/ null,
1134 /*dynamicDepthMinFrameDurations*/ null,
1135 /*dynamicDepthStallDurations*/ null,
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001136 /*heicconfiguration*/ null,
1137 /*heicminduration*/ null,
1138 /*heicstallduration*/ null,
Emilian Peev934ffa62019-01-04 17:48:31 +00001139 /*highspeedvideoconfigurations*/ null,
Emilian Peev2776ca32018-09-18 14:00:39 +01001140 /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]);
1141 break;
1142 case RecommendedStreamConfigurationMap.USECASE_RECORD:
1143 map = new StreamConfigurationMap(scData.streamConfigurationArray,
1144 scData.minDurationArray, scData.stallDurationArray,
1145 /*depthconfiguration*/ null, /*depthminduration*/ null,
Emilian Peev934ffa62019-01-04 17:48:31 +00001146 /*depthstallduration*/ null,
1147 /*dynamicDepthConfigurations*/ null,
1148 /*dynamicDepthMinFrameDurations*/ null,
1149 /*dynamicDepthStallDurations*/ null,
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001150 /*heicconfiguration*/ null,
1151 /*heicminduration*/ null,
1152 /*heicstallduration*/ null,
Emilian Peev934ffa62019-01-04 17:48:31 +00001153 highSpeedVideoConfigurations,
Emilian Peev2776ca32018-09-18 14:00:39 +01001154 /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]);
1155 break;
1156 case RecommendedStreamConfigurationMap.USECASE_ZSL:
1157 map = new StreamConfigurationMap(scData.streamConfigurationArray,
1158 scData.minDurationArray, scData.stallDurationArray,
1159 depthScData.streamConfigurationArray, depthScData.minDurationArray,
Emilian Peev934ffa62019-01-04 17:48:31 +00001160 depthScData.stallDurationArray,
1161 /*dynamicDepthConfigurations*/ null,
1162 /*dynamicDepthMinFrameDurations*/ null,
1163 /*dynamicDepthStallDurations*/ null,
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001164 /*heicconfiguration*/ null,
1165 /*heicminduration*/ null,
1166 /*heicstallduration*/ null,
Emilian Peev934ffa62019-01-04 17:48:31 +00001167 /*highSpeedVideoConfigurations*/ null,
Emilian Peev2776ca32018-09-18 14:00:39 +01001168 inputOutputFormatsMap, listHighResolution, supportsPrivate[i]);
1169 break;
1170 default:
1171 map = new StreamConfigurationMap(scData.streamConfigurationArray,
1172 scData.minDurationArray, scData.stallDurationArray,
1173 depthScData.streamConfigurationArray, depthScData.minDurationArray,
Emilian Peev934ffa62019-01-04 17:48:31 +00001174 depthScData.stallDurationArray,
1175 /*dynamicDepthConfigurations*/ null,
1176 /*dynamicDepthMinFrameDurations*/ null,
1177 /*dynamicDepthStallDurations*/ null,
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001178 /*heicconfiguration*/ null,
1179 /*heicminduration*/ null,
1180 /*heicstallduration*/ null,
Emilian Peev934ffa62019-01-04 17:48:31 +00001181 /*highSpeedVideoConfigurations*/ null,
Emilian Peev2776ca32018-09-18 14:00:39 +01001182 /*inputOutputFormatsMap*/ null, listHighResolution, supportsPrivate[i]);
1183 }
1184
1185 recommendedConfigurations.add(new RecommendedStreamConfigurationMap(map, /*usecase*/i,
1186 supportsPrivate[i]));
1187 }
1188
1189 return recommendedConfigurations;
1190 }
1191
1192 private boolean isBurstSupported() {
1193 boolean ret = false;
1194
1195 int[] capabilities = getBase(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
1196 for (int capability : capabilities) {
1197 if (capability == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE) {
1198 ret = true;
1199 break;
1200 }
1201 }
1202
1203 return ret;
1204 }
1205
Emilian Peev423cbd72018-11-10 18:37:45 +00001206 private MandatoryStreamCombination[] getMandatoryStreamCombinations() {
1207 int[] capabilities = getBase(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
1208 ArrayList<Integer> caps = new ArrayList<Integer>();
1209 caps.ensureCapacity(capabilities.length);
1210 for (int c : capabilities) {
1211 caps.add(new Integer(c));
1212 }
1213 int hwLevel = getBase(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
1214 MandatoryStreamCombination.Builder build = new MandatoryStreamCombination.Builder(
1215 mCameraId, hwLevel, mDisplaySize, caps, getStreamConfigurationMap());
1216 List<MandatoryStreamCombination> combs = build.getAvailableMandatoryStreamCombinations();
1217 if ((combs != null) && (!combs.isEmpty())) {
1218 MandatoryStreamCombination[] combArray = new MandatoryStreamCombination[combs.size()];
1219 combArray = combs.toArray(combArray);
1220 return combArray;
1221 }
1222
1223 return null;
1224 }
1225
Igor Murashkin9c595172014-05-12 13:56:20 -07001226 private StreamConfigurationMap getStreamConfigurationMap() {
1227 StreamConfiguration[] configurations = getBase(
1228 CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
1229 StreamConfigurationDuration[] minFrameDurations = getBase(
1230 CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
1231 StreamConfigurationDuration[] stallDurations = getBase(
1232 CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS);
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001233 StreamConfiguration[] depthConfigurations = getBase(
1234 CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS);
1235 StreamConfigurationDuration[] depthMinFrameDurations = getBase(
1236 CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS);
1237 StreamConfigurationDuration[] depthStallDurations = getBase(
1238 CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS);
Emilian Peev934ffa62019-01-04 17:48:31 +00001239 StreamConfiguration[] dynamicDepthConfigurations = getBase(
1240 CameraCharacteristics.DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS);
1241 StreamConfigurationDuration[] dynamicDepthMinFrameDurations = getBase(
1242 CameraCharacteristics.DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS);
1243 StreamConfigurationDuration[] dynamicDepthStallDurations = getBase(
1244 CameraCharacteristics.DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS);
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001245 StreamConfiguration[] heicConfigurations = getBase(
1246 CameraCharacteristics.HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS);
1247 StreamConfigurationDuration[] heicMinFrameDurations = getBase(
1248 CameraCharacteristics.HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS);
1249 StreamConfigurationDuration[] heicStallDurations = getBase(
1250 CameraCharacteristics.HEIC_AVAILABLE_HEIC_STALL_DURATIONS);
Yin-Chia Yeh12da1402014-07-15 10:37:31 -07001251 HighSpeedVideoConfiguration[] highSpeedVideoConfigurations = getBase(
1252 CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
Chien-Yu Chen0a551f12015-04-03 17:57:35 -07001253 ReprocessFormatsMap inputOutputFormatsMap = getBase(
1254 CameraCharacteristics.SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP);
Emilian Peev2776ca32018-09-18 14:00:39 +01001255 boolean listHighResolution = isBurstSupported();
Yin-Chia Yeh12da1402014-07-15 10:37:31 -07001256 return new StreamConfigurationMap(
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001257 configurations, minFrameDurations, stallDurations,
1258 depthConfigurations, depthMinFrameDurations, depthStallDurations,
Emilian Peev934ffa62019-01-04 17:48:31 +00001259 dynamicDepthConfigurations, dynamicDepthMinFrameDurations,
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001260 dynamicDepthStallDurations, heicConfigurations,
1261 heicMinFrameDurations, heicStallDurations,
1262 highSpeedVideoConfigurations, inputOutputFormatsMap,
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001263 listHighResolution);
Igor Murashkin9c595172014-05-12 13:56:20 -07001264 }
1265
Igor Murashkin78712a82014-05-27 18:32:18 -07001266 private <T> Integer getMaxRegions(Key<T> key) {
1267 final int AE = 0;
1268 final int AWB = 1;
1269 final int AF = 2;
1270
1271 // The order of the elements is: (AE, AWB, AF)
1272 int[] maxRegions = getBase(CameraCharacteristics.CONTROL_MAX_REGIONS);
1273
1274 if (maxRegions == null) {
1275 return null;
1276 }
1277
1278 if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AE)) {
1279 return maxRegions[AE];
1280 } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB)) {
1281 return maxRegions[AWB];
1282 } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AF)) {
1283 return maxRegions[AF];
1284 } else {
1285 throw new AssertionError("Invalid key " + key);
1286 }
1287 }
1288
1289 private <T> Integer getMaxNumOutputs(Key<T> key) {
1290 final int RAW = 0;
1291 final int PROC = 1;
1292 final int PROC_STALLING = 2;
1293
1294 // The order of the elements is: (raw, proc+nonstalling, proc+stalling)
1295 int[] maxNumOutputs = getBase(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_STREAMS);
1296
1297 if (maxNumOutputs == null) {
1298 return null;
1299 }
1300
1301 if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW)) {
1302 return maxNumOutputs[RAW];
1303 } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC)) {
1304 return maxNumOutputs[PROC];
1305 } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING)) {
1306 return maxNumOutputs[PROC_STALLING];
1307 } else {
1308 throw new AssertionError("Invalid key " + key);
1309 }
1310 }
1311
Yin-Chia Yeh8490ace2014-05-27 10:04:54 -07001312 private <T> TonemapCurve getTonemapCurve() {
1313 float[] red = getBase(CaptureRequest.TONEMAP_CURVE_RED);
1314 float[] green = getBase(CaptureRequest.TONEMAP_CURVE_GREEN);
1315 float[] blue = getBase(CaptureRequest.TONEMAP_CURVE_BLUE);
Yin-Chia Yehd47699a2014-08-28 10:35:37 -07001316
1317 if (areValuesAllNull(red, green, blue)) {
1318 return null;
1319 }
1320
Yin-Chia Yeh8490ace2014-05-27 10:04:54 -07001321 if (red == null || green == null || blue == null) {
Yin-Chia Yehd47699a2014-08-28 10:35:37 -07001322 Log.w(TAG, "getTonemapCurve - missing tone curve components");
Yin-Chia Yeh8490ace2014-05-27 10:04:54 -07001323 return null;
1324 }
1325 TonemapCurve tc = new TonemapCurve(red, green, blue);
1326 return tc;
1327 }
1328
Chien-Yu Chenc804d1c2018-02-15 12:44:19 -08001329 private OisSample[] getOisSamples() {
1330 long[] timestamps = getBase(CaptureResult.STATISTICS_OIS_TIMESTAMPS);
1331 float[] xShifts = getBase(CaptureResult.STATISTICS_OIS_X_SHIFTS);
1332 float[] yShifts = getBase(CaptureResult.STATISTICS_OIS_Y_SHIFTS);
1333
1334 if (timestamps == null) {
1335 if (xShifts != null) {
1336 throw new AssertionError("timestamps is null but xShifts is not");
1337 }
1338
1339 if (yShifts != null) {
1340 throw new AssertionError("timestamps is null but yShifts is not");
1341 }
1342
1343 return null;
1344 }
1345
1346 if (xShifts == null) {
1347 throw new AssertionError("timestamps is not null but xShifts is");
1348 }
1349
1350 if (yShifts == null) {
1351 throw new AssertionError("timestamps is not null but yShifts is");
1352 }
1353
1354 if (xShifts.length != timestamps.length) {
1355 throw new AssertionError(String.format(
1356 "timestamps has %d entries but xShifts has %d", timestamps.length,
1357 xShifts.length));
1358 }
1359
1360 if (yShifts.length != timestamps.length) {
1361 throw new AssertionError(String.format(
1362 "timestamps has %d entries but yShifts has %d", timestamps.length,
1363 yShifts.length));
1364 }
1365
1366 OisSample[] samples = new OisSample[timestamps.length];
1367 for (int i = 0; i < timestamps.length; i++) {
1368 samples[i] = new OisSample(timestamps[i], xShifts[i], yShifts[i]);
1369 }
1370 return samples;
1371 }
1372
Igor Murashkind6d65152014-05-19 16:31:02 -07001373 private <T> void setBase(CameraCharacteristics.Key<T> key, T value) {
1374 setBase(key.getNativeKey(), value);
1375 }
1376
1377 private <T> void setBase(CaptureResult.Key<T> key, T value) {
1378 setBase(key.getNativeKey(), value);
1379 }
1380
1381 private <T> void setBase(CaptureRequest.Key<T> key, T value) {
1382 setBase(key.getNativeKey(), value);
1383 }
1384
Zhijun Heb7bfdc72013-10-02 11:39:43 -07001385 private <T> void setBase(Key<T> key, T value) {
Emilian Peevde62d842017-03-23 19:20:40 +00001386 int tag = nativeGetTagFromKeyLocal(key.getName());
Zhijun Heb7bfdc72013-10-02 11:39:43 -07001387 if (value == null) {
Igor Murashkin3c40a042014-04-22 15:05:50 -07001388 // Erase the entry
1389 writeValues(tag, /*src*/null);
Zhijun Heb7bfdc72013-10-02 11:39:43 -07001390 return;
Igor Murashkin3c40a042014-04-22 15:05:50 -07001391 } // else update the entry to a new value
Zhijun Heb7bfdc72013-10-02 11:39:43 -07001392
Emilian Peevde62d842017-03-23 19:20:40 +00001393 int nativeType = nativeGetTypeFromTagLocal(tag);
1394 Marshaler<T> marshaler = getMarshalerForKey(key, nativeType);
Igor Murashkin3c40a042014-04-22 15:05:50 -07001395 int size = marshaler.calculateMarshalSize(value);
Zhijun Heb7bfdc72013-10-02 11:39:43 -07001396
1397 // TODO: Optimization. Cache the byte[] and reuse if the size is big enough.
1398 byte[] values = new byte[size];
1399
1400 ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
Igor Murashkin3c40a042014-04-22 15:05:50 -07001401 marshaler.marshal(value, buffer);
Zhijun Heb7bfdc72013-10-02 11:39:43 -07001402
1403 writeValues(tag, values);
1404 }
1405
Ruben Brunkd1f113d2014-07-11 11:46:20 -07001406 // Use Command pattern here to avoid lots of expensive if/equals checks in get for overridden
1407 // metadata.
1408 private static final HashMap<Key<?>, SetCommand> sSetCommandMap =
1409 new HashMap<Key<?>, SetCommand>();
1410 static {
1411 sSetCommandMap.put(CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey(),
1412 new SetCommand() {
1413 @Override
1414 public <T> void setValue(CameraMetadataNative metadata, T value) {
1415 metadata.setAvailableFormats((int[]) value);
1416 }
1417 });
1418 sSetCommandMap.put(CaptureResult.STATISTICS_FACE_RECTANGLES.getNativeKey(),
1419 new SetCommand() {
1420 @Override
1421 public <T> void setValue(CameraMetadataNative metadata, T value) {
1422 metadata.setFaceRectangles((Rect[]) value);
1423 }
1424 });
Igor Murashkin0a1ef4d2014-07-31 15:53:34 -07001425 sSetCommandMap.put(CaptureResult.STATISTICS_FACES.getNativeKey(),
1426 new SetCommand() {
1427 @Override
1428 public <T> void setValue(CameraMetadataNative metadata, T value) {
1429 metadata.setFaces((Face[])value);
1430 }
1431 });
Ruben Brunkd1f113d2014-07-11 11:46:20 -07001432 sSetCommandMap.put(CaptureRequest.TONEMAP_CURVE.getNativeKey(), new SetCommand() {
1433 @Override
1434 public <T> void setValue(CameraMetadataNative metadata, T value) {
1435 metadata.setTonemapCurve((TonemapCurve) value);
1436 }
1437 });
1438 sSetCommandMap.put(CaptureResult.JPEG_GPS_LOCATION.getNativeKey(), new SetCommand() {
1439 @Override
1440 public <T> void setValue(CameraMetadataNative metadata, T value) {
1441 metadata.setGpsLocation((Location) value);
1442 }
1443 });
Zhijun Heb7bfdc72013-10-02 11:39:43 -07001444 }
1445
1446 private boolean setAvailableFormats(int[] value) {
1447 int[] availableFormat = value;
1448 if (value == null) {
1449 // Let setBase() to handle the null value case.
1450 return false;
1451 }
1452
1453 int[] newValues = new int[availableFormat.length];
1454 for (int i = 0; i < availableFormat.length; i++) {
1455 newValues[i] = availableFormat[i];
1456 if (availableFormat[i] == ImageFormat.JPEG) {
1457 newValues[i] = NATIVE_JPEG_FORMAT;
1458 }
1459 }
1460
1461 setBase(CameraCharacteristics.SCALER_AVAILABLE_FORMATS, newValues);
1462 return true;
1463 }
1464
Zhijun He2f1680b2013-11-13 13:16:56 -08001465 /**
1466 * Convert Face Rectangles from managed side to native side as they have different definitions.
1467 * <p>
1468 * Managed side face rectangles are defined as: left, top, width, height.
1469 * Native side face rectangles are defined as: left, top, right, bottom.
1470 * The input face rectangle need to be converted to native side definition when set is called.
1471 * </p>
1472 *
1473 * @param faceRects Input face rectangles.
1474 * @return true if face rectangles can be set successfully. Otherwise, Let the caller
1475 * (setBase) to handle it appropriately.
1476 */
1477 private boolean setFaceRectangles(Rect[] faceRects) {
1478 if (faceRects == null) {
1479 return false;
1480 }
1481
1482 Rect[] newFaceRects = new Rect[faceRects.length];
1483 for (int i = 0; i < newFaceRects.length; i++) {
1484 newFaceRects[i] = new Rect(
1485 faceRects[i].left,
1486 faceRects[i].top,
1487 faceRects[i].right + faceRects[i].left,
1488 faceRects[i].bottom + faceRects[i].top);
1489 }
1490
1491 setBase(CaptureResult.STATISTICS_FACE_RECTANGLES, newFaceRects);
1492 return true;
1493 }
1494
Yin-Chia Yeh8490ace2014-05-27 10:04:54 -07001495 private <T> boolean setTonemapCurve(TonemapCurve tc) {
1496 if (tc == null) {
1497 return false;
1498 }
1499
1500 float[][] curve = new float[3][];
1501 for (int i = TonemapCurve.CHANNEL_RED; i <= TonemapCurve.CHANNEL_BLUE; i++) {
1502 int pointCount = tc.getPointCount(i);
1503 curve[i] = new float[pointCount * TonemapCurve.POINT_SIZE];
1504 tc.copyColorCurve(i, curve[i], 0);
1505 }
1506 setBase(CaptureRequest.TONEMAP_CURVE_RED, curve[0]);
1507 setBase(CaptureRequest.TONEMAP_CURVE_GREEN, curve[1]);
1508 setBase(CaptureRequest.TONEMAP_CURVE_BLUE, curve[2]);
1509
1510 return true;
1511 }
1512
Emilian Peev423cbd72018-11-10 18:37:45 +00001513 private int mCameraId = -1;
1514 private Size mDisplaySize = new Size(0, 0);
1515
1516 /**
1517 * Set the current camera Id.
1518 *
1519 * @param cameraId Current camera id.
1520 *
1521 * @hide
1522 */
1523 public void setCameraId(int cameraId) {
1524 mCameraId = cameraId;
1525 }
1526
1527 /**
1528 * Set the current display size.
1529 *
1530 * @param displaySize The current display size.
1531 *
1532 * @hide
1533 */
1534 public void setDisplaySize(Size displaySize) {
1535 mDisplaySize = displaySize;
1536 }
1537
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001538 @UnsupportedAppUsage
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001539 private long mMetadataPtr; // native CameraMetadata*
1540
1541 private native long nativeAllocate();
1542 private native long nativeAllocateCopy(CameraMetadataNative other)
1543 throws NullPointerException;
1544
1545 private native synchronized void nativeWriteToParcel(Parcel dest);
1546 private native synchronized void nativeReadFromParcel(Parcel source);
1547 private native synchronized void nativeSwap(CameraMetadataNative other)
1548 throws NullPointerException;
1549 private native synchronized void nativeClose();
1550 private native synchronized boolean nativeIsEmpty();
1551 private native synchronized int nativeGetEntryCount();
1552
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001553 @UnsupportedAppUsage
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001554 private native synchronized byte[] nativeReadValues(int tag);
1555 private native synchronized void nativeWriteValues(int tag, byte[] src);
Igor Murashkind6d65152014-05-19 16:31:02 -07001556 private native synchronized void nativeDump() throws IOException; // dump to ALOGD
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001557
Emilian Peevde62d842017-03-23 19:20:40 +00001558 private native synchronized ArrayList nativeGetAllVendorKeys(Class keyClass);
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001559 @UnsupportedAppUsage
Emilian Peevde62d842017-03-23 19:20:40 +00001560 private native synchronized int nativeGetTagFromKeyLocal(String keyName)
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001561 throws IllegalArgumentException;
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001562 @UnsupportedAppUsage
Emilian Peevde62d842017-03-23 19:20:40 +00001563 private native synchronized int nativeGetTypeFromTagLocal(int tag)
1564 throws IllegalArgumentException;
1565 private static native int nativeGetTagFromKey(String keyName, long vendorId)
1566 throws IllegalArgumentException;
1567 private static native int nativeGetTypeFromTag(int tag, long vendorId)
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001568 throws IllegalArgumentException;
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001569
1570 /**
1571 * <p>Perform a 0-copy swap of the internal metadata with another object.</p>
1572 *
1573 * <p>Useful to convert a CameraMetadata into e.g. a CaptureRequest.</p>
1574 *
1575 * @param other Metadata to swap with
1576 * @throws NullPointerException if other was null
1577 * @hide
1578 */
1579 public void swap(CameraMetadataNative other) {
1580 nativeSwap(other);
Emilian Peev423cbd72018-11-10 18:37:45 +00001581 mCameraId = other.mCameraId;
1582 mDisplaySize = other.mDisplaySize;
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001583 }
1584
1585 /**
1586 * @hide
1587 */
1588 public int getEntryCount() {
1589 return nativeGetEntryCount();
1590 }
1591
1592 /**
1593 * Does this metadata contain at least 1 entry?
1594 *
1595 * @hide
1596 */
1597 public boolean isEmpty() {
1598 return nativeIsEmpty();
1599 }
1600
Ruben Brunkc620eb72015-07-29 18:19:11 -07001601
1602 /**
1603 * Return a list containing keys of the given key class for all defined vendor tags.
1604 *
1605 * @hide
1606 */
Emilian Peevde62d842017-03-23 19:20:40 +00001607 public <K> ArrayList<K> getAllVendorKeys(Class<K> keyClass) {
Ruben Brunkc620eb72015-07-29 18:19:11 -07001608 if (keyClass == null) {
1609 throw new NullPointerException();
1610 }
1611 return (ArrayList<K>) nativeGetAllVendorKeys(keyClass);
1612 }
1613
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001614 /**
1615 * Convert a key string into the equivalent native tag.
1616 *
1617 * @throws IllegalArgumentException if the key was not recognized
1618 * @throws NullPointerException if the key was null
1619 *
1620 * @hide
1621 */
1622 public static int getTag(String key) {
Emilian Peevde62d842017-03-23 19:20:40 +00001623 return nativeGetTagFromKey(key, Long.MAX_VALUE);
1624 }
1625
1626 /**
1627 * Convert a key string into the equivalent native tag.
1628 *
1629 * @throws IllegalArgumentException if the key was not recognized
1630 * @throws NullPointerException if the key was null
1631 *
1632 * @hide
1633 */
1634 public static int getTag(String key, long vendorId) {
1635 return nativeGetTagFromKey(key, vendorId);
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001636 }
1637
1638 /**
1639 * Get the underlying native type for a tag.
1640 *
1641 * @param tag An integer tag, see e.g. {@link #getTag}
Emilian Peevde62d842017-03-23 19:20:40 +00001642 * @param vendorId A vendor tag provider id
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001643 * @return An int enum for the metadata type, see e.g. {@link #TYPE_BYTE}
1644 *
1645 * @hide
1646 */
Emilian Peevde62d842017-03-23 19:20:40 +00001647 public static int getNativeType(int tag, long vendorId) {
1648 return nativeGetTypeFromTag(tag, vendorId);
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001649 }
1650
1651 /**
1652 * <p>Updates the existing entry for tag with the new bytes pointed by src, erasing
1653 * the entry if src was null.</p>
1654 *
1655 * <p>An empty array can be passed in to update the entry to 0 elements.</p>
1656 *
1657 * @param tag An integer tag, see e.g. {@link #getTag}
1658 * @param src An array of bytes, or null to erase the entry
1659 *
1660 * @hide
1661 */
1662 public void writeValues(int tag, byte[] src) {
1663 nativeWriteValues(tag, src);
1664 }
1665
1666 /**
1667 * <p>Returns a byte[] of data corresponding to this tag. Use a wrapped bytebuffer to unserialize
1668 * the data properly.</p>
1669 *
1670 * <p>An empty array can be returned to denote an existing entry with 0 elements.</p>
1671 *
1672 * @param tag An integer tag, see e.g. {@link #getTag}
1673 *
1674 * @return {@code null} if there were 0 entries for this tag, a byte[] otherwise.
1675 * @hide
1676 */
1677 public byte[] readValues(int tag) {
Zhijun Heb7bfdc72013-10-02 11:39:43 -07001678 // TODO: Optimization. Native code returns a ByteBuffer instead.
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001679 return nativeReadValues(tag);
1680 }
1681
Igor Murashkind6d65152014-05-19 16:31:02 -07001682 /**
1683 * Dumps the native metadata contents to logcat.
1684 *
1685 * <p>Visibility for testing/debugging only. The results will not
1686 * include any synthesized keys, as they are invisible to the native layer.</p>
1687 *
1688 * @hide
1689 */
1690 public void dumpToLog() {
1691 try {
1692 nativeDump();
1693 } catch (IOException e) {
1694 Log.wtf(TAG, "Dump logging failed", e);
1695 }
1696 }
1697
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001698 @Override
1699 protected void finalize() throws Throwable {
1700 try {
1701 close();
1702 } finally {
1703 super.finalize();
1704 }
1705 }
1706
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001707 /**
Igor Murashkin3c40a042014-04-22 15:05:50 -07001708 * Get the marshaler compatible with the {@code key} and type {@code T}.
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001709 *
Igor Murashkin3c40a042014-04-22 15:05:50 -07001710 * @throws UnsupportedOperationException
1711 * if the native/managed type combination for {@code key} is not supported
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001712 */
Emilian Peevde62d842017-03-23 19:20:40 +00001713 private static <T> Marshaler<T> getMarshalerForKey(Key<T> key, int nativeType) {
Igor Murashkin3c40a042014-04-22 15:05:50 -07001714 return MarshalRegistry.getMarshaler(key.getTypeReference(),
Emilian Peevde62d842017-03-23 19:20:40 +00001715 nativeType);
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001716 }
1717
Igor Murashkin3c40a042014-04-22 15:05:50 -07001718 @SuppressWarnings({ "unchecked", "rawtypes" })
1719 private static void registerAllMarshalers() {
Eino-Ville Talvalaa78791f2015-06-01 12:39:54 -07001720 if (DEBUG) {
Eino-Ville Talvala51ca8d62013-10-04 14:39:58 -07001721 Log.v(TAG, "Shall register metadata marshalers");
1722 }
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001723
Igor Murashkin3c40a042014-04-22 15:05:50 -07001724 MarshalQueryable[] queryList = new MarshalQueryable[] {
1725 // marshalers for standard types
1726 new MarshalQueryablePrimitive(),
1727 new MarshalQueryableEnum(),
1728 new MarshalQueryableArray(),
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001729
Igor Murashkin3c40a042014-04-22 15:05:50 -07001730 // pseudo standard types, that expand/narrow the native type into a managed type
1731 new MarshalQueryableBoolean(),
1732 new MarshalQueryableNativeByteToInteger(),
1733
1734 // marshalers for custom types
1735 new MarshalQueryableRect(),
1736 new MarshalQueryableSize(),
1737 new MarshalQueryableSizeF(),
1738 new MarshalQueryableString(),
1739 new MarshalQueryableReprocessFormatsMap(),
1740 new MarshalQueryableRange(),
Igor Murashkin57438682014-05-30 10:49:00 -07001741 new MarshalQueryablePair(),
Igor Murashkin3c40a042014-04-22 15:05:50 -07001742 new MarshalQueryableMeteringRectangle(),
1743 new MarshalQueryableColorSpaceTransform(),
1744 new MarshalQueryableStreamConfiguration(),
1745 new MarshalQueryableStreamConfigurationDuration(),
1746 new MarshalQueryableRggbChannelVector(),
Ruben Brunk52842e72014-06-05 13:16:45 -07001747 new MarshalQueryableBlackLevelPattern(),
Yin-Chia Yeh12da1402014-07-15 10:37:31 -07001748 new MarshalQueryableHighSpeedVideoConfiguration(),
Emilian Peev2776ca32018-09-18 14:00:39 +01001749 new MarshalQueryableRecommendedStreamConfiguration(),
Igor Murashkin3c40a042014-04-22 15:05:50 -07001750
1751 // generic parcelable marshaler (MUST BE LAST since it has lowest priority)
1752 new MarshalQueryableParcelable(),
1753 };
1754
1755 for (MarshalQueryable query : queryList) {
1756 MarshalRegistry.registerMarshalQueryable(query);
1757 }
Eino-Ville Talvalaa78791f2015-06-01 12:39:54 -07001758 if (DEBUG) {
Eino-Ville Talvala51ca8d62013-10-04 14:39:58 -07001759 Log.v(TAG, "Registered metadata marshalers");
1760 }
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001761 }
1762
Yin-Chia Yehd47699a2014-08-28 10:35:37 -07001763 /** Check if input arguments are all {@code null}.
1764 *
1765 * @param objs Input arguments for null check
1766 * @return {@code true} if input arguments are all {@code null}, otherwise {@code false}
1767 */
1768 private static boolean areValuesAllNull(Object... objs) {
1769 for (Object o : objs) {
1770 if (o != null) return false;
1771 }
1772 return true;
1773 }
1774
Igor Murashkin3c40a042014-04-22 15:05:50 -07001775 static {
Igor Murashkin3c40a042014-04-22 15:05:50 -07001776 registerAllMarshalers();
1777 }
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001778}