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