blob: e926a98d9c2bb742e6c413fb43f64d1b6c4b5ff6 [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
Zhijun Heb7bfdc72013-10-02 11:39:43 -070019import android.graphics.ImageFormat;
20import android.graphics.Point;
21import android.graphics.Rect;
22import android.hardware.camera2.CameraCharacteristics;
Igor Murashkind6d65152014-05-19 16:31:02 -070023import android.hardware.camera2.CaptureRequest;
Zhijun Heb7bfdc72013-10-02 11:39:43 -070024import android.hardware.camera2.CaptureResult;
Igor Murashkin3c40a042014-04-22 15:05:50 -070025import android.hardware.camera2.marshal.Marshaler;
26import android.hardware.camera2.marshal.MarshalQueryable;
27import android.hardware.camera2.marshal.MarshalRegistry;
28import android.hardware.camera2.marshal.impl.MarshalQueryableArray;
29import android.hardware.camera2.marshal.impl.MarshalQueryableBoolean;
Ruben Brunk52842e72014-06-05 13:16:45 -070030import android.hardware.camera2.marshal.impl.MarshalQueryableBlackLevelPattern;
Igor Murashkin3c40a042014-04-22 15:05:50 -070031import android.hardware.camera2.marshal.impl.MarshalQueryableColorSpaceTransform;
32import android.hardware.camera2.marshal.impl.MarshalQueryableEnum;
Yin-Chia Yeh12da1402014-07-15 10:37:31 -070033import android.hardware.camera2.marshal.impl.MarshalQueryableHighSpeedVideoConfiguration;
Igor Murashkin3c40a042014-04-22 15:05:50 -070034import android.hardware.camera2.marshal.impl.MarshalQueryableMeteringRectangle;
35import android.hardware.camera2.marshal.impl.MarshalQueryableNativeByteToInteger;
Igor Murashkin57438682014-05-30 10:49:00 -070036import android.hardware.camera2.marshal.impl.MarshalQueryablePair;
Igor Murashkin3c40a042014-04-22 15:05:50 -070037import android.hardware.camera2.marshal.impl.MarshalQueryableParcelable;
38import android.hardware.camera2.marshal.impl.MarshalQueryablePrimitive;
39import android.hardware.camera2.marshal.impl.MarshalQueryableRange;
40import android.hardware.camera2.marshal.impl.MarshalQueryableRect;
41import android.hardware.camera2.marshal.impl.MarshalQueryableReprocessFormatsMap;
42import android.hardware.camera2.marshal.impl.MarshalQueryableRggbChannelVector;
43import android.hardware.camera2.marshal.impl.MarshalQueryableSize;
44import android.hardware.camera2.marshal.impl.MarshalQueryableSizeF;
45import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfiguration;
46import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration;
47import android.hardware.camera2.marshal.impl.MarshalQueryableString;
Igor Murashkin72f9f0a2014-05-14 15:46:10 -070048import android.hardware.camera2.params.Face;
Yin-Chia Yeh12da1402014-07-15 10:37:31 -070049import android.hardware.camera2.params.HighSpeedVideoConfiguration;
Ruben Brunk57493682014-05-27 18:58:08 -070050import android.hardware.camera2.params.LensShadingMap;
Igor Murashkin9c595172014-05-12 13:56:20 -070051import android.hardware.camera2.params.StreamConfiguration;
52import android.hardware.camera2.params.StreamConfigurationDuration;
53import android.hardware.camera2.params.StreamConfigurationMap;
Yin-Chia Yeh8490ace2014-05-27 10:04:54 -070054import android.hardware.camera2.params.TonemapCurve;
Igor Murashkind6d65152014-05-19 16:31:02 -070055import android.hardware.camera2.utils.TypeReference;
Ruben Brunk57493682014-05-27 18:58:08 -070056import android.location.Location;
57import android.location.LocationManager;
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070058import android.os.Parcelable;
59import android.os.Parcel;
60import android.util.Log;
Ruben Brunk57493682014-05-27 18:58:08 -070061import android.util.Size;
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070062
Igor Murashkind6d65152014-05-19 16:31:02 -070063import com.android.internal.util.Preconditions;
64
65import java.io.IOException;
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070066import java.nio.ByteBuffer;
67import java.nio.ByteOrder;
68import java.util.ArrayList;
Ruben Brunk57493682014-05-27 18:58:08 -070069import java.util.HashMap;
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070070
71/**
72 * Implementation of camera metadata marshal/unmarshal across Binder to
73 * the camera service
74 */
Igor Murashkind6d65152014-05-19 16:31:02 -070075public class CameraMetadataNative implements Parcelable {
76
77 public static class Key<T> {
78 private boolean mHasTag;
79 private int mTag;
80 private final Class<T> mType;
81 private final TypeReference<T> mTypeReference;
82 private final String mName;
Ruben Brunkd1f113d2014-07-11 11:46:20 -070083 private final int mHash;
Igor Murashkind6d65152014-05-19 16:31:02 -070084 /**
85 * Visible for testing only.
86 *
87 * <p>Use the CameraCharacteristics.Key, CaptureResult.Key, or CaptureRequest.Key
88 * for application code or vendor-extended keys.</p>
89 */
90 public Key(String name, Class<T> type) {
91 if (name == null) {
92 throw new NullPointerException("Key needs a valid name");
93 } else if (type == null) {
94 throw new NullPointerException("Type needs to be non-null");
95 }
96 mName = name;
97 mType = type;
98 mTypeReference = TypeReference.createSpecializedTypeReference(type);
Ruben Brunkd1f113d2014-07-11 11:46:20 -070099 mHash = mName.hashCode() ^ mTypeReference.hashCode();
Igor Murashkind6d65152014-05-19 16:31:02 -0700100 }
101
102 /**
103 * Visible for testing only.
104 *
105 * <p>Use the CameraCharacteristics.Key, CaptureResult.Key, or CaptureRequest.Key
106 * for application code or vendor-extended keys.</p>
107 */
108 @SuppressWarnings("unchecked")
109 public Key(String name, TypeReference<T> typeReference) {
110 if (name == null) {
111 throw new NullPointerException("Key needs a valid name");
112 } else if (typeReference == null) {
113 throw new NullPointerException("TypeReference needs to be non-null");
114 }
115 mName = name;
116 mType = (Class<T>)typeReference.getRawType();
117 mTypeReference = typeReference;
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700118 mHash = mName.hashCode() ^ mTypeReference.hashCode();
Igor Murashkind6d65152014-05-19 16:31:02 -0700119 }
120
121 /**
122 * Return a camelCase, period separated name formatted like:
123 * {@code "root.section[.subsections].name"}.
124 *
125 * <p>Built-in keys exposed by the Android SDK are always prefixed with {@code "android."};
126 * keys that are device/platform-specific are prefixed with {@code "com."}.</p>
127 *
128 * <p>For example, {@code CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP} would
129 * have a name of {@code "android.scaler.streamConfigurationMap"}; whereas a device
130 * specific key might look like {@code "com.google.nexus.data.private"}.</p>
131 *
132 * @return String representation of the key name
133 */
134 public final String getName() {
135 return mName;
136 }
137
138 /**
139 * {@inheritDoc}
140 */
141 @Override
142 public final int hashCode() {
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700143 return mHash;
Igor Murashkind6d65152014-05-19 16:31:02 -0700144 }
145
146 /**
147 * Compare this key against other native keys, request keys, result keys, and
148 * characteristics keys.
149 *
150 * <p>Two keys are considered equal if their name and type reference are equal.</p>
151 *
152 * <p>Note that the equality against non-native keys is one-way. A native key may be equal
153 * to a result key; but that same result key will not be equal to a native key.</p>
154 */
155 @SuppressWarnings("rawtypes")
156 @Override
157 public final boolean equals(Object o) {
158 if (this == o) {
159 return true;
160 }
161
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700162 if (o == null || this.hashCode() != o.hashCode()) {
163 return false;
164 }
165
Igor Murashkind6d65152014-05-19 16:31:02 -0700166 Key<?> lhs;
167
168 if (o instanceof CaptureResult.Key) {
169 lhs = ((CaptureResult.Key)o).getNativeKey();
170 } else if (o instanceof CaptureRequest.Key) {
171 lhs = ((CaptureRequest.Key)o).getNativeKey();
172 } else if (o instanceof CameraCharacteristics.Key) {
173 lhs = ((CameraCharacteristics.Key)o).getNativeKey();
174 } else if ((o instanceof Key)) {
175 lhs = (Key<?>)o;
176 } else {
177 return false;
178 }
179
180 return mName.equals(lhs.mName) && mTypeReference.equals(lhs.mTypeReference);
181 }
182
183 /**
184 * <p>
185 * Get the tag corresponding to this key. This enables insertion into the
186 * native metadata.
187 * </p>
188 *
189 * <p>This value is looked up the first time, and cached subsequently.</p>
190 *
191 * @return The tag numeric value corresponding to the string
192 */
193 public final int getTag() {
194 if (!mHasTag) {
195 mTag = CameraMetadataNative.getTag(mName);
196 mHasTag = true;
197 }
198 return mTag;
199 }
200
201 /**
202 * Get the raw class backing the type {@code T} for this key.
203 *
204 * <p>The distinction is only important if {@code T} is a generic, e.g.
205 * {@code Range<Integer>} since the nested type will be erased.</p>
206 */
207 public final Class<T> getType() {
208 // TODO: remove this; other places should use #getTypeReference() instead
209 return mType;
210 }
211
212 /**
213 * Get the type reference backing the type {@code T} for this key.
214 *
215 * <p>The distinction is only important if {@code T} is a generic, e.g.
216 * {@code Range<Integer>} since the nested type will be retained.</p>
217 */
218 public final TypeReference<T> getTypeReference() {
219 return mTypeReference;
220 }
221 }
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700222
223 private static final String TAG = "CameraMetadataJV";
Eino-Ville Talvala227c09f2013-10-04 16:14:38 -0700224 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700225 // this should be in sync with HAL_PIXEL_FORMAT_BLOB defined in graphics.h
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700226 public static final int NATIVE_JPEG_FORMAT = 0x21;
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700227
Ruben Brunk57493682014-05-27 18:58:08 -0700228 private static final String CELLID_PROCESS = "CELLID";
229 private static final String GPS_PROCESS = "GPS";
Igor Murashkin0a1ef4d2014-07-31 15:53:34 -0700230 private static final int FACE_LANDMARK_SIZE = 6;
Ruben Brunk57493682014-05-27 18:58:08 -0700231
232 private static String translateLocationProviderToProcess(final String provider) {
233 if (provider == null) {
234 return null;
235 }
236 switch(provider) {
237 case LocationManager.GPS_PROVIDER:
238 return GPS_PROCESS;
239 case LocationManager.NETWORK_PROVIDER:
240 return CELLID_PROCESS;
241 default:
242 return null;
243 }
244 }
245
246 private static String translateProcessToLocationProvider(final String process) {
247 if (process == null) {
248 return null;
249 }
250 switch(process) {
251 case GPS_PROCESS:
252 return LocationManager.GPS_PROVIDER;
253 case CELLID_PROCESS:
254 return LocationManager.NETWORK_PROVIDER;
255 default:
256 return null;
257 }
258 }
259
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700260 public CameraMetadataNative() {
261 super();
262 mMetadataPtr = nativeAllocate();
263 if (mMetadataPtr == 0) {
264 throw new OutOfMemoryError("Failed to allocate native CameraMetadata");
265 }
266 }
267
268 /**
269 * Copy constructor - clone metadata
270 */
271 public CameraMetadataNative(CameraMetadataNative other) {
272 super();
273 mMetadataPtr = nativeAllocateCopy(other);
274 if (mMetadataPtr == 0) {
275 throw new OutOfMemoryError("Failed to allocate native CameraMetadata");
276 }
277 }
278
Igor Murashkind6d65152014-05-19 16:31:02 -0700279 /**
280 * Move the contents from {@code other} into a new camera metadata instance.</p>
281 *
282 * <p>After this call, {@code other} will become empty.</p>
283 *
284 * @param other the previous metadata instance which will get pilfered
285 * @return a new metadata instance with the values from {@code other} moved into it
286 */
287 public static CameraMetadataNative move(CameraMetadataNative other) {
288 CameraMetadataNative newObject = new CameraMetadataNative();
289 newObject.swap(other);
290 return newObject;
291 }
292
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700293 public static final Parcelable.Creator<CameraMetadataNative> CREATOR =
294 new Parcelable.Creator<CameraMetadataNative>() {
295 @Override
296 public CameraMetadataNative createFromParcel(Parcel in) {
297 CameraMetadataNative metadata = new CameraMetadataNative();
298 metadata.readFromParcel(in);
299 return metadata;
300 }
301
302 @Override
303 public CameraMetadataNative[] newArray(int size) {
304 return new CameraMetadataNative[size];
305 }
306 };
307
308 @Override
309 public int describeContents() {
310 return 0;
311 }
312
313 @Override
314 public void writeToParcel(Parcel dest, int flags) {
315 nativeWriteToParcel(dest);
316 }
317
Igor Murashkind6d65152014-05-19 16:31:02 -0700318 /**
319 * @hide
320 */
321 public <T> T get(CameraCharacteristics.Key<T> key) {
322 return get(key.getNativeKey());
323 }
324
325 /**
326 * @hide
327 */
328 public <T> T get(CaptureResult.Key<T> key) {
329 return get(key.getNativeKey());
330 }
331
332 /**
333 * @hide
334 */
335 public <T> T get(CaptureRequest.Key<T> key) {
336 return get(key.getNativeKey());
337 }
338
339 /**
340 * Look-up a metadata field value by its key.
341 *
342 * @param key a non-{@code null} key instance
343 * @return the field corresponding to the {@code key}, or {@code null} if no value was set
344 */
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700345 public <T> T get(Key<T> key) {
Igor Murashkind6d65152014-05-19 16:31:02 -0700346 Preconditions.checkNotNull(key, "key must not be null");
347
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700348 // Check if key has been overridden to use a wrapper class on the java side.
349 GetCommand g = sGetCommandMap.get(key);
350 if (g != null) {
Igor Murashkin0a1ef4d2014-07-31 15:53:34 -0700351 return g.getValue(this, key);
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700352 }
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700353 return getBase(key);
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700354 }
355
356 public void readFromParcel(Parcel in) {
357 nativeReadFromParcel(in);
358 }
359
360 /**
Ruben Brunk85c43882014-02-21 17:40:51 -0800361 * Set the global client-side vendor tag descriptor to allow use of vendor
362 * tags in camera applications.
363 *
364 * @return int A native status_t value corresponding to one of the
365 * {@link CameraBinderDecorator} integer constants.
366 * @see CameraBinderDecorator#throwOnError
367 *
368 * @hide
369 */
370 public static native int nativeSetupGlobalVendorTagDescriptor();
371
372 /**
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700373 * Set a camera metadata field to a value. The field definitions can be
Igor Murashkin68f40062013-09-10 12:15:54 -0700374 * found in {@link CameraCharacteristics}, {@link CaptureResult}, and
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700375 * {@link CaptureRequest}.
376 *
377 * @param key The metadata field to write.
378 * @param value The value to set the field to, which must be of a matching
379 * type to the key.
380 */
381 public <T> void set(Key<T> key, T value) {
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700382 SetCommand s = sSetCommandMap.get(key);
383 if (s != null) {
384 s.setValue(this, value);
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700385 return;
386 }
387
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700388 setBase(key, value);
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700389 }
390
Igor Murashkind6d65152014-05-19 16:31:02 -0700391 public <T> void set(CaptureRequest.Key<T> key, T value) {
392 set(key.getNativeKey(), value);
393 }
394
395 public <T> void set(CaptureResult.Key<T> key, T value) {
396 set(key.getNativeKey(), value);
397 }
398
399 public <T> void set(CameraCharacteristics.Key<T> key, T value) {
400 set(key.getNativeKey(), value);
401 }
402
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700403 // Keep up-to-date with camera_metadata.h
404 /**
405 * @hide
406 */
407 public static final int TYPE_BYTE = 0;
408 /**
409 * @hide
410 */
411 public static final int TYPE_INT32 = 1;
412 /**
413 * @hide
414 */
415 public static final int TYPE_FLOAT = 2;
416 /**
417 * @hide
418 */
419 public static final int TYPE_INT64 = 3;
420 /**
421 * @hide
422 */
423 public static final int TYPE_DOUBLE = 4;
424 /**
425 * @hide
426 */
427 public static final int TYPE_RATIONAL = 5;
428 /**
429 * @hide
430 */
431 public static final int NUM_TYPES = 6;
432
433 private void close() {
434 // this sets mMetadataPtr to 0
435 nativeClose();
436 mMetadataPtr = 0; // set it to 0 again to prevent eclipse from making this field final
437 }
438
Igor Murashkind6d65152014-05-19 16:31:02 -0700439 private <T> T getBase(CameraCharacteristics.Key<T> key) {
440 return getBase(key.getNativeKey());
441 }
442
443 private <T> T getBase(CaptureResult.Key<T> key) {
444 return getBase(key.getNativeKey());
445 }
446
447 private <T> T getBase(CaptureRequest.Key<T> key) {
448 return getBase(key.getNativeKey());
449 }
450
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700451 private <T> T getBase(Key<T> key) {
452 int tag = key.getTag();
453 byte[] values = readValues(tag);
454 if (values == null) {
455 return null;
456 }
457
Igor Murashkin3c40a042014-04-22 15:05:50 -0700458 Marshaler<T> marshaler = getMarshalerForKey(key);
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700459 ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
Igor Murashkin3c40a042014-04-22 15:05:50 -0700460 return marshaler.unmarshal(buffer);
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700461 }
Igor Murashkin78712a82014-05-27 18:32:18 -0700462
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700463 // Use Command pattern here to avoid lots of expensive if/equals checks in get for overridden
464 // metadata.
465 private static final HashMap<Key<?>, GetCommand> sGetCommandMap =
466 new HashMap<Key<?>, GetCommand>();
467 static {
468 sGetCommandMap.put(
469 CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey(), new GetCommand() {
470 @Override
471 @SuppressWarnings("unchecked")
472 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
473 return (T) metadata.getAvailableFormats();
474 }
475 });
476 sGetCommandMap.put(
477 CaptureResult.STATISTICS_FACES.getNativeKey(), new GetCommand() {
478 @Override
479 @SuppressWarnings("unchecked")
480 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
Ruben Brunk40001f52014-07-17 11:02:28 -0700481 return (T) metadata.getFaces();
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700482 }
483 });
484 sGetCommandMap.put(
485 CaptureResult.STATISTICS_FACE_RECTANGLES.getNativeKey(), new GetCommand() {
486 @Override
487 @SuppressWarnings("unchecked")
488 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
Ruben Brunk40001f52014-07-17 11:02:28 -0700489 return (T) metadata.getFaceRectangles();
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700490 }
491 });
492 sGetCommandMap.put(
493 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP.getNativeKey(),
494 new GetCommand() {
495 @Override
496 @SuppressWarnings("unchecked")
497 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
498 return (T) metadata.getStreamConfigurationMap();
499 }
500 });
501 sGetCommandMap.put(
502 CameraCharacteristics.CONTROL_MAX_REGIONS_AE.getNativeKey(), new GetCommand() {
503 @Override
504 @SuppressWarnings("unchecked")
505 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
506 return (T) metadata.getMaxRegions(key);
507 }
508 });
509 sGetCommandMap.put(
510 CameraCharacteristics.CONTROL_MAX_REGIONS_AWB.getNativeKey(), new GetCommand() {
511 @Override
512 @SuppressWarnings("unchecked")
513 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
514 return (T) metadata.getMaxRegions(key);
515 }
516 });
517 sGetCommandMap.put(
518 CameraCharacteristics.CONTROL_MAX_REGIONS_AF.getNativeKey(), new GetCommand() {
519 @Override
520 @SuppressWarnings("unchecked")
521 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
522 return (T) metadata.getMaxRegions(key);
523 }
524 });
525 sGetCommandMap.put(
526 CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW.getNativeKey(), new GetCommand() {
527 @Override
528 @SuppressWarnings("unchecked")
529 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
530 return (T) metadata.getMaxNumOutputs(key);
531 }
532 });
533 sGetCommandMap.put(
534 CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC.getNativeKey(), new GetCommand() {
535 @Override
536 @SuppressWarnings("unchecked")
537 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
538 return (T) metadata.getMaxNumOutputs(key);
539 }
540 });
541 sGetCommandMap.put(
542 CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING.getNativeKey(),
543 new GetCommand() {
544 @Override
545 @SuppressWarnings("unchecked")
546 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
547 return (T) metadata.getMaxNumOutputs(key);
548 }
549 });
550 sGetCommandMap.put(
551 CaptureRequest.TONEMAP_CURVE.getNativeKey(), new GetCommand() {
552 @Override
553 @SuppressWarnings("unchecked")
554 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
555 return (T) metadata.getTonemapCurve();
556 }
557 });
558 sGetCommandMap.put(
559 CaptureResult.JPEG_GPS_LOCATION.getNativeKey(), new GetCommand() {
560 @Override
561 @SuppressWarnings("unchecked")
562 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
563 return (T) metadata.getGpsLocation();
564 }
565 });
566 sGetCommandMap.put(
567 CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP.getNativeKey(),
568 new GetCommand() {
569 @Override
570 @SuppressWarnings("unchecked")
571 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
572 return (T) metadata.getLensShadingMap();
573 }
574 });
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700575 }
576
577 private int[] getAvailableFormats() {
578 int[] availableFormats = getBase(CameraCharacteristics.SCALER_AVAILABLE_FORMATS);
Zhijun He2f1680b2013-11-13 13:16:56 -0800579 if (availableFormats != null) {
580 for (int i = 0; i < availableFormats.length; i++) {
581 // JPEG has different value between native and managed side, need override.
582 if (availableFormats[i] == NATIVE_JPEG_FORMAT) {
583 availableFormats[i] = ImageFormat.JPEG;
584 }
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700585 }
586 }
Zhijun He2f1680b2013-11-13 13:16:56 -0800587
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700588 return availableFormats;
589 }
590
Igor Murashkin0a1ef4d2014-07-31 15:53:34 -0700591 private boolean setFaces(Face[] faces) {
592 if (faces == null) {
593 return false;
594 }
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700595
Igor Murashkin0a1ef4d2014-07-31 15:53:34 -0700596 int numFaces = faces.length;
597
598 // Detect if all faces are SIMPLE or not; count # of valid faces
599 boolean fullMode = true;
600 for (Face face : faces) {
601 if (face == null) {
602 numFaces--;
603 Log.w(TAG, "setFaces - null face detected, skipping");
604 continue;
605 }
606
607 if (face.getId() == Face.ID_UNSUPPORTED) {
608 fullMode = false;
609 }
610 }
611
612 Rect[] faceRectangles = new Rect[numFaces];
613 byte[] faceScores = new byte[numFaces];
614 int[] faceIds = null;
615 int[] faceLandmarks = null;
616
617 if (fullMode) {
618 faceIds = new int[numFaces];
619 faceLandmarks = new int[numFaces * FACE_LANDMARK_SIZE];
620 }
621
622 int i = 0;
623 for (Face face : faces) {
624 if (face == null) {
625 continue;
626 }
627
628 faceRectangles[i] = face.getBounds();
629 faceScores[i] = (byte)face.getScore();
630
631 if (fullMode) {
632 faceIds[i] = face.getId();
633
634 int j = 0;
635
636 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getLeftEyePosition().x;
637 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getLeftEyePosition().y;
638 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getRightEyePosition().x;
639 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getRightEyePosition().y;
640 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getMouthPosition().x;
641 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getMouthPosition().y;
642 }
643
644 i++;
645 }
646
647 set(CaptureResult.STATISTICS_FACE_RECTANGLES, faceRectangles);
648 set(CaptureResult.STATISTICS_FACE_IDS, faceIds);
649 set(CaptureResult.STATISTICS_FACE_LANDMARKS, faceLandmarks);
650 set(CaptureResult.STATISTICS_FACE_SCORES, faceScores);
651
652 return true;
653 }
654
655 private Face[] getFaces() {
Zhijun He58216c22013-10-14 15:29:37 -0700656 Integer faceDetectMode = get(CaptureResult.STATISTICS_FACE_DETECT_MODE);
Yin-Chia Yehd47699a2014-08-28 10:35:37 -0700657 byte[] faceScores = get(CaptureResult.STATISTICS_FACE_SCORES);
658 Rect[] faceRectangles = get(CaptureResult.STATISTICS_FACE_RECTANGLES);
659 int[] faceIds = get(CaptureResult.STATISTICS_FACE_IDS);
660 int[] faceLandmarks = get(CaptureResult.STATISTICS_FACE_LANDMARKS);
661
662 if (areValuesAllNull(faceDetectMode, faceScores, faceRectangles, faceIds, faceLandmarks)) {
663 return null;
664 }
665
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700666 if (faceDetectMode == null) {
Zhijun He58216c22013-10-14 15:29:37 -0700667 Log.w(TAG, "Face detect mode metadata is null, assuming the mode is SIMPLE");
668 faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE;
669 } else {
670 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_OFF) {
671 return new Face[0];
672 }
673 if (faceDetectMode != CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE &&
674 faceDetectMode != CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) {
675 Log.w(TAG, "Unknown face detect mode: " + faceDetectMode);
676 return new Face[0];
677 }
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700678 }
679
680 // Face scores and rectangles are required by SIMPLE and FULL mode.
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700681 if (faceScores == null || faceRectangles == null) {
Zhijun He58216c22013-10-14 15:29:37 -0700682 Log.w(TAG, "Expect face scores and rectangles to be non-null");
683 return new Face[0];
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700684 } else if (faceScores.length != faceRectangles.length) {
Zhijun He58216c22013-10-14 15:29:37 -0700685 Log.w(TAG, String.format("Face score size(%d) doesn match face rectangle size(%d)!",
686 faceScores.length, faceRectangles.length));
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700687 }
688
Zhijun He58216c22013-10-14 15:29:37 -0700689 // To be safe, make number of faces is the minimal of all face info metadata length.
690 int numFaces = Math.min(faceScores.length, faceRectangles.length);
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700691 // Face id and landmarks are only required by FULL mode.
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700692 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) {
693 if (faceIds == null || faceLandmarks == null) {
Zhijun He58216c22013-10-14 15:29:37 -0700694 Log.w(TAG, "Expect face ids and landmarks to be non-null for FULL mode," +
695 "fallback to SIMPLE mode");
696 faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE;
697 } else {
698 if (faceIds.length != numFaces ||
699 faceLandmarks.length != numFaces * FACE_LANDMARK_SIZE) {
700 Log.w(TAG, String.format("Face id size(%d), or face landmark size(%d) don't" +
701 "match face number(%d)!",
702 faceIds.length, faceLandmarks.length * FACE_LANDMARK_SIZE, numFaces));
703 }
704 // To be safe, make number of faces is the minimal of all face info metadata length.
705 numFaces = Math.min(numFaces, faceIds.length);
706 numFaces = Math.min(numFaces, faceLandmarks.length / FACE_LANDMARK_SIZE);
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700707 }
708 }
709
Zhijun He844b3522013-10-16 16:13:50 -0700710 ArrayList<Face> faceList = new ArrayList<Face>();
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700711 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE) {
712 for (int i = 0; i < numFaces; i++) {
Zhijun He844b3522013-10-16 16:13:50 -0700713 if (faceScores[i] <= Face.SCORE_MAX &&
714 faceScores[i] >= Face.SCORE_MIN) {
715 faceList.add(new Face(faceRectangles[i], faceScores[i]));
716 }
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700717 }
718 } else {
719 // CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL
720 for (int i = 0; i < numFaces; i++) {
Zhijun He844b3522013-10-16 16:13:50 -0700721 if (faceScores[i] <= Face.SCORE_MAX &&
722 faceScores[i] >= Face.SCORE_MIN &&
723 faceIds[i] >= 0) {
Igor Murashkin0a1ef4d2014-07-31 15:53:34 -0700724 Point leftEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE],
725 faceLandmarks[i*FACE_LANDMARK_SIZE+1]);
726 Point rightEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+2],
727 faceLandmarks[i*FACE_LANDMARK_SIZE+3]);
728 Point mouth = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+4],
729 faceLandmarks[i*FACE_LANDMARK_SIZE+5]);
Zhijun He844b3522013-10-16 16:13:50 -0700730 Face face = new Face(faceRectangles[i], faceScores[i], faceIds[i],
731 leftEye, rightEye, mouth);
732 faceList.add(face);
733 }
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700734 }
735 }
Zhijun He844b3522013-10-16 16:13:50 -0700736 Face[] faces = new Face[faceList.size()];
737 faceList.toArray(faces);
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700738 return faces;
739 }
740
Eino-Ville Talvala615b75f2013-10-14 18:20:43 -0700741 // Face rectangles are defined as (left, top, right, bottom) instead of
742 // (left, top, width, height) at the native level, so the normal Rect
743 // conversion that does (l, t, w, h) -> (l, t, r, b) is unnecessary. Undo
744 // that conversion here for just the faces.
Zhijun He2f1680b2013-11-13 13:16:56 -0800745 private Rect[] getFaceRectangles() {
Eino-Ville Talvala615b75f2013-10-14 18:20:43 -0700746 Rect[] faceRectangles = getBase(CaptureResult.STATISTICS_FACE_RECTANGLES);
747 if (faceRectangles == null) return null;
748
749 Rect[] fixedFaceRectangles = new Rect[faceRectangles.length];
750 for (int i = 0; i < faceRectangles.length; i++) {
751 fixedFaceRectangles[i] = new Rect(
752 faceRectangles[i].left,
753 faceRectangles[i].top,
754 faceRectangles[i].right - faceRectangles[i].left,
755 faceRectangles[i].bottom - faceRectangles[i].top);
756 }
757 return fixedFaceRectangles;
758 }
759
Ruben Brunk57493682014-05-27 18:58:08 -0700760 private LensShadingMap getLensShadingMap() {
761 float[] lsmArray = getBase(CaptureResult.STATISTICS_LENS_SHADING_MAP);
Yin-Chia Yehd47699a2014-08-28 10:35:37 -0700762 Size s = get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE);
763
764 // Do not warn if lsmArray is null while s is not. This is valid.
Ruben Brunk57493682014-05-27 18:58:08 -0700765 if (lsmArray == null) {
Ruben Brunk57493682014-05-27 18:58:08 -0700766 return null;
767 }
Yin-Chia Yehd47699a2014-08-28 10:35:37 -0700768
769 if (s == null) {
770 Log.w(TAG, "getLensShadingMap - Lens shading map size was null.");
771 return null;
772 }
773
Ruben Brunk57493682014-05-27 18:58:08 -0700774 LensShadingMap map = new LensShadingMap(lsmArray, s.getHeight(), s.getWidth());
775 return map;
776 }
777
778 private Location getGpsLocation() {
779 String processingMethod = get(CaptureResult.JPEG_GPS_PROCESSING_METHOD);
Ruben Brunk57493682014-05-27 18:58:08 -0700780 double[] coords = get(CaptureResult.JPEG_GPS_COORDINATES);
781 Long timeStamp = get(CaptureResult.JPEG_GPS_TIMESTAMP);
782
Yin-Chia Yehd47699a2014-08-28 10:35:37 -0700783 if (areValuesAllNull(processingMethod, coords, timeStamp)) {
784 return null;
785 }
786
787 Location l = new Location(translateProcessToLocationProvider(processingMethod));
Ruben Brunk57493682014-05-27 18:58:08 -0700788 if (timeStamp != null) {
789 l.setTime(timeStamp);
790 } else {
791 Log.w(TAG, "getGpsLocation - No timestamp for GPS location.");
792 }
793
794 if (coords != null) {
795 l.setLatitude(coords[0]);
796 l.setLongitude(coords[1]);
797 l.setAltitude(coords[2]);
798 } else {
799 Log.w(TAG, "getGpsLocation - No coordinates for GPS location");
800 }
801
802 return l;
803 }
804
805 private boolean setGpsLocation(Location l) {
806 if (l == null) {
807 return false;
808 }
809
810 double[] coords = { l.getLatitude(), l.getLongitude(), l.getAltitude() };
811 String processMethod = translateLocationProviderToProcess(l.getProvider());
812 long timestamp = l.getTime();
813
814 set(CaptureRequest.JPEG_GPS_TIMESTAMP, timestamp);
815 set(CaptureRequest.JPEG_GPS_COORDINATES, coords);
816
817 if (processMethod == null) {
818 Log.w(TAG, "setGpsLocation - No process method, Location is not from a GPS or NETWORK" +
819 "provider");
820 } else {
821 setBase(CaptureRequest.JPEG_GPS_PROCESSING_METHOD, processMethod);
822 }
823 return true;
824 }
825
Igor Murashkin9c595172014-05-12 13:56:20 -0700826 private StreamConfigurationMap getStreamConfigurationMap() {
827 StreamConfiguration[] configurations = getBase(
828 CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
829 StreamConfigurationDuration[] minFrameDurations = getBase(
830 CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
831 StreamConfigurationDuration[] stallDurations = getBase(
832 CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS);
Eino-Ville Talvala838beb22015-03-05 15:42:49 -0800833 StreamConfiguration[] depthConfigurations = getBase(
834 CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS);
835 StreamConfigurationDuration[] depthMinFrameDurations = getBase(
836 CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS);
837 StreamConfigurationDuration[] depthStallDurations = getBase(
838 CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS);
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700839 HighSpeedVideoConfiguration[] highSpeedVideoConfigurations = getBase(
840 CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
Igor Murashkin9c595172014-05-12 13:56:20 -0700841
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700842 return new StreamConfigurationMap(
Eino-Ville Talvala838beb22015-03-05 15:42:49 -0800843 configurations, minFrameDurations, stallDurations,
844 depthConfigurations, depthMinFrameDurations, depthStallDurations,
845 highSpeedVideoConfigurations);
Igor Murashkin9c595172014-05-12 13:56:20 -0700846 }
847
Igor Murashkin78712a82014-05-27 18:32:18 -0700848 private <T> Integer getMaxRegions(Key<T> key) {
849 final int AE = 0;
850 final int AWB = 1;
851 final int AF = 2;
852
853 // The order of the elements is: (AE, AWB, AF)
854 int[] maxRegions = getBase(CameraCharacteristics.CONTROL_MAX_REGIONS);
855
856 if (maxRegions == null) {
857 return null;
858 }
859
860 if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AE)) {
861 return maxRegions[AE];
862 } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB)) {
863 return maxRegions[AWB];
864 } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AF)) {
865 return maxRegions[AF];
866 } else {
867 throw new AssertionError("Invalid key " + key);
868 }
869 }
870
871 private <T> Integer getMaxNumOutputs(Key<T> key) {
872 final int RAW = 0;
873 final int PROC = 1;
874 final int PROC_STALLING = 2;
875
876 // The order of the elements is: (raw, proc+nonstalling, proc+stalling)
877 int[] maxNumOutputs = getBase(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_STREAMS);
878
879 if (maxNumOutputs == null) {
880 return null;
881 }
882
883 if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW)) {
884 return maxNumOutputs[RAW];
885 } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC)) {
886 return maxNumOutputs[PROC];
887 } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING)) {
888 return maxNumOutputs[PROC_STALLING];
889 } else {
890 throw new AssertionError("Invalid key " + key);
891 }
892 }
893
Yin-Chia Yeh8490ace2014-05-27 10:04:54 -0700894 private <T> TonemapCurve getTonemapCurve() {
895 float[] red = getBase(CaptureRequest.TONEMAP_CURVE_RED);
896 float[] green = getBase(CaptureRequest.TONEMAP_CURVE_GREEN);
897 float[] blue = getBase(CaptureRequest.TONEMAP_CURVE_BLUE);
Yin-Chia Yehd47699a2014-08-28 10:35:37 -0700898
899 if (areValuesAllNull(red, green, blue)) {
900 return null;
901 }
902
Yin-Chia Yeh8490ace2014-05-27 10:04:54 -0700903 if (red == null || green == null || blue == null) {
Yin-Chia Yehd47699a2014-08-28 10:35:37 -0700904 Log.w(TAG, "getTonemapCurve - missing tone curve components");
Yin-Chia Yeh8490ace2014-05-27 10:04:54 -0700905 return null;
906 }
907 TonemapCurve tc = new TonemapCurve(red, green, blue);
908 return tc;
909 }
910
Igor Murashkind6d65152014-05-19 16:31:02 -0700911 private <T> void setBase(CameraCharacteristics.Key<T> key, T value) {
912 setBase(key.getNativeKey(), value);
913 }
914
915 private <T> void setBase(CaptureResult.Key<T> key, T value) {
916 setBase(key.getNativeKey(), value);
917 }
918
919 private <T> void setBase(CaptureRequest.Key<T> key, T value) {
920 setBase(key.getNativeKey(), value);
921 }
922
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700923 private <T> void setBase(Key<T> key, T value) {
924 int tag = key.getTag();
925
926 if (value == null) {
Igor Murashkin3c40a042014-04-22 15:05:50 -0700927 // Erase the entry
928 writeValues(tag, /*src*/null);
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700929 return;
Igor Murashkin3c40a042014-04-22 15:05:50 -0700930 } // else update the entry to a new value
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700931
Igor Murashkin3c40a042014-04-22 15:05:50 -0700932 Marshaler<T> marshaler = getMarshalerForKey(key);
933 int size = marshaler.calculateMarshalSize(value);
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700934
935 // TODO: Optimization. Cache the byte[] and reuse if the size is big enough.
936 byte[] values = new byte[size];
937
938 ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
Igor Murashkin3c40a042014-04-22 15:05:50 -0700939 marshaler.marshal(value, buffer);
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700940
941 writeValues(tag, values);
942 }
943
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700944 // Use Command pattern here to avoid lots of expensive if/equals checks in get for overridden
945 // metadata.
946 private static final HashMap<Key<?>, SetCommand> sSetCommandMap =
947 new HashMap<Key<?>, SetCommand>();
948 static {
949 sSetCommandMap.put(CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey(),
950 new SetCommand() {
951 @Override
952 public <T> void setValue(CameraMetadataNative metadata, T value) {
953 metadata.setAvailableFormats((int[]) value);
954 }
955 });
956 sSetCommandMap.put(CaptureResult.STATISTICS_FACE_RECTANGLES.getNativeKey(),
957 new SetCommand() {
958 @Override
959 public <T> void setValue(CameraMetadataNative metadata, T value) {
960 metadata.setFaceRectangles((Rect[]) value);
961 }
962 });
Igor Murashkin0a1ef4d2014-07-31 15:53:34 -0700963 sSetCommandMap.put(CaptureResult.STATISTICS_FACES.getNativeKey(),
964 new SetCommand() {
965 @Override
966 public <T> void setValue(CameraMetadataNative metadata, T value) {
967 metadata.setFaces((Face[])value);
968 }
969 });
Ruben Brunkd1f113d2014-07-11 11:46:20 -0700970 sSetCommandMap.put(CaptureRequest.TONEMAP_CURVE.getNativeKey(), new SetCommand() {
971 @Override
972 public <T> void setValue(CameraMetadataNative metadata, T value) {
973 metadata.setTonemapCurve((TonemapCurve) value);
974 }
975 });
976 sSetCommandMap.put(CaptureResult.JPEG_GPS_LOCATION.getNativeKey(), new SetCommand() {
977 @Override
978 public <T> void setValue(CameraMetadataNative metadata, T value) {
979 metadata.setGpsLocation((Location) value);
980 }
981 });
Zhijun Heb7bfdc72013-10-02 11:39:43 -0700982 }
983
984 private boolean setAvailableFormats(int[] value) {
985 int[] availableFormat = value;
986 if (value == null) {
987 // Let setBase() to handle the null value case.
988 return false;
989 }
990
991 int[] newValues = new int[availableFormat.length];
992 for (int i = 0; i < availableFormat.length; i++) {
993 newValues[i] = availableFormat[i];
994 if (availableFormat[i] == ImageFormat.JPEG) {
995 newValues[i] = NATIVE_JPEG_FORMAT;
996 }
997 }
998
999 setBase(CameraCharacteristics.SCALER_AVAILABLE_FORMATS, newValues);
1000 return true;
1001 }
1002
Zhijun He2f1680b2013-11-13 13:16:56 -08001003 /**
1004 * Convert Face Rectangles from managed side to native side as they have different definitions.
1005 * <p>
1006 * Managed side face rectangles are defined as: left, top, width, height.
1007 * Native side face rectangles are defined as: left, top, right, bottom.
1008 * The input face rectangle need to be converted to native side definition when set is called.
1009 * </p>
1010 *
1011 * @param faceRects Input face rectangles.
1012 * @return true if face rectangles can be set successfully. Otherwise, Let the caller
1013 * (setBase) to handle it appropriately.
1014 */
1015 private boolean setFaceRectangles(Rect[] faceRects) {
1016 if (faceRects == null) {
1017 return false;
1018 }
1019
1020 Rect[] newFaceRects = new Rect[faceRects.length];
1021 for (int i = 0; i < newFaceRects.length; i++) {
1022 newFaceRects[i] = new Rect(
1023 faceRects[i].left,
1024 faceRects[i].top,
1025 faceRects[i].right + faceRects[i].left,
1026 faceRects[i].bottom + faceRects[i].top);
1027 }
1028
1029 setBase(CaptureResult.STATISTICS_FACE_RECTANGLES, newFaceRects);
1030 return true;
1031 }
1032
Yin-Chia Yeh8490ace2014-05-27 10:04:54 -07001033 private <T> boolean setTonemapCurve(TonemapCurve tc) {
1034 if (tc == null) {
1035 return false;
1036 }
1037
1038 float[][] curve = new float[3][];
1039 for (int i = TonemapCurve.CHANNEL_RED; i <= TonemapCurve.CHANNEL_BLUE; i++) {
1040 int pointCount = tc.getPointCount(i);
1041 curve[i] = new float[pointCount * TonemapCurve.POINT_SIZE];
1042 tc.copyColorCurve(i, curve[i], 0);
1043 }
1044 setBase(CaptureRequest.TONEMAP_CURVE_RED, curve[0]);
1045 setBase(CaptureRequest.TONEMAP_CURVE_GREEN, curve[1]);
1046 setBase(CaptureRequest.TONEMAP_CURVE_BLUE, curve[2]);
1047
1048 return true;
1049 }
1050
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001051 private long mMetadataPtr; // native CameraMetadata*
1052
1053 private native long nativeAllocate();
1054 private native long nativeAllocateCopy(CameraMetadataNative other)
1055 throws NullPointerException;
1056
1057 private native synchronized void nativeWriteToParcel(Parcel dest);
1058 private native synchronized void nativeReadFromParcel(Parcel source);
1059 private native synchronized void nativeSwap(CameraMetadataNative other)
1060 throws NullPointerException;
1061 private native synchronized void nativeClose();
1062 private native synchronized boolean nativeIsEmpty();
1063 private native synchronized int nativeGetEntryCount();
1064
1065 private native synchronized byte[] nativeReadValues(int tag);
1066 private native synchronized void nativeWriteValues(int tag, byte[] src);
Igor Murashkind6d65152014-05-19 16:31:02 -07001067 private native synchronized void nativeDump() throws IOException; // dump to ALOGD
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001068
1069 private static native int nativeGetTagFromKey(String keyName)
1070 throws IllegalArgumentException;
1071 private static native int nativeGetTypeFromTag(int tag)
1072 throws IllegalArgumentException;
1073 private static native void nativeClassInit();
1074
1075 /**
1076 * <p>Perform a 0-copy swap of the internal metadata with another object.</p>
1077 *
1078 * <p>Useful to convert a CameraMetadata into e.g. a CaptureRequest.</p>
1079 *
1080 * @param other Metadata to swap with
1081 * @throws NullPointerException if other was null
1082 * @hide
1083 */
1084 public void swap(CameraMetadataNative other) {
1085 nativeSwap(other);
1086 }
1087
1088 /**
1089 * @hide
1090 */
1091 public int getEntryCount() {
1092 return nativeGetEntryCount();
1093 }
1094
1095 /**
1096 * Does this metadata contain at least 1 entry?
1097 *
1098 * @hide
1099 */
1100 public boolean isEmpty() {
1101 return nativeIsEmpty();
1102 }
1103
1104 /**
1105 * Convert a key string into the equivalent native tag.
1106 *
1107 * @throws IllegalArgumentException if the key was not recognized
1108 * @throws NullPointerException if the key was null
1109 *
1110 * @hide
1111 */
1112 public static int getTag(String key) {
1113 return nativeGetTagFromKey(key);
1114 }
1115
1116 /**
1117 * Get the underlying native type for a tag.
1118 *
1119 * @param tag An integer tag, see e.g. {@link #getTag}
1120 * @return An int enum for the metadata type, see e.g. {@link #TYPE_BYTE}
1121 *
1122 * @hide
1123 */
1124 public static int getNativeType(int tag) {
1125 return nativeGetTypeFromTag(tag);
1126 }
1127
1128 /**
1129 * <p>Updates the existing entry for tag with the new bytes pointed by src, erasing
1130 * the entry if src was null.</p>
1131 *
1132 * <p>An empty array can be passed in to update the entry to 0 elements.</p>
1133 *
1134 * @param tag An integer tag, see e.g. {@link #getTag}
1135 * @param src An array of bytes, or null to erase the entry
1136 *
1137 * @hide
1138 */
1139 public void writeValues(int tag, byte[] src) {
1140 nativeWriteValues(tag, src);
1141 }
1142
1143 /**
1144 * <p>Returns a byte[] of data corresponding to this tag. Use a wrapped bytebuffer to unserialize
1145 * the data properly.</p>
1146 *
1147 * <p>An empty array can be returned to denote an existing entry with 0 elements.</p>
1148 *
1149 * @param tag An integer tag, see e.g. {@link #getTag}
1150 *
1151 * @return {@code null} if there were 0 entries for this tag, a byte[] otherwise.
1152 * @hide
1153 */
1154 public byte[] readValues(int tag) {
Zhijun Heb7bfdc72013-10-02 11:39:43 -07001155 // TODO: Optimization. Native code returns a ByteBuffer instead.
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001156 return nativeReadValues(tag);
1157 }
1158
Igor Murashkind6d65152014-05-19 16:31:02 -07001159 /**
1160 * Dumps the native metadata contents to logcat.
1161 *
1162 * <p>Visibility for testing/debugging only. The results will not
1163 * include any synthesized keys, as they are invisible to the native layer.</p>
1164 *
1165 * @hide
1166 */
1167 public void dumpToLog() {
1168 try {
1169 nativeDump();
1170 } catch (IOException e) {
1171 Log.wtf(TAG, "Dump logging failed", e);
1172 }
1173 }
1174
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001175 @Override
1176 protected void finalize() throws Throwable {
1177 try {
1178 close();
1179 } finally {
1180 super.finalize();
1181 }
1182 }
1183
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001184 /**
Igor Murashkin3c40a042014-04-22 15:05:50 -07001185 * Get the marshaler compatible with the {@code key} and type {@code T}.
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001186 *
Igor Murashkin3c40a042014-04-22 15:05:50 -07001187 * @throws UnsupportedOperationException
1188 * if the native/managed type combination for {@code key} is not supported
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001189 */
Igor Murashkin3c40a042014-04-22 15:05:50 -07001190 private static <T> Marshaler<T> getMarshalerForKey(Key<T> key) {
1191 return MarshalRegistry.getMarshaler(key.getTypeReference(),
1192 getNativeType(key.getTag()));
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001193 }
1194
Igor Murashkin3c40a042014-04-22 15:05:50 -07001195 @SuppressWarnings({ "unchecked", "rawtypes" })
1196 private static void registerAllMarshalers() {
Eino-Ville Talvala51ca8d62013-10-04 14:39:58 -07001197 if (VERBOSE) {
1198 Log.v(TAG, "Shall register metadata marshalers");
1199 }
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001200
Igor Murashkin3c40a042014-04-22 15:05:50 -07001201 MarshalQueryable[] queryList = new MarshalQueryable[] {
1202 // marshalers for standard types
1203 new MarshalQueryablePrimitive(),
1204 new MarshalQueryableEnum(),
1205 new MarshalQueryableArray(),
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001206
Igor Murashkin3c40a042014-04-22 15:05:50 -07001207 // pseudo standard types, that expand/narrow the native type into a managed type
1208 new MarshalQueryableBoolean(),
1209 new MarshalQueryableNativeByteToInteger(),
1210
1211 // marshalers for custom types
1212 new MarshalQueryableRect(),
1213 new MarshalQueryableSize(),
1214 new MarshalQueryableSizeF(),
1215 new MarshalQueryableString(),
1216 new MarshalQueryableReprocessFormatsMap(),
1217 new MarshalQueryableRange(),
Igor Murashkin57438682014-05-30 10:49:00 -07001218 new MarshalQueryablePair(),
Igor Murashkin3c40a042014-04-22 15:05:50 -07001219 new MarshalQueryableMeteringRectangle(),
1220 new MarshalQueryableColorSpaceTransform(),
1221 new MarshalQueryableStreamConfiguration(),
1222 new MarshalQueryableStreamConfigurationDuration(),
1223 new MarshalQueryableRggbChannelVector(),
Ruben Brunk52842e72014-06-05 13:16:45 -07001224 new MarshalQueryableBlackLevelPattern(),
Yin-Chia Yeh12da1402014-07-15 10:37:31 -07001225 new MarshalQueryableHighSpeedVideoConfiguration(),
Igor Murashkin3c40a042014-04-22 15:05:50 -07001226
1227 // generic parcelable marshaler (MUST BE LAST since it has lowest priority)
1228 new MarshalQueryableParcelable(),
1229 };
1230
1231 for (MarshalQueryable query : queryList) {
1232 MarshalRegistry.registerMarshalQueryable(query);
1233 }
Eino-Ville Talvala51ca8d62013-10-04 14:39:58 -07001234 if (VERBOSE) {
1235 Log.v(TAG, "Registered metadata marshalers");
1236 }
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001237 }
1238
Yin-Chia Yehd47699a2014-08-28 10:35:37 -07001239 /** Check if input arguments are all {@code null}.
1240 *
1241 * @param objs Input arguments for null check
1242 * @return {@code true} if input arguments are all {@code null}, otherwise {@code false}
1243 */
1244 private static boolean areValuesAllNull(Object... objs) {
1245 for (Object o : objs) {
1246 if (o != null) return false;
1247 }
1248 return true;
1249 }
1250
Igor Murashkin3c40a042014-04-22 15:05:50 -07001251 static {
1252 /*
1253 * We use a class initializer to allow the native code to cache some field offsets
1254 */
1255 nativeClassInit();
1256 registerAllMarshalers();
1257 }
Eino-Ville Talvala70c22072013-08-27 12:09:04 -07001258}