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