1 /* 2 * Copyright (C) 2014 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 android.hardware.camera2.cts; 18 19 import android.content.Context; 20 import android.graphics.ImageFormat; 21 import android.graphics.Rect; 22 import android.graphics.SurfaceTexture; 23 import android.hardware.camera2.CameraCharacteristics; 24 import android.hardware.camera2.CameraCharacteristics.Key; 25 import android.hardware.camera2.CameraManager; 26 import android.hardware.camera2.CaptureRequest; 27 import android.hardware.camera2.cts.helpers.CameraErrorCollector; 28 import android.hardware.camera2.params.BlackLevelPattern; 29 import android.hardware.camera2.params.ColorSpaceTransform; 30 import android.hardware.camera2.params.StreamConfigurationMap; 31 import android.media.CamcorderProfile; 32 import android.media.ImageReader; 33 import android.test.AndroidTestCase; 34 import android.util.Log; 35 import android.util.Rational; 36 import android.util.Range; 37 import android.util.Size; 38 import android.view.Surface; 39 40 import java.util.ArrayList; 41 import java.util.Arrays; 42 import java.util.List; 43 import java.util.Objects; 44 45 import static android.hardware.camera2.cts.helpers.AssertHelpers.*; 46 47 /** 48 * Extended tests for static camera characteristics. 49 */ 50 public class ExtendedCameraCharacteristicsTest extends AndroidTestCase { 51 private static final String TAG = "ExChrsTest"; // must be short so next line doesn't throw 52 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 53 54 private static final String PREFIX_ANDROID = "android"; 55 private static final String PREFIX_VENDOR = "com"; 56 57 /* 58 * Constants for static RAW metadata. 59 */ 60 private static final int MIN_ALLOWABLE_WHITELEVEL = 32; // must have sensor bit depth > 5 61 62 private CameraManager mCameraManager; 63 private List<CameraCharacteristics> mCharacteristics; 64 private String[] mIds; 65 private CameraErrorCollector mCollector; 66 67 private static final Size FULLHD = new Size(1920, 1080); 68 private static final Size FULLHD_ALT = new Size(1920, 1088); 69 private static final Size HD = new Size(1280, 720); 70 private static final Size VGA = new Size(640, 480); 71 private static final Size QVGA = new Size(320, 240); 72 73 /* 74 * HW Levels short hand 75 */ 76 private static final int LEGACY = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY; 77 private static final int LIMITED = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED; 78 private static final int FULL = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL; 79 private static final int OPT = Integer.MAX_VALUE; // For keys that are optional on all hardware levels. 80 81 /* 82 * Capabilities short hand 83 */ 84 private static final int NONE = -1; 85 private static final int BC = 86 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE; 87 private static final int MANUAL_SENSOR = 88 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR; 89 private static final int MANUAL_POSTPROC = 90 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING; 91 private static final int RAW = 92 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW; 93 private static final int YUV_REPROCESS = 94 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING; 95 private static final int OPAQUE_REPROCESS = 96 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING; 97 private static final int CONSTRAINED_HIGH_SPEED = 98 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO; 99 private static final int HIGH_SPEED_FPS_LOWER_MIN = 30; 100 private static final int HIGH_SPEED_FPS_UPPER_MIN = 120; 101 102 @Override setContext(Context context)103 public void setContext(Context context) { 104 super.setContext(context); 105 mCameraManager = (CameraManager)context.getSystemService(Context.CAMERA_SERVICE); 106 assertNotNull("Can't connect to camera manager", mCameraManager); 107 } 108 109 @Override setUp()110 protected void setUp() throws Exception { 111 super.setUp(); 112 mIds = mCameraManager.getCameraIdList(); 113 mCharacteristics = new ArrayList<>(); 114 mCollector = new CameraErrorCollector(); 115 for (int i = 0; i < mIds.length; i++) { 116 CameraCharacteristics props = mCameraManager.getCameraCharacteristics(mIds[i]); 117 assertNotNull(String.format("Can't get camera characteristics from: ID %s", mIds[i]), 118 props); 119 mCharacteristics.add(props); 120 } 121 } 122 123 @Override tearDown()124 protected void tearDown() throws Exception { 125 mCharacteristics = null; 126 127 try { 128 mCollector.verify(); 129 } catch (Throwable e) { 130 // When new Exception(e) is used, exception info will be printed twice. 131 throw new Exception(e.getMessage()); 132 } finally { 133 super.tearDown(); 134 } 135 } 136 137 /** 138 * Test that the available stream configurations contain a few required formats and sizes. 139 */ testAvailableStreamConfigs()140 public void testAvailableStreamConfigs() { 141 int counter = 0; 142 for (CameraCharacteristics c : mCharacteristics) { 143 StreamConfigurationMap config = 144 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 145 assertNotNull(String.format("No stream configuration map found for: ID %s", 146 mIds[counter]), config); 147 int[] outputFormats = config.getOutputFormats(); 148 149 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 150 assertNotNull("android.request.availableCapabilities must never be null", 151 actualCapabilities); 152 153 // Check required formats exist (JPEG, and YUV_420_888). 154 if (!arrayContains(actualCapabilities, BC)) { 155 Log.i(TAG, "Camera " + mIds[counter] + 156 ": BACKWARD_COMPATIBLE capability not supported, skipping test"); 157 continue; 158 } 159 160 assertArrayContains( 161 String.format("No valid YUV_420_888 preview formats found for: ID %s", 162 mIds[counter]), outputFormats, ImageFormat.YUV_420_888); 163 assertArrayContains(String.format("No JPEG image format for: ID %s", 164 mIds[counter]), outputFormats, ImageFormat.JPEG); 165 166 Size[] yuvSizes = config.getOutputSizes(ImageFormat.YUV_420_888); 167 Size[] jpegSizes = config.getOutputSizes(ImageFormat.JPEG); 168 Size[] privateSizes = config.getOutputSizes(ImageFormat.PRIVATE); 169 170 CameraTestUtils.assertArrayNotEmpty(yuvSizes, 171 String.format("No sizes for preview format %x for: ID %s", 172 ImageFormat.YUV_420_888, mIds[counter])); 173 174 Rect activeRect = CameraTestUtils.getValueNotNull( 175 c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 176 Size activeArraySize = new Size(activeRect.width(), activeRect.height()); 177 Integer hwLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 178 179 if (activeArraySize.getWidth() >= FULLHD.getWidth() && 180 activeArraySize.getHeight() >= FULLHD.getHeight()) { 181 assertArrayContainsAnyOf(String.format( 182 "Required FULLHD size not found for format %x for: ID %s", 183 ImageFormat.JPEG, mIds[counter]), jpegSizes, 184 new Size[] {FULLHD, FULLHD_ALT}); 185 } 186 187 if (activeArraySize.getWidth() >= HD.getWidth() && 188 activeArraySize.getHeight() >= HD.getHeight()) { 189 assertArrayContains(String.format( 190 "Required HD size not found for format %x for: ID %s", 191 ImageFormat.JPEG, mIds[counter]), jpegSizes, HD); 192 } 193 194 if (activeArraySize.getWidth() >= VGA.getWidth() && 195 activeArraySize.getHeight() >= VGA.getHeight()) { 196 assertArrayContains(String.format( 197 "Required VGA size not found for format %x for: ID %s", 198 ImageFormat.JPEG, mIds[counter]), jpegSizes, VGA); 199 } 200 201 if (activeArraySize.getWidth() >= QVGA.getWidth() && 202 activeArraySize.getHeight() >= QVGA.getHeight()) { 203 assertArrayContains(String.format( 204 "Required QVGA size not found for format %x for: ID %s", 205 ImageFormat.JPEG, mIds[counter]), jpegSizes, QVGA); 206 } 207 208 ArrayList<Size> jpegSizesList = new ArrayList<>(Arrays.asList(jpegSizes)); 209 ArrayList<Size> yuvSizesList = new ArrayList<>(Arrays.asList(yuvSizes)); 210 ArrayList<Size> privateSizesList = new ArrayList<>(Arrays.asList(privateSizes)); 211 212 CamcorderProfile maxVideoProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH); 213 Size maxVideoSize = new Size( 214 maxVideoProfile.videoFrameWidth, maxVideoProfile.videoFrameHeight); 215 216 // Handle FullHD special case first 217 if (jpegSizesList.contains(FULLHD)) { 218 if (hwLevel == FULL || (hwLevel == LIMITED && 219 maxVideoSize.getWidth() >= FULLHD.getWidth() && 220 maxVideoSize.getHeight() >= FULLHD.getHeight())) { 221 boolean yuvSupportFullHD = yuvSizesList.contains(FULLHD) || 222 yuvSizesList.contains(FULLHD_ALT); 223 boolean privateSupportFullHD = privateSizesList.contains(FULLHD) || 224 privateSizesList.contains(FULLHD_ALT); 225 assertTrue("Full device FullHD YUV size not found", yuvSupportFullHD); 226 assertTrue("Full device FullHD PRIVATE size not found", privateSupportFullHD); 227 } 228 // remove all FullHD or FullHD_Alt sizes for the remaining of the test 229 jpegSizesList.remove(FULLHD); 230 jpegSizesList.remove(FULLHD_ALT); 231 } 232 233 // Check all sizes other than FullHD 234 if (hwLevel == LIMITED) { 235 // Remove all jpeg sizes larger than max video size 236 ArrayList<Size> toBeRemoved = new ArrayList<>(); 237 for (Size size : jpegSizesList) { 238 if (size.getWidth() >= maxVideoSize.getWidth() && 239 size.getHeight() >= maxVideoSize.getHeight()) { 240 toBeRemoved.add(size); 241 } 242 } 243 jpegSizesList.removeAll(toBeRemoved); 244 } 245 246 if (hwLevel == FULL || hwLevel == LIMITED) { 247 if (!yuvSizesList.containsAll(jpegSizesList)) { 248 for (Size s : jpegSizesList) { 249 if (!yuvSizesList.contains(s)) { 250 fail("Size " + s + " not found in YUV format"); 251 } 252 } 253 } 254 } 255 256 if (!privateSizesList.containsAll(yuvSizesList)) { 257 for (Size s : yuvSizesList) { 258 if (!privateSizesList.contains(s)) { 259 fail("Size " + s + " not found in PRIVATE format"); 260 } 261 } 262 } 263 264 counter++; 265 } 266 } 267 268 /** 269 * Test {@link CameraCharacteristics#getKeys} 270 */ testKeys()271 public void testKeys() { 272 int counter = 0; 273 for (CameraCharacteristics c : mCharacteristics) { 274 mCollector.setCameraId(mIds[counter]); 275 276 if (VERBOSE) { 277 Log.v(TAG, "testKeys - testing characteristics for camera " + mIds[counter]); 278 } 279 280 List<CameraCharacteristics.Key<?>> allKeys = c.getKeys(); 281 assertNotNull("Camera characteristics keys must not be null", allKeys); 282 assertFalse("Camera characteristics keys must have at least 1 key", 283 allKeys.isEmpty()); 284 285 for (CameraCharacteristics.Key<?> key : allKeys) { 286 assertKeyPrefixValid(key.getName()); 287 288 // All characteristics keys listed must never be null 289 mCollector.expectKeyValueNotNull(c, key); 290 291 // TODO: add a check that key must not be @hide 292 } 293 294 /* 295 * List of keys that must be present in camera characteristics (not null). 296 * 297 * Keys for LIMITED, FULL devices might be available despite lacking either 298 * the hardware level or the capability. This is *OK*. This only lists the 299 * *minimal* requirements for a key to be listed. 300 * 301 * LEGACY devices are a bit special since they map to api1 devices, so we know 302 * for a fact most keys are going to be illegal there so they should never be 303 * available. 304 * 305 * For LIMITED-level keys, if the level is >= LIMITED, then the capabilities are used to 306 * do the actual checking. 307 */ 308 { 309 // (Key Name) (HW Level) (Capabilities <Var-Arg>) 310 expectKeyAvailable(c, CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES , OPT , BC ); 311 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_MODES , OPT , BC ); 312 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_ANTIBANDING_MODES , OPT , BC ); 313 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES , OPT , BC ); 314 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES , OPT , BC ); 315 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE , OPT , BC ); 316 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP , OPT , BC ); 317 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE , OPT , BC ); 318 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES , OPT , BC ); 319 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS , OPT , BC ); 320 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES , OPT , BC ); 321 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES , OPT , BC ); 322 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES , OPT , BC ); 323 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE , OPT , BC ); 324 expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AE , OPT , BC ); 325 expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AF , OPT , BC ); 326 expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AWB , OPT , BC ); 327 expectKeyAvailable(c, CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES , FULL , NONE ); 328 expectKeyAvailable(c, CameraCharacteristics.FLASH_INFO_AVAILABLE , OPT , BC ); 329 expectKeyAvailable(c, CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES , OPT , RAW ); 330 expectKeyAvailable(c, CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL , OPT , BC ); 331 expectKeyAvailable(c, CameraCharacteristics.JPEG_AVAILABLE_THUMBNAIL_SIZES , OPT , BC ); 332 expectKeyAvailable(c, CameraCharacteristics.LENS_FACING , OPT , BC ); 333 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES , FULL , MANUAL_SENSOR ); 334 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_FILTER_DENSITIES , FULL , MANUAL_SENSOR ); 335 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS , OPT , BC ); 336 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION , LIMITED , BC ); 337 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_FOCUS_DISTANCE_CALIBRATION , LIMITED , MANUAL_SENSOR ); 338 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_HYPERFOCAL_DISTANCE , LIMITED , BC ); 339 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE , LIMITED , BC ); 340 expectKeyAvailable(c, CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES , OPT , BC ); 341 expectKeyAvailable(c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES , OPT , BC ); 342 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_INPUT_STREAMS , OPT , YUV_REPROCESS, OPAQUE_REPROCESS); 343 expectKeyAvailable(c, CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP , OPT , CONSTRAINED_HIGH_SPEED); 344 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC , OPT , BC ); 345 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING , OPT , BC ); 346 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW , OPT , BC ); 347 expectKeyAvailable(c, CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT , OPT , BC ); 348 expectKeyAvailable(c, CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH , OPT , BC ); 349 expectKeyAvailable(c, CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM , OPT , BC ); 350 expectKeyAvailable(c, CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP , OPT , BC ); 351 expectKeyAvailable(c, CameraCharacteristics.SCALER_CROPPING_TYPE , OPT , BC ); 352 expectKeyAvailable(c, CameraCharacteristics.SENSOR_AVAILABLE_TEST_PATTERN_MODES , OPT , BC ); 353 expectKeyAvailable(c, CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN , FULL , MANUAL_SENSOR, RAW ); 354 expectKeyAvailable(c, CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM1 , OPT , RAW ); 355 expectKeyAvailable(c, CameraCharacteristics.SENSOR_COLOR_TRANSFORM1 , OPT , RAW ); 356 expectKeyAvailable(c, CameraCharacteristics.SENSOR_FORWARD_MATRIX1 , OPT , RAW ); 357 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE , OPT , BC, RAW ); 358 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT , FULL , RAW ); 359 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE , FULL , MANUAL_SENSOR ); 360 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_MAX_FRAME_DURATION , FULL , MANUAL_SENSOR ); 361 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE , OPT , BC ); 362 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE , OPT , BC ); 363 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE , FULL , MANUAL_SENSOR ); 364 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL , OPT , RAW ); 365 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE , OPT , BC ); 366 expectKeyAvailable(c, CameraCharacteristics.SENSOR_MAX_ANALOG_SENSITIVITY , FULL , MANUAL_SENSOR ); 367 expectKeyAvailable(c, CameraCharacteristics.SENSOR_ORIENTATION , OPT , BC ); 368 expectKeyAvailable(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1 , OPT , RAW ); 369 expectKeyAvailable(c, CameraCharacteristics.SHADING_AVAILABLE_MODES , LIMITED , MANUAL_POSTPROC, RAW ); 370 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES , OPT , BC ); 371 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES , OPT , RAW ); 372 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, LIMITED , RAW ); 373 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT , OPT , BC ); 374 expectKeyAvailable(c, CameraCharacteristics.SYNC_MAX_LATENCY , OPT , BC ); 375 expectKeyAvailable(c, CameraCharacteristics.TONEMAP_AVAILABLE_TONE_MAP_MODES , FULL , MANUAL_POSTPROC ); 376 expectKeyAvailable(c, CameraCharacteristics.TONEMAP_MAX_CURVE_POINTS , FULL , MANUAL_POSTPROC ); 377 378 // Future: Use column editors for modifying above, ignore line length to keep 1 key per line 379 380 // TODO: check that no other 'android' keys are listed in #getKeys if they aren't in the above list 381 } 382 383 // Only check for these if the second reference illuminant is included 384 if (allKeys.contains(CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2)) { 385 expectKeyAvailable(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2 , OPT , RAW ); 386 expectKeyAvailable(c, CameraCharacteristics.SENSOR_COLOR_TRANSFORM2 , OPT , RAW ); 387 expectKeyAvailable(c, CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM2 , OPT , RAW ); 388 expectKeyAvailable(c, CameraCharacteristics.SENSOR_FORWARD_MATRIX2 , OPT , RAW ); 389 } 390 391 counter++; 392 } 393 } 394 395 /** 396 * Test values for static metadata used by the RAW capability. 397 */ testStaticRawCharacteristics()398 public void testStaticRawCharacteristics() { 399 int counter = 0; 400 for (CameraCharacteristics c : mCharacteristics) { 401 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 402 assertNotNull("android.request.availableCapabilities must never be null", 403 actualCapabilities); 404 if (!arrayContains(actualCapabilities, 405 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 406 Log.i(TAG, "RAW capability is not supported in camera " + counter++ + 407 ". Skip the test."); 408 continue; 409 } 410 411 Integer actualHwLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 412 if (actualHwLevel != null && actualHwLevel == FULL) { 413 mCollector.expectKeyValueContains(c, 414 CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES, 415 CameraCharacteristics.HOT_PIXEL_MODE_FAST); 416 } 417 mCollector.expectKeyValueContains(c, 418 CameraCharacteristics.STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES, false); 419 mCollector.expectKeyValueGreaterThan(c, CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL, 420 MIN_ALLOWABLE_WHITELEVEL); 421 422 mCollector.expectKeyValueIsIn(c, 423 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT, 424 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB, 425 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG, 426 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG, 427 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR); 428 // TODO: SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB isn't supported yet. 429 430 mCollector.expectKeyValueInRange(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1, 431 CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT, 432 CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN); 433 mCollector.expectKeyValueInRange(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2, 434 (byte) CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT, 435 (byte) CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN); 436 437 Rational[] zeroes = new Rational[9]; 438 Arrays.fill(zeroes, Rational.ZERO); 439 440 ColorSpaceTransform zeroed = new ColorSpaceTransform(zeroes); 441 mCollector.expectNotEquals("Forward Matrix1 should not contain all zeroes.", zeroed, 442 c.get(CameraCharacteristics.SENSOR_FORWARD_MATRIX1)); 443 mCollector.expectNotEquals("Forward Matrix2 should not contain all zeroes.", zeroed, 444 c.get(CameraCharacteristics.SENSOR_FORWARD_MATRIX2)); 445 mCollector.expectNotEquals("Calibration Transform1 should not contain all zeroes.", 446 zeroed, c.get(CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM1)); 447 mCollector.expectNotEquals("Calibration Transform2 should not contain all zeroes.", 448 zeroed, c.get(CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM2)); 449 mCollector.expectNotEquals("Color Transform1 should not contain all zeroes.", 450 zeroed, c.get(CameraCharacteristics.SENSOR_COLOR_TRANSFORM1)); 451 mCollector.expectNotEquals("Color Transform2 should not contain all zeroes.", 452 zeroed, c.get(CameraCharacteristics.SENSOR_COLOR_TRANSFORM2)); 453 454 BlackLevelPattern blackLevel = mCollector.expectKeyValueNotNull(c, 455 CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN); 456 if (blackLevel != null) { 457 String blackLevelPatternString = blackLevel.toString(); 458 if (VERBOSE) { 459 Log.v(TAG, "Black level pattern: " + blackLevelPatternString); 460 } 461 int[] blackLevelPattern = new int[BlackLevelPattern.COUNT]; 462 blackLevel.copyTo(blackLevelPattern, /*offset*/0); 463 Integer whitelevel = c.get(CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL); 464 if (whitelevel != null) { 465 mCollector.expectValuesInRange("BlackLevelPattern", blackLevelPattern, 0, 466 whitelevel); 467 } else { 468 mCollector.addMessage( 469 "No WhiteLevel available, cannot check BlackLevelPattern range."); 470 } 471 } 472 473 // TODO: profileHueSatMap, and profileToneCurve aren't supported yet. 474 counter++; 475 } 476 } 477 478 /** 479 * Test values for static metadata used by the BURST capability. 480 */ testStaticBurstCharacteristics()481 public void testStaticBurstCharacteristics() throws Exception { 482 int counter = 0; 483 final float SIZE_ERROR_MARGIN = 0.03f; 484 for (CameraCharacteristics c : mCharacteristics) { 485 int[] actualCapabilities = CameraTestUtils.getValueNotNull( 486 c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 487 488 // Check if the burst capability is defined 489 boolean haveBurstCapability = arrayContains(actualCapabilities, 490 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE); 491 boolean haveBC = arrayContains(actualCapabilities, 492 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE); 493 494 if(haveBurstCapability && !haveBC) { 495 fail("Must have BACKWARD_COMPATIBLE capability if BURST_CAPTURE capability is defined"); 496 } 497 498 if (!haveBC) continue; 499 500 StreamConfigurationMap config = 501 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 502 assertNotNull(String.format("No stream configuration map found for: ID %s", 503 mIds[counter]), config); 504 Rect activeRect = CameraTestUtils.getValueNotNull( 505 c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 506 Size sensorSize = new Size(activeRect.width(), activeRect.height()); 507 508 // Ensure that max YUV size matches max JPEG size 509 Size maxYuvSize = CameraTestUtils.getMaxSize( 510 config.getOutputSizes(ImageFormat.YUV_420_888)); 511 Size maxFastYuvSize = maxYuvSize; 512 513 Size[] slowYuvSizes = config.getHighResolutionOutputSizes(ImageFormat.YUV_420_888); 514 if (haveBurstCapability && slowYuvSizes != null && slowYuvSizes.length > 0) { 515 Size maxSlowYuvSize = CameraTestUtils.getMaxSize(slowYuvSizes); 516 maxYuvSize = CameraTestUtils.getMaxSize(new Size[]{maxYuvSize, maxSlowYuvSize}); 517 } 518 519 Size maxJpegSize = CameraTestUtils.getMaxSize(CameraTestUtils.getSupportedSizeForFormat( 520 ImageFormat.JPEG, mIds[counter], mCameraManager)); 521 522 boolean haveMaxYuv = maxYuvSize != null ? 523 (maxJpegSize.getWidth() <= maxYuvSize.getWidth() && 524 maxJpegSize.getHeight() <= maxYuvSize.getHeight()) : false; 525 526 boolean maxYuvMatchSensor = 527 (maxYuvSize.getWidth() <= sensorSize.getWidth() * (1.0 + SIZE_ERROR_MARGIN) && 528 maxYuvSize.getWidth() >= sensorSize.getWidth() * (1.0 - SIZE_ERROR_MARGIN) && 529 maxYuvSize.getHeight() <= sensorSize.getHeight() * (1.0 + SIZE_ERROR_MARGIN) && 530 maxYuvSize.getHeight() >= sensorSize.getHeight() * (1.0 - SIZE_ERROR_MARGIN)); 531 532 // No need to do null check since framework will generate the key if HAL don't supply 533 boolean haveAeLock = CameraTestUtils.getValueNotNull( 534 c, CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE); 535 boolean haveAwbLock = CameraTestUtils.getValueNotNull( 536 c, CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE); 537 538 // Ensure that max YUV output is fast enough - needs to be at least 10 fps 539 540 long maxYuvRate = 541 config.getOutputMinFrameDuration(ImageFormat.YUV_420_888, maxYuvSize); 542 final long MIN_MAXSIZE_DURATION_BOUND_NS = 100000000; // 100 ms, 10 fps 543 boolean haveMaxYuvRate = maxYuvRate <= MIN_MAXSIZE_DURATION_BOUND_NS; 544 545 // Ensure that some >=8MP YUV output is fast enough - needs to be at least 20 fps 546 547 long maxFastYuvRate = 548 config.getOutputMinFrameDuration(ImageFormat.YUV_420_888, maxFastYuvSize); 549 final long MIN_8MP_DURATION_BOUND_NS = 200000000; // 50 ms, 20 fps 550 boolean haveFastYuvRate = maxFastYuvRate <= MIN_8MP_DURATION_BOUND_NS; 551 552 final int SIZE_8MP_BOUND = 8000000; 553 boolean havefast8MPYuv = (maxFastYuvSize.getWidth() * maxFastYuvSize.getHeight()) > 554 SIZE_8MP_BOUND; 555 556 // Ensure that there's an FPS range that's fast enough to capture at above 557 // minFrameDuration, for full-auto bursts at the fast resolutions 558 Range[] fpsRanges = CameraTestUtils.getValueNotNull( 559 c, CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); 560 float minYuvFps = 1.f / maxFastYuvRate; 561 562 boolean haveFastAeTargetFps = false; 563 for (Range<Integer> r : fpsRanges) { 564 if (r.getLower() >= minYuvFps) { 565 haveFastAeTargetFps = true; 566 break; 567 } 568 } 569 570 // Ensure that maximum sync latency is small enough for fast setting changes, even if 571 // it's not quite per-frame 572 573 Integer maxSyncLatencyValue = c.get(CameraCharacteristics.SYNC_MAX_LATENCY); 574 assertNotNull(String.format("No sync latency declared for ID %s", mIds[counter]), 575 maxSyncLatencyValue); 576 577 int maxSyncLatency = maxSyncLatencyValue; 578 final long MAX_LATENCY_BOUND = 4; 579 boolean haveFastSyncLatency = 580 (maxSyncLatency <= MAX_LATENCY_BOUND) && (maxSyncLatency >= 0); 581 582 if (haveBurstCapability) { 583 assertTrue("Must have slow YUV size array when BURST_CAPTURE capability is defined!", 584 slowYuvSizes != null); 585 assertTrue( 586 String.format("BURST-capable camera device %s does not have maximum YUV " + 587 "size that is at least max JPEG size", 588 mIds[counter]), 589 haveMaxYuv); 590 assertTrue( 591 String.format("BURST-capable camera device %s max-resolution " + 592 "YUV frame rate is too slow" + 593 "(%d ns min frame duration reported, less than %d ns expected)", 594 mIds[counter], maxYuvRate, MIN_MAXSIZE_DURATION_BOUND_NS), 595 haveMaxYuvRate); 596 assertTrue( 597 String.format("BURST-capable camera device %s >= 8MP YUV output " + 598 "frame rate is too slow" + 599 "(%d ns min frame duration reported, less than %d ns expected)", 600 mIds[counter], maxYuvRate, MIN_8MP_DURATION_BOUND_NS), 601 haveFastYuvRate); 602 assertTrue( 603 String.format("BURST-capable camera device %s does not list an AE target " + 604 " FPS range with min FPS >= %f, for full-AUTO bursts", 605 mIds[counter], minYuvFps), 606 haveFastAeTargetFps); 607 assertTrue( 608 String.format("BURST-capable camera device %s YUV sync latency is too long" + 609 "(%d frames reported, [0, %d] frames expected)", 610 mIds[counter], maxSyncLatency, MAX_LATENCY_BOUND), 611 haveFastSyncLatency); 612 assertTrue( 613 String.format("BURST-capable camera device %s max YUV size %s should be" + 614 "close to active array size %s", 615 mIds[counter], maxYuvSize.toString(), sensorSize.toString()), 616 maxYuvMatchSensor); 617 assertTrue( 618 String.format("BURST-capable camera device %s does not support AE lock", 619 mIds[counter]), 620 haveAeLock); 621 assertTrue( 622 String.format("BURST-capable camera device %s does not support AWB lock", 623 mIds[counter]), 624 haveAwbLock); 625 } else { 626 assertTrue("Must have null slow YUV size array when no BURST_CAPTURE capability!", 627 slowYuvSizes == null); 628 assertTrue( 629 String.format("Camera device %s has all the requirements for BURST" + 630 " capability but does not report it!", mIds[counter]), 631 !(haveMaxYuv && haveMaxYuvRate && haveFastAeTargetFps && 632 haveFastSyncLatency && maxYuvMatchSensor && 633 haveAeLock && haveAwbLock)); 634 } 635 636 counter++; 637 } 638 } 639 640 /** 641 * Check reprocessing capabilities. 642 */ testReprocessingCharacteristics()643 public void testReprocessingCharacteristics() { 644 int counter = 0; 645 646 for (CameraCharacteristics c : mCharacteristics) { 647 Log.i(TAG, "testReprocessingCharacteristics: Testing camera ID " + mIds[counter]); 648 649 int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 650 assertNotNull("android.request.availableCapabilities must never be null", 651 capabilities); 652 boolean supportYUV = arrayContains(capabilities, 653 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING); 654 boolean supportOpaque = arrayContains(capabilities, 655 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING); 656 StreamConfigurationMap configs = 657 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 658 Integer maxNumInputStreams = 659 c.get(CameraCharacteristics.REQUEST_MAX_NUM_INPUT_STREAMS); 660 int[] availableEdgeModes = c.get(CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES); 661 int[] availableNoiseReductionModes = c.get( 662 CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES); 663 664 int[] inputFormats = configs.getInputFormats(); 665 666 boolean supportZslEdgeMode = false; 667 boolean supportZslNoiseReductionMode = false; 668 669 if (availableEdgeModes != null) { 670 supportZslEdgeMode = Arrays.asList(CameraTestUtils.toObject(availableEdgeModes)). 671 contains(CaptureRequest.EDGE_MODE_ZERO_SHUTTER_LAG); 672 } 673 674 if (availableNoiseReductionModes != null) { 675 supportZslNoiseReductionMode = Arrays.asList( 676 CameraTestUtils.toObject(availableNoiseReductionModes)).contains( 677 CaptureRequest.NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG); 678 } 679 680 if (supportYUV || supportOpaque) { 681 mCollector.expectTrue("Support reprocessing but max number of input stream is " + 682 maxNumInputStreams, maxNumInputStreams != null && maxNumInputStreams > 0); 683 mCollector.expectTrue("Support reprocessing but EDGE_MODE_ZERO_SHUTTER_LAG is " + 684 "not supported", supportZslEdgeMode); 685 mCollector.expectTrue("Support reprocessing but " + 686 "NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG is not supported", 687 supportZslNoiseReductionMode); 688 689 // Verify mandatory input formats are supported 690 mCollector.expectTrue("YUV_420_888 input must be supported for YUV reprocessing", 691 !supportYUV || arrayContains(inputFormats, ImageFormat.YUV_420_888)); 692 mCollector.expectTrue("PRIVATE input must be supported for OPAQUE reprocessing", 693 !supportOpaque || arrayContains(inputFormats, ImageFormat.PRIVATE)); 694 695 // max capture stall must be reported if one of the reprocessing is supported. 696 final int MAX_ALLOWED_STALL_FRAMES = 4; 697 Integer maxCaptureStall = c.get(CameraCharacteristics.REPROCESS_MAX_CAPTURE_STALL); 698 mCollector.expectTrue("max capture stall must be non-null and no larger than " 699 + MAX_ALLOWED_STALL_FRAMES, 700 maxCaptureStall != null && maxCaptureStall <= MAX_ALLOWED_STALL_FRAMES); 701 702 for (int input : inputFormats) { 703 // Verify mandatory output formats are supported 704 int[] outputFormats = configs.getValidOutputFormatsForInput(input); 705 mCollector.expectTrue("YUV_420_888 output must be supported for reprocessing", 706 arrayContains(outputFormats, ImageFormat.YUV_420_888)); 707 mCollector.expectTrue("JPEG output must be supported for reprocessing", 708 arrayContains(outputFormats, ImageFormat.JPEG)); 709 710 // Verify camera can output the reprocess input formats and sizes. 711 Size[] inputSizes = configs.getInputSizes(input); 712 Size[] outputSizes = configs.getOutputSizes(input); 713 Size[] highResOutputSizes = configs.getHighResolutionOutputSizes(input); 714 mCollector.expectTrue("no input size supported for format " + input, 715 inputSizes.length > 0); 716 mCollector.expectTrue("no output size supported for format " + input, 717 outputSizes.length > 0); 718 719 for (Size inputSize : inputSizes) { 720 mCollector.expectTrue("Camera must be able to output the supported " + 721 "reprocessing input size", 722 arrayContains(outputSizes, inputSize) || 723 arrayContains(highResOutputSizes, inputSize)); 724 } 725 } 726 } else { 727 mCollector.expectTrue("Doesn't support reprocessing but report input format: " + 728 Arrays.toString(inputFormats), inputFormats.length == 0); 729 mCollector.expectTrue("Doesn't support reprocessing but max number of input " + 730 "stream is " + maxNumInputStreams, 731 maxNumInputStreams == null || maxNumInputStreams == 0); 732 mCollector.expectTrue("Doesn't support reprocessing but " + 733 "EDGE_MODE_ZERO_SHUTTER_LAG is supported", !supportZslEdgeMode); 734 mCollector.expectTrue("Doesn't support reprocessing but " + 735 "NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG is supported", 736 !supportZslNoiseReductionMode); 737 } 738 } 739 } 740 741 /** 742 * Check depth output capability 743 */ testDepthOutputCharacteristics()744 public void testDepthOutputCharacteristics() { 745 int counter = 0; 746 747 for (CameraCharacteristics c : mCharacteristics) { 748 Log.i(TAG, "testDepthOutputCharacteristics: Testing camera ID " + mIds[counter]); 749 750 int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 751 assertNotNull("android.request.availableCapabilities must never be null", 752 capabilities); 753 boolean supportDepth = arrayContains(capabilities, 754 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT); 755 StreamConfigurationMap configs = 756 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 757 758 int[] outputFormats = configs.getOutputFormats(); 759 boolean hasDepth16 = arrayContains(outputFormats, ImageFormat.DEPTH16); 760 761 Boolean depthIsExclusive = c.get(CameraCharacteristics.DEPTH_DEPTH_IS_EXCLUSIVE); 762 763 float[] poseRotation = c.get(CameraCharacteristics.LENS_POSE_ROTATION); 764 float[] poseTranslation = c.get(CameraCharacteristics.LENS_POSE_TRANSLATION); 765 float[] cameraIntrinsics = c.get(CameraCharacteristics.LENS_INTRINSIC_CALIBRATION); 766 float[] radialDistortion = c.get(CameraCharacteristics.LENS_RADIAL_DISTORTION); 767 768 if (supportDepth) { 769 mCollector.expectTrue("Supports DEPTH_OUTPUT but does not support DEPTH16", 770 hasDepth16); 771 if (hasDepth16) { 772 Size[] depthSizes = configs.getOutputSizes(ImageFormat.DEPTH16); 773 mCollector.expectTrue("Supports DEPTH_OUTPUT but no sizes for DEPTH16 supported!", 774 depthSizes != null && depthSizes.length > 0); 775 if (depthSizes != null) { 776 for (Size depthSize : depthSizes) { 777 mCollector.expectTrue("All depth16 sizes must be positive", 778 depthSize.getWidth() > 0 && depthSize.getHeight() > 0); 779 long minFrameDuration = configs.getOutputMinFrameDuration( 780 ImageFormat.DEPTH16, depthSize); 781 mCollector.expectTrue("Non-negative min frame duration for depth size " 782 + depthSize + " expected, got " + minFrameDuration, 783 minFrameDuration >= 0); 784 long stallDuration = configs.getOutputStallDuration( 785 ImageFormat.DEPTH16, depthSize); 786 mCollector.expectTrue("Non-negative stall duration for depth size " 787 + depthSize + " expected, got " + stallDuration, 788 stallDuration >= 0); 789 } 790 } 791 } 792 if (arrayContains(outputFormats, ImageFormat.DEPTH_POINT_CLOUD)) { 793 Size[] depthCloudSizes = configs.getOutputSizes(ImageFormat.DEPTH_POINT_CLOUD); 794 mCollector.expectTrue("Supports DEPTH_POINT_CLOUD " + 795 "but no sizes for DEPTH_POINT_CLOUD supported!", 796 depthCloudSizes != null && depthCloudSizes.length > 0); 797 if (depthCloudSizes != null) { 798 for (Size depthCloudSize : depthCloudSizes) { 799 mCollector.expectTrue("All depth point cloud sizes must be nonzero", 800 depthCloudSize.getWidth() > 0); 801 mCollector.expectTrue("All depth point cloud sizes must be N x 1", 802 depthCloudSize.getHeight() == 1); 803 long minFrameDuration = configs.getOutputMinFrameDuration( 804 ImageFormat.DEPTH_POINT_CLOUD, depthCloudSize); 805 mCollector.expectTrue("Non-negative min frame duration for depth size " 806 + depthCloudSize + " expected, got " + minFrameDuration, 807 minFrameDuration >= 0); 808 long stallDuration = configs.getOutputStallDuration( 809 ImageFormat.DEPTH_POINT_CLOUD, depthCloudSize); 810 mCollector.expectTrue("Non-negative stall duration for depth size " 811 + depthCloudSize + " expected, got " + stallDuration, 812 stallDuration >= 0); 813 } 814 } 815 } 816 817 mCollector.expectTrue("Supports DEPTH_OUTPUT but DEPTH_IS_EXCLUSIVE is not defined", 818 depthIsExclusive != null); 819 820 mCollector.expectTrue( 821 "Supports DEPTH_OUTPUT but LENS_POSE_ROTATION not right size", 822 poseRotation != null && poseRotation.length == 4); 823 mCollector.expectTrue( 824 "Supports DEPTH_OUTPUT but LENS_POSE_TRANSLATION not right size", 825 poseTranslation != null && poseTranslation.length == 3); 826 mCollector.expectTrue( 827 "Supports DEPTH_OUTPUT but LENS_INTRINSIC_CALIBRATION not right size", 828 cameraIntrinsics != null && cameraIntrinsics.length == 5); 829 mCollector.expectTrue( 830 "Supports DEPTH_OUTPUT but LENS_RADIAL_DISTORTION not right size", 831 radialDistortion != null && radialDistortion.length == 6); 832 833 if (poseRotation != null && poseRotation.length == 4) { 834 float normSq = 835 poseRotation[0] * poseRotation[0] + 836 poseRotation[1] * poseRotation[1] + 837 poseRotation[2] * poseRotation[2] + 838 poseRotation[3] * poseRotation[3]; 839 mCollector.expectTrue( 840 "LENS_POSE_ROTATION quarternion must be unit-length", 841 0.9999f < normSq && normSq < 1.0001f); 842 843 // TODO: Cross-validate orientation/facing and poseRotation 844 Integer orientation = c.get(CameraCharacteristics.SENSOR_ORIENTATION); 845 Integer facing = c.get(CameraCharacteristics.LENS_FACING); 846 } 847 848 if (poseTranslation != null && poseTranslation.length == 3) { 849 float normSq = 850 poseTranslation[0] * poseTranslation[0] + 851 poseTranslation[1] * poseTranslation[1] + 852 poseTranslation[2] * poseTranslation[2]; 853 mCollector.expectTrue("Pose translation is larger than 1 m", 854 normSq < 1.f); 855 } 856 857 Rect precorrectionArray = 858 c.get(CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 859 mCollector.expectTrue("Supports DEPTH_OUTPUT but does not have " + 860 "precorrection active array defined", precorrectionArray != null); 861 862 if (cameraIntrinsics != null && precorrectionArray != null) { 863 float fx = cameraIntrinsics[0]; 864 float fy = cameraIntrinsics[1]; 865 float cx = cameraIntrinsics[2]; 866 float cy = cameraIntrinsics[3]; 867 float s = cameraIntrinsics[4]; 868 mCollector.expectTrue("Optical center expected to be within precorrection array", 869 0 <= cx && cx < precorrectionArray.width() && 870 0 <= cy && cy < precorrectionArray.height()); 871 872 // TODO: Verify focal lengths and skew are reasonable 873 } 874 875 if (radialDistortion != null) { 876 // TODO: Verify radial distortion 877 } 878 879 } else { 880 boolean hasFields = 881 hasDepth16 && (poseTranslation != null) && 882 (poseRotation != null) && (cameraIntrinsics != null) && 883 (radialDistortion != null) && (depthIsExclusive != null); 884 885 mCollector.expectTrue( 886 "All necessary depth fields defined, but DEPTH_OUTPUT capability is not listed", 887 !hasFields); 888 } 889 } 890 } 891 892 /** 893 * Cross-check StreamConfigurationMap output 894 */ testStreamConfigurationMap()895 public void testStreamConfigurationMap() throws Exception { 896 int counter = 0; 897 for (CameraCharacteristics c : mCharacteristics) { 898 Log.i(TAG, "testStreamConfigurationMap: Testing camera ID " + mIds[counter]); 899 StreamConfigurationMap config = 900 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 901 assertNotNull(String.format("No stream configuration map found for: ID %s", 902 mIds[counter]), config); 903 904 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 905 assertNotNull("android.request.availableCapabilities must never be null", 906 actualCapabilities); 907 908 if (arrayContains(actualCapabilities, BC)) { 909 assertTrue("ImageReader must be supported", 910 config.isOutputSupportedFor(android.media.ImageReader.class)); 911 assertTrue("MediaRecorder must be supported", 912 config.isOutputSupportedFor(android.media.MediaRecorder.class)); 913 assertTrue("MediaCodec must be supported", 914 config.isOutputSupportedFor(android.media.MediaCodec.class)); 915 assertTrue("Allocation must be supported", 916 config.isOutputSupportedFor(android.renderscript.Allocation.class)); 917 assertTrue("SurfaceHolder must be supported", 918 config.isOutputSupportedFor(android.view.SurfaceHolder.class)); 919 assertTrue("SurfaceTexture must be supported", 920 config.isOutputSupportedFor(android.graphics.SurfaceTexture.class)); 921 922 assertTrue("YUV_420_888 must be supported", 923 config.isOutputSupportedFor(ImageFormat.YUV_420_888)); 924 assertTrue("JPEG must be supported", 925 config.isOutputSupportedFor(ImageFormat.JPEG)); 926 } else { 927 assertTrue("YUV_420_88 may not be supported if BACKWARD_COMPATIBLE capability is not listed", 928 !config.isOutputSupportedFor(ImageFormat.YUV_420_888)); 929 assertTrue("JPEG may not be supported if BACKWARD_COMPATIBLE capability is not listed", 930 !config.isOutputSupportedFor(ImageFormat.JPEG)); 931 } 932 933 // Legacy YUV formats should not be listed 934 assertTrue("NV21 must not be supported", 935 !config.isOutputSupportedFor(ImageFormat.NV21)); 936 937 // Check RAW 938 939 if (arrayContains(actualCapabilities, 940 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 941 assertTrue("RAW_SENSOR must be supported if RAW capability is advertised", 942 config.isOutputSupportedFor(ImageFormat.RAW_SENSOR)); 943 } 944 945 // Cross check public formats and sizes 946 947 int[] supportedFormats = config.getOutputFormats(); 948 for (int format : supportedFormats) { 949 assertTrue("Format " + format + " fails cross check", 950 config.isOutputSupportedFor(format)); 951 List<Size> supportedSizes = CameraTestUtils.getAscendingOrderSizes( 952 Arrays.asList(config.getOutputSizes(format)), /*ascending*/true); 953 if (arrayContains(actualCapabilities, 954 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE)) { 955 supportedSizes.addAll( 956 Arrays.asList(config.getHighResolutionOutputSizes(format))); 957 supportedSizes = CameraTestUtils.getAscendingOrderSizes( 958 supportedSizes, /*ascending*/true); 959 } 960 assertTrue("Supported format " + format + " has no sizes listed", 961 supportedSizes.size() > 0); 962 for (int i = 0; i < supportedSizes.size(); i++) { 963 Size size = supportedSizes.get(i); 964 if (VERBOSE) { 965 Log.v(TAG, 966 String.format("Testing camera %s, format %d, size %s", 967 mIds[counter], format, size.toString())); 968 } 969 970 long stallDuration = config.getOutputStallDuration(format, size); 971 switch(format) { 972 case ImageFormat.YUV_420_888: 973 assertTrue("YUV_420_888 may not have a non-zero stall duration", 974 stallDuration == 0); 975 break; 976 case ImageFormat.JPEG: 977 case ImageFormat.RAW_SENSOR: 978 final float TOLERANCE_FACTOR = 2.0f; 979 long prevDuration = 0; 980 if (i > 0) { 981 prevDuration = config.getOutputStallDuration( 982 format, supportedSizes.get(i - 1)); 983 } 984 long nextDuration = Long.MAX_VALUE; 985 if (i < (supportedSizes.size() - 1)) { 986 nextDuration = config.getOutputStallDuration( 987 format, supportedSizes.get(i + 1)); 988 } 989 long curStallDuration = config.getOutputStallDuration(format, size); 990 // Stall duration should be in a reasonable range: larger size should 991 // normally have larger stall duration. 992 mCollector.expectInRange("Stall duration (format " + format + 993 " and size " + size + ") is not in the right range", 994 curStallDuration, 995 (long) (prevDuration / TOLERANCE_FACTOR), 996 (long) (nextDuration * TOLERANCE_FACTOR)); 997 break; 998 default: 999 assertTrue("Negative stall duration for format " + format, 1000 stallDuration >= 0); 1001 break; 1002 } 1003 long minDuration = config.getOutputMinFrameDuration(format, size); 1004 if (arrayContains(actualCapabilities, 1005 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 1006 assertTrue("MANUAL_SENSOR capability, need positive min frame duration for" 1007 + "format " + format + " for size " + size + " minDuration " + 1008 minDuration, 1009 minDuration > 0); 1010 } else { 1011 assertTrue("Need non-negative min frame duration for format " + format, 1012 minDuration >= 0); 1013 } 1014 1015 // todo: test opaque image reader when it's supported. 1016 if (format != ImageFormat.PRIVATE) { 1017 ImageReader testReader = ImageReader.newInstance( 1018 size.getWidth(), 1019 size.getHeight(), 1020 format, 1021 1); 1022 Surface testSurface = testReader.getSurface(); 1023 1024 assertTrue( 1025 String.format("isOutputSupportedFor fails for config %s, format %d", 1026 size.toString(), format), 1027 config.isOutputSupportedFor(testSurface)); 1028 1029 testReader.close(); 1030 } 1031 } // sizes 1032 1033 // Try an invalid size in this format, should round 1034 Size invalidSize = findInvalidSize(supportedSizes); 1035 int MAX_ROUNDING_WIDTH = 1920; 1036 // todo: test opaque image reader when it's supported. 1037 if (format != ImageFormat.PRIVATE && 1038 invalidSize.getWidth() <= MAX_ROUNDING_WIDTH) { 1039 ImageReader testReader = ImageReader.newInstance( 1040 invalidSize.getWidth(), 1041 invalidSize.getHeight(), 1042 format, 1043 1); 1044 Surface testSurface = testReader.getSurface(); 1045 1046 assertTrue( 1047 String.format("isOutputSupportedFor fails for config %s, %d", 1048 invalidSize.toString(), format), 1049 config.isOutputSupportedFor(testSurface)); 1050 1051 testReader.close(); 1052 } 1053 } // formats 1054 1055 // Cross-check opaque format and sizes 1056 if (arrayContains(actualCapabilities, BC)) { 1057 SurfaceTexture st = new SurfaceTexture(1); 1058 Surface surf = new Surface(st); 1059 1060 Size[] opaqueSizes = CameraTestUtils.getSupportedSizeForClass(SurfaceTexture.class, 1061 mIds[counter], mCameraManager); 1062 assertTrue("Opaque format has no sizes listed", 1063 opaqueSizes.length > 0); 1064 for (Size size : opaqueSizes) { 1065 long stallDuration = config.getOutputStallDuration(SurfaceTexture.class, size); 1066 assertTrue("Opaque output may not have a non-zero stall duration", 1067 stallDuration == 0); 1068 1069 long minDuration = config.getOutputMinFrameDuration(SurfaceTexture.class, size); 1070 if (arrayContains(actualCapabilities, 1071 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 1072 assertTrue("MANUAL_SENSOR capability, need positive min frame duration for" 1073 + "opaque format", 1074 minDuration > 0); 1075 } else { 1076 assertTrue("Need non-negative min frame duration for opaque format ", 1077 minDuration >= 0); 1078 } 1079 st.setDefaultBufferSize(size.getWidth(), size.getHeight()); 1080 1081 assertTrue( 1082 String.format("isOutputSupportedFor fails for SurfaceTexture config %s", 1083 size.toString()), 1084 config.isOutputSupportedFor(surf)); 1085 1086 } // opaque sizes 1087 1088 // Try invalid opaque size, should get rounded 1089 Size invalidSize = findInvalidSize(opaqueSizes); 1090 st.setDefaultBufferSize(invalidSize.getWidth(), invalidSize.getHeight()); 1091 assertTrue( 1092 String.format("isOutputSupportedFor fails for SurfaceTexture config %s", 1093 invalidSize.toString()), 1094 config.isOutputSupportedFor(surf)); 1095 1096 counter++; 1097 } 1098 1099 } // mCharacteristics 1100 } 1101 1102 /** 1103 * Test high speed capability and cross-check the high speed sizes and fps ranges from 1104 * the StreamConfigurationMap. 1105 */ testConstrainedHighSpeedCapability()1106 public void testConstrainedHighSpeedCapability() throws Exception { 1107 int counter = 0; 1108 for (CameraCharacteristics c : mCharacteristics) { 1109 int[] capabilities = CameraTestUtils.getValueNotNull( 1110 c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 1111 boolean supportHighSpeed = arrayContains(capabilities, CONSTRAINED_HIGH_SPEED); 1112 if (supportHighSpeed) { 1113 StreamConfigurationMap config = 1114 CameraTestUtils.getValueNotNull( 1115 c, CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 1116 List<Size> highSpeedSizes = Arrays.asList(config.getHighSpeedVideoSizes()); 1117 assertTrue("High speed sizes shouldn't be empty", highSpeedSizes.size() > 0); 1118 Size[] allSizes = CameraTestUtils.getSupportedSizeForFormat(ImageFormat.PRIVATE, 1119 mIds[counter], mCameraManager); 1120 assertTrue("Normal size for PRIVATE format shouldn't be null or empty", 1121 allSizes != null && allSizes.length > 0); 1122 for (Size size: highSpeedSizes) { 1123 // The sizes must be a subset of the normal sizes 1124 assertTrue("High speed size " + size + 1125 " must be part of normal sizes " + Arrays.toString(allSizes), 1126 Arrays.asList(allSizes).contains(size)); 1127 1128 // Sanitize the high speed FPS ranges for each size 1129 List<Range<Integer>> ranges = 1130 Arrays.asList(config.getHighSpeedVideoFpsRangesFor(size)); 1131 for (Range<Integer> range : ranges) { 1132 assertTrue("The range " + range + " doesn't satisfy the" 1133 + " min/max boundary requirements.", 1134 range.getLower() >= HIGH_SPEED_FPS_LOWER_MIN && 1135 range.getUpper() >= HIGH_SPEED_FPS_UPPER_MIN); 1136 assertTrue("The range " + range + " should be multiple of 30fps", 1137 range.getLower() % 30 == 0 && range.getUpper() % 30 == 0); 1138 // If the range is fixed high speed range, it should contain the 1139 // [30, fps_max] in the high speed range list; if it's variable FPS range, 1140 // the corresponding fixed FPS Range must be included in the range list. 1141 if (range.getLower() == range.getUpper()) { 1142 Range<Integer> variableRange = new Range<Integer>(30, range.getUpper()); 1143 assertTrue("The variable FPS range " + variableRange + 1144 " shoould be included in the high speed ranges for size " + 1145 size, ranges.contains(variableRange)); 1146 } else { 1147 Range<Integer> fixedRange = 1148 new Range<Integer>(range.getUpper(), range.getUpper()); 1149 assertTrue("The fixed FPS range " + fixedRange + 1150 " shoould be included in the high speed ranges for size " + 1151 size, ranges.contains(fixedRange)); 1152 } 1153 } 1154 } 1155 // If the device advertise some high speed profiles, the sizes and FPS ranges 1156 // should be advertise by the camera. 1157 for (int quality = CamcorderProfile.QUALITY_HIGH_SPEED_480P; 1158 quality <= CamcorderProfile.QUALITY_HIGH_SPEED_2160P; quality++) { 1159 if (CamcorderProfile.hasProfile(quality)) { 1160 CamcorderProfile profile = CamcorderProfile.get(quality); 1161 Size camcorderProfileSize = 1162 new Size(profile.videoFrameWidth, profile.videoFrameHeight); 1163 assertTrue("CamcorderPrfile size " + camcorderProfileSize + 1164 " must be included in the high speed sizes " + 1165 Arrays.toString(highSpeedSizes.toArray()), 1166 highSpeedSizes.contains(camcorderProfileSize)); 1167 Range<Integer> camcorderFpsRange = 1168 new Range<Integer>(profile.videoFrameRate, profile.videoFrameRate); 1169 List<Range<Integer>> allRanges = 1170 Arrays.asList(config.getHighSpeedVideoFpsRangesFor( 1171 camcorderProfileSize)); 1172 assertTrue("Camcorder fps range " + camcorderFpsRange + 1173 " should be included by high speed fps ranges " + 1174 Arrays.toString(allRanges.toArray()), 1175 allRanges.contains(camcorderFpsRange)); 1176 } 1177 } 1178 } 1179 counter++; 1180 } 1181 } 1182 1183 /** 1184 * Create an invalid size that's close to one of the good sizes in the list, but not one of them 1185 */ findInvalidSize(Size[] goodSizes)1186 private Size findInvalidSize(Size[] goodSizes) { 1187 return findInvalidSize(Arrays.asList(goodSizes)); 1188 } 1189 1190 /** 1191 * Create an invalid size that's close to one of the good sizes in the list, but not one of them 1192 */ findInvalidSize(List<Size> goodSizes)1193 private Size findInvalidSize(List<Size> goodSizes) { 1194 Size invalidSize = new Size(goodSizes.get(0).getWidth() + 1, goodSizes.get(0).getHeight()); 1195 while(goodSizes.contains(invalidSize)) { 1196 invalidSize = new Size(invalidSize.getWidth() + 1, invalidSize.getHeight()); 1197 } 1198 return invalidSize; 1199 } 1200 1201 /** 1202 * Check key is present in characteristics if the hardware level is at least {@code hwLevel}; 1203 * check that the key is present if the actual capabilities are one of {@code capabilities}. 1204 * 1205 * @return value of the {@code key} from {@code c} 1206 */ expectKeyAvailable(CameraCharacteristics c, CameraCharacteristics.Key<T> key, int hwLevel, int... capabilities)1207 private <T> T expectKeyAvailable(CameraCharacteristics c, CameraCharacteristics.Key<T> key, 1208 int hwLevel, int... capabilities) { 1209 1210 Integer actualHwLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 1211 assertNotNull("android.info.supportedHardwareLevel must never be null", actualHwLevel); 1212 1213 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 1214 assertNotNull("android.request.availableCapabilities must never be null", 1215 actualCapabilities); 1216 1217 List<Key<?>> allKeys = c.getKeys(); 1218 1219 T value = c.get(key); 1220 1221 // For LIMITED-level targeted keys, rely on capability check, not level 1222 if ((compareHardwareLevel(actualHwLevel, hwLevel) >= 0) && (hwLevel != LIMITED)) { 1223 mCollector.expectTrue( 1224 String.format("Key (%s) must be in characteristics for this hardware level " + 1225 "(required minimal HW level %s, actual HW level %s)", 1226 key.getName(), toStringHardwareLevel(hwLevel), 1227 toStringHardwareLevel(actualHwLevel)), 1228 value != null); 1229 mCollector.expectTrue( 1230 String.format("Key (%s) must be in characteristics list of keys for this " + 1231 "hardware level (required minimal HW level %s, actual HW level %s)", 1232 key.getName(), toStringHardwareLevel(hwLevel), 1233 toStringHardwareLevel(actualHwLevel)), 1234 allKeys.contains(key)); 1235 } else if (arrayContainsAnyOf(actualCapabilities, capabilities)) { 1236 if (!(hwLevel == LIMITED && compareHardwareLevel(actualHwLevel, hwLevel) < 0)) { 1237 // Don't enforce LIMITED-starting keys on LEGACY level, even if cap is defined 1238 mCollector.expectTrue( 1239 String.format("Key (%s) must be in characteristics for these capabilities " + 1240 "(required capabilities %s, actual capabilities %s)", 1241 key.getName(), Arrays.toString(capabilities), 1242 Arrays.toString(actualCapabilities)), 1243 value != null); 1244 mCollector.expectTrue( 1245 String.format("Key (%s) must be in characteristics list of keys for " + 1246 "these capabilities (required capabilities %s, actual capabilities %s)", 1247 key.getName(), Arrays.toString(capabilities), 1248 Arrays.toString(actualCapabilities)), 1249 allKeys.contains(key)); 1250 } 1251 } else { 1252 if (actualHwLevel == LEGACY && hwLevel != OPT) { 1253 if (value != null || allKeys.contains(key)) { 1254 Log.w(TAG, String.format( 1255 "Key (%s) is not required for LEGACY devices but still appears", 1256 key.getName())); 1257 } 1258 } 1259 // OK: Key may or may not be present. 1260 } 1261 return value; 1262 } 1263 arrayContains(int[] arr, int needle)1264 private static boolean arrayContains(int[] arr, int needle) { 1265 if (arr == null) { 1266 return false; 1267 } 1268 1269 for (int elem : arr) { 1270 if (elem == needle) { 1271 return true; 1272 } 1273 } 1274 1275 return false; 1276 } 1277 arrayContains(T[] arr, T needle)1278 private static <T> boolean arrayContains(T[] arr, T needle) { 1279 if (arr == null) { 1280 return false; 1281 } 1282 1283 for (T elem : arr) { 1284 if (elem.equals(needle)) { 1285 return true; 1286 } 1287 } 1288 1289 return false; 1290 } 1291 arrayContainsAnyOf(int[] arr, int[] needles)1292 private static boolean arrayContainsAnyOf(int[] arr, int[] needles) { 1293 for (int needle : needles) { 1294 if (arrayContains(arr, needle)) { 1295 return true; 1296 } 1297 } 1298 return false; 1299 } 1300 1301 /** 1302 * The key name has a prefix of either "android." or "com."; other prefixes are not valid. 1303 */ assertKeyPrefixValid(String keyName)1304 private static void assertKeyPrefixValid(String keyName) { 1305 assertStartsWithAnyOf( 1306 "All metadata keys must start with 'android.' (built-in keys) " + 1307 "or 'com.' (vendor-extended keys)", new String[] { 1308 PREFIX_ANDROID + ".", 1309 PREFIX_VENDOR + ".", 1310 }, keyName); 1311 } 1312 assertTrueForKey(String msg, CameraCharacteristics.Key<?> key, boolean actual)1313 private static void assertTrueForKey(String msg, CameraCharacteristics.Key<?> key, 1314 boolean actual) { 1315 assertTrue(msg + " (key = '" + key.getName() + "')", actual); 1316 } 1317 assertOneOf(String msg, T[] expected, T actual)1318 private static <T> void assertOneOf(String msg, T[] expected, T actual) { 1319 for (int i = 0; i < expected.length; ++i) { 1320 if (Objects.equals(expected[i], actual)) { 1321 return; 1322 } 1323 } 1324 1325 fail(String.format("%s: (expected one of %s, actual %s)", 1326 msg, Arrays.toString(expected), actual)); 1327 } 1328 assertStartsWithAnyOf(String msg, String[] expected, String actual)1329 private static <T> void assertStartsWithAnyOf(String msg, String[] expected, String actual) { 1330 for (int i = 0; i < expected.length; ++i) { 1331 if (actual.startsWith(expected[i])) { 1332 return; 1333 } 1334 } 1335 1336 fail(String.format("%s: (expected to start with any of %s, but value was %s)", 1337 msg, Arrays.toString(expected), actual)); 1338 } 1339 1340 /** Return a positive int if left > right, 0 if left==right, negative int if left < right */ compareHardwareLevel(int left, int right)1341 private static int compareHardwareLevel(int left, int right) { 1342 return remapHardwareLevel(left) - remapHardwareLevel(right); 1343 } 1344 1345 /** Remap HW levels worst<->best, 0 = worst, 2 = best */ remapHardwareLevel(int level)1346 private static int remapHardwareLevel(int level) { 1347 switch (level) { 1348 case OPT: 1349 return Integer.MAX_VALUE; 1350 case LEGACY: 1351 return 0; // lowest 1352 case LIMITED: 1353 return 1; // second lowest 1354 case FULL: 1355 return 2; // best 1356 } 1357 1358 fail("Unknown HW level: " + level); 1359 return -1; 1360 } 1361 toStringHardwareLevel(int level)1362 private static String toStringHardwareLevel(int level) { 1363 switch (level) { 1364 case LEGACY: 1365 return "LEGACY"; 1366 case LIMITED: 1367 return "LIMITED"; 1368 case FULL: 1369 return "FULL"; 1370 } 1371 1372 // unknown 1373 Log.w(TAG, "Unknown hardware level " + level); 1374 return Integer.toString(level); 1375 } 1376 } 1377