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