CameraMetadataNative.java revision 51ca8d6bc031313e5040c716cc207c8f62a68891
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.hardware.camera2.CameraMetadata; 20import android.hardware.camera2.Rational; 21import android.os.Parcelable; 22import android.os.Parcel; 23import android.util.Log; 24 25import java.lang.reflect.Array; 26import java.nio.ByteBuffer; 27import java.nio.ByteOrder; 28import java.util.ArrayList; 29import java.util.HashMap; 30 31/** 32 * Implementation of camera metadata marshal/unmarshal across Binder to 33 * the camera service 34 */ 35public class CameraMetadataNative extends CameraMetadata implements Parcelable { 36 37 private static final String TAG = "CameraMetadataJV"; 38 private final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 39 40 public CameraMetadataNative() { 41 super(); 42 mMetadataPtr = nativeAllocate(); 43 if (mMetadataPtr == 0) { 44 throw new OutOfMemoryError("Failed to allocate native CameraMetadata"); 45 } 46 } 47 48 /** 49 * Copy constructor - clone metadata 50 */ 51 public CameraMetadataNative(CameraMetadataNative other) { 52 super(); 53 mMetadataPtr = nativeAllocateCopy(other); 54 if (mMetadataPtr == 0) { 55 throw new OutOfMemoryError("Failed to allocate native CameraMetadata"); 56 } 57 } 58 59 public static final Parcelable.Creator<CameraMetadataNative> CREATOR = 60 new Parcelable.Creator<CameraMetadataNative>() { 61 @Override 62 public CameraMetadataNative createFromParcel(Parcel in) { 63 CameraMetadataNative metadata = new CameraMetadataNative(); 64 metadata.readFromParcel(in); 65 return metadata; 66 } 67 68 @Override 69 public CameraMetadataNative[] newArray(int size) { 70 return new CameraMetadataNative[size]; 71 } 72 }; 73 74 @Override 75 public int describeContents() { 76 return 0; 77 } 78 79 @Override 80 public void writeToParcel(Parcel dest, int flags) { 81 nativeWriteToParcel(dest); 82 } 83 84 @SuppressWarnings("unchecked") 85 @Override 86 public <T> T get(Key<T> key) { 87 int tag = key.getTag(); 88 byte[] values = readValues(tag); 89 if (values == null) { 90 return null; 91 } 92 93 int nativeType = getNativeType(tag); 94 95 ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder()); 96 return unpackSingle(buffer, key.getType(), nativeType); 97 } 98 99 public void readFromParcel(Parcel in) { 100 nativeReadFromParcel(in); 101 } 102 103 /** 104 * Set a camera metadata field to a value. The field definitions can be 105 * found in {@link CameraCharacteristics}, {@link CaptureResult}, and 106 * {@link CaptureRequest}. 107 * 108 * @param key The metadata field to write. 109 * @param value The value to set the field to, which must be of a matching 110 * type to the key. 111 */ 112 public <T> void set(Key<T> key, T value) { 113 int tag = key.getTag(); 114 115 if (value == null) { 116 writeValues(tag, null); 117 return; 118 } 119 120 int nativeType = getNativeType(tag); 121 122 int size = packSingle(value, null, key.getType(), nativeType, /* sizeOnly */true); 123 124 // TODO: Optimization. Cache the byte[] and reuse if the size is big enough. 125 byte[] values = new byte[size]; 126 127 ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder()); 128 packSingle(value, buffer, key.getType(), nativeType, /*sizeOnly*/false); 129 130 writeValues(tag, values); 131 } 132 133 // Keep up-to-date with camera_metadata.h 134 /** 135 * @hide 136 */ 137 public static final int TYPE_BYTE = 0; 138 /** 139 * @hide 140 */ 141 public static final int TYPE_INT32 = 1; 142 /** 143 * @hide 144 */ 145 public static final int TYPE_FLOAT = 2; 146 /** 147 * @hide 148 */ 149 public static final int TYPE_INT64 = 3; 150 /** 151 * @hide 152 */ 153 public static final int TYPE_DOUBLE = 4; 154 /** 155 * @hide 156 */ 157 public static final int TYPE_RATIONAL = 5; 158 /** 159 * @hide 160 */ 161 public static final int NUM_TYPES = 6; 162 163 private void close() { 164 // this sets mMetadataPtr to 0 165 nativeClose(); 166 mMetadataPtr = 0; // set it to 0 again to prevent eclipse from making this field final 167 } 168 169 private static int getTypeSize(int nativeType) { 170 switch(nativeType) { 171 case TYPE_BYTE: 172 return 1; 173 case TYPE_INT32: 174 case TYPE_FLOAT: 175 return 4; 176 case TYPE_INT64: 177 case TYPE_DOUBLE: 178 case TYPE_RATIONAL: 179 return 8; 180 } 181 182 throw new UnsupportedOperationException("Unknown type, can't get size " 183 + nativeType); 184 } 185 186 private static Class<?> getExpectedType(int nativeType) { 187 switch(nativeType) { 188 case TYPE_BYTE: 189 return Byte.TYPE; 190 case TYPE_INT32: 191 return Integer.TYPE; 192 case TYPE_FLOAT: 193 return Float.TYPE; 194 case TYPE_INT64: 195 return Long.TYPE; 196 case TYPE_DOUBLE: 197 return Double.TYPE; 198 case TYPE_RATIONAL: 199 return Rational.class; 200 } 201 202 throw new UnsupportedOperationException("Unknown type, can't map to Java type " 203 + nativeType); 204 } 205 206 @SuppressWarnings("unchecked") 207 private static <T> int packSingleNative(T value, ByteBuffer buffer, Class<T> type, 208 int nativeType, boolean sizeOnly) { 209 210 if (!sizeOnly) { 211 /** 212 * Rewrite types when the native type doesn't match the managed type 213 * - Boolean -> Byte 214 * - Integer -> Byte 215 */ 216 217 if (nativeType == TYPE_BYTE && type == Boolean.TYPE) { 218 // Since a boolean can't be cast to byte, and we don't want to use putBoolean 219 boolean asBool = (Boolean) value; 220 byte asByte = (byte) (asBool ? 1 : 0); 221 value = (T) (Byte) asByte; 222 } else if (nativeType == TYPE_BYTE && type == Integer.TYPE) { 223 int asInt = (Integer) value; 224 byte asByte = (byte) asInt; 225 value = (T) (Byte) asByte; 226 } else if (type != getExpectedType(nativeType)) { 227 throw new UnsupportedOperationException("Tried to pack a type of " + type + 228 " but we expected the type to be " + getExpectedType(nativeType)); 229 } 230 231 if (nativeType == TYPE_BYTE) { 232 buffer.put((Byte) value); 233 } else if (nativeType == TYPE_INT32) { 234 buffer.putInt((Integer) value); 235 } else if (nativeType == TYPE_FLOAT) { 236 buffer.putFloat((Float) value); 237 } else if (nativeType == TYPE_INT64) { 238 buffer.putLong((Long) value); 239 } else if (nativeType == TYPE_DOUBLE) { 240 buffer.putDouble((Double) value); 241 } else if (nativeType == TYPE_RATIONAL) { 242 Rational r = (Rational) value; 243 buffer.putInt(r.getNumerator()); 244 buffer.putInt(r.getDenominator()); 245 } 246 247 } 248 249 return getTypeSize(nativeType); 250 } 251 252 @SuppressWarnings({"unchecked", "rawtypes"}) 253 private static <T> int packSingle(T value, ByteBuffer buffer, Class<T> type, int nativeType, 254 boolean sizeOnly) { 255 256 int size = 0; 257 258 if (type.isPrimitive() || type == Rational.class) { 259 size = packSingleNative(value, buffer, type, nativeType, sizeOnly); 260 } else if (type.isEnum()) { 261 size = packEnum((Enum)value, buffer, (Class<Enum>)type, nativeType, sizeOnly); 262 } else if (type.isArray()) { 263 size = packArray(value, buffer, type, nativeType, sizeOnly); 264 } else { 265 size = packClass(value, buffer, type, nativeType, sizeOnly); 266 } 267 268 return size; 269 } 270 271 private static <T extends Enum<T>> int packEnum(T value, ByteBuffer buffer, Class<T> type, 272 int nativeType, boolean sizeOnly) { 273 274 // TODO: add support for enums with their own values. 275 return packSingleNative(getEnumValue(value), buffer, Integer.TYPE, nativeType, sizeOnly); 276 } 277 278 @SuppressWarnings("unchecked") 279 private static <T> int packClass(T value, ByteBuffer buffer, Class<T> type, int nativeType, 280 boolean sizeOnly) { 281 282 MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType); 283 if (marshaler == null) { 284 throw new IllegalArgumentException(String.format("Unknown Key type: %s", type)); 285 } 286 287 return marshaler.marshal(value, buffer, nativeType, sizeOnly); 288 } 289 290 private static <T> int packArray(T value, ByteBuffer buffer, Class<T> type, int nativeType, 291 boolean sizeOnly) { 292 293 int size = 0; 294 int arrayLength = Array.getLength(value); 295 296 @SuppressWarnings("unchecked") 297 Class<Object> componentType = (Class<Object>)type.getComponentType(); 298 299 for (int i = 0; i < arrayLength; ++i) { 300 size += packSingle(Array.get(value, i), buffer, componentType, nativeType, sizeOnly); 301 } 302 303 return size; 304 } 305 306 @SuppressWarnings("unchecked") 307 private static <T> T unpackSingleNative(ByteBuffer buffer, Class<T> type, int nativeType) { 308 309 T val; 310 311 if (nativeType == TYPE_BYTE) { 312 val = (T) (Byte) buffer.get(); 313 } else if (nativeType == TYPE_INT32) { 314 val = (T) (Integer) buffer.getInt(); 315 } else if (nativeType == TYPE_FLOAT) { 316 val = (T) (Float) buffer.getFloat(); 317 } else if (nativeType == TYPE_INT64) { 318 val = (T) (Long) buffer.getLong(); 319 } else if (nativeType == TYPE_DOUBLE) { 320 val = (T) (Double) buffer.getDouble(); 321 } else if (nativeType == TYPE_RATIONAL) { 322 val = (T) new Rational(buffer.getInt(), buffer.getInt()); 323 } else { 324 throw new UnsupportedOperationException("Unknown type, can't unpack a native type " 325 + nativeType); 326 } 327 328 /** 329 * Rewrite types when the native type doesn't match the managed type 330 * - Byte -> Boolean 331 * - Byte -> Integer 332 */ 333 334 if (nativeType == TYPE_BYTE && type == Boolean.TYPE) { 335 // Since a boolean can't be cast to byte, and we don't want to use getBoolean 336 byte asByte = (Byte) val; 337 boolean asBool = asByte != 0; 338 val = (T) (Boolean) asBool; 339 } else if (nativeType == TYPE_BYTE && type == Integer.TYPE) { 340 byte asByte = (Byte) val; 341 int asInt = asByte; 342 val = (T) (Integer) asInt; 343 } else if (type != getExpectedType(nativeType)) { 344 throw new UnsupportedOperationException("Tried to unpack a type of " + type + 345 " but we expected the type to be " + getExpectedType(nativeType)); 346 } 347 348 return val; 349 } 350 351 @SuppressWarnings({"unchecked", "rawtypes"}) 352 private static <T> T unpackSingle(ByteBuffer buffer, Class<T> type, int nativeType) { 353 354 if (type.isPrimitive() || type == Rational.class) { 355 return unpackSingleNative(buffer, type, nativeType); 356 } 357 358 if (type.isEnum()) { 359 return (T) unpackEnum(buffer, (Class<Enum>)type, nativeType); 360 } 361 362 if (type.isArray()) { 363 return unpackArray(buffer, type, nativeType); 364 } 365 366 T instance = unpackClass(buffer, type, nativeType); 367 368 return instance; 369 } 370 371 private static <T extends Enum<T>> T unpackEnum(ByteBuffer buffer, Class<T> type, 372 int nativeType) { 373 int ordinal = unpackSingleNative(buffer, Integer.TYPE, nativeType); 374 return getEnumFromValue(type, ordinal); 375 } 376 377 private static <T> T unpackClass(ByteBuffer buffer, Class<T> type, int nativeType) { 378 379 MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType); 380 if (marshaler == null) { 381 throw new IllegalArgumentException("Unknown class type: " + type); 382 } 383 384 return marshaler.unmarshal(buffer, nativeType); 385 } 386 387 @SuppressWarnings("unchecked") 388 private static <T> T unpackArray(ByteBuffer buffer, Class<T> type, int nativeType) { 389 390 Class<?> componentType = type.getComponentType(); 391 Object array; 392 393 int elementSize = getTypeSize(nativeType); 394 395 MetadataMarshalClass<?> marshaler = getMarshaler(componentType, nativeType); 396 if (marshaler != null) { 397 elementSize = marshaler.getNativeSize(nativeType); 398 } 399 400 if (elementSize != MetadataMarshalClass.NATIVE_SIZE_DYNAMIC) { 401 int remaining = buffer.remaining(); 402 int arraySize = remaining / elementSize; 403 404 if (VERBOSE) { 405 Log.v(TAG, 406 String.format( 407 "Attempting to unpack array (count = %d, element size = %d, bytes " + 408 "remaining = %d) for type %s", 409 arraySize, elementSize, remaining, type)); 410 } 411 412 array = Array.newInstance(componentType, arraySize); 413 for (int i = 0; i < arraySize; ++i) { 414 Object elem = unpackSingle(buffer, componentType, nativeType); 415 Array.set(array, i, elem); 416 } 417 } else { 418 // Dynamic size, use an array list. 419 ArrayList<Object> arrayList = new ArrayList<Object>(); 420 421 int primitiveSize = getTypeSize(nativeType); 422 while (buffer.remaining() >= primitiveSize) { 423 Object elem = unpackSingle(buffer, componentType, nativeType); 424 arrayList.add(elem); 425 } 426 427 array = arrayList.toArray((T[]) Array.newInstance(componentType, 0)); 428 } 429 430 if (buffer.remaining() != 0) { 431 Log.e(TAG, "Trailing bytes (" + buffer.remaining() + ") left over after unpacking " 432 + type); 433 } 434 435 return (T) array; 436 } 437 438 private long mMetadataPtr; // native CameraMetadata* 439 440 private native long nativeAllocate(); 441 private native long nativeAllocateCopy(CameraMetadataNative other) 442 throws NullPointerException; 443 444 private native synchronized void nativeWriteToParcel(Parcel dest); 445 private native synchronized void nativeReadFromParcel(Parcel source); 446 private native synchronized void nativeSwap(CameraMetadataNative other) 447 throws NullPointerException; 448 private native synchronized void nativeClose(); 449 private native synchronized boolean nativeIsEmpty(); 450 private native synchronized int nativeGetEntryCount(); 451 452 private native synchronized byte[] nativeReadValues(int tag); 453 private native synchronized void nativeWriteValues(int tag, byte[] src); 454 455 private static native int nativeGetTagFromKey(String keyName) 456 throws IllegalArgumentException; 457 private static native int nativeGetTypeFromTag(int tag) 458 throws IllegalArgumentException; 459 private static native void nativeClassInit(); 460 461 /** 462 * <p>Perform a 0-copy swap of the internal metadata with another object.</p> 463 * 464 * <p>Useful to convert a CameraMetadata into e.g. a CaptureRequest.</p> 465 * 466 * @param other Metadata to swap with 467 * @throws NullPointerException if other was null 468 * @hide 469 */ 470 public void swap(CameraMetadataNative other) { 471 nativeSwap(other); 472 } 473 474 /** 475 * @hide 476 */ 477 public int getEntryCount() { 478 return nativeGetEntryCount(); 479 } 480 481 /** 482 * Does this metadata contain at least 1 entry? 483 * 484 * @hide 485 */ 486 public boolean isEmpty() { 487 return nativeIsEmpty(); 488 } 489 490 /** 491 * Convert a key string into the equivalent native tag. 492 * 493 * @throws IllegalArgumentException if the key was not recognized 494 * @throws NullPointerException if the key was null 495 * 496 * @hide 497 */ 498 public static int getTag(String key) { 499 return nativeGetTagFromKey(key); 500 } 501 502 /** 503 * Get the underlying native type for a tag. 504 * 505 * @param tag An integer tag, see e.g. {@link #getTag} 506 * @return An int enum for the metadata type, see e.g. {@link #TYPE_BYTE} 507 * 508 * @hide 509 */ 510 public static int getNativeType(int tag) { 511 return nativeGetTypeFromTag(tag); 512 } 513 514 /** 515 * <p>Updates the existing entry for tag with the new bytes pointed by src, erasing 516 * the entry if src was null.</p> 517 * 518 * <p>An empty array can be passed in to update the entry to 0 elements.</p> 519 * 520 * @param tag An integer tag, see e.g. {@link #getTag} 521 * @param src An array of bytes, or null to erase the entry 522 * 523 * @hide 524 */ 525 public void writeValues(int tag, byte[] src) { 526 nativeWriteValues(tag, src); 527 } 528 529 /** 530 * <p>Returns a byte[] of data corresponding to this tag. Use a wrapped bytebuffer to unserialize 531 * the data properly.</p> 532 * 533 * <p>An empty array can be returned to denote an existing entry with 0 elements.</p> 534 * 535 * @param tag An integer tag, see e.g. {@link #getTag} 536 * 537 * @return {@code null} if there were 0 entries for this tag, a byte[] otherwise. 538 * @hide 539 */ 540 public byte[] readValues(int tag) { 541 // TODO: Optimization. Native code returns a ByteBuffer instead. 542 return nativeReadValues(tag); 543 } 544 545 @Override 546 protected void finalize() throws Throwable { 547 try { 548 close(); 549 } finally { 550 super.finalize(); 551 } 552 } 553 554 private static final HashMap<Class<? extends Enum>, int[]> sEnumValues = 555 new HashMap<Class<? extends Enum>, int[]>(); 556 /** 557 * Register a non-sequential set of values to be used with the pack/unpack functions. 558 * This enables get/set to correctly marshal the enum into a value that is C-compatible. 559 * 560 * @param enumType The class for an enum 561 * @param values A list of values mapping to the ordinals of the enum 562 * 563 * @hide 564 */ 565 public static <T extends Enum<T>> void registerEnumValues(Class<T> enumType, int[] values) { 566 if (enumType.getEnumConstants().length != values.length) { 567 throw new IllegalArgumentException( 568 "Expected values array to be the same size as the enumTypes values " 569 + values.length + " for type " + enumType); 570 } 571 if (VERBOSE) { 572 Log.v(TAG, "Registered enum values for type " + enumType + " values"); 573 } 574 575 sEnumValues.put(enumType, values); 576 } 577 578 /** 579 * Get the numeric value from an enum. This is usually the same as the ordinal value for 580 * enums that have fully sequential values, although for C-style enums the range of values 581 * may not map 1:1. 582 * 583 * @param enumValue Enum instance 584 * @return Int guaranteed to be ABI-compatible with the C enum equivalent 585 */ 586 private static <T extends Enum<T>> int getEnumValue(T enumValue) { 587 int[] values; 588 values = sEnumValues.get(enumValue.getClass()); 589 590 int ordinal = enumValue.ordinal(); 591 if (values != null) { 592 return values[ordinal]; 593 } 594 595 return ordinal; 596 } 597 598 /** 599 * Finds the enum corresponding to it's numeric value. Opposite of {@link #getEnumValue} method. 600 * 601 * @param enumType Class of the enum we want to find 602 * @param value The numeric value of the enum 603 * @return An instance of the enum 604 */ 605 private static <T extends Enum<T>> T getEnumFromValue(Class<T> enumType, int value) { 606 int ordinal; 607 608 int[] registeredValues = sEnumValues.get(enumType); 609 if (registeredValues != null) { 610 ordinal = -1; 611 612 for (int i = 0; i < registeredValues.length; ++i) { 613 if (registeredValues[i] == value) { 614 ordinal = i; 615 break; 616 } 617 } 618 } else { 619 ordinal = value; 620 } 621 622 T[] values = enumType.getEnumConstants(); 623 624 if (ordinal < 0 || ordinal >= values.length) { 625 throw new IllegalArgumentException( 626 String.format( 627 "Argument 'value' (%d) was not a valid enum value for type %s " 628 + "(registered? %b)", 629 value, 630 enumType, (registeredValues != null))); 631 } 632 633 return values[ordinal]; 634 } 635 636 static HashMap<Class<?>, MetadataMarshalClass<?>> sMarshalerMap = new 637 HashMap<Class<?>, MetadataMarshalClass<?>>(); 638 639 private static <T> void registerMarshaler(MetadataMarshalClass<T> marshaler) { 640 sMarshalerMap.put(marshaler.getMarshalingClass(), marshaler); 641 } 642 643 @SuppressWarnings("unchecked") 644 private static <T> MetadataMarshalClass<T> getMarshaler(Class<T> type, int nativeType) { 645 MetadataMarshalClass<T> marshaler = (MetadataMarshalClass<T>) sMarshalerMap.get(type); 646 647 if (marshaler != null && !marshaler.isNativeTypeSupported(nativeType)) { 648 throw new UnsupportedOperationException("Unsupported type " + nativeType + 649 " to be marshalled to/from a " + type); 650 } 651 652 return marshaler; 653 } 654 655 /** 656 * We use a class initializer to allow the native code to cache some field offsets 657 */ 658 static { 659 nativeClassInit(); 660 661 if (VERBOSE) { 662 Log.v(TAG, "Shall register metadata marshalers"); 663 } 664 665 // load built-in marshallers 666 registerMarshaler(new MetadataMarshalRect()); 667 registerMarshaler(new MetadataMarshalSize()); 668 registerMarshaler(new MetadataMarshalString()); 669 670 if (VERBOSE) { 671 Log.v(TAG, "Registered metadata marshalers"); 672 } 673 } 674 675} 676