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 17 package com.android.mediaframeworktest.unit; 18 19 import android.test.suitebuilder.annotation.SmallTest; 20 import android.util.Log; 21 import android.util.Pair; 22 import android.util.Range; 23 import android.util.Rational; 24 import android.util.SizeF; 25 import android.graphics.ImageFormat; 26 import android.graphics.Point; 27 import android.graphics.PointF; 28 import android.graphics.Rect; 29 import android.graphics.SurfaceTexture; 30 import android.hardware.camera2.CameraCharacteristics; 31 import android.hardware.camera2.CameraMetadata; 32 import android.hardware.camera2.CaptureRequest; 33 import android.hardware.camera2.CaptureResult; 34 import android.util.Size; 35 import android.hardware.camera2.impl.CameraMetadataNative; 36 import android.hardware.camera2.marshal.impl.MarshalQueryableEnum; 37 import android.hardware.camera2.params.ColorSpaceTransform; 38 import android.hardware.camera2.params.Face; 39 import android.hardware.camera2.params.HighSpeedVideoConfiguration; 40 import android.hardware.camera2.params.MeteringRectangle; 41 import android.hardware.camera2.params.ReprocessFormatsMap; 42 import android.hardware.camera2.params.RggbChannelVector; 43 import android.hardware.camera2.params.StreamConfiguration; 44 import android.hardware.camera2.params.StreamConfigurationDuration; 45 import android.hardware.camera2.params.StreamConfigurationMap; 46 import android.hardware.camera2.params.TonemapCurve; 47 import android.hardware.camera2.utils.TypeReference; 48 49 import static android.hardware.camera2.impl.CameraMetadataNative.*; 50 import static com.android.mediaframeworktest.unit.ByteArrayHelpers.*; 51 52 import java.lang.reflect.Array; 53 import java.nio.ByteBuffer; 54 import java.nio.ByteOrder; 55 import java.util.List; 56 57 /** 58 * <pre> 59 * adb shell am instrument \ 60 * -e class 'com.android.mediaframeworktest.unit.CameraMetadataTest' \ 61 * -w com.android.mediaframeworktest/.MediaFrameworkUnitTestRunner 62 * </pre> 63 */ 64 public class CameraMetadataTest extends junit.framework.TestCase { 65 66 private static final boolean VERBOSE = false; 67 private static final String TAG = "CameraMetadataTest"; 68 69 70 CameraMetadataNative mMetadata; 71 72 // Sections 73 static final int ANDROID_COLOR_CORRECTION = 0; 74 static final int ANDROID_CONTROL = 1; 75 76 // Section starts 77 static final int ANDROID_COLOR_CORRECTION_START = ANDROID_COLOR_CORRECTION << 16; 78 static final int ANDROID_CONTROL_START = ANDROID_CONTROL << 16; 79 80 // Tags 81 static final int ANDROID_COLOR_CORRECTION_MODE = ANDROID_COLOR_CORRECTION_START; 82 static final int ANDROID_COLOR_CORRECTION_TRANSFORM = ANDROID_COLOR_CORRECTION_START + 1; 83 static final int ANDROID_COLOR_CORRECTION_GAINS = ANDROID_COLOR_CORRECTION_START + 2; 84 85 static final int ANDROID_CONTROL_AE_ANTIBANDING_MODE = ANDROID_CONTROL_START; 86 static final int ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION = ANDROID_CONTROL_START + 1; 87 88 // From graphics.h 89 private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22; 90 91 @Override setUp()92 public void setUp() { 93 mMetadata = new CameraMetadataNative(); 94 } 95 96 @Override tearDown()97 public void tearDown() throws Exception { 98 mMetadata = null; 99 } 100 101 @SmallTest testNew()102 public void testNew() { 103 assertEquals(0, mMetadata.getEntryCount()); 104 assertTrue(mMetadata.isEmpty()); 105 } 106 107 @SmallTest testGetTagFromKey()108 public void testGetTagFromKey() { 109 110 // Test success 111 112 assertEquals(ANDROID_COLOR_CORRECTION_MODE, 113 CameraMetadataNative.getTag("android.colorCorrection.mode")); 114 assertEquals(ANDROID_COLOR_CORRECTION_TRANSFORM, 115 CameraMetadataNative.getTag("android.colorCorrection.transform")); 116 assertEquals(ANDROID_CONTROL_AE_ANTIBANDING_MODE, 117 CameraMetadataNative.getTag("android.control.aeAntibandingMode")); 118 assertEquals(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION, 119 CameraMetadataNative.getTag("android.control.aeExposureCompensation")); 120 121 // Test failures 122 123 try { 124 CameraMetadataNative.getTag(null); 125 fail("A null key should throw NPE"); 126 } catch(NullPointerException e) { 127 } 128 129 try { 130 CameraMetadataNative.getTag("android.control"); 131 fail("A section name only should not be a valid key"); 132 } catch(IllegalArgumentException e) { 133 } 134 135 try { 136 CameraMetadataNative.getTag("android.control.thisTagNameIsFakeAndDoesNotExist"); 137 fail("A valid section with an invalid tag name should not be a valid key"); 138 } catch(IllegalArgumentException e) { 139 } 140 141 try { 142 CameraMetadataNative.getTag("android"); 143 fail("A namespace name only should not be a valid key"); 144 } catch(IllegalArgumentException e) { 145 } 146 147 try { 148 CameraMetadataNative.getTag("this.key.is.definitely.invalid"); 149 fail("A completely fake key name should not be valid"); 150 } catch(IllegalArgumentException e) { 151 } 152 } 153 154 @SmallTest testGetTypeFromTag()155 public void testGetTypeFromTag() { 156 assertEquals(TYPE_BYTE, 157 CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_MODE, Long.MAX_VALUE)); 158 assertEquals(TYPE_RATIONAL, 159 CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_TRANSFORM, Long.MAX_VALUE)); 160 assertEquals(TYPE_FLOAT, 161 CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_GAINS, Long.MAX_VALUE)); 162 assertEquals(TYPE_BYTE, 163 CameraMetadataNative.getNativeType(ANDROID_CONTROL_AE_ANTIBANDING_MODE, Long.MAX_VALUE)); 164 assertEquals(TYPE_INT32, 165 CameraMetadataNative.getNativeType(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION, Long.MAX_VALUE)); 166 167 try { 168 CameraMetadataNative.getNativeType(0xDEADF00D, Long.MAX_VALUE); 169 fail("No type should exist for invalid tag 0xDEADF00D"); 170 } catch(IllegalArgumentException e) { 171 } 172 } 173 174 @SmallTest testReadWriteValues()175 public void testReadWriteValues() { 176 final byte ANDROID_COLOR_CORRECTION_MODE_HIGH_QUALITY = 2; 177 byte[] valueResult; 178 179 assertEquals(0, mMetadata.getEntryCount()); 180 assertEquals(true, mMetadata.isEmpty()); 181 182 // 183 // android.colorCorrection.mode (single enum byte) 184 // 185 186 assertEquals(null, mMetadata.readValues(ANDROID_COLOR_CORRECTION_MODE)); 187 188 // Write/read null values 189 mMetadata.writeValues(ANDROID_COLOR_CORRECTION_MODE, null); 190 assertEquals(null, mMetadata.readValues(ANDROID_COLOR_CORRECTION_MODE)); 191 192 // Write 0 values 193 mMetadata.writeValues(ANDROID_COLOR_CORRECTION_MODE, new byte[] {}); 194 195 // Read 0 values 196 valueResult = mMetadata.readValues(ANDROID_COLOR_CORRECTION_MODE); 197 assertNotNull(valueResult); 198 assertEquals(0, valueResult.length); 199 200 assertEquals(1, mMetadata.getEntryCount()); 201 assertEquals(false, mMetadata.isEmpty()); 202 203 // Write 1 value 204 mMetadata.writeValues(ANDROID_COLOR_CORRECTION_MODE, new byte[] { 205 ANDROID_COLOR_CORRECTION_MODE_HIGH_QUALITY 206 }); 207 208 // Read 1 value 209 valueResult = mMetadata.readValues(ANDROID_COLOR_CORRECTION_MODE); 210 assertNotNull(valueResult); 211 assertEquals(1, valueResult.length); 212 assertEquals(ANDROID_COLOR_CORRECTION_MODE_HIGH_QUALITY, valueResult[0]); 213 214 assertEquals(1, mMetadata.getEntryCount()); 215 assertEquals(false, mMetadata.isEmpty()); 216 217 // 218 // android.colorCorrection.colorCorrectionGains (float x 4 array) 219 // 220 221 final float[] colorCorrectionGains = new float[] { 1.0f, 2.0f, 3.0f, 4.0f}; 222 byte[] colorCorrectionGainsAsByteArray = new byte[colorCorrectionGains.length * 4]; 223 ByteBuffer colorCorrectionGainsByteBuffer = 224 ByteBuffer.wrap(colorCorrectionGainsAsByteArray).order(ByteOrder.nativeOrder()); 225 for (float f : colorCorrectionGains) 226 colorCorrectionGainsByteBuffer.putFloat(f); 227 228 // Read 229 assertNull(mMetadata.readValues(ANDROID_COLOR_CORRECTION_GAINS)); 230 mMetadata.writeValues(ANDROID_COLOR_CORRECTION_GAINS, colorCorrectionGainsAsByteArray); 231 232 // Write 233 assertArrayEquals(colorCorrectionGainsAsByteArray, 234 mMetadata.readValues(ANDROID_COLOR_CORRECTION_GAINS)); 235 236 assertEquals(2, mMetadata.getEntryCount()); 237 assertEquals(false, mMetadata.isEmpty()); 238 239 // Erase 240 mMetadata.writeValues(ANDROID_COLOR_CORRECTION_GAINS, null); 241 assertNull(mMetadata.readValues(ANDROID_COLOR_CORRECTION_GAINS)); 242 assertEquals(1, mMetadata.getEntryCount()); 243 } 244 245 /** 246 * Format an array into a string with the {@code badIndex} highlighted with {@code **}. 247 * 248 * <p>Numbers are printed as hexadecimal values.</p> 249 * 250 * <p>Example: {@code "[hello, **world**]"} for a {@code string[]}, 251 * or a {@code "[**0xFF**, 0xFF]"} for a {@code int[]}.</p> 252 */ formatArray(T array, int badIndex)253 private static <T> String formatArray(T array, int badIndex) { 254 StringBuilder builder = new StringBuilder(); 255 256 builder.append("["); 257 258 int len = Array.getLength(array); 259 for (int i = 0; i < len; ++i) { 260 261 Object elem = Array.get(array, i); 262 263 if (i == badIndex) { 264 builder.append("**"); 265 } 266 267 if (elem instanceof Byte) { 268 builder.append(String.format("%x", (Byte) elem)); 269 } else if (elem instanceof Short) { 270 builder.append(String.format("%x", (Short) elem)); 271 } else if (elem instanceof Integer) { 272 builder.append(String.format("%x", (Integer) elem)); 273 } else if (elem instanceof Long) { 274 builder.append(String.format("%x", (Long) elem)); 275 } else { 276 builder.append(elem); 277 } 278 279 if (i == badIndex) { 280 builder.append("**"); 281 } 282 283 if (i != len - 1) { 284 builder.append(", "); 285 } 286 } 287 288 builder.append("]"); 289 290 return builder.toString(); 291 } 292 assertArrayEquals(T expected, T actual)293 private static <T> void assertArrayEquals(T expected, T actual) { 294 if (!expected.getClass().isArray() || !actual.getClass().isArray()) { 295 throw new IllegalArgumentException("expected, actual must both be arrays"); 296 } 297 298 assertEquals("Array lengths must be equal", 299 Array.getLength(expected), Array.getLength(actual)); 300 301 int len = Array.getLength(expected); 302 for (int i = 0; i < len; ++i) { 303 304 Object expectedElement = Array.get(expected, i); 305 Object actualElement = Array.get(actual, i); 306 307 if (!expectedElement.equals(actualElement)) { 308 fail(String.format( 309 "element %d in array was not equal (expected %s, actual %s). " 310 + "Arrays were: (expected %s, actual %s).", 311 i, expectedElement, actualElement, 312 formatArray(expected, i), 313 formatArray(actual, i))); 314 } 315 } 316 } 317 assertArrayContains(T needle, T2 array)318 private static <T, T2> void assertArrayContains(T needle, T2 array) { 319 if (!array.getClass().isArray()) { 320 throw new IllegalArgumentException("actual must be array"); 321 } 322 323 int len = Array.getLength(array); 324 for (int i = 0; i < len; ++i) { 325 326 Object actualElement = Array.get(array, i); 327 328 if (needle.equals(actualElement)) { 329 return; 330 } 331 } 332 333 fail(String.format( 334 "could not find element in array (needle %s). " 335 + "Array was: %s.", 336 needle, 337 formatArray(array, len))); 338 } 339 checkKeyGetAndSet(String keyStr, TypeReference<T> typeToken, T expected, boolean reuse)340 private <T> void checkKeyGetAndSet(String keyStr, TypeReference<T> typeToken, T expected, 341 boolean reuse) { 342 Key<T> key = new Key<T>(keyStr, typeToken); 343 assertNull(mMetadata.get(key)); 344 mMetadata.set(key, null); 345 assertNull(mMetadata.get(key)); 346 mMetadata.set(key, expected); 347 348 T actual = mMetadata.get(key); 349 350 if (typeToken.getRawType().isArray()) { 351 assertArrayEquals(expected, actual); 352 } else { 353 assertEquals(expected, actual); 354 } 355 356 if (reuse) { 357 // reset the key incase we want to use it again 358 mMetadata.set(key, null); 359 } 360 } 361 checkKeyGetAndSet(String keyStr, TypeReference<T> typeToken, T expected)362 private <T> void checkKeyGetAndSet(String keyStr, TypeReference<T> typeToken, T expected) { 363 checkKeyGetAndSet(keyStr, typeToken, expected, /*reuse*/false); 364 } 365 checkKeyGetAndSet(String keyStr, Class<T> type, T expected)366 private <T> void checkKeyGetAndSet(String keyStr, Class<T> type, T expected) { 367 checkKeyGetAndSet(keyStr, TypeReference.createSpecializedTypeReference(type), expected); 368 } 369 370 /** 371 * Ensure that the data survives a marshal/unmarshal round-trip; 372 * it must also be equal to the {@code expectedNative} byte array. 373 * 374 * <p>As a side-effect, the metadata value corresponding to the key is now set to 375 * {@code expected}.</p> 376 * 377 * @return key created with {@code keyName} and {@code T} 378 */ checkKeyMarshal(String keyName, TypeReference<T> typeReference, T expected, byte[] expectedNative)379 private <T> Key<T> checkKeyMarshal(String keyName, TypeReference<T> typeReference, 380 T expected, byte[] expectedNative) { 381 Key<T> key = new Key<T>(keyName, typeReference); 382 383 mMetadata.set(key, null); 384 assertNull(mMetadata.get(key)); 385 386 // Write managed value -> make sure native bytes are what we expect 387 mMetadata.set(key, expected); 388 389 byte[] actualValues = mMetadata.readValues(key.getTag()); 390 assertArrayEquals(expectedNative, actualValues); 391 392 // Write managed value -> make sure read-out managed value is what we expect 393 T actual = mMetadata.get(key); 394 395 if (typeReference.getRawType().isArray()) { 396 assertArrayEquals(expected, actual); 397 } else { 398 assertEquals(expected, actual); 399 } 400 401 // Write native bytes -> make sure read-out managed value is what we expect 402 mMetadata.writeValues(key.getTag(), expectedNative); 403 actual = mMetadata.get(key); 404 405 if (typeReference.getRawType().isArray()) { 406 assertArrayEquals(expected, actual); 407 } else { 408 assertEquals(expected, actual); 409 } 410 411 return key; 412 } 413 414 /** 415 * Ensure that the data survives a marshal/unmarshal round-trip; 416 * it must also be equal to the {@code expectedNative} byte array. 417 * 418 * <p>As a side-effect, 419 * the metadata value corresponding to the key is now set to {@code expected}.</p> 420 * 421 * @return key created with {@code keyName} and {@code T} 422 */ checkKeyMarshal(String keyName, T expected, byte[] expectedNative)423 private <T> Key<T> checkKeyMarshal(String keyName, T expected, byte[] expectedNative) { 424 @SuppressWarnings("unchecked") 425 Class<T> expectedClass = (Class<T>) expected.getClass(); 426 return checkKeyMarshal(keyName, 427 TypeReference.createSpecializedTypeReference(expectedClass), 428 expected, 429 expectedNative); 430 } 431 432 @SmallTest testReadWritePrimitive()433 public void testReadWritePrimitive() { 434 // int32 (single) 435 checkKeyGetAndSet("android.control.aeExposureCompensation", Integer.TYPE, 0xC0FFEE); 436 437 // byte (single) 438 checkKeyGetAndSet("android.flash.maxEnergy", Byte.TYPE, (byte)6); 439 440 // int64 (single) 441 checkKeyGetAndSet("android.flash.firingTime", Long.TYPE, 0xABCD12345678FFFFL); 442 443 // float (single) 444 checkKeyGetAndSet("android.lens.aperture", Float.TYPE, Float.MAX_VALUE); 445 446 // double (single) -- technically double x 3, but we fake it 447 checkKeyGetAndSet("android.jpeg.gpsCoordinates", Double.TYPE, Double.MAX_VALUE); 448 449 // rational (single) 450 checkKeyGetAndSet("android.sensor.baseGainFactor", Rational.class, new Rational(1, 2)); 451 452 /** 453 * Weirder cases, that don't map 1:1 with the native types 454 */ 455 456 // bool (single) -- with TYPE_BYTE 457 checkKeyGetAndSet("android.control.aeLock", Boolean.TYPE, true); 458 459 // integer (single) -- with TYPE_BYTE 460 checkKeyGetAndSet("android.control.aePrecaptureTrigger", Integer.TYPE, 6); 461 } 462 463 @SmallTest testReadWritePrimitiveArray()464 public void testReadWritePrimitiveArray() { 465 // int32 (n) 466 checkKeyGetAndSet("android.sensor.info.sensitivityRange", int[].class, 467 new int[] { 468 0xC0FFEE, 0xDEADF00D 469 }); 470 471 // byte (n) 472 checkKeyGetAndSet("android.statistics.faceScores", byte[].class, new byte[] { 473 1, 2, 3, 4 474 }); 475 476 // int64 (n) 477 checkKeyGetAndSet("android.scaler.availableProcessedMinDurations", long[].class, 478 new long[] { 479 0xABCD12345678FFFFL, 0x1234ABCD5678FFFFL, 0xFFFF12345678ABCDL 480 }); 481 482 // float (n) 483 checkKeyGetAndSet("android.lens.info.availableApertures", float[].class, 484 new float[] { 485 Float.MAX_VALUE, Float.MIN_NORMAL, Float.MIN_VALUE 486 }); 487 488 // double (n) -- in particular double x 3 489 checkKeyGetAndSet("android.jpeg.gpsCoordinates", double[].class, 490 new double[] { 491 Double.MAX_VALUE, Double.MIN_NORMAL, Double.MIN_VALUE 492 }); 493 494 // rational (n) -- in particular rational x 9 495 checkKeyGetAndSet("android.sensor.calibrationTransform1", Rational[].class, 496 new Rational[] { 497 new Rational(1, 2), new Rational(3, 4), new Rational(5, 6), 498 new Rational(7, 8), new Rational(9, 10), new Rational(10, 11), 499 new Rational(12, 13), new Rational(14, 15), new Rational(15, 16) 500 }); 501 502 /** 503 * Weirder cases, that don't map 1:1 with the native types 504 */ 505 506 // bool (n) -- with TYPE_BYTE 507 checkKeyGetAndSet("android.control.aeLock", boolean[].class, new boolean[] { 508 true, false, true 509 }); 510 511 // integer (n) -- with TYPE_BYTE 512 checkKeyGetAndSet("android.control.aeAvailableModes", int[].class, new int[] { 513 1, 2, 3, 4 514 }); 515 } 516 517 private enum ColorCorrectionMode { 518 TRANSFORM_MATRIX, 519 FAST, 520 HIGH_QUALITY 521 } 522 523 private enum AeAntibandingMode { 524 OFF, 525 _50HZ, 526 _60HZ, 527 AUTO 528 } 529 530 private enum AvailableFormat { 531 RAW_SENSOR, 532 YV12, 533 YCrCb_420_SP, 534 IMPLEMENTATION_DEFINED, 535 YCbCr_420_888, 536 BLOB 537 } 538 539 @SmallTest testReadWriteEnum()540 public void testReadWriteEnum() { 541 // byte (single) 542 checkKeyGetAndSet("android.colorCorrection.mode", ColorCorrectionMode.class, 543 ColorCorrectionMode.HIGH_QUALITY); 544 545 // byte (single) 546 checkKeyGetAndSet("android.control.aeAntibandingMode", AeAntibandingMode.class, 547 AeAntibandingMode.AUTO); 548 549 // byte (n) 550 checkKeyGetAndSet("android.control.aeAvailableAntibandingModes", 551 AeAntibandingMode[].class, new AeAntibandingMode[] { 552 AeAntibandingMode.OFF, AeAntibandingMode._50HZ, AeAntibandingMode._60HZ, 553 AeAntibandingMode.AUTO 554 }); 555 556 /** 557 * Stranger cases that don't use byte enums 558 */ 559 // int (n) 560 checkKeyGetAndSet("android.scaler.availableFormats", AvailableFormat[].class, 561 new AvailableFormat[] { 562 AvailableFormat.RAW_SENSOR, 563 AvailableFormat.YV12, 564 AvailableFormat.IMPLEMENTATION_DEFINED, 565 AvailableFormat.YCbCr_420_888, 566 AvailableFormat.BLOB 567 }); 568 569 } 570 571 @SmallTest testReadWriteEnumWithCustomValues()572 public void testReadWriteEnumWithCustomValues() { 573 MarshalQueryableEnum.registerEnumValues(AeAntibandingMode.class, new int[] { 574 0, 575 10, 576 20, 577 30 578 }); 579 580 // byte (single) 581 checkKeyGetAndSet("android.control.aeAntibandingMode", AeAntibandingMode.class, 582 AeAntibandingMode.AUTO); 583 584 // byte (n) 585 checkKeyGetAndSet("android.control.aeAvailableAntibandingModes", 586 AeAntibandingMode[].class, new AeAntibandingMode[] { 587 AeAntibandingMode.OFF, AeAntibandingMode._50HZ, AeAntibandingMode._60HZ, 588 AeAntibandingMode.AUTO 589 }); 590 591 byte[] aeAntibandingModeValues = mMetadata.readValues(CameraMetadataNative 592 .getTag("android.control.aeAvailableAntibandingModes")); 593 byte[] expectedValues = new byte[] { 0, 10, 20, 30 }; 594 assertArrayEquals(expectedValues, aeAntibandingModeValues); 595 596 597 /** 598 * Stranger cases that don't use byte enums 599 */ 600 // int (n) 601 MarshalQueryableEnum.registerEnumValues(AvailableFormat.class, new int[] { 602 0x20, 603 0x32315659, 604 0x11, 605 0x22, 606 0x23, 607 0x21, 608 }); 609 610 checkKeyGetAndSet("android.scaler.availableFormats", AvailableFormat[].class, 611 new AvailableFormat[] { 612 AvailableFormat.RAW_SENSOR, 613 AvailableFormat.YV12, 614 AvailableFormat.IMPLEMENTATION_DEFINED, 615 AvailableFormat.YCbCr_420_888, 616 AvailableFormat.BLOB 617 }); 618 619 Key<AvailableFormat[]> availableFormatsKey = 620 new Key<AvailableFormat[]>("android.scaler.availableFormats", 621 AvailableFormat[].class); 622 byte[] availableFormatValues = mMetadata.readValues(CameraMetadataNative 623 .getTag(availableFormatsKey.getName())); 624 625 int[] expectedIntValues = new int[] { 626 0x20, 627 0x32315659, 628 0x22, 629 0x23, 630 0x21 631 }; 632 633 ByteBuffer bf = ByteBuffer.wrap(availableFormatValues).order(ByteOrder.nativeOrder()); 634 635 assertEquals(expectedIntValues.length * 4, availableFormatValues.length); 636 for (int i = 0; i < expectedIntValues.length; ++i) { 637 assertEquals(expectedIntValues[i], bf.getInt()); 638 } 639 } 640 641 @SmallTest testReadWriteSize()642 public void testReadWriteSize() { 643 // int32 x n 644 checkKeyGetAndSet("android.jpeg.thumbnailSize", Size.class, new Size(123, 456)); 645 646 // int32 x 2 x n 647 checkKeyGetAndSet("android.scaler.availableJpegSizes", Size[].class, new Size[] { 648 new Size(123, 456), 649 new Size(0xDEAD, 0xF00D), 650 new Size(0xF00, 0xB00) 651 }); 652 } 653 654 @SmallTest testReadWriteRggbChannelVector()655 public void testReadWriteRggbChannelVector() { 656 // int32 x n 657 checkKeyMarshal("android.colorCorrection.gains", 658 new RggbChannelVector(1.0f, 2.1f, 3.2f, 4.5f), 659 toByteArray(1.0f, 2.1f, 3.2f, 4.5f)); 660 661 // int32 x 2 x n [pretend; actual is not array] 662 checkKeyMarshal("android.colorCorrection.gains", 663 new RggbChannelVector[] { 664 new RggbChannelVector(1.0f, 2.0f, 3.0f, 4.0f), 665 new RggbChannelVector(9.0f, 8.0f, 7.0f, 6.0f), 666 new RggbChannelVector(1.3f, 5.5f, 2.4f, 6.7f), 667 }, toByteArray( 668 1.0f, 2.0f, 3.0f, 4.0f, 669 9.0f, 8.0f, 7.0f, 6.0f, 670 1.3f, 5.5f, 2.4f, 6.7f 671 )); 672 } 673 674 @SmallTest testReadWriteSizeF()675 public void testReadWriteSizeF() { 676 // int32 x n 677 checkKeyMarshal("android.sensor.info.physicalSize", 678 new SizeF(123f, 456f), 679 toByteArray(123f, 456f)); 680 681 // int32 x 2 x n 682 checkKeyMarshal("android.sensor.info.physicalSize", 683 new SizeF[] { 684 new SizeF(123f, 456f), 685 new SizeF(1.234f, 4.567f), 686 new SizeF(999.0f, 555.0f) 687 }, 688 toByteArray( 689 123f, 456f, 690 1.234f, 4.567f, 691 999.0f, 555.0f) 692 ); 693 } 694 695 @SmallTest testReadWriteRectangle()696 public void testReadWriteRectangle() { 697 // int32 x n 698 checkKeyMarshal("android.scaler.cropRegion", 699 // x1, y1, x2, y2 700 new Rect(10, 11, 1280, 1024), 701 // x, y, width, height 702 toByteArray(10, 11, 1280 - 10, 1024 - 11)); 703 704 // int32 x 2 x n [actually not array, but we pretend it is] 705 checkKeyMarshal("android.scaler.cropRegion", new Rect[] { 706 new Rect(110, 111, 11280, 11024), 707 new Rect(210, 111, 21280, 21024), 708 new Rect(310, 111, 31280, 31024) 709 }, toByteArray( 710 110, 111, 11280 - 110, 11024 - 111, 711 210, 111, 21280 - 210, 21024 - 111, 712 310, 111, 31280 - 310, 31024 - 111 713 )); 714 } 715 716 @SmallTest testReadWriteMeteringRectangle()717 public void testReadWriteMeteringRectangle() { 718 // int32 x 5 x area_count [but we pretend it's a single element] 719 checkKeyMarshal("android.control.aeRegions", 720 new MeteringRectangle(/*x*/1, /*y*/2, /*width*/100, /*height*/200, /*weight*/5), 721 /* xmin, ymin, xmax, ymax, weight */ 722 toByteArray(1, 2, 1 + 100, 2 + 200, 5)); 723 724 // int32 x 5 x area_count 725 checkKeyMarshal("android.control.afRegions", 726 new MeteringRectangle[] { 727 new MeteringRectangle(/*x*/5, /*y*/6, /*width*/123, /*height*/456, /*weight*/7), 728 new MeteringRectangle(/*x*/7, /*y*/8, /*width*/456, /*height*/999, /*weight*/6), 729 new MeteringRectangle(/*x*/1, /*y*/2, /*width*/100, /*height*/200, /*weight*/5) 730 }, 731 toByteArray( 732 5, 6, 5 + 123, 6 + 456, 7, 733 7, 8, 7 + 456, 8 + 999, 6, 734 1, 2, 1 + 100, 2 + 200, 5 735 )); 736 } 737 738 @SmallTest testReadWriteHighSpeedVideoConfiguration()739 public void testReadWriteHighSpeedVideoConfiguration() { 740 // int32 x 5 x 1 741 checkKeyMarshal("android.control.availableHighSpeedVideoConfigurations", 742 new HighSpeedVideoConfiguration( 743 /*width*/1000, /*height*/255, /*fpsMin*/30, /*fpsMax*/200, 744 /*batchSizeMax*/8), 745 /* width, height, fpsMin, fpsMax */ 746 toByteArray(1000, 255, 30, 200, 8)); 747 748 // int32 x 5 x 3 749 checkKeyMarshal("android.control.availableHighSpeedVideoConfigurations", 750 new HighSpeedVideoConfiguration[] { 751 new HighSpeedVideoConfiguration( 752 /*width*/1280, /*height*/720, /*fpsMin*/60, /*fpsMax*/120, 753 /*batchSizeMax*/8), 754 new HighSpeedVideoConfiguration( 755 /*width*/123, /*height*/456, /*fpsMin*/1, /*fpsMax*/200, 756 /*batchSizeMax*/4), 757 new HighSpeedVideoConfiguration( 758 /*width*/4096, /*height*/2592, /*fpsMin*/30, /*fpsMax*/60, 759 /*batchSizeMax*/2) 760 }, 761 toByteArray( 762 1280, 720, 60, 120, 8, 763 123, 456, 1, 200, 4, 764 4096, 2592, 30, 60, 2 765 )); 766 } 767 768 @SmallTest testReadWriteColorSpaceTransform()769 public void testReadWriteColorSpaceTransform() { 770 // rational x 3 x 3 771 checkKeyMarshal("android.colorCorrection.transform", 772 new ColorSpaceTransform(new Rational[] { 773 new Rational(1, 2), new Rational(3, 4), new Rational(5, 6), 774 new Rational(7, 8), new Rational(8, 9), new Rational(10, 11), 775 new Rational(1, 5), new Rational(2, 8), new Rational(3, 9), 776 }), 777 toByteArray( 778 1, 2, 3, 4, 5, 6, 779 7, 8, 8, 9, 10, 11, 780 1, 5, 1, 4, 1, 3)); 781 } 782 783 @SmallTest testReadWritePoint()784 public void testReadWritePoint() { 785 // int32 x 2 [actually 'x n' but pretend it's a single value for now] 786 checkKeyMarshal("android.statistics.hotPixelMap", 787 new Point(1, 2), 788 toByteArray(1, 2)); 789 790 // int32 x 2 x samples 791 checkKeyMarshal("android.statistics.hotPixelMap", 792 new Point[] { 793 new Point(1, 2), 794 new Point(3, 4), 795 new Point(5, 6), 796 new Point(7, 8), 797 }, 798 toByteArray( 799 1, 2, 800 3, 4, 801 5, 6, 802 7, 8) 803 ); 804 } 805 806 @SmallTest testReadWritePointF()807 public void testReadWritePointF() { 808 // float x 2 [actually 'x samples' but pretend it's a single value for now] 809 checkKeyMarshal( 810 "android.sensor.profileToneCurve", 811 new PointF(1.0f, 2.0f), 812 toByteArray(1.0f, 2.0f)); 813 814 // float x 2 x samples 815 checkKeyMarshal("android.sensor.profileToneCurve", 816 new PointF[] { 817 new PointF(1.0f, 2.0f), 818 new PointF(3.0f, 4.0f), 819 new PointF(5.0f, 6.0f), 820 new PointF(7.0f, 8.0f), 821 }, 822 toByteArray( 823 1.0f, 2.0f, 824 3.0f, 4.0f, 825 5.0f, 6.0f, 826 7.0f, 8.0f)); 827 } 828 829 @SmallTest testReadWritePair()830 public void testReadWritePair() { 831 // float x 2 832 checkKeyMarshal("android.lens.focusRange", 833 new TypeReference<Pair<Float, Float>>() {{ }}, 834 Pair.create(1.0f / 2.0f, 1.0f / 3.0f), 835 toByteArray(1.0f / 2.0f, 1.0f / 3.0f)); 836 837 // byte, int (fake from TYPE_BYTE) 838 // This takes advantage of the TYPE_BYTE -> int marshaler designed for enums. 839 checkKeyMarshal("android.flash.mode", 840 new TypeReference<Pair<Byte, Integer>>() {{ }}, 841 Pair.create((byte)123, 22), 842 toByteArray((byte)123, (byte)22)); 843 } 844 845 @SmallTest testReadWriteRange()846 public void testReadWriteRange() { 847 // int32 x 2 848 checkKeyMarshal("android.control.aeTargetFpsRange", 849 new TypeReference<Range<Integer>>() {{ }}, 850 Range.create(123, 456), 851 toByteArray(123, 456)); 852 853 // int64 x 2 854 checkKeyMarshal("android.sensor.info.exposureTimeRange", 855 new TypeReference<Range<Long>>() {{ }}, 856 Range.create(123L, 456L), 857 toByteArray(123L, 456L)); 858 } 859 860 @SmallTest testReadWriteStreamConfiguration()861 public void testReadWriteStreamConfiguration() { 862 // int32 x 4 x n 863 checkKeyMarshal("android.scaler.availableStreamConfigurations", 864 new StreamConfiguration[] { 865 new StreamConfiguration(ImageFormat.YUV_420_888, 640, 480, /*input*/false), 866 new StreamConfiguration(ImageFormat.RGB_565, 320, 240, /*input*/true), 867 }, 868 toByteArray( 869 ImageFormat.YUV_420_888, 640, 480, /*input*/0, 870 ImageFormat.RGB_565, 320, 240, /*input*/1) 871 ); 872 } 873 874 @SmallTest testReadWriteStreamConfigurationDuration()875 public void testReadWriteStreamConfigurationDuration() { 876 // Avoid sign extending ints when converting to a long 877 final long MASK_UNSIGNED_INT = 0x00000000ffffffffL; 878 879 // int64 x 4 x n 880 checkKeyMarshal("android.scaler.availableMinFrameDurations", 881 new StreamConfigurationDuration[] { 882 new StreamConfigurationDuration( 883 ImageFormat.YUV_420_888, 640, 480, /*duration*/123L), 884 new StreamConfigurationDuration( 885 ImageFormat.RGB_565, 320, 240, /*duration*/345L), 886 }, 887 toByteArray( 888 ImageFormat.YUV_420_888 & MASK_UNSIGNED_INT, 640L, 480L, /*duration*/123L, 889 ImageFormat.RGB_565 & MASK_UNSIGNED_INT, 320L, 240L, /*duration*/345L) 890 ); 891 } 892 893 894 @SmallTest testReadWriteReprocessFormatsMap()895 public void testReadWriteReprocessFormatsMap() { 896 897 // final int RAW_OPAQUE = 0x24; // TODO: add RAW_OPAQUE to ImageFormat 898 final int RAW16 = ImageFormat.RAW_SENSOR; 899 final int YUV_420_888 = ImageFormat.YUV_420_888; 900 final int BLOB = 0x21; 901 902 // TODO: also test HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED as an output 903 int[] contents = new int[] { 904 YUV_420_888, 3, YUV_420_888, ImageFormat.NV21, BLOB, 905 RAW16, 2, YUV_420_888, BLOB, 906 907 }; 908 909 // int32 x n 910 Key<ReprocessFormatsMap> key = new Key<ReprocessFormatsMap>( 911 "android.scaler.availableInputOutputFormatsMap", ReprocessFormatsMap.class); 912 mMetadata.writeValues(key.getTag(), toByteArray(contents)); 913 914 ReprocessFormatsMap map = mMetadata.get(key); 915 916 /* 917 * Make sure the inputs/outputs were what we expected. 918 * - Use public image format constants here. 919 */ 920 921 int[] expectedInputs = new int[] { 922 YUV_420_888, RAW16 923 }; 924 assertArrayEquals(expectedInputs, map.getInputs()); 925 926 int[] expectedYuvOutputs = new int[] { 927 YUV_420_888, ImageFormat.NV21, ImageFormat.JPEG, 928 }; 929 assertArrayEquals(expectedYuvOutputs, map.getOutputs(ImageFormat.YUV_420_888)); 930 931 int[] expectedRaw16Outputs = new int[] { 932 YUV_420_888, ImageFormat.JPEG, 933 }; 934 assertArrayEquals(expectedRaw16Outputs, map.getOutputs(ImageFormat.RAW_SENSOR)); 935 936 // Finally, do a round-trip check for consistency 937 checkKeyMarshal( 938 "android.scaler.availableInputOutputFormatsMap", 939 new ReprocessFormatsMap(contents), 940 toByteArray(contents) 941 ); 942 } 943 944 @SmallTest testReadWriteString()945 public void testReadWriteString() { 946 // (byte) string 947 Key<String> gpsProcessingMethodKey = 948 new Key<String>("android.jpeg.gpsProcessingMethod", String.class); 949 950 String helloWorld = new String("HelloWorld"); 951 byte[] helloWorldBytes = new byte[] { 952 'H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd', '\0' }; 953 954 mMetadata.set(gpsProcessingMethodKey, helloWorld); 955 956 String actual = mMetadata.get(gpsProcessingMethodKey); 957 assertEquals(helloWorld, actual); 958 959 byte[] actualBytes = mMetadata.readValues(getTag(gpsProcessingMethodKey.getName())); 960 assertArrayEquals(helloWorldBytes, actualBytes); 961 962 // Does not yet test as a string[] since we don't support that in native code. 963 964 // (byte) string 965 Key<String[]> gpsProcessingMethodKeyArray = 966 new Key<String[]>("android.jpeg.gpsProcessingMethod", String[].class); 967 968 String[] gpsStrings = new String[] { "HelloWorld", "FooBar", "Shazbot" }; 969 byte[] gpsBytes = new byte[] { 970 'H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd', '\0', 971 'F', 'o', 'o', 'B', 'a', 'r', '\0', 972 'S', 'h', 'a', 'z', 'b', 'o', 't', '\0'}; 973 974 mMetadata.set(gpsProcessingMethodKeyArray, gpsStrings); 975 976 String[] actualArray = mMetadata.get(gpsProcessingMethodKeyArray); 977 assertArrayEquals(gpsStrings, actualArray); 978 979 byte[] actualBytes2 = mMetadata.readValues(getTag(gpsProcessingMethodKeyArray.getName())); 980 assertArrayEquals(gpsBytes, actualBytes2); 981 } 982 983 @SmallTest testReadWriteOverride()984 public void testReadWriteOverride() { 985 // 986 // android.scaler.availableFormats (int x n array) 987 // 988 int[] availableFormats = new int[] { 989 0x20, // RAW_SENSOR 990 0x32315659, // YV12 991 0x11, // YCrCb_420_SP 992 0x100, // ImageFormat.JPEG 993 0x22, // IMPLEMENTATION_DEFINED 994 0x23, // YCbCr_420_888 995 }; 996 int[] expectedIntValues = new int[] { 997 0x20, // RAW_SENSOR 998 0x32315659, // YV12 999 0x11, // YCrCb_420_SP 1000 0x21, // BLOB 1001 0x22, // IMPLEMENTATION_DEFINED 1002 0x23, // YCbCr_420_888 1003 }; 1004 int availableFormatTag = CameraMetadataNative.getTag("android.scaler.availableFormats"); 1005 1006 Key<int[]> formatKey = CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey(); 1007 1008 validateArrayMetadataReadWriteOverride(formatKey, availableFormats, 1009 expectedIntValues, availableFormatTag); 1010 1011 // 1012 // android.statistics.faces (Face x n array) 1013 // 1014 int[] expectedFaceIds = new int[] {1, 2, 3, 4, 5}; 1015 byte[] expectedFaceScores = new byte[] {10, 20, 30, 40, 50}; 1016 int numFaces = expectedFaceIds.length; 1017 Rect[] expectedRects = new Rect[numFaces]; 1018 for (int i = 0; i < numFaces; i++) { 1019 expectedRects[i] = new Rect(i*4 + 1, i * 4 + 2, i * 4 + 3, i * 4 + 4); 1020 } 1021 int[] expectedFaceLM = new int[] { 1022 1, 2, 3, 4, 5, 6, 1023 7, 8, 9, 10, 11, 12, 1024 13, 14, 15, 16, 17, 18, 1025 19, 20, 21, 22, 23, 24, 1026 25, 26, 27, 28, 29, 30, 1027 }; 1028 Point[] expectedFaceLMPoints = new Point[numFaces * 3]; 1029 for (int i = 0; i < numFaces; i++) { 1030 expectedFaceLMPoints[i*3] = new Point(expectedFaceLM[i*6], expectedFaceLM[i*6+1]); 1031 expectedFaceLMPoints[i*3+1] = new Point(expectedFaceLM[i*6+2], expectedFaceLM[i*6+3]); 1032 expectedFaceLMPoints[i*3+2] = new Point(expectedFaceLM[i*6+4], expectedFaceLM[i*6+5]); 1033 } 1034 1035 /** 1036 * Read - FACE_DETECT_MODE == FULL 1037 */ 1038 mMetadata.set(CaptureResult.STATISTICS_FACE_DETECT_MODE, 1039 CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL); 1040 mMetadata.set(CaptureResult.STATISTICS_FACE_IDS, expectedFaceIds); 1041 mMetadata.set(CaptureResult.STATISTICS_FACE_SCORES, expectedFaceScores); 1042 mMetadata.set(CaptureResult.STATISTICS_FACE_RECTANGLES, expectedRects); 1043 mMetadata.set(CaptureResult.STATISTICS_FACE_LANDMARKS, expectedFaceLM); 1044 Face[] resultFaces = mMetadata.get(CaptureResult.STATISTICS_FACES); 1045 assertEquals(numFaces, resultFaces.length); 1046 for (int i = 0; i < numFaces; i++) { 1047 assertEquals(expectedFaceIds[i], resultFaces[i].getId()); 1048 assertEquals(expectedFaceScores[i], resultFaces[i].getScore()); 1049 assertEquals(expectedRects[i], resultFaces[i].getBounds()); 1050 assertEquals(expectedFaceLMPoints[i*3], resultFaces[i].getLeftEyePosition()); 1051 assertEquals(expectedFaceLMPoints[i*3+1], resultFaces[i].getRightEyePosition()); 1052 assertEquals(expectedFaceLMPoints[i*3+2], resultFaces[i].getMouthPosition()); 1053 } 1054 1055 /** 1056 * Read - FACE_DETECT_MODE == SIMPLE 1057 */ 1058 mMetadata.set(CaptureResult.STATISTICS_FACE_DETECT_MODE, 1059 CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE); 1060 mMetadata.set(CaptureResult.STATISTICS_FACE_SCORES, expectedFaceScores); 1061 mMetadata.set(CaptureResult.STATISTICS_FACE_RECTANGLES, expectedRects); 1062 Face[] resultSimpleFaces = mMetadata.get(CaptureResult.STATISTICS_FACES); 1063 assertEquals(numFaces, resultSimpleFaces.length); 1064 for (int i = 0; i < numFaces; i++) { 1065 assertEquals(Face.ID_UNSUPPORTED, resultSimpleFaces[i].getId()); 1066 assertEquals(expectedFaceScores[i], resultSimpleFaces[i].getScore()); 1067 assertEquals(expectedRects[i], resultSimpleFaces[i].getBounds()); 1068 assertNull(resultSimpleFaces[i].getLeftEyePosition()); 1069 assertNull(resultSimpleFaces[i].getRightEyePosition()); 1070 assertNull(resultSimpleFaces[i].getMouthPosition()); 1071 } 1072 1073 /** 1074 * Read/Write TonemapCurve 1075 */ 1076 float[] red = new float[] {0.0f, 0.0f, 1.0f, 1.0f}; 1077 float[] green = new float[] {0.0f, 1.0f, 1.0f, 0.0f}; 1078 float[] blue = new float[] { 1079 0.0000f, 0.0000f, 0.0667f, 0.2920f, 0.1333f, 0.4002f, 0.2000f, 0.4812f, 1080 0.2667f, 0.5484f, 0.3333f, 0.6069f, 0.4000f, 0.6594f, 0.4667f, 0.7072f, 1081 0.5333f, 0.7515f, 0.6000f, 0.7928f, 0.6667f, 0.8317f, 0.7333f, 0.8685f, 1082 0.8000f, 0.9035f, 0.8667f, 0.9370f, 0.9333f, 0.9691f, 1.0000f, 1.0000f}; 1083 TonemapCurve tcIn = new TonemapCurve(red, green, blue); 1084 mMetadata.set(CaptureResult.TONEMAP_CURVE, tcIn); 1085 float[] redOut = mMetadata.get(CaptureResult.TONEMAP_CURVE_RED); 1086 float[] greenOut = mMetadata.get(CaptureResult.TONEMAP_CURVE_GREEN); 1087 float[] blueOut = mMetadata.get(CaptureResult.TONEMAP_CURVE_BLUE); 1088 assertArrayEquals(red, redOut); 1089 assertArrayEquals(green, greenOut); 1090 assertArrayEquals(blue, blueOut); 1091 TonemapCurve tcOut = mMetadata.get(CaptureResult.TONEMAP_CURVE); 1092 assertEquals(tcIn, tcOut); 1093 mMetadata.set(CaptureResult.TONEMAP_CURVE_GREEN, null); 1094 // If any of channel has null curve, return a null TonemapCurve 1095 assertNull(mMetadata.get(CaptureResult.TONEMAP_CURVE)); 1096 } 1097 1098 /** 1099 * Set the raw native value of the available stream configurations; ensure that 1100 * the read-out managed value is consistent with what we write in. 1101 */ 1102 @SmallTest testOverrideStreamConfigurationMap()1103 public void testOverrideStreamConfigurationMap() { 1104 1105 /* 1106 * First, write all the raw values: 1107 * - availableStreamConfigurations 1108 * - availableMinFrameDurations 1109 * - availableStallDurations 1110 * 1111 * Then, read this out as a synthetic multi-key 'streamConfigurationMap' 1112 * 1113 * Finally, validate that the map was unmarshaled correctly 1114 * and is converting the internal formats to public formats properly. 1115 */ 1116 1117 // 1118 // android.scaler.availableStreamConfigurations (int x n x 4 array) 1119 // 1120 final int OUTPUT = 0; 1121 final int INPUT = 1; 1122 int[] rawAvailableStreamConfigs = new int[] { 1123 0x20, 3280, 2464, OUTPUT, // RAW16 1124 0x23, 3264, 2448, OUTPUT, // YCbCr_420_888 1125 0x23, 3200, 2400, OUTPUT, // YCbCr_420_888 1126 0x21, 3264, 2448, OUTPUT, // BLOB 1127 0x21, 3200, 2400, OUTPUT, // BLOB 1128 0x21, 2592, 1944, OUTPUT, // BLOB 1129 0x21, 2048, 1536, OUTPUT, // BLOB 1130 0x21, 1920, 1080, OUTPUT, // BLOB 1131 0x22, 640, 480, OUTPUT, // IMPLEMENTATION_DEFINED 1132 0x20, 320, 240, INPUT, // RAW16 1133 }; 1134 Key<StreamConfiguration[]> configKey = 1135 CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS.getNativeKey(); 1136 mMetadata.writeValues(configKey.getTag(), 1137 toByteArray(rawAvailableStreamConfigs)); 1138 1139 // 1140 // android.scaler.availableMinFrameDurations (int x n x 4 array) 1141 // 1142 long[] expectedAvailableMinDurations = new long[] { 1143 0x20, 3280, 2464, 33333331, // RAW16 1144 0x23, 3264, 2448, 33333332, // YCbCr_420_888 1145 0x23, 3200, 2400, 33333333, // YCbCr_420_888 1146 0x100, 3264, 2448, 33333334, // ImageFormat.JPEG 1147 0x100, 3200, 2400, 33333335, // ImageFormat.JPEG 1148 0x100, 2592, 1944, 33333336, // ImageFormat.JPEG 1149 0x100, 2048, 1536, 33333337, // ImageFormat.JPEG 1150 0x100, 1920, 1080, 33333338 // ImageFormat.JPEG 1151 }; 1152 long[] rawAvailableMinDurations = new long[] { 1153 0x20, 3280, 2464, 33333331, // RAW16 1154 0x23, 3264, 2448, 33333332, // YCbCr_420_888 1155 0x23, 3200, 2400, 33333333, // YCbCr_420_888 1156 0x21, 3264, 2448, 33333334, // BLOB 1157 0x21, 3200, 2400, 33333335, // BLOB 1158 0x21, 2592, 1944, 33333336, // BLOB 1159 0x21, 2048, 1536, 33333337, // BLOB 1160 0x21, 1920, 1080, 33333338 // BLOB 1161 }; 1162 Key<StreamConfigurationDuration[]> durationKey = 1163 CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS.getNativeKey(); 1164 mMetadata.writeValues(durationKey.getTag(), 1165 toByteArray(rawAvailableMinDurations)); 1166 1167 // 1168 // android.scaler.availableStallDurations (int x n x 4 array) 1169 // 1170 long[] expectedAvailableStallDurations = new long[] { 1171 0x20, 3280, 2464, 0, // RAW16 1172 0x23, 3264, 2448, 0, // YCbCr_420_888 1173 0x23, 3200, 2400, 0, // YCbCr_420_888 1174 0x100, 3264, 2448, 33333334, // ImageFormat.JPEG 1175 0x100, 3200, 2400, 33333335, // ImageFormat.JPEG 1176 0x100, 2592, 1944, 33333336, // ImageFormat.JPEG 1177 0x100, 2048, 1536, 33333337, // ImageFormat.JPEG 1178 0x100, 1920, 1080, 33333338 // ImageFormat.JPEG 1179 }; 1180 // Note: RAW16 and YUV_420_888 omitted intentionally; omitted values should default to 0 1181 long[] rawAvailableStallDurations = new long[] { 1182 0x21, 3264, 2448, 33333334, // BLOB 1183 0x21, 3200, 2400, 33333335, // BLOB 1184 0x21, 2592, 1944, 33333336, // BLOB 1185 0x21, 2048, 1536, 33333337, // BLOB 1186 0x21, 1920, 1080, 33333338 // BLOB 1187 }; 1188 Key<StreamConfigurationDuration[]> stallDurationKey = 1189 CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS.getNativeKey(); 1190 mMetadata.writeValues(stallDurationKey.getTag(), 1191 toByteArray(rawAvailableStallDurations)); 1192 1193 // 1194 // android.scaler.streamConfigurationMap (synthetic as StreamConfigurationMap) 1195 // 1196 StreamConfigurationMap streamConfigMap = mMetadata.get( 1197 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 1198 1199 // Inputs 1200 checkStreamConfigurationMapByFormatSize( 1201 streamConfigMap, ImageFormat.RAW_SENSOR, 320, 240, /*output*/false); 1202 1203 // Outputs 1204 checkStreamConfigurationMapByFormatSize( 1205 streamConfigMap, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 640, 480, /*output*/true); 1206 checkStreamConfigurationMapByFormatSize( 1207 streamConfigMap, ImageFormat.JPEG, 1920, 1080, /*output*/true); 1208 checkStreamConfigurationMapByFormatSize( 1209 streamConfigMap, ImageFormat.JPEG, 2048, 1536, /*output*/true); 1210 checkStreamConfigurationMapByFormatSize( 1211 streamConfigMap, ImageFormat.JPEG, 2592, 1944, /*output*/true); 1212 checkStreamConfigurationMapByFormatSize( 1213 streamConfigMap, ImageFormat.JPEG, 3200, 2400, /*output*/true); 1214 checkStreamConfigurationMapByFormatSize( 1215 streamConfigMap, ImageFormat.YUV_420_888, 3200, 2400, /*output*/true); 1216 checkStreamConfigurationMapByFormatSize( 1217 streamConfigMap, ImageFormat.YUV_420_888, 3264, 2448, /*output*/true); 1218 checkStreamConfigurationMapByFormatSize( 1219 streamConfigMap, ImageFormat.RAW_SENSOR, 3280, 2464, /*output*/true); 1220 1221 // Min Frame Durations 1222 1223 final int DURATION_TUPLE_SIZE = 4; 1224 for (int i = 0; i < expectedAvailableMinDurations.length; i += DURATION_TUPLE_SIZE) { 1225 checkStreamConfigurationMapDurationByFormatSize( 1226 streamConfigMap, 1227 (int)expectedAvailableMinDurations[i], 1228 (int)expectedAvailableMinDurations[i+1], 1229 (int)expectedAvailableMinDurations[i+2], 1230 Duration.MinFrame, 1231 expectedAvailableMinDurations[i+3]); 1232 } 1233 1234 // Stall Frame Durations 1235 1236 for (int i = 0; i < expectedAvailableStallDurations.length; i += DURATION_TUPLE_SIZE) { 1237 checkStreamConfigurationMapDurationByFormatSize( 1238 streamConfigMap, 1239 (int)expectedAvailableStallDurations[i], 1240 (int)expectedAvailableStallDurations[i+1], 1241 (int)expectedAvailableStallDurations[i+2], 1242 Duration.Stall, 1243 expectedAvailableStallDurations[i+3]); 1244 } 1245 } 1246 assertKeyValueEquals(T expected, CameraCharacteristics.Key<T> key)1247 private <T> void assertKeyValueEquals(T expected, CameraCharacteristics.Key<T> key) { 1248 assertKeyValueEquals(expected, key.getNativeKey()); 1249 } 1250 assertKeyValueEquals(T expected, Key<T> key)1251 private <T> void assertKeyValueEquals(T expected, Key<T> key) { 1252 T actual = mMetadata.get(key); 1253 1254 assertEquals("Expected value for key " + key + " to match", expected, actual); 1255 } 1256 1257 @SmallTest testOverrideMaxRegions()1258 public void testOverrideMaxRegions() { 1259 // All keys are null before doing any writes. 1260 assertKeyValueEquals(null, CameraCharacteristics.CONTROL_MAX_REGIONS_AE); 1261 assertKeyValueEquals(null, CameraCharacteristics.CONTROL_MAX_REGIONS_AWB); 1262 assertKeyValueEquals(null, CameraCharacteristics.CONTROL_MAX_REGIONS_AF); 1263 1264 mMetadata.set(CameraCharacteristics.CONTROL_MAX_REGIONS, 1265 new int[] { /*AE*/1, /*AWB*/2, /*AF*/3 }); 1266 1267 // All keys are the expected value after doing a write 1268 assertKeyValueEquals(1, CameraCharacteristics.CONTROL_MAX_REGIONS_AE); 1269 assertKeyValueEquals(2, CameraCharacteristics.CONTROL_MAX_REGIONS_AWB); 1270 assertKeyValueEquals(3, CameraCharacteristics.CONTROL_MAX_REGIONS_AF); 1271 } 1272 1273 @SmallTest testOverrideMaxNumOutputStreams()1274 public void testOverrideMaxNumOutputStreams() { 1275 // All keys are null before doing any writes. 1276 assertKeyValueEquals(null, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW); 1277 assertKeyValueEquals(null, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC); 1278 assertKeyValueEquals(null, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING); 1279 1280 mMetadata.set(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_STREAMS, 1281 new int[] { /*AE*/1, /*AWB*/2, /*AF*/3 }); 1282 1283 // All keys are the expected value after doing a write 1284 assertKeyValueEquals(1, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW); 1285 assertKeyValueEquals(2, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC); 1286 assertKeyValueEquals(3, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING); 1287 } 1288 1289 @SmallTest testCaptureResult()1290 public void testCaptureResult() { 1291 mMetadata.set(CaptureRequest.CONTROL_AE_MODE, 1292 CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH); 1293 1294 if (VERBOSE) mMetadata.dumpToLog(); 1295 1296 CaptureResult captureResult = new CaptureResult(mMetadata, /*sequenceId*/0); 1297 1298 List<CaptureResult.Key<?>> allKeys = captureResult.getKeys(); 1299 if (VERBOSE) Log.v(TAG, "testCaptureResult: key list size " + allKeys); 1300 for (CaptureResult.Key<?> key : captureResult.getKeys()) { 1301 if (VERBOSE) { 1302 Log.v(TAG, 1303 "testCaptureResult: key " + key + " value" + captureResult.get(key)); 1304 } 1305 } 1306 1307 assertTrue(allKeys.size() >= 1); // FIXME: android.statistics.faces counts as a key 1308 assertTrue(allKeys.contains(CaptureResult.CONTROL_AE_MODE)); 1309 1310 assertEquals(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH, 1311 (int)captureResult.get(CaptureResult.CONTROL_AE_MODE)); 1312 } 1313 checkStreamConfigurationMapByFormatSize(StreamConfigurationMap configMap, int format, int width, int height, boolean output)1314 private static void checkStreamConfigurationMapByFormatSize(StreamConfigurationMap configMap, 1315 int format, int width, int height, 1316 boolean output) { 1317 1318 /** arbitrary class for which StreamConfigurationMap#isOutputSupportedFor(Class) is true */ 1319 final Class<?> IMPLEMENTATION_DEFINED_OUTPUT_CLASS = SurfaceTexture.class; 1320 1321 android.util.Size[] sizes; 1322 int[] formats; 1323 1324 if (output) { 1325 if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) { 1326 sizes = configMap.getOutputSizes(IMPLEMENTATION_DEFINED_OUTPUT_CLASS); 1327 // in this case the 'is output format supported' is vacuously true 1328 formats = new int[] { HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED }; 1329 } else { 1330 sizes = configMap.getOutputSizes(format); 1331 formats = configMap.getOutputFormats(); 1332 assertTrue("Format must be supported by stream configuration map", 1333 configMap.isOutputSupportedFor(format)); 1334 } 1335 } else { 1336 // NOTE: No function to do input sizes from IMPL_DEFINED, so it would just fail for that 1337 sizes = configMap.getInputSizes(format); 1338 formats = configMap.getInputFormats(); 1339 } 1340 1341 android.util.Size expectedSize = new android.util.Size(width, height); 1342 1343 assertArrayContains(format, formats); 1344 assertArrayContains(expectedSize, sizes); 1345 } 1346 1347 private enum Duration { 1348 MinFrame, 1349 Stall 1350 } 1351 checkStreamConfigurationMapDurationByFormatSize( StreamConfigurationMap configMap, int format, int width, int height, Duration durationKind, long expectedDuration)1352 private static void checkStreamConfigurationMapDurationByFormatSize( 1353 StreamConfigurationMap configMap, 1354 int format, int width, int height, Duration durationKind, long expectedDuration) { 1355 1356 /** arbitrary class for which StreamConfigurationMap#isOutputSupportedFor(Class) is true */ 1357 final Class<?> IMPLEMENTATION_DEFINED_OUTPUT_CLASS = SurfaceTexture.class; 1358 1359 long actualDuration; 1360 1361 android.util.Size size = new android.util.Size(width, height); 1362 switch (durationKind) { 1363 case MinFrame: 1364 if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) { 1365 actualDuration = configMap.getOutputMinFrameDuration( 1366 IMPLEMENTATION_DEFINED_OUTPUT_CLASS, size); 1367 } else { 1368 actualDuration = configMap.getOutputMinFrameDuration(format, size); 1369 } 1370 1371 break; 1372 case Stall: 1373 if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) { 1374 actualDuration = configMap.getOutputStallDuration( 1375 IMPLEMENTATION_DEFINED_OUTPUT_CLASS, size); 1376 } else { 1377 actualDuration = configMap.getOutputStallDuration(format, size); 1378 } 1379 1380 break; 1381 default: 1382 throw new AssertionError(); 1383 } 1384 1385 assertEquals("Expected " + durationKind + " to match actual value", expectedDuration, 1386 actualDuration); 1387 } 1388 1389 /** 1390 * Validate metadata array tag read/write override. 1391 * 1392 * <p>Only support long and int array for now, can be easily extend to support other 1393 * primitive arrays.</p> 1394 */ validateArrayMetadataReadWriteOverride(Key<T> key, T expectedWriteValues, T expectedReadValues, int tag)1395 private <T> void validateArrayMetadataReadWriteOverride(Key<T> key, T expectedWriteValues, 1396 T expectedReadValues, int tag) { 1397 Class<?> type = expectedWriteValues.getClass(); 1398 if (!type.isArray()) { 1399 throw new IllegalArgumentException("This function expects an key with array type"); 1400 } else if (type != int[].class && type != long[].class) { 1401 throw new IllegalArgumentException("This function expects long or int array values"); 1402 } 1403 1404 // Write 1405 mMetadata.set(key, expectedWriteValues); 1406 1407 byte[] readOutValues = mMetadata.readValues(tag); 1408 1409 ByteBuffer bf = ByteBuffer.wrap(readOutValues).order(ByteOrder.nativeOrder()); 1410 1411 int readValuesLength = Array.getLength(expectedReadValues); 1412 int readValuesNumBytes = readValuesLength * 4; 1413 if (type == long[].class) { 1414 readValuesNumBytes = readValuesLength * 8; 1415 } 1416 1417 assertEquals(readValuesNumBytes, readOutValues.length); 1418 for (int i = 0; i < readValuesLength; ++i) { 1419 if (type == int[].class) { 1420 assertEquals(Array.getInt(expectedReadValues, i), bf.getInt()); 1421 } else if (type == long[].class) { 1422 assertEquals(Array.getLong(expectedReadValues, i), bf.getLong()); 1423 } 1424 } 1425 1426 // Read 1427 byte[] readOutValuesAsByteArray = new byte[readValuesNumBytes]; 1428 ByteBuffer readOutValuesByteBuffer = 1429 ByteBuffer.wrap(readOutValuesAsByteArray).order(ByteOrder.nativeOrder()); 1430 for (int i = 0; i < readValuesLength; ++i) { 1431 if (type == int[].class) { 1432 readOutValuesByteBuffer.putInt(Array.getInt(expectedReadValues, i)); 1433 } else if (type == long[].class) { 1434 readOutValuesByteBuffer.putLong(Array.getLong(expectedReadValues, i)); 1435 } 1436 } 1437 mMetadata.writeValues(tag, readOutValuesAsByteArray); 1438 1439 T result = mMetadata.get(key); 1440 assertNotNull(key.getName() + " result shouldn't be null", result); 1441 assertArrayEquals(expectedWriteValues, result); 1442 } 1443 1444 // TODO: move somewhere else 1445 @SmallTest testToByteArray()1446 public void testToByteArray() { 1447 assertArrayEquals(new byte[] { 5, 0, 0, 0, 6, 0, 0, 0 }, 1448 toByteArray(5, 6)); 1449 assertArrayEquals(new byte[] { 5, 0, 6, 0, }, 1450 toByteArray((short)5, (short)6)); 1451 assertArrayEquals(new byte[] { (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, 1452 (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,}, 1453 toByteArray(~0, ~0)); 1454 1455 assertArrayEquals(new byte[] { (byte)0xAB, (byte)0xFF, 0, 0, 1456 0x0D, (byte)0xF0, (byte)0xAD, (byte)0xDE }, 1457 toByteArray(0xFFAB, 0xDEADF00D)); 1458 } 1459 } 1460