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