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.graphics.ImageFormat; 20 import android.graphics.Point; 21 import android.graphics.Rect; 22 import android.hardware.camera2.CameraCharacteristics; 23 import android.hardware.camera2.CaptureRequest; 24 import android.hardware.camera2.CaptureResult; 25 import android.hardware.camera2.marshal.Marshaler; 26 import android.hardware.camera2.marshal.MarshalQueryable; 27 import android.hardware.camera2.marshal.MarshalRegistry; 28 import android.hardware.camera2.marshal.impl.MarshalQueryableArray; 29 import android.hardware.camera2.marshal.impl.MarshalQueryableBoolean; 30 import android.hardware.camera2.marshal.impl.MarshalQueryableBlackLevelPattern; 31 import android.hardware.camera2.marshal.impl.MarshalQueryableColorSpaceTransform; 32 import android.hardware.camera2.marshal.impl.MarshalQueryableEnum; 33 import android.hardware.camera2.marshal.impl.MarshalQueryableHighSpeedVideoConfiguration; 34 import android.hardware.camera2.marshal.impl.MarshalQueryableMeteringRectangle; 35 import android.hardware.camera2.marshal.impl.MarshalQueryableNativeByteToInteger; 36 import android.hardware.camera2.marshal.impl.MarshalQueryablePair; 37 import android.hardware.camera2.marshal.impl.MarshalQueryableParcelable; 38 import android.hardware.camera2.marshal.impl.MarshalQueryablePrimitive; 39 import android.hardware.camera2.marshal.impl.MarshalQueryableRange; 40 import android.hardware.camera2.marshal.impl.MarshalQueryableRect; 41 import android.hardware.camera2.marshal.impl.MarshalQueryableReprocessFormatsMap; 42 import android.hardware.camera2.marshal.impl.MarshalQueryableRggbChannelVector; 43 import android.hardware.camera2.marshal.impl.MarshalQueryableSize; 44 import android.hardware.camera2.marshal.impl.MarshalQueryableSizeF; 45 import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfiguration; 46 import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration; 47 import android.hardware.camera2.marshal.impl.MarshalQueryableString; 48 import android.hardware.camera2.params.Face; 49 import android.hardware.camera2.params.HighSpeedVideoConfiguration; 50 import android.hardware.camera2.params.LensShadingMap; 51 import android.hardware.camera2.params.ReprocessFormatsMap; 52 import android.hardware.camera2.params.StreamConfiguration; 53 import android.hardware.camera2.params.StreamConfigurationDuration; 54 import android.hardware.camera2.params.StreamConfigurationMap; 55 import android.hardware.camera2.params.TonemapCurve; 56 import android.hardware.camera2.utils.TypeReference; 57 import android.location.Location; 58 import android.location.LocationManager; 59 import android.os.Parcelable; 60 import android.os.Parcel; 61 import android.os.ServiceSpecificException; 62 import android.util.Log; 63 import android.util.Size; 64 65 import com.android.internal.util.Preconditions; 66 67 import java.io.IOException; 68 import java.nio.ByteBuffer; 69 import java.nio.ByteOrder; 70 import java.util.ArrayList; 71 import java.util.HashMap; 72 73 /** 74 * Implementation of camera metadata marshal/unmarshal across Binder to 75 * the camera service 76 */ 77 public class CameraMetadataNative implements Parcelable { 78 79 public static class Key<T> { 80 private boolean mHasTag; 81 private int mTag; 82 private long mVendorId = Long.MAX_VALUE; 83 private final Class<T> mType; 84 private final TypeReference<T> mTypeReference; 85 private final String mName; 86 private final int mHash; 87 88 /** 89 * @hide 90 */ Key(String name, Class<T> type, long vendorId)91 public Key(String name, Class<T> type, long vendorId) { 92 if (name == null) { 93 throw new NullPointerException("Key needs a valid name"); 94 } else if (type == null) { 95 throw new NullPointerException("Type needs to be non-null"); 96 } 97 mName = name; 98 mType = type; 99 mVendorId = vendorId; 100 mTypeReference = TypeReference.createSpecializedTypeReference(type); 101 mHash = mName.hashCode() ^ mTypeReference.hashCode(); 102 } 103 104 /** 105 * Visible for testing only. 106 * 107 * <p>Use the CameraCharacteristics.Key, CaptureResult.Key, or CaptureRequest.Key 108 * for application code or vendor-extended keys.</p> 109 */ Key(String name, Class<T> type)110 public Key(String name, Class<T> type) { 111 if (name == null) { 112 throw new NullPointerException("Key needs a valid name"); 113 } else if (type == null) { 114 throw new NullPointerException("Type needs to be non-null"); 115 } 116 mName = name; 117 mType = type; 118 mTypeReference = TypeReference.createSpecializedTypeReference(type); 119 mHash = mName.hashCode() ^ mTypeReference.hashCode(); 120 } 121 122 /** 123 * Visible for testing only. 124 * 125 * <p>Use the CameraCharacteristics.Key, CaptureResult.Key, or CaptureRequest.Key 126 * for application code or vendor-extended keys.</p> 127 */ 128 @SuppressWarnings("unchecked") Key(String name, TypeReference<T> typeReference)129 public Key(String name, TypeReference<T> typeReference) { 130 if (name == null) { 131 throw new NullPointerException("Key needs a valid name"); 132 } else if (typeReference == null) { 133 throw new NullPointerException("TypeReference needs to be non-null"); 134 } 135 mName = name; 136 mType = (Class<T>)typeReference.getRawType(); 137 mTypeReference = typeReference; 138 mHash = mName.hashCode() ^ mTypeReference.hashCode(); 139 } 140 141 /** 142 * Return a camelCase, period separated name formatted like: 143 * {@code "root.section[.subsections].name"}. 144 * 145 * <p>Built-in keys exposed by the Android SDK are always prefixed with {@code "android."}; 146 * keys that are device/platform-specific are prefixed with {@code "com."}.</p> 147 * 148 * <p>For example, {@code CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP} would 149 * have a name of {@code "android.scaler.streamConfigurationMap"}; whereas a device 150 * specific key might look like {@code "com.google.nexus.data.private"}.</p> 151 * 152 * @return String representation of the key name 153 */ getName()154 public final String getName() { 155 return mName; 156 } 157 158 /** 159 * {@inheritDoc} 160 */ 161 @Override hashCode()162 public final int hashCode() { 163 return mHash; 164 } 165 166 /** 167 * Compare this key against other native keys, request keys, result keys, and 168 * characteristics keys. 169 * 170 * <p>Two keys are considered equal if their name and type reference are equal.</p> 171 * 172 * <p>Note that the equality against non-native keys is one-way. A native key may be equal 173 * to a result key; but that same result key will not be equal to a native key.</p> 174 */ 175 @SuppressWarnings("rawtypes") 176 @Override equals(Object o)177 public final boolean equals(Object o) { 178 if (this == o) { 179 return true; 180 } 181 182 if (o == null || this.hashCode() != o.hashCode()) { 183 return false; 184 } 185 186 Key<?> lhs; 187 188 if (o instanceof CaptureResult.Key) { 189 lhs = ((CaptureResult.Key)o).getNativeKey(); 190 } else if (o instanceof CaptureRequest.Key) { 191 lhs = ((CaptureRequest.Key)o).getNativeKey(); 192 } else if (o instanceof CameraCharacteristics.Key) { 193 lhs = ((CameraCharacteristics.Key)o).getNativeKey(); 194 } else if ((o instanceof Key)) { 195 lhs = (Key<?>)o; 196 } else { 197 return false; 198 } 199 200 return mName.equals(lhs.mName) && mTypeReference.equals(lhs.mTypeReference); 201 } 202 203 /** 204 * <p> 205 * Get the tag corresponding to this key. This enables insertion into the 206 * native metadata. 207 * </p> 208 * 209 * <p>This value is looked up the first time, and cached subsequently.</p> 210 * 211 * @return The tag numeric value corresponding to the string 212 */ getTag()213 public final int getTag() { 214 if (!mHasTag) { 215 mTag = CameraMetadataNative.getTag(mName, mVendorId); 216 mHasTag = true; 217 } 218 return mTag; 219 } 220 221 /** 222 * Get the raw class backing the type {@code T} for this key. 223 * 224 * <p>The distinction is only important if {@code T} is a generic, e.g. 225 * {@code Range<Integer>} since the nested type will be erased.</p> 226 */ getType()227 public final Class<T> getType() { 228 // TODO: remove this; other places should use #getTypeReference() instead 229 return mType; 230 } 231 232 /** 233 * Get the vendor tag provider id. 234 * 235 * @hide 236 */ getVendorId()237 public final long getVendorId() { 238 return mVendorId; 239 } 240 241 /** 242 * Get the type reference backing the type {@code T} for this key. 243 * 244 * <p>The distinction is only important if {@code T} is a generic, e.g. 245 * {@code Range<Integer>} since the nested type will be retained.</p> 246 */ getTypeReference()247 public final TypeReference<T> getTypeReference() { 248 return mTypeReference; 249 } 250 } 251 252 private static final String TAG = "CameraMetadataJV"; 253 private static final boolean DEBUG = false; 254 255 // this should be in sync with HAL_PIXEL_FORMAT_BLOB defined in graphics.h 256 public static final int NATIVE_JPEG_FORMAT = 0x21; 257 258 private static final String CELLID_PROCESS = "CELLID"; 259 private static final String GPS_PROCESS = "GPS"; 260 private static final int FACE_LANDMARK_SIZE = 6; 261 translateLocationProviderToProcess(final String provider)262 private static String translateLocationProviderToProcess(final String provider) { 263 if (provider == null) { 264 return null; 265 } 266 switch(provider) { 267 case LocationManager.GPS_PROVIDER: 268 return GPS_PROCESS; 269 case LocationManager.NETWORK_PROVIDER: 270 return CELLID_PROCESS; 271 default: 272 return null; 273 } 274 } 275 translateProcessToLocationProvider(final String process)276 private static String translateProcessToLocationProvider(final String process) { 277 if (process == null) { 278 return null; 279 } 280 switch(process) { 281 case GPS_PROCESS: 282 return LocationManager.GPS_PROVIDER; 283 case CELLID_PROCESS: 284 return LocationManager.NETWORK_PROVIDER; 285 default: 286 return null; 287 } 288 } 289 CameraMetadataNative()290 public CameraMetadataNative() { 291 super(); 292 mMetadataPtr = nativeAllocate(); 293 if (mMetadataPtr == 0) { 294 throw new OutOfMemoryError("Failed to allocate native CameraMetadata"); 295 } 296 } 297 298 /** 299 * Copy constructor - clone metadata 300 */ CameraMetadataNative(CameraMetadataNative other)301 public CameraMetadataNative(CameraMetadataNative other) { 302 super(); 303 mMetadataPtr = nativeAllocateCopy(other); 304 if (mMetadataPtr == 0) { 305 throw new OutOfMemoryError("Failed to allocate native CameraMetadata"); 306 } 307 } 308 309 /** 310 * Move the contents from {@code other} into a new camera metadata instance.</p> 311 * 312 * <p>After this call, {@code other} will become empty.</p> 313 * 314 * @param other the previous metadata instance which will get pilfered 315 * @return a new metadata instance with the values from {@code other} moved into it 316 */ move(CameraMetadataNative other)317 public static CameraMetadataNative move(CameraMetadataNative other) { 318 CameraMetadataNative newObject = new CameraMetadataNative(); 319 newObject.swap(other); 320 return newObject; 321 } 322 323 public static final Parcelable.Creator<CameraMetadataNative> CREATOR = 324 new Parcelable.Creator<CameraMetadataNative>() { 325 @Override 326 public CameraMetadataNative createFromParcel(Parcel in) { 327 CameraMetadataNative metadata = new CameraMetadataNative(); 328 metadata.readFromParcel(in); 329 return metadata; 330 } 331 332 @Override 333 public CameraMetadataNative[] newArray(int size) { 334 return new CameraMetadataNative[size]; 335 } 336 }; 337 338 @Override describeContents()339 public int describeContents() { 340 return 0; 341 } 342 343 @Override writeToParcel(Parcel dest, int flags)344 public void writeToParcel(Parcel dest, int flags) { 345 nativeWriteToParcel(dest); 346 } 347 348 /** 349 * @hide 350 */ get(CameraCharacteristics.Key<T> key)351 public <T> T get(CameraCharacteristics.Key<T> key) { 352 return get(key.getNativeKey()); 353 } 354 355 /** 356 * @hide 357 */ get(CaptureResult.Key<T> key)358 public <T> T get(CaptureResult.Key<T> key) { 359 return get(key.getNativeKey()); 360 } 361 362 /** 363 * @hide 364 */ get(CaptureRequest.Key<T> key)365 public <T> T get(CaptureRequest.Key<T> key) { 366 return get(key.getNativeKey()); 367 } 368 369 /** 370 * Look-up a metadata field value by its key. 371 * 372 * @param key a non-{@code null} key instance 373 * @return the field corresponding to the {@code key}, or {@code null} if no value was set 374 */ get(Key<T> key)375 public <T> T get(Key<T> key) { 376 Preconditions.checkNotNull(key, "key must not be null"); 377 378 // Check if key has been overridden to use a wrapper class on the java side. 379 GetCommand g = sGetCommandMap.get(key); 380 if (g != null) { 381 return g.getValue(this, key); 382 } 383 return getBase(key); 384 } 385 readFromParcel(Parcel in)386 public void readFromParcel(Parcel in) { 387 nativeReadFromParcel(in); 388 } 389 390 /** 391 * Set the global client-side vendor tag descriptor to allow use of vendor 392 * tags in camera applications. 393 * 394 * @throws ServiceSpecificException 395 * @hide 396 */ setupGlobalVendorTagDescriptor()397 public static void setupGlobalVendorTagDescriptor() throws ServiceSpecificException { 398 int err = nativeSetupGlobalVendorTagDescriptor(); 399 if (err != 0) { 400 throw new ServiceSpecificException(err, "Failure to set up global vendor tags"); 401 } 402 } 403 404 /** 405 * Set the global client-side vendor tag descriptor to allow use of vendor 406 * tags in camera applications. 407 * 408 * @return int An error code corresponding to one of the 409 * {@link ICameraService} error constants, or 0 on success. 410 */ nativeSetupGlobalVendorTagDescriptor()411 private static native int nativeSetupGlobalVendorTagDescriptor(); 412 413 /** 414 * Set a camera metadata field to a value. The field definitions can be 415 * found in {@link CameraCharacteristics}, {@link CaptureResult}, and 416 * {@link CaptureRequest}. 417 * 418 * @param key The metadata field to write. 419 * @param value The value to set the field to, which must be of a matching 420 * type to the key. 421 */ set(Key<T> key, T value)422 public <T> void set(Key<T> key, T value) { 423 SetCommand s = sSetCommandMap.get(key); 424 if (s != null) { 425 s.setValue(this, value); 426 return; 427 } 428 429 setBase(key, value); 430 } 431 set(CaptureRequest.Key<T> key, T value)432 public <T> void set(CaptureRequest.Key<T> key, T value) { 433 set(key.getNativeKey(), value); 434 } 435 set(CaptureResult.Key<T> key, T value)436 public <T> void set(CaptureResult.Key<T> key, T value) { 437 set(key.getNativeKey(), value); 438 } 439 set(CameraCharacteristics.Key<T> key, T value)440 public <T> void set(CameraCharacteristics.Key<T> key, T value) { 441 set(key.getNativeKey(), value); 442 } 443 444 // Keep up-to-date with camera_metadata.h 445 /** 446 * @hide 447 */ 448 public static final int TYPE_BYTE = 0; 449 /** 450 * @hide 451 */ 452 public static final int TYPE_INT32 = 1; 453 /** 454 * @hide 455 */ 456 public static final int TYPE_FLOAT = 2; 457 /** 458 * @hide 459 */ 460 public static final int TYPE_INT64 = 3; 461 /** 462 * @hide 463 */ 464 public static final int TYPE_DOUBLE = 4; 465 /** 466 * @hide 467 */ 468 public static final int TYPE_RATIONAL = 5; 469 /** 470 * @hide 471 */ 472 public static final int NUM_TYPES = 6; 473 close()474 private void close() { 475 // this sets mMetadataPtr to 0 476 nativeClose(); 477 mMetadataPtr = 0; // set it to 0 again to prevent eclipse from making this field final 478 } 479 getBase(CameraCharacteristics.Key<T> key)480 private <T> T getBase(CameraCharacteristics.Key<T> key) { 481 return getBase(key.getNativeKey()); 482 } 483 getBase(CaptureResult.Key<T> key)484 private <T> T getBase(CaptureResult.Key<T> key) { 485 return getBase(key.getNativeKey()); 486 } 487 getBase(CaptureRequest.Key<T> key)488 private <T> T getBase(CaptureRequest.Key<T> key) { 489 return getBase(key.getNativeKey()); 490 } 491 getBase(Key<T> key)492 private <T> T getBase(Key<T> key) { 493 int tag = nativeGetTagFromKeyLocal(key.getName()); 494 byte[] values = readValues(tag); 495 if (values == null) { 496 return null; 497 } 498 499 int nativeType = nativeGetTypeFromTagLocal(tag); 500 Marshaler<T> marshaler = getMarshalerForKey(key, nativeType); 501 ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder()); 502 return marshaler.unmarshal(buffer); 503 } 504 505 // Use Command pattern here to avoid lots of expensive if/equals checks in get for overridden 506 // metadata. 507 private static final HashMap<Key<?>, GetCommand> sGetCommandMap = 508 new HashMap<Key<?>, GetCommand>(); 509 static { 510 sGetCommandMap.put( GetCommand()511 CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey(), new GetCommand() { 512 @Override 513 @SuppressWarnings("unchecked") 514 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 515 return (T) metadata.getAvailableFormats(); 516 } 517 }); 518 sGetCommandMap.put( GetCommand()519 CaptureResult.STATISTICS_FACES.getNativeKey(), new GetCommand() { 520 @Override 521 @SuppressWarnings("unchecked") 522 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 523 return (T) metadata.getFaces(); 524 } 525 }); 526 sGetCommandMap.put( GetCommand()527 CaptureResult.STATISTICS_FACE_RECTANGLES.getNativeKey(), new GetCommand() { 528 @Override 529 @SuppressWarnings("unchecked") 530 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 531 return (T) metadata.getFaceRectangles(); 532 } 533 }); 534 sGetCommandMap.put( CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP.getNativeKey()535 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP.getNativeKey(), 536 new GetCommand() { 537 @Override 538 @SuppressWarnings("unchecked") 539 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 540 return (T) metadata.getStreamConfigurationMap(); 541 } 542 }); 543 sGetCommandMap.put( CameraCharacteristics.CONTROL_MAX_REGIONS_AE.getNativeKey()544 CameraCharacteristics.CONTROL_MAX_REGIONS_AE.getNativeKey(), new GetCommand() { 545 @Override 546 @SuppressWarnings("unchecked") 547 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 548 return (T) metadata.getMaxRegions(key); 549 } 550 }); 551 sGetCommandMap.put( GetCommand()552 CameraCharacteristics.CONTROL_MAX_REGIONS_AWB.getNativeKey(), new GetCommand() { 553 @Override 554 @SuppressWarnings("unchecked") 555 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 556 return (T) metadata.getMaxRegions(key); 557 } 558 }); 559 sGetCommandMap.put( CameraCharacteristics.CONTROL_MAX_REGIONS_AF.getNativeKey()560 CameraCharacteristics.CONTROL_MAX_REGIONS_AF.getNativeKey(), new GetCommand() { 561 @Override 562 @SuppressWarnings("unchecked") 563 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 564 return (T) metadata.getMaxRegions(key); 565 } 566 }); 567 sGetCommandMap.put( GetCommand()568 CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW.getNativeKey(), new GetCommand() { 569 @Override 570 @SuppressWarnings("unchecked") 571 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 572 return (T) metadata.getMaxNumOutputs(key); 573 } 574 }); 575 sGetCommandMap.put( GetCommand()576 CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC.getNativeKey(), new GetCommand() { 577 @Override 578 @SuppressWarnings("unchecked") 579 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 580 return (T) metadata.getMaxNumOutputs(key); 581 } 582 }); 583 sGetCommandMap.put( CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING.getNativeKey()584 CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING.getNativeKey(), 585 new GetCommand() { 586 @Override 587 @SuppressWarnings("unchecked") 588 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 589 return (T) metadata.getMaxNumOutputs(key); 590 } 591 }); 592 sGetCommandMap.put( GetCommand()593 CaptureRequest.TONEMAP_CURVE.getNativeKey(), new GetCommand() { 594 @Override 595 @SuppressWarnings("unchecked") 596 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 597 return (T) metadata.getTonemapCurve(); 598 } 599 }); 600 sGetCommandMap.put( GetCommand()601 CaptureResult.JPEG_GPS_LOCATION.getNativeKey(), new GetCommand() { 602 @Override 603 @SuppressWarnings("unchecked") 604 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 605 return (T) metadata.getGpsLocation(); 606 } 607 }); 608 sGetCommandMap.put( CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP.getNativeKey()609 CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP.getNativeKey(), 610 new GetCommand() { 611 @Override 612 @SuppressWarnings("unchecked") 613 public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { 614 return (T) metadata.getLensShadingMap(); 615 } 616 }); 617 } 618 getAvailableFormats()619 private int[] getAvailableFormats() { 620 int[] availableFormats = getBase(CameraCharacteristics.SCALER_AVAILABLE_FORMATS); 621 if (availableFormats != null) { 622 for (int i = 0; i < availableFormats.length; i++) { 623 // JPEG has different value between native and managed side, need override. 624 if (availableFormats[i] == NATIVE_JPEG_FORMAT) { 625 availableFormats[i] = ImageFormat.JPEG; 626 } 627 } 628 } 629 630 return availableFormats; 631 } 632 setFaces(Face[] faces)633 private boolean setFaces(Face[] faces) { 634 if (faces == null) { 635 return false; 636 } 637 638 int numFaces = faces.length; 639 640 // Detect if all faces are SIMPLE or not; count # of valid faces 641 boolean fullMode = true; 642 for (Face face : faces) { 643 if (face == null) { 644 numFaces--; 645 Log.w(TAG, "setFaces - null face detected, skipping"); 646 continue; 647 } 648 649 if (face.getId() == Face.ID_UNSUPPORTED) { 650 fullMode = false; 651 } 652 } 653 654 Rect[] faceRectangles = new Rect[numFaces]; 655 byte[] faceScores = new byte[numFaces]; 656 int[] faceIds = null; 657 int[] faceLandmarks = null; 658 659 if (fullMode) { 660 faceIds = new int[numFaces]; 661 faceLandmarks = new int[numFaces * FACE_LANDMARK_SIZE]; 662 } 663 664 int i = 0; 665 for (Face face : faces) { 666 if (face == null) { 667 continue; 668 } 669 670 faceRectangles[i] = face.getBounds(); 671 faceScores[i] = (byte)face.getScore(); 672 673 if (fullMode) { 674 faceIds[i] = face.getId(); 675 676 int j = 0; 677 678 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getLeftEyePosition().x; 679 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getLeftEyePosition().y; 680 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getRightEyePosition().x; 681 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getRightEyePosition().y; 682 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getMouthPosition().x; 683 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getMouthPosition().y; 684 } 685 686 i++; 687 } 688 689 set(CaptureResult.STATISTICS_FACE_RECTANGLES, faceRectangles); 690 set(CaptureResult.STATISTICS_FACE_IDS, faceIds); 691 set(CaptureResult.STATISTICS_FACE_LANDMARKS, faceLandmarks); 692 set(CaptureResult.STATISTICS_FACE_SCORES, faceScores); 693 694 return true; 695 } 696 getFaces()697 private Face[] getFaces() { 698 Integer faceDetectMode = get(CaptureResult.STATISTICS_FACE_DETECT_MODE); 699 byte[] faceScores = get(CaptureResult.STATISTICS_FACE_SCORES); 700 Rect[] faceRectangles = get(CaptureResult.STATISTICS_FACE_RECTANGLES); 701 int[] faceIds = get(CaptureResult.STATISTICS_FACE_IDS); 702 int[] faceLandmarks = get(CaptureResult.STATISTICS_FACE_LANDMARKS); 703 704 if (areValuesAllNull(faceDetectMode, faceScores, faceRectangles, faceIds, faceLandmarks)) { 705 return null; 706 } 707 708 if (faceDetectMode == null) { 709 Log.w(TAG, "Face detect mode metadata is null, assuming the mode is SIMPLE"); 710 faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE; 711 } else { 712 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_OFF) { 713 return new Face[0]; 714 } 715 if (faceDetectMode != CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE && 716 faceDetectMode != CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) { 717 Log.w(TAG, "Unknown face detect mode: " + faceDetectMode); 718 return new Face[0]; 719 } 720 } 721 722 // Face scores and rectangles are required by SIMPLE and FULL mode. 723 if (faceScores == null || faceRectangles == null) { 724 Log.w(TAG, "Expect face scores and rectangles to be non-null"); 725 return new Face[0]; 726 } else if (faceScores.length != faceRectangles.length) { 727 Log.w(TAG, String.format("Face score size(%d) doesn match face rectangle size(%d)!", 728 faceScores.length, faceRectangles.length)); 729 } 730 731 // To be safe, make number of faces is the minimal of all face info metadata length. 732 int numFaces = Math.min(faceScores.length, faceRectangles.length); 733 // Face id and landmarks are only required by FULL mode. 734 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) { 735 if (faceIds == null || faceLandmarks == null) { 736 Log.w(TAG, "Expect face ids and landmarks to be non-null for FULL mode," + 737 "fallback to SIMPLE mode"); 738 faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE; 739 } else { 740 if (faceIds.length != numFaces || 741 faceLandmarks.length != numFaces * FACE_LANDMARK_SIZE) { 742 Log.w(TAG, String.format("Face id size(%d), or face landmark size(%d) don't" + 743 "match face number(%d)!", 744 faceIds.length, faceLandmarks.length * FACE_LANDMARK_SIZE, numFaces)); 745 } 746 // To be safe, make number of faces is the minimal of all face info metadata length. 747 numFaces = Math.min(numFaces, faceIds.length); 748 numFaces = Math.min(numFaces, faceLandmarks.length / FACE_LANDMARK_SIZE); 749 } 750 } 751 752 ArrayList<Face> faceList = new ArrayList<Face>(); 753 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE) { 754 for (int i = 0; i < numFaces; i++) { 755 if (faceScores[i] <= Face.SCORE_MAX && 756 faceScores[i] >= Face.SCORE_MIN) { 757 faceList.add(new Face(faceRectangles[i], faceScores[i])); 758 } 759 } 760 } else { 761 // CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL 762 for (int i = 0; i < numFaces; i++) { 763 if (faceScores[i] <= Face.SCORE_MAX && 764 faceScores[i] >= Face.SCORE_MIN && 765 faceIds[i] >= 0) { 766 Point leftEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE], 767 faceLandmarks[i*FACE_LANDMARK_SIZE+1]); 768 Point rightEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+2], 769 faceLandmarks[i*FACE_LANDMARK_SIZE+3]); 770 Point mouth = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+4], 771 faceLandmarks[i*FACE_LANDMARK_SIZE+5]); 772 Face face = new Face(faceRectangles[i], faceScores[i], faceIds[i], 773 leftEye, rightEye, mouth); 774 faceList.add(face); 775 } 776 } 777 } 778 Face[] faces = new Face[faceList.size()]; 779 faceList.toArray(faces); 780 return faces; 781 } 782 783 // Face rectangles are defined as (left, top, right, bottom) instead of 784 // (left, top, width, height) at the native level, so the normal Rect 785 // conversion that does (l, t, w, h) -> (l, t, r, b) is unnecessary. Undo 786 // that conversion here for just the faces. getFaceRectangles()787 private Rect[] getFaceRectangles() { 788 Rect[] faceRectangles = getBase(CaptureResult.STATISTICS_FACE_RECTANGLES); 789 if (faceRectangles == null) return null; 790 791 Rect[] fixedFaceRectangles = new Rect[faceRectangles.length]; 792 for (int i = 0; i < faceRectangles.length; i++) { 793 fixedFaceRectangles[i] = new Rect( 794 faceRectangles[i].left, 795 faceRectangles[i].top, 796 faceRectangles[i].right - faceRectangles[i].left, 797 faceRectangles[i].bottom - faceRectangles[i].top); 798 } 799 return fixedFaceRectangles; 800 } 801 getLensShadingMap()802 private LensShadingMap getLensShadingMap() { 803 float[] lsmArray = getBase(CaptureResult.STATISTICS_LENS_SHADING_MAP); 804 Size s = get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE); 805 806 // Do not warn if lsmArray is null while s is not. This is valid. 807 if (lsmArray == null) { 808 return null; 809 } 810 811 if (s == null) { 812 Log.w(TAG, "getLensShadingMap - Lens shading map size was null."); 813 return null; 814 } 815 816 LensShadingMap map = new LensShadingMap(lsmArray, s.getHeight(), s.getWidth()); 817 return map; 818 } 819 getGpsLocation()820 private Location getGpsLocation() { 821 String processingMethod = get(CaptureResult.JPEG_GPS_PROCESSING_METHOD); 822 double[] coords = get(CaptureResult.JPEG_GPS_COORDINATES); 823 Long timeStamp = get(CaptureResult.JPEG_GPS_TIMESTAMP); 824 825 if (areValuesAllNull(processingMethod, coords, timeStamp)) { 826 return null; 827 } 828 829 Location l = new Location(translateProcessToLocationProvider(processingMethod)); 830 if (timeStamp != null) { 831 // Location expects timestamp in [ms.] 832 l.setTime(timeStamp * 1000); 833 } else { 834 Log.w(TAG, "getGpsLocation - No timestamp for GPS location."); 835 } 836 837 if (coords != null) { 838 l.setLatitude(coords[0]); 839 l.setLongitude(coords[1]); 840 l.setAltitude(coords[2]); 841 } else { 842 Log.w(TAG, "getGpsLocation - No coordinates for GPS location"); 843 } 844 845 return l; 846 } 847 setGpsLocation(Location l)848 private boolean setGpsLocation(Location l) { 849 if (l == null) { 850 return false; 851 } 852 853 double[] coords = { l.getLatitude(), l.getLongitude(), l.getAltitude() }; 854 String processMethod = translateLocationProviderToProcess(l.getProvider()); 855 //JPEG_GPS_TIMESTAMP expects sec. instead of msec. 856 long timestamp = l.getTime() / 1000; 857 858 set(CaptureRequest.JPEG_GPS_TIMESTAMP, timestamp); 859 set(CaptureRequest.JPEG_GPS_COORDINATES, coords); 860 861 if (processMethod == null) { 862 Log.w(TAG, "setGpsLocation - No process method, Location is not from a GPS or NETWORK" + 863 "provider"); 864 } else { 865 setBase(CaptureRequest.JPEG_GPS_PROCESSING_METHOD, processMethod); 866 } 867 return true; 868 } 869 getStreamConfigurationMap()870 private StreamConfigurationMap getStreamConfigurationMap() { 871 StreamConfiguration[] configurations = getBase( 872 CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS); 873 StreamConfigurationDuration[] minFrameDurations = getBase( 874 CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS); 875 StreamConfigurationDuration[] stallDurations = getBase( 876 CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS); 877 StreamConfiguration[] depthConfigurations = getBase( 878 CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS); 879 StreamConfigurationDuration[] depthMinFrameDurations = getBase( 880 CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS); 881 StreamConfigurationDuration[] depthStallDurations = getBase( 882 CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS); 883 HighSpeedVideoConfiguration[] highSpeedVideoConfigurations = getBase( 884 CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS); 885 ReprocessFormatsMap inputOutputFormatsMap = getBase( 886 CameraCharacteristics.SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP); 887 int[] capabilities = getBase(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 888 boolean listHighResolution = false; 889 for (int capability : capabilities) { 890 if (capability == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE) { 891 listHighResolution = true; 892 break; 893 } 894 } 895 return new StreamConfigurationMap( 896 configurations, minFrameDurations, stallDurations, 897 depthConfigurations, depthMinFrameDurations, depthStallDurations, 898 highSpeedVideoConfigurations, inputOutputFormatsMap, 899 listHighResolution); 900 } 901 getMaxRegions(Key<T> key)902 private <T> Integer getMaxRegions(Key<T> key) { 903 final int AE = 0; 904 final int AWB = 1; 905 final int AF = 2; 906 907 // The order of the elements is: (AE, AWB, AF) 908 int[] maxRegions = getBase(CameraCharacteristics.CONTROL_MAX_REGIONS); 909 910 if (maxRegions == null) { 911 return null; 912 } 913 914 if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AE)) { 915 return maxRegions[AE]; 916 } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB)) { 917 return maxRegions[AWB]; 918 } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AF)) { 919 return maxRegions[AF]; 920 } else { 921 throw new AssertionError("Invalid key " + key); 922 } 923 } 924 getMaxNumOutputs(Key<T> key)925 private <T> Integer getMaxNumOutputs(Key<T> key) { 926 final int RAW = 0; 927 final int PROC = 1; 928 final int PROC_STALLING = 2; 929 930 // The order of the elements is: (raw, proc+nonstalling, proc+stalling) 931 int[] maxNumOutputs = getBase(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_STREAMS); 932 933 if (maxNumOutputs == null) { 934 return null; 935 } 936 937 if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW)) { 938 return maxNumOutputs[RAW]; 939 } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC)) { 940 return maxNumOutputs[PROC]; 941 } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING)) { 942 return maxNumOutputs[PROC_STALLING]; 943 } else { 944 throw new AssertionError("Invalid key " + key); 945 } 946 } 947 getTonemapCurve()948 private <T> TonemapCurve getTonemapCurve() { 949 float[] red = getBase(CaptureRequest.TONEMAP_CURVE_RED); 950 float[] green = getBase(CaptureRequest.TONEMAP_CURVE_GREEN); 951 float[] blue = getBase(CaptureRequest.TONEMAP_CURVE_BLUE); 952 953 if (areValuesAllNull(red, green, blue)) { 954 return null; 955 } 956 957 if (red == null || green == null || blue == null) { 958 Log.w(TAG, "getTonemapCurve - missing tone curve components"); 959 return null; 960 } 961 TonemapCurve tc = new TonemapCurve(red, green, blue); 962 return tc; 963 } 964 setBase(CameraCharacteristics.Key<T> key, T value)965 private <T> void setBase(CameraCharacteristics.Key<T> key, T value) { 966 setBase(key.getNativeKey(), value); 967 } 968 setBase(CaptureResult.Key<T> key, T value)969 private <T> void setBase(CaptureResult.Key<T> key, T value) { 970 setBase(key.getNativeKey(), value); 971 } 972 setBase(CaptureRequest.Key<T> key, T value)973 private <T> void setBase(CaptureRequest.Key<T> key, T value) { 974 setBase(key.getNativeKey(), value); 975 } 976 setBase(Key<T> key, T value)977 private <T> void setBase(Key<T> key, T value) { 978 int tag = nativeGetTagFromKeyLocal(key.getName()); 979 if (value == null) { 980 // Erase the entry 981 writeValues(tag, /*src*/null); 982 return; 983 } // else update the entry to a new value 984 985 int nativeType = nativeGetTypeFromTagLocal(tag); 986 Marshaler<T> marshaler = getMarshalerForKey(key, nativeType); 987 int size = marshaler.calculateMarshalSize(value); 988 989 // TODO: Optimization. Cache the byte[] and reuse if the size is big enough. 990 byte[] values = new byte[size]; 991 992 ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder()); 993 marshaler.marshal(value, buffer); 994 995 writeValues(tag, values); 996 } 997 998 // Use Command pattern here to avoid lots of expensive if/equals checks in get for overridden 999 // metadata. 1000 private static final HashMap<Key<?>, SetCommand> sSetCommandMap = 1001 new HashMap<Key<?>, SetCommand>(); 1002 static { CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey()1003 sSetCommandMap.put(CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey(), 1004 new SetCommand() { 1005 @Override 1006 public <T> void setValue(CameraMetadataNative metadata, T value) { 1007 metadata.setAvailableFormats((int[]) value); 1008 } 1009 }); CaptureResult.STATISTICS_FACE_RECTANGLES.getNativeKey()1010 sSetCommandMap.put(CaptureResult.STATISTICS_FACE_RECTANGLES.getNativeKey(), 1011 new SetCommand() { 1012 @Override 1013 public <T> void setValue(CameraMetadataNative metadata, T value) { 1014 metadata.setFaceRectangles((Rect[]) value); 1015 } 1016 }); CaptureResult.STATISTICS_FACES.getNativeKey()1017 sSetCommandMap.put(CaptureResult.STATISTICS_FACES.getNativeKey(), 1018 new SetCommand() { 1019 @Override 1020 public <T> void setValue(CameraMetadataNative metadata, T value) { 1021 metadata.setFaces((Face[])value); 1022 } 1023 }); CaptureRequest.TONEMAP_CURVE.getNativeKey()1024 sSetCommandMap.put(CaptureRequest.TONEMAP_CURVE.getNativeKey(), new SetCommand() { 1025 @Override 1026 public <T> void setValue(CameraMetadataNative metadata, T value) { 1027 metadata.setTonemapCurve((TonemapCurve) value); 1028 } 1029 }); CaptureResult.JPEG_GPS_LOCATION.getNativeKey()1030 sSetCommandMap.put(CaptureResult.JPEG_GPS_LOCATION.getNativeKey(), new SetCommand() { 1031 @Override 1032 public <T> void setValue(CameraMetadataNative metadata, T value) { 1033 metadata.setGpsLocation((Location) value); 1034 } 1035 }); 1036 } 1037 setAvailableFormats(int[] value)1038 private boolean setAvailableFormats(int[] value) { 1039 int[] availableFormat = value; 1040 if (value == null) { 1041 // Let setBase() to handle the null value case. 1042 return false; 1043 } 1044 1045 int[] newValues = new int[availableFormat.length]; 1046 for (int i = 0; i < availableFormat.length; i++) { 1047 newValues[i] = availableFormat[i]; 1048 if (availableFormat[i] == ImageFormat.JPEG) { 1049 newValues[i] = NATIVE_JPEG_FORMAT; 1050 } 1051 } 1052 1053 setBase(CameraCharacteristics.SCALER_AVAILABLE_FORMATS, newValues); 1054 return true; 1055 } 1056 1057 /** 1058 * Convert Face Rectangles from managed side to native side as they have different definitions. 1059 * <p> 1060 * Managed side face rectangles are defined as: left, top, width, height. 1061 * Native side face rectangles are defined as: left, top, right, bottom. 1062 * The input face rectangle need to be converted to native side definition when set is called. 1063 * </p> 1064 * 1065 * @param faceRects Input face rectangles. 1066 * @return true if face rectangles can be set successfully. Otherwise, Let the caller 1067 * (setBase) to handle it appropriately. 1068 */ setFaceRectangles(Rect[] faceRects)1069 private boolean setFaceRectangles(Rect[] faceRects) { 1070 if (faceRects == null) { 1071 return false; 1072 } 1073 1074 Rect[] newFaceRects = new Rect[faceRects.length]; 1075 for (int i = 0; i < newFaceRects.length; i++) { 1076 newFaceRects[i] = new Rect( 1077 faceRects[i].left, 1078 faceRects[i].top, 1079 faceRects[i].right + faceRects[i].left, 1080 faceRects[i].bottom + faceRects[i].top); 1081 } 1082 1083 setBase(CaptureResult.STATISTICS_FACE_RECTANGLES, newFaceRects); 1084 return true; 1085 } 1086 setTonemapCurve(TonemapCurve tc)1087 private <T> boolean setTonemapCurve(TonemapCurve tc) { 1088 if (tc == null) { 1089 return false; 1090 } 1091 1092 float[][] curve = new float[3][]; 1093 for (int i = TonemapCurve.CHANNEL_RED; i <= TonemapCurve.CHANNEL_BLUE; i++) { 1094 int pointCount = tc.getPointCount(i); 1095 curve[i] = new float[pointCount * TonemapCurve.POINT_SIZE]; 1096 tc.copyColorCurve(i, curve[i], 0); 1097 } 1098 setBase(CaptureRequest.TONEMAP_CURVE_RED, curve[0]); 1099 setBase(CaptureRequest.TONEMAP_CURVE_GREEN, curve[1]); 1100 setBase(CaptureRequest.TONEMAP_CURVE_BLUE, curve[2]); 1101 1102 return true; 1103 } 1104 1105 private long mMetadataPtr; // native CameraMetadata* 1106 nativeAllocate()1107 private native long nativeAllocate(); nativeAllocateCopy(CameraMetadataNative other)1108 private native long nativeAllocateCopy(CameraMetadataNative other) 1109 throws NullPointerException; 1110 nativeWriteToParcel(Parcel dest)1111 private native synchronized void nativeWriteToParcel(Parcel dest); nativeReadFromParcel(Parcel source)1112 private native synchronized void nativeReadFromParcel(Parcel source); nativeSwap(CameraMetadataNative other)1113 private native synchronized void nativeSwap(CameraMetadataNative other) 1114 throws NullPointerException; nativeClose()1115 private native synchronized void nativeClose(); nativeIsEmpty()1116 private native synchronized boolean nativeIsEmpty(); nativeGetEntryCount()1117 private native synchronized int nativeGetEntryCount(); 1118 nativeReadValues(int tag)1119 private native synchronized byte[] nativeReadValues(int tag); nativeWriteValues(int tag, byte[] src)1120 private native synchronized void nativeWriteValues(int tag, byte[] src); nativeDump()1121 private native synchronized void nativeDump() throws IOException; // dump to ALOGD 1122 nativeGetAllVendorKeys(Class keyClass)1123 private native synchronized ArrayList nativeGetAllVendorKeys(Class keyClass); nativeGetTagFromKeyLocal(String keyName)1124 private native synchronized int nativeGetTagFromKeyLocal(String keyName) 1125 throws IllegalArgumentException; nativeGetTypeFromTagLocal(int tag)1126 private native synchronized int nativeGetTypeFromTagLocal(int tag) 1127 throws IllegalArgumentException; nativeGetTagFromKey(String keyName, long vendorId)1128 private static native int nativeGetTagFromKey(String keyName, long vendorId) 1129 throws IllegalArgumentException; nativeGetTypeFromTag(int tag, long vendorId)1130 private static native int nativeGetTypeFromTag(int tag, long vendorId) 1131 throws IllegalArgumentException; 1132 1133 /** 1134 * <p>Perform a 0-copy swap of the internal metadata with another object.</p> 1135 * 1136 * <p>Useful to convert a CameraMetadata into e.g. a CaptureRequest.</p> 1137 * 1138 * @param other Metadata to swap with 1139 * @throws NullPointerException if other was null 1140 * @hide 1141 */ swap(CameraMetadataNative other)1142 public void swap(CameraMetadataNative other) { 1143 nativeSwap(other); 1144 } 1145 1146 /** 1147 * @hide 1148 */ getEntryCount()1149 public int getEntryCount() { 1150 return nativeGetEntryCount(); 1151 } 1152 1153 /** 1154 * Does this metadata contain at least 1 entry? 1155 * 1156 * @hide 1157 */ isEmpty()1158 public boolean isEmpty() { 1159 return nativeIsEmpty(); 1160 } 1161 1162 1163 /** 1164 * Return a list containing keys of the given key class for all defined vendor tags. 1165 * 1166 * @hide 1167 */ getAllVendorKeys(Class<K> keyClass)1168 public <K> ArrayList<K> getAllVendorKeys(Class<K> keyClass) { 1169 if (keyClass == null) { 1170 throw new NullPointerException(); 1171 } 1172 return (ArrayList<K>) nativeGetAllVendorKeys(keyClass); 1173 } 1174 1175 /** 1176 * Convert a key string into the equivalent native tag. 1177 * 1178 * @throws IllegalArgumentException if the key was not recognized 1179 * @throws NullPointerException if the key was null 1180 * 1181 * @hide 1182 */ getTag(String key)1183 public static int getTag(String key) { 1184 return nativeGetTagFromKey(key, Long.MAX_VALUE); 1185 } 1186 1187 /** 1188 * Convert a key string into the equivalent native tag. 1189 * 1190 * @throws IllegalArgumentException if the key was not recognized 1191 * @throws NullPointerException if the key was null 1192 * 1193 * @hide 1194 */ getTag(String key, long vendorId)1195 public static int getTag(String key, long vendorId) { 1196 return nativeGetTagFromKey(key, vendorId); 1197 } 1198 1199 /** 1200 * Get the underlying native type for a tag. 1201 * 1202 * @param tag An integer tag, see e.g. {@link #getTag} 1203 * @param vendorId A vendor tag provider id 1204 * @return An int enum for the metadata type, see e.g. {@link #TYPE_BYTE} 1205 * 1206 * @hide 1207 */ getNativeType(int tag, long vendorId)1208 public static int getNativeType(int tag, long vendorId) { 1209 return nativeGetTypeFromTag(tag, vendorId); 1210 } 1211 1212 /** 1213 * <p>Updates the existing entry for tag with the new bytes pointed by src, erasing 1214 * the entry if src was null.</p> 1215 * 1216 * <p>An empty array can be passed in to update the entry to 0 elements.</p> 1217 * 1218 * @param tag An integer tag, see e.g. {@link #getTag} 1219 * @param src An array of bytes, or null to erase the entry 1220 * 1221 * @hide 1222 */ writeValues(int tag, byte[] src)1223 public void writeValues(int tag, byte[] src) { 1224 nativeWriteValues(tag, src); 1225 } 1226 1227 /** 1228 * <p>Returns a byte[] of data corresponding to this tag. Use a wrapped bytebuffer to unserialize 1229 * the data properly.</p> 1230 * 1231 * <p>An empty array can be returned to denote an existing entry with 0 elements.</p> 1232 * 1233 * @param tag An integer tag, see e.g. {@link #getTag} 1234 * 1235 * @return {@code null} if there were 0 entries for this tag, a byte[] otherwise. 1236 * @hide 1237 */ readValues(int tag)1238 public byte[] readValues(int tag) { 1239 // TODO: Optimization. Native code returns a ByteBuffer instead. 1240 return nativeReadValues(tag); 1241 } 1242 1243 /** 1244 * Dumps the native metadata contents to logcat. 1245 * 1246 * <p>Visibility for testing/debugging only. The results will not 1247 * include any synthesized keys, as they are invisible to the native layer.</p> 1248 * 1249 * @hide 1250 */ dumpToLog()1251 public void dumpToLog() { 1252 try { 1253 nativeDump(); 1254 } catch (IOException e) { 1255 Log.wtf(TAG, "Dump logging failed", e); 1256 } 1257 } 1258 1259 @Override finalize()1260 protected void finalize() throws Throwable { 1261 try { 1262 close(); 1263 } finally { 1264 super.finalize(); 1265 } 1266 } 1267 1268 /** 1269 * Get the marshaler compatible with the {@code key} and type {@code T}. 1270 * 1271 * @throws UnsupportedOperationException 1272 * if the native/managed type combination for {@code key} is not supported 1273 */ getMarshalerForKey(Key<T> key, int nativeType)1274 private static <T> Marshaler<T> getMarshalerForKey(Key<T> key, int nativeType) { 1275 return MarshalRegistry.getMarshaler(key.getTypeReference(), 1276 nativeType); 1277 } 1278 1279 @SuppressWarnings({ "unchecked", "rawtypes" }) registerAllMarshalers()1280 private static void registerAllMarshalers() { 1281 if (DEBUG) { 1282 Log.v(TAG, "Shall register metadata marshalers"); 1283 } 1284 1285 MarshalQueryable[] queryList = new MarshalQueryable[] { 1286 // marshalers for standard types 1287 new MarshalQueryablePrimitive(), 1288 new MarshalQueryableEnum(), 1289 new MarshalQueryableArray(), 1290 1291 // pseudo standard types, that expand/narrow the native type into a managed type 1292 new MarshalQueryableBoolean(), 1293 new MarshalQueryableNativeByteToInteger(), 1294 1295 // marshalers for custom types 1296 new MarshalQueryableRect(), 1297 new MarshalQueryableSize(), 1298 new MarshalQueryableSizeF(), 1299 new MarshalQueryableString(), 1300 new MarshalQueryableReprocessFormatsMap(), 1301 new MarshalQueryableRange(), 1302 new MarshalQueryablePair(), 1303 new MarshalQueryableMeteringRectangle(), 1304 new MarshalQueryableColorSpaceTransform(), 1305 new MarshalQueryableStreamConfiguration(), 1306 new MarshalQueryableStreamConfigurationDuration(), 1307 new MarshalQueryableRggbChannelVector(), 1308 new MarshalQueryableBlackLevelPattern(), 1309 new MarshalQueryableHighSpeedVideoConfiguration(), 1310 1311 // generic parcelable marshaler (MUST BE LAST since it has lowest priority) 1312 new MarshalQueryableParcelable(), 1313 }; 1314 1315 for (MarshalQueryable query : queryList) { 1316 MarshalRegistry.registerMarshalQueryable(query); 1317 } 1318 if (DEBUG) { 1319 Log.v(TAG, "Registered metadata marshalers"); 1320 } 1321 } 1322 1323 /** Check if input arguments are all {@code null}. 1324 * 1325 * @param objs Input arguments for null check 1326 * @return {@code true} if input arguments are all {@code null}, otherwise {@code false} 1327 */ areValuesAllNull(Object... objs)1328 private static boolean areValuesAllNull(Object... objs) { 1329 for (Object o : objs) { 1330 if (o != null) return false; 1331 } 1332 return true; 1333 } 1334 1335 static { registerAllMarshalers()1336 registerAllMarshalers(); 1337 } 1338 } 1339