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