CameraMetadataNative.java revision 85c4388de1fea3d45783f07895c2b113c4cc1ba5
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.CameraMetadata; 24import android.hardware.camera2.CaptureResult; 25import android.hardware.camera2.Face; 26import android.hardware.camera2.Rational; 27import android.os.Parcelable; 28import android.os.Parcel; 29import android.util.Log; 30 31import java.lang.reflect.Array; 32import java.nio.ByteBuffer; 33import java.nio.ByteOrder; 34import java.util.ArrayList; 35import java.util.HashMap; 36 37/** 38 * Implementation of camera metadata marshal/unmarshal across Binder to 39 * the camera service 40 */ 41public class CameraMetadataNative extends CameraMetadata implements Parcelable { 42 43 private static final String TAG = "CameraMetadataJV"; 44 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 45 // this should be in sync with HAL_PIXEL_FORMAT_BLOB defined in graphics.h 46 private static final int NATIVE_JPEG_FORMAT = 0x21; 47 48 public CameraMetadataNative() { 49 super(); 50 mMetadataPtr = nativeAllocate(); 51 if (mMetadataPtr == 0) { 52 throw new OutOfMemoryError("Failed to allocate native CameraMetadata"); 53 } 54 } 55 56 /** 57 * Copy constructor - clone metadata 58 */ 59 public CameraMetadataNative(CameraMetadataNative other) { 60 super(); 61 mMetadataPtr = nativeAllocateCopy(other); 62 if (mMetadataPtr == 0) { 63 throw new OutOfMemoryError("Failed to allocate native CameraMetadata"); 64 } 65 } 66 67 public static final Parcelable.Creator<CameraMetadataNative> CREATOR = 68 new Parcelable.Creator<CameraMetadataNative>() { 69 @Override 70 public CameraMetadataNative createFromParcel(Parcel in) { 71 CameraMetadataNative metadata = new CameraMetadataNative(); 72 metadata.readFromParcel(in); 73 return metadata; 74 } 75 76 @Override 77 public CameraMetadataNative[] newArray(int size) { 78 return new CameraMetadataNative[size]; 79 } 80 }; 81 82 @Override 83 public int describeContents() { 84 return 0; 85 } 86 87 @Override 88 public void writeToParcel(Parcel dest, int flags) { 89 nativeWriteToParcel(dest); 90 } 91 92 @SuppressWarnings("unchecked") 93 @Override 94 public <T> T get(Key<T> key) { 95 T value = getOverride(key); 96 if (value != null) { 97 return value; 98 } 99 100 return getBase(key); 101 } 102 103 public void readFromParcel(Parcel in) { 104 nativeReadFromParcel(in); 105 } 106 107 /** 108 * Set the global client-side vendor tag descriptor to allow use of vendor 109 * tags in camera applications. 110 * 111 * @return int A native status_t value corresponding to one of the 112 * {@link CameraBinderDecorator} integer constants. 113 * @see CameraBinderDecorator#throwOnError 114 * 115 * @hide 116 */ 117 public static native int nativeSetupGlobalVendorTagDescriptor(); 118 119 /** 120 * Set a camera metadata field to a value. The field definitions can be 121 * found in {@link CameraCharacteristics}, {@link CaptureResult}, and 122 * {@link CaptureRequest}. 123 * 124 * @param key The metadata field to write. 125 * @param value The value to set the field to, which must be of a matching 126 * type to the key. 127 */ 128 public <T> void set(Key<T> key, T value) { 129 if (setOverride(key, value)) { 130 return; 131 } 132 133 setBase(key, value); 134 } 135 136 // Keep up-to-date with camera_metadata.h 137 /** 138 * @hide 139 */ 140 public static final int TYPE_BYTE = 0; 141 /** 142 * @hide 143 */ 144 public static final int TYPE_INT32 = 1; 145 /** 146 * @hide 147 */ 148 public static final int TYPE_FLOAT = 2; 149 /** 150 * @hide 151 */ 152 public static final int TYPE_INT64 = 3; 153 /** 154 * @hide 155 */ 156 public static final int TYPE_DOUBLE = 4; 157 /** 158 * @hide 159 */ 160 public static final int TYPE_RATIONAL = 5; 161 /** 162 * @hide 163 */ 164 public static final int NUM_TYPES = 6; 165 166 private void close() { 167 // this sets mMetadataPtr to 0 168 nativeClose(); 169 mMetadataPtr = 0; // set it to 0 again to prevent eclipse from making this field final 170 } 171 172 private static int getTypeSize(int nativeType) { 173 switch(nativeType) { 174 case TYPE_BYTE: 175 return 1; 176 case TYPE_INT32: 177 case TYPE_FLOAT: 178 return 4; 179 case TYPE_INT64: 180 case TYPE_DOUBLE: 181 case TYPE_RATIONAL: 182 return 8; 183 } 184 185 throw new UnsupportedOperationException("Unknown type, can't get size " 186 + nativeType); 187 } 188 189 private static Class<?> getExpectedType(int nativeType) { 190 switch(nativeType) { 191 case TYPE_BYTE: 192 return Byte.TYPE; 193 case TYPE_INT32: 194 return Integer.TYPE; 195 case TYPE_FLOAT: 196 return Float.TYPE; 197 case TYPE_INT64: 198 return Long.TYPE; 199 case TYPE_DOUBLE: 200 return Double.TYPE; 201 case TYPE_RATIONAL: 202 return Rational.class; 203 } 204 205 throw new UnsupportedOperationException("Unknown type, can't map to Java type " 206 + nativeType); 207 } 208 209 @SuppressWarnings("unchecked") 210 private static <T> int packSingleNative(T value, ByteBuffer buffer, Class<T> type, 211 int nativeType, boolean sizeOnly) { 212 213 if (!sizeOnly) { 214 /** 215 * Rewrite types when the native type doesn't match the managed type 216 * - Boolean -> Byte 217 * - Integer -> Byte 218 */ 219 220 if (nativeType == TYPE_BYTE && type == Boolean.TYPE) { 221 // Since a boolean can't be cast to byte, and we don't want to use putBoolean 222 boolean asBool = (Boolean) value; 223 byte asByte = (byte) (asBool ? 1 : 0); 224 value = (T) (Byte) asByte; 225 } else if (nativeType == TYPE_BYTE && type == Integer.TYPE) { 226 int asInt = (Integer) value; 227 byte asByte = (byte) asInt; 228 value = (T) (Byte) asByte; 229 } else if (type != getExpectedType(nativeType)) { 230 throw new UnsupportedOperationException("Tried to pack a type of " + type + 231 " but we expected the type to be " + getExpectedType(nativeType)); 232 } 233 234 if (nativeType == TYPE_BYTE) { 235 buffer.put((Byte) value); 236 } else if (nativeType == TYPE_INT32) { 237 buffer.putInt((Integer) value); 238 } else if (nativeType == TYPE_FLOAT) { 239 buffer.putFloat((Float) value); 240 } else if (nativeType == TYPE_INT64) { 241 buffer.putLong((Long) value); 242 } else if (nativeType == TYPE_DOUBLE) { 243 buffer.putDouble((Double) value); 244 } else if (nativeType == TYPE_RATIONAL) { 245 Rational r = (Rational) value; 246 buffer.putInt(r.getNumerator()); 247 buffer.putInt(r.getDenominator()); 248 } 249 250 } 251 252 return getTypeSize(nativeType); 253 } 254 255 @SuppressWarnings({"unchecked", "rawtypes"}) 256 private static <T> int packSingle(T value, ByteBuffer buffer, Class<T> type, int nativeType, 257 boolean sizeOnly) { 258 259 int size = 0; 260 261 if (type.isPrimitive() || type == Rational.class) { 262 size = packSingleNative(value, buffer, type, nativeType, sizeOnly); 263 } else if (type.isEnum()) { 264 size = packEnum((Enum)value, buffer, (Class<Enum>)type, nativeType, sizeOnly); 265 } else if (type.isArray()) { 266 size = packArray(value, buffer, type, nativeType, sizeOnly); 267 } else { 268 size = packClass(value, buffer, type, nativeType, sizeOnly); 269 } 270 271 return size; 272 } 273 274 private static <T extends Enum<T>> int packEnum(T value, ByteBuffer buffer, Class<T> type, 275 int nativeType, boolean sizeOnly) { 276 277 // TODO: add support for enums with their own values. 278 return packSingleNative(getEnumValue(value), buffer, Integer.TYPE, nativeType, sizeOnly); 279 } 280 281 @SuppressWarnings("unchecked") 282 private static <T> int packClass(T value, ByteBuffer buffer, Class<T> type, int nativeType, 283 boolean sizeOnly) { 284 285 MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType); 286 if (marshaler == null) { 287 throw new IllegalArgumentException(String.format("Unknown Key type: %s", type)); 288 } 289 290 return marshaler.marshal(value, buffer, nativeType, sizeOnly); 291 } 292 293 private static <T> int packArray(T value, ByteBuffer buffer, Class<T> type, int nativeType, 294 boolean sizeOnly) { 295 296 int size = 0; 297 int arrayLength = Array.getLength(value); 298 299 @SuppressWarnings("unchecked") 300 Class<Object> componentType = (Class<Object>)type.getComponentType(); 301 302 for (int i = 0; i < arrayLength; ++i) { 303 size += packSingle(Array.get(value, i), buffer, componentType, nativeType, sizeOnly); 304 } 305 306 return size; 307 } 308 309 @SuppressWarnings("unchecked") 310 private static <T> T unpackSingleNative(ByteBuffer buffer, Class<T> type, int nativeType) { 311 312 T val; 313 314 if (nativeType == TYPE_BYTE) { 315 val = (T) (Byte) buffer.get(); 316 } else if (nativeType == TYPE_INT32) { 317 val = (T) (Integer) buffer.getInt(); 318 } else if (nativeType == TYPE_FLOAT) { 319 val = (T) (Float) buffer.getFloat(); 320 } else if (nativeType == TYPE_INT64) { 321 val = (T) (Long) buffer.getLong(); 322 } else if (nativeType == TYPE_DOUBLE) { 323 val = (T) (Double) buffer.getDouble(); 324 } else if (nativeType == TYPE_RATIONAL) { 325 val = (T) new Rational(buffer.getInt(), buffer.getInt()); 326 } else { 327 throw new UnsupportedOperationException("Unknown type, can't unpack a native type " 328 + nativeType); 329 } 330 331 /** 332 * Rewrite types when the native type doesn't match the managed type 333 * - Byte -> Boolean 334 * - Byte -> Integer 335 */ 336 337 if (nativeType == TYPE_BYTE && type == Boolean.TYPE) { 338 // Since a boolean can't be cast to byte, and we don't want to use getBoolean 339 byte asByte = (Byte) val; 340 boolean asBool = asByte != 0; 341 val = (T) (Boolean) asBool; 342 } else if (nativeType == TYPE_BYTE && type == Integer.TYPE) { 343 byte asByte = (Byte) val; 344 int asInt = asByte; 345 val = (T) (Integer) asInt; 346 } else if (type != getExpectedType(nativeType)) { 347 throw new UnsupportedOperationException("Tried to unpack a type of " + type + 348 " but we expected the type to be " + getExpectedType(nativeType)); 349 } 350 351 return val; 352 } 353 354 @SuppressWarnings({"unchecked", "rawtypes"}) 355 private static <T> T unpackSingle(ByteBuffer buffer, Class<T> type, int nativeType) { 356 357 if (type.isPrimitive() || type == Rational.class) { 358 return unpackSingleNative(buffer, type, nativeType); 359 } 360 361 if (type.isEnum()) { 362 return (T) unpackEnum(buffer, (Class<Enum>)type, nativeType); 363 } 364 365 if (type.isArray()) { 366 return unpackArray(buffer, type, nativeType); 367 } 368 369 T instance = unpackClass(buffer, type, nativeType); 370 371 return instance; 372 } 373 374 private static <T extends Enum<T>> T unpackEnum(ByteBuffer buffer, Class<T> type, 375 int nativeType) { 376 int ordinal = unpackSingleNative(buffer, Integer.TYPE, nativeType); 377 return getEnumFromValue(type, ordinal); 378 } 379 380 private static <T> T unpackClass(ByteBuffer buffer, Class<T> type, int nativeType) { 381 382 MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType); 383 if (marshaler == null) { 384 throw new IllegalArgumentException("Unknown class type: " + type); 385 } 386 387 return marshaler.unmarshal(buffer, nativeType); 388 } 389 390 @SuppressWarnings("unchecked") 391 private static <T> T unpackArray(ByteBuffer buffer, Class<T> type, int nativeType) { 392 393 Class<?> componentType = type.getComponentType(); 394 Object array; 395 396 int elementSize = getTypeSize(nativeType); 397 398 MetadataMarshalClass<?> marshaler = getMarshaler(componentType, nativeType); 399 if (marshaler != null) { 400 elementSize = marshaler.getNativeSize(nativeType); 401 } 402 403 if (elementSize != MetadataMarshalClass.NATIVE_SIZE_DYNAMIC) { 404 int remaining = buffer.remaining(); 405 int arraySize = remaining / elementSize; 406 407 if (VERBOSE) { 408 Log.v(TAG, 409 String.format( 410 "Attempting to unpack array (count = %d, element size = %d, bytes " + 411 "remaining = %d) for type %s", 412 arraySize, elementSize, remaining, type)); 413 } 414 415 array = Array.newInstance(componentType, arraySize); 416 for (int i = 0; i < arraySize; ++i) { 417 Object elem = unpackSingle(buffer, componentType, nativeType); 418 Array.set(array, i, elem); 419 } 420 } else { 421 // Dynamic size, use an array list. 422 ArrayList<Object> arrayList = new ArrayList<Object>(); 423 424 int primitiveSize = getTypeSize(nativeType); 425 while (buffer.remaining() >= primitiveSize) { 426 Object elem = unpackSingle(buffer, componentType, nativeType); 427 arrayList.add(elem); 428 } 429 430 array = arrayList.toArray((T[]) Array.newInstance(componentType, 0)); 431 } 432 433 if (buffer.remaining() != 0) { 434 Log.e(TAG, "Trailing bytes (" + buffer.remaining() + ") left over after unpacking " 435 + type); 436 } 437 438 return (T) array; 439 } 440 441 private <T> T getBase(Key<T> key) { 442 int tag = key.getTag(); 443 byte[] values = readValues(tag); 444 if (values == null) { 445 return null; 446 } 447 448 int nativeType = getNativeType(tag); 449 450 ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder()); 451 return unpackSingle(buffer, key.getType(), nativeType); 452 } 453 454 // Need overwrite some metadata that has different definitions between native 455 // and managed sides. 456 @SuppressWarnings("unchecked") 457 private <T> T getOverride(Key<T> key) { 458 if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_FORMATS)) { 459 return (T) getAvailableFormats(); 460 } else if (key.equals(CaptureResult.STATISTICS_FACES)) { 461 return (T) getFaces(); 462 } else if (key.equals(CaptureResult.STATISTICS_FACE_RECTANGLES)) { 463 return (T) getFaceRectangles(); 464 } 465 466 // For other keys, get() falls back to getBase() 467 return null; 468 } 469 470 private int[] getAvailableFormats() { 471 int[] availableFormats = getBase(CameraCharacteristics.SCALER_AVAILABLE_FORMATS); 472 if (availableFormats != null) { 473 for (int i = 0; i < availableFormats.length; i++) { 474 // JPEG has different value between native and managed side, need override. 475 if (availableFormats[i] == NATIVE_JPEG_FORMAT) { 476 availableFormats[i] = ImageFormat.JPEG; 477 } 478 } 479 } 480 481 return availableFormats; 482 } 483 484 private Face[] getFaces() { 485 final int FACE_LANDMARK_SIZE = 6; 486 487 Integer faceDetectMode = get(CaptureResult.STATISTICS_FACE_DETECT_MODE); 488 if (faceDetectMode == null) { 489 Log.w(TAG, "Face detect mode metadata is null, assuming the mode is SIMPLE"); 490 faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE; 491 } else { 492 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_OFF) { 493 return new Face[0]; 494 } 495 if (faceDetectMode != CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE && 496 faceDetectMode != CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) { 497 Log.w(TAG, "Unknown face detect mode: " + faceDetectMode); 498 return new Face[0]; 499 } 500 } 501 502 // Face scores and rectangles are required by SIMPLE and FULL mode. 503 byte[] faceScores = get(CaptureResult.STATISTICS_FACE_SCORES); 504 Rect[] faceRectangles = get(CaptureResult.STATISTICS_FACE_RECTANGLES); 505 if (faceScores == null || faceRectangles == null) { 506 Log.w(TAG, "Expect face scores and rectangles to be non-null"); 507 return new Face[0]; 508 } else if (faceScores.length != faceRectangles.length) { 509 Log.w(TAG, String.format("Face score size(%d) doesn match face rectangle size(%d)!", 510 faceScores.length, faceRectangles.length)); 511 } 512 513 // To be safe, make number of faces is the minimal of all face info metadata length. 514 int numFaces = Math.min(faceScores.length, faceRectangles.length); 515 // Face id and landmarks are only required by FULL mode. 516 int[] faceIds = get(CaptureResult.STATISTICS_FACE_IDS); 517 int[] faceLandmarks = get(CaptureResult.STATISTICS_FACE_LANDMARKS); 518 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) { 519 if (faceIds == null || faceLandmarks == null) { 520 Log.w(TAG, "Expect face ids and landmarks to be non-null for FULL mode," + 521 "fallback to SIMPLE mode"); 522 faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE; 523 } else { 524 if (faceIds.length != numFaces || 525 faceLandmarks.length != numFaces * FACE_LANDMARK_SIZE) { 526 Log.w(TAG, String.format("Face id size(%d), or face landmark size(%d) don't" + 527 "match face number(%d)!", 528 faceIds.length, faceLandmarks.length * FACE_LANDMARK_SIZE, numFaces)); 529 } 530 // To be safe, make number of faces is the minimal of all face info metadata length. 531 numFaces = Math.min(numFaces, faceIds.length); 532 numFaces = Math.min(numFaces, faceLandmarks.length / FACE_LANDMARK_SIZE); 533 } 534 } 535 536 ArrayList<Face> faceList = new ArrayList<Face>(); 537 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE) { 538 for (int i = 0; i < numFaces; i++) { 539 if (faceScores[i] <= Face.SCORE_MAX && 540 faceScores[i] >= Face.SCORE_MIN) { 541 faceList.add(new Face(faceRectangles[i], faceScores[i])); 542 } 543 } 544 } else { 545 // CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL 546 for (int i = 0; i < numFaces; i++) { 547 if (faceScores[i] <= Face.SCORE_MAX && 548 faceScores[i] >= Face.SCORE_MIN && 549 faceIds[i] >= 0) { 550 Point leftEye = new Point(faceLandmarks[i*6], faceLandmarks[i*6+1]); 551 Point rightEye = new Point(faceLandmarks[i*6+2], faceLandmarks[i*6+3]); 552 Point mouth = new Point(faceLandmarks[i*6+4], faceLandmarks[i*6+5]); 553 Face face = new Face(faceRectangles[i], faceScores[i], faceIds[i], 554 leftEye, rightEye, mouth); 555 faceList.add(face); 556 } 557 } 558 } 559 Face[] faces = new Face[faceList.size()]; 560 faceList.toArray(faces); 561 return faces; 562 } 563 564 // Face rectangles are defined as (left, top, right, bottom) instead of 565 // (left, top, width, height) at the native level, so the normal Rect 566 // conversion that does (l, t, w, h) -> (l, t, r, b) is unnecessary. Undo 567 // that conversion here for just the faces. 568 private Rect[] getFaceRectangles() { 569 Rect[] faceRectangles = getBase(CaptureResult.STATISTICS_FACE_RECTANGLES); 570 if (faceRectangles == null) return null; 571 572 Rect[] fixedFaceRectangles = new Rect[faceRectangles.length]; 573 for (int i = 0; i < faceRectangles.length; i++) { 574 fixedFaceRectangles[i] = new Rect( 575 faceRectangles[i].left, 576 faceRectangles[i].top, 577 faceRectangles[i].right - faceRectangles[i].left, 578 faceRectangles[i].bottom - faceRectangles[i].top); 579 } 580 return fixedFaceRectangles; 581 } 582 583 private <T> void setBase(Key<T> key, T value) { 584 int tag = key.getTag(); 585 586 if (value == null) { 587 writeValues(tag, null); 588 return; 589 } 590 591 int nativeType = getNativeType(tag); 592 593 int size = packSingle(value, null, key.getType(), nativeType, /* sizeOnly */true); 594 595 // TODO: Optimization. Cache the byte[] and reuse if the size is big enough. 596 byte[] values = new byte[size]; 597 598 ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder()); 599 packSingle(value, buffer, key.getType(), nativeType, /*sizeOnly*/false); 600 601 writeValues(tag, values); 602 } 603 604 // Set the camera metadata override. 605 private <T> boolean setOverride(Key<T> key, T value) { 606 if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_FORMATS)) { 607 return setAvailableFormats((int[]) value); 608 } else if (key.equals(CaptureResult.STATISTICS_FACE_RECTANGLES)) { 609 return setFaceRectangles((Rect[]) value); 610 } 611 612 // For other keys, set() falls back to setBase(). 613 return false; 614 } 615 616 private boolean setAvailableFormats(int[] value) { 617 int[] availableFormat = value; 618 if (value == null) { 619 // Let setBase() to handle the null value case. 620 return false; 621 } 622 623 int[] newValues = new int[availableFormat.length]; 624 for (int i = 0; i < availableFormat.length; i++) { 625 newValues[i] = availableFormat[i]; 626 if (availableFormat[i] == ImageFormat.JPEG) { 627 newValues[i] = NATIVE_JPEG_FORMAT; 628 } 629 } 630 631 setBase(CameraCharacteristics.SCALER_AVAILABLE_FORMATS, newValues); 632 return true; 633 } 634 635 /** 636 * Convert Face Rectangles from managed side to native side as they have different definitions. 637 * <p> 638 * Managed side face rectangles are defined as: left, top, width, height. 639 * Native side face rectangles are defined as: left, top, right, bottom. 640 * The input face rectangle need to be converted to native side definition when set is called. 641 * </p> 642 * 643 * @param faceRects Input face rectangles. 644 * @return true if face rectangles can be set successfully. Otherwise, Let the caller 645 * (setBase) to handle it appropriately. 646 */ 647 private boolean setFaceRectangles(Rect[] faceRects) { 648 if (faceRects == null) { 649 return false; 650 } 651 652 Rect[] newFaceRects = new Rect[faceRects.length]; 653 for (int i = 0; i < newFaceRects.length; i++) { 654 newFaceRects[i] = new Rect( 655 faceRects[i].left, 656 faceRects[i].top, 657 faceRects[i].right + faceRects[i].left, 658 faceRects[i].bottom + faceRects[i].top); 659 } 660 661 setBase(CaptureResult.STATISTICS_FACE_RECTANGLES, newFaceRects); 662 return true; 663 } 664 665 private long mMetadataPtr; // native CameraMetadata* 666 667 private native long nativeAllocate(); 668 private native long nativeAllocateCopy(CameraMetadataNative other) 669 throws NullPointerException; 670 671 private native synchronized void nativeWriteToParcel(Parcel dest); 672 private native synchronized void nativeReadFromParcel(Parcel source); 673 private native synchronized void nativeSwap(CameraMetadataNative other) 674 throws NullPointerException; 675 private native synchronized void nativeClose(); 676 private native synchronized boolean nativeIsEmpty(); 677 private native synchronized int nativeGetEntryCount(); 678 679 private native synchronized byte[] nativeReadValues(int tag); 680 private native synchronized void nativeWriteValues(int tag, byte[] src); 681 682 private static native int nativeGetTagFromKey(String keyName) 683 throws IllegalArgumentException; 684 private static native int nativeGetTypeFromTag(int tag) 685 throws IllegalArgumentException; 686 private static native void nativeClassInit(); 687 688 /** 689 * <p>Perform a 0-copy swap of the internal metadata with another object.</p> 690 * 691 * <p>Useful to convert a CameraMetadata into e.g. a CaptureRequest.</p> 692 * 693 * @param other Metadata to swap with 694 * @throws NullPointerException if other was null 695 * @hide 696 */ 697 public void swap(CameraMetadataNative other) { 698 nativeSwap(other); 699 } 700 701 /** 702 * @hide 703 */ 704 public int getEntryCount() { 705 return nativeGetEntryCount(); 706 } 707 708 /** 709 * Does this metadata contain at least 1 entry? 710 * 711 * @hide 712 */ 713 public boolean isEmpty() { 714 return nativeIsEmpty(); 715 } 716 717 /** 718 * Convert a key string into the equivalent native tag. 719 * 720 * @throws IllegalArgumentException if the key was not recognized 721 * @throws NullPointerException if the key was null 722 * 723 * @hide 724 */ 725 public static int getTag(String key) { 726 return nativeGetTagFromKey(key); 727 } 728 729 /** 730 * Get the underlying native type for a tag. 731 * 732 * @param tag An integer tag, see e.g. {@link #getTag} 733 * @return An int enum for the metadata type, see e.g. {@link #TYPE_BYTE} 734 * 735 * @hide 736 */ 737 public static int getNativeType(int tag) { 738 return nativeGetTypeFromTag(tag); 739 } 740 741 /** 742 * <p>Updates the existing entry for tag with the new bytes pointed by src, erasing 743 * the entry if src was null.</p> 744 * 745 * <p>An empty array can be passed in to update the entry to 0 elements.</p> 746 * 747 * @param tag An integer tag, see e.g. {@link #getTag} 748 * @param src An array of bytes, or null to erase the entry 749 * 750 * @hide 751 */ 752 public void writeValues(int tag, byte[] src) { 753 nativeWriteValues(tag, src); 754 } 755 756 /** 757 * <p>Returns a byte[] of data corresponding to this tag. Use a wrapped bytebuffer to unserialize 758 * the data properly.</p> 759 * 760 * <p>An empty array can be returned to denote an existing entry with 0 elements.</p> 761 * 762 * @param tag An integer tag, see e.g. {@link #getTag} 763 * 764 * @return {@code null} if there were 0 entries for this tag, a byte[] otherwise. 765 * @hide 766 */ 767 public byte[] readValues(int tag) { 768 // TODO: Optimization. Native code returns a ByteBuffer instead. 769 return nativeReadValues(tag); 770 } 771 772 @Override 773 protected void finalize() throws Throwable { 774 try { 775 close(); 776 } finally { 777 super.finalize(); 778 } 779 } 780 781 private static final HashMap<Class<? extends Enum>, int[]> sEnumValues = 782 new HashMap<Class<? extends Enum>, int[]>(); 783 /** 784 * Register a non-sequential set of values to be used with the pack/unpack functions. 785 * This enables get/set to correctly marshal the enum into a value that is C-compatible. 786 * 787 * @param enumType The class for an enum 788 * @param values A list of values mapping to the ordinals of the enum 789 * 790 * @hide 791 */ 792 public static <T extends Enum<T>> void registerEnumValues(Class<T> enumType, int[] values) { 793 if (enumType.getEnumConstants().length != values.length) { 794 throw new IllegalArgumentException( 795 "Expected values array to be the same size as the enumTypes values " 796 + values.length + " for type " + enumType); 797 } 798 if (VERBOSE) { 799 Log.v(TAG, "Registered enum values for type " + enumType + " values"); 800 } 801 802 sEnumValues.put(enumType, values); 803 } 804 805 /** 806 * Get the numeric value from an enum. This is usually the same as the ordinal value for 807 * enums that have fully sequential values, although for C-style enums the range of values 808 * may not map 1:1. 809 * 810 * @param enumValue Enum instance 811 * @return Int guaranteed to be ABI-compatible with the C enum equivalent 812 */ 813 private static <T extends Enum<T>> int getEnumValue(T enumValue) { 814 int[] values; 815 values = sEnumValues.get(enumValue.getClass()); 816 817 int ordinal = enumValue.ordinal(); 818 if (values != null) { 819 return values[ordinal]; 820 } 821 822 return ordinal; 823 } 824 825 /** 826 * Finds the enum corresponding to it's numeric value. Opposite of {@link #getEnumValue} method. 827 * 828 * @param enumType Class of the enum we want to find 829 * @param value The numeric value of the enum 830 * @return An instance of the enum 831 */ 832 private static <T extends Enum<T>> T getEnumFromValue(Class<T> enumType, int value) { 833 int ordinal; 834 835 int[] registeredValues = sEnumValues.get(enumType); 836 if (registeredValues != null) { 837 ordinal = -1; 838 839 for (int i = 0; i < registeredValues.length; ++i) { 840 if (registeredValues[i] == value) { 841 ordinal = i; 842 break; 843 } 844 } 845 } else { 846 ordinal = value; 847 } 848 849 T[] values = enumType.getEnumConstants(); 850 851 if (ordinal < 0 || ordinal >= values.length) { 852 throw new IllegalArgumentException( 853 String.format( 854 "Argument 'value' (%d) was not a valid enum value for type %s " 855 + "(registered? %b)", 856 value, 857 enumType, (registeredValues != null))); 858 } 859 860 return values[ordinal]; 861 } 862 863 static HashMap<Class<?>, MetadataMarshalClass<?>> sMarshalerMap = new 864 HashMap<Class<?>, MetadataMarshalClass<?>>(); 865 866 private static <T> void registerMarshaler(MetadataMarshalClass<T> marshaler) { 867 sMarshalerMap.put(marshaler.getMarshalingClass(), marshaler); 868 } 869 870 @SuppressWarnings("unchecked") 871 private static <T> MetadataMarshalClass<T> getMarshaler(Class<T> type, int nativeType) { 872 MetadataMarshalClass<T> marshaler = (MetadataMarshalClass<T>) sMarshalerMap.get(type); 873 874 if (marshaler != null && !marshaler.isNativeTypeSupported(nativeType)) { 875 throw new UnsupportedOperationException("Unsupported type " + nativeType + 876 " to be marshalled to/from a " + type); 877 } 878 879 return marshaler; 880 } 881 882 /** 883 * We use a class initializer to allow the native code to cache some field offsets 884 */ 885 static { 886 nativeClassInit(); 887 888 if (VERBOSE) { 889 Log.v(TAG, "Shall register metadata marshalers"); 890 } 891 892 // load built-in marshallers 893 registerMarshaler(new MetadataMarshalRect()); 894 registerMarshaler(new MetadataMarshalSize()); 895 registerMarshaler(new MetadataMarshalString()); 896 897 if (VERBOSE) { 898 Log.v(TAG, "Registered metadata marshalers"); 899 } 900 } 901 902} 903