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