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