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