blob: 7c1ddad5fe12fe38fc2ca78a990b0387be08dfbf [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;
Shuzhen Wang1ab85142019-07-08 15:14:16 -070024import android.hardware.camera2.CameraMetadata;
Emilian Peev2776ca32018-09-18 14:00:39 +010025import android.hardware.camera2.CameraDevice;
Igor Murashkind6d65152014-05-19 16:31:02 -070026import android.hardware.camera2.CaptureRequest;
Zhijun Heb7bfdc72013-10-02 11:39:43 -070027import android.hardware.camera2.CaptureResult;
Igor Murashkin3c40a042014-04-22 15:05:50 -070028import android.hardware.camera2.marshal.MarshalQueryable;
29import android.hardware.camera2.marshal.MarshalRegistry;
Chien-Yu Chenc804d1c2018-02-15 12:44:19 -080030import android.hardware.camera2.marshal.Marshaler;
Igor Murashkin3c40a042014-04-22 15:05:50 -070031import android.hardware.camera2.marshal.impl.MarshalQueryableArray;
Ruben Brunk52842e72014-06-05 13:16:45 -070032import android.hardware.camera2.marshal.impl.MarshalQueryableBlackLevelPattern;
Shuzhen Wang1ab85142019-07-08 15:14:16 -070033import android.hardware.camera2.marshal.impl.MarshalQueryableCapabilityAndMaxSize;
Chien-Yu Chenc804d1c2018-02-15 12:44:19 -080034import android.hardware.camera2.marshal.impl.MarshalQueryableBoolean;
Igor Murashkin3c40a042014-04-22 15:05:50 -070035import android.hardware.camera2.marshal.impl.MarshalQueryableColorSpaceTransform;
36import android.hardware.camera2.marshal.impl.MarshalQueryableEnum;
Yin-Chia Yeh12da1402014-07-15 10:37:31 -070037import android.hardware.camera2.marshal.impl.MarshalQueryableHighSpeedVideoConfiguration;
Igor Murashkin3c40a042014-04-22 15:05:50 -070038import android.hardware.camera2.marshal.impl.MarshalQueryableMeteringRectangle;
39import android.hardware.camera2.marshal.impl.MarshalQueryableNativeByteToInteger;
Igor Murashkin57438682014-05-30 10:49:00 -070040import android.hardware.camera2.marshal.impl.MarshalQueryablePair;
Igor Murashkin3c40a042014-04-22 15:05:50 -070041import android.hardware.camera2.marshal.impl.MarshalQueryableParcelable;
42import android.hardware.camera2.marshal.impl.MarshalQueryablePrimitive;
43import android.hardware.camera2.marshal.impl.MarshalQueryableRange;
Emilian Peev2776ca32018-09-18 14:00:39 +010044import android.hardware.camera2.marshal.impl.MarshalQueryableRecommendedStreamConfiguration;
Igor Murashkin3c40a042014-04-22 15:05:50 -070045import android.hardware.camera2.marshal.impl.MarshalQueryableRect;
46import android.hardware.camera2.marshal.impl.MarshalQueryableReprocessFormatsMap;
47import android.hardware.camera2.marshal.impl.MarshalQueryableRggbChannelVector;
48import android.hardware.camera2.marshal.impl.MarshalQueryableSize;
49import android.hardware.camera2.marshal.impl.MarshalQueryableSizeF;
50import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfiguration;
51import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration;
52import android.hardware.camera2.marshal.impl.MarshalQueryableString;
Shuzhen Wang1ab85142019-07-08 15:14:16 -070053import android.hardware.camera2.params.CapabilityAndMaxSize;
Igor Murashkin72f9f0a2014-05-14 15:46:10 -070054import android.hardware.camera2.params.Face;
Yin-Chia Yeh12da1402014-07-15 10:37:31 -070055import android.hardware.camera2.params.HighSpeedVideoConfiguration;
Ruben Brunk57493682014-05-27 18:58:08 -070056import android.hardware.camera2.params.LensShadingMap;
Emilian Peev423cbd72018-11-10 18:37:45 +000057import android.hardware.camera2.params.MandatoryStreamCombination;
58import android.hardware.camera2.params.MandatoryStreamCombination.MandatoryStreamInformation;
Chien-Yu Chenc804d1c2018-02-15 12:44:19 -080059import android.hardware.camera2.params.OisSample;
Emilian Peev2776ca32018-09-18 14:00:39 +010060import android.hardware.camera2.params.RecommendedStreamConfiguration;
61import android.hardware.camera2.params.RecommendedStreamConfigurationMap;
Chien-Yu Chen0a551f12015-04-03 17:57:35 -070062import android.hardware.camera2.params.ReprocessFormatsMap;
Igor Murashkin9c595172014-05-12 13:56:20 -070063import android.hardware.camera2.params.StreamConfiguration;
64import android.hardware.camera2.params.StreamConfigurationDuration;
65import android.hardware.camera2.params.StreamConfigurationMap;
Yin-Chia Yeh8490ace2014-05-27 10:04:54 -070066import android.hardware.camera2.params.TonemapCurve;
Igor Murashkind6d65152014-05-19 16:31:02 -070067import android.hardware.camera2.utils.TypeReference;
Ruben Brunk57493682014-05-27 18:58:08 -070068import android.location.Location;
69import android.location.LocationManager;
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070070import android.os.Parcel;
Chien-Yu Chenc804d1c2018-02-15 12:44:19 -080071import android.os.Parcelable;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -080072import android.os.ServiceSpecificException;
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070073import android.util.Log;
Ruben Brunk57493682014-05-27 18:58:08 -070074import android.util.Size;
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070075
Igor Murashkind6d65152014-05-19 16:31:02 -070076import com.android.internal.util.Preconditions;
77
78import java.io.IOException;
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070079import java.nio.ByteBuffer;
80import java.nio.ByteOrder;
81import java.util.ArrayList;
Ruben Brunk57493682014-05-27 18:58:08 -070082import java.util.HashMap;
Emilian Peev423cbd72018-11-10 18:37:45 +000083import java.util.List;
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070084
85/**
86 * Implementation of camera metadata marshal/unmarshal across Binder to
87 * the camera service
88 */
Igor Murashkind6d65152014-05-19 16:31:02 -070089public class CameraMetadataNative implements Parcelable {
90
91 public static class Key<T> {
92 private boolean mHasTag;
93 private int mTag;
Emilian Peevde62d842017-03-23 19:20:40 +000094 private long mVendorId = Long.MAX_VALUE;
Igor Murashkind6d65152014-05-19 16:31:02 -070095 private final Class<T> mType;
96 private final TypeReference<T> mTypeReference;
97 private final String mName;
Justin Yunf01e40c2018-05-18 20:39:45 +090098 private final String mFallbackName;
Ruben Brunkd1f113d2014-07-11 11:46:20 -070099 private final int mHash;
Emilian Peevde62d842017-03-23 19:20:40 +0000100
101 /**
102 * @hide
103 */
104 public Key(String name, Class<T> type, long vendorId) {
105 if (name == null) {
106 throw new NullPointerException("Key needs a valid name");
107 } else if (type == null) {
108 throw new NullPointerException("Type needs to be non-null");
109 }
110 mName = name;
Justin Yunf01e40c2018-05-18 20:39:45 +0900111 mFallbackName = null;
Emilian Peevde62d842017-03-23 19:20:40 +0000112 mType = type;
113 mVendorId = vendorId;
114 mTypeReference = TypeReference.createSpecializedTypeReference(type);
115 mHash = mName.hashCode() ^ mTypeReference.hashCode();
116 }
117
Igor Murashkind6d65152014-05-19 16:31:02 -0700118 /**
Justin Yunf01e40c2018-05-18 20:39:45 +0900119 * @hide
120 */
121 public Key(String name, String fallbackName, Class<T> type) {
122 if (name == null) {
123 throw new NullPointerException("Key needs a valid name");
124 } else if (type == null) {
125 throw new NullPointerException("Type needs to be non-null");
126 }
127 mName = name;
128 mFallbackName = fallbackName;
129 mType = type;
130 mTypeReference = TypeReference.createSpecializedTypeReference(type);
131 mHash = mName.hashCode() ^ mTypeReference.hashCode();
132 }
133
134 /**
Igor Murashkind6d65152014-05-19 16:31:02 -0700135 * Visible for testing only.
136 *
137 * <p>Use the CameraCharacteristics.Key, CaptureResult.Key, or CaptureRequest.Key
138 * for application code or vendor-extended keys.</p>
139 */
140 public Key(String name, Class<T> type) {
141 if (name == null) {
142 throw new NullPointerException("Key needs a valid name");
143 } else if (type == null) {
144 throw new NullPointerException("Type needs to be non-null");
145 }
146 mName = name;
Justin Yunf01e40c2018-05-18 20:39:45 +0900147 mFallbackName = null;
Igor Murashkind6d65152014-05-19 16:31:02 -0700148 mType = type;
149 mTypeReference = TypeReference.createSpecializedTypeReference(type);
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700150 mHash = mName.hashCode() ^ mTypeReference.hashCode();
Igor Murashkind6d65152014-05-19 16:31:02 -0700151 }
152
153 /**
154 * Visible for testing only.
155 *
156 * <p>Use the CameraCharacteristics.Key, CaptureResult.Key, or CaptureRequest.Key
157 * for application code or vendor-extended keys.</p>
158 */
159 @SuppressWarnings("unchecked")
160 public Key(String name, TypeReference<T> typeReference) {
161 if (name == null) {
162 throw new NullPointerException("Key needs a valid name");
163 } else if (typeReference == null) {
164 throw new NullPointerException("TypeReference needs to be non-null");
165 }
166 mName = name;
Justin Yunf01e40c2018-05-18 20:39:45 +0900167 mFallbackName = null;
Igor Murashkind6d65152014-05-19 16:31:02 -0700168 mType = (Class<T>)typeReference.getRawType();
169 mTypeReference = typeReference;
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700170 mHash = mName.hashCode() ^ mTypeReference.hashCode();
Igor Murashkind6d65152014-05-19 16:31:02 -0700171 }
172
173 /**
174 * Return a camelCase, period separated name formatted like:
175 * {@code "root.section[.subsections].name"}.
176 *
177 * <p>Built-in keys exposed by the Android SDK are always prefixed with {@code "android."};
178 * keys that are device/platform-specific are prefixed with {@code "com."}.</p>
179 *
180 * <p>For example, {@code CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP} would
181 * have a name of {@code "android.scaler.streamConfigurationMap"}; whereas a device
182 * specific key might look like {@code "com.google.nexus.data.private"}.</p>
183 *
184 * @return String representation of the key name
185 */
186 public final String getName() {
187 return mName;
188 }
189
190 /**
191 * {@inheritDoc}
192 */
193 @Override
194 public final int hashCode() {
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700195 return mHash;
Igor Murashkind6d65152014-05-19 16:31:02 -0700196 }
197
198 /**
199 * Compare this key against other native keys, request keys, result keys, and
200 * characteristics keys.
201 *
202 * <p>Two keys are considered equal if their name and type reference are equal.</p>
203 *
204 * <p>Note that the equality against non-native keys is one-way. A native key may be equal
205 * to a result key; but that same result key will not be equal to a native key.</p>
206 */
207 @SuppressWarnings("rawtypes")
208 @Override
209 public final boolean equals(Object o) {
210 if (this == o) {
211 return true;
212 }
213
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700214 if (o == null || this.hashCode() != o.hashCode()) {
215 return false;
216 }
217
Igor Murashkind6d65152014-05-19 16:31:02 -0700218 Key<?> lhs;
219
220 if (o instanceof CaptureResult.Key) {
221 lhs = ((CaptureResult.Key)o).getNativeKey();
222 } else if (o instanceof CaptureRequest.Key) {
223 lhs = ((CaptureRequest.Key)o).getNativeKey();
224 } else if (o instanceof CameraCharacteristics.Key) {
225 lhs = ((CameraCharacteristics.Key)o).getNativeKey();
226 } else if ((o instanceof Key)) {
227 lhs = (Key<?>)o;
228 } else {
229 return false;
230 }
231
232 return mName.equals(lhs.mName) && mTypeReference.equals(lhs.mTypeReference);
233 }
234
235 /**
236 * <p>
237 * Get the tag corresponding to this key. This enables insertion into the
238 * native metadata.
239 * </p>
240 *
241 * <p>This value is looked up the first time, and cached subsequently.</p>
242 *
243 * @return The tag numeric value corresponding to the string
244 */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100245 @UnsupportedAppUsage
Igor Murashkind6d65152014-05-19 16:31:02 -0700246 public final int getTag() {
247 if (!mHasTag) {
Emilian Peevde62d842017-03-23 19:20:40 +0000248 mTag = CameraMetadataNative.getTag(mName, mVendorId);
Igor Murashkind6d65152014-05-19 16:31:02 -0700249 mHasTag = true;
250 }
251 return mTag;
252 }
253
254 /**
255 * Get the raw class backing the type {@code T} for this key.
256 *
257 * <p>The distinction is only important if {@code T} is a generic, e.g.
258 * {@code Range<Integer>} since the nested type will be erased.</p>
259 */
260 public final Class<T> getType() {
261 // TODO: remove this; other places should use #getTypeReference() instead
262 return mType;
263 }
264
265 /**
Emilian Peevde62d842017-03-23 19:20:40 +0000266 * Get the vendor tag provider id.
267 *
268 * @hide
269 */
270 public final long getVendorId() {
271 return mVendorId;
272 }
273
274 /**
Igor Murashkind6d65152014-05-19 16:31:02 -0700275 * Get the type reference backing the type {@code T} for this key.
276 *
277 * <p>The distinction is only important if {@code T} is a generic, e.g.
278 * {@code Range<Integer>} since the nested type will be retained.</p>
279 */
280 public final TypeReference<T> getTypeReference() {
281 return mTypeReference;
282 }
283 }
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700284
285 private static final String TAG = "CameraMetadataJV";
Eino-Ville Talvalaa78791f2015-06-01 12:39:54 -0700286 private static final boolean DEBUG = false;
287
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700288 // this should be in sync with HAL_PIXEL_FORMAT_BLOB defined in graphics.h
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700289 public static final int NATIVE_JPEG_FORMAT = 0x21;
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700290
Ruben Brunk57493682014-05-27 18:58:08 -0700291 private static final String CELLID_PROCESS = "CELLID";
292 private static final String GPS_PROCESS = "GPS";
Igor Murashkin0a1ef4d2014-07-31 15:53:34 -0700293 private static final int FACE_LANDMARK_SIZE = 6;
Ruben Brunk57493682014-05-27 18:58:08 -0700294
295 private static String translateLocationProviderToProcess(final String provider) {
296 if (provider == null) {
297 return null;
298 }
299 switch(provider) {
300 case LocationManager.GPS_PROVIDER:
301 return GPS_PROCESS;
302 case LocationManager.NETWORK_PROVIDER:
303 return CELLID_PROCESS;
304 default:
305 return null;
306 }
307 }
308
309 private static String translateProcessToLocationProvider(final String process) {
310 if (process == null) {
311 return null;
312 }
313 switch(process) {
314 case GPS_PROCESS:
315 return LocationManager.GPS_PROVIDER;
316 case CELLID_PROCESS:
317 return LocationManager.NETWORK_PROVIDER;
318 default:
319 return null;
320 }
321 }
322
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700323 public CameraMetadataNative() {
324 super();
325 mMetadataPtr = nativeAllocate();
326 if (mMetadataPtr == 0) {
327 throw new OutOfMemoryError("Failed to allocate native CameraMetadata");
328 }
329 }
330
331 /**
332 * Copy constructor - clone metadata
333 */
334 public CameraMetadataNative(CameraMetadataNative other) {
335 super();
336 mMetadataPtr = nativeAllocateCopy(other);
337 if (mMetadataPtr == 0) {
338 throw new OutOfMemoryError("Failed to allocate native CameraMetadata");
339 }
340 }
341
Igor Murashkind6d65152014-05-19 16:31:02 -0700342 /**
343 * Move the contents from {@code other} into a new camera metadata instance.</p>
344 *
345 * <p>After this call, {@code other} will become empty.</p>
346 *
347 * @param other the previous metadata instance which will get pilfered
348 * @return a new metadata instance with the values from {@code other} moved into it
349 */
350 public static CameraMetadataNative move(CameraMetadataNative other) {
351 CameraMetadataNative newObject = new CameraMetadataNative();
352 newObject.swap(other);
353 return newObject;
354 }
355
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700356 public static final @android.annotation.NonNull Parcelable.Creator<CameraMetadataNative> CREATOR =
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700357 new Parcelable.Creator<CameraMetadataNative>() {
358 @Override
359 public CameraMetadataNative createFromParcel(Parcel in) {
360 CameraMetadataNative metadata = new CameraMetadataNative();
361 metadata.readFromParcel(in);
362 return metadata;
363 }
364
365 @Override
366 public CameraMetadataNative[] newArray(int size) {
367 return new CameraMetadataNative[size];
368 }
369 };
370
371 @Override
372 public int describeContents() {
373 return 0;
374 }
375
376 @Override
377 public void writeToParcel(Parcel dest, int flags) {
378 nativeWriteToParcel(dest);
379 }
380
Igor Murashkind6d65152014-05-19 16:31:02 -0700381 /**
382 * @hide
383 */
384 public <T> T get(CameraCharacteristics.Key<T> key) {
385 return get(key.getNativeKey());
386 }
387
388 /**
389 * @hide
390 */
391 public <T> T get(CaptureResult.Key<T> key) {
392 return get(key.getNativeKey());
393 }
394
395 /**
396 * @hide
397 */
398 public <T> T get(CaptureRequest.Key<T> key) {
399 return get(key.getNativeKey());
400 }
401
402 /**
403 * Look-up a metadata field value by its key.
404 *
405 * @param key a non-{@code null} key instance
406 * @return the field corresponding to the {@code key}, or {@code null} if no value was set
407 */
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700408 public <T> T get(Key<T> key) {
Igor Murashkind6d65152014-05-19 16:31:02 -0700409 Preconditions.checkNotNull(key, "key must not be null");
410
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700411 // Check if key has been overridden to use a wrapper class on the java side.
412 GetCommand g = sGetCommandMap.get(key);
413 if (g != null) {
Igor Murashkin0a1ef4d2014-07-31 15:53:34 -0700414 return g.getValue(this, key);
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700415 }
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700416 return getBase(key);
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700417 }
418
419 public void readFromParcel(Parcel in) {
420 nativeReadFromParcel(in);
421 }
422
423 /**
Ruben Brunk85c43882014-02-21 17:40:51 -0800424 * Set the global client-side vendor tag descriptor to allow use of vendor
425 * tags in camera applications.
426 *
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800427 * @throws ServiceSpecificException
Ruben Brunk85c43882014-02-21 17:40:51 -0800428 * @hide
429 */
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800430 public static void setupGlobalVendorTagDescriptor() throws ServiceSpecificException {
431 int err = nativeSetupGlobalVendorTagDescriptor();
432 if (err != 0) {
433 throw new ServiceSpecificException(err, "Failure to set up global vendor tags");
434 }
435 }
436
437 /**
438 * Set the global client-side vendor tag descriptor to allow use of vendor
439 * tags in camera applications.
440 *
441 * @return int An error code corresponding to one of the
442 * {@link ICameraService} error constants, or 0 on success.
443 */
444 private static native int nativeSetupGlobalVendorTagDescriptor();
Ruben Brunk85c43882014-02-21 17:40:51 -0800445
446 /**
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700447 * Set a camera metadata field to a value. The field definitions can be
Igor Murashkin68f40062013-09-10 12:15:54 -0700448 * found in {@link CameraCharacteristics}, {@link CaptureResult}, and
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700449 * {@link CaptureRequest}.
450 *
451 * @param key The metadata field to write.
452 * @param value The value to set the field to, which must be of a matching
453 * type to the key.
454 */
455 public <T> void set(Key<T> key, T value) {
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700456 SetCommand s = sSetCommandMap.get(key);
457 if (s != null) {
458 s.setValue(this, value);
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700459 return;
460 }
461
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700462 setBase(key, value);
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700463 }
464
Igor Murashkind6d65152014-05-19 16:31:02 -0700465 public <T> void set(CaptureRequest.Key<T> key, T value) {
466 set(key.getNativeKey(), value);
467 }
468
469 public <T> void set(CaptureResult.Key<T> key, T value) {
470 set(key.getNativeKey(), value);
471 }
472
473 public <T> void set(CameraCharacteristics.Key<T> key, T value) {
474 set(key.getNativeKey(), value);
475 }
476
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700477 // Keep up-to-date with camera_metadata.h
478 /**
479 * @hide
480 */
481 public static final int TYPE_BYTE = 0;
482 /**
483 * @hide
484 */
485 public static final int TYPE_INT32 = 1;
486 /**
487 * @hide
488 */
489 public static final int TYPE_FLOAT = 2;
490 /**
491 * @hide
492 */
493 public static final int TYPE_INT64 = 3;
494 /**
495 * @hide
496 */
497 public static final int TYPE_DOUBLE = 4;
498 /**
499 * @hide
500 */
501 public static final int TYPE_RATIONAL = 5;
502 /**
503 * @hide
504 */
505 public static final int NUM_TYPES = 6;
506
507 private void close() {
508 // this sets mMetadataPtr to 0
509 nativeClose();
510 mMetadataPtr = 0; // set it to 0 again to prevent eclipse from making this field final
511 }
512
Igor Murashkind6d65152014-05-19 16:31:02 -0700513 private <T> T getBase(CameraCharacteristics.Key<T> key) {
514 return getBase(key.getNativeKey());
515 }
516
517 private <T> T getBase(CaptureResult.Key<T> key) {
518 return getBase(key.getNativeKey());
519 }
520
521 private <T> T getBase(CaptureRequest.Key<T> key) {
522 return getBase(key.getNativeKey());
523 }
524
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700525 private <T> T getBase(Key<T> key) {
Emilian Peevde62d842017-03-23 19:20:40 +0000526 int tag = nativeGetTagFromKeyLocal(key.getName());
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700527 byte[] values = readValues(tag);
528 if (values == null) {
Justin Yunf01e40c2018-05-18 20:39:45 +0900529 // If the key returns null, use the fallback key if exists.
530 // This is to support old key names for the newly published keys.
531 if (key.mFallbackName == null) {
532 return null;
533 }
534 tag = nativeGetTagFromKeyLocal(key.mFallbackName);
535 values = readValues(tag);
536 if (values == null) {
537 return null;
538 }
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700539 }
540
Emilian Peevde62d842017-03-23 19:20:40 +0000541 int nativeType = nativeGetTypeFromTagLocal(tag);
542 Marshaler<T> marshaler = getMarshalerForKey(key, nativeType);
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700543 ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
Igor Murashkin3c40a042014-04-22 15:05:50 -0700544 return marshaler.unmarshal(buffer);
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700545 }
Igor Murashkin78712a82014-05-27 18:32:18 -0700546
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700547 // Use Command pattern here to avoid lots of expensive if/equals checks in get for overridden
548 // metadata.
549 private static final HashMap<Key<?>, GetCommand> sGetCommandMap =
550 new HashMap<Key<?>, GetCommand>();
551 static {
552 sGetCommandMap.put(
553 CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey(), new GetCommand() {
554 @Override
555 @SuppressWarnings("unchecked")
556 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
557 return (T) metadata.getAvailableFormats();
558 }
559 });
560 sGetCommandMap.put(
561 CaptureResult.STATISTICS_FACES.getNativeKey(), new GetCommand() {
562 @Override
563 @SuppressWarnings("unchecked")
564 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
Ruben Brunk40001f52014-07-17 11:02:28 -0700565 return (T) metadata.getFaces();
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700566 }
567 });
568 sGetCommandMap.put(
569 CaptureResult.STATISTICS_FACE_RECTANGLES.getNativeKey(), new GetCommand() {
570 @Override
571 @SuppressWarnings("unchecked")
572 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
Ruben Brunk40001f52014-07-17 11:02:28 -0700573 return (T) metadata.getFaceRectangles();
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700574 }
575 });
576 sGetCommandMap.put(
577 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP.getNativeKey(),
578 new GetCommand() {
579 @Override
580 @SuppressWarnings("unchecked")
581 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
582 return (T) metadata.getStreamConfigurationMap();
583 }
584 });
585 sGetCommandMap.put(
Emilian Peev423cbd72018-11-10 18:37:45 +0000586 CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS.getNativeKey(),
587 new GetCommand() {
588 @Override
589 @SuppressWarnings("unchecked")
590 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
591 return (T) metadata.getMandatoryStreamCombinations();
592 }
593 });
594 sGetCommandMap.put(
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700595 CameraCharacteristics.CONTROL_MAX_REGIONS_AE.getNativeKey(), new GetCommand() {
596 @Override
597 @SuppressWarnings("unchecked")
598 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
599 return (T) metadata.getMaxRegions(key);
600 }
601 });
602 sGetCommandMap.put(
603 CameraCharacteristics.CONTROL_MAX_REGIONS_AWB.getNativeKey(), new GetCommand() {
604 @Override
605 @SuppressWarnings("unchecked")
606 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
607 return (T) metadata.getMaxRegions(key);
608 }
609 });
610 sGetCommandMap.put(
611 CameraCharacteristics.CONTROL_MAX_REGIONS_AF.getNativeKey(), new GetCommand() {
612 @Override
613 @SuppressWarnings("unchecked")
614 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
615 return (T) metadata.getMaxRegions(key);
616 }
617 });
618 sGetCommandMap.put(
619 CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW.getNativeKey(), new GetCommand() {
620 @Override
621 @SuppressWarnings("unchecked")
622 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
623 return (T) metadata.getMaxNumOutputs(key);
624 }
625 });
626 sGetCommandMap.put(
627 CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC.getNativeKey(), new GetCommand() {
628 @Override
629 @SuppressWarnings("unchecked")
630 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
631 return (T) metadata.getMaxNumOutputs(key);
632 }
633 });
634 sGetCommandMap.put(
635 CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING.getNativeKey(),
636 new GetCommand() {
637 @Override
638 @SuppressWarnings("unchecked")
639 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
640 return (T) metadata.getMaxNumOutputs(key);
641 }
642 });
643 sGetCommandMap.put(
644 CaptureRequest.TONEMAP_CURVE.getNativeKey(), new GetCommand() {
645 @Override
646 @SuppressWarnings("unchecked")
647 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
648 return (T) metadata.getTonemapCurve();
649 }
650 });
651 sGetCommandMap.put(
652 CaptureResult.JPEG_GPS_LOCATION.getNativeKey(), new GetCommand() {
653 @Override
654 @SuppressWarnings("unchecked")
655 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
656 return (T) metadata.getGpsLocation();
657 }
658 });
659 sGetCommandMap.put(
660 CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP.getNativeKey(),
661 new GetCommand() {
662 @Override
663 @SuppressWarnings("unchecked")
664 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
665 return (T) metadata.getLensShadingMap();
666 }
667 });
Chien-Yu Chenc804d1c2018-02-15 12:44:19 -0800668 sGetCommandMap.put(
669 CaptureResult.STATISTICS_OIS_SAMPLES.getNativeKey(),
670 new GetCommand() {
671 @Override
672 @SuppressWarnings("unchecked")
673 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
674 return (T) metadata.getOisSamples();
675 }
676 });
Shuzhen Wang1ab85142019-07-08 15:14:16 -0700677 sGetCommandMap.put(
678 CameraCharacteristics.CONTROL_AVAILABLE_BOKEH_CAPABILITIES.getNativeKey(),
679 new GetCommand() {
680 @Override
681 @SuppressWarnings("unchecked")
682 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
683 return (T) metadata.getBokehCapabilities();
684 }
685 });
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700686 }
687
688 private int[] getAvailableFormats() {
689 int[] availableFormats = getBase(CameraCharacteristics.SCALER_AVAILABLE_FORMATS);
Zhijun He2f1680b2013-11-13 13:16:56 -0800690 if (availableFormats != null) {
691 for (int i = 0; i < availableFormats.length; i++) {
692 // JPEG has different value between native and managed side, need override.
693 if (availableFormats[i] == NATIVE_JPEG_FORMAT) {
694 availableFormats[i] = ImageFormat.JPEG;
695 }
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700696 }
697 }
Zhijun He2f1680b2013-11-13 13:16:56 -0800698
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700699 return availableFormats;
700 }
701
Igor Murashkin0a1ef4d2014-07-31 15:53:34 -0700702 private boolean setFaces(Face[] faces) {
703 if (faces == null) {
704 return false;
705 }
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700706
Igor Murashkin0a1ef4d2014-07-31 15:53:34 -0700707 int numFaces = faces.length;
708
709 // Detect if all faces are SIMPLE or not; count # of valid faces
710 boolean fullMode = true;
711 for (Face face : faces) {
712 if (face == null) {
713 numFaces--;
714 Log.w(TAG, "setFaces - null face detected, skipping");
715 continue;
716 }
717
718 if (face.getId() == Face.ID_UNSUPPORTED) {
719 fullMode = false;
720 }
721 }
722
723 Rect[] faceRectangles = new Rect[numFaces];
724 byte[] faceScores = new byte[numFaces];
725 int[] faceIds = null;
726 int[] faceLandmarks = null;
727
728 if (fullMode) {
729 faceIds = new int[numFaces];
730 faceLandmarks = new int[numFaces * FACE_LANDMARK_SIZE];
731 }
732
733 int i = 0;
734 for (Face face : faces) {
735 if (face == null) {
736 continue;
737 }
738
739 faceRectangles[i] = face.getBounds();
740 faceScores[i] = (byte)face.getScore();
741
742 if (fullMode) {
743 faceIds[i] = face.getId();
744
745 int j = 0;
746
747 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getLeftEyePosition().x;
748 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getLeftEyePosition().y;
749 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getRightEyePosition().x;
750 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getRightEyePosition().y;
751 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getMouthPosition().x;
752 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getMouthPosition().y;
753 }
754
755 i++;
756 }
757
758 set(CaptureResult.STATISTICS_FACE_RECTANGLES, faceRectangles);
759 set(CaptureResult.STATISTICS_FACE_IDS, faceIds);
760 set(CaptureResult.STATISTICS_FACE_LANDMARKS, faceLandmarks);
761 set(CaptureResult.STATISTICS_FACE_SCORES, faceScores);
762
763 return true;
764 }
765
766 private Face[] getFaces() {
Zhijun He58216c22013-10-14 15:29:37 -0700767 Integer faceDetectMode = get(CaptureResult.STATISTICS_FACE_DETECT_MODE);
Yin-Chia Yehd47699a2014-08-28 10:35:37 -0700768 byte[] faceScores = get(CaptureResult.STATISTICS_FACE_SCORES);
769 Rect[] faceRectangles = get(CaptureResult.STATISTICS_FACE_RECTANGLES);
770 int[] faceIds = get(CaptureResult.STATISTICS_FACE_IDS);
771 int[] faceLandmarks = get(CaptureResult.STATISTICS_FACE_LANDMARKS);
772
773 if (areValuesAllNull(faceDetectMode, faceScores, faceRectangles, faceIds, faceLandmarks)) {
774 return null;
775 }
776
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700777 if (faceDetectMode == null) {
Zhijun He58216c22013-10-14 15:29:37 -0700778 Log.w(TAG, "Face detect mode metadata is null, assuming the mode is SIMPLE");
779 faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE;
Donghui Han5f967a32018-07-10 16:32:39 -0700780 } else if (faceDetectMode > CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) {
781 // Face detect mode is larger than FULL, assuming the mode is FULL
782 faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL;
Zhijun He58216c22013-10-14 15:29:37 -0700783 } else {
784 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_OFF) {
785 return new Face[0];
786 }
787 if (faceDetectMode != CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE &&
788 faceDetectMode != CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) {
789 Log.w(TAG, "Unknown face detect mode: " + faceDetectMode);
790 return new Face[0];
791 }
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700792 }
793
794 // Face scores and rectangles are required by SIMPLE and FULL mode.
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700795 if (faceScores == null || faceRectangles == null) {
Zhijun He58216c22013-10-14 15:29:37 -0700796 Log.w(TAG, "Expect face scores and rectangles to be non-null");
797 return new Face[0];
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700798 } else if (faceScores.length != faceRectangles.length) {
Zhijun He58216c22013-10-14 15:29:37 -0700799 Log.w(TAG, String.format("Face score size(%d) doesn match face rectangle size(%d)!",
800 faceScores.length, faceRectangles.length));
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700801 }
802
Zhijun He58216c22013-10-14 15:29:37 -0700803 // To be safe, make number of faces is the minimal of all face info metadata length.
804 int numFaces = Math.min(faceScores.length, faceRectangles.length);
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700805 // Face id and landmarks are only required by FULL mode.
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700806 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) {
807 if (faceIds == null || faceLandmarks == null) {
Zhijun He58216c22013-10-14 15:29:37 -0700808 Log.w(TAG, "Expect face ids and landmarks to be non-null for FULL mode," +
809 "fallback to SIMPLE mode");
810 faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE;
811 } else {
812 if (faceIds.length != numFaces ||
813 faceLandmarks.length != numFaces * FACE_LANDMARK_SIZE) {
814 Log.w(TAG, String.format("Face id size(%d), or face landmark size(%d) don't" +
815 "match face number(%d)!",
816 faceIds.length, faceLandmarks.length * FACE_LANDMARK_SIZE, numFaces));
817 }
818 // To be safe, make number of faces is the minimal of all face info metadata length.
819 numFaces = Math.min(numFaces, faceIds.length);
820 numFaces = Math.min(numFaces, faceLandmarks.length / FACE_LANDMARK_SIZE);
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700821 }
822 }
823
Zhijun He844b3522013-10-16 16:13:50 -0700824 ArrayList<Face> faceList = new ArrayList<Face>();
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700825 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE) {
826 for (int i = 0; i < numFaces; i++) {
Zhijun He844b3522013-10-16 16:13:50 -0700827 if (faceScores[i] <= Face.SCORE_MAX &&
828 faceScores[i] >= Face.SCORE_MIN) {
829 faceList.add(new Face(faceRectangles[i], faceScores[i]));
830 }
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700831 }
832 } else {
833 // CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL
834 for (int i = 0; i < numFaces; i++) {
Zhijun He844b3522013-10-16 16:13:50 -0700835 if (faceScores[i] <= Face.SCORE_MAX &&
836 faceScores[i] >= Face.SCORE_MIN &&
837 faceIds[i] >= 0) {
Igor Murashkin0a1ef4d2014-07-31 15:53:34 -0700838 Point leftEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE],
839 faceLandmarks[i*FACE_LANDMARK_SIZE+1]);
840 Point rightEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+2],
841 faceLandmarks[i*FACE_LANDMARK_SIZE+3]);
842 Point mouth = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+4],
843 faceLandmarks[i*FACE_LANDMARK_SIZE+5]);
Zhijun He844b3522013-10-16 16:13:50 -0700844 Face face = new Face(faceRectangles[i], faceScores[i], faceIds[i],
845 leftEye, rightEye, mouth);
846 faceList.add(face);
847 }
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700848 }
849 }
Zhijun He844b3522013-10-16 16:13:50 -0700850 Face[] faces = new Face[faceList.size()];
851 faceList.toArray(faces);
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700852 return faces;
853 }
854
Eino-Ville Talvala615b75f2013-10-14 18:20:43 -0700855 // Face rectangles are defined as (left, top, right, bottom) instead of
856 // (left, top, width, height) at the native level, so the normal Rect
857 // conversion that does (l, t, w, h) -> (l, t, r, b) is unnecessary. Undo
858 // that conversion here for just the faces.
Zhijun He2f1680b2013-11-13 13:16:56 -0800859 private Rect[] getFaceRectangles() {
Eino-Ville Talvala615b75f2013-10-14 18:20:43 -0700860 Rect[] faceRectangles = getBase(CaptureResult.STATISTICS_FACE_RECTANGLES);
861 if (faceRectangles == null) return null;
862
863 Rect[] fixedFaceRectangles = new Rect[faceRectangles.length];
864 for (int i = 0; i < faceRectangles.length; i++) {
865 fixedFaceRectangles[i] = new Rect(
866 faceRectangles[i].left,
867 faceRectangles[i].top,
868 faceRectangles[i].right - faceRectangles[i].left,
869 faceRectangles[i].bottom - faceRectangles[i].top);
870 }
871 return fixedFaceRectangles;
872 }
873
Ruben Brunk57493682014-05-27 18:58:08 -0700874 private LensShadingMap getLensShadingMap() {
875 float[] lsmArray = getBase(CaptureResult.STATISTICS_LENS_SHADING_MAP);
Yin-Chia Yehd47699a2014-08-28 10:35:37 -0700876 Size s = get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE);
877
878 // Do not warn if lsmArray is null while s is not. This is valid.
Ruben Brunk57493682014-05-27 18:58:08 -0700879 if (lsmArray == null) {
Ruben Brunk57493682014-05-27 18:58:08 -0700880 return null;
881 }
Yin-Chia Yehd47699a2014-08-28 10:35:37 -0700882
883 if (s == null) {
884 Log.w(TAG, "getLensShadingMap - Lens shading map size was null.");
885 return null;
886 }
887
Ruben Brunk57493682014-05-27 18:58:08 -0700888 LensShadingMap map = new LensShadingMap(lsmArray, s.getHeight(), s.getWidth());
889 return map;
890 }
891
892 private Location getGpsLocation() {
893 String processingMethod = get(CaptureResult.JPEG_GPS_PROCESSING_METHOD);
Ruben Brunk57493682014-05-27 18:58:08 -0700894 double[] coords = get(CaptureResult.JPEG_GPS_COORDINATES);
Emilian Peevd0084792017-01-31 15:29:20 +0000895 Long timeStamp = get(CaptureResult.JPEG_GPS_TIMESTAMP);
Ruben Brunk57493682014-05-27 18:58:08 -0700896
Yin-Chia Yehd47699a2014-08-28 10:35:37 -0700897 if (areValuesAllNull(processingMethod, coords, timeStamp)) {
898 return null;
899 }
900
901 Location l = new Location(translateProcessToLocationProvider(processingMethod));
Ruben Brunk57493682014-05-27 18:58:08 -0700902 if (timeStamp != null) {
Emilian Peevd0084792017-01-31 15:29:20 +0000903 // Location expects timestamp in [ms.]
904 l.setTime(timeStamp * 1000);
Ruben Brunk57493682014-05-27 18:58:08 -0700905 } else {
906 Log.w(TAG, "getGpsLocation - No timestamp for GPS location.");
907 }
908
909 if (coords != null) {
910 l.setLatitude(coords[0]);
911 l.setLongitude(coords[1]);
912 l.setAltitude(coords[2]);
913 } else {
914 Log.w(TAG, "getGpsLocation - No coordinates for GPS location");
915 }
916
917 return l;
918 }
919
920 private boolean setGpsLocation(Location l) {
921 if (l == null) {
922 return false;
923 }
924
925 double[] coords = { l.getLatitude(), l.getLongitude(), l.getAltitude() };
926 String processMethod = translateLocationProviderToProcess(l.getProvider());
Emilian Peev8f240962017-01-26 08:39:54 -0800927 //JPEG_GPS_TIMESTAMP expects sec. instead of msec.
928 long timestamp = l.getTime() / 1000;
Ruben Brunk57493682014-05-27 18:58:08 -0700929
930 set(CaptureRequest.JPEG_GPS_TIMESTAMP, timestamp);
931 set(CaptureRequest.JPEG_GPS_COORDINATES, coords);
932
933 if (processMethod == null) {
934 Log.w(TAG, "setGpsLocation - No process method, Location is not from a GPS or NETWORK" +
935 "provider");
936 } else {
937 setBase(CaptureRequest.JPEG_GPS_PROCESSING_METHOD, processMethod);
938 }
939 return true;
940 }
941
Emilian Peev2776ca32018-09-18 14:00:39 +0100942 private void parseRecommendedConfigurations(RecommendedStreamConfiguration[] configurations,
943 StreamConfigurationMap fullMap, boolean isDepth,
944 ArrayList<ArrayList<StreamConfiguration>> /*out*/streamConfigList,
945 ArrayList<ArrayList<StreamConfigurationDuration>> /*out*/streamDurationList,
946 ArrayList<ArrayList<StreamConfigurationDuration>> /*out*/streamStallList,
947 boolean[] /*out*/supportsPrivate) {
948
949 streamConfigList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT);
950 streamDurationList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT);
951 streamStallList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT);
952 for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) {
953 streamConfigList.add(new ArrayList<StreamConfiguration> ());
954 streamDurationList.add(new ArrayList<StreamConfigurationDuration> ());
955 streamStallList.add(new ArrayList<StreamConfigurationDuration> ());
956 }
957
958 for (RecommendedStreamConfiguration c : configurations) {
959 int width = c.getWidth();
960 int height = c.getHeight();
961 int internalFormat = c.getFormat();
962 int publicFormat =
963 (isDepth) ? StreamConfigurationMap.depthFormatToPublic(internalFormat) :
964 StreamConfigurationMap.imageFormatToPublic(internalFormat);
965 Size sz = new Size(width, height);
966 int usecaseBitmap = c.getUsecaseBitmap();
967
968 if (!c.isInput()) {
969 StreamConfigurationDuration minDurationConfiguration = null;
970 StreamConfigurationDuration stallDurationConfiguration = null;
971
972 StreamConfiguration streamConfiguration = new StreamConfiguration(internalFormat,
973 width, height, /*input*/ false);
974
975 long minFrameDuration = fullMap.getOutputMinFrameDuration(publicFormat, sz);
976 if (minFrameDuration > 0) {
977 minDurationConfiguration = new StreamConfigurationDuration(internalFormat,
978 width, height, minFrameDuration);
979 }
980
981 long stallDuration = fullMap.getOutputStallDuration(publicFormat, sz);
982 if (stallDuration > 0) {
983 stallDurationConfiguration = new StreamConfigurationDuration(internalFormat,
984 width, height, stallDuration);
985 }
986
987 for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) {
988 if ((usecaseBitmap & (1 << i)) != 0) {
989 ArrayList<StreamConfiguration> sc = streamConfigList.get(i);
990 sc.add(streamConfiguration);
991
992 if (minFrameDuration > 0) {
993 ArrayList<StreamConfigurationDuration> scd = streamDurationList.get(i);
994 scd.add(minDurationConfiguration);
995 }
996
997 if (stallDuration > 0) {
998 ArrayList<StreamConfigurationDuration> scs = streamStallList.get(i);
999 scs.add(stallDurationConfiguration);
1000 }
1001
1002 if ((supportsPrivate != null) && !supportsPrivate[i] &&
1003 (publicFormat == ImageFormat.PRIVATE)) {
1004 supportsPrivate[i] = true;
1005 }
1006 }
1007 }
1008 } else {
1009 if (usecaseBitmap != (1 << RecommendedStreamConfigurationMap.USECASE_ZSL)) {
1010 throw new IllegalArgumentException("Recommended input stream configurations " +
1011 "should only be advertised in the ZSL use case!");
1012 }
1013
1014 ArrayList<StreamConfiguration> sc = streamConfigList.get(
1015 RecommendedStreamConfigurationMap.USECASE_ZSL);
1016 sc.add(new StreamConfiguration(internalFormat,
1017 width, height, /*input*/ true));
1018 }
1019 }
1020 }
1021
1022 private class StreamConfigurationData {
1023 StreamConfiguration [] streamConfigurationArray = null;
1024 StreamConfigurationDuration [] minDurationArray = null;
1025 StreamConfigurationDuration [] stallDurationArray = null;
1026 }
1027
1028 public void initializeStreamConfigurationData(ArrayList<StreamConfiguration> sc,
1029 ArrayList<StreamConfigurationDuration> scd, ArrayList<StreamConfigurationDuration> scs,
1030 StreamConfigurationData /*out*/scData) {
1031 if ((scData == null) || (sc == null)) {
1032 return;
1033 }
1034
1035 scData.streamConfigurationArray = new StreamConfiguration[sc.size()];
1036 scData.streamConfigurationArray = sc.toArray(scData.streamConfigurationArray);
1037
1038 if ((scd != null) && !scd.isEmpty()) {
1039 scData.minDurationArray = new StreamConfigurationDuration[scd.size()];
1040 scData.minDurationArray = scd.toArray(scData.minDurationArray);
1041 } else {
1042 scData.minDurationArray = new StreamConfigurationDuration[0];
1043 }
1044
1045 if ((scs != null) && !scs.isEmpty()) {
1046 scData.stallDurationArray = new StreamConfigurationDuration[scs.size()];
1047 scData.stallDurationArray = scs.toArray(scData.stallDurationArray);
1048 } else {
1049 scData.stallDurationArray = new StreamConfigurationDuration[0];
1050 }
1051 }
1052
1053 /**
1054 * Retrieve the list of recommended stream configurations.
1055 *
1056 * @return A list of recommended stream configuration maps for each common use case or null
1057 * in case the recommended stream configurations are invalid or incomplete.
1058 * @hide
1059 */
1060 public ArrayList<RecommendedStreamConfigurationMap> getRecommendedStreamConfigurations() {
1061 RecommendedStreamConfiguration[] configurations = getBase(
1062 CameraCharacteristics.SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS);
1063 RecommendedStreamConfiguration[] depthConfigurations = getBase(
1064 CameraCharacteristics.DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS);
1065 if ((configurations == null) && (depthConfigurations == null)) {
1066 return null;
1067 }
1068
1069 StreamConfigurationMap fullMap = getStreamConfigurationMap();
1070 ArrayList<RecommendedStreamConfigurationMap> recommendedConfigurations =
1071 new ArrayList<RecommendedStreamConfigurationMap> ();
1072
1073 ArrayList<ArrayList<StreamConfiguration>> streamConfigList =
1074 new ArrayList<ArrayList<StreamConfiguration>>();
1075 ArrayList<ArrayList<StreamConfigurationDuration>> streamDurationList =
1076 new ArrayList<ArrayList<StreamConfigurationDuration>>();
1077 ArrayList<ArrayList<StreamConfigurationDuration>> streamStallList =
1078 new ArrayList<ArrayList<StreamConfigurationDuration>>();
1079 boolean[] supportsPrivate =
1080 new boolean[RecommendedStreamConfigurationMap.MAX_USECASE_COUNT];
1081 try {
1082 if (configurations != null) {
1083 parseRecommendedConfigurations(configurations, fullMap, /*isDepth*/ false,
1084 streamConfigList, streamDurationList, streamStallList, supportsPrivate);
1085 }
1086 } catch (IllegalArgumentException e) {
1087 Log.e(TAG, "Failed parsing the recommended stream configurations!");
1088 return null;
1089 }
1090
1091 ArrayList<ArrayList<StreamConfiguration>> depthStreamConfigList =
1092 new ArrayList<ArrayList<StreamConfiguration>>();
1093 ArrayList<ArrayList<StreamConfigurationDuration>> depthStreamDurationList =
1094 new ArrayList<ArrayList<StreamConfigurationDuration>>();
1095 ArrayList<ArrayList<StreamConfigurationDuration>> depthStreamStallList =
1096 new ArrayList<ArrayList<StreamConfigurationDuration>>();
1097 if (depthConfigurations != null) {
1098 try {
1099 parseRecommendedConfigurations(depthConfigurations, fullMap, /*isDepth*/ true,
1100 depthStreamConfigList, depthStreamDurationList, depthStreamStallList,
1101 /*supportsPrivate*/ null);
1102 } catch (IllegalArgumentException e) {
1103 Log.e(TAG, "Failed parsing the recommended depth stream configurations!");
1104 return null;
1105 }
1106 }
1107
1108 ReprocessFormatsMap inputOutputFormatsMap = getBase(
1109 CameraCharacteristics.SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP);
1110 HighSpeedVideoConfiguration[] highSpeedVideoConfigurations = getBase(
1111 CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
1112 boolean listHighResolution = isBurstSupported();
1113 recommendedConfigurations.ensureCapacity(
1114 RecommendedStreamConfigurationMap.MAX_USECASE_COUNT);
1115 for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) {
1116 StreamConfigurationData scData = new StreamConfigurationData();
1117 if (configurations != null) {
1118 initializeStreamConfigurationData(streamConfigList.get(i),
1119 streamDurationList.get(i), streamStallList.get(i), scData);
1120 }
1121
1122 StreamConfigurationData depthScData = new StreamConfigurationData();
1123 if (depthConfigurations != null) {
1124 initializeStreamConfigurationData(depthStreamConfigList.get(i),
1125 depthStreamDurationList.get(i), depthStreamStallList.get(i), depthScData);
1126 }
1127
Emilian Peev506acca2019-03-12 18:00:42 -07001128 if ((scData.streamConfigurationArray == null ||
1129 scData.streamConfigurationArray.length == 0) &&
1130 (depthScData.streamConfigurationArray == null ||
1131 depthScData.streamConfigurationArray.length == 0)) {
Emilian Peev2776ca32018-09-18 14:00:39 +01001132 recommendedConfigurations.add(null);
1133 continue;
1134 }
1135
Emilian Peev934ffa62019-01-04 17:48:31 +00001136 // Dynamic depth streams involve alot of SW processing and currently cannot be
1137 // recommended.
Emilian Peev2776ca32018-09-18 14:00:39 +01001138 StreamConfigurationMap map = null;
1139 switch (i) {
1140 case RecommendedStreamConfigurationMap.USECASE_PREVIEW:
1141 case RecommendedStreamConfigurationMap.USECASE_RAW:
Emilian Peev506acca2019-03-12 18:00:42 -07001142 case RecommendedStreamConfigurationMap.USECASE_LOW_LATENCY_SNAPSHOT:
Emilian Peev2776ca32018-09-18 14:00:39 +01001143 case RecommendedStreamConfigurationMap.USECASE_VIDEO_SNAPSHOT:
1144 map = new StreamConfigurationMap(scData.streamConfigurationArray,
1145 scData.minDurationArray, scData.stallDurationArray,
1146 /*depthconfiguration*/ null, /*depthminduration*/ null,
Emilian Peev934ffa62019-01-04 17:48:31 +00001147 /*depthstallduration*/ null,
1148 /*dynamicDepthConfigurations*/ null,
1149 /*dynamicDepthMinFrameDurations*/ null,
1150 /*dynamicDepthStallDurations*/ null,
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001151 /*heicconfiguration*/ null,
1152 /*heicminduration*/ null,
1153 /*heicstallduration*/ null,
Emilian Peev934ffa62019-01-04 17:48:31 +00001154 /*highspeedvideoconfigurations*/ null,
Emilian Peev2776ca32018-09-18 14:00:39 +01001155 /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]);
1156 break;
1157 case RecommendedStreamConfigurationMap.USECASE_RECORD:
1158 map = new StreamConfigurationMap(scData.streamConfigurationArray,
1159 scData.minDurationArray, scData.stallDurationArray,
1160 /*depthconfiguration*/ null, /*depthminduration*/ null,
Emilian Peev934ffa62019-01-04 17:48:31 +00001161 /*depthstallduration*/ null,
1162 /*dynamicDepthConfigurations*/ null,
1163 /*dynamicDepthMinFrameDurations*/ null,
1164 /*dynamicDepthStallDurations*/ null,
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001165 /*heicconfiguration*/ null,
1166 /*heicminduration*/ null,
1167 /*heicstallduration*/ null,
Emilian Peev934ffa62019-01-04 17:48:31 +00001168 highSpeedVideoConfigurations,
Emilian Peev2776ca32018-09-18 14:00:39 +01001169 /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]);
1170 break;
1171 case RecommendedStreamConfigurationMap.USECASE_ZSL:
1172 map = new StreamConfigurationMap(scData.streamConfigurationArray,
1173 scData.minDurationArray, scData.stallDurationArray,
1174 depthScData.streamConfigurationArray, depthScData.minDurationArray,
Emilian Peev934ffa62019-01-04 17:48:31 +00001175 depthScData.stallDurationArray,
1176 /*dynamicDepthConfigurations*/ null,
1177 /*dynamicDepthMinFrameDurations*/ null,
1178 /*dynamicDepthStallDurations*/ null,
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001179 /*heicconfiguration*/ null,
1180 /*heicminduration*/ null,
1181 /*heicstallduration*/ null,
Emilian Peev934ffa62019-01-04 17:48:31 +00001182 /*highSpeedVideoConfigurations*/ null,
Emilian Peev2776ca32018-09-18 14:00:39 +01001183 inputOutputFormatsMap, listHighResolution, supportsPrivate[i]);
1184 break;
1185 default:
1186 map = new StreamConfigurationMap(scData.streamConfigurationArray,
1187 scData.minDurationArray, scData.stallDurationArray,
1188 depthScData.streamConfigurationArray, depthScData.minDurationArray,
Emilian Peev934ffa62019-01-04 17:48:31 +00001189 depthScData.stallDurationArray,
1190 /*dynamicDepthConfigurations*/ null,
1191 /*dynamicDepthMinFrameDurations*/ null,
1192 /*dynamicDepthStallDurations*/ null,
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001193 /*heicconfiguration*/ null,
1194 /*heicminduration*/ null,
1195 /*heicstallduration*/ null,
Emilian Peev934ffa62019-01-04 17:48:31 +00001196 /*highSpeedVideoConfigurations*/ null,
Emilian Peev2776ca32018-09-18 14:00:39 +01001197 /*inputOutputFormatsMap*/ null, listHighResolution, supportsPrivate[i]);
1198 }
1199
1200 recommendedConfigurations.add(new RecommendedStreamConfigurationMap(map, /*usecase*/i,
1201 supportsPrivate[i]));
1202 }
1203
1204 return recommendedConfigurations;
1205 }
1206
1207 private boolean isBurstSupported() {
1208 boolean ret = false;
1209
1210 int[] capabilities = getBase(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
1211 for (int capability : capabilities) {
1212 if (capability == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE) {
1213 ret = true;
1214 break;
1215 }
1216 }
1217
1218 return ret;
1219 }
1220
Emilian Peev423cbd72018-11-10 18:37:45 +00001221 private MandatoryStreamCombination[] getMandatoryStreamCombinations() {
1222 int[] capabilities = getBase(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
1223 ArrayList<Integer> caps = new ArrayList<Integer>();
1224 caps.ensureCapacity(capabilities.length);
1225 for (int c : capabilities) {
1226 caps.add(new Integer(c));
1227 }
1228 int hwLevel = getBase(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
1229 MandatoryStreamCombination.Builder build = new MandatoryStreamCombination.Builder(
1230 mCameraId, hwLevel, mDisplaySize, caps, getStreamConfigurationMap());
1231 List<MandatoryStreamCombination> combs = build.getAvailableMandatoryStreamCombinations();
1232 if ((combs != null) && (!combs.isEmpty())) {
1233 MandatoryStreamCombination[] combArray = new MandatoryStreamCombination[combs.size()];
1234 combArray = combs.toArray(combArray);
1235 return combArray;
1236 }
1237
1238 return null;
1239 }
1240
Igor Murashkin9c595172014-05-12 13:56:20 -07001241 private StreamConfigurationMap getStreamConfigurationMap() {
1242 StreamConfiguration[] configurations = getBase(
1243 CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
1244 StreamConfigurationDuration[] minFrameDurations = getBase(
1245 CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
1246 StreamConfigurationDuration[] stallDurations = getBase(
1247 CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS);
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001248 StreamConfiguration[] depthConfigurations = getBase(
1249 CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS);
1250 StreamConfigurationDuration[] depthMinFrameDurations = getBase(
1251 CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS);
1252 StreamConfigurationDuration[] depthStallDurations = getBase(
1253 CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS);
Emilian Peev934ffa62019-01-04 17:48:31 +00001254 StreamConfiguration[] dynamicDepthConfigurations = getBase(
1255 CameraCharacteristics.DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS);
1256 StreamConfigurationDuration[] dynamicDepthMinFrameDurations = getBase(
1257 CameraCharacteristics.DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS);
1258 StreamConfigurationDuration[] dynamicDepthStallDurations = getBase(
1259 CameraCharacteristics.DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS);
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001260 StreamConfiguration[] heicConfigurations = getBase(
1261 CameraCharacteristics.HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS);
1262 StreamConfigurationDuration[] heicMinFrameDurations = getBase(
1263 CameraCharacteristics.HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS);
1264 StreamConfigurationDuration[] heicStallDurations = getBase(
1265 CameraCharacteristics.HEIC_AVAILABLE_HEIC_STALL_DURATIONS);
Yin-Chia Yeh12da1402014-07-15 10:37:31 -07001266 HighSpeedVideoConfiguration[] highSpeedVideoConfigurations = getBase(
1267 CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
Chien-Yu Chen0a551f12015-04-03 17:57:35 -07001268 ReprocessFormatsMap inputOutputFormatsMap = getBase(
1269 CameraCharacteristics.SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP);
Emilian Peev2776ca32018-09-18 14:00:39 +01001270 boolean listHighResolution = isBurstSupported();
Yin-Chia Yeh12da1402014-07-15 10:37:31 -07001271 return new StreamConfigurationMap(
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001272 configurations, minFrameDurations, stallDurations,
1273 depthConfigurations, depthMinFrameDurations, depthStallDurations,
Emilian Peev934ffa62019-01-04 17:48:31 +00001274 dynamicDepthConfigurations, dynamicDepthMinFrameDurations,
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001275 dynamicDepthStallDurations, heicConfigurations,
1276 heicMinFrameDurations, heicStallDurations,
1277 highSpeedVideoConfigurations, inputOutputFormatsMap,
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001278 listHighResolution);
Igor Murashkin9c595172014-05-12 13:56:20 -07001279 }
1280
Igor Murashkin78712a82014-05-27 18:32:18 -07001281 private <T> Integer getMaxRegions(Key<T> key) {
1282 final int AE = 0;
1283 final int AWB = 1;
1284 final int AF = 2;
1285
1286 // The order of the elements is: (AE, AWB, AF)
1287 int[] maxRegions = getBase(CameraCharacteristics.CONTROL_MAX_REGIONS);
1288
1289 if (maxRegions == null) {
1290 return null;
1291 }
1292
1293 if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AE)) {
1294 return maxRegions[AE];
1295 } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB)) {
1296 return maxRegions[AWB];
1297 } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AF)) {
1298 return maxRegions[AF];
1299 } else {
1300 throw new AssertionError("Invalid key " + key);
1301 }
1302 }
1303
1304 private <T> Integer getMaxNumOutputs(Key<T> key) {
1305 final int RAW = 0;
1306 final int PROC = 1;
1307 final int PROC_STALLING = 2;
1308
1309 // The order of the elements is: (raw, proc+nonstalling, proc+stalling)
1310 int[] maxNumOutputs = getBase(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_STREAMS);
1311
1312 if (maxNumOutputs == null) {
1313 return null;
1314 }
1315
1316 if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW)) {
1317 return maxNumOutputs[RAW];
1318 } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC)) {
1319 return maxNumOutputs[PROC];
1320 } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING)) {
1321 return maxNumOutputs[PROC_STALLING];
1322 } else {
1323 throw new AssertionError("Invalid key " + key);
1324 }
1325 }
1326
Yin-Chia Yeh8490ace2014-05-27 10:04:54 -07001327 private <T> TonemapCurve getTonemapCurve() {
1328 float[] red = getBase(CaptureRequest.TONEMAP_CURVE_RED);
1329 float[] green = getBase(CaptureRequest.TONEMAP_CURVE_GREEN);
1330 float[] blue = getBase(CaptureRequest.TONEMAP_CURVE_BLUE);
Yin-Chia Yehd47699a2014-08-28 10:35:37 -07001331
1332 if (areValuesAllNull(red, green, blue)) {
1333 return null;
1334 }
1335
Yin-Chia Yeh8490ace2014-05-27 10:04:54 -07001336 if (red == null || green == null || blue == null) {
Yin-Chia Yehd47699a2014-08-28 10:35:37 -07001337 Log.w(TAG, "getTonemapCurve - missing tone curve components");
Yin-Chia Yeh8490ace2014-05-27 10:04:54 -07001338 return null;
1339 }
1340 TonemapCurve tc = new TonemapCurve(red, green, blue);
1341 return tc;
1342 }
1343
Chien-Yu Chenc804d1c2018-02-15 12:44:19 -08001344 private OisSample[] getOisSamples() {
1345 long[] timestamps = getBase(CaptureResult.STATISTICS_OIS_TIMESTAMPS);
1346 float[] xShifts = getBase(CaptureResult.STATISTICS_OIS_X_SHIFTS);
1347 float[] yShifts = getBase(CaptureResult.STATISTICS_OIS_Y_SHIFTS);
1348
1349 if (timestamps == null) {
1350 if (xShifts != null) {
1351 throw new AssertionError("timestamps is null but xShifts is not");
1352 }
1353
1354 if (yShifts != null) {
1355 throw new AssertionError("timestamps is null but yShifts is not");
1356 }
1357
1358 return null;
1359 }
1360
1361 if (xShifts == null) {
1362 throw new AssertionError("timestamps is not null but xShifts is");
1363 }
1364
1365 if (yShifts == null) {
1366 throw new AssertionError("timestamps is not null but yShifts is");
1367 }
1368
1369 if (xShifts.length != timestamps.length) {
1370 throw new AssertionError(String.format(
1371 "timestamps has %d entries but xShifts has %d", timestamps.length,
1372 xShifts.length));
1373 }
1374
1375 if (yShifts.length != timestamps.length) {
1376 throw new AssertionError(String.format(
1377 "timestamps has %d entries but yShifts has %d", timestamps.length,
1378 yShifts.length));
1379 }
1380
1381 OisSample[] samples = new OisSample[timestamps.length];
1382 for (int i = 0; i < timestamps.length; i++) {
1383 samples[i] = new OisSample(timestamps[i], xShifts[i], yShifts[i]);
1384 }
1385 return samples;
1386 }
1387
Shuzhen Wang1ab85142019-07-08 15:14:16 -07001388 private CapabilityAndMaxSize[] getBokehCapabilities() {
1389 CapabilityAndMaxSize[] bcs = getBase(
1390 CameraCharacteristics.CONTROL_AVAILABLE_BOKEH_CAPABILITIES);
1391
1392 if (bcs != null) {
1393 for (CapabilityAndMaxSize bc : bcs) {
1394 if (bc.getMode() < CameraMetadata.CONTROL_BOKEH_MODE_OFF ||
1395 bc.getMode() > CameraMetadata.CONTROL_BOKEH_MODE_CONTINUOUS) {
1396 throw new AssertionError(String.format(
1397 "bokehMode %d is out of valid range [%d, %d]", bc.getMode(),
1398 CameraMetadata.CONTROL_BOKEH_MODE_OFF,
1399 CameraMetadata.CONTROL_BOKEH_MODE_CONTINUOUS));
1400 }
1401 }
1402 }
1403 return bcs;
1404 }
1405
Igor Murashkind6d65152014-05-19 16:31:02 -07001406 private <T> void setBase(CameraCharacteristics.Key<T> key, T value) {
1407 setBase(key.getNativeKey(), value);
1408 }
1409
1410 private <T> void setBase(CaptureResult.Key<T> key, T value) {
1411 setBase(key.getNativeKey(), value);
1412 }
1413
1414 private <T> void setBase(CaptureRequest.Key<T> key, T value) {
1415 setBase(key.getNativeKey(), value);
1416 }
1417
Zhijun Heb7bfdc72013-10-02 11:39:43 -07001418 private <T> void setBase(Key<T> key, T value) {
Emilian Peevde62d842017-03-23 19:20:40 +00001419 int tag = nativeGetTagFromKeyLocal(key.getName());
Zhijun Heb7bfdc72013-10-02 11:39:43 -07001420 if (value == null) {
Igor Murashkin3c40a042014-04-22 15:05:50 -07001421 // Erase the entry
1422 writeValues(tag, /*src*/null);
Zhijun Heb7bfdc72013-10-02 11:39:43 -07001423 return;
Igor Murashkin3c40a042014-04-22 15:05:50 -07001424 } // else update the entry to a new value
Zhijun Heb7bfdc72013-10-02 11:39:43 -07001425
Emilian Peevde62d842017-03-23 19:20:40 +00001426 int nativeType = nativeGetTypeFromTagLocal(tag);
1427 Marshaler<T> marshaler = getMarshalerForKey(key, nativeType);
Igor Murashkin3c40a042014-04-22 15:05:50 -07001428 int size = marshaler.calculateMarshalSize(value);
Zhijun Heb7bfdc72013-10-02 11:39:43 -07001429
1430 // TODO: Optimization. Cache the byte[] and reuse if the size is big enough.
1431 byte[] values = new byte[size];
1432
1433 ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
Igor Murashkin3c40a042014-04-22 15:05:50 -07001434 marshaler.marshal(value, buffer);
Zhijun Heb7bfdc72013-10-02 11:39:43 -07001435
1436 writeValues(tag, values);
1437 }
1438
Ruben Brunkd1f113d2014-07-11 11:46:20 -07001439 // Use Command pattern here to avoid lots of expensive if/equals checks in get for overridden
1440 // metadata.
1441 private static final HashMap<Key<?>, SetCommand> sSetCommandMap =
1442 new HashMap<Key<?>, SetCommand>();
1443 static {
1444 sSetCommandMap.put(CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey(),
1445 new SetCommand() {
1446 @Override
1447 public <T> void setValue(CameraMetadataNative metadata, T value) {
1448 metadata.setAvailableFormats((int[]) value);
1449 }
1450 });
1451 sSetCommandMap.put(CaptureResult.STATISTICS_FACE_RECTANGLES.getNativeKey(),
1452 new SetCommand() {
1453 @Override
1454 public <T> void setValue(CameraMetadataNative metadata, T value) {
1455 metadata.setFaceRectangles((Rect[]) value);
1456 }
1457 });
Igor Murashkin0a1ef4d2014-07-31 15:53:34 -07001458 sSetCommandMap.put(CaptureResult.STATISTICS_FACES.getNativeKey(),
1459 new SetCommand() {
1460 @Override
1461 public <T> void setValue(CameraMetadataNative metadata, T value) {
1462 metadata.setFaces((Face[])value);
1463 }
1464 });
Ruben Brunkd1f113d2014-07-11 11:46:20 -07001465 sSetCommandMap.put(CaptureRequest.TONEMAP_CURVE.getNativeKey(), new SetCommand() {
1466 @Override
1467 public <T> void setValue(CameraMetadataNative metadata, T value) {
1468 metadata.setTonemapCurve((TonemapCurve) value);
1469 }
1470 });
1471 sSetCommandMap.put(CaptureResult.JPEG_GPS_LOCATION.getNativeKey(), new SetCommand() {
1472 @Override
1473 public <T> void setValue(CameraMetadataNative metadata, T value) {
1474 metadata.setGpsLocation((Location) value);
1475 }
1476 });
Zhijun Heb7bfdc72013-10-02 11:39:43 -07001477 }
1478
1479 private boolean setAvailableFormats(int[] value) {
1480 int[] availableFormat = value;
1481 if (value == null) {
1482 // Let setBase() to handle the null value case.
1483 return false;
1484 }
1485
1486 int[] newValues = new int[availableFormat.length];
1487 for (int i = 0; i < availableFormat.length; i++) {
1488 newValues[i] = availableFormat[i];
1489 if (availableFormat[i] == ImageFormat.JPEG) {
1490 newValues[i] = NATIVE_JPEG_FORMAT;
1491 }
1492 }
1493
1494 setBase(CameraCharacteristics.SCALER_AVAILABLE_FORMATS, newValues);
1495 return true;
1496 }
1497
Zhijun He2f1680b2013-11-13 13:16:56 -08001498 /**
1499 * Convert Face Rectangles from managed side to native side as they have different definitions.
1500 * <p>
1501 * Managed side face rectangles are defined as: left, top, width, height.
1502 * Native side face rectangles are defined as: left, top, right, bottom.
1503 * The input face rectangle need to be converted to native side definition when set is called.
1504 * </p>
1505 *
1506 * @param faceRects Input face rectangles.
1507 * @return true if face rectangles can be set successfully. Otherwise, Let the caller
1508 * (setBase) to handle it appropriately.
1509 */
1510 private boolean setFaceRectangles(Rect[] faceRects) {
1511 if (faceRects == null) {
1512 return false;
1513 }
1514
1515 Rect[] newFaceRects = new Rect[faceRects.length];
1516 for (int i = 0; i < newFaceRects.length; i++) {
1517 newFaceRects[i] = new Rect(
1518 faceRects[i].left,
1519 faceRects[i].top,
1520 faceRects[i].right + faceRects[i].left,
1521 faceRects[i].bottom + faceRects[i].top);
1522 }
1523
1524 setBase(CaptureResult.STATISTICS_FACE_RECTANGLES, newFaceRects);
1525 return true;
1526 }
1527
Yin-Chia Yeh8490ace2014-05-27 10:04:54 -07001528 private <T> boolean setTonemapCurve(TonemapCurve tc) {
1529 if (tc == null) {
1530 return false;
1531 }
1532
1533 float[][] curve = new float[3][];
1534 for (int i = TonemapCurve.CHANNEL_RED; i <= TonemapCurve.CHANNEL_BLUE; i++) {
1535 int pointCount = tc.getPointCount(i);
1536 curve[i] = new float[pointCount * TonemapCurve.POINT_SIZE];
1537 tc.copyColorCurve(i, curve[i], 0);
1538 }
1539 setBase(CaptureRequest.TONEMAP_CURVE_RED, curve[0]);
1540 setBase(CaptureRequest.TONEMAP_CURVE_GREEN, curve[1]);
1541 setBase(CaptureRequest.TONEMAP_CURVE_BLUE, curve[2]);
1542
1543 return true;
1544 }
1545
Emilian Peev423cbd72018-11-10 18:37:45 +00001546 private int mCameraId = -1;
1547 private Size mDisplaySize = new Size(0, 0);
1548
1549 /**
1550 * Set the current camera Id.
1551 *
1552 * @param cameraId Current camera id.
1553 *
1554 * @hide
1555 */
1556 public void setCameraId(int cameraId) {
1557 mCameraId = cameraId;
1558 }
1559
1560 /**
1561 * Set the current display size.
1562 *
1563 * @param displaySize The current display size.
1564 *
1565 * @hide
1566 */
1567 public void setDisplaySize(Size displaySize) {
1568 mDisplaySize = displaySize;
1569 }
1570
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001571 @UnsupportedAppUsage
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001572 private long mMetadataPtr; // native CameraMetadata*
1573
1574 private native long nativeAllocate();
1575 private native long nativeAllocateCopy(CameraMetadataNative other)
1576 throws NullPointerException;
1577
1578 private native synchronized void nativeWriteToParcel(Parcel dest);
1579 private native synchronized void nativeReadFromParcel(Parcel source);
1580 private native synchronized void nativeSwap(CameraMetadataNative other)
1581 throws NullPointerException;
1582 private native synchronized void nativeClose();
1583 private native synchronized boolean nativeIsEmpty();
1584 private native synchronized int nativeGetEntryCount();
1585
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001586 @UnsupportedAppUsage
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001587 private native synchronized byte[] nativeReadValues(int tag);
1588 private native synchronized void nativeWriteValues(int tag, byte[] src);
Igor Murashkind6d65152014-05-19 16:31:02 -07001589 private native synchronized void nativeDump() throws IOException; // dump to ALOGD
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001590
Emilian Peevde62d842017-03-23 19:20:40 +00001591 private native synchronized ArrayList nativeGetAllVendorKeys(Class keyClass);
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001592 @UnsupportedAppUsage
Emilian Peevde62d842017-03-23 19:20:40 +00001593 private native synchronized int nativeGetTagFromKeyLocal(String keyName)
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001594 throws IllegalArgumentException;
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001595 @UnsupportedAppUsage
Emilian Peevde62d842017-03-23 19:20:40 +00001596 private native synchronized int nativeGetTypeFromTagLocal(int tag)
1597 throws IllegalArgumentException;
1598 private static native int nativeGetTagFromKey(String keyName, long vendorId)
1599 throws IllegalArgumentException;
1600 private static native int nativeGetTypeFromTag(int tag, long vendorId)
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001601 throws IllegalArgumentException;
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001602
1603 /**
1604 * <p>Perform a 0-copy swap of the internal metadata with another object.</p>
1605 *
1606 * <p>Useful to convert a CameraMetadata into e.g. a CaptureRequest.</p>
1607 *
1608 * @param other Metadata to swap with
1609 * @throws NullPointerException if other was null
1610 * @hide
1611 */
1612 public void swap(CameraMetadataNative other) {
1613 nativeSwap(other);
Emilian Peev423cbd72018-11-10 18:37:45 +00001614 mCameraId = other.mCameraId;
1615 mDisplaySize = other.mDisplaySize;
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001616 }
1617
1618 /**
1619 * @hide
1620 */
1621 public int getEntryCount() {
1622 return nativeGetEntryCount();
1623 }
1624
1625 /**
1626 * Does this metadata contain at least 1 entry?
1627 *
1628 * @hide
1629 */
1630 public boolean isEmpty() {
1631 return nativeIsEmpty();
1632 }
1633
Ruben Brunkc620eb72015-07-29 18:19:11 -07001634
1635 /**
1636 * Return a list containing keys of the given key class for all defined vendor tags.
1637 *
1638 * @hide
1639 */
Emilian Peevde62d842017-03-23 19:20:40 +00001640 public <K> ArrayList<K> getAllVendorKeys(Class<K> keyClass) {
Ruben Brunkc620eb72015-07-29 18:19:11 -07001641 if (keyClass == null) {
1642 throw new NullPointerException();
1643 }
1644 return (ArrayList<K>) nativeGetAllVendorKeys(keyClass);
1645 }
1646
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001647 /**
1648 * Convert a key string into the equivalent native tag.
1649 *
1650 * @throws IllegalArgumentException if the key was not recognized
1651 * @throws NullPointerException if the key was null
1652 *
1653 * @hide
1654 */
1655 public static int getTag(String key) {
Emilian Peevde62d842017-03-23 19:20:40 +00001656 return nativeGetTagFromKey(key, Long.MAX_VALUE);
1657 }
1658
1659 /**
1660 * Convert a key string into the equivalent native tag.
1661 *
1662 * @throws IllegalArgumentException if the key was not recognized
1663 * @throws NullPointerException if the key was null
1664 *
1665 * @hide
1666 */
1667 public static int getTag(String key, long vendorId) {
1668 return nativeGetTagFromKey(key, vendorId);
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001669 }
1670
1671 /**
1672 * Get the underlying native type for a tag.
1673 *
1674 * @param tag An integer tag, see e.g. {@link #getTag}
Emilian Peevde62d842017-03-23 19:20:40 +00001675 * @param vendorId A vendor tag provider id
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001676 * @return An int enum for the metadata type, see e.g. {@link #TYPE_BYTE}
1677 *
1678 * @hide
1679 */
Emilian Peevde62d842017-03-23 19:20:40 +00001680 public static int getNativeType(int tag, long vendorId) {
1681 return nativeGetTypeFromTag(tag, vendorId);
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001682 }
1683
1684 /**
1685 * <p>Updates the existing entry for tag with the new bytes pointed by src, erasing
1686 * the entry if src was null.</p>
1687 *
1688 * <p>An empty array can be passed in to update the entry to 0 elements.</p>
1689 *
1690 * @param tag An integer tag, see e.g. {@link #getTag}
1691 * @param src An array of bytes, or null to erase the entry
1692 *
1693 * @hide
1694 */
1695 public void writeValues(int tag, byte[] src) {
1696 nativeWriteValues(tag, src);
1697 }
1698
1699 /**
1700 * <p>Returns a byte[] of data corresponding to this tag. Use a wrapped bytebuffer to unserialize
1701 * the data properly.</p>
1702 *
1703 * <p>An empty array can be returned to denote an existing entry with 0 elements.</p>
1704 *
1705 * @param tag An integer tag, see e.g. {@link #getTag}
1706 *
1707 * @return {@code null} if there were 0 entries for this tag, a byte[] otherwise.
1708 * @hide
1709 */
1710 public byte[] readValues(int tag) {
Zhijun Heb7bfdc72013-10-02 11:39:43 -07001711 // TODO: Optimization. Native code returns a ByteBuffer instead.
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001712 return nativeReadValues(tag);
1713 }
1714
Igor Murashkind6d65152014-05-19 16:31:02 -07001715 /**
1716 * Dumps the native metadata contents to logcat.
1717 *
1718 * <p>Visibility for testing/debugging only. The results will not
1719 * include any synthesized keys, as they are invisible to the native layer.</p>
1720 *
1721 * @hide
1722 */
1723 public void dumpToLog() {
1724 try {
1725 nativeDump();
1726 } catch (IOException e) {
1727 Log.wtf(TAG, "Dump logging failed", e);
1728 }
1729 }
1730
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001731 @Override
1732 protected void finalize() throws Throwable {
1733 try {
1734 close();
1735 } finally {
1736 super.finalize();
1737 }
1738 }
1739
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001740 /**
Igor Murashkin3c40a042014-04-22 15:05:50 -07001741 * Get the marshaler compatible with the {@code key} and type {@code T}.
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001742 *
Igor Murashkin3c40a042014-04-22 15:05:50 -07001743 * @throws UnsupportedOperationException
1744 * if the native/managed type combination for {@code key} is not supported
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001745 */
Emilian Peevde62d842017-03-23 19:20:40 +00001746 private static <T> Marshaler<T> getMarshalerForKey(Key<T> key, int nativeType) {
Igor Murashkin3c40a042014-04-22 15:05:50 -07001747 return MarshalRegistry.getMarshaler(key.getTypeReference(),
Emilian Peevde62d842017-03-23 19:20:40 +00001748 nativeType);
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001749 }
1750
Igor Murashkin3c40a042014-04-22 15:05:50 -07001751 @SuppressWarnings({ "unchecked", "rawtypes" })
1752 private static void registerAllMarshalers() {
Eino-Ville Talvalaa78791f2015-06-01 12:39:54 -07001753 if (DEBUG) {
Eino-Ville Talvala51ca8d62013-10-04 14:39:58 -07001754 Log.v(TAG, "Shall register metadata marshalers");
1755 }
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001756
Igor Murashkin3c40a042014-04-22 15:05:50 -07001757 MarshalQueryable[] queryList = new MarshalQueryable[] {
1758 // marshalers for standard types
1759 new MarshalQueryablePrimitive(),
1760 new MarshalQueryableEnum(),
1761 new MarshalQueryableArray(),
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001762
Igor Murashkin3c40a042014-04-22 15:05:50 -07001763 // pseudo standard types, that expand/narrow the native type into a managed type
1764 new MarshalQueryableBoolean(),
1765 new MarshalQueryableNativeByteToInteger(),
1766
1767 // marshalers for custom types
1768 new MarshalQueryableRect(),
1769 new MarshalQueryableSize(),
1770 new MarshalQueryableSizeF(),
1771 new MarshalQueryableString(),
1772 new MarshalQueryableReprocessFormatsMap(),
1773 new MarshalQueryableRange(),
Igor Murashkin57438682014-05-30 10:49:00 -07001774 new MarshalQueryablePair(),
Igor Murashkin3c40a042014-04-22 15:05:50 -07001775 new MarshalQueryableMeteringRectangle(),
1776 new MarshalQueryableColorSpaceTransform(),
1777 new MarshalQueryableStreamConfiguration(),
1778 new MarshalQueryableStreamConfigurationDuration(),
1779 new MarshalQueryableRggbChannelVector(),
Ruben Brunk52842e72014-06-05 13:16:45 -07001780 new MarshalQueryableBlackLevelPattern(),
Yin-Chia Yeh12da1402014-07-15 10:37:31 -07001781 new MarshalQueryableHighSpeedVideoConfiguration(),
Emilian Peev2776ca32018-09-18 14:00:39 +01001782 new MarshalQueryableRecommendedStreamConfiguration(),
Shuzhen Wang1ab85142019-07-08 15:14:16 -07001783 new MarshalQueryableCapabilityAndMaxSize(),
Igor Murashkin3c40a042014-04-22 15:05:50 -07001784
1785 // generic parcelable marshaler (MUST BE LAST since it has lowest priority)
1786 new MarshalQueryableParcelable(),
1787 };
1788
1789 for (MarshalQueryable query : queryList) {
1790 MarshalRegistry.registerMarshalQueryable(query);
1791 }
Eino-Ville Talvalaa78791f2015-06-01 12:39:54 -07001792 if (DEBUG) {
Eino-Ville Talvala51ca8d62013-10-04 14:39:58 -07001793 Log.v(TAG, "Registered metadata marshalers");
1794 }
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001795 }
1796
Yin-Chia Yehd47699a2014-08-28 10:35:37 -07001797 /** Check if input arguments are all {@code null}.
1798 *
1799 * @param objs Input arguments for null check
1800 * @return {@code true} if input arguments are all {@code null}, otherwise {@code false}
1801 */
1802 private static boolean areValuesAllNull(Object... objs) {
1803 for (Object o : objs) {
1804 if (o != null) return false;
1805 }
1806 return true;
1807 }
1808
Igor Murashkin3c40a042014-04-22 15:05:50 -07001809 static {
Igor Murashkin3c40a042014-04-22 15:05:50 -07001810 registerAllMarshalers();
1811 }
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001812}