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