CameraMetadataNative.java revision 0a551f1487e00a598b20b1bc58a1ccd7226e7091
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.ReprocessFormatsMap; 52import android.hardware.camera2.params.StreamConfiguration; 53import android.hardware.camera2.params.StreamConfigurationDuration; 54import android.hardware.camera2.params.StreamConfigurationMap; 55import android.hardware.camera2.params.TonemapCurve; 56import android.hardware.camera2.utils.TypeReference; 57import android.location.Location; 58import android.location.LocationManager; 59import android.os.Parcelable; 60import android.os.Parcel; 61import android.util.Log; 62import android.util.Size; 63 64import com.android.internal.util.Preconditions; 65 66import java.io.IOException; 67import java.nio.ByteBuffer; 68import java.nio.ByteOrder; 69import java.util.ArrayList; 70import java.util.HashMap; 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 byte[] faceScores = get(CaptureResult.STATISTICS_FACE_SCORES); 659 Rect[] faceRectangles = get(CaptureResult.STATISTICS_FACE_RECTANGLES); 660 int[] faceIds = get(CaptureResult.STATISTICS_FACE_IDS); 661 int[] faceLandmarks = get(CaptureResult.STATISTICS_FACE_LANDMARKS); 662 663 if (areValuesAllNull(faceDetectMode, faceScores, faceRectangles, faceIds, faceLandmarks)) { 664 return null; 665 } 666 667 if (faceDetectMode == null) { 668 Log.w(TAG, "Face detect mode metadata is null, assuming the mode is SIMPLE"); 669 faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE; 670 } else { 671 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_OFF) { 672 return new Face[0]; 673 } 674 if (faceDetectMode != CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE && 675 faceDetectMode != CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) { 676 Log.w(TAG, "Unknown face detect mode: " + faceDetectMode); 677 return new Face[0]; 678 } 679 } 680 681 // Face scores and rectangles are required by SIMPLE and FULL mode. 682 if (faceScores == null || faceRectangles == null) { 683 Log.w(TAG, "Expect face scores and rectangles to be non-null"); 684 return new Face[0]; 685 } else if (faceScores.length != faceRectangles.length) { 686 Log.w(TAG, String.format("Face score size(%d) doesn match face rectangle size(%d)!", 687 faceScores.length, faceRectangles.length)); 688 } 689 690 // To be safe, make number of faces is the minimal of all face info metadata length. 691 int numFaces = Math.min(faceScores.length, faceRectangles.length); 692 // Face id and landmarks are only required by FULL mode. 693 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) { 694 if (faceIds == null || faceLandmarks == null) { 695 Log.w(TAG, "Expect face ids and landmarks to be non-null for FULL mode," + 696 "fallback to SIMPLE mode"); 697 faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE; 698 } else { 699 if (faceIds.length != numFaces || 700 faceLandmarks.length != numFaces * FACE_LANDMARK_SIZE) { 701 Log.w(TAG, String.format("Face id size(%d), or face landmark size(%d) don't" + 702 "match face number(%d)!", 703 faceIds.length, faceLandmarks.length * FACE_LANDMARK_SIZE, numFaces)); 704 } 705 // To be safe, make number of faces is the minimal of all face info metadata length. 706 numFaces = Math.min(numFaces, faceIds.length); 707 numFaces = Math.min(numFaces, faceLandmarks.length / FACE_LANDMARK_SIZE); 708 } 709 } 710 711 ArrayList<Face> faceList = new ArrayList<Face>(); 712 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE) { 713 for (int i = 0; i < numFaces; i++) { 714 if (faceScores[i] <= Face.SCORE_MAX && 715 faceScores[i] >= Face.SCORE_MIN) { 716 faceList.add(new Face(faceRectangles[i], faceScores[i])); 717 } 718 } 719 } else { 720 // CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL 721 for (int i = 0; i < numFaces; i++) { 722 if (faceScores[i] <= Face.SCORE_MAX && 723 faceScores[i] >= Face.SCORE_MIN && 724 faceIds[i] >= 0) { 725 Point leftEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE], 726 faceLandmarks[i*FACE_LANDMARK_SIZE+1]); 727 Point rightEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+2], 728 faceLandmarks[i*FACE_LANDMARK_SIZE+3]); 729 Point mouth = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+4], 730 faceLandmarks[i*FACE_LANDMARK_SIZE+5]); 731 Face face = new Face(faceRectangles[i], faceScores[i], faceIds[i], 732 leftEye, rightEye, mouth); 733 faceList.add(face); 734 } 735 } 736 } 737 Face[] faces = new Face[faceList.size()]; 738 faceList.toArray(faces); 739 return faces; 740 } 741 742 // Face rectangles are defined as (left, top, right, bottom) instead of 743 // (left, top, width, height) at the native level, so the normal Rect 744 // conversion that does (l, t, w, h) -> (l, t, r, b) is unnecessary. Undo 745 // that conversion here for just the faces. 746 private Rect[] getFaceRectangles() { 747 Rect[] faceRectangles = getBase(CaptureResult.STATISTICS_FACE_RECTANGLES); 748 if (faceRectangles == null) return null; 749 750 Rect[] fixedFaceRectangles = new Rect[faceRectangles.length]; 751 for (int i = 0; i < faceRectangles.length; i++) { 752 fixedFaceRectangles[i] = new Rect( 753 faceRectangles[i].left, 754 faceRectangles[i].top, 755 faceRectangles[i].right - faceRectangles[i].left, 756 faceRectangles[i].bottom - faceRectangles[i].top); 757 } 758 return fixedFaceRectangles; 759 } 760 761 private LensShadingMap getLensShadingMap() { 762 float[] lsmArray = getBase(CaptureResult.STATISTICS_LENS_SHADING_MAP); 763 Size s = get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE); 764 765 // Do not warn if lsmArray is null while s is not. This is valid. 766 if (lsmArray == null) { 767 return null; 768 } 769 770 if (s == null) { 771 Log.w(TAG, "getLensShadingMap - Lens shading map size was null."); 772 return null; 773 } 774 775 LensShadingMap map = new LensShadingMap(lsmArray, s.getHeight(), s.getWidth()); 776 return map; 777 } 778 779 private Location getGpsLocation() { 780 String processingMethod = get(CaptureResult.JPEG_GPS_PROCESSING_METHOD); 781 double[] coords = get(CaptureResult.JPEG_GPS_COORDINATES); 782 Long timeStamp = get(CaptureResult.JPEG_GPS_TIMESTAMP); 783 784 if (areValuesAllNull(processingMethod, coords, timeStamp)) { 785 return null; 786 } 787 788 Location l = new Location(translateProcessToLocationProvider(processingMethod)); 789 if (timeStamp != null) { 790 l.setTime(timeStamp); 791 } else { 792 Log.w(TAG, "getGpsLocation - No timestamp for GPS location."); 793 } 794 795 if (coords != null) { 796 l.setLatitude(coords[0]); 797 l.setLongitude(coords[1]); 798 l.setAltitude(coords[2]); 799 } else { 800 Log.w(TAG, "getGpsLocation - No coordinates for GPS location"); 801 } 802 803 return l; 804 } 805 806 private boolean setGpsLocation(Location l) { 807 if (l == null) { 808 return false; 809 } 810 811 double[] coords = { l.getLatitude(), l.getLongitude(), l.getAltitude() }; 812 String processMethod = translateLocationProviderToProcess(l.getProvider()); 813 long timestamp = l.getTime(); 814 815 set(CaptureRequest.JPEG_GPS_TIMESTAMP, timestamp); 816 set(CaptureRequest.JPEG_GPS_COORDINATES, coords); 817 818 if (processMethod == null) { 819 Log.w(TAG, "setGpsLocation - No process method, Location is not from a GPS or NETWORK" + 820 "provider"); 821 } else { 822 setBase(CaptureRequest.JPEG_GPS_PROCESSING_METHOD, processMethod); 823 } 824 return true; 825 } 826 827 private StreamConfigurationMap getStreamConfigurationMap() { 828 StreamConfiguration[] configurations = getBase( 829 CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS); 830 StreamConfigurationDuration[] minFrameDurations = getBase( 831 CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS); 832 StreamConfigurationDuration[] stallDurations = getBase( 833 CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS); 834 StreamConfiguration[] depthConfigurations = getBase( 835 CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS); 836 StreamConfigurationDuration[] depthMinFrameDurations = getBase( 837 CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS); 838 StreamConfigurationDuration[] depthStallDurations = getBase( 839 CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS); 840 HighSpeedVideoConfiguration[] highSpeedVideoConfigurations = getBase( 841 CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS); 842 ReprocessFormatsMap inputOutputFormatsMap = getBase( 843 CameraCharacteristics.SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP); 844 845 return new StreamConfigurationMap( 846 configurations, minFrameDurations, stallDurations, 847 depthConfigurations, depthMinFrameDurations, depthStallDurations, 848 highSpeedVideoConfigurations, inputOutputFormatsMap); 849 } 850 851 private <T> Integer getMaxRegions(Key<T> key) { 852 final int AE = 0; 853 final int AWB = 1; 854 final int AF = 2; 855 856 // The order of the elements is: (AE, AWB, AF) 857 int[] maxRegions = getBase(CameraCharacteristics.CONTROL_MAX_REGIONS); 858 859 if (maxRegions == null) { 860 return null; 861 } 862 863 if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AE)) { 864 return maxRegions[AE]; 865 } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB)) { 866 return maxRegions[AWB]; 867 } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AF)) { 868 return maxRegions[AF]; 869 } else { 870 throw new AssertionError("Invalid key " + key); 871 } 872 } 873 874 private <T> Integer getMaxNumOutputs(Key<T> key) { 875 final int RAW = 0; 876 final int PROC = 1; 877 final int PROC_STALLING = 2; 878 879 // The order of the elements is: (raw, proc+nonstalling, proc+stalling) 880 int[] maxNumOutputs = getBase(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_STREAMS); 881 882 if (maxNumOutputs == null) { 883 return null; 884 } 885 886 if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW)) { 887 return maxNumOutputs[RAW]; 888 } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC)) { 889 return maxNumOutputs[PROC]; 890 } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING)) { 891 return maxNumOutputs[PROC_STALLING]; 892 } else { 893 throw new AssertionError("Invalid key " + key); 894 } 895 } 896 897 private <T> TonemapCurve getTonemapCurve() { 898 float[] red = getBase(CaptureRequest.TONEMAP_CURVE_RED); 899 float[] green = getBase(CaptureRequest.TONEMAP_CURVE_GREEN); 900 float[] blue = getBase(CaptureRequest.TONEMAP_CURVE_BLUE); 901 902 if (areValuesAllNull(red, green, blue)) { 903 return null; 904 } 905 906 if (red == null || green == null || blue == null) { 907 Log.w(TAG, "getTonemapCurve - missing tone curve components"); 908 return null; 909 } 910 TonemapCurve tc = new TonemapCurve(red, green, blue); 911 return tc; 912 } 913 914 private <T> void setBase(CameraCharacteristics.Key<T> key, T value) { 915 setBase(key.getNativeKey(), value); 916 } 917 918 private <T> void setBase(CaptureResult.Key<T> key, T value) { 919 setBase(key.getNativeKey(), value); 920 } 921 922 private <T> void setBase(CaptureRequest.Key<T> key, T value) { 923 setBase(key.getNativeKey(), value); 924 } 925 926 private <T> void setBase(Key<T> key, T value) { 927 int tag = key.getTag(); 928 929 if (value == null) { 930 // Erase the entry 931 writeValues(tag, /*src*/null); 932 return; 933 } // else update the entry to a new value 934 935 Marshaler<T> marshaler = getMarshalerForKey(key); 936 int size = marshaler.calculateMarshalSize(value); 937 938 // TODO: Optimization. Cache the byte[] and reuse if the size is big enough. 939 byte[] values = new byte[size]; 940 941 ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder()); 942 marshaler.marshal(value, buffer); 943 944 writeValues(tag, values); 945 } 946 947 // Use Command pattern here to avoid lots of expensive if/equals checks in get for overridden 948 // metadata. 949 private static final HashMap<Key<?>, SetCommand> sSetCommandMap = 950 new HashMap<Key<?>, SetCommand>(); 951 static { 952 sSetCommandMap.put(CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey(), 953 new SetCommand() { 954 @Override 955 public <T> void setValue(CameraMetadataNative metadata, T value) { 956 metadata.setAvailableFormats((int[]) value); 957 } 958 }); 959 sSetCommandMap.put(CaptureResult.STATISTICS_FACE_RECTANGLES.getNativeKey(), 960 new SetCommand() { 961 @Override 962 public <T> void setValue(CameraMetadataNative metadata, T value) { 963 metadata.setFaceRectangles((Rect[]) value); 964 } 965 }); 966 sSetCommandMap.put(CaptureResult.STATISTICS_FACES.getNativeKey(), 967 new SetCommand() { 968 @Override 969 public <T> void setValue(CameraMetadataNative metadata, T value) { 970 metadata.setFaces((Face[])value); 971 } 972 }); 973 sSetCommandMap.put(CaptureRequest.TONEMAP_CURVE.getNativeKey(), new SetCommand() { 974 @Override 975 public <T> void setValue(CameraMetadataNative metadata, T value) { 976 metadata.setTonemapCurve((TonemapCurve) value); 977 } 978 }); 979 sSetCommandMap.put(CaptureResult.JPEG_GPS_LOCATION.getNativeKey(), new SetCommand() { 980 @Override 981 public <T> void setValue(CameraMetadataNative metadata, T value) { 982 metadata.setGpsLocation((Location) value); 983 } 984 }); 985 } 986 987 private boolean setAvailableFormats(int[] value) { 988 int[] availableFormat = value; 989 if (value == null) { 990 // Let setBase() to handle the null value case. 991 return false; 992 } 993 994 int[] newValues = new int[availableFormat.length]; 995 for (int i = 0; i < availableFormat.length; i++) { 996 newValues[i] = availableFormat[i]; 997 if (availableFormat[i] == ImageFormat.JPEG) { 998 newValues[i] = NATIVE_JPEG_FORMAT; 999 } 1000 } 1001 1002 setBase(CameraCharacteristics.SCALER_AVAILABLE_FORMATS, newValues); 1003 return true; 1004 } 1005 1006 /** 1007 * Convert Face Rectangles from managed side to native side as they have different definitions. 1008 * <p> 1009 * Managed side face rectangles are defined as: left, top, width, height. 1010 * Native side face rectangles are defined as: left, top, right, bottom. 1011 * The input face rectangle need to be converted to native side definition when set is called. 1012 * </p> 1013 * 1014 * @param faceRects Input face rectangles. 1015 * @return true if face rectangles can be set successfully. Otherwise, Let the caller 1016 * (setBase) to handle it appropriately. 1017 */ 1018 private boolean setFaceRectangles(Rect[] faceRects) { 1019 if (faceRects == null) { 1020 return false; 1021 } 1022 1023 Rect[] newFaceRects = new Rect[faceRects.length]; 1024 for (int i = 0; i < newFaceRects.length; i++) { 1025 newFaceRects[i] = new Rect( 1026 faceRects[i].left, 1027 faceRects[i].top, 1028 faceRects[i].right + faceRects[i].left, 1029 faceRects[i].bottom + faceRects[i].top); 1030 } 1031 1032 setBase(CaptureResult.STATISTICS_FACE_RECTANGLES, newFaceRects); 1033 return true; 1034 } 1035 1036 private <T> boolean setTonemapCurve(TonemapCurve tc) { 1037 if (tc == null) { 1038 return false; 1039 } 1040 1041 float[][] curve = new float[3][]; 1042 for (int i = TonemapCurve.CHANNEL_RED; i <= TonemapCurve.CHANNEL_BLUE; i++) { 1043 int pointCount = tc.getPointCount(i); 1044 curve[i] = new float[pointCount * TonemapCurve.POINT_SIZE]; 1045 tc.copyColorCurve(i, curve[i], 0); 1046 } 1047 setBase(CaptureRequest.TONEMAP_CURVE_RED, curve[0]); 1048 setBase(CaptureRequest.TONEMAP_CURVE_GREEN, curve[1]); 1049 setBase(CaptureRequest.TONEMAP_CURVE_BLUE, curve[2]); 1050 1051 return true; 1052 } 1053 1054 private long mMetadataPtr; // native CameraMetadata* 1055 1056 private native long nativeAllocate(); 1057 private native long nativeAllocateCopy(CameraMetadataNative other) 1058 throws NullPointerException; 1059 1060 private native synchronized void nativeWriteToParcel(Parcel dest); 1061 private native synchronized void nativeReadFromParcel(Parcel source); 1062 private native synchronized void nativeSwap(CameraMetadataNative other) 1063 throws NullPointerException; 1064 private native synchronized void nativeClose(); 1065 private native synchronized boolean nativeIsEmpty(); 1066 private native synchronized int nativeGetEntryCount(); 1067 1068 private native synchronized byte[] nativeReadValues(int tag); 1069 private native synchronized void nativeWriteValues(int tag, byte[] src); 1070 private native synchronized void nativeDump() throws IOException; // dump to ALOGD 1071 1072 private static native int nativeGetTagFromKey(String keyName) 1073 throws IllegalArgumentException; 1074 private static native int nativeGetTypeFromTag(int tag) 1075 throws IllegalArgumentException; 1076 private static native void nativeClassInit(); 1077 1078 /** 1079 * <p>Perform a 0-copy swap of the internal metadata with another object.</p> 1080 * 1081 * <p>Useful to convert a CameraMetadata into e.g. a CaptureRequest.</p> 1082 * 1083 * @param other Metadata to swap with 1084 * @throws NullPointerException if other was null 1085 * @hide 1086 */ 1087 public void swap(CameraMetadataNative other) { 1088 nativeSwap(other); 1089 } 1090 1091 /** 1092 * @hide 1093 */ 1094 public int getEntryCount() { 1095 return nativeGetEntryCount(); 1096 } 1097 1098 /** 1099 * Does this metadata contain at least 1 entry? 1100 * 1101 * @hide 1102 */ 1103 public boolean isEmpty() { 1104 return nativeIsEmpty(); 1105 } 1106 1107 /** 1108 * Convert a key string into the equivalent native tag. 1109 * 1110 * @throws IllegalArgumentException if the key was not recognized 1111 * @throws NullPointerException if the key was null 1112 * 1113 * @hide 1114 */ 1115 public static int getTag(String key) { 1116 return nativeGetTagFromKey(key); 1117 } 1118 1119 /** 1120 * Get the underlying native type for a tag. 1121 * 1122 * @param tag An integer tag, see e.g. {@link #getTag} 1123 * @return An int enum for the metadata type, see e.g. {@link #TYPE_BYTE} 1124 * 1125 * @hide 1126 */ 1127 public static int getNativeType(int tag) { 1128 return nativeGetTypeFromTag(tag); 1129 } 1130 1131 /** 1132 * <p>Updates the existing entry for tag with the new bytes pointed by src, erasing 1133 * the entry if src was null.</p> 1134 * 1135 * <p>An empty array can be passed in to update the entry to 0 elements.</p> 1136 * 1137 * @param tag An integer tag, see e.g. {@link #getTag} 1138 * @param src An array of bytes, or null to erase the entry 1139 * 1140 * @hide 1141 */ 1142 public void writeValues(int tag, byte[] src) { 1143 nativeWriteValues(tag, src); 1144 } 1145 1146 /** 1147 * <p>Returns a byte[] of data corresponding to this tag. Use a wrapped bytebuffer to unserialize 1148 * the data properly.</p> 1149 * 1150 * <p>An empty array can be returned to denote an existing entry with 0 elements.</p> 1151 * 1152 * @param tag An integer tag, see e.g. {@link #getTag} 1153 * 1154 * @return {@code null} if there were 0 entries for this tag, a byte[] otherwise. 1155 * @hide 1156 */ 1157 public byte[] readValues(int tag) { 1158 // TODO: Optimization. Native code returns a ByteBuffer instead. 1159 return nativeReadValues(tag); 1160 } 1161 1162 /** 1163 * Dumps the native metadata contents to logcat. 1164 * 1165 * <p>Visibility for testing/debugging only. The results will not 1166 * include any synthesized keys, as they are invisible to the native layer.</p> 1167 * 1168 * @hide 1169 */ 1170 public void dumpToLog() { 1171 try { 1172 nativeDump(); 1173 } catch (IOException e) { 1174 Log.wtf(TAG, "Dump logging failed", e); 1175 } 1176 } 1177 1178 @Override 1179 protected void finalize() throws Throwable { 1180 try { 1181 close(); 1182 } finally { 1183 super.finalize(); 1184 } 1185 } 1186 1187 /** 1188 * Get the marshaler compatible with the {@code key} and type {@code T}. 1189 * 1190 * @throws UnsupportedOperationException 1191 * if the native/managed type combination for {@code key} is not supported 1192 */ 1193 private static <T> Marshaler<T> getMarshalerForKey(Key<T> key) { 1194 return MarshalRegistry.getMarshaler(key.getTypeReference(), 1195 getNativeType(key.getTag())); 1196 } 1197 1198 @SuppressWarnings({ "unchecked", "rawtypes" }) 1199 private static void registerAllMarshalers() { 1200 if (VERBOSE) { 1201 Log.v(TAG, "Shall register metadata marshalers"); 1202 } 1203 1204 MarshalQueryable[] queryList = new MarshalQueryable[] { 1205 // marshalers for standard types 1206 new MarshalQueryablePrimitive(), 1207 new MarshalQueryableEnum(), 1208 new MarshalQueryableArray(), 1209 1210 // pseudo standard types, that expand/narrow the native type into a managed type 1211 new MarshalQueryableBoolean(), 1212 new MarshalQueryableNativeByteToInteger(), 1213 1214 // marshalers for custom types 1215 new MarshalQueryableRect(), 1216 new MarshalQueryableSize(), 1217 new MarshalQueryableSizeF(), 1218 new MarshalQueryableString(), 1219 new MarshalQueryableReprocessFormatsMap(), 1220 new MarshalQueryableRange(), 1221 new MarshalQueryablePair(), 1222 new MarshalQueryableMeteringRectangle(), 1223 new MarshalQueryableColorSpaceTransform(), 1224 new MarshalQueryableStreamConfiguration(), 1225 new MarshalQueryableStreamConfigurationDuration(), 1226 new MarshalQueryableRggbChannelVector(), 1227 new MarshalQueryableBlackLevelPattern(), 1228 new MarshalQueryableHighSpeedVideoConfiguration(), 1229 1230 // generic parcelable marshaler (MUST BE LAST since it has lowest priority) 1231 new MarshalQueryableParcelable(), 1232 }; 1233 1234 for (MarshalQueryable query : queryList) { 1235 MarshalRegistry.registerMarshalQueryable(query); 1236 } 1237 if (VERBOSE) { 1238 Log.v(TAG, "Registered metadata marshalers"); 1239 } 1240 } 1241 1242 /** Check if input arguments are all {@code null}. 1243 * 1244 * @param objs Input arguments for null check 1245 * @return {@code true} if input arguments are all {@code null}, otherwise {@code false} 1246 */ 1247 private static boolean areValuesAllNull(Object... objs) { 1248 for (Object o : objs) { 1249 if (o != null) return false; 1250 } 1251 return true; 1252 } 1253 1254 static { 1255 /* 1256 * We use a class initializer to allow the native code to cache some field offsets 1257 */ 1258 nativeClassInit(); 1259 registerAllMarshalers(); 1260 } 1261} 1262