1 /* 2 * Copyright 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 static android.hardware.camera2.cts.CameraTestUtils.*; 20 import static android.hardware.camera2.CameraCharacteristics.*; 21 22 import android.graphics.Point; 23 import android.graphics.PointF; 24 import android.graphics.Rect; 25 import android.hardware.camera2.CameraCharacteristics; 26 import android.hardware.camera2.CameraDevice; 27 import android.hardware.camera2.CameraMetadata; 28 import android.hardware.camera2.CaptureRequest; 29 import android.hardware.camera2.CaptureResult; 30 import android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback; 31 import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase; 32 import android.hardware.camera2.params.ColorSpaceTransform; 33 import android.hardware.camera2.params.Face; 34 import android.hardware.camera2.params.LensShadingMap; 35 import android.hardware.camera2.params.MeteringRectangle; 36 import android.hardware.camera2.params.RggbChannelVector; 37 import android.hardware.camera2.params.TonemapCurve; 38 39 import android.util.Log; 40 import android.util.Range; 41 import android.util.Rational; 42 import android.util.Size; 43 44 import java.util.ArrayList; 45 import java.util.Arrays; 46 import java.util.List; 47 48 /** 49 * <p> 50 * Basic test for camera CaptureRequest key controls. 51 * </p> 52 * <p> 53 * Several test categories are covered: manual sensor control, 3A control, 54 * manual ISP control and other per-frame control and synchronization. 55 * </p> 56 */ 57 public class CaptureRequestTest extends Camera2SurfaceViewTestCase { 58 private static final String TAG = "CaptureRequestTest"; 59 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 60 private static final int NUM_FRAMES_VERIFIED = 15; 61 private static final int NUM_FACE_DETECTION_FRAMES_VERIFIED = 60; 62 /** 30ms exposure time must be supported by full capability devices. */ 63 private static final long DEFAULT_EXP_TIME_NS = 30000000L; 64 private static final int DEFAULT_SENSITIVITY = 100; 65 private static final int RGGB_COLOR_CHANNEL_COUNT = 4; 66 private static final int MAX_SHADING_MAP_SIZE = 64 * 64 * RGGB_COLOR_CHANNEL_COUNT; 67 private static final int MIN_SHADING_MAP_SIZE = 1 * 1 * RGGB_COLOR_CHANNEL_COUNT; 68 private static final long IGNORE_REQUESTED_EXPOSURE_TIME_CHECK = -1L; 69 private static final long EXPOSURE_TIME_BOUNDARY_50HZ_NS = 10000000L; // 10ms 70 private static final long EXPOSURE_TIME_BOUNDARY_60HZ_NS = 8333333L; // 8.3ms, Approximation. 71 private static final long EXPOSURE_TIME_ERROR_MARGIN_NS = 100000L; // 100us, Approximation. 72 private static final int SENSITIVITY_ERROR_MARGIN = 10; // 10 73 private static final int DEFAULT_NUM_EXPOSURE_TIME_STEPS = 3; 74 private static final int DEFAULT_NUM_SENSITIVITY_STEPS = 16; 75 private static final int DEFAULT_SENSITIVITY_STEP_SIZE = 100; 76 private static final int NUM_RESULTS_WAIT_TIMEOUT = 100; 77 private static final int NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY = 8; 78 private static final int NUM_TEST_FOCUS_DISTANCES = 10; 79 // 5 percent error margin for calibrated device 80 private static final float FOCUS_DISTANCE_ERROR_PERCENT_CALIBRATED = 0.05f; 81 // 25 percent error margin for uncalibrated device 82 private static final float FOCUS_DISTANCE_ERROR_PERCENT_UNCALIBRATED = 0.25f; 83 // 10 percent error margin for approximate device 84 private static final float FOCUS_DISTANCE_ERROR_PERCENT_APPROXIMATE = 0.10f; 85 private static final int ANTI_FLICKERING_50HZ = 1; 86 private static final int ANTI_FLICKERING_60HZ = 2; 87 88 // 5 percent error margin for resulting crop regions 89 private static final float CROP_REGION_ERROR_PERCENT_DELTA = 0.05f; 90 // 1 percent error margin for centering the crop region 91 private static final float CROP_REGION_ERROR_PERCENT_CENTERED = 0.01f; 92 93 // Linear tone mapping curve example. 94 private static final float[] TONEMAP_CURVE_LINEAR = {0, 0, 1.0f, 1.0f}; 95 // Standard sRGB tone mapping, per IEC 61966-2-1:1999, with 16 control points. 96 private static final float[] TONEMAP_CURVE_SRGB = { 97 0.0000f, 0.0000f, 0.0667f, 0.2864f, 0.1333f, 0.4007f, 0.2000f, 0.4845f, 98 0.2667f, 0.5532f, 0.3333f, 0.6125f, 0.4000f, 0.6652f, 0.4667f, 0.7130f, 99 0.5333f, 0.7569f, 0.6000f, 0.7977f, 0.6667f, 0.8360f, 0.7333f, 0.8721f, 100 0.8000f, 0.9063f, 0.8667f, 0.9389f, 0.9333f, 0.9701f, 1.0000f, 1.0000f 101 }; 102 private final Rational ZERO_R = new Rational(0, 1); 103 private final Rational ONE_R = new Rational(1, 1); 104 105 private final int NUM_ALGORITHMS = 3; // AE, AWB and AF 106 private final int INDEX_ALGORITHM_AE = 0; 107 private final int INDEX_ALGORITHM_AWB = 1; 108 private final int INDEX_ALGORITHM_AF = 2; 109 110 private enum TorchSeqState { 111 RAMPING_UP, 112 FIRED, 113 RAMPING_DOWN 114 } 115 116 @Override setUp()117 protected void setUp() throws Exception { 118 super.setUp(); 119 } 120 121 @Override tearDown()122 protected void tearDown() throws Exception { 123 super.tearDown(); 124 } 125 126 /** 127 * Test black level lock when exposure value change. 128 * <p> 129 * When {@link CaptureRequest#BLACK_LEVEL_LOCK} is true in a request, the 130 * camera device should lock the black level. When the exposure values are changed, 131 * the camera may require reset black level Since changes to certain capture 132 * parameters (such as exposure time) may require resetting of black level 133 * compensation. However, the black level must remain locked after exposure 134 * value changes (when requests have lock ON). 135 * </p> 136 */ testBlackLevelLock()137 public void testBlackLevelLock() throws Exception { 138 for (int i = 0; i < mCameraIds.length; i++) { 139 try { 140 openDevice(mCameraIds[i]); 141 142 if (!mStaticInfo.isCapabilitySupported( 143 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 144 continue; 145 } 146 147 SimpleCaptureCallback listener = new SimpleCaptureCallback(); 148 CaptureRequest.Builder requestBuilder = 149 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 150 151 // Start with default manual exposure time, with black level being locked. 152 requestBuilder.set(CaptureRequest.BLACK_LEVEL_LOCK, true); 153 changeExposure(requestBuilder, DEFAULT_EXP_TIME_NS, DEFAULT_SENSITIVITY); 154 155 Size previewSz = 156 getMaxPreviewSize(mCamera.getId(), mCameraManager, 157 getPreviewSizeBound(mWindowManager, PREVIEW_SIZE_BOUND)); 158 159 startPreview(requestBuilder, previewSz, listener); 160 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 161 // No lock OFF state is allowed as the exposure is not changed. 162 verifyBlackLevelLockResults(listener, NUM_FRAMES_VERIFIED, /*maxLockOffCnt*/0); 163 164 // Double the exposure time and gain, with black level still being locked. 165 changeExposure(requestBuilder, DEFAULT_EXP_TIME_NS * 2, DEFAULT_SENSITIVITY * 2); 166 listener = new SimpleCaptureCallback(); 167 startPreview(requestBuilder, previewSz, listener); 168 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 169 // Allow at most one lock OFF state as the exposure is changed once. 170 verifyBlackLevelLockResults(listener, NUM_FRAMES_VERIFIED, /*maxLockOffCnt*/1); 171 172 stopPreview(); 173 } finally { 174 closeDevice(); 175 } 176 } 177 } 178 179 /** 180 * Basic lens shading map request test. 181 * <p> 182 * When {@link CaptureRequest#SHADING_MODE} is set to OFF, no lens shading correction will 183 * be applied by the camera device, and an identity lens shading map data 184 * will be provided if {@link CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE} is ON. 185 * </p> 186 * <p> 187 * When {@link CaptureRequest#SHADING_MODE} is set to other modes, lens shading correction 188 * will be applied by the camera device. The lens shading map data can be 189 * requested by setting {@link CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE} to ON. 190 * </p> 191 */ testLensShadingMap()192 public void testLensShadingMap() throws Exception { 193 for (int i = 0; i < mCameraIds.length; i++) { 194 try { 195 openDevice(mCameraIds[i]); 196 197 if (!mStaticInfo.isManualLensShadingMapSupported()) { 198 Log.i(TAG, "Camera " + mCameraIds[i] + 199 " doesn't support lens shading controls, skipping test"); 200 continue; 201 } 202 203 List<Integer> lensShadingMapModes = Arrays.asList(CameraTestUtils.toObject( 204 mStaticInfo.getAvailableLensShadingMapModesChecked())); 205 206 if (!lensShadingMapModes.contains(STATISTICS_LENS_SHADING_MAP_MODE_ON)) { 207 continue; 208 } 209 210 SimpleCaptureCallback listener = new SimpleCaptureCallback(); 211 CaptureRequest.Builder requestBuilder = 212 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 213 requestBuilder.set(CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE, 214 STATISTICS_LENS_SHADING_MAP_MODE_ON); 215 216 Size previewSz = 217 getMaxPreviewSize(mCamera.getId(), mCameraManager, 218 getPreviewSizeBound(mWindowManager, PREVIEW_SIZE_BOUND)); 219 List<Integer> lensShadingModes = Arrays.asList(CameraTestUtils.toObject( 220 mStaticInfo.getAvailableLensShadingModesChecked())); 221 222 // Shading map mode OFF, lensShadingMapMode ON, camera device 223 // should output unity maps. 224 if (lensShadingModes.contains(SHADING_MODE_OFF)) { 225 requestBuilder.set(CaptureRequest.SHADING_MODE, SHADING_MODE_OFF); 226 listener = new SimpleCaptureCallback(); 227 startPreview(requestBuilder, previewSz, listener); 228 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 229 verifyShadingMap(listener, NUM_FRAMES_VERIFIED, SHADING_MODE_OFF); 230 } 231 232 // Shading map mode FAST, lensShadingMapMode ON, camera device 233 // should output valid maps. 234 if (lensShadingModes.contains(SHADING_MODE_FAST)) { 235 requestBuilder.set(CaptureRequest.SHADING_MODE, SHADING_MODE_FAST); 236 237 listener = new SimpleCaptureCallback(); 238 startPreview(requestBuilder, previewSz, listener); 239 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 240 // Allow at most one lock OFF state as the exposure is changed once. 241 verifyShadingMap(listener, NUM_FRAMES_VERIFIED, SHADING_MODE_FAST); 242 } 243 244 // Shading map mode HIGH_QUALITY, lensShadingMapMode ON, camera device 245 // should output valid maps. 246 if (lensShadingModes.contains(SHADING_MODE_HIGH_QUALITY)) { 247 requestBuilder.set(CaptureRequest.SHADING_MODE, SHADING_MODE_HIGH_QUALITY); 248 249 listener = new SimpleCaptureCallback(); 250 startPreview(requestBuilder, previewSz, listener); 251 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 252 verifyShadingMap(listener, NUM_FRAMES_VERIFIED, SHADING_MODE_HIGH_QUALITY); 253 } 254 255 stopPreview(); 256 } finally { 257 closeDevice(); 258 } 259 } 260 } 261 262 /** 263 * Test {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE} control. 264 * <p> 265 * Test all available anti-banding modes, check if the exposure time adjustment is 266 * correct. 267 * </p> 268 */ testAntiBandingModes()269 public void testAntiBandingModes() throws Exception { 270 for (int i = 0; i < mCameraIds.length; i++) { 271 try { 272 openDevice(mCameraIds[i]); 273 274 // Without manual sensor control, exposure time cannot be verified 275 if (!mStaticInfo.isCapabilitySupported( 276 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 277 continue; 278 } 279 280 int[] modes = mStaticInfo.getAeAvailableAntiBandingModesChecked(); 281 282 Size previewSz = 283 getMaxPreviewSize(mCamera.getId(), mCameraManager, 284 getPreviewSizeBound(mWindowManager, PREVIEW_SIZE_BOUND)); 285 286 for (int mode : modes) { 287 antiBandingTestByMode(previewSz, mode); 288 } 289 } finally { 290 closeDevice(); 291 } 292 } 293 294 } 295 296 /** 297 * Test AE mode and lock. 298 * 299 * <p> 300 * For AE lock, when it is locked, exposure parameters shouldn't be changed. 301 * For AE modes, each mode should satisfy the per frame controls defined in 302 * API specifications. 303 * </p> 304 */ testAeModeAndLock()305 public void testAeModeAndLock() throws Exception { 306 for (int i = 0; i < mCameraIds.length; i++) { 307 try { 308 openDevice(mCameraIds[i]); 309 if (!mStaticInfo.isColorOutputSupported()) { 310 Log.i(TAG, "Camera " + mCameraIds[i] + 311 " does not support color outputs, skipping"); 312 continue; 313 } 314 315 Size maxPreviewSz = mOrderedPreviewSizes.get(0); // Max preview size. 316 317 // Update preview surface with given size for all sub-tests. 318 updatePreviewSurface(maxPreviewSz); 319 320 // Test aeMode and lock 321 int[] aeModes = mStaticInfo.getAeAvailableModesChecked(); 322 for (int mode : aeModes) { 323 aeModeAndLockTestByMode(mode); 324 } 325 } finally { 326 closeDevice(); 327 } 328 } 329 } 330 331 /** Test {@link CaptureRequest#FLASH_MODE} control. 332 * <p> 333 * For each {@link CaptureRequest#FLASH_MODE} mode, test the flash control 334 * and {@link CaptureResult#FLASH_STATE} result. 335 * </p> 336 */ testFlashControl()337 public void testFlashControl() throws Exception { 338 for (int i = 0; i < mCameraIds.length; i++) { 339 try { 340 openDevice(mCameraIds[i]); 341 if (!mStaticInfo.isColorOutputSupported()) { 342 Log.i(TAG, "Camera " + mCameraIds[i] + 343 " does not support color outputs, skipping"); 344 continue; 345 } 346 347 SimpleCaptureCallback listener = new SimpleCaptureCallback(); 348 CaptureRequest.Builder requestBuilder = 349 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 350 351 Size maxPreviewSz = mOrderedPreviewSizes.get(0); // Max preview size. 352 353 startPreview(requestBuilder, maxPreviewSz, listener); 354 355 // Flash control can only be used when the AE mode is ON or OFF. 356 flashTestByAeMode(listener, CaptureRequest.CONTROL_AE_MODE_ON); 357 358 // LEGACY won't support AE mode OFF 359 boolean aeOffModeSupported = false; 360 for (int aeMode : mStaticInfo.getAeAvailableModesChecked()) { 361 if (aeMode == CaptureRequest.CONTROL_AE_MODE_OFF) { 362 aeOffModeSupported = true; 363 } 364 } 365 if (aeOffModeSupported) { 366 flashTestByAeMode(listener, CaptureRequest.CONTROL_AE_MODE_OFF); 367 } 368 369 stopPreview(); 370 } finally { 371 closeDevice(); 372 } 373 } 374 } 375 376 /** 377 * Test face detection modes and results. 378 */ testFaceDetection()379 public void testFaceDetection() throws Exception { 380 for (int i = 0; i < mCameraIds.length; i++) { 381 try { 382 openDevice(mCameraIds[i]); 383 if (!mStaticInfo.isColorOutputSupported()) { 384 Log.i(TAG, "Camera " + mCameraIds[i] + 385 " does not support color outputs, skipping"); 386 continue; 387 } 388 faceDetectionTestByCamera(); 389 } finally { 390 closeDevice(); 391 } 392 } 393 } 394 395 /** 396 * Test tone map modes and controls. 397 */ testToneMapControl()398 public void testToneMapControl() throws Exception { 399 for (String id : mCameraIds) { 400 try { 401 openDevice(id); 402 if (!mStaticInfo.isManualToneMapSupported()) { 403 Log.i(TAG, "Camera " + id + 404 " doesn't support tone mapping controls, skipping test"); 405 continue; 406 } 407 toneMapTestByCamera(); 408 } finally { 409 closeDevice(); 410 } 411 } 412 } 413 414 /** 415 * Test color correction modes and controls. 416 */ testColorCorrectionControl()417 public void testColorCorrectionControl() throws Exception { 418 for (String id : mCameraIds) { 419 try { 420 openDevice(id); 421 if (!mStaticInfo.isColorCorrectionSupported()) { 422 Log.i(TAG, "Camera " + id + 423 " doesn't support color correction controls, skipping test"); 424 continue; 425 } 426 colorCorrectionTestByCamera(); 427 } finally { 428 closeDevice(); 429 } 430 } 431 } 432 testEdgeModeControl()433 public void testEdgeModeControl() throws Exception { 434 for (String id : mCameraIds) { 435 try { 436 openDevice(id); 437 if (!mStaticInfo.isEdgeModeControlSupported()) { 438 Log.i(TAG, "Camera " + id + 439 " doesn't support EDGE_MODE controls, skipping test"); 440 continue; 441 } 442 443 edgeModesTestByCamera(); 444 } finally { 445 closeDevice(); 446 } 447 } 448 } 449 450 /** 451 * Test focus distance control. 452 */ testFocusDistanceControl()453 public void testFocusDistanceControl() throws Exception { 454 for (String id : mCameraIds) { 455 try { 456 openDevice(id); 457 if (!mStaticInfo.hasFocuser()) { 458 Log.i(TAG, "Camera " + id + " has no focuser, skipping test"); 459 continue; 460 } 461 462 if (!mStaticInfo.isCapabilitySupported( 463 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 464 Log.i(TAG, "Camera " + id + 465 " does not support MANUAL_SENSOR, skipping test"); 466 continue; 467 } 468 469 focusDistanceTestByCamera(); 470 } finally { 471 closeDevice(); 472 } 473 } 474 } 475 testNoiseReductionModeControl()476 public void testNoiseReductionModeControl() throws Exception { 477 for (String id : mCameraIds) { 478 try { 479 openDevice(id); 480 if (!mStaticInfo.isNoiseReductionModeControlSupported()) { 481 Log.i(TAG, "Camera " + id + 482 " doesn't support noise reduction mode, skipping test"); 483 continue; 484 } 485 486 noiseReductionModeTestByCamera(); 487 } finally { 488 closeDevice(); 489 } 490 } 491 } 492 493 /** 494 * Test AWB lock control. 495 * 496 * <p>The color correction gain and transform shouldn't be changed when AWB is locked.</p> 497 */ testAwbModeAndLock()498 public void testAwbModeAndLock() throws Exception { 499 for (String id : mCameraIds) { 500 try { 501 openDevice(id); 502 if (!mStaticInfo.isColorOutputSupported()) { 503 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 504 continue; 505 } 506 awbModeAndLockTestByCamera(); 507 } finally { 508 closeDevice(); 509 } 510 } 511 } 512 513 /** 514 * Test different AF modes. 515 */ testAfModes()516 public void testAfModes() throws Exception { 517 for (String id : mCameraIds) { 518 try { 519 openDevice(id); 520 if (!mStaticInfo.isColorOutputSupported()) { 521 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 522 continue; 523 } 524 afModeTestByCamera(); 525 } finally { 526 closeDevice(); 527 } 528 } 529 } 530 531 /** 532 * Test video and optical stabilizations. 533 */ testCameraStabilizations()534 public void testCameraStabilizations() throws Exception { 535 for (String id : mCameraIds) { 536 try { 537 openDevice(id); 538 List<Key<?>> keys = mStaticInfo.getCharacteristics().getKeys(); 539 if (!(keys.contains( 540 CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES) || 541 keys.contains( 542 CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION))) { 543 Log.i(TAG, "Camera " + id + " doesn't support any stabilization modes"); 544 continue; 545 } 546 if (!mStaticInfo.isColorOutputSupported()) { 547 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 548 continue; 549 } 550 stabilizationTestByCamera(); 551 } finally { 552 closeDevice(); 553 } 554 } 555 } 556 557 /** 558 * Test digitalZoom (center wise and non-center wise), validate the returned crop regions. 559 * The max preview size is used for each camera. 560 */ testDigitalZoom()561 public void testDigitalZoom() throws Exception { 562 for (String id : mCameraIds) { 563 try { 564 openDevice(id); 565 if (!mStaticInfo.isColorOutputSupported()) { 566 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 567 continue; 568 } 569 Size maxPreviewSize = mOrderedPreviewSizes.get(0); 570 digitalZoomTestByCamera(maxPreviewSize); 571 } finally { 572 closeDevice(); 573 } 574 } 575 } 576 577 /** 578 * Test digital zoom and all preview size combinations. 579 * TODO: this and above test should all be moved to preview test class. 580 */ testDigitalZoomPreviewCombinations()581 public void testDigitalZoomPreviewCombinations() throws Exception { 582 for (String id : mCameraIds) { 583 try { 584 openDevice(id); 585 if (!mStaticInfo.isColorOutputSupported()) { 586 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 587 continue; 588 } 589 digitalZoomPreviewCombinationTestByCamera(); 590 } finally { 591 closeDevice(); 592 } 593 } 594 } 595 596 /** 597 * Test scene mode controls. 598 */ testSceneModes()599 public void testSceneModes() throws Exception { 600 for (String id : mCameraIds) { 601 try { 602 openDevice(id); 603 if (mStaticInfo.isSceneModeSupported()) { 604 sceneModeTestByCamera(); 605 } 606 } finally { 607 closeDevice(); 608 } 609 } 610 } 611 612 /** 613 * Test effect mode controls. 614 */ testEffectModes()615 public void testEffectModes() throws Exception { 616 for (String id : mCameraIds) { 617 try { 618 openDevice(id); 619 if (!mStaticInfo.isColorOutputSupported()) { 620 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 621 continue; 622 } 623 effectModeTestByCamera(); 624 } finally { 625 closeDevice(); 626 } 627 } 628 } 629 630 // TODO: add 3A state machine test. 631 noiseReductionModeTestByCamera()632 private void noiseReductionModeTestByCamera() throws Exception { 633 Size maxPrevSize = mOrderedPreviewSizes.get(0); 634 CaptureRequest.Builder requestBuilder = 635 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 636 int[] availableModes = mStaticInfo.getAvailableNoiseReductionModesChecked(); 637 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 638 startPreview(requestBuilder, maxPrevSize, resultListener); 639 640 for (int mode : availableModes) { 641 requestBuilder.set(CaptureRequest.NOISE_REDUCTION_MODE, mode); 642 resultListener = new SimpleCaptureCallback(); 643 mSession.setRepeatingRequest(requestBuilder.build(), resultListener, mHandler); 644 waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 645 646 verifyCaptureResultForKey(CaptureResult.NOISE_REDUCTION_MODE, mode, 647 resultListener, NUM_FRAMES_VERIFIED); 648 649 // Test that OFF and FAST mode should not slow down the frame rate. 650 if (mode == CaptureRequest.NOISE_REDUCTION_MODE_OFF || 651 mode == CaptureRequest.NOISE_REDUCTION_MODE_FAST) { 652 verifyFpsNotSlowDown(requestBuilder, NUM_FRAMES_VERIFIED); 653 } 654 } 655 656 stopPreview(); 657 } 658 focusDistanceTestByCamera()659 private void focusDistanceTestByCamera() throws Exception { 660 Size maxPrevSize = mOrderedPreviewSizes.get(0); 661 float[] testDistances = getFocusDistanceTestValuesInOrder(); 662 CaptureRequest.Builder requestBuilder = 663 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 664 requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF); 665 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 666 startPreview(requestBuilder, maxPrevSize, resultListener); 667 668 CaptureRequest request; 669 float[] resultDistances = new float[testDistances.length]; 670 for (int i = 0; i < testDistances.length; i++) { 671 requestBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE, testDistances[i]); 672 request = requestBuilder.build(); 673 resultListener = new SimpleCaptureCallback(); 674 mSession.setRepeatingRequest(request, resultListener, mHandler); 675 waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 676 resultDistances[i] = verifyFocusDistanceControl(testDistances[i], request, 677 resultListener); 678 if (VERBOSE) { 679 Log.v(TAG, "Capture request focus distance: " + testDistances[i] + " result: " 680 + resultDistances[i]); 681 } 682 } 683 684 // Verify the monotonicity 685 mCollector.checkArrayMonotonicityAndNotAllEqual(CameraTestUtils.toObject(resultDistances), 686 /*ascendingOrder*/true); 687 688 if (mStaticInfo.getCharacteristics().getKeys(). 689 contains(CameraCharacteristics.LENS_INFO_HYPERFOCAL_DISTANCE)) { 690 691 // Test hyperfocal distance optionally 692 float hyperFocalDistance = mStaticInfo.getHyperfocalDistanceChecked(); 693 if (hyperFocalDistance > 0) { 694 requestBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE, hyperFocalDistance); 695 request = requestBuilder.build(); 696 resultListener = new SimpleCaptureCallback(); 697 mSession.setRepeatingRequest(request, resultListener, mHandler); 698 waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 699 700 // Then wait for the lens.state to be stationary. 701 waitForResultValue(resultListener, CaptureResult.LENS_STATE, 702 CaptureResult.LENS_STATE_STATIONARY, NUM_RESULTS_WAIT_TIMEOUT); 703 // Need get reasonably accurate value. 704 CaptureResult result = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 705 Float focusDistance = getValueNotNull(result, CaptureResult.LENS_FOCUS_DISTANCE); 706 float errorMargin = FOCUS_DISTANCE_ERROR_PERCENT_UNCALIBRATED; 707 int calibrationStatus = mStaticInfo.getFocusDistanceCalibrationChecked(); 708 if (calibrationStatus == 709 CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED) { 710 errorMargin = FOCUS_DISTANCE_ERROR_PERCENT_CALIBRATED; 711 } else if (calibrationStatus == 712 CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_APPROXIMATE) { 713 errorMargin = FOCUS_DISTANCE_ERROR_PERCENT_APPROXIMATE; 714 } 715 mCollector.expectInRange("Focus distance for hyper focal should be close enough to" + 716 "requested value", focusDistance, 717 hyperFocalDistance * (1.0f - errorMargin), 718 hyperFocalDistance * (1.0f + errorMargin) 719 ); 720 } 721 } 722 } 723 724 /** 725 * Verify focus distance control. 726 * 727 * @param distance The focus distance requested 728 * @param request The capture request to control the manual focus distance 729 * @param resultListener The capture listener to recieve capture result callbacks 730 * @return the result focus distance 731 */ verifyFocusDistanceControl(float distance, CaptureRequest request, SimpleCaptureCallback resultListener)732 private float verifyFocusDistanceControl(float distance, CaptureRequest request, 733 SimpleCaptureCallback resultListener) { 734 // Need make sure the result corresponding to the request is back, then check. 735 CaptureResult result = 736 resultListener.getCaptureResultForRequest(request, NUM_RESULTS_WAIT_TIMEOUT); 737 // Then wait for the lens.state to be stationary. 738 waitForResultValue(resultListener, CaptureResult.LENS_STATE, 739 CaptureResult.LENS_STATE_STATIONARY, NUM_RESULTS_WAIT_TIMEOUT); 740 // Then check the focus distance. 741 result = resultListener.getCaptureResultForRequest(request, NUM_RESULTS_WAIT_TIMEOUT); 742 Float resultDistance = getValueNotNull(result, CaptureResult.LENS_FOCUS_DISTANCE); 743 if (mStaticInfo.getFocusDistanceCalibrationChecked() == 744 CameraCharacteristics.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED) { 745 // TODO: what's more to test for CALIBRATED devices? 746 } 747 748 float minValue = 0; 749 float maxValue = mStaticInfo.getMinimumFocusDistanceChecked(); 750 mCollector.expectInRange("Result focus distance is out of range", 751 resultDistance, minValue, maxValue); 752 753 return resultDistance; 754 } 755 756 /** 757 * Verify edge mode control results. 758 */ edgeModesTestByCamera()759 private void edgeModesTestByCamera() throws Exception { 760 Size maxPrevSize = mOrderedPreviewSizes.get(0); 761 int[] edgeModes = mStaticInfo.getAvailableEdgeModesChecked(); 762 CaptureRequest.Builder requestBuilder = 763 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 764 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 765 startPreview(requestBuilder, maxPrevSize, resultListener); 766 767 for (int mode : edgeModes) { 768 requestBuilder.set(CaptureRequest.EDGE_MODE, mode); 769 resultListener = new SimpleCaptureCallback(); 770 mSession.setRepeatingRequest(requestBuilder.build(), resultListener, mHandler); 771 waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 772 773 verifyCaptureResultForKey(CaptureResult.EDGE_MODE, mode, resultListener, 774 NUM_FRAMES_VERIFIED); 775 776 // Test that OFF and FAST mode should not slow down the frame rate. 777 if (mode == CaptureRequest.EDGE_MODE_OFF || 778 mode == CaptureRequest.EDGE_MODE_FAST) { 779 verifyFpsNotSlowDown(requestBuilder, NUM_FRAMES_VERIFIED); 780 } 781 } 782 783 stopPreview(); 784 } 785 786 /** 787 * Test color correction controls. 788 * 789 * <p>Test different color correction modes. For TRANSFORM_MATRIX, only test 790 * the unit gain and identity transform.</p> 791 */ colorCorrectionTestByCamera()792 private void colorCorrectionTestByCamera() throws Exception { 793 CaptureRequest request; 794 CaptureResult result; 795 Size maxPreviewSz = mOrderedPreviewSizes.get(0); // Max preview size. 796 updatePreviewSurface(maxPreviewSz); 797 CaptureRequest.Builder manualRequestBuilder = createRequestForPreview(); 798 CaptureRequest.Builder previewRequestBuilder = createRequestForPreview(); 799 SimpleCaptureCallback listener = new SimpleCaptureCallback(); 800 801 startPreview(previewRequestBuilder, maxPreviewSz, listener); 802 803 // Default preview result should give valid color correction metadata. 804 result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 805 validateColorCorrectionResult(result, 806 previewRequestBuilder.get(CaptureRequest.COLOR_CORRECTION_MODE)); 807 int colorCorrectionMode = CaptureRequest.COLOR_CORRECTION_MODE_TRANSFORM_MATRIX; 808 // TRANSFORM_MATRIX mode 809 // Only test unit gain and identity transform 810 List<Integer> availableControlModes = Arrays.asList( 811 CameraTestUtils.toObject(mStaticInfo.getAvailableControlModesChecked())); 812 List<Integer> availableAwbModes = Arrays.asList( 813 CameraTestUtils.toObject(mStaticInfo.getAwbAvailableModesChecked())); 814 boolean isManualCCSupported = 815 availableControlModes.contains(CaptureRequest.CONTROL_MODE_OFF) || 816 availableAwbModes.contains(CaptureRequest.CONTROL_AWB_MODE_OFF); 817 if (isManualCCSupported) { 818 if (!availableControlModes.contains(CaptureRequest.CONTROL_MODE_OFF)) { 819 // Only manual AWB mode is supported 820 manualRequestBuilder.set(CaptureRequest.CONTROL_MODE, 821 CaptureRequest.CONTROL_MODE_AUTO); 822 manualRequestBuilder.set(CaptureRequest.CONTROL_AWB_MODE, 823 CaptureRequest.CONTROL_AWB_MODE_OFF); 824 } else { 825 // All 3A manual controls are supported, it doesn't matter what we set for AWB mode. 826 manualRequestBuilder.set(CaptureRequest.CONTROL_MODE, 827 CaptureRequest.CONTROL_MODE_OFF); 828 } 829 830 RggbChannelVector UNIT_GAIN = new RggbChannelVector(1.0f, 1.0f, 1.0f, 1.0f); 831 832 ColorSpaceTransform IDENTITY_TRANSFORM = new ColorSpaceTransform( 833 new Rational[] { 834 ONE_R, ZERO_R, ZERO_R, 835 ZERO_R, ONE_R, ZERO_R, 836 ZERO_R, ZERO_R, ONE_R 837 }); 838 839 manualRequestBuilder.set(CaptureRequest.COLOR_CORRECTION_MODE, colorCorrectionMode); 840 manualRequestBuilder.set(CaptureRequest.COLOR_CORRECTION_GAINS, UNIT_GAIN); 841 manualRequestBuilder.set(CaptureRequest.COLOR_CORRECTION_TRANSFORM, IDENTITY_TRANSFORM); 842 request = manualRequestBuilder.build(); 843 mSession.capture(request, listener, mHandler); 844 result = listener.getCaptureResultForRequest(request, NUM_RESULTS_WAIT_TIMEOUT); 845 RggbChannelVector gains = result.get(CaptureResult.COLOR_CORRECTION_GAINS); 846 ColorSpaceTransform transform = result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM); 847 validateColorCorrectionResult(result, colorCorrectionMode); 848 mCollector.expectEquals("control mode result/request mismatch", 849 CaptureResult.CONTROL_MODE_OFF, result.get(CaptureResult.CONTROL_MODE)); 850 mCollector.expectEquals("Color correction gain result/request mismatch", 851 UNIT_GAIN, gains); 852 mCollector.expectEquals("Color correction gain result/request mismatch", 853 IDENTITY_TRANSFORM, transform); 854 855 } 856 857 // FAST mode 858 colorCorrectionMode = CaptureRequest.COLOR_CORRECTION_MODE_FAST; 859 manualRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO); 860 manualRequestBuilder.set(CaptureRequest.COLOR_CORRECTION_MODE, colorCorrectionMode); 861 request = manualRequestBuilder.build(); 862 mSession.capture(request, listener, mHandler); 863 result = listener.getCaptureResultForRequest(request, NUM_RESULTS_WAIT_TIMEOUT); 864 validateColorCorrectionResult(result, colorCorrectionMode); 865 mCollector.expectEquals("control mode result/request mismatch", 866 CaptureResult.CONTROL_MODE_AUTO, result.get(CaptureResult.CONTROL_MODE)); 867 868 // HIGH_QUALITY mode 869 colorCorrectionMode = CaptureRequest.COLOR_CORRECTION_MODE_HIGH_QUALITY; 870 manualRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO); 871 manualRequestBuilder.set(CaptureRequest.COLOR_CORRECTION_MODE, colorCorrectionMode); 872 request = manualRequestBuilder.build(); 873 mSession.capture(request, listener, mHandler); 874 result = listener.getCaptureResultForRequest(request, NUM_RESULTS_WAIT_TIMEOUT); 875 validateColorCorrectionResult(result, colorCorrectionMode); 876 mCollector.expectEquals("control mode result/request mismatch", 877 CaptureResult.CONTROL_MODE_AUTO, result.get(CaptureResult.CONTROL_MODE)); 878 } 879 validateColorCorrectionResult(CaptureResult result, int colorCorrectionMode)880 private void validateColorCorrectionResult(CaptureResult result, int colorCorrectionMode) { 881 final RggbChannelVector ZERO_GAINS = new RggbChannelVector(0, 0, 0, 0); 882 final int TRANSFORM_SIZE = 9; 883 Rational[] zeroTransform = new Rational[TRANSFORM_SIZE]; 884 Arrays.fill(zeroTransform, ZERO_R); 885 final ColorSpaceTransform ZERO_TRANSFORM = new ColorSpaceTransform(zeroTransform); 886 887 RggbChannelVector resultGain; 888 if ((resultGain = mCollector.expectKeyValueNotNull(result, 889 CaptureResult.COLOR_CORRECTION_GAINS)) != null) { 890 mCollector.expectKeyValueNotEquals(result, 891 CaptureResult.COLOR_CORRECTION_GAINS, ZERO_GAINS); 892 } 893 894 ColorSpaceTransform resultTransform; 895 if ((resultTransform = mCollector.expectKeyValueNotNull(result, 896 CaptureResult.COLOR_CORRECTION_TRANSFORM)) != null) { 897 mCollector.expectKeyValueNotEquals(result, 898 CaptureResult.COLOR_CORRECTION_TRANSFORM, ZERO_TRANSFORM); 899 } 900 901 mCollector.expectEquals("color correction mode result/request mismatch", 902 colorCorrectionMode, result.get(CaptureResult.COLOR_CORRECTION_MODE)); 903 } 904 905 /** 906 * Test flash mode control by AE mode. 907 * <p> 908 * Only allow AE mode ON or OFF, because other AE mode could run into conflict with 909 * flash manual control. This function expects the camera to already have an active 910 * repeating request and be sending results to the listener. 911 * </p> 912 * 913 * @param listener The Capture listener that is used to wait for capture result 914 * @param aeMode The AE mode for flash to test with 915 */ flashTestByAeMode(SimpleCaptureCallback listener, int aeMode)916 private void flashTestByAeMode(SimpleCaptureCallback listener, int aeMode) throws Exception { 917 CaptureResult result; 918 final int NUM_FLASH_REQUESTS_TESTED = 10; 919 CaptureRequest.Builder requestBuilder = createRequestForPreview(); 920 921 if (aeMode == CaptureRequest.CONTROL_AE_MODE_ON) { 922 requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, aeMode); 923 } else if (aeMode == CaptureRequest.CONTROL_AE_MODE_OFF) { 924 changeExposure(requestBuilder, DEFAULT_EXP_TIME_NS, DEFAULT_SENSITIVITY); 925 } else { 926 throw new IllegalArgumentException("This test only works when AE mode is ON or OFF"); 927 } 928 929 mSession.setRepeatingRequest(requestBuilder.build(), listener, mHandler); 930 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 931 932 // For camera that doesn't have flash unit, flash state should always be UNAVAILABLE. 933 if (mStaticInfo.getFlashInfoChecked() == false) { 934 for (int i = 0; i < NUM_FLASH_REQUESTS_TESTED; i++) { 935 result = listener.getCaptureResult(CAPTURE_RESULT_TIMEOUT_MS); 936 mCollector.expectEquals("No flash unit available, flash state must be UNAVAILABLE" 937 + "for AE mode " + aeMode, CaptureResult.FLASH_STATE_UNAVAILABLE, 938 result.get(CaptureResult.FLASH_STATE)); 939 } 940 941 return; 942 } 943 944 // Test flash SINGLE mode control. Wait for flash state to be READY first. 945 if (mStaticInfo.isHardwareLevelLimitedOrBetter()) { 946 waitForResultValue(listener, CaptureResult.FLASH_STATE, CaptureResult.FLASH_STATE_READY, 947 NUM_RESULTS_WAIT_TIMEOUT); 948 } // else the settings were already waited on earlier 949 950 requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_SINGLE); 951 CaptureRequest flashSinglerequest = requestBuilder.build(); 952 953 int flashModeSingleRequests = captureRequestsSynchronized( 954 flashSinglerequest, listener, mHandler); 955 waitForNumResults(listener, flashModeSingleRequests - 1); 956 result = listener.getCaptureResultForRequest(flashSinglerequest, NUM_RESULTS_WAIT_TIMEOUT); 957 // Result mode must be SINGLE, state must be FIRED. 958 mCollector.expectEquals("Flash mode result must be SINGLE", 959 CaptureResult.FLASH_MODE_SINGLE, result.get(CaptureResult.FLASH_MODE)); 960 mCollector.expectEquals("Flash state result must be FIRED", 961 CaptureResult.FLASH_STATE_FIRED, result.get(CaptureResult.FLASH_STATE)); 962 963 // Test flash TORCH mode control. 964 requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH); 965 CaptureRequest torchRequest = requestBuilder.build(); 966 967 int flashModeTorchRequests = captureRequestsSynchronized(torchRequest, 968 NUM_FLASH_REQUESTS_TESTED, listener, mHandler); 969 waitForNumResults(listener, flashModeTorchRequests - NUM_FLASH_REQUESTS_TESTED); 970 971 // Verify the results 972 TorchSeqState state = TorchSeqState.RAMPING_UP; 973 for (int i = 0; i < NUM_FLASH_REQUESTS_TESTED; i++) { 974 result = listener.getCaptureResultForRequest(torchRequest, 975 NUM_RESULTS_WAIT_TIMEOUT); 976 int flashMode = result.get(CaptureResult.FLASH_MODE); 977 int flashState = result.get(CaptureResult.FLASH_STATE); 978 // Result mode must be TORCH 979 mCollector.expectEquals("Flash mode result " + i + " must be TORCH", 980 CaptureResult.FLASH_MODE_TORCH, result.get(CaptureResult.FLASH_MODE)); 981 if (state == TorchSeqState.RAMPING_UP && 982 flashState == CaptureResult.FLASH_STATE_FIRED) { 983 state = TorchSeqState.FIRED; 984 } else if (state == TorchSeqState.FIRED && 985 flashState == CaptureResult.FLASH_STATE_PARTIAL) { 986 state = TorchSeqState.RAMPING_DOWN; 987 } 988 989 if (i == 0 && mStaticInfo.isPerFrameControlSupported()) { 990 mCollector.expectTrue( 991 "Per frame control device must enter FIRED state on first torch request", 992 state == TorchSeqState.FIRED); 993 } 994 995 if (state == TorchSeqState.FIRED) { 996 mCollector.expectEquals("Flash state result " + i + " must be FIRED", 997 CaptureResult.FLASH_STATE_FIRED, result.get(CaptureResult.FLASH_STATE)); 998 } else { 999 mCollector.expectEquals("Flash state result " + i + " must be PARTIAL", 1000 CaptureResult.FLASH_STATE_PARTIAL, result.get(CaptureResult.FLASH_STATE)); 1001 } 1002 } 1003 mCollector.expectTrue("Torch state FIRED never seen", 1004 state == TorchSeqState.FIRED || state == TorchSeqState.RAMPING_DOWN); 1005 1006 // Test flash OFF mode control 1007 requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); 1008 CaptureRequest flashOffrequest = requestBuilder.build(); 1009 1010 int flashModeOffRequests = captureRequestsSynchronized(flashOffrequest, listener, mHandler); 1011 waitForNumResults(listener, flashModeOffRequests - 1); 1012 result = listener.getCaptureResultForRequest(flashOffrequest, NUM_RESULTS_WAIT_TIMEOUT); 1013 mCollector.expectEquals("Flash mode result must be OFF", CaptureResult.FLASH_MODE_OFF, 1014 result.get(CaptureResult.FLASH_MODE)); 1015 } 1016 verifyAntiBandingMode(SimpleCaptureCallback listener, int numFramesVerified, int mode, boolean isAeManual, long requestExpTime)1017 private void verifyAntiBandingMode(SimpleCaptureCallback listener, int numFramesVerified, 1018 int mode, boolean isAeManual, long requestExpTime) throws Exception { 1019 // Skip the first a couple of frames as antibanding may not be fully up yet. 1020 final int NUM_FRAMES_SKIPPED = 5; 1021 for (int i = 0; i < NUM_FRAMES_SKIPPED; i++) { 1022 listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 1023 } 1024 1025 for (int i = 0; i < numFramesVerified; i++) { 1026 CaptureResult result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 1027 Long resultExpTime = result.get(CaptureResult.SENSOR_EXPOSURE_TIME); 1028 assertNotNull("Exposure time shouldn't be null", resultExpTime); 1029 Integer flicker = result.get(CaptureResult.STATISTICS_SCENE_FLICKER); 1030 // Scene flicker result should be always available. 1031 assertNotNull("Scene flicker must not be null", flicker); 1032 assertTrue("Scene flicker is invalid", flicker >= STATISTICS_SCENE_FLICKER_NONE && 1033 flicker <= STATISTICS_SCENE_FLICKER_60HZ); 1034 1035 if (isAeManual) { 1036 // First, round down not up, second, need close enough. 1037 validateExposureTime(requestExpTime, resultExpTime); 1038 return; 1039 } 1040 1041 long expectedExpTime = resultExpTime; // Default, no exposure adjustment. 1042 if (mode == CONTROL_AE_ANTIBANDING_MODE_50HZ) { 1043 // result exposure time must be adjusted by 50Hz illuminant source. 1044 expectedExpTime = 1045 getAntiFlickeringExposureTime(ANTI_FLICKERING_50HZ, resultExpTime); 1046 } else if (mode == CONTROL_AE_ANTIBANDING_MODE_60HZ) { 1047 // result exposure time must be adjusted by 60Hz illuminant source. 1048 expectedExpTime = 1049 getAntiFlickeringExposureTime(ANTI_FLICKERING_60HZ, resultExpTime); 1050 } else if (mode == CONTROL_AE_ANTIBANDING_MODE_AUTO){ 1051 /** 1052 * Use STATISTICS_SCENE_FLICKER to tell the illuminant source 1053 * and do the exposure adjustment. 1054 */ 1055 expectedExpTime = resultExpTime; 1056 if (flicker == STATISTICS_SCENE_FLICKER_60HZ) { 1057 expectedExpTime = 1058 getAntiFlickeringExposureTime(ANTI_FLICKERING_60HZ, resultExpTime); 1059 } else if (flicker == STATISTICS_SCENE_FLICKER_50HZ) { 1060 expectedExpTime = 1061 getAntiFlickeringExposureTime(ANTI_FLICKERING_50HZ, resultExpTime); 1062 } 1063 } 1064 1065 if (Math.abs(resultExpTime - expectedExpTime) > EXPOSURE_TIME_ERROR_MARGIN_NS) { 1066 mCollector.addMessage(String.format("Result exposure time %dns diverges too much" 1067 + " from expected exposure time %dns for mode %d when AE is auto", 1068 resultExpTime, expectedExpTime, mode)); 1069 } 1070 } 1071 } 1072 antiBandingTestByMode(Size size, int mode)1073 private void antiBandingTestByMode(Size size, int mode) 1074 throws Exception { 1075 if(VERBOSE) { 1076 Log.v(TAG, "Anti-banding test for mode " + mode + " for camera " + mCamera.getId()); 1077 } 1078 CaptureRequest.Builder requestBuilder = 1079 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 1080 1081 requestBuilder.set(CaptureRequest.CONTROL_AE_ANTIBANDING_MODE, mode); 1082 1083 // Test auto AE mode anti-banding behavior 1084 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 1085 startPreview(requestBuilder, size, resultListener); 1086 waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 1087 verifyAntiBandingMode(resultListener, NUM_FRAMES_VERIFIED, mode, /*isAeManual*/false, 1088 IGNORE_REQUESTED_EXPOSURE_TIME_CHECK); 1089 1090 // Test manual AE mode anti-banding behavior 1091 // 65ms, must be supported by full capability devices. 1092 final long TEST_MANUAL_EXP_TIME_NS = 65000000L; 1093 long manualExpTime = mStaticInfo.getExposureClampToRange(TEST_MANUAL_EXP_TIME_NS); 1094 changeExposure(requestBuilder, manualExpTime); 1095 resultListener = new SimpleCaptureCallback(); 1096 startPreview(requestBuilder, size, resultListener); 1097 waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 1098 verifyAntiBandingMode(resultListener, NUM_FRAMES_VERIFIED, mode, /*isAeManual*/true, 1099 manualExpTime); 1100 1101 stopPreview(); 1102 } 1103 1104 /** 1105 * Test the all available AE modes and AE lock. 1106 * <p> 1107 * For manual AE mode, test iterates through different sensitivities and 1108 * exposure times, validate the result exposure time correctness. For 1109 * CONTROL_AE_MODE_ON_ALWAYS_FLASH mode, the AE lock and flash are tested. 1110 * For the rest of the AUTO mode, AE lock is tested. 1111 * </p> 1112 * 1113 * @param mode 1114 */ aeModeAndLockTestByMode(int mode)1115 private void aeModeAndLockTestByMode(int mode) 1116 throws Exception { 1117 switch (mode) { 1118 case CONTROL_AE_MODE_OFF: 1119 if (mStaticInfo.isCapabilitySupported( 1120 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 1121 // Test manual exposure control. 1122 aeManualControlTest(); 1123 } else { 1124 Log.w(TAG, 1125 "aeModeAndLockTestByMode - can't test AE mode OFF without " + 1126 "manual sensor control"); 1127 } 1128 break; 1129 case CONTROL_AE_MODE_ON: 1130 case CONTROL_AE_MODE_ON_AUTO_FLASH: 1131 case CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE: 1132 case CONTROL_AE_MODE_ON_ALWAYS_FLASH: 1133 // Test AE lock for above AUTO modes. 1134 aeAutoModeTestLock(mode); 1135 break; 1136 default: 1137 throw new UnsupportedOperationException("Unhandled AE mode " + mode); 1138 } 1139 } 1140 1141 /** 1142 * Test AE auto modes. 1143 * <p> 1144 * Use single request rather than repeating request to test AE lock per frame control. 1145 * </p> 1146 */ aeAutoModeTestLock(int mode)1147 private void aeAutoModeTestLock(int mode) throws Exception { 1148 CaptureRequest.Builder requestBuilder = 1149 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 1150 if (mStaticInfo.isAeLockSupported()) { 1151 requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false); 1152 } 1153 requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, mode); 1154 configurePreviewOutput(requestBuilder); 1155 1156 final int MAX_NUM_CAPTURES_DURING_LOCK = 5; 1157 for (int i = 1; i <= MAX_NUM_CAPTURES_DURING_LOCK; i++) { 1158 autoAeMultipleCapturesThenTestLock(requestBuilder, mode, i); 1159 } 1160 } 1161 1162 /** 1163 * Issue multiple auto AE captures, then lock AE, validate the AE lock vs. 1164 * the first capture result after the AE lock. The right AE lock behavior is: 1165 * When it is locked, it locks to the current exposure value, and all subsequent 1166 * request with lock ON will have the same exposure value locked. 1167 */ autoAeMultipleCapturesThenTestLock( CaptureRequest.Builder requestBuilder, int aeMode, int numCapturesDuringLock)1168 private void autoAeMultipleCapturesThenTestLock( 1169 CaptureRequest.Builder requestBuilder, int aeMode, int numCapturesDuringLock) 1170 throws Exception { 1171 if (numCapturesDuringLock < 1) { 1172 throw new IllegalArgumentException("numCapturesBeforeLock must be no less than 1"); 1173 } 1174 if (VERBOSE) { 1175 Log.v(TAG, "Camera " + mCamera.getId() + ": Testing auto AE mode and lock for mode " 1176 + aeMode + " with " + numCapturesDuringLock + " captures before lock"); 1177 } 1178 1179 final int NUM_CAPTURES_BEFORE_LOCK = 2; 1180 SimpleCaptureCallback listener = new SimpleCaptureCallback(); 1181 1182 CaptureResult[] resultsDuringLock = new CaptureResult[numCapturesDuringLock]; 1183 boolean canSetAeLock = mStaticInfo.isAeLockSupported(); 1184 1185 // Reset the AE lock to OFF, since we are reusing this builder many times 1186 if (canSetAeLock) { 1187 requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false); 1188 } 1189 1190 // Just send several captures with auto AE, lock off. 1191 CaptureRequest request = requestBuilder.build(); 1192 for (int i = 0; i < NUM_CAPTURES_BEFORE_LOCK; i++) { 1193 mSession.capture(request, listener, mHandler); 1194 } 1195 waitForNumResults(listener, NUM_CAPTURES_BEFORE_LOCK); 1196 1197 if (!canSetAeLock) { 1198 // Without AE lock, the remaining tests items won't work 1199 return; 1200 } 1201 1202 // Then fire several capture to lock the AE. 1203 requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true); 1204 1205 int requestCount = captureRequestsSynchronized( 1206 requestBuilder.build(), numCapturesDuringLock, listener, mHandler); 1207 1208 int[] sensitivities = new int[numCapturesDuringLock]; 1209 long[] expTimes = new long[numCapturesDuringLock]; 1210 Arrays.fill(sensitivities, -1); 1211 Arrays.fill(expTimes, -1L); 1212 1213 // Get the AE lock on result and validate the exposure values. 1214 waitForNumResults(listener, requestCount - numCapturesDuringLock); 1215 for (int i = 0; i < resultsDuringLock.length; i++) { 1216 resultsDuringLock[i] = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 1217 } 1218 1219 for (int i = 0; i < numCapturesDuringLock; i++) { 1220 mCollector.expectKeyValueEquals( 1221 resultsDuringLock[i], CaptureResult.CONTROL_AE_LOCK, true); 1222 } 1223 1224 // Can't read manual sensor/exposure settings without manual sensor 1225 if (mStaticInfo.isCapabilitySupported( 1226 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS)) { 1227 int sensitivityLocked = 1228 getValueNotNull(resultsDuringLock[0], CaptureResult.SENSOR_SENSITIVITY); 1229 long expTimeLocked = 1230 getValueNotNull(resultsDuringLock[0], CaptureResult.SENSOR_EXPOSURE_TIME); 1231 for (int i = 1; i < resultsDuringLock.length; i++) { 1232 mCollector.expectKeyValueEquals( 1233 resultsDuringLock[i], CaptureResult.SENSOR_EXPOSURE_TIME, expTimeLocked); 1234 mCollector.expectKeyValueEquals( 1235 resultsDuringLock[i], CaptureResult.SENSOR_SENSITIVITY, sensitivityLocked); 1236 } 1237 } 1238 } 1239 1240 /** 1241 * Iterate through exposure times and sensitivities for manual AE control. 1242 * <p> 1243 * Use single request rather than repeating request to test manual exposure 1244 * value change per frame control. 1245 * </p> 1246 */ aeManualControlTest()1247 private void aeManualControlTest() 1248 throws Exception { 1249 CaptureRequest.Builder requestBuilder = 1250 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 1251 1252 requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CONTROL_AE_MODE_OFF); 1253 configurePreviewOutput(requestBuilder); 1254 SimpleCaptureCallback listener = new SimpleCaptureCallback(); 1255 1256 long[] expTimes = getExposureTimeTestValues(); 1257 int[] sensitivities = getSensitivityTestValues(); 1258 // Submit single request at a time, then verify the result. 1259 for (int i = 0; i < expTimes.length; i++) { 1260 for (int j = 0; j < sensitivities.length; j++) { 1261 if (VERBOSE) { 1262 Log.v(TAG, "Camera " + mCamera.getId() + ": Testing sensitivity " 1263 + sensitivities[j] + ", exposure time " + expTimes[i] + "ns"); 1264 } 1265 1266 changeExposure(requestBuilder, expTimes[i], sensitivities[j]); 1267 mSession.capture(requestBuilder.build(), listener, mHandler); 1268 1269 // make sure timeout is long enough for long exposure time 1270 long timeout = WAIT_FOR_RESULT_TIMEOUT_MS + expTimes[i]; 1271 CaptureResult result = listener.getCaptureResult(timeout); 1272 long resultExpTime = getValueNotNull(result, CaptureResult.SENSOR_EXPOSURE_TIME); 1273 int resultSensitivity = getValueNotNull(result, CaptureResult.SENSOR_SENSITIVITY); 1274 validateExposureTime(expTimes[i], resultExpTime); 1275 validateSensitivity(sensitivities[j], resultSensitivity); 1276 validateFrameDurationForCapture(result); 1277 } 1278 } 1279 // TODO: Add another case to test where we can submit all requests, then wait for 1280 // results, which will hide the pipeline latency. this is not only faster, but also 1281 // test high speed per frame control and synchronization. 1282 } 1283 1284 1285 /** 1286 * Verify black level lock control. 1287 */ verifyBlackLevelLockResults(SimpleCaptureCallback listener, int numFramesVerified, int maxLockOffCnt)1288 private void verifyBlackLevelLockResults(SimpleCaptureCallback listener, int numFramesVerified, 1289 int maxLockOffCnt) throws Exception { 1290 int noLockCnt = 0; 1291 for (int i = 0; i < numFramesVerified; i++) { 1292 CaptureResult result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 1293 Boolean blackLevelLock = result.get(CaptureResult.BLACK_LEVEL_LOCK); 1294 assertNotNull("Black level lock result shouldn't be null", blackLevelLock); 1295 1296 // Count the lock == false result, which could possibly occur at most once. 1297 if (blackLevelLock == false) { 1298 noLockCnt++; 1299 } 1300 1301 if(VERBOSE) { 1302 Log.v(TAG, "Black level lock result: " + blackLevelLock); 1303 } 1304 } 1305 assertTrue("Black level lock OFF occurs " + noLockCnt + " times, expect at most " 1306 + maxLockOffCnt + " for camera " + mCamera.getId(), noLockCnt <= maxLockOffCnt); 1307 } 1308 1309 /** 1310 * Verify shading map for different shading modes. 1311 */ verifyShadingMap(SimpleCaptureCallback listener, int numFramesVerified, int shadingMode)1312 private void verifyShadingMap(SimpleCaptureCallback listener, int numFramesVerified, 1313 int shadingMode) throws Exception { 1314 1315 for (int i = 0; i < numFramesVerified; i++) { 1316 CaptureResult result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 1317 mCollector.expectEquals("Shading mode result doesn't match request", 1318 shadingMode, result.get(CaptureResult.SHADING_MODE)); 1319 LensShadingMap mapObj = result.get( 1320 CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP); 1321 assertNotNull("Map object must not be null", mapObj); 1322 int numElementsInMap = mapObj.getGainFactorCount(); 1323 float[] map = new float[numElementsInMap]; 1324 mapObj.copyGainFactors(map, /*offset*/0); 1325 assertNotNull("Map must not be null", map); 1326 assertFalse(String.format( 1327 "Map size %d should be less than %d", numElementsInMap, MAX_SHADING_MAP_SIZE), 1328 numElementsInMap >= MAX_SHADING_MAP_SIZE); 1329 assertFalse(String.format("Map size %d should be no less than %d", numElementsInMap, 1330 MIN_SHADING_MAP_SIZE), numElementsInMap < MIN_SHADING_MAP_SIZE); 1331 1332 if (shadingMode == CaptureRequest.SHADING_MODE_FAST || 1333 shadingMode == CaptureRequest.SHADING_MODE_HIGH_QUALITY) { 1334 // shading mode is FAST or HIGH_QUALITY, expect to receive a map with all 1335 // elements >= 1.0f 1336 1337 int badValueCnt = 0; 1338 // Detect the bad values of the map data. 1339 for (int j = 0; j < numElementsInMap; j++) { 1340 if (Float.isNaN(map[j]) || map[j] < 1.0f) { 1341 badValueCnt++; 1342 } 1343 } 1344 assertEquals("Number of value in the map is " + badValueCnt + " out of " 1345 + numElementsInMap, /*expected*/0, /*actual*/badValueCnt); 1346 } else if (shadingMode == CaptureRequest.SHADING_MODE_OFF) { 1347 float[] unityMap = new float[numElementsInMap]; 1348 Arrays.fill(unityMap, 1.0f); 1349 // shading mode is OFF, expect to receive a unity map. 1350 assertTrue("Result map " + Arrays.toString(map) + " must be an unity map", 1351 Arrays.equals(unityMap, map)); 1352 } 1353 } 1354 } 1355 1356 /** 1357 * Test face detection for a camera. 1358 */ 1359 private void faceDetectionTestByCamera() throws Exception { 1360 int[] faceDetectModes = mStaticInfo.getAvailableFaceDetectModesChecked(); 1361 1362 SimpleCaptureCallback listener; 1363 CaptureRequest.Builder requestBuilder = 1364 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 1365 1366 Size maxPreviewSz = mOrderedPreviewSizes.get(0); // Max preview size. 1367 for (int mode : faceDetectModes) { 1368 requestBuilder.set(CaptureRequest.STATISTICS_FACE_DETECT_MODE, mode); 1369 if (VERBOSE) { 1370 Log.v(TAG, "Start testing face detection mode " + mode); 1371 } 1372 1373 // Create a new listener for each run to avoid the results from one run spill 1374 // into another run. 1375 listener = new SimpleCaptureCallback(); 1376 startPreview(requestBuilder, maxPreviewSz, listener); 1377 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 1378 verifyFaceDetectionResults(listener, NUM_FACE_DETECTION_FRAMES_VERIFIED, mode); 1379 } 1380 1381 stopPreview(); 1382 } 1383 1384 /** 1385 * Verify face detection results for different face detection modes. 1386 * 1387 * @param listener The listener to get capture result 1388 * @param numFramesVerified Number of results to be verified 1389 * @param faceDetectionMode Face detection mode to be verified against 1390 */ 1391 private void verifyFaceDetectionResults(SimpleCaptureCallback listener, int numFramesVerified, 1392 int faceDetectionMode) { 1393 for (int i = 0; i < numFramesVerified; i++) { 1394 CaptureResult result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 1395 mCollector.expectEquals("Result face detection mode should match the request", 1396 faceDetectionMode, result.get(CaptureResult.STATISTICS_FACE_DETECT_MODE)); 1397 1398 Face[] faces = result.get(CaptureResult.STATISTICS_FACES); 1399 List<Integer> faceIds = new ArrayList<Integer>(faces.length); 1400 List<Integer> faceScores = new ArrayList<Integer>(faces.length); 1401 if (faceDetectionMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_OFF) { 1402 mCollector.expectEquals("Number of detection faces should always 0 for OFF mode", 1403 0, faces.length); 1404 } else if (faceDetectionMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE) { 1405 for (Face face : faces) { 1406 mCollector.expectNotNull("Face rectangle shouldn't be null", face.getBounds()); 1407 faceScores.add(face.getScore()); 1408 mCollector.expectTrue("Face id is expected to be -1 for SIMPLE mode", 1409 face.getId() == Face.ID_UNSUPPORTED); 1410 } 1411 } else if (faceDetectionMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) { 1412 if (VERBOSE) { 1413 Log.v(TAG, "Number of faces detected: " + faces.length); 1414 } 1415 1416 for (Face face : faces) { 1417 Rect faceBound; 1418 boolean faceRectAvailable = mCollector.expectTrue("Face rectangle " 1419 + "shouldn't be null", face.getBounds() != null); 1420 if (!faceRectAvailable) { 1421 continue; 1422 } 1423 faceBound = face.getBounds(); 1424 1425 faceScores.add(face.getScore()); 1426 faceIds.add(face.getId()); 1427 1428 mCollector.expectTrue("Face id is shouldn't be -1 for FULL mode", 1429 face.getId() != Face.ID_UNSUPPORTED); 1430 boolean leftEyeAvailable = 1431 mCollector.expectTrue("Left eye position shouldn't be null", 1432 face.getLeftEyePosition() != null); 1433 boolean rightEyeAvailable = 1434 mCollector.expectTrue("Right eye position shouldn't be null", 1435 face.getRightEyePosition() != null); 1436 boolean mouthAvailable = 1437 mCollector.expectTrue("Mouth position shouldn't be null", 1438 face.getMouthPosition() != null); 1439 // Eyes/mouth position should be inside of the face rect. 1440 if (leftEyeAvailable) { 1441 Point leftEye = face.getLeftEyePosition(); 1442 mCollector.expectTrue("Left eye " + leftEye + "should be" 1443 + "inside of face rect " + faceBound, 1444 faceBound.contains(leftEye.x, leftEye.y)); 1445 } 1446 if (rightEyeAvailable) { 1447 Point rightEye = face.getRightEyePosition(); 1448 mCollector.expectTrue("Right eye " + rightEye + "should be" 1449 + "inside of face rect " + faceBound, 1450 faceBound.contains(rightEye.x, rightEye.y)); 1451 } 1452 if (mouthAvailable) { 1453 Point mouth = face.getMouthPosition(); 1454 mCollector.expectTrue("Mouth " + mouth + " should be inside of" 1455 + " face rect " + faceBound, 1456 faceBound.contains(mouth.x, mouth.y)); 1457 } 1458 } 1459 } 1460 mCollector.expectValuesInRange("Face scores are invalid", faceScores, 1461 Face.SCORE_MIN, Face.SCORE_MAX); 1462 mCollector.expectValuesUnique("Face ids are invalid", faceIds); 1463 } 1464 } 1465 1466 /** 1467 * Test tone map mode and result by camera 1468 */ 1469 private void toneMapTestByCamera() throws Exception { 1470 if (!mStaticInfo.isManualToneMapSupported()) { 1471 return; 1472 } 1473 1474 CaptureRequest.Builder requestBuilder = 1475 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 1476 int[] toneMapModes = mStaticInfo.getAvailableToneMapModesChecked(); 1477 for (int mode : toneMapModes) { 1478 if (VERBOSE) { 1479 Log.v(TAG, "Testing tonemap mode " + mode); 1480 } 1481 1482 requestBuilder.set(CaptureRequest.TONEMAP_MODE, mode); 1483 switch (mode) { 1484 case CaptureRequest.TONEMAP_MODE_CONTRAST_CURVE: 1485 TonemapCurve toneCurve = new TonemapCurve(TONEMAP_CURVE_LINEAR, 1486 TONEMAP_CURVE_LINEAR, TONEMAP_CURVE_LINEAR); 1487 requestBuilder.set(CaptureRequest.TONEMAP_CURVE, toneCurve); 1488 testToneMapMode(NUM_FRAMES_VERIFIED, requestBuilder); 1489 1490 toneCurve = new TonemapCurve(TONEMAP_CURVE_SRGB, 1491 TONEMAP_CURVE_SRGB, TONEMAP_CURVE_SRGB); 1492 requestBuilder.set(CaptureRequest.TONEMAP_CURVE, toneCurve); 1493 testToneMapMode(NUM_FRAMES_VERIFIED, requestBuilder); 1494 break; 1495 case CaptureRequest.TONEMAP_MODE_GAMMA_VALUE: 1496 requestBuilder.set(CaptureRequest.TONEMAP_GAMMA, 1.0f); 1497 testToneMapMode(NUM_FRAMES_VERIFIED, requestBuilder); 1498 requestBuilder.set(CaptureRequest.TONEMAP_GAMMA, 2.2f); 1499 testToneMapMode(NUM_FRAMES_VERIFIED, requestBuilder); 1500 requestBuilder.set(CaptureRequest.TONEMAP_GAMMA, 5.0f); 1501 testToneMapMode(NUM_FRAMES_VERIFIED, requestBuilder); 1502 break; 1503 case CaptureRequest.TONEMAP_MODE_PRESET_CURVE: 1504 requestBuilder.set(CaptureRequest.TONEMAP_PRESET_CURVE, 1505 CaptureRequest.TONEMAP_PRESET_CURVE_REC709); 1506 testToneMapMode(NUM_FRAMES_VERIFIED, requestBuilder); 1507 requestBuilder.set(CaptureRequest.TONEMAP_PRESET_CURVE, 1508 CaptureRequest.TONEMAP_PRESET_CURVE_SRGB); 1509 testToneMapMode(NUM_FRAMES_VERIFIED, requestBuilder); 1510 break; 1511 default: 1512 testToneMapMode(NUM_FRAMES_VERIFIED, requestBuilder); 1513 break; 1514 } 1515 } 1516 1517 1518 } 1519 1520 /** 1521 * Test tonemap mode with speficied request settings 1522 * 1523 * @param numFramesVerified Number of results to be verified 1524 * @param requestBuilder the request builder of settings to be tested 1525 */ 1526 private void testToneMapMode (int numFramesVerified, 1527 CaptureRequest.Builder requestBuilder) throws Exception { 1528 final int MIN_TONEMAP_CURVE_POINTS = 2; 1529 final Float ZERO = new Float(0); 1530 final Float ONE = new Float(1.0f); 1531 1532 SimpleCaptureCallback listener = new SimpleCaptureCallback(); 1533 int tonemapMode = requestBuilder.get(CaptureRequest.TONEMAP_MODE); 1534 Size maxPreviewSz = mOrderedPreviewSizes.get(0); // Max preview size. 1535 startPreview(requestBuilder, maxPreviewSz, listener); 1536 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 1537 1538 int maxCurvePoints = mStaticInfo.getMaxTonemapCurvePointChecked(); 1539 for (int i = 0; i < numFramesVerified; i++) { 1540 CaptureResult result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 1541 mCollector.expectEquals("Capture result tonemap mode should match request", tonemapMode, 1542 result.get(CaptureResult.TONEMAP_MODE)); 1543 TonemapCurve tc = getValueNotNull(result, CaptureResult.TONEMAP_CURVE); 1544 int pointCount = tc.getPointCount(TonemapCurve.CHANNEL_RED); 1545 float[] mapRed = new float[pointCount * TonemapCurve.POINT_SIZE]; 1546 pointCount = tc.getPointCount(TonemapCurve.CHANNEL_GREEN); 1547 float[] mapGreen = new float[pointCount * TonemapCurve.POINT_SIZE]; 1548 pointCount = tc.getPointCount(TonemapCurve.CHANNEL_BLUE); 1549 float[] mapBlue = new float[pointCount * TonemapCurve.POINT_SIZE]; 1550 tc.copyColorCurve(TonemapCurve.CHANNEL_RED, mapRed, 0); 1551 tc.copyColorCurve(TonemapCurve.CHANNEL_GREEN, mapGreen, 0); 1552 tc.copyColorCurve(TonemapCurve.CHANNEL_BLUE, mapBlue, 0); 1553 if (tonemapMode == CaptureResult.TONEMAP_MODE_CONTRAST_CURVE) { 1554 /** 1555 * TODO: need figure out a good way to measure the difference 1556 * between request and result, as they may have different array 1557 * size. 1558 */ 1559 } else if (tonemapMode == CaptureResult.TONEMAP_MODE_GAMMA_VALUE) { 1560 mCollector.expectEquals("Capture result gamma value should match request", 1561 requestBuilder.get(CaptureRequest.TONEMAP_GAMMA), 1562 result.get(CaptureResult.TONEMAP_GAMMA)); 1563 } else if (tonemapMode == CaptureResult.TONEMAP_MODE_PRESET_CURVE) { 1564 mCollector.expectEquals("Capture result preset curve should match request", 1565 requestBuilder.get(CaptureRequest.TONEMAP_PRESET_CURVE), 1566 result.get(CaptureResult.TONEMAP_PRESET_CURVE)); 1567 } 1568 1569 // Tonemap curve result availability and basic sanity check for all modes. 1570 mCollector.expectValuesInRange("Tonemap curve red values are out of range", 1571 CameraTestUtils.toObject(mapRed), /*min*/ZERO, /*max*/ONE); 1572 mCollector.expectInRange("Tonemap curve red length is out of range", 1573 mapRed.length, MIN_TONEMAP_CURVE_POINTS, maxCurvePoints * 2); 1574 mCollector.expectValuesInRange("Tonemap curve green values are out of range", 1575 CameraTestUtils.toObject(mapGreen), /*min*/ZERO, /*max*/ONE); 1576 mCollector.expectInRange("Tonemap curve green length is out of range", 1577 mapGreen.length, MIN_TONEMAP_CURVE_POINTS, maxCurvePoints * 2); 1578 mCollector.expectValuesInRange("Tonemap curve blue values are out of range", 1579 CameraTestUtils.toObject(mapBlue), /*min*/ZERO, /*max*/ONE); 1580 mCollector.expectInRange("Tonemap curve blue length is out of range", 1581 mapBlue.length, MIN_TONEMAP_CURVE_POINTS, maxCurvePoints * 2); 1582 } 1583 stopPreview(); 1584 } 1585 1586 /** 1587 * Test awb mode control. 1588 * <p> 1589 * Test each supported AWB mode, verify the AWB mode in capture result 1590 * matches request. When AWB is locked, the color correction gains and 1591 * transform should remain unchanged. 1592 * </p> 1593 */ 1594 private void awbModeAndLockTestByCamera() throws Exception { 1595 int[] awbModes = mStaticInfo.getAwbAvailableModesChecked(); 1596 Size maxPreviewSize = mOrderedPreviewSizes.get(0); 1597 boolean canSetAwbLock = mStaticInfo.isAwbLockSupported(); 1598 CaptureRequest.Builder requestBuilder = 1599 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 1600 startPreview(requestBuilder, maxPreviewSize, /*listener*/null); 1601 1602 for (int mode : awbModes) { 1603 SimpleCaptureCallback listener; 1604 requestBuilder.set(CaptureRequest.CONTROL_AWB_MODE, mode); 1605 listener = new SimpleCaptureCallback(); 1606 mSession.setRepeatingRequest(requestBuilder.build(), listener, mHandler); 1607 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 1608 1609 // Verify AWB mode in capture result. 1610 verifyCaptureResultForKey(CaptureResult.CONTROL_AWB_MODE, mode, listener, 1611 NUM_FRAMES_VERIFIED); 1612 1613 if (mode == CameraMetadata.CONTROL_AWB_MODE_AUTO && canSetAwbLock) { 1614 // Verify color correction transform and gains stay unchanged after a lock. 1615 requestBuilder.set(CaptureRequest.CONTROL_AWB_LOCK, true); 1616 listener = new SimpleCaptureCallback(); 1617 mSession.setRepeatingRequest(requestBuilder.build(), listener, mHandler); 1618 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 1619 1620 if (mStaticInfo.areKeysAvailable(CaptureResult.CONTROL_AWB_STATE)) { 1621 waitForResultValue(listener, CaptureResult.CONTROL_AWB_STATE, 1622 CaptureResult.CONTROL_AWB_STATE_LOCKED, NUM_RESULTS_WAIT_TIMEOUT); 1623 } 1624 1625 } 1626 // Don't verify auto mode result if AWB lock is not supported 1627 if (mode != CameraMetadata.CONTROL_AWB_MODE_AUTO || canSetAwbLock) { 1628 verifyAwbCaptureResultUnchanged(listener, NUM_FRAMES_VERIFIED); 1629 } 1630 } 1631 } 1632 1633 private void verifyAwbCaptureResultUnchanged(SimpleCaptureCallback listener, 1634 int numFramesVerified) { 1635 // Skip check if cc gains/transform/mode are not available 1636 if (!mStaticInfo.areKeysAvailable( 1637 CaptureResult.COLOR_CORRECTION_GAINS, 1638 CaptureResult.COLOR_CORRECTION_TRANSFORM, 1639 CaptureResult.COLOR_CORRECTION_MODE)) { 1640 return; 1641 } 1642 1643 CaptureResult result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 1644 RggbChannelVector lockedGains = 1645 getValueNotNull(result, CaptureResult.COLOR_CORRECTION_GAINS); 1646 ColorSpaceTransform lockedTransform = 1647 getValueNotNull(result, CaptureResult.COLOR_CORRECTION_TRANSFORM); 1648 1649 for (int i = 0; i < numFramesVerified; i++) { 1650 result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 1651 // Color correction mode check is skipped here, as it is checked in colorCorrectionTest. 1652 validateColorCorrectionResult(result, result.get(CaptureResult.COLOR_CORRECTION_MODE)); 1653 1654 RggbChannelVector gains = getValueNotNull(result, CaptureResult.COLOR_CORRECTION_GAINS); 1655 ColorSpaceTransform transform = 1656 getValueNotNull(result, CaptureResult.COLOR_CORRECTION_TRANSFORM); 1657 mCollector.expectEquals("Color correction gains should remain unchanged after awb lock", 1658 lockedGains, gains); 1659 mCollector.expectEquals("Color correction transform should remain unchanged after" 1660 + " awb lock", lockedTransform, transform); 1661 } 1662 } 1663 1664 /** 1665 * Test AF mode control. 1666 * <p> 1667 * Test all supported AF modes, verify the AF mode in capture result matches 1668 * request. When AF mode is one of the CONTROL_AF_MODE_CONTINUOUS_* mode, 1669 * verify if the AF can converge to PASSIVE_FOCUSED or PASSIVE_UNFOCUSED 1670 * state within certain amount of frames. 1671 * </p> 1672 */ 1673 private void afModeTestByCamera() throws Exception { 1674 int[] afModes = mStaticInfo.getAfAvailableModesChecked(); 1675 Size maxPreviewSize = mOrderedPreviewSizes.get(0); 1676 CaptureRequest.Builder requestBuilder = 1677 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 1678 startPreview(requestBuilder, maxPreviewSize, /*listener*/null); 1679 1680 for (int mode : afModes) { 1681 SimpleCaptureCallback listener; 1682 requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, mode); 1683 listener = new SimpleCaptureCallback(); 1684 mSession.setRepeatingRequest(requestBuilder.build(), listener, mHandler); 1685 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 1686 1687 // Verify AF mode in capture result. 1688 verifyCaptureResultForKey(CaptureResult.CONTROL_AF_MODE, mode, listener, 1689 NUM_FRAMES_VERIFIED); 1690 1691 // Verify AF can finish a scan for CONTROL_AF_MODE_CONTINUOUS_* modes. 1692 // In LEGACY mode, a transition to one of the continuous AF modes does not necessarily 1693 // result in a passive AF call if the camera has already been focused, and the scene has 1694 // not changed enough to trigger an AF pass. Skip this constraint for LEGACY. 1695 if (mStaticInfo.isHardwareLevelLimitedOrBetter() && 1696 (mode == CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE || 1697 mode == CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO)) { 1698 List<Integer> afStateList = new ArrayList<Integer>(); 1699 afStateList.add(CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED); 1700 afStateList.add(CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED); 1701 waitForAnyResultValue(listener, CaptureResult.CONTROL_AF_STATE, afStateList, 1702 NUM_RESULTS_WAIT_TIMEOUT); 1703 } 1704 } 1705 } 1706 1707 /** 1708 * Test video and optical stabilizations if they are supported by a given camera. 1709 */ 1710 private void stabilizationTestByCamera() throws Exception { 1711 // video stabilization test. 1712 List<Key<?>> keys = mStaticInfo.getCharacteristics().getKeys(); 1713 1714 int[] videoStabModes = (keys.contains(CameraCharacteristics. 1715 CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES)) ? 1716 mStaticInfo.getAvailableVideoStabilizationModesChecked() : new int[0]; 1717 int[] opticalStabModes = (keys.contains( 1718 CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION)) ? 1719 mStaticInfo.getAvailableOpticalStabilizationChecked() : new int[0]; 1720 1721 Size maxPreviewSize = mOrderedPreviewSizes.get(0); 1722 CaptureRequest.Builder requestBuilder = 1723 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 1724 SimpleCaptureCallback listener = new SimpleCaptureCallback(); 1725 startPreview(requestBuilder, maxPreviewSize, listener); 1726 1727 for (int mode : videoStabModes) { 1728 listener = new SimpleCaptureCallback(); 1729 requestBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, mode); 1730 mSession.setRepeatingRequest(requestBuilder.build(), listener, mHandler); 1731 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 1732 verifyCaptureResultForKey(CaptureResult.CONTROL_VIDEO_STABILIZATION_MODE, mode, 1733 listener, NUM_FRAMES_VERIFIED); 1734 } 1735 1736 for (int mode : opticalStabModes) { 1737 listener = new SimpleCaptureCallback(); 1738 requestBuilder.set(CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE, mode); 1739 mSession.setRepeatingRequest(requestBuilder.build(), listener, mHandler); 1740 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 1741 verifyCaptureResultForKey(CaptureResult.LENS_OPTICAL_STABILIZATION_MODE, mode, 1742 listener, NUM_FRAMES_VERIFIED); 1743 } 1744 1745 stopPreview(); 1746 } 1747 1748 private void digitalZoomTestByCamera(Size previewSize) throws Exception { 1749 final int ZOOM_STEPS = 15; 1750 final PointF[] TEST_ZOOM_CENTERS; 1751 1752 final int croppingType = mStaticInfo.getScalerCroppingTypeChecked(); 1753 if (croppingType == 1754 CameraCharacteristics.SCALER_CROPPING_TYPE_FREEFORM) { 1755 TEST_ZOOM_CENTERS = new PointF[] { 1756 new PointF(0.5f, 0.5f), // Center point 1757 new PointF(0.25f, 0.25f), // top left corner zoom, minimal zoom: 2x 1758 new PointF(0.75f, 0.25f), // top right corner zoom, minimal zoom: 2x 1759 new PointF(0.25f, 0.75f), // bottom left corner zoom, minimal zoom: 2x 1760 new PointF(0.75f, 0.75f), // bottom right corner zoom, minimal zoom: 2x 1761 }; 1762 1763 if (VERBOSE) { 1764 Log.v(TAG, "Testing zoom with CROPPING_TYPE = FREEFORM"); 1765 } 1766 } else { 1767 // CENTER_ONLY 1768 TEST_ZOOM_CENTERS = new PointF[] { 1769 new PointF(0.5f, 0.5f), // Center point 1770 }; 1771 1772 if (VERBOSE) { 1773 Log.v(TAG, "Testing zoom with CROPPING_TYPE = CENTER_ONLY"); 1774 } 1775 } 1776 1777 final float maxZoom = mStaticInfo.getAvailableMaxDigitalZoomChecked(); 1778 final Rect activeArraySize = mStaticInfo.getActiveArraySizeChecked(); 1779 Rect[] cropRegions = new Rect[ZOOM_STEPS]; 1780 MeteringRectangle[][] expectRegions = new MeteringRectangle[ZOOM_STEPS][]; 1781 CaptureRequest.Builder requestBuilder = 1782 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 1783 SimpleCaptureCallback listener = new SimpleCaptureCallback(); 1784 1785 updatePreviewSurface(previewSize); 1786 configurePreviewOutput(requestBuilder); 1787 1788 CaptureRequest[] requests = new CaptureRequest[ZOOM_STEPS]; 1789 1790 // Set algorithm regions to full active region 1791 // TODO: test more different 3A regions 1792 final MeteringRectangle[] defaultMeteringRect = new MeteringRectangle[] { 1793 new MeteringRectangle ( 1794 /*x*/0, /*y*/0, activeArraySize.width(), activeArraySize.height(), 1795 /*meteringWeight*/1) 1796 }; 1797 1798 for (int algo = 0; algo < NUM_ALGORITHMS; algo++) { 1799 update3aRegion(requestBuilder, algo, defaultMeteringRect); 1800 } 1801 1802 final int CAPTURE_SUBMIT_REPEAT; 1803 { 1804 int maxLatency = mStaticInfo.getSyncMaxLatency(); 1805 if (maxLatency == CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN) { 1806 CAPTURE_SUBMIT_REPEAT = NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY + 1; 1807 } else { 1808 CAPTURE_SUBMIT_REPEAT = maxLatency + 1; 1809 } 1810 } 1811 1812 if (VERBOSE) { 1813 Log.v(TAG, "Testing zoom with CAPTURE_SUBMIT_REPEAT = " + CAPTURE_SUBMIT_REPEAT); 1814 } 1815 1816 for (PointF center : TEST_ZOOM_CENTERS) { 1817 Rect previousCrop = null; 1818 1819 for (int i = 0; i < ZOOM_STEPS; i++) { 1820 /* 1821 * Submit capture request 1822 */ 1823 float zoomFactor = (float) (1.0f + (maxZoom - 1.0) * i / ZOOM_STEPS); 1824 cropRegions[i] = getCropRegionForZoom(zoomFactor, center, maxZoom, activeArraySize); 1825 if (VERBOSE) { 1826 Log.v(TAG, "Testing Zoom for factor " + zoomFactor + " and center " + 1827 center + " The cropRegion is " + cropRegions[i] + 1828 " Preview size is " + previewSize); 1829 } 1830 requestBuilder.set(CaptureRequest.SCALER_CROP_REGION, cropRegions[i]); 1831 requests[i] = requestBuilder.build(); 1832 for (int j = 0; j < CAPTURE_SUBMIT_REPEAT; ++j) { 1833 if (VERBOSE) { 1834 Log.v(TAG, "submit crop region " + cropRegions[i]); 1835 } 1836 mSession.capture(requests[i], listener, mHandler); 1837 } 1838 1839 /* 1840 * Validate capture result 1841 */ 1842 waitForNumResults(listener, CAPTURE_SUBMIT_REPEAT - 1); // Drop first few frames 1843 CaptureResult result = listener.getCaptureResultForRequest( 1844 requests[i], NUM_RESULTS_WAIT_TIMEOUT); 1845 Rect cropRegion = getValueNotNull(result, CaptureResult.SCALER_CROP_REGION); 1846 1847 /* 1848 * Validate resulting crop regions 1849 */ 1850 if (previousCrop != null) { 1851 Rect currentCrop = cropRegion; 1852 mCollector.expectTrue(String.format( 1853 "Crop region should shrink or stay the same " + 1854 "(previous = %s, current = %s)", 1855 previousCrop, currentCrop), 1856 previousCrop.equals(currentCrop) || 1857 (previousCrop.width() > currentCrop.width() && 1858 previousCrop.height() > currentCrop.height())); 1859 } 1860 1861 if (mStaticInfo.isHardwareLevelLimitedOrBetter()) { 1862 mCollector.expectRectsAreSimilar( 1863 "Request and result crop region should be similar", 1864 cropRegions[i], cropRegion, CROP_REGION_ERROR_PERCENT_DELTA); 1865 } 1866 1867 if (croppingType == SCALER_CROPPING_TYPE_CENTER_ONLY) { 1868 mCollector.expectRectCentered( 1869 "Result crop region should be centered inside the active array", 1870 new Size(activeArraySize.width(), activeArraySize.height()), 1871 cropRegion, CROP_REGION_ERROR_PERCENT_CENTERED); 1872 } 1873 1874 /* 1875 * Validate resulting metering regions 1876 */ 1877 1878 // Use the actual reported crop region to calculate the resulting metering region 1879 expectRegions[i] = getExpectedOutputRegion( 1880 /*requestRegion*/defaultMeteringRect, 1881 /*cropRect*/ cropRegion); 1882 1883 // Verify Output 3A region is intersection of input 3A region and crop region 1884 for (int algo = 0; algo < NUM_ALGORITHMS; algo++) { 1885 validate3aRegion(result, algo, expectRegions[i]); 1886 } 1887 1888 previousCrop = cropRegion; 1889 } 1890 1891 if (maxZoom > 1.0f) { 1892 mCollector.expectTrue( 1893 String.format("Most zoomed-in crop region should be smaller" + 1894 "than active array w/h" + 1895 "(last crop = %s, active array = %s)", 1896 previousCrop, activeArraySize), 1897 (previousCrop.width() < activeArraySize.width() && 1898 previousCrop.height() < activeArraySize.height())); 1899 } 1900 } 1901 } 1902 1903 private void digitalZoomPreviewCombinationTestByCamera() throws Exception { 1904 final double ASPECT_RATIO_THRESHOLD = 0.001; 1905 List<Double> aspectRatiosTested = new ArrayList<Double>(); 1906 Size maxPreviewSize = mOrderedPreviewSizes.get(0); 1907 aspectRatiosTested.add((double)(maxPreviewSize.getWidth()) / maxPreviewSize.getHeight()); 1908 1909 for (Size size : mOrderedPreviewSizes) { 1910 // Max preview size was already tested in testDigitalZoom test. skip it. 1911 if (size.equals(maxPreviewSize)) { 1912 continue; 1913 } 1914 1915 // Only test the largest size for each aspect ratio. 1916 double aspectRatio = (double)(size.getWidth()) / size.getHeight(); 1917 if (isAspectRatioContained(aspectRatiosTested, aspectRatio, ASPECT_RATIO_THRESHOLD)) { 1918 continue; 1919 } 1920 1921 if (VERBOSE) { 1922 Log.v(TAG, "Test preview size " + size.toString() + " digital zoom"); 1923 } 1924 1925 aspectRatiosTested.add(aspectRatio); 1926 digitalZoomTestByCamera(size); 1927 } 1928 } 1929 1930 private static boolean isAspectRatioContained(List<Double> aspectRatioList, 1931 double aspectRatio, double delta) { 1932 for (Double ratio : aspectRatioList) { 1933 if (Math.abs(ratio - aspectRatio) < delta) { 1934 return true; 1935 } 1936 } 1937 1938 return false; 1939 } 1940 1941 private void sceneModeTestByCamera() throws Exception { 1942 int[] sceneModes = mStaticInfo.getAvailableSceneModesChecked(); 1943 Size maxPreviewSize = mOrderedPreviewSizes.get(0); 1944 CaptureRequest.Builder requestBuilder = 1945 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 1946 SimpleCaptureCallback listener = new SimpleCaptureCallback(); 1947 requestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_USE_SCENE_MODE); 1948 startPreview(requestBuilder, maxPreviewSize, listener); 1949 1950 for(int mode : sceneModes) { 1951 requestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, mode); 1952 listener = new SimpleCaptureCallback(); 1953 mSession.setRepeatingRequest(requestBuilder.build(), listener, mHandler); 1954 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 1955 1956 verifyCaptureResultForKey(CaptureResult.CONTROL_SCENE_MODE, 1957 mode, listener, NUM_FRAMES_VERIFIED); 1958 // This also serves as purpose of showing preview for NUM_FRAMES_VERIFIED 1959 verifyCaptureResultForKey(CaptureResult.CONTROL_MODE, 1960 CaptureRequest.CONTROL_MODE_USE_SCENE_MODE, listener, NUM_FRAMES_VERIFIED); 1961 } 1962 } 1963 1964 private void effectModeTestByCamera() throws Exception { 1965 int[] effectModes = mStaticInfo.getAvailableEffectModesChecked(); 1966 Size maxPreviewSize = mOrderedPreviewSizes.get(0); 1967 CaptureRequest.Builder requestBuilder = 1968 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 1969 requestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO); 1970 SimpleCaptureCallback listener = new SimpleCaptureCallback(); 1971 startPreview(requestBuilder, maxPreviewSize, listener); 1972 1973 for(int mode : effectModes) { 1974 requestBuilder.set(CaptureRequest.CONTROL_EFFECT_MODE, mode); 1975 listener = new SimpleCaptureCallback(); 1976 mSession.setRepeatingRequest(requestBuilder.build(), listener, mHandler); 1977 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 1978 1979 verifyCaptureResultForKey(CaptureResult.CONTROL_EFFECT_MODE, 1980 mode, listener, NUM_FRAMES_VERIFIED); 1981 // This also serves as purpose of showing preview for NUM_FRAMES_VERIFIED 1982 verifyCaptureResultForKey(CaptureResult.CONTROL_MODE, 1983 CaptureRequest.CONTROL_MODE_AUTO, listener, NUM_FRAMES_VERIFIED); 1984 } 1985 } 1986 1987 //---------------------------------------------------------------- 1988 //---------Below are common functions for all tests.-------------- 1989 //---------------------------------------------------------------- 1990 1991 /** 1992 * Enable exposure manual control and change exposure and sensitivity and 1993 * clamp the value into the supported range. 1994 */ 1995 private void changeExposure(CaptureRequest.Builder requestBuilder, 1996 long expTime, int sensitivity) { 1997 // Check if the max analog sensitivity is available and no larger than max sensitivity. 1998 // The max analog sensitivity is not actually used here. This is only an extra sanity check. 1999 mStaticInfo.getMaxAnalogSensitivityChecked(); 2000 2001 expTime = mStaticInfo.getExposureClampToRange(expTime); 2002 sensitivity = mStaticInfo.getSensitivityClampToRange(sensitivity); 2003 2004 requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CONTROL_AE_MODE_OFF); 2005 requestBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, expTime); 2006 requestBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, sensitivity); 2007 } 2008 /** 2009 * Enable exposure manual control and change exposure time and 2010 * clamp the value into the supported range. 2011 * 2012 * <p>The sensitivity is set to default value.</p> 2013 */ 2014 private void changeExposure(CaptureRequest.Builder requestBuilder, long expTime) { 2015 changeExposure(requestBuilder, expTime, DEFAULT_SENSITIVITY); 2016 } 2017 2018 /** 2019 * Get the exposure time array that contains multiple exposure time steps in 2020 * the exposure time range. 2021 */ 2022 private long[] getExposureTimeTestValues() { 2023 long[] testValues = new long[DEFAULT_NUM_EXPOSURE_TIME_STEPS + 1]; 2024 long maxExpTime = mStaticInfo.getExposureMaximumOrDefault(DEFAULT_EXP_TIME_NS); 2025 long minExpTime = mStaticInfo.getExposureMinimumOrDefault(DEFAULT_EXP_TIME_NS); 2026 2027 long range = maxExpTime - minExpTime; 2028 double stepSize = range / (double)DEFAULT_NUM_EXPOSURE_TIME_STEPS; 2029 for (int i = 0; i < testValues.length; i++) { 2030 testValues[i] = maxExpTime - (long)(stepSize * i); 2031 testValues[i] = mStaticInfo.getExposureClampToRange(testValues[i]); 2032 } 2033 2034 return testValues; 2035 } 2036 2037 /** 2038 * Generate test focus distances in range of [0, minFocusDistance] in increasing order. 2039 */ 2040 private float[] getFocusDistanceTestValuesInOrder() { 2041 float[] testValues = new float[NUM_TEST_FOCUS_DISTANCES + 1]; 2042 float minValue = 0; 2043 float maxValue = mStaticInfo.getMinimumFocusDistanceChecked(); 2044 2045 float range = maxValue - minValue; 2046 float stepSize = range / NUM_TEST_FOCUS_DISTANCES; 2047 for (int i = 0; i < testValues.length; i++) { 2048 testValues[i] = minValue + stepSize * i; 2049 } 2050 2051 return testValues; 2052 } 2053 2054 /** 2055 * Get the sensitivity array that contains multiple sensitivity steps in the 2056 * sensitivity range. 2057 * <p> 2058 * Sensitivity number of test values is determined by 2059 * {@value #DEFAULT_SENSITIVITY_STEP_SIZE} and sensitivity range, and 2060 * bounded by {@value #DEFAULT_NUM_SENSITIVITY_STEPS}. 2061 * </p> 2062 */ 2063 private int[] getSensitivityTestValues() { 2064 int maxSensitivity = mStaticInfo.getSensitivityMaximumOrDefault( 2065 DEFAULT_SENSITIVITY); 2066 int minSensitivity = mStaticInfo.getSensitivityMinimumOrDefault( 2067 DEFAULT_SENSITIVITY); 2068 2069 int range = maxSensitivity - minSensitivity; 2070 int stepSize = DEFAULT_SENSITIVITY_STEP_SIZE; 2071 int numSteps = range / stepSize; 2072 // Bound the test steps to avoid supper long test. 2073 if (numSteps > DEFAULT_NUM_SENSITIVITY_STEPS) { 2074 numSteps = DEFAULT_NUM_SENSITIVITY_STEPS; 2075 stepSize = range / numSteps; 2076 } 2077 int[] testValues = new int[numSteps + 1]; 2078 for (int i = 0; i < testValues.length; i++) { 2079 testValues[i] = maxSensitivity - stepSize * i; 2080 testValues[i] = mStaticInfo.getSensitivityClampToRange(testValues[i]); 2081 } 2082 2083 return testValues; 2084 } 2085 2086 /** 2087 * Validate the AE manual control exposure time. 2088 * 2089 * <p>Exposure should be close enough, and only round down if they are not equal.</p> 2090 * 2091 * @param request Request exposure time 2092 * @param result Result exposure time 2093 */ 2094 private void validateExposureTime(long request, long result) { 2095 long expTimeDelta = request - result; 2096 // First, round down not up, second, need close enough. 2097 mCollector.expectTrue("Exposture time is invalid for AE manaul control test, request: " 2098 + request + " result: " + result, 2099 expTimeDelta < EXPOSURE_TIME_ERROR_MARGIN_NS && expTimeDelta >= 0); 2100 } 2101 2102 /** 2103 * Validate AE manual control sensitivity. 2104 * 2105 * @param request Request sensitivity 2106 * @param result Result sensitivity 2107 */ 2108 private void validateSensitivity(int request, int result) { 2109 int sensitivityDelta = request - result; 2110 // First, round down not up, second, need close enough. 2111 mCollector.expectTrue("Sensitivity is invalid for AE manaul control test, request: " 2112 + request + " result: " + result, 2113 sensitivityDelta < SENSITIVITY_ERROR_MARGIN && sensitivityDelta >= 0); 2114 } 2115 2116 /** 2117 * Validate frame duration for a given capture. 2118 * 2119 * <p>Frame duration should be longer than exposure time.</p> 2120 * 2121 * @param result The capture result for a given capture 2122 */ 2123 private void validateFrameDurationForCapture(CaptureResult result) { 2124 long expTime = getValueNotNull(result, CaptureResult.SENSOR_EXPOSURE_TIME); 2125 long frameDuration = getValueNotNull(result, CaptureResult.SENSOR_FRAME_DURATION); 2126 if (VERBOSE) { 2127 Log.v(TAG, "frame duration: " + frameDuration + " Exposure time: " + expTime); 2128 } 2129 2130 mCollector.expectTrue(String.format("Frame duration (%d) should be longer than exposure" 2131 + " time (%d) for a given capture", frameDuration, expTime), 2132 frameDuration >= expTime); 2133 2134 validatePipelineDepth(result); 2135 } 2136 2137 /** 2138 * Basic verification for the control mode capture result. 2139 * 2140 * @param key The capture result key to be verified against 2141 * @param requestMode The request mode for this result 2142 * @param listener The capture listener to get capture results 2143 * @param numFramesVerified The number of capture results to be verified 2144 */ 2145 private <T> void verifyCaptureResultForKey(CaptureResult.Key<T> key, T requestMode, 2146 SimpleCaptureCallback listener, int numFramesVerified) { 2147 for (int i = 0; i < numFramesVerified; i++) { 2148 CaptureResult result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 2149 validatePipelineDepth(result); 2150 T resultMode = getValueNotNull(result, key); 2151 if (VERBOSE) { 2152 Log.v(TAG, "Expect value: " + requestMode.toString() + " result value: " 2153 + resultMode.toString()); 2154 } 2155 mCollector.expectEquals("Key " + key.getName() + " result should match request", 2156 requestMode, resultMode); 2157 } 2158 } 2159 2160 /** 2161 * Verify if the fps is slow down for given input request with certain 2162 * controls inside. 2163 * <p> 2164 * This method selects a max preview size for each fps range, and then 2165 * configure the preview stream. Preview is started with the max preview 2166 * size, and then verify if the result frame duration is in the frame 2167 * duration range. 2168 * </p> 2169 * 2170 * @param requestBuilder The request builder that contains post-processing 2171 * controls that could impact the output frame rate, such as 2172 * {@link CaptureRequest.NOISE_REDUCTION_MODE}. The value of 2173 * these controls must be set to some values such that the frame 2174 * rate is not slow down. 2175 * @param numFramesVerified The number of frames to be verified 2176 */ 2177 private void verifyFpsNotSlowDown(CaptureRequest.Builder requestBuilder, 2178 int numFramesVerified) throws Exception { 2179 boolean frameDurationAvailable = true; 2180 // Allow a few frames for AE to settle on target FPS range 2181 final int NUM_FRAME_TO_SKIP = 6; 2182 float frameDurationErrorMargin = FRAME_DURATION_ERROR_MARGIN; 2183 if (!mStaticInfo.areKeysAvailable(CaptureResult.SENSOR_FRAME_DURATION)) { 2184 frameDurationAvailable = false; 2185 // Allow a larger error margin (1.5%) for timestamps 2186 frameDurationErrorMargin = 0.015f; 2187 } 2188 2189 Range<Integer>[] fpsRanges = mStaticInfo.getAeAvailableTargetFpsRangesChecked(); 2190 boolean antiBandingOffIsSupported = mStaticInfo.isAntiBandingOffModeSupported(); 2191 Range<Integer> fpsRange; 2192 SimpleCaptureCallback resultListener; 2193 2194 for (int i = 0; i < fpsRanges.length; i += 1) { 2195 fpsRange = fpsRanges[i]; 2196 Size previewSz = getMaxPreviewSizeForFpsRange(fpsRange); 2197 // If unable to find a preview size, then log the failure, and skip this run. 2198 if (previewSz == null) { 2199 if (mStaticInfo.isCapabilitySupported( 2200 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 2201 mCollector.addMessage(String.format( 2202 "Unable to find a preview size supporting given fps range %s", 2203 fpsRange)); 2204 } 2205 continue; 2206 } 2207 2208 if (VERBOSE) { 2209 Log.v(TAG, String.format("Test fps range %s for preview size %s", 2210 fpsRange, previewSz.toString())); 2211 } 2212 requestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fpsRange); 2213 // Turn off auto antibanding to avoid exposure time and frame duration interference 2214 // from antibanding algorithm. 2215 if (antiBandingOffIsSupported) { 2216 requestBuilder.set(CaptureRequest.CONTROL_AE_ANTIBANDING_MODE, 2217 CaptureRequest.CONTROL_AE_ANTIBANDING_MODE_OFF); 2218 } else { 2219 // The device doesn't implement the OFF mode, test continues. It need make sure 2220 // that the antibanding algorithm doesn't slow down the fps. 2221 Log.i(TAG, "OFF antibanding mode is not supported, the camera device output must" + 2222 " not slow down the frame rate regardless of its current antibanding" + 2223 " mode"); 2224 } 2225 2226 resultListener = new SimpleCaptureCallback(); 2227 startPreview(requestBuilder, previewSz, resultListener); 2228 waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 2229 // Wait several more frames for AE to settle on target FPS range 2230 waitForNumResults(resultListener, NUM_FRAME_TO_SKIP); 2231 2232 long[] frameDurationRange = new long[]{ 2233 (long) (1e9 / fpsRange.getUpper()), (long) (1e9 / fpsRange.getLower())}; 2234 long captureTime = 0, prevCaptureTime = 0; 2235 for (int j = 0; j < numFramesVerified; j++) { 2236 long frameDuration = frameDurationRange[0]; 2237 CaptureResult result = 2238 resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 2239 validatePipelineDepth(result); 2240 if (frameDurationAvailable) { 2241 frameDuration = getValueNotNull(result, CaptureResult.SENSOR_FRAME_DURATION); 2242 } else { 2243 // if frame duration is not available, check timestamp instead 2244 captureTime = getValueNotNull(result, CaptureResult.SENSOR_TIMESTAMP); 2245 if (j > 0) { 2246 frameDuration = captureTime - prevCaptureTime; 2247 } 2248 prevCaptureTime = captureTime; 2249 } 2250 mCollector.expectInRange( 2251 "Frame duration must be in the range of " + 2252 Arrays.toString(frameDurationRange), 2253 frameDuration, 2254 (long) (frameDurationRange[0] * (1 - frameDurationErrorMargin)), 2255 (long) (frameDurationRange[1] * (1 + frameDurationErrorMargin))); 2256 } 2257 } 2258 2259 mSession.stopRepeating(); 2260 } 2261 2262 /** 2263 * Validate the pipeline depth result. 2264 * 2265 * @param result The capture result to get pipeline depth data 2266 */ 2267 private void validatePipelineDepth(CaptureResult result) { 2268 final byte MIN_PIPELINE_DEPTH = 1; 2269 byte maxPipelineDepth = mStaticInfo.getPipelineMaxDepthChecked(); 2270 Byte pipelineDepth = getValueNotNull(result, CaptureResult.REQUEST_PIPELINE_DEPTH); 2271 mCollector.expectInRange(String.format("Pipeline depth must be in the range of [%d, %d]", 2272 MIN_PIPELINE_DEPTH, maxPipelineDepth), pipelineDepth, MIN_PIPELINE_DEPTH, 2273 maxPipelineDepth); 2274 } 2275 2276 /** 2277 * Calculate the anti-flickering corrected exposure time. 2278 * <p> 2279 * If the input exposure time is very short (shorter than flickering 2280 * boundary), which indicate the scene is bright and very likely at outdoor 2281 * environment, skip the correction, as it doesn't make much sense by doing so. 2282 * </p> 2283 * <p> 2284 * For long exposure time (larger than the flickering boundary), find the 2285 * exposure time that is closest to the flickering boundary. 2286 * </p> 2287 * 2288 * @param flickeringMode The flickering mode 2289 * @param exposureTime The input exposureTime to be corrected 2290 * @return anti-flickering corrected exposure time 2291 */ 2292 private long getAntiFlickeringExposureTime(int flickeringMode, long exposureTime) { 2293 if (flickeringMode != ANTI_FLICKERING_50HZ && flickeringMode != ANTI_FLICKERING_60HZ) { 2294 throw new IllegalArgumentException("Input anti-flickering mode must be 50 or 60Hz"); 2295 } 2296 long flickeringBoundary = EXPOSURE_TIME_BOUNDARY_50HZ_NS; 2297 if (flickeringMode == ANTI_FLICKERING_60HZ) { 2298 flickeringBoundary = EXPOSURE_TIME_BOUNDARY_60HZ_NS; 2299 } 2300 2301 if (exposureTime <= flickeringBoundary) { 2302 return exposureTime; 2303 } 2304 2305 // Find the closest anti-flickering corrected exposure time 2306 long correctedExpTime = exposureTime + (flickeringBoundary / 2); 2307 correctedExpTime = correctedExpTime - (correctedExpTime % flickeringBoundary); 2308 return correctedExpTime; 2309 } 2310 2311 /** 2312 * Update one 3A region in capture request builder if that region is supported. Do nothing 2313 * if the specified 3A region is not supported by camera device. 2314 * @param requestBuilder The request to be updated 2315 * @param algoIdx The index to the algorithm. (AE: 0, AWB: 1, AF: 2) 2316 * @param regions The 3A regions to be set 2317 */ 2318 private void update3aRegion( 2319 CaptureRequest.Builder requestBuilder, int algoIdx, MeteringRectangle[] regions) 2320 { 2321 int maxRegions; 2322 CaptureRequest.Key<MeteringRectangle[]> key; 2323 2324 if (regions == null || regions.length == 0) { 2325 throw new IllegalArgumentException("Invalid input 3A region!"); 2326 } 2327 2328 switch (algoIdx) { 2329 case INDEX_ALGORITHM_AE: 2330 maxRegions = mStaticInfo.getAeMaxRegionsChecked(); 2331 key = CaptureRequest.CONTROL_AE_REGIONS; 2332 break; 2333 case INDEX_ALGORITHM_AWB: 2334 maxRegions = mStaticInfo.getAwbMaxRegionsChecked(); 2335 key = CaptureRequest.CONTROL_AWB_REGIONS; 2336 break; 2337 case INDEX_ALGORITHM_AF: 2338 maxRegions = mStaticInfo.getAfMaxRegionsChecked(); 2339 key = CaptureRequest.CONTROL_AF_REGIONS; 2340 break; 2341 default: 2342 throw new IllegalArgumentException("Unknown 3A Algorithm!"); 2343 } 2344 2345 if (maxRegions >= regions.length) { 2346 requestBuilder.set(key, regions); 2347 } 2348 } 2349 2350 /** 2351 * Validate one 3A region in capture result equals to expected region if that region is 2352 * supported. Do nothing if the specified 3A region is not supported by camera device. 2353 * @param result The capture result to be validated 2354 * @param algoIdx The index to the algorithm. (AE: 0, AWB: 1, AF: 2) 2355 * @param expectRegions The 3A regions expected in capture result 2356 */ 2357 private void validate3aRegion( 2358 CaptureResult result, int algoIdx, MeteringRectangle[] expectRegions) 2359 { 2360 int maxRegions; 2361 CaptureResult.Key<MeteringRectangle[]> key; 2362 MeteringRectangle[] actualRegion; 2363 2364 switch (algoIdx) { 2365 case INDEX_ALGORITHM_AE: 2366 maxRegions = mStaticInfo.getAeMaxRegionsChecked(); 2367 key = CaptureResult.CONTROL_AE_REGIONS; 2368 break; 2369 case INDEX_ALGORITHM_AWB: 2370 maxRegions = mStaticInfo.getAwbMaxRegionsChecked(); 2371 key = CaptureResult.CONTROL_AWB_REGIONS; 2372 break; 2373 case INDEX_ALGORITHM_AF: 2374 maxRegions = mStaticInfo.getAfMaxRegionsChecked(); 2375 key = CaptureResult.CONTROL_AF_REGIONS; 2376 break; 2377 default: 2378 throw new IllegalArgumentException("Unknown 3A Algorithm!"); 2379 } 2380 2381 if (maxRegions > 0) 2382 { 2383 actualRegion = getValueNotNull(result, key); 2384 mCollector.expectEquals( 2385 "Expected 3A regions: " + Arrays.toString(expectRegions) + 2386 " does not match actual one: " + Arrays.toString(actualRegion), 2387 expectRegions, actualRegion); 2388 } 2389 } 2390 } 2391