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.SurfaceTexture; 22 import android.hardware.camera2.CameraCharacteristics; 23 import android.hardware.camera2.CameraCharacteristics.Key; 24 import android.hardware.camera2.CameraManager; 25 import android.hardware.camera2.cts.helpers.CameraErrorCollector; 26 import android.hardware.camera2.params.BlackLevelPattern; 27 import android.hardware.camera2.params.ColorSpaceTransform; 28 import android.hardware.camera2.params.StreamConfigurationMap; 29 import android.media.ImageReader; 30 import android.test.AndroidTestCase; 31 import android.util.Log; 32 import android.util.Rational; 33 import android.util.Range; 34 import android.util.Size; 35 import android.view.Surface; 36 37 import java.util.ArrayList; 38 import java.util.Arrays; 39 import java.util.List; 40 import java.util.Objects; 41 42 import static android.hardware.camera2.cts.helpers.AssertHelpers.*; 43 44 /** 45 * Extended tests for static camera characteristics. 46 */ 47 public class ExtendedCameraCharacteristicsTest extends AndroidTestCase { 48 private static final String TAG = "ExChrsTest"; // must be short so next line doesn't throw 49 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 50 51 private static final String PREFIX_ANDROID = "android"; 52 private static final String PREFIX_VENDOR = "com"; 53 54 /* 55 * Constants for static RAW metadata. 56 */ 57 private static final int MIN_ALLOWABLE_WHITELEVEL = 32; // must have sensor bit depth > 5 58 59 private CameraManager mCameraManager; 60 private List<CameraCharacteristics> mCharacteristics; 61 private String[] mIds; 62 private CameraErrorCollector mCollector; 63 64 private static final Size VGA = new Size(640, 480); 65 66 /* 67 * HW Levels short hand 68 */ 69 private static final int LEGACY = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY; 70 private static final int LIMITED = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED; 71 private static final int FULL = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL; 72 private static final int OPT = Integer.MAX_VALUE; // For keys that are optional on all hardware levels. 73 74 /* 75 * Capabilities short hand 76 */ 77 private static final int NONE = -1; 78 private static final int BC = 79 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE; 80 private static final int MANUAL_SENSOR = 81 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR; 82 private static final int MANUAL_POSTPROC = 83 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING; 84 private static final int RAW = 85 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW; 86 87 @Override 88 public void setContext(Context context) { 89 super.setContext(context); 90 mCameraManager = (CameraManager)context.getSystemService(Context.CAMERA_SERVICE); 91 assertNotNull("Can't connect to camera manager", mCameraManager); 92 } 93 94 @Override 95 protected void setUp() throws Exception { 96 super.setUp(); 97 mIds = mCameraManager.getCameraIdList(); 98 mCharacteristics = new ArrayList<>(); 99 mCollector = new CameraErrorCollector(); 100 for (int i = 0; i < mIds.length; i++) { 101 CameraCharacteristics props = mCameraManager.getCameraCharacteristics(mIds[i]); 102 assertNotNull(String.format("Can't get camera characteristics from: ID %s", mIds[i]), 103 props); 104 mCharacteristics.add(props); 105 } 106 } 107 108 @Override 109 protected void tearDown() throws Exception { 110 mCharacteristics = null; 111 112 try { 113 mCollector.verify(); 114 } catch (Throwable e) { 115 // When new Exception(e) is used, exception info will be printed twice. 116 throw new Exception(e.getMessage()); 117 } finally { 118 super.tearDown(); 119 } 120 } 121 122 /** 123 * Test that the available stream configurations contain a few required formats and sizes. 124 */ 125 public void testAvailableStreamConfigs() { 126 int counter = 0; 127 for (CameraCharacteristics c : mCharacteristics) { 128 StreamConfigurationMap config = 129 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 130 assertNotNull(String.format("No stream configuration map found for: ID %s", 131 mIds[counter]), config); 132 int[] outputFormats = config.getOutputFormats(); 133 134 // Check required formats exist (JPEG, and YUV_420_888). 135 assertArrayContains( 136 String.format("No valid YUV_420_888 preview formats found for: ID %s", 137 mIds[counter]), outputFormats, ImageFormat.YUV_420_888); 138 assertArrayContains(String.format("No JPEG image format for: ID %s", 139 mIds[counter]), outputFormats, ImageFormat.JPEG); 140 141 Size[] sizes = config.getOutputSizes(ImageFormat.YUV_420_888); 142 CameraTestUtils.assertArrayNotEmpty(sizes, 143 String.format("No sizes for preview format %x for: ID %s", 144 ImageFormat.YUV_420_888, mIds[counter])); 145 146 assertArrayContains(String.format( 147 "Required VGA size not found for format %x for: ID %s", 148 ImageFormat.YUV_420_888, mIds[counter]), sizes, VGA); 149 150 counter++; 151 } 152 } 153 154 /** 155 * Test {@link CameraCharacteristics#getKeys} 156 */ 157 public void testKeys() { 158 int counter = 0; 159 for (CameraCharacteristics c : mCharacteristics) { 160 mCollector.setCameraId(mIds[counter]); 161 162 if (VERBOSE) { 163 Log.v(TAG, "testKeys - testing characteristics for camera " + mIds[counter]); 164 } 165 166 List<CameraCharacteristics.Key<?>> allKeys = c.getKeys(); 167 assertNotNull("Camera characteristics keys must not be null", allKeys); 168 assertFalse("Camera characteristics keys must have at least 1 key", 169 allKeys.isEmpty()); 170 171 for (CameraCharacteristics.Key<?> key : allKeys) { 172 assertKeyPrefixValid(key.getName()); 173 174 // All characteristics keys listed must never be null 175 mCollector.expectKeyValueNotNull(c, key); 176 177 // TODO: add a check that key must not be @hide 178 } 179 180 /* 181 * List of keys that must be present in camera characteristics (not null). 182 * 183 * Keys for LIMITED, FULL devices might be available despite lacking either 184 * the hardware level or the capability. This is *OK*. This only lists the 185 * *minimal* requirements for a key to be listed. 186 * 187 * LEGACY devices are a bit special since they map to api1 devices, so we know 188 * for a fact most keys are going to be illegal there so they should never be 189 * available. 190 * 191 * (TODO: Codegen this) 192 */ 193 { 194 // (Key Name) (HW Level) (Capabilities <Var-Arg>) 195 expectKeyAvailable(c, CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES , LEGACY , BC ); 196 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_ANTIBANDING_MODES , LEGACY , BC ); 197 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES , LEGACY , BC ); 198 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES , LEGACY , BC ); 199 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE , LEGACY , BC ); 200 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP , LEGACY , BC ); 201 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES , LEGACY , BC ); 202 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS , LEGACY , BC ); 203 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES , LEGACY , BC ); 204 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES , LEGACY , BC ); 205 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES , LEGACY , BC ); 206 expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AE , LEGACY , BC ); 207 expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AF , LEGACY , BC ); 208 expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AWB , LEGACY , BC ); 209 expectKeyAvailable(c, CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES , FULL , NONE ); 210 expectKeyAvailable(c, CameraCharacteristics.FLASH_INFO_AVAILABLE , LEGACY , BC ); 211 expectKeyAvailable(c, CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES , OPT , RAW ); 212 expectKeyAvailable(c, CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL , LEGACY , BC ); 213 expectKeyAvailable(c, CameraCharacteristics.JPEG_AVAILABLE_THUMBNAIL_SIZES , LEGACY , BC ); 214 expectKeyAvailable(c, CameraCharacteristics.LENS_FACING , LEGACY , BC ); 215 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES , FULL , MANUAL_SENSOR ); 216 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_FILTER_DENSITIES , FULL , MANUAL_SENSOR ); 217 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS , LEGACY , BC ); 218 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION , LIMITED , MANUAL_SENSOR ); 219 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_FOCUS_DISTANCE_CALIBRATION , LIMITED , MANUAL_SENSOR ); 220 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_HYPERFOCAL_DISTANCE , LIMITED , MANUAL_SENSOR ); 221 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE , LIMITED , NONE ); 222 expectKeyAvailable(c, CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES , LEGACY , BC ); 223 expectKeyAvailable(c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES , LEGACY , BC ); 224 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC , LEGACY , BC ); 225 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING , LEGACY , BC ); 226 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW , LEGACY , BC ); 227 expectKeyAvailable(c, CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT , LEGACY , BC ); 228 expectKeyAvailable(c, CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH , LEGACY , BC ); 229 expectKeyAvailable(c, CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM , LEGACY , BC ); 230 expectKeyAvailable(c, CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP , LEGACY , BC ); 231 expectKeyAvailable(c, CameraCharacteristics.SCALER_CROPPING_TYPE , LEGACY , BC ); 232 expectKeyAvailable(c, CameraCharacteristics.SENSOR_AVAILABLE_TEST_PATTERN_MODES , LEGACY , NONE ); 233 expectKeyAvailable(c, CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN , FULL , MANUAL_SENSOR, RAW ); 234 expectKeyAvailable(c, CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM1 , OPT , RAW ); 235 expectKeyAvailable(c, CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM2 , OPT , RAW ); 236 expectKeyAvailable(c, CameraCharacteristics.SENSOR_COLOR_TRANSFORM1 , OPT , RAW ); 237 expectKeyAvailable(c, CameraCharacteristics.SENSOR_COLOR_TRANSFORM2 , OPT , RAW ); 238 expectKeyAvailable(c, CameraCharacteristics.SENSOR_FORWARD_MATRIX1 , OPT , RAW ); 239 expectKeyAvailable(c, CameraCharacteristics.SENSOR_FORWARD_MATRIX2 , OPT , RAW ); 240 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE , LEGACY , BC, RAW ); 241 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT , FULL , RAW ); 242 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE , FULL , MANUAL_SENSOR ); 243 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_MAX_FRAME_DURATION , FULL , MANUAL_SENSOR ); 244 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE , LEGACY , BC ); 245 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE , LEGACY , BC ); 246 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE , FULL , MANUAL_SENSOR ); 247 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL , OPT , RAW ); 248 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE , LEGACY , BC ); 249 expectKeyAvailable(c, CameraCharacteristics.SENSOR_MAX_ANALOG_SENSITIVITY , FULL , MANUAL_SENSOR ); 250 expectKeyAvailable(c, CameraCharacteristics.SENSOR_ORIENTATION , LEGACY , BC ); 251 expectKeyAvailable(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1 , OPT , RAW ); 252 expectKeyAvailable(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2 , OPT , RAW ); 253 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES , LEGACY , BC ); 254 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES , OPT , RAW ); 255 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT , LEGACY , BC ); 256 expectKeyAvailable(c, CameraCharacteristics.SYNC_MAX_LATENCY , LEGACY , BC ); 257 expectKeyAvailable(c, CameraCharacteristics.TONEMAP_AVAILABLE_TONE_MAP_MODES , FULL , MANUAL_POSTPROC ); 258 expectKeyAvailable(c, CameraCharacteristics.TONEMAP_MAX_CURVE_POINTS , FULL , MANUAL_POSTPROC ); 259 260 // Future: Use column editors for modifying above, ignore line length to keep 1 key per line 261 262 // TODO: check that no other 'android' keys are listed in #getKeys if they aren't in the above list 263 } 264 265 counter++; 266 } 267 } 268 269 /** 270 * Test values for static metadata used by the RAW capability. 271 */ 272 public void testStaticRawCharacteristics() { 273 int counter = 0; 274 for (CameraCharacteristics c : mCharacteristics) { 275 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 276 assertNotNull("android.request.availableCapabilities must never be null", 277 actualCapabilities); 278 if (!arrayContains(actualCapabilities, 279 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 280 Log.i(TAG, "RAW capability is not supported in camera " + counter++ + 281 ". Skip the test."); 282 continue; 283 } 284 285 Integer actualHwLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 286 if (actualHwLevel != null && actualHwLevel == FULL) { 287 mCollector.expectKeyValueContains(c, 288 CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES, 289 CameraCharacteristics.HOT_PIXEL_MODE_FAST); 290 } 291 mCollector.expectKeyValueContains(c, 292 CameraCharacteristics.STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES, false); 293 mCollector.expectKeyValueGreaterThan(c, CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL, 294 MIN_ALLOWABLE_WHITELEVEL); 295 296 mCollector.expectKeyValueIsIn(c, 297 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT, 298 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB, 299 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG, 300 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG, 301 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR); 302 // TODO: SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB isn't supported yet. 303 304 mCollector.expectKeyValueInRange(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1, 305 CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT, 306 CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN); 307 mCollector.expectKeyValueInRange(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2, 308 (byte) CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT, 309 (byte) CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN); 310 311 Rational[] zeroes = new Rational[9]; 312 Arrays.fill(zeroes, Rational.ZERO); 313 314 ColorSpaceTransform zeroed = new ColorSpaceTransform(zeroes); 315 mCollector.expectNotEquals("Forward Matrix1 should not contain all zeroes.", zeroed, 316 c.get(CameraCharacteristics.SENSOR_FORWARD_MATRIX1)); 317 mCollector.expectNotEquals("Forward Matrix2 should not contain all zeroes.", zeroed, 318 c.get(CameraCharacteristics.SENSOR_FORWARD_MATRIX2)); 319 mCollector.expectNotEquals("Calibration Transform1 should not contain all zeroes.", 320 zeroed, c.get(CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM1)); 321 mCollector.expectNotEquals("Calibration Transform2 should not contain all zeroes.", 322 zeroed, c.get(CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM2)); 323 mCollector.expectNotEquals("Color Transform1 should not contain all zeroes.", 324 zeroed, c.get(CameraCharacteristics.SENSOR_COLOR_TRANSFORM1)); 325 mCollector.expectNotEquals("Color Transform2 should not contain all zeroes.", 326 zeroed, c.get(CameraCharacteristics.SENSOR_COLOR_TRANSFORM2)); 327 328 BlackLevelPattern blackLevel = mCollector.expectKeyValueNotNull(c, 329 CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN); 330 if (blackLevel != null) { 331 int[] blackLevelPattern = new int[BlackLevelPattern.COUNT]; 332 blackLevel.copyTo(blackLevelPattern, /*offset*/0); 333 Integer whitelevel = c.get(CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL); 334 if (whitelevel != null) { 335 mCollector.expectValuesInRange("BlackLevelPattern", blackLevelPattern, 0, 336 whitelevel); 337 } else { 338 mCollector.addMessage( 339 "No WhiteLevel available, cannot check BlackLevelPattern range."); 340 } 341 } 342 343 // TODO: profileHueSatMap, and profileToneCurve aren't supported yet. 344 counter++; 345 } 346 } 347 348 /** 349 * Test values for static metadata used by the BURST capability. 350 */ 351 public void testStaticBurstCharacteristics() { 352 int counter = 0; 353 for (CameraCharacteristics c : mCharacteristics) { 354 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 355 assertNotNull("android.request.availableCapabilities must never be null", 356 actualCapabilities); 357 358 // Check if the burst capability is defined 359 boolean haveBurstCapability = arrayContains(actualCapabilities, 360 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE); 361 362 StreamConfigurationMap config = 363 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 364 assertNotNull(String.format("No stream configuration map found for: ID %s", 365 mIds[counter]), config); 366 367 // Ensure that max YUV size matches max JPEG size 368 Size maxYuvSize = CameraTestUtils.getMaxSize( 369 config.getOutputSizes(ImageFormat.YUV_420_888)); 370 Size maxJpegSize = CameraTestUtils.getMaxSize(config.getOutputSizes(ImageFormat.JPEG)); 371 372 boolean haveMaxYuv = maxYuvSize != null ? 373 (maxJpegSize.getWidth() <= maxYuvSize.getWidth() && 374 maxJpegSize.getHeight() <= maxYuvSize.getHeight()) : false; 375 376 // Ensure that YUV output is fast enough - needs to be at least 20 fps 377 378 long maxYuvRate = 379 config.getOutputMinFrameDuration(ImageFormat.YUV_420_888, maxYuvSize); 380 final long MIN_DURATION_BOUND_NS = 50000000; // 50 ms, 20 fps 381 382 boolean haveMaxYuvRate = maxYuvRate <= MIN_DURATION_BOUND_NS; 383 384 // Ensure that there's an FPS range that's fast enough to capture at above 385 // minFrameDuration, for full-auto bursts 386 Range[] fpsRanges = c.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); 387 float minYuvFps = 1.f / maxYuvRate; 388 389 boolean haveFastAeTargetFps = false; 390 for (Range<Integer> r : fpsRanges) { 391 if (r.getLower() >= minYuvFps) { 392 haveFastAeTargetFps = true; 393 break; 394 } 395 } 396 397 // Ensure that maximum sync latency is small enough for fast setting changes, even if 398 // it's not quite per-frame 399 400 Integer maxSyncLatencyValue = c.get(CameraCharacteristics.SYNC_MAX_LATENCY); 401 assertNotNull(String.format("No sync latency declared for ID %s", mIds[counter]), 402 maxSyncLatencyValue); 403 404 int maxSyncLatency = maxSyncLatencyValue; 405 final long MAX_LATENCY_BOUND = 4; 406 boolean haveFastSyncLatency = 407 (maxSyncLatency <= MAX_LATENCY_BOUND) && (maxSyncLatency >= 0); 408 409 if (haveBurstCapability) { 410 assertTrue( 411 String.format("BURST-capable camera device %s does not have maximum YUV " + 412 "size that is at least max JPEG size", 413 mIds[counter]), 414 haveMaxYuv); 415 assertTrue( 416 String.format("BURST-capable camera device %s YUV frame rate is too slow" + 417 "(%d ns min frame duration reported, less than %d ns expected)", 418 mIds[counter], maxYuvRate, MIN_DURATION_BOUND_NS), 419 haveMaxYuvRate); 420 assertTrue( 421 String.format("BURST-capable camera device %s does not list an AE target " + 422 " FPS range with min FPS >= %f, for full-AUTO bursts", 423 mIds[counter], minYuvFps), 424 haveFastAeTargetFps); 425 assertTrue( 426 String.format("BURST-capable camera device %s YUV sync latency is too long" + 427 "(%d frames reported, [0, %d] frames expected)", 428 mIds[counter], maxSyncLatency, MAX_LATENCY_BOUND), 429 haveFastSyncLatency); 430 } else { 431 assertTrue( 432 String.format("Camera device %s has all the requirements for BURST" + 433 " capability but does not report it!", mIds[counter]), 434 !(haveMaxYuv && haveMaxYuvRate && 435 haveFastAeTargetFps && haveFastSyncLatency)); 436 } 437 438 counter++; 439 } 440 } 441 442 /** 443 * Cross-check StreamConfigurationMap output 444 */ 445 public void testStreamConfigurationMap() { 446 int counter = 0; 447 for (CameraCharacteristics c : mCharacteristics) { 448 Log.i(TAG, "testStreamConfigurationMap: Testing camera ID " + mIds[counter]); 449 StreamConfigurationMap config = 450 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 451 assertNotNull(String.format("No stream configuration map found for: ID %s", 452 mIds[counter]), config); 453 454 assertTrue("ImageReader must be supported", 455 config.isOutputSupportedFor(android.media.ImageReader.class)); 456 assertTrue("MediaRecorder must be supported", 457 config.isOutputSupportedFor(android.media.MediaRecorder.class)); 458 assertTrue("MediaCodec must be supported", 459 config.isOutputSupportedFor(android.media.MediaCodec.class)); 460 assertTrue("Allocation must be supported", 461 config.isOutputSupportedFor(android.renderscript.Allocation.class)); 462 assertTrue("SurfaceHolder must be supported", 463 config.isOutputSupportedFor(android.view.SurfaceHolder.class)); 464 assertTrue("SurfaceTexture must be supported", 465 config.isOutputSupportedFor(android.graphics.SurfaceTexture.class)); 466 467 assertTrue("YUV_420_888 must be supported", 468 config.isOutputSupportedFor(ImageFormat.YUV_420_888)); 469 assertTrue("JPEG must be supported", 470 config.isOutputSupportedFor(ImageFormat.JPEG)); 471 472 // Legacy YUV formats should not be listed 473 assertTrue("NV21 must not be supported", 474 !config.isOutputSupportedFor(ImageFormat.NV21)); 475 476 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 477 assertNotNull("android.request.availableCapabilities must never be null", 478 actualCapabilities); 479 if (arrayContains(actualCapabilities, 480 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 481 assertTrue("RAW_SENSOR must be supported if RAW capability is advertised", 482 config.isOutputSupportedFor(ImageFormat.RAW_SENSOR)); 483 } 484 485 // Cross check public formats and sizes 486 487 int[] supportedFormats = config.getOutputFormats(); 488 for (int format : supportedFormats) { 489 assertTrue("Format " + format + " fails cross check", 490 config.isOutputSupportedFor(format)); 491 Size[] supportedSizes = config.getOutputSizes(format); 492 assertTrue("Supported format " + format + " has no sizes listed", 493 supportedSizes.length > 0); 494 for (Size size : supportedSizes) { 495 if (VERBOSE) { 496 Log.v(TAG, 497 String.format("Testing camera %s, format %d, size %s", 498 mIds[counter], format, size.toString())); 499 } 500 501 long stallDuration = config.getOutputStallDuration(format, size); 502 switch(format) { 503 case ImageFormat.YUV_420_888: 504 assertTrue("YUV_420_888 may not have a non-zero stall duration", 505 stallDuration == 0); 506 break; 507 default: 508 assertTrue("Negative stall duration for format " + format, 509 stallDuration >= 0); 510 break; 511 } 512 long minDuration = config.getOutputMinFrameDuration(format, size); 513 if (arrayContains(actualCapabilities, 514 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 515 assertTrue("MANUAL_SENSOR capability, need positive min frame duration for" 516 + "format " + format + " for size " + size + " minDuration " + 517 minDuration, 518 minDuration > 0); 519 } else { 520 assertTrue("Need non-negative min frame duration for format " + format, 521 minDuration >= 0); 522 } 523 524 ImageReader testReader = ImageReader.newInstance( 525 size.getWidth(), 526 size.getHeight(), 527 format, 528 1); 529 Surface testSurface = testReader.getSurface(); 530 531 assertTrue( 532 String.format("isOutputSupportedFor fails for config %s, format %d", 533 size.toString(), format), 534 config.isOutputSupportedFor(testSurface)); 535 536 testReader.close(); 537 538 } // sizes 539 540 // Try an invalid size in this format, should round 541 Size invalidSize = findInvalidSize(supportedSizes); 542 int MAX_ROUNDING_WIDTH = 1920; 543 if (invalidSize.getWidth() <= MAX_ROUNDING_WIDTH) { 544 ImageReader testReader = ImageReader.newInstance( 545 invalidSize.getWidth(), 546 invalidSize.getHeight(), 547 format, 548 1); 549 Surface testSurface = testReader.getSurface(); 550 551 assertTrue( 552 String.format("isOutputSupportedFor fails for config %s, %d", 553 invalidSize.toString(), format), 554 config.isOutputSupportedFor(testSurface)); 555 556 testReader.close(); 557 } 558 } // formats 559 560 // Cross-check opaque format and sizes 561 562 SurfaceTexture st = new SurfaceTexture(1); 563 Surface surf = new Surface(st); 564 565 Size[] opaqueSizes = config.getOutputSizes(SurfaceTexture.class); 566 assertTrue("Opaque format has no sizes listed", 567 opaqueSizes.length > 0); 568 for (Size size : opaqueSizes) { 569 long stallDuration = config.getOutputStallDuration(SurfaceTexture.class, size); 570 assertTrue("Opaque output may not have a non-zero stall duration", 571 stallDuration == 0); 572 573 long minDuration = config.getOutputMinFrameDuration(SurfaceTexture.class, size); 574 if (arrayContains(actualCapabilities, 575 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 576 assertTrue("MANUAL_SENSOR capability, need positive min frame duration for" 577 + "opaque format", 578 minDuration > 0); 579 } else { 580 assertTrue("Need non-negative min frame duration for opaque format ", 581 minDuration >= 0); 582 } 583 st.setDefaultBufferSize(size.getWidth(), size.getHeight()); 584 585 assertTrue( 586 String.format("isOutputSupportedFor fails for SurfaceTexture config %s", 587 size.toString()), 588 config.isOutputSupportedFor(surf)); 589 590 } // opaque sizes 591 592 // Try invalid opaque size, should get rounded 593 Size invalidSize = findInvalidSize(opaqueSizes); 594 st.setDefaultBufferSize(invalidSize.getWidth(), invalidSize.getHeight()); 595 assertTrue( 596 String.format("isOutputSupportedFor fails for SurfaceTexture config %s", 597 invalidSize.toString()), 598 config.isOutputSupportedFor(surf)); 599 600 counter++; 601 } // mCharacteristics 602 603 } 604 605 /** 606 * Create an invalid size that's close to one of the good sizes in the list, but not one of them 607 */ 608 private Size findInvalidSize(Size[] goodSizes) { 609 Size invalidSize = new Size(goodSizes[0].getWidth() + 1, goodSizes[0].getHeight()); 610 while(arrayContains(goodSizes, invalidSize)) { 611 invalidSize = new Size(invalidSize.getWidth() + 1, invalidSize.getHeight()); 612 } 613 return invalidSize; 614 } 615 616 /** 617 * Check key is present in characteristics if the hardware level is at least {@code hwLevel}; 618 * check that the key is present if the actual capabilities are one of {@code capabilities}. 619 * 620 * @return value of the {@code key} from {@code c} 621 */ 622 private <T> T expectKeyAvailable(CameraCharacteristics c, CameraCharacteristics.Key<T> key, 623 int hwLevel, int... capabilities) { 624 625 Integer actualHwLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 626 assertNotNull("android.info.supportedHardwareLevel must never be null", actualHwLevel); 627 628 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 629 assertNotNull("android.request.availableCapabilities must never be null", 630 actualCapabilities); 631 632 List<Key<?>> allKeys = c.getKeys(); 633 634 T value = c.get(key); 635 636 if (compareHardwareLevel(actualHwLevel, hwLevel) >= 0) { 637 mCollector.expectTrue( 638 String.format("Key (%s) must be in characteristics for this hardware level " + 639 "(required minimal HW level %s, actual HW level %s)", 640 key.getName(), toStringHardwareLevel(hwLevel), 641 toStringHardwareLevel(actualHwLevel)), 642 value != null); 643 mCollector.expectTrue( 644 String.format("Key (%s) must be in characteristics list of keys for this " + 645 "hardware level (required minimal HW level %s, actual HW level %s)", 646 key.getName(), toStringHardwareLevel(hwLevel), 647 toStringHardwareLevel(actualHwLevel)), 648 allKeys.contains(key)); 649 } else if (arrayContainsAnyOf(actualCapabilities, capabilities)) { 650 mCollector.expectTrue( 651 String.format("Key (%s) must be in characteristics for these capabilities " + 652 "(required capabilities %s, actual capabilities %s)", 653 key.getName(), Arrays.toString(capabilities), 654 Arrays.toString(actualCapabilities)), 655 value != null); 656 mCollector.expectTrue( 657 String.format("Key (%s) must be in characteristics list of keys for " + 658 "these capabilities (required capabilities %s, actual capabilities %s)", 659 key.getName(), Arrays.toString(capabilities), 660 Arrays.toString(actualCapabilities)), 661 allKeys.contains(key)); 662 } else { 663 if (actualHwLevel == LEGACY && hwLevel != OPT) { 664 if (value != null || allKeys.contains(key)) { 665 Log.w(TAG, String.format( 666 "Key (%s) is not required for LEGACY devices but still appears", 667 key.getName())); 668 } 669 } 670 // OK: Key may or may not be present. 671 } 672 return value; 673 } 674 675 private static boolean arrayContains(int[] arr, int needle) { 676 if (arr == null) { 677 return false; 678 } 679 680 for (int elem : arr) { 681 if (elem == needle) { 682 return true; 683 } 684 } 685 686 return false; 687 } 688 689 private static <T> boolean arrayContains(T[] arr, T needle) { 690 if (arr == null) { 691 return false; 692 } 693 694 for (T elem : arr) { 695 if (elem.equals(needle)) { 696 return true; 697 } 698 } 699 700 return false; 701 } 702 703 private static boolean arrayContainsAnyOf(int[] arr, int[] needles) { 704 for (int needle : needles) { 705 if (arrayContains(arr, needle)) { 706 return true; 707 } 708 } 709 return false; 710 } 711 712 /** 713 * The key name has a prefix of either "android." or "com."; other prefixes are not valid. 714 */ 715 private static void assertKeyPrefixValid(String keyName) { 716 assertStartsWithAnyOf( 717 "All metadata keys must start with 'android.' (built-in keys) " + 718 "or 'com.' (vendor-extended keys)", new String[] { 719 PREFIX_ANDROID + ".", 720 PREFIX_VENDOR + ".", 721 }, keyName); 722 } 723 724 private static void assertTrueForKey(String msg, CameraCharacteristics.Key<?> key, 725 boolean actual) { 726 assertTrue(msg + " (key = '" + key.getName() + "')", actual); 727 } 728 729 private static <T> void assertOneOf(String msg, T[] expected, T actual) { 730 for (int i = 0; i < expected.length; ++i) { 731 if (Objects.equals(expected[i], actual)) { 732 return; 733 } 734 } 735 736 fail(String.format("%s: (expected one of %s, actual %s)", 737 msg, Arrays.toString(expected), actual)); 738 } 739 740 private static <T> void assertStartsWithAnyOf(String msg, String[] expected, String actual) { 741 for (int i = 0; i < expected.length; ++i) { 742 if (actual.startsWith(expected[i])) { 743 return; 744 } 745 } 746 747 fail(String.format("%s: (expected to start with any of %s, but value was %s)", 748 msg, Arrays.toString(expected), actual)); 749 } 750 751 /** Return a positive int if left > right, 0 if left==right, negative int if left < right */ 752 private static int compareHardwareLevel(int left, int right) { 753 return remapHardwareLevel(left) - remapHardwareLevel(right); 754 } 755 756 /** Remap HW levels worst<->best, 0 = worst, 2 = best */ 757 private static int remapHardwareLevel(int level) { 758 switch (level) { 759 case OPT: 760 return Integer.MAX_VALUE; 761 case LEGACY: 762 return 0; // lowest 763 case LIMITED: 764 return 1; // second lowest 765 case FULL: 766 return 2; // best 767 } 768 769 fail("Unknown HW level: " + level); 770 return -1; 771 } 772 773 private static String toStringHardwareLevel(int level) { 774 switch (level) { 775 case LEGACY: 776 return "LEGACY"; 777 case LIMITED: 778 return "LIMITED"; 779 case FULL: 780 return "FULL"; 781 } 782 783 // unknown 784 Log.w(TAG, "Unknown hardware level " + level); 785 return Integer.toString(level); 786 } 787 } 788