1 /* 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 17 package android.hardware.camera2.impl; 18 19 import android.compat.annotation.UnsupportedAppUsage; 20 import android.graphics.ImageFormat; 21 import android.graphics.Point; 22 import android.graphics.Rect; 23 import android.hardware.camera2.CameraCharacteristics; 24 import android.hardware.camera2.CaptureRequest; 25 import android.hardware.camera2.CaptureResult; 26 import android.hardware.camera2.marshal.MarshalQueryable; 27 import android.hardware.camera2.marshal.MarshalRegistry; 28 import android.hardware.camera2.marshal.Marshaler; 29 import android.hardware.camera2.marshal.impl.MarshalQueryableArray; 30 import android.hardware.camera2.marshal.impl.MarshalQueryableBlackLevelPattern; 31 import android.hardware.camera2.marshal.impl.MarshalQueryableBoolean; 32 import android.hardware.camera2.marshal.impl.MarshalQueryableColorSpaceTransform; 33 import android.hardware.camera2.marshal.impl.MarshalQueryableEnum; 34 import android.hardware.camera2.marshal.impl.MarshalQueryableHighSpeedVideoConfiguration; 35 import android.hardware.camera2.marshal.impl.MarshalQueryableMeteringRectangle; 36 import android.hardware.camera2.marshal.impl.MarshalQueryableNativeByteToInteger; 37 import android.hardware.camera2.marshal.impl.MarshalQueryablePair; 38 import android.hardware.camera2.marshal.impl.MarshalQueryableParcelable; 39 import android.hardware.camera2.marshal.impl.MarshalQueryablePrimitive; 40 import android.hardware.camera2.marshal.impl.MarshalQueryableRange; 41 import android.hardware.camera2.marshal.impl.MarshalQueryableRecommendedStreamConfiguration; 42 import android.hardware.camera2.marshal.impl.MarshalQueryableRect; 43 import android.hardware.camera2.marshal.impl.MarshalQueryableReprocessFormatsMap; 44 import android.hardware.camera2.marshal.impl.MarshalQueryableRggbChannelVector; 45 import android.hardware.camera2.marshal.impl.MarshalQueryableSize; 46 import android.hardware.camera2.marshal.impl.MarshalQueryableSizeF; 47 import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfiguration; 48 import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration; 49 import android.hardware.camera2.marshal.impl.MarshalQueryableString; 50 import android.hardware.camera2.params.Face; 51 import android.hardware.camera2.params.HighSpeedVideoConfiguration; 52 import android.hardware.camera2.params.LensShadingMap; 53 import android.hardware.camera2.params.MandatoryStreamCombination; 54 import android.hardware.camera2.params.OisSample; 55 import android.hardware.camera2.params.RecommendedStreamConfiguration; 56 import android.hardware.camera2.params.RecommendedStreamConfigurationMap; 57 import android.hardware.camera2.params.ReprocessFormatsMap; 58 import android.hardware.camera2.params.StreamConfiguration; 59 import android.hardware.camera2.params.StreamConfigurationDuration; 60 import android.hardware.camera2.params.StreamConfigurationMap; 61 import android.hardware.camera2.params.TonemapCurve; 62 import android.hardware.camera2.utils.TypeReference; 63 import android.location.Location; 64 import android.location.LocationManager; 65 import android.os.Parcel; 66 import android.os.Parcelable; 67 import android.os.ServiceSpecificException; 68 import android.util.Log; 69 import android.util.Size; 70 71 import com.android.internal.util.Preconditions; 72 73 import java.io.IOException; 74 import java.nio.ByteBuffer; 75 import java.nio.ByteOrder; 76 import java.util.ArrayList; 77 import java.util.HashMap; 78 import java.util.List; 79 80 /** 81 * Implementation of camera metadata marshal/unmarshal across Binder to 82 * the camera service 83 */ 84 public class CameraMetadataNative implements Parcelable { 85 86 public static class Key<T> { 87 private boolean mHasTag; 88 private int mTag; 89 private long mVendorId = Long.MAX_VALUE; 90 private final Class<T> mType; 91 private final TypeReference<T> mTypeReference; 92 private final String mName; 93 private final String mFallbackName; 94 private final int mHash; 95 96 /** 97 * @hide 98 */ Key(String name, Class<T> type, long vendorId)99 public Key(String name, Class<T> type, long vendorId) { 100 if (name == null) { 101 throw new NullPointerException("Key needs a valid name"); 102 } else if (type == null) { 103 throw new NullPointerException("Type needs to be non-null"); 104 } 105 mName = name; 106 mFallbackName = null; 107 mType = type; 108 mVendorId = vendorId; 109 mTypeReference = TypeReference.createSpecializedTypeReference(type); 110 mHash = mName.hashCode() ^ mTypeReference.hashCode(); 111 } 112 113 /** 114 * @hide 115 */ Key(String name, String fallbackName, Class<T> type)116 public Key(String name, String fallbackName, Class<T> type) { 117 if (name == null) { 118 throw new NullPointerException("Key needs a valid name"); 119 } else if (type == null) { 120 throw new NullPointerException("Type needs to be non-null"); 121 } 122 mName = name; 123 mFallbackName = fallbackName; 124 mType = type; 125 mTypeReference = TypeReference.createSpecializedTypeReference(type); 126 mHash = mName.hashCode() ^ mTypeReference.hashCode(); 127 } 128 129 /** 130 * Visible for testing only. 131 * 132 * <p>Use the CameraCharacteristics.Key, CaptureResult.Key, or CaptureRequest.Key 133 * for application code or vendor-extended keys.</p> 134 */ Key(String name, Class<T> type)135 public Key(String name, Class<T> type) { 136 if (name == null) { 137 throw new NullPointerException("Key needs a valid name"); 138 } else if (type == null) { 139 throw new NullPointerException("Type needs to be non-null"); 140 } 141 mName = name; 142 mFallbackName = null; 143 mType = type; 144 mTypeReference = TypeReference.createSpecializedTypeReference(type); 145 mHash = mName.hashCode() ^ mTypeReference.hashCode(); 146 } 147 148 /** 149 * Visible for testing only. 150 * 151 * <p>Use the CameraCharacteristics.Key, CaptureResult.Key, or CaptureRequest.Key 152 * for application code or vendor-extended keys.</p> 153 */ 154 @SuppressWarnings("unchecked") Key(String name, TypeReference<T> typeReference)155 public Key(String name, TypeReference<T> typeReference) { 156 if (name == null) { 157 throw new NullPointerException("Key needs a valid name"); 158 } else if (typeReference == null) { 159 throw new NullPointerException("TypeReference needs to be non-null"); 160 } 161 mName = name; 162 mFallbackName = null; 163 mType = (Class<T>)typeReference.getRawType(); 164 mTypeReference = typeReference; 165 mHash = mName.hashCode() ^ mTypeReference.hashCode(); 166 } 167 168 /** 169 * Return a camelCase, period separated name formatted like: 170 * {@code "root.section[.subsections].name"}. 171 * 172 * <p>Built-in keys exposed by the Android SDK are always prefixed with {@code "android."}; 173 * keys that are device/platform-specific are prefixed with {@code "com."}.</p> 174 * 175 * <p>For example, {@code CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP} would 176 * have a name of {@code "android.scaler.streamConfigurationMap"}; whereas a device 177 * specific key might look like {@code "com.google.nexus.data.private"}.</p> 178 * 179 * @return String representation of the key name 180 */ getName()181 public final String getName() { 182 return mName; 183 } 184 185 /** 186 * {@inheritDoc} 187 */ 188 @Override hashCode()189 public final int hashCode() { 190 return mHash; 191 } 192 193 /** 194 * Compare this key against other native keys, request keys, result keys, and 195 * characteristics keys. 196 * 197 * <p>Two keys are considered equal if their name and type reference are equal.</p> 198 * 199 * <p>Note that the equality against non-native keys is one-way. A native key may be equal 200 * to a result key; but that same result key will not be equal to a native key.</p> 201 */ 202 @SuppressWarnings("rawtypes") 203 @Override equals(Object o)204 public final boolean equals(Object o) { 205 if (this == o) { 206 return true; 207 } 208 209 if (o == null || this.hashCode() != o.hashCode()) { 210 return false; 211 } 212 213 Key<?> lhs; 214 215 if (o instanceof CaptureResult.Key) { 216 lhs = ((CaptureResult.Key)o).getNativeKey(); 217 } else if (o instanceof CaptureRequest.Key) { 218 lhs = ((CaptureRequest.Key)o).getNativeKey(); 219 } else if (o instanceof CameraCharacteristics.Key) { 220 lhs = ((CameraCharacteristics.Key)o).getNativeKey(); 221 } else if ((o instanceof Key)) { 222 lhs = (Key<?>)o; 223 } else { 224 return false; 225 } 226 227 return mName.equals(lhs.mName) && mTypeReference.equals(lhs.mTypeReference); 228 } 229 230 /** 231 * <p> 232 * Get the tag corresponding to this key. This enables insertion into the 233 * native metadata. 234 * </p> 235 * 236 * <p>This value is looked up the first time, and cached subsequently.</p> 237 * 238 * @return The tag numeric value corresponding to the string 239 */ 240 @UnsupportedAppUsage getTag()241 public final int getTag() { 242 if (!mHasTag) { 243 mTag = CameraMetadataNative.getTag(mName, mVendorId); 244 mHasTag = true; 245 } 246 return mTag; 247 } 248 249 /** 250 * Get the raw class backing the type {@code T} for this key. 251 * 252 * <p>The distinction is only important if {@code T} is a generic, e.g. 253 * {@code Range<Integer>} since the nested type will be erased.</p> 254 */ getType()255 public final Class<T> getType() { 256 // TODO: remove this; other places should use #getTypeReference() instead 257 return mType; 258 } 259 260 /** 261 * Get the vendor tag provider id. 262 * 263 * @hide 264 */ getVendorId()265 public final long getVendorId() { 266 return mVendorId; 267 } 268 269 /** 270 * Get the type reference backing the type {@code T} for this key. 271 * 272 * <p>The distinction is only important if {@code T} is a generic, e.g. 273 * {@code Range<Integer>} since the nested type will be retained.</p> 274 */ getTypeReference()275 public final TypeReference<T> getTypeReference() { 276 return mTypeReference; 277 } 278 } 279 280 private static final String TAG = "CameraMetadataJV"; 281 private static final boolean DEBUG = false; 282 283 // this should be in sync with HAL_PIXEL_FORMAT_BLOB defined in graphics.h 284 public static final int NATIVE_JPEG_FORMAT = 0x21; 285 286 private static final String CELLID_PROCESS = "CELLID"; 287 private static final String GPS_PROCESS = "GPS"; 288 private static final int FACE_LANDMARK_SIZE = 6; 289 translateLocationProviderToProcess(final String provider)290 private static String translateLocationProviderToProcess(final String provider) { 291 if (provider == null) { 292 return null; 293 } 294 switch(provider) { 295 case LocationManager.GPS_PROVIDER: 296 return GPS_PROCESS; 297 case LocationManager.NETWORK_PROVIDER: 298 return CELLID_PROCESS; 299 default: 300 return null; 301 } 302 } 303 translateProcessToLocationProvider(final String process)304 private static String translateProcessToLocationProvider(final String process) { 305 if (process == null) { 306 return null; 307 } 308 switch(process) { 309 case GPS_PROCESS: 310 return LocationManager.GPS_PROVIDER; 311 case CELLID_PROCESS: 312 return LocationManager.NETWORK_PROVIDER; 313 default: 314 return null; 315 } 316 } 317 CameraMetadataNative()318 public CameraMetadataNative() { 319 super(); 320 mMetadataPtr = nativeAllocate(); 321 if (mMetadataPtr == 0) { 322 throw new OutOfMemoryError("Failed to allocate native CameraMetadata"); 323 } 324 } 325 326 /** 327 * Copy constructor - clone metadata 328 */ CameraMetadataNative(CameraMetadataNative other)329 public CameraMetadataNative(CameraMetadataNative other) { 330 super(); 331 mMetadataPtr = nativeAllocateCopy(other); 332 if (mMetadataPtr == 0) { 333 throw new OutOfMemoryError("Failed to allocate native CameraMetadata"); 334 } 335 } 336 337 /** 338 * Move the contents from {@code other} into a new camera metadata instance.</p> 339 * 340 * <p>After this call, {@code other} will become empty.</p> 341 * 342 * @param other the previous metadata instance which will get pilfered 343 * @return a new metadata instance with the values from {@code other} moved into it 344 */ move(CameraMetadataNative other)345 public static CameraMetadataNative move(CameraMetadataNative other) { 346 CameraMetadataNative newObject = new CameraMetadataNative(); 347 newObject.swap(other); 348 return newObject; 349 } 350 351 public static final @android.annotation.NonNull Parcelable.Creator<CameraMetadataNative> CREATOR = 352 new Parcelable.Creator<CameraMetadataNative>() { 353 @Override 354 public CameraMetadataNative createFromParcel(Parcel in) { 355 CameraMetadataNative metadata = new CameraMetadataNative(); 356 metadata.readFromParcel(in); 357 return metadata; 358 } 359 360 @Override 361 public CameraMetadataNative[] newArray(int size) { 362 return new CameraMetadataNative[size]; 363 } 364 }; 365 366 @Override describeContents()367 public int describeContents() { 368 return 0; 369 } 370 371 @Override writeToParcel(Parcel dest, int flags)372 public void writeToParcel(Parcel dest, int flags) { 373 nativeWriteToParcel(dest); 374 } 375 376 /** 377 * @hide 378 */ get(CameraCharacteristics.Key<T> key)379 public <T> T get(CameraCharacteristics.Key<T> key) { 380 return get(key.getNativeKey()); 381 } 382 383 /** 384 * @hide 385 */ get(CaptureResult.Key<T> key)386 public <T> T get(CaptureResult.Key<T> key) { 387 return get(key.getNativeKey()); 388 } 389 390 /** 391 * @hide 392 */ get(CaptureRequest.Key<T> key)393 public <T> T get(CaptureRequest.Key<T> key) { 394 return get(key.getNativeKey()); 395 } 396 397 /** 398 * Look-up a metadata field value by its key. 399 * 400 * @param key a non-{@code null} key instance 401 * @return the field corresponding to the {@code key}, or {@code null} if no value was set 402 */ get(Key<T> key)403 public <T> T get(Key<T> key) { 404 Preconditions.checkNotNull(key, "key must not be null"); 405 406 // Check if key has been overridden to use a wrapper class on the java side. 407 GetCommand g = sGetCommandMap.get(key); 408 if (g != null) { 409 return g.getValue(this, key); 410 } 411 return getBase(key); 412 } 413 readFromParcel(Parcel in)414 public void readFromParcel(Parcel in) { 415 nativeReadFromParcel(in); 416 } 417 418 /** 419 * Set the global client-side vendor tag descriptor to allow use of vendor 420 * tags in camera applications. 421 * 422 * @throws ServiceSpecificException 423 * @hide 424 */ setupGlobalVendorTagDescriptor()425 public static void setupGlobalVendorTagDescriptor() throws ServiceSpecificException { 426 int err = nativeSetupGlobalVendorTagDescriptor(); 427 if (err != 0) { 428 throw new ServiceSpecificException(err, "Failure to set up global vendor tags"); 429 } 430 } 431 432 /** 433 * Set the global client-side vendor tag descriptor to allow use of vendor 434 * tags in camera applications. 435 * 436 * @return int An error code corresponding to one of the 437 * {@link ICameraService} error constants, or 0 on success. 438 */ nativeSetupGlobalVendorTagDescriptor()439 private static native int nativeSetupGlobalVendorTagDescriptor(); 440 441 /** 442 * Set a camera metadata field to a value. The field definitions can be 443 * found in {@link CameraCharacteristics}, {@link CaptureResult}, and 444 * {@link CaptureRequest}. 445 * 446 * @param key The metadata field to write. 447 * @param value The value to set the field to, which must be of a matching 448 * type to the key. 449 */ set(Key<T> key, T value)450 public <T> void set(Key<T> key, T value) { 451 SetCommand s = sSetCommandMap.get(key); 452 if (s != null) { 453 s.setValue(this, value); 454 return; 455 } 456 457 setBase(key, value); 458 } 459 set(CaptureRequest.Key<T> key, T value)460 public <T> void set(CaptureRequest.Key<T> key, T value) { 461 set(key.getNativeKey(), value); 462 } 463 set(CaptureResult.Key<T> key, T value)464 public <T> void set(CaptureResult.Key<T> key, T value) { 465 set(key.getNativeKey(), value); 466 } 467 set(CameraCharacteristics.Key<T> key, T value)468 public <T> void set(CameraCharacteristics.Key<T> key, T value) { 469 set(key.getNativeKey(), value); 470 } 471 472 // Keep up-to-date with camera_metadata.h 473 /** 474 * @hide 475 */ 476 public static final int TYPE_BYTE = 0; 477 /** 478 * @hide 479 */ 480 public static final int TYPE_INT32 = 1; 481 /** 482 * @hide 483 */ 484 public static final int TYPE_FLOAT = 2; 485 /** 486 * @hide 487 */ 488 public static final int TYPE_INT64 = 3; 489 /** 490 * @hide 491 */ 492 public static final int TYPE_DOUBLE = 4; 493 /** 494 * @hide 495 */ 496 public static final int TYPE_RATIONAL = 5; 497 /** 498 * @hide 499 */ 500 public static final int NUM_TYPES = 6; 501 close()502 private void close() { 503 // this sets mMetadataPtr to 0 504 nativeClose(); 505 mMetadataPtr = 0; // set it to 0 again to prevent eclipse from making this field final 506 } 507 getBase(CameraCharacteristics.Key<T> key)508 private <T> T getBase(CameraCharacteristics.Key<T> key) { 509 return getBase(key.getNativeKey()); 510 } 511 getBase(CaptureResult.Key<T> key)512 private <T> T getBase(CaptureResult.Key<T> key) { 513 return getBase(key.getNativeKey()); 514 } 515 getBase(CaptureRequest.Key<T> key)516 private <T> T getBase(CaptureRequest.Key<T> key) { 517 return getBase(key.getNativeKey()); 518 } 519 getBase(Key<T> key)520 private <T> T getBase(Key<T> key) { 521 int tag = nativeGetTagFromKeyLocal(key.getName()); 522 byte[] values = readValues(tag); 523 if (values == null) { 524 // If the key returns null, use the fallback key if exists. 525 // This is to support old key names for the newly published keys. 526 if (key.mFallbackName == null) { 527 return null; 528 } 529 tag = nativeGetTagFromKeyLocal(key.mFallbackName); 530 values = readValues(tag); 531 if (values == null) { 532 return null; 533 } 534 } 535 536 int nativeType = nativeGetTypeFromTagLocal(tag); 537 Marshaler<T> marshaler = getMarshalerForKey(key, nativeType); 538 ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder()); 539 return marshaler.unmarshal(buffer); 540 } 541 542 // Use Command pattern here to avoid lots of expensive if/equals checks in get for overridden 543 // metadata. 544 private static final HashMap<Key<?>, GetCommand> sGetCommandMap = 545 new HashMap<Key<?>, GetCommand>(); 546 static { 547 sGetCommandMap.put( GetCommand()548 CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey(), new GetCommand() { 549 @Override 550 @SuppressWarnings("unchecked") 551 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 552 return (T) metadata.getAvailableFormats(); 553 } 554 }); 555 sGetCommandMap.put( GetCommand()556 CaptureResult.STATISTICS_FACES.getNativeKey(), new GetCommand() { 557 @Override 558 @SuppressWarnings("unchecked") 559 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 560 return (T) metadata.getFaces(); 561 } 562 }); 563 sGetCommandMap.put( GetCommand()564 CaptureResult.STATISTICS_FACE_RECTANGLES.getNativeKey(), new GetCommand() { 565 @Override 566 @SuppressWarnings("unchecked") 567 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 568 return (T) metadata.getFaceRectangles(); 569 } 570 }); 571 sGetCommandMap.put( CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP.getNativeKey()572 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP.getNativeKey(), 573 new GetCommand() { 574 @Override 575 @SuppressWarnings("unchecked") 576 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 577 return (T) metadata.getStreamConfigurationMap(); 578 } 579 }); 580 sGetCommandMap.put( CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS.getNativeKey()581 CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS.getNativeKey(), 582 new GetCommand() { 583 @Override 584 @SuppressWarnings("unchecked") 585 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 586 return (T) metadata.getMandatoryStreamCombinations(); 587 } 588 }); 589 sGetCommandMap.put( CameraCharacteristics.CONTROL_MAX_REGIONS_AE.getNativeKey()590 CameraCharacteristics.CONTROL_MAX_REGIONS_AE.getNativeKey(), new GetCommand() { 591 @Override 592 @SuppressWarnings("unchecked") 593 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 594 return (T) metadata.getMaxRegions(key); 595 } 596 }); 597 sGetCommandMap.put( GetCommand()598 CameraCharacteristics.CONTROL_MAX_REGIONS_AWB.getNativeKey(), new GetCommand() { 599 @Override 600 @SuppressWarnings("unchecked") 601 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 602 return (T) metadata.getMaxRegions(key); 603 } 604 }); 605 sGetCommandMap.put( CameraCharacteristics.CONTROL_MAX_REGIONS_AF.getNativeKey()606 CameraCharacteristics.CONTROL_MAX_REGIONS_AF.getNativeKey(), new GetCommand() { 607 @Override 608 @SuppressWarnings("unchecked") 609 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 610 return (T) metadata.getMaxRegions(key); 611 } 612 }); 613 sGetCommandMap.put( GetCommand()614 CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW.getNativeKey(), new GetCommand() { 615 @Override 616 @SuppressWarnings("unchecked") 617 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 618 return (T) metadata.getMaxNumOutputs(key); 619 } 620 }); 621 sGetCommandMap.put( GetCommand()622 CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC.getNativeKey(), new GetCommand() { 623 @Override 624 @SuppressWarnings("unchecked") 625 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 626 return (T) metadata.getMaxNumOutputs(key); 627 } 628 }); 629 sGetCommandMap.put( CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING.getNativeKey()630 CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING.getNativeKey(), 631 new GetCommand() { 632 @Override 633 @SuppressWarnings("unchecked") 634 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 635 return (T) metadata.getMaxNumOutputs(key); 636 } 637 }); 638 sGetCommandMap.put( GetCommand()639 CaptureRequest.TONEMAP_CURVE.getNativeKey(), new GetCommand() { 640 @Override 641 @SuppressWarnings("unchecked") 642 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 643 return (T) metadata.getTonemapCurve(); 644 } 645 }); 646 sGetCommandMap.put( GetCommand()647 CaptureResult.JPEG_GPS_LOCATION.getNativeKey(), new GetCommand() { 648 @Override 649 @SuppressWarnings("unchecked") 650 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 651 return (T) metadata.getGpsLocation(); 652 } 653 }); 654 sGetCommandMap.put( CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP.getNativeKey()655 CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP.getNativeKey(), 656 new GetCommand() { 657 @Override 658 @SuppressWarnings("unchecked") 659 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 660 return (T) metadata.getLensShadingMap(); 661 } 662 }); 663 sGetCommandMap.put( CaptureResult.STATISTICS_OIS_SAMPLES.getNativeKey()664 CaptureResult.STATISTICS_OIS_SAMPLES.getNativeKey(), 665 new GetCommand() { 666 @Override 667 @SuppressWarnings("unchecked") 668 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 669 return (T) metadata.getOisSamples(); 670 } 671 }); 672 } 673 getAvailableFormats()674 private int[] getAvailableFormats() { 675 int[] availableFormats = getBase(CameraCharacteristics.SCALER_AVAILABLE_FORMATS); 676 if (availableFormats != null) { 677 for (int i = 0; i < availableFormats.length; i++) { 678 // JPEG has different value between native and managed side, need override. 679 if (availableFormats[i] == NATIVE_JPEG_FORMAT) { 680 availableFormats[i] = ImageFormat.JPEG; 681 } 682 } 683 } 684 685 return availableFormats; 686 } 687 setFaces(Face[] faces)688 private boolean setFaces(Face[] faces) { 689 if (faces == null) { 690 return false; 691 } 692 693 int numFaces = faces.length; 694 695 // Detect if all faces are SIMPLE or not; count # of valid faces 696 boolean fullMode = true; 697 for (Face face : faces) { 698 if (face == null) { 699 numFaces--; 700 Log.w(TAG, "setFaces - null face detected, skipping"); 701 continue; 702 } 703 704 if (face.getId() == Face.ID_UNSUPPORTED) { 705 fullMode = false; 706 } 707 } 708 709 Rect[] faceRectangles = new Rect[numFaces]; 710 byte[] faceScores = new byte[numFaces]; 711 int[] faceIds = null; 712 int[] faceLandmarks = null; 713 714 if (fullMode) { 715 faceIds = new int[numFaces]; 716 faceLandmarks = new int[numFaces * FACE_LANDMARK_SIZE]; 717 } 718 719 int i = 0; 720 for (Face face : faces) { 721 if (face == null) { 722 continue; 723 } 724 725 faceRectangles[i] = face.getBounds(); 726 faceScores[i] = (byte)face.getScore(); 727 728 if (fullMode) { 729 faceIds[i] = face.getId(); 730 731 int j = 0; 732 733 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getLeftEyePosition().x; 734 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getLeftEyePosition().y; 735 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getRightEyePosition().x; 736 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getRightEyePosition().y; 737 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getMouthPosition().x; 738 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getMouthPosition().y; 739 } 740 741 i++; 742 } 743 744 set(CaptureResult.STATISTICS_FACE_RECTANGLES, faceRectangles); 745 set(CaptureResult.STATISTICS_FACE_IDS, faceIds); 746 set(CaptureResult.STATISTICS_FACE_LANDMARKS, faceLandmarks); 747 set(CaptureResult.STATISTICS_FACE_SCORES, faceScores); 748 749 return true; 750 } 751 getFaces()752 private Face[] getFaces() { 753 Integer faceDetectMode = get(CaptureResult.STATISTICS_FACE_DETECT_MODE); 754 byte[] faceScores = get(CaptureResult.STATISTICS_FACE_SCORES); 755 Rect[] faceRectangles = get(CaptureResult.STATISTICS_FACE_RECTANGLES); 756 int[] faceIds = get(CaptureResult.STATISTICS_FACE_IDS); 757 int[] faceLandmarks = get(CaptureResult.STATISTICS_FACE_LANDMARKS); 758 759 if (areValuesAllNull(faceDetectMode, faceScores, faceRectangles, faceIds, faceLandmarks)) { 760 return null; 761 } 762 763 if (faceDetectMode == null) { 764 Log.w(TAG, "Face detect mode metadata is null, assuming the mode is SIMPLE"); 765 faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE; 766 } else if (faceDetectMode > CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) { 767 // Face detect mode is larger than FULL, assuming the mode is FULL 768 faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL; 769 } else { 770 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_OFF) { 771 return new Face[0]; 772 } 773 if (faceDetectMode != CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE && 774 faceDetectMode != CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) { 775 Log.w(TAG, "Unknown face detect mode: " + faceDetectMode); 776 return new Face[0]; 777 } 778 } 779 780 // Face scores and rectangles are required by SIMPLE and FULL mode. 781 if (faceScores == null || faceRectangles == null) { 782 Log.w(TAG, "Expect face scores and rectangles to be non-null"); 783 return new Face[0]; 784 } else if (faceScores.length != faceRectangles.length) { 785 Log.w(TAG, String.format("Face score size(%d) doesn match face rectangle size(%d)!", 786 faceScores.length, faceRectangles.length)); 787 } 788 789 // To be safe, make number of faces is the minimal of all face info metadata length. 790 int numFaces = Math.min(faceScores.length, faceRectangles.length); 791 // Face id and landmarks are only required by FULL mode. 792 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) { 793 if (faceIds == null || faceLandmarks == null) { 794 Log.w(TAG, "Expect face ids and landmarks to be non-null for FULL mode," + 795 "fallback to SIMPLE mode"); 796 faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE; 797 } else { 798 if (faceIds.length != numFaces || 799 faceLandmarks.length != numFaces * FACE_LANDMARK_SIZE) { 800 Log.w(TAG, String.format("Face id size(%d), or face landmark size(%d) don't" + 801 "match face number(%d)!", 802 faceIds.length, faceLandmarks.length * FACE_LANDMARK_SIZE, numFaces)); 803 } 804 // To be safe, make number of faces is the minimal of all face info metadata length. 805 numFaces = Math.min(numFaces, faceIds.length); 806 numFaces = Math.min(numFaces, faceLandmarks.length / FACE_LANDMARK_SIZE); 807 } 808 } 809 810 ArrayList<Face> faceList = new ArrayList<Face>(); 811 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE) { 812 for (int i = 0; i < numFaces; i++) { 813 if (faceScores[i] <= Face.SCORE_MAX && 814 faceScores[i] >= Face.SCORE_MIN) { 815 faceList.add(new Face(faceRectangles[i], faceScores[i])); 816 } 817 } 818 } else { 819 // CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL 820 for (int i = 0; i < numFaces; i++) { 821 if (faceScores[i] <= Face.SCORE_MAX && 822 faceScores[i] >= Face.SCORE_MIN && 823 faceIds[i] >= 0) { 824 Point leftEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE], 825 faceLandmarks[i*FACE_LANDMARK_SIZE+1]); 826 Point rightEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+2], 827 faceLandmarks[i*FACE_LANDMARK_SIZE+3]); 828 Point mouth = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+4], 829 faceLandmarks[i*FACE_LANDMARK_SIZE+5]); 830 Face face = new Face(faceRectangles[i], faceScores[i], faceIds[i], 831 leftEye, rightEye, mouth); 832 faceList.add(face); 833 } 834 } 835 } 836 Face[] faces = new Face[faceList.size()]; 837 faceList.toArray(faces); 838 return faces; 839 } 840 841 // Face rectangles are defined as (left, top, right, bottom) instead of 842 // (left, top, width, height) at the native level, so the normal Rect 843 // conversion that does (l, t, w, h) -> (l, t, r, b) is unnecessary. Undo 844 // that conversion here for just the faces. getFaceRectangles()845 private Rect[] getFaceRectangles() { 846 Rect[] faceRectangles = getBase(CaptureResult.STATISTICS_FACE_RECTANGLES); 847 if (faceRectangles == null) return null; 848 849 Rect[] fixedFaceRectangles = new Rect[faceRectangles.length]; 850 for (int i = 0; i < faceRectangles.length; i++) { 851 fixedFaceRectangles[i] = new Rect( 852 faceRectangles[i].left, 853 faceRectangles[i].top, 854 faceRectangles[i].right - faceRectangles[i].left, 855 faceRectangles[i].bottom - faceRectangles[i].top); 856 } 857 return fixedFaceRectangles; 858 } 859 getLensShadingMap()860 private LensShadingMap getLensShadingMap() { 861 float[] lsmArray = getBase(CaptureResult.STATISTICS_LENS_SHADING_MAP); 862 Size s = get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE); 863 864 // Do not warn if lsmArray is null while s is not. This is valid. 865 if (lsmArray == null) { 866 return null; 867 } 868 869 if (s == null) { 870 Log.w(TAG, "getLensShadingMap - Lens shading map size was null."); 871 return null; 872 } 873 874 LensShadingMap map = new LensShadingMap(lsmArray, s.getHeight(), s.getWidth()); 875 return map; 876 } 877 getGpsLocation()878 private Location getGpsLocation() { 879 String processingMethod = get(CaptureResult.JPEG_GPS_PROCESSING_METHOD); 880 double[] coords = get(CaptureResult.JPEG_GPS_COORDINATES); 881 Long timeStamp = get(CaptureResult.JPEG_GPS_TIMESTAMP); 882 883 if (areValuesAllNull(processingMethod, coords, timeStamp)) { 884 return null; 885 } 886 887 Location l = new Location(translateProcessToLocationProvider(processingMethod)); 888 if (timeStamp != null) { 889 // Location expects timestamp in [ms.] 890 l.setTime(timeStamp * 1000); 891 } else { 892 Log.w(TAG, "getGpsLocation - No timestamp for GPS location."); 893 } 894 895 if (coords != null) { 896 l.setLatitude(coords[0]); 897 l.setLongitude(coords[1]); 898 l.setAltitude(coords[2]); 899 } else { 900 Log.w(TAG, "getGpsLocation - No coordinates for GPS location"); 901 } 902 903 return l; 904 } 905 setGpsLocation(Location l)906 private boolean setGpsLocation(Location l) { 907 if (l == null) { 908 return false; 909 } 910 911 double[] coords = { l.getLatitude(), l.getLongitude(), l.getAltitude() }; 912 String processMethod = translateLocationProviderToProcess(l.getProvider()); 913 //JPEG_GPS_TIMESTAMP expects sec. instead of msec. 914 long timestamp = l.getTime() / 1000; 915 916 set(CaptureRequest.JPEG_GPS_TIMESTAMP, timestamp); 917 set(CaptureRequest.JPEG_GPS_COORDINATES, coords); 918 919 if (processMethod == null) { 920 Log.w(TAG, "setGpsLocation - No process method, Location is not from a GPS or NETWORK" + 921 "provider"); 922 } else { 923 setBase(CaptureRequest.JPEG_GPS_PROCESSING_METHOD, processMethod); 924 } 925 return true; 926 } 927 parseRecommendedConfigurations(RecommendedStreamConfiguration[] configurations, StreamConfigurationMap fullMap, boolean isDepth, ArrayList<ArrayList<StreamConfiguration>> streamConfigList, ArrayList<ArrayList<StreamConfigurationDuration>> streamDurationList, ArrayList<ArrayList<StreamConfigurationDuration>> streamStallList, boolean[] supportsPrivate)928 private void parseRecommendedConfigurations(RecommendedStreamConfiguration[] configurations, 929 StreamConfigurationMap fullMap, boolean isDepth, 930 ArrayList<ArrayList<StreamConfiguration>> /*out*/streamConfigList, 931 ArrayList<ArrayList<StreamConfigurationDuration>> /*out*/streamDurationList, 932 ArrayList<ArrayList<StreamConfigurationDuration>> /*out*/streamStallList, 933 boolean[] /*out*/supportsPrivate) { 934 935 streamConfigList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT); 936 streamDurationList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT); 937 streamStallList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT); 938 for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) { 939 streamConfigList.add(new ArrayList<StreamConfiguration> ()); 940 streamDurationList.add(new ArrayList<StreamConfigurationDuration> ()); 941 streamStallList.add(new ArrayList<StreamConfigurationDuration> ()); 942 } 943 944 for (RecommendedStreamConfiguration c : configurations) { 945 int width = c.getWidth(); 946 int height = c.getHeight(); 947 int internalFormat = c.getFormat(); 948 int publicFormat = 949 (isDepth) ? StreamConfigurationMap.depthFormatToPublic(internalFormat) : 950 StreamConfigurationMap.imageFormatToPublic(internalFormat); 951 Size sz = new Size(width, height); 952 int usecaseBitmap = c.getUsecaseBitmap(); 953 954 if (!c.isInput()) { 955 StreamConfigurationDuration minDurationConfiguration = null; 956 StreamConfigurationDuration stallDurationConfiguration = null; 957 958 StreamConfiguration streamConfiguration = new StreamConfiguration(internalFormat, 959 width, height, /*input*/ false); 960 961 long minFrameDuration = fullMap.getOutputMinFrameDuration(publicFormat, sz); 962 if (minFrameDuration > 0) { 963 minDurationConfiguration = new StreamConfigurationDuration(internalFormat, 964 width, height, minFrameDuration); 965 } 966 967 long stallDuration = fullMap.getOutputStallDuration(publicFormat, sz); 968 if (stallDuration > 0) { 969 stallDurationConfiguration = new StreamConfigurationDuration(internalFormat, 970 width, height, stallDuration); 971 } 972 973 for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) { 974 if ((usecaseBitmap & (1 << i)) != 0) { 975 ArrayList<StreamConfiguration> sc = streamConfigList.get(i); 976 sc.add(streamConfiguration); 977 978 if (minFrameDuration > 0) { 979 ArrayList<StreamConfigurationDuration> scd = streamDurationList.get(i); 980 scd.add(minDurationConfiguration); 981 } 982 983 if (stallDuration > 0) { 984 ArrayList<StreamConfigurationDuration> scs = streamStallList.get(i); 985 scs.add(stallDurationConfiguration); 986 } 987 988 if ((supportsPrivate != null) && !supportsPrivate[i] && 989 (publicFormat == ImageFormat.PRIVATE)) { 990 supportsPrivate[i] = true; 991 } 992 } 993 } 994 } else { 995 if (usecaseBitmap != (1 << RecommendedStreamConfigurationMap.USECASE_ZSL)) { 996 throw new IllegalArgumentException("Recommended input stream configurations " + 997 "should only be advertised in the ZSL use case!"); 998 } 999 1000 ArrayList<StreamConfiguration> sc = streamConfigList.get( 1001 RecommendedStreamConfigurationMap.USECASE_ZSL); 1002 sc.add(new StreamConfiguration(internalFormat, 1003 width, height, /*input*/ true)); 1004 } 1005 } 1006 } 1007 1008 private class StreamConfigurationData { 1009 StreamConfiguration [] streamConfigurationArray = null; 1010 StreamConfigurationDuration [] minDurationArray = null; 1011 StreamConfigurationDuration [] stallDurationArray = null; 1012 } 1013 initializeStreamConfigurationData(ArrayList<StreamConfiguration> sc, ArrayList<StreamConfigurationDuration> scd, ArrayList<StreamConfigurationDuration> scs, StreamConfigurationData scData)1014 public void initializeStreamConfigurationData(ArrayList<StreamConfiguration> sc, 1015 ArrayList<StreamConfigurationDuration> scd, ArrayList<StreamConfigurationDuration> scs, 1016 StreamConfigurationData /*out*/scData) { 1017 if ((scData == null) || (sc == null)) { 1018 return; 1019 } 1020 1021 scData.streamConfigurationArray = new StreamConfiguration[sc.size()]; 1022 scData.streamConfigurationArray = sc.toArray(scData.streamConfigurationArray); 1023 1024 if ((scd != null) && !scd.isEmpty()) { 1025 scData.minDurationArray = new StreamConfigurationDuration[scd.size()]; 1026 scData.minDurationArray = scd.toArray(scData.minDurationArray); 1027 } else { 1028 scData.minDurationArray = new StreamConfigurationDuration[0]; 1029 } 1030 1031 if ((scs != null) && !scs.isEmpty()) { 1032 scData.stallDurationArray = new StreamConfigurationDuration[scs.size()]; 1033 scData.stallDurationArray = scs.toArray(scData.stallDurationArray); 1034 } else { 1035 scData.stallDurationArray = new StreamConfigurationDuration[0]; 1036 } 1037 } 1038 1039 /** 1040 * Retrieve the list of recommended stream configurations. 1041 * 1042 * @return A list of recommended stream configuration maps for each common use case or null 1043 * in case the recommended stream configurations are invalid or incomplete. 1044 * @hide 1045 */ getRecommendedStreamConfigurations()1046 public ArrayList<RecommendedStreamConfigurationMap> getRecommendedStreamConfigurations() { 1047 RecommendedStreamConfiguration[] configurations = getBase( 1048 CameraCharacteristics.SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS); 1049 RecommendedStreamConfiguration[] depthConfigurations = getBase( 1050 CameraCharacteristics.DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS); 1051 if ((configurations == null) && (depthConfigurations == null)) { 1052 return null; 1053 } 1054 1055 StreamConfigurationMap fullMap = getStreamConfigurationMap(); 1056 ArrayList<RecommendedStreamConfigurationMap> recommendedConfigurations = 1057 new ArrayList<RecommendedStreamConfigurationMap> (); 1058 1059 ArrayList<ArrayList<StreamConfiguration>> streamConfigList = 1060 new ArrayList<ArrayList<StreamConfiguration>>(); 1061 ArrayList<ArrayList<StreamConfigurationDuration>> streamDurationList = 1062 new ArrayList<ArrayList<StreamConfigurationDuration>>(); 1063 ArrayList<ArrayList<StreamConfigurationDuration>> streamStallList = 1064 new ArrayList<ArrayList<StreamConfigurationDuration>>(); 1065 boolean[] supportsPrivate = 1066 new boolean[RecommendedStreamConfigurationMap.MAX_USECASE_COUNT]; 1067 try { 1068 if (configurations != null) { 1069 parseRecommendedConfigurations(configurations, fullMap, /*isDepth*/ false, 1070 streamConfigList, streamDurationList, streamStallList, supportsPrivate); 1071 } 1072 } catch (IllegalArgumentException e) { 1073 Log.e(TAG, "Failed parsing the recommended stream configurations!"); 1074 return null; 1075 } 1076 1077 ArrayList<ArrayList<StreamConfiguration>> depthStreamConfigList = 1078 new ArrayList<ArrayList<StreamConfiguration>>(); 1079 ArrayList<ArrayList<StreamConfigurationDuration>> depthStreamDurationList = 1080 new ArrayList<ArrayList<StreamConfigurationDuration>>(); 1081 ArrayList<ArrayList<StreamConfigurationDuration>> depthStreamStallList = 1082 new ArrayList<ArrayList<StreamConfigurationDuration>>(); 1083 if (depthConfigurations != null) { 1084 try { 1085 parseRecommendedConfigurations(depthConfigurations, fullMap, /*isDepth*/ true, 1086 depthStreamConfigList, depthStreamDurationList, depthStreamStallList, 1087 /*supportsPrivate*/ null); 1088 } catch (IllegalArgumentException e) { 1089 Log.e(TAG, "Failed parsing the recommended depth stream configurations!"); 1090 return null; 1091 } 1092 } 1093 1094 ReprocessFormatsMap inputOutputFormatsMap = getBase( 1095 CameraCharacteristics.SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP); 1096 HighSpeedVideoConfiguration[] highSpeedVideoConfigurations = getBase( 1097 CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS); 1098 boolean listHighResolution = isBurstSupported(); 1099 recommendedConfigurations.ensureCapacity( 1100 RecommendedStreamConfigurationMap.MAX_USECASE_COUNT); 1101 for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) { 1102 StreamConfigurationData scData = new StreamConfigurationData(); 1103 if (configurations != null) { 1104 initializeStreamConfigurationData(streamConfigList.get(i), 1105 streamDurationList.get(i), streamStallList.get(i), scData); 1106 } 1107 1108 StreamConfigurationData depthScData = new StreamConfigurationData(); 1109 if (depthConfigurations != null) { 1110 initializeStreamConfigurationData(depthStreamConfigList.get(i), 1111 depthStreamDurationList.get(i), depthStreamStallList.get(i), depthScData); 1112 } 1113 1114 if ((scData.streamConfigurationArray == null || 1115 scData.streamConfigurationArray.length == 0) && 1116 (depthScData.streamConfigurationArray == null || 1117 depthScData.streamConfigurationArray.length == 0)) { 1118 recommendedConfigurations.add(null); 1119 continue; 1120 } 1121 1122 // Dynamic depth streams involve alot of SW processing and currently cannot be 1123 // recommended. 1124 StreamConfigurationMap map = null; 1125 switch (i) { 1126 case RecommendedStreamConfigurationMap.USECASE_PREVIEW: 1127 case RecommendedStreamConfigurationMap.USECASE_RAW: 1128 case RecommendedStreamConfigurationMap.USECASE_LOW_LATENCY_SNAPSHOT: 1129 case RecommendedStreamConfigurationMap.USECASE_VIDEO_SNAPSHOT: 1130 map = new StreamConfigurationMap(scData.streamConfigurationArray, 1131 scData.minDurationArray, scData.stallDurationArray, 1132 /*depthconfiguration*/ null, /*depthminduration*/ null, 1133 /*depthstallduration*/ null, 1134 /*dynamicDepthConfigurations*/ null, 1135 /*dynamicDepthMinFrameDurations*/ null, 1136 /*dynamicDepthStallDurations*/ null, 1137 /*heicconfiguration*/ null, 1138 /*heicminduration*/ null, 1139 /*heicstallduration*/ null, 1140 /*highspeedvideoconfigurations*/ null, 1141 /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]); 1142 break; 1143 case RecommendedStreamConfigurationMap.USECASE_RECORD: 1144 map = new StreamConfigurationMap(scData.streamConfigurationArray, 1145 scData.minDurationArray, scData.stallDurationArray, 1146 /*depthconfiguration*/ null, /*depthminduration*/ null, 1147 /*depthstallduration*/ null, 1148 /*dynamicDepthConfigurations*/ null, 1149 /*dynamicDepthMinFrameDurations*/ null, 1150 /*dynamicDepthStallDurations*/ null, 1151 /*heicconfiguration*/ null, 1152 /*heicminduration*/ null, 1153 /*heicstallduration*/ null, 1154 highSpeedVideoConfigurations, 1155 /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]); 1156 break; 1157 case RecommendedStreamConfigurationMap.USECASE_ZSL: 1158 map = new StreamConfigurationMap(scData.streamConfigurationArray, 1159 scData.minDurationArray, scData.stallDurationArray, 1160 depthScData.streamConfigurationArray, depthScData.minDurationArray, 1161 depthScData.stallDurationArray, 1162 /*dynamicDepthConfigurations*/ null, 1163 /*dynamicDepthMinFrameDurations*/ null, 1164 /*dynamicDepthStallDurations*/ null, 1165 /*heicconfiguration*/ null, 1166 /*heicminduration*/ null, 1167 /*heicstallduration*/ null, 1168 /*highSpeedVideoConfigurations*/ null, 1169 inputOutputFormatsMap, listHighResolution, supportsPrivate[i]); 1170 break; 1171 default: 1172 map = new StreamConfigurationMap(scData.streamConfigurationArray, 1173 scData.minDurationArray, scData.stallDurationArray, 1174 depthScData.streamConfigurationArray, depthScData.minDurationArray, 1175 depthScData.stallDurationArray, 1176 /*dynamicDepthConfigurations*/ null, 1177 /*dynamicDepthMinFrameDurations*/ null, 1178 /*dynamicDepthStallDurations*/ null, 1179 /*heicconfiguration*/ null, 1180 /*heicminduration*/ null, 1181 /*heicstallduration*/ null, 1182 /*highSpeedVideoConfigurations*/ null, 1183 /*inputOutputFormatsMap*/ null, listHighResolution, supportsPrivate[i]); 1184 } 1185 1186 recommendedConfigurations.add(new RecommendedStreamConfigurationMap(map, /*usecase*/i, 1187 supportsPrivate[i])); 1188 } 1189 1190 return recommendedConfigurations; 1191 } 1192 isBurstSupported()1193 private boolean isBurstSupported() { 1194 boolean ret = false; 1195 1196 int[] capabilities = getBase(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 1197 for (int capability : capabilities) { 1198 if (capability == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE) { 1199 ret = true; 1200 break; 1201 } 1202 } 1203 1204 return ret; 1205 } 1206 getMandatoryStreamCombinations()1207 private MandatoryStreamCombination[] getMandatoryStreamCombinations() { 1208 int[] capabilities = getBase(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 1209 ArrayList<Integer> caps = new ArrayList<Integer>(); 1210 caps.ensureCapacity(capabilities.length); 1211 for (int c : capabilities) { 1212 caps.add(new Integer(c)); 1213 } 1214 int hwLevel = getBase(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 1215 MandatoryStreamCombination.Builder build = new MandatoryStreamCombination.Builder( 1216 mCameraId, hwLevel, mDisplaySize, caps, getStreamConfigurationMap()); 1217 List<MandatoryStreamCombination> combs = build.getAvailableMandatoryStreamCombinations(); 1218 if ((combs != null) && (!combs.isEmpty())) { 1219 MandatoryStreamCombination[] combArray = new MandatoryStreamCombination[combs.size()]; 1220 combArray = combs.toArray(combArray); 1221 return combArray; 1222 } 1223 1224 return null; 1225 } 1226 getStreamConfigurationMap()1227 private StreamConfigurationMap getStreamConfigurationMap() { 1228 StreamConfiguration[] configurations = getBase( 1229 CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS); 1230 StreamConfigurationDuration[] minFrameDurations = getBase( 1231 CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS); 1232 StreamConfigurationDuration[] stallDurations = getBase( 1233 CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS); 1234 StreamConfiguration[] depthConfigurations = getBase( 1235 CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS); 1236 StreamConfigurationDuration[] depthMinFrameDurations = getBase( 1237 CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS); 1238 StreamConfigurationDuration[] depthStallDurations = getBase( 1239 CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS); 1240 StreamConfiguration[] dynamicDepthConfigurations = getBase( 1241 CameraCharacteristics.DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS); 1242 StreamConfigurationDuration[] dynamicDepthMinFrameDurations = getBase( 1243 CameraCharacteristics.DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS); 1244 StreamConfigurationDuration[] dynamicDepthStallDurations = getBase( 1245 CameraCharacteristics.DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS); 1246 StreamConfiguration[] heicConfigurations = getBase( 1247 CameraCharacteristics.HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS); 1248 StreamConfigurationDuration[] heicMinFrameDurations = getBase( 1249 CameraCharacteristics.HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS); 1250 StreamConfigurationDuration[] heicStallDurations = getBase( 1251 CameraCharacteristics.HEIC_AVAILABLE_HEIC_STALL_DURATIONS); 1252 HighSpeedVideoConfiguration[] highSpeedVideoConfigurations = getBase( 1253 CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS); 1254 ReprocessFormatsMap inputOutputFormatsMap = getBase( 1255 CameraCharacteristics.SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP); 1256 boolean listHighResolution = isBurstSupported(); 1257 return new StreamConfigurationMap( 1258 configurations, minFrameDurations, stallDurations, 1259 depthConfigurations, depthMinFrameDurations, depthStallDurations, 1260 dynamicDepthConfigurations, dynamicDepthMinFrameDurations, 1261 dynamicDepthStallDurations, heicConfigurations, 1262 heicMinFrameDurations, heicStallDurations, 1263 highSpeedVideoConfigurations, inputOutputFormatsMap, 1264 listHighResolution); 1265 } 1266 getMaxRegions(Key<T> key)1267 private <T> Integer getMaxRegions(Key<T> key) { 1268 final int AE = 0; 1269 final int AWB = 1; 1270 final int AF = 2; 1271 1272 // The order of the elements is: (AE, AWB, AF) 1273 int[] maxRegions = getBase(CameraCharacteristics.CONTROL_MAX_REGIONS); 1274 1275 if (maxRegions == null) { 1276 return null; 1277 } 1278 1279 if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AE)) { 1280 return maxRegions[AE]; 1281 } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB)) { 1282 return maxRegions[AWB]; 1283 } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AF)) { 1284 return maxRegions[AF]; 1285 } else { 1286 throw new AssertionError("Invalid key " + key); 1287 } 1288 } 1289 getMaxNumOutputs(Key<T> key)1290 private <T> Integer getMaxNumOutputs(Key<T> key) { 1291 final int RAW = 0; 1292 final int PROC = 1; 1293 final int PROC_STALLING = 2; 1294 1295 // The order of the elements is: (raw, proc+nonstalling, proc+stalling) 1296 int[] maxNumOutputs = getBase(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_STREAMS); 1297 1298 if (maxNumOutputs == null) { 1299 return null; 1300 } 1301 1302 if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW)) { 1303 return maxNumOutputs[RAW]; 1304 } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC)) { 1305 return maxNumOutputs[PROC]; 1306 } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING)) { 1307 return maxNumOutputs[PROC_STALLING]; 1308 } else { 1309 throw new AssertionError("Invalid key " + key); 1310 } 1311 } 1312 getTonemapCurve()1313 private <T> TonemapCurve getTonemapCurve() { 1314 float[] red = getBase(CaptureRequest.TONEMAP_CURVE_RED); 1315 float[] green = getBase(CaptureRequest.TONEMAP_CURVE_GREEN); 1316 float[] blue = getBase(CaptureRequest.TONEMAP_CURVE_BLUE); 1317 1318 if (areValuesAllNull(red, green, blue)) { 1319 return null; 1320 } 1321 1322 if (red == null || green == null || blue == null) { 1323 Log.w(TAG, "getTonemapCurve - missing tone curve components"); 1324 return null; 1325 } 1326 TonemapCurve tc = new TonemapCurve(red, green, blue); 1327 return tc; 1328 } 1329 getOisSamples()1330 private OisSample[] getOisSamples() { 1331 long[] timestamps = getBase(CaptureResult.STATISTICS_OIS_TIMESTAMPS); 1332 float[] xShifts = getBase(CaptureResult.STATISTICS_OIS_X_SHIFTS); 1333 float[] yShifts = getBase(CaptureResult.STATISTICS_OIS_Y_SHIFTS); 1334 1335 if (timestamps == null) { 1336 if (xShifts != null) { 1337 throw new AssertionError("timestamps is null but xShifts is not"); 1338 } 1339 1340 if (yShifts != null) { 1341 throw new AssertionError("timestamps is null but yShifts is not"); 1342 } 1343 1344 return null; 1345 } 1346 1347 if (xShifts == null) { 1348 throw new AssertionError("timestamps is not null but xShifts is"); 1349 } 1350 1351 if (yShifts == null) { 1352 throw new AssertionError("timestamps is not null but yShifts is"); 1353 } 1354 1355 if (xShifts.length != timestamps.length) { 1356 throw new AssertionError(String.format( 1357 "timestamps has %d entries but xShifts has %d", timestamps.length, 1358 xShifts.length)); 1359 } 1360 1361 if (yShifts.length != timestamps.length) { 1362 throw new AssertionError(String.format( 1363 "timestamps has %d entries but yShifts has %d", timestamps.length, 1364 yShifts.length)); 1365 } 1366 1367 OisSample[] samples = new OisSample[timestamps.length]; 1368 for (int i = 0; i < timestamps.length; i++) { 1369 samples[i] = new OisSample(timestamps[i], xShifts[i], yShifts[i]); 1370 } 1371 return samples; 1372 } 1373 setBase(CameraCharacteristics.Key<T> key, T value)1374 private <T> void setBase(CameraCharacteristics.Key<T> key, T value) { 1375 setBase(key.getNativeKey(), value); 1376 } 1377 setBase(CaptureResult.Key<T> key, T value)1378 private <T> void setBase(CaptureResult.Key<T> key, T value) { 1379 setBase(key.getNativeKey(), value); 1380 } 1381 setBase(CaptureRequest.Key<T> key, T value)1382 private <T> void setBase(CaptureRequest.Key<T> key, T value) { 1383 setBase(key.getNativeKey(), value); 1384 } 1385 setBase(Key<T> key, T value)1386 private <T> void setBase(Key<T> key, T value) { 1387 int tag = nativeGetTagFromKeyLocal(key.getName()); 1388 if (value == null) { 1389 // Erase the entry 1390 writeValues(tag, /*src*/null); 1391 return; 1392 } // else update the entry to a new value 1393 1394 int nativeType = nativeGetTypeFromTagLocal(tag); 1395 Marshaler<T> marshaler = getMarshalerForKey(key, nativeType); 1396 int size = marshaler.calculateMarshalSize(value); 1397 1398 // TODO: Optimization. Cache the byte[] and reuse if the size is big enough. 1399 byte[] values = new byte[size]; 1400 1401 ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder()); 1402 marshaler.marshal(value, buffer); 1403 1404 writeValues(tag, values); 1405 } 1406 1407 // Use Command pattern here to avoid lots of expensive if/equals checks in get for overridden 1408 // metadata. 1409 private static final HashMap<Key<?>, SetCommand> sSetCommandMap = 1410 new HashMap<Key<?>, SetCommand>(); 1411 static { CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey()1412 sSetCommandMap.put(CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey(), 1413 new SetCommand() { 1414 @Override 1415 public <T> void setValue(CameraMetadataNative metadata, T value) { 1416 metadata.setAvailableFormats((int[]) value); 1417 } 1418 }); CaptureResult.STATISTICS_FACE_RECTANGLES.getNativeKey()1419 sSetCommandMap.put(CaptureResult.STATISTICS_FACE_RECTANGLES.getNativeKey(), 1420 new SetCommand() { 1421 @Override 1422 public <T> void setValue(CameraMetadataNative metadata, T value) { 1423 metadata.setFaceRectangles((Rect[]) value); 1424 } 1425 }); CaptureResult.STATISTICS_FACES.getNativeKey()1426 sSetCommandMap.put(CaptureResult.STATISTICS_FACES.getNativeKey(), 1427 new SetCommand() { 1428 @Override 1429 public <T> void setValue(CameraMetadataNative metadata, T value) { 1430 metadata.setFaces((Face[])value); 1431 } 1432 }); CaptureRequest.TONEMAP_CURVE.getNativeKey()1433 sSetCommandMap.put(CaptureRequest.TONEMAP_CURVE.getNativeKey(), new SetCommand() { 1434 @Override 1435 public <T> void setValue(CameraMetadataNative metadata, T value) { 1436 metadata.setTonemapCurve((TonemapCurve) value); 1437 } 1438 }); CaptureResult.JPEG_GPS_LOCATION.getNativeKey()1439 sSetCommandMap.put(CaptureResult.JPEG_GPS_LOCATION.getNativeKey(), new SetCommand() { 1440 @Override 1441 public <T> void setValue(CameraMetadataNative metadata, T value) { 1442 metadata.setGpsLocation((Location) value); 1443 } 1444 }); 1445 } 1446 setAvailableFormats(int[] value)1447 private boolean setAvailableFormats(int[] value) { 1448 int[] availableFormat = value; 1449 if (value == null) { 1450 // Let setBase() to handle the null value case. 1451 return false; 1452 } 1453 1454 int[] newValues = new int[availableFormat.length]; 1455 for (int i = 0; i < availableFormat.length; i++) { 1456 newValues[i] = availableFormat[i]; 1457 if (availableFormat[i] == ImageFormat.JPEG) { 1458 newValues[i] = NATIVE_JPEG_FORMAT; 1459 } 1460 } 1461 1462 setBase(CameraCharacteristics.SCALER_AVAILABLE_FORMATS, newValues); 1463 return true; 1464 } 1465 1466 /** 1467 * Convert Face Rectangles from managed side to native side as they have different definitions. 1468 * <p> 1469 * Managed side face rectangles are defined as: left, top, width, height. 1470 * Native side face rectangles are defined as: left, top, right, bottom. 1471 * The input face rectangle need to be converted to native side definition when set is called. 1472 * </p> 1473 * 1474 * @param faceRects Input face rectangles. 1475 * @return true if face rectangles can be set successfully. Otherwise, Let the caller 1476 * (setBase) to handle it appropriately. 1477 */ setFaceRectangles(Rect[] faceRects)1478 private boolean setFaceRectangles(Rect[] faceRects) { 1479 if (faceRects == null) { 1480 return false; 1481 } 1482 1483 Rect[] newFaceRects = new Rect[faceRects.length]; 1484 for (int i = 0; i < newFaceRects.length; i++) { 1485 newFaceRects[i] = new Rect( 1486 faceRects[i].left, 1487 faceRects[i].top, 1488 faceRects[i].right + faceRects[i].left, 1489 faceRects[i].bottom + faceRects[i].top); 1490 } 1491 1492 setBase(CaptureResult.STATISTICS_FACE_RECTANGLES, newFaceRects); 1493 return true; 1494 } 1495 setTonemapCurve(TonemapCurve tc)1496 private <T> boolean setTonemapCurve(TonemapCurve tc) { 1497 if (tc == null) { 1498 return false; 1499 } 1500 1501 float[][] curve = new float[3][]; 1502 for (int i = TonemapCurve.CHANNEL_RED; i <= TonemapCurve.CHANNEL_BLUE; i++) { 1503 int pointCount = tc.getPointCount(i); 1504 curve[i] = new float[pointCount * TonemapCurve.POINT_SIZE]; 1505 tc.copyColorCurve(i, curve[i], 0); 1506 } 1507 setBase(CaptureRequest.TONEMAP_CURVE_RED, curve[0]); 1508 setBase(CaptureRequest.TONEMAP_CURVE_GREEN, curve[1]); 1509 setBase(CaptureRequest.TONEMAP_CURVE_BLUE, curve[2]); 1510 1511 return true; 1512 } 1513 1514 private int mCameraId = -1; 1515 private Size mDisplaySize = new Size(0, 0); 1516 1517 /** 1518 * Set the current camera Id. 1519 * 1520 * @param cameraId Current camera id. 1521 * 1522 * @hide 1523 */ setCameraId(int cameraId)1524 public void setCameraId(int cameraId) { 1525 mCameraId = cameraId; 1526 } 1527 1528 /** 1529 * Set the current display size. 1530 * 1531 * @param displaySize The current display size. 1532 * 1533 * @hide 1534 */ setDisplaySize(Size displaySize)1535 public void setDisplaySize(Size displaySize) { 1536 mDisplaySize = displaySize; 1537 } 1538 1539 @UnsupportedAppUsage 1540 private long mMetadataPtr; // native CameraMetadata* 1541 nativeAllocate()1542 private native long nativeAllocate(); nativeAllocateCopy(CameraMetadataNative other)1543 private native long nativeAllocateCopy(CameraMetadataNative other) 1544 throws NullPointerException; 1545 nativeWriteToParcel(Parcel dest)1546 private native synchronized void nativeWriteToParcel(Parcel dest); nativeReadFromParcel(Parcel source)1547 private native synchronized void nativeReadFromParcel(Parcel source); nativeSwap(CameraMetadataNative other)1548 private native synchronized void nativeSwap(CameraMetadataNative other) 1549 throws NullPointerException; nativeClose()1550 private native synchronized void nativeClose(); nativeIsEmpty()1551 private native synchronized boolean nativeIsEmpty(); nativeGetEntryCount()1552 private native synchronized int nativeGetEntryCount(); 1553 1554 @UnsupportedAppUsage nativeReadValues(int tag)1555 private native synchronized byte[] nativeReadValues(int tag); nativeWriteValues(int tag, byte[] src)1556 private native synchronized void nativeWriteValues(int tag, byte[] src); nativeDump()1557 private native synchronized void nativeDump() throws IOException; // dump to ALOGD 1558 nativeGetAllVendorKeys(Class keyClass)1559 private native synchronized ArrayList nativeGetAllVendorKeys(Class keyClass); 1560 @UnsupportedAppUsage nativeGetTagFromKeyLocal(String keyName)1561 private native synchronized int nativeGetTagFromKeyLocal(String keyName) 1562 throws IllegalArgumentException; 1563 @UnsupportedAppUsage nativeGetTypeFromTagLocal(int tag)1564 private native synchronized int nativeGetTypeFromTagLocal(int tag) 1565 throws IllegalArgumentException; nativeGetTagFromKey(String keyName, long vendorId)1566 private static native int nativeGetTagFromKey(String keyName, long vendorId) 1567 throws IllegalArgumentException; nativeGetTypeFromTag(int tag, long vendorId)1568 private static native int nativeGetTypeFromTag(int tag, long vendorId) 1569 throws IllegalArgumentException; 1570 1571 /** 1572 * <p>Perform a 0-copy swap of the internal metadata with another object.</p> 1573 * 1574 * <p>Useful to convert a CameraMetadata into e.g. a CaptureRequest.</p> 1575 * 1576 * @param other Metadata to swap with 1577 * @throws NullPointerException if other was null 1578 * @hide 1579 */ swap(CameraMetadataNative other)1580 public void swap(CameraMetadataNative other) { 1581 nativeSwap(other); 1582 mCameraId = other.mCameraId; 1583 mDisplaySize = other.mDisplaySize; 1584 } 1585 1586 /** 1587 * @hide 1588 */ getEntryCount()1589 public int getEntryCount() { 1590 return nativeGetEntryCount(); 1591 } 1592 1593 /** 1594 * Does this metadata contain at least 1 entry? 1595 * 1596 * @hide 1597 */ isEmpty()1598 public boolean isEmpty() { 1599 return nativeIsEmpty(); 1600 } 1601 1602 1603 /** 1604 * Return a list containing keys of the given key class for all defined vendor tags. 1605 * 1606 * @hide 1607 */ getAllVendorKeys(Class<K> keyClass)1608 public <K> ArrayList<K> getAllVendorKeys(Class<K> keyClass) { 1609 if (keyClass == null) { 1610 throw new NullPointerException(); 1611 } 1612 return (ArrayList<K>) nativeGetAllVendorKeys(keyClass); 1613 } 1614 1615 /** 1616 * Convert a key string into the equivalent native tag. 1617 * 1618 * @throws IllegalArgumentException if the key was not recognized 1619 * @throws NullPointerException if the key was null 1620 * 1621 * @hide 1622 */ getTag(String key)1623 public static int getTag(String key) { 1624 return nativeGetTagFromKey(key, Long.MAX_VALUE); 1625 } 1626 1627 /** 1628 * Convert a key string into the equivalent native tag. 1629 * 1630 * @throws IllegalArgumentException if the key was not recognized 1631 * @throws NullPointerException if the key was null 1632 * 1633 * @hide 1634 */ getTag(String key, long vendorId)1635 public static int getTag(String key, long vendorId) { 1636 return nativeGetTagFromKey(key, vendorId); 1637 } 1638 1639 /** 1640 * Get the underlying native type for a tag. 1641 * 1642 * @param tag An integer tag, see e.g. {@link #getTag} 1643 * @param vendorId A vendor tag provider id 1644 * @return An int enum for the metadata type, see e.g. {@link #TYPE_BYTE} 1645 * 1646 * @hide 1647 */ getNativeType(int tag, long vendorId)1648 public static int getNativeType(int tag, long vendorId) { 1649 return nativeGetTypeFromTag(tag, vendorId); 1650 } 1651 1652 /** 1653 * <p>Updates the existing entry for tag with the new bytes pointed by src, erasing 1654 * the entry if src was null.</p> 1655 * 1656 * <p>An empty array can be passed in to update the entry to 0 elements.</p> 1657 * 1658 * @param tag An integer tag, see e.g. {@link #getTag} 1659 * @param src An array of bytes, or null to erase the entry 1660 * 1661 * @hide 1662 */ writeValues(int tag, byte[] src)1663 public void writeValues(int tag, byte[] src) { 1664 nativeWriteValues(tag, src); 1665 } 1666 1667 /** 1668 * <p>Returns a byte[] of data corresponding to this tag. Use a wrapped bytebuffer to unserialize 1669 * the data properly.</p> 1670 * 1671 * <p>An empty array can be returned to denote an existing entry with 0 elements.</p> 1672 * 1673 * @param tag An integer tag, see e.g. {@link #getTag} 1674 * 1675 * @return {@code null} if there were 0 entries for this tag, a byte[] otherwise. 1676 * @hide 1677 */ readValues(int tag)1678 public byte[] readValues(int tag) { 1679 // TODO: Optimization. Native code returns a ByteBuffer instead. 1680 return nativeReadValues(tag); 1681 } 1682 1683 /** 1684 * Dumps the native metadata contents to logcat. 1685 * 1686 * <p>Visibility for testing/debugging only. The results will not 1687 * include any synthesized keys, as they are invisible to the native layer.</p> 1688 * 1689 * @hide 1690 */ dumpToLog()1691 public void dumpToLog() { 1692 try { 1693 nativeDump(); 1694 } catch (IOException e) { 1695 Log.wtf(TAG, "Dump logging failed", e); 1696 } 1697 } 1698 1699 @Override finalize()1700 protected void finalize() throws Throwable { 1701 try { 1702 close(); 1703 } finally { 1704 super.finalize(); 1705 } 1706 } 1707 1708 /** 1709 * Get the marshaler compatible with the {@code key} and type {@code T}. 1710 * 1711 * @throws UnsupportedOperationException 1712 * if the native/managed type combination for {@code key} is not supported 1713 */ getMarshalerForKey(Key<T> key, int nativeType)1714 private static <T> Marshaler<T> getMarshalerForKey(Key<T> key, int nativeType) { 1715 return MarshalRegistry.getMarshaler(key.getTypeReference(), 1716 nativeType); 1717 } 1718 1719 @SuppressWarnings({ "unchecked", "rawtypes" }) registerAllMarshalers()1720 private static void registerAllMarshalers() { 1721 if (DEBUG) { 1722 Log.v(TAG, "Shall register metadata marshalers"); 1723 } 1724 1725 MarshalQueryable[] queryList = new MarshalQueryable[] { 1726 // marshalers for standard types 1727 new MarshalQueryablePrimitive(), 1728 new MarshalQueryableEnum(), 1729 new MarshalQueryableArray(), 1730 1731 // pseudo standard types, that expand/narrow the native type into a managed type 1732 new MarshalQueryableBoolean(), 1733 new MarshalQueryableNativeByteToInteger(), 1734 1735 // marshalers for custom types 1736 new MarshalQueryableRect(), 1737 new MarshalQueryableSize(), 1738 new MarshalQueryableSizeF(), 1739 new MarshalQueryableString(), 1740 new MarshalQueryableReprocessFormatsMap(), 1741 new MarshalQueryableRange(), 1742 new MarshalQueryablePair(), 1743 new MarshalQueryableMeteringRectangle(), 1744 new MarshalQueryableColorSpaceTransform(), 1745 new MarshalQueryableStreamConfiguration(), 1746 new MarshalQueryableStreamConfigurationDuration(), 1747 new MarshalQueryableRggbChannelVector(), 1748 new MarshalQueryableBlackLevelPattern(), 1749 new MarshalQueryableHighSpeedVideoConfiguration(), 1750 new MarshalQueryableRecommendedStreamConfiguration(), 1751 1752 // generic parcelable marshaler (MUST BE LAST since it has lowest priority) 1753 new MarshalQueryableParcelable(), 1754 }; 1755 1756 for (MarshalQueryable query : queryList) { 1757 MarshalRegistry.registerMarshalQueryable(query); 1758 } 1759 if (DEBUG) { 1760 Log.v(TAG, "Registered metadata marshalers"); 1761 } 1762 } 1763 1764 /** Check if input arguments are all {@code null}. 1765 * 1766 * @param objs Input arguments for null check 1767 * @return {@code true} if input arguments are all {@code null}, otherwise {@code false} 1768 */ areValuesAllNull(Object... objs)1769 private static boolean areValuesAllNull(Object... objs) { 1770 for (Object o : objs) { 1771 if (o != null) return false; 1772 } 1773 return true; 1774 } 1775 1776 static { registerAllMarshalers()1777 registerAllMarshalers(); 1778 } 1779 } 1780