1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.hardware.camera2.cts; 18 19 import static android.hardware.camera2.cts.CameraTestUtils.*; 20 import static android.hardware.camera2.cts.helpers.AssertHelpers.assertArrayContains; 21 22 import android.graphics.ImageFormat; 23 import android.graphics.Point; 24 import android.graphics.Rect; 25 import android.hardware.camera2.CameraCharacteristics; 26 import android.hardware.camera2.CameraDevice; 27 import android.hardware.camera2.CaptureRequest; 28 import android.hardware.camera2.CaptureResult; 29 import android.hardware.camera2.DngCreator; 30 import android.media.ImageReader; 31 import android.util.Pair; 32 import android.util.Size; 33 import android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback; 34 import android.hardware.camera2.cts.CameraTestUtils.SimpleImageReaderListener; 35 import android.hardware.camera2.cts.helpers.Camera2Focuser; 36 import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase; 37 import android.hardware.camera2.params.MeteringRectangle; 38 import android.media.Image; 39 import android.os.ConditionVariable; 40 import android.util.Log; 41 import android.util.Range; 42 import android.util.Rational; 43 import android.view.Surface; 44 45 import com.android.ex.camera2.blocking.BlockingSessionCallback; 46 import com.android.ex.camera2.exceptions.TimeoutRuntimeException; 47 48 import java.io.ByteArrayOutputStream; 49 import java.util.ArrayList; 50 import java.util.Arrays; 51 import java.util.List; 52 53 public class StillCaptureTest extends Camera2SurfaceViewTestCase { 54 private static final String TAG = "StillCaptureTest"; 55 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 56 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 57 // 60 second to accommodate the possible long exposure time. 58 private static final int RELAXED_CAPTURE_IMAGE_TIMEOUT_MS = CAPTURE_IMAGE_TIMEOUT_MS + 1000; 59 private static final int MAX_REGIONS_AE_INDEX = 0; 60 private static final int MAX_REGIONS_AWB_INDEX = 1; 61 private static final int MAX_REGIONS_AF_INDEX = 2; 62 private static final int WAIT_FOR_FOCUS_DONE_TIMEOUT_MS = 6000; 63 private static final double AE_COMPENSATION_ERROR_TOLERANCE = 0.2; 64 private static final int NUM_FRAMES_WAITED = 30; 65 // 5 percent error margin for resulting metering regions 66 private static final float METERING_REGION_ERROR_PERCENT_DELTA = 0.05f; 67 68 @Override setUp()69 protected void setUp() throws Exception { 70 super.setUp(); 71 } 72 73 @Override tearDown()74 protected void tearDown() throws Exception { 75 super.tearDown(); 76 } 77 78 /** 79 * Test JPEG capture exif fields for each camera. 80 */ testJpegExif()81 public void testJpegExif() throws Exception { 82 for (int i = 0; i < mCameraIds.length; i++) { 83 try { 84 Log.i(TAG, "Testing JPEG exif for Camera " + mCameraIds[i]); 85 openDevice(mCameraIds[i]); 86 if (!mStaticInfo.isColorOutputSupported()) { 87 Log.i(TAG, "Camera " + mCameraIds[i] + 88 " does not support color outputs, skipping"); 89 continue; 90 } 91 jpegExifTestByCamera(); 92 } finally { 93 closeDevice(); 94 closeImageReader(); 95 } 96 } 97 } 98 99 /** 100 * Test normal still capture sequence. 101 * <p> 102 * Preview and and jpeg output streams are configured. Max still capture 103 * size is used for jpeg capture. The sequence of still capture being test 104 * is: start preview, auto focus, precapture metering (if AE is not 105 * converged), then capture jpeg. The AWB and AE are in auto modes. AF mode 106 * is CONTINUOUS_PICTURE. 107 * </p> 108 */ testTakePicture()109 public void testTakePicture() throws Exception{ 110 for (String id : mCameraIds) { 111 try { 112 Log.i(TAG, "Testing basic take picture for Camera " + id); 113 openDevice(id); 114 if (!mStaticInfo.isColorOutputSupported()) { 115 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 116 continue; 117 } 118 takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null, /*afRegions*/null); 119 } finally { 120 closeDevice(); 121 closeImageReader(); 122 } 123 } 124 } 125 126 /** 127 * Test basic Raw capture. Raw buffer avaiablility is checked, but raw buffer data is not. 128 */ testBasicRawCapture()129 public void testBasicRawCapture() throws Exception { 130 for (int i = 0; i < mCameraIds.length; i++) { 131 try { 132 Log.i(TAG, "Testing raw capture for Camera " + mCameraIds[i]); 133 openDevice(mCameraIds[i]); 134 135 if (!mStaticInfo.isCapabilitySupported( 136 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 137 Log.i(TAG, "RAW capability is not supported in camera " + mCameraIds[i] + 138 ". Skip the test."); 139 continue; 140 } 141 142 rawCaptureTestByCamera(); 143 } finally { 144 closeDevice(); 145 closeImageReader(); 146 } 147 } 148 } 149 150 151 /** 152 * Test the full raw capture use case. 153 * 154 * This includes: 155 * - Configuring the camera with a preview, jpeg, and raw output stream. 156 * - Running preview until AE/AF can settle. 157 * - Capturing with a request targeting all three output streams. 158 */ testFullRawCapture()159 public void testFullRawCapture() throws Exception { 160 for (int i = 0; i < mCameraIds.length; i++) { 161 try { 162 Log.i(TAG, "Testing raw capture for Camera " + mCameraIds[i]); 163 openDevice(mCameraIds[i]); 164 if (!mStaticInfo.isCapabilitySupported( 165 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 166 Log.i(TAG, "RAW capability is not supported in camera " + mCameraIds[i] + 167 ". Skip the test."); 168 continue; 169 } 170 171 fullRawCaptureTestByCamera(); 172 } finally { 173 closeDevice(); 174 closeImageReader(); 175 } 176 } 177 } 178 /** 179 * Test touch for focus. 180 * <p> 181 * AF is in CAF mode when preview is started, test uses several pre-selected 182 * regions to simulate touches. Active scan is triggered to make sure the AF 183 * converges in reasonable time. 184 * </p> 185 */ testTouchForFocus()186 public void testTouchForFocus() throws Exception { 187 for (String id : mCameraIds) { 188 try { 189 Log.i(TAG, "Testing touch for focus for Camera " + id); 190 openDevice(id); 191 int maxAfRegions = mStaticInfo.getAfMaxRegionsChecked(); 192 if (!(mStaticInfo.hasFocuser() && maxAfRegions > 0)) { 193 continue; 194 } 195 // TODO: Relax test to use non-SurfaceView output for depth cases 196 if (!mStaticInfo.isColorOutputSupported()) { 197 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 198 continue; 199 } 200 touchForFocusTestByCamera(); 201 } finally { 202 closeDevice(); 203 closeImageReader(); 204 } 205 } 206 } 207 208 /** 209 * Test all combination of available preview sizes and still sizes. 210 * <p> 211 * For each still capture, Only the jpeg buffer is validated, capture 212 * result validation is covered by {@link #jpegExifTestByCamera} test. 213 * </p> 214 */ testStillPreviewCombination()215 public void testStillPreviewCombination() throws Exception { 216 for (String id : mCameraIds) { 217 try { 218 Log.i(TAG, "Testing Still preview capture combination for Camera " + id); 219 openDevice(id); 220 if (!mStaticInfo.isColorOutputSupported()) { 221 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 222 continue; 223 } 224 previewStillCombinationTestByCamera(); 225 } finally { 226 closeDevice(); 227 closeImageReader(); 228 } 229 } 230 } 231 232 /** 233 * Test AE compensation. 234 * <p> 235 * For each integer EV compensation setting: retrieve the exposure value (exposure time * 236 * sensitivity) with or without compensation, verify if the exposure value is legal (conformed 237 * to what static info has) and the ratio between two exposure values matches EV compensation 238 * setting. Also test for the behavior that exposure settings should be changed when AE 239 * compensation settings is changed, even when AE lock is ON. 240 * </p> 241 */ testAeCompensation()242 public void testAeCompensation() throws Exception { 243 for (String id : mCameraIds) { 244 try { 245 Log.i(TAG, "Testing AE compensation for Camera " + id); 246 openDevice(id); 247 248 if (mStaticInfo.isHardwareLevelLegacy()) { 249 Log.i(TAG, "Skipping test on legacy devices"); 250 continue; 251 } 252 if (!mStaticInfo.isColorOutputSupported()) { 253 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 254 continue; 255 } 256 aeCompensationTestByCamera(); 257 } finally { 258 closeDevice(); 259 closeImageReader(); 260 } 261 } 262 } 263 264 /** 265 * Test Ae region for still capture. 266 */ testAeRegions()267 public void testAeRegions() throws Exception { 268 for (String id : mCameraIds) { 269 try { 270 Log.i(TAG, "Testing AE regions for Camera " + id); 271 openDevice(id); 272 273 boolean aeRegionsSupported = isRegionsSupportedFor3A(MAX_REGIONS_AE_INDEX); 274 if (!aeRegionsSupported) { 275 continue; 276 } 277 278 ArrayList<MeteringRectangle[]> aeRegionTestCases = get3ARegionTestCasesForCamera(); 279 for (MeteringRectangle[] aeRegions : aeRegionTestCases) { 280 takePictureTestByCamera(aeRegions, /*awbRegions*/null, /*afRegions*/null); 281 } 282 } finally { 283 closeDevice(); 284 closeImageReader(); 285 } 286 } 287 } 288 289 /** 290 * Test AWB region for still capture. 291 */ testAwbRegions()292 public void testAwbRegions() throws Exception { 293 for (String id : mCameraIds) { 294 try { 295 Log.i(TAG, "Testing AE regions for Camera " + id); 296 openDevice(id); 297 298 boolean awbRegionsSupported = isRegionsSupportedFor3A(MAX_REGIONS_AWB_INDEX); 299 if (!awbRegionsSupported) { 300 continue; 301 } 302 303 ArrayList<MeteringRectangle[]> awbRegionTestCases = get3ARegionTestCasesForCamera(); 304 for (MeteringRectangle[] awbRegions : awbRegionTestCases) { 305 takePictureTestByCamera(/*aeRegions*/null, awbRegions, /*afRegions*/null); 306 } 307 } finally { 308 closeDevice(); 309 closeImageReader(); 310 } 311 } 312 } 313 314 /** 315 * Test Af region for still capture. 316 */ testAfRegions()317 public void testAfRegions() throws Exception { 318 for (String id : mCameraIds) { 319 try { 320 Log.i(TAG, "Testing AF regions for Camera " + id); 321 openDevice(id); 322 323 boolean afRegionsSupported = isRegionsSupportedFor3A(MAX_REGIONS_AF_INDEX); 324 if (!afRegionsSupported) { 325 continue; 326 } 327 328 ArrayList<MeteringRectangle[]> afRegionTestCases = get3ARegionTestCasesForCamera(); 329 for (MeteringRectangle[] afRegions : afRegionTestCases) { 330 takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null, afRegions); 331 } 332 } finally { 333 closeDevice(); 334 closeImageReader(); 335 } 336 } 337 } 338 339 /** 340 * Test preview is still running after a still request 341 */ testPreviewPersistence()342 public void testPreviewPersistence() throws Exception { 343 for (String id : mCameraIds) { 344 try { 345 Log.i(TAG, "Testing preview persistence for Camera " + id); 346 openDevice(id); 347 if (!mStaticInfo.isColorOutputSupported()) { 348 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 349 continue; 350 } 351 previewPersistenceTestByCamera(); 352 } finally { 353 closeDevice(); 354 closeImageReader(); 355 } 356 } 357 } 358 testAePrecaptureTriggerCancelJpegCapture()359 public void testAePrecaptureTriggerCancelJpegCapture() throws Exception { 360 for (String id : mCameraIds) { 361 try { 362 Log.i(TAG, "Testing AE precapture cancel for jpeg capture for Camera " + id); 363 openDevice(id); 364 365 // Legacy device doesn't support AE precapture trigger 366 if (mStaticInfo.isHardwareLevelLegacy()) { 367 Log.i(TAG, "Skipping AE precapture trigger cancel test on legacy devices"); 368 continue; 369 } 370 if (!mStaticInfo.isColorOutputSupported()) { 371 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 372 continue; 373 } 374 takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null, /*afRegions*/null, 375 /*addAeTriggerCancel*/true); 376 } finally { 377 closeDevice(); 378 closeImageReader(); 379 } 380 } 381 } 382 383 /** 384 * Start preview,take a picture and test preview is still running after snapshot 385 */ previewPersistenceTestByCamera()386 private void previewPersistenceTestByCamera() throws Exception { 387 Size maxStillSz = mOrderedStillSizes.get(0); 388 Size maxPreviewSz = mOrderedPreviewSizes.get(0); 389 390 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 391 SimpleCaptureCallback stillResultListener = new SimpleCaptureCallback(); 392 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 393 CaptureRequest.Builder previewRequest = 394 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 395 CaptureRequest.Builder stillRequest = 396 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 397 prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz, 398 maxStillSz, resultListener, imageListener); 399 400 // make sure preview is actually running 401 waitForNumResults(resultListener, NUM_FRAMES_WAITED); 402 403 // take a picture 404 CaptureRequest request = stillRequest.build(); 405 mSession.capture(request, stillResultListener, mHandler); 406 stillResultListener.getCaptureResultForRequest(request, 407 WAIT_FOR_RESULT_TIMEOUT_MS); 408 409 // validate image 410 Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 411 validateJpegCapture(image, maxStillSz); 412 413 // make sure preview is still running after still capture 414 waitForNumResults(resultListener, NUM_FRAMES_WAITED); 415 416 stopPreview(); 417 418 // Free image resources 419 image.close(); 420 closeImageReader(); 421 return; 422 } 423 424 /** 425 * Take a picture for a given set of 3A regions for a particular camera. 426 * <p> 427 * Before take a still capture, it triggers an auto focus and lock it first, 428 * then wait for AWB to converge and lock it, then trigger a precapture 429 * metering sequence and wait for AE converged. After capture is received, the 430 * capture result and image are validated. 431 * </p> 432 * 433 * @param aeRegions AE regions for this capture 434 * @param awbRegions AWB regions for this capture 435 * @param afRegions AF regions for this capture 436 */ takePictureTestByCamera( MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions, MeteringRectangle[] afRegions)437 private void takePictureTestByCamera( 438 MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions, 439 MeteringRectangle[] afRegions) throws Exception { 440 takePictureTestByCamera(aeRegions, awbRegions, afRegions, 441 /*addAeTriggerCancel*/false); 442 } 443 444 /** 445 * Take a picture for a given set of 3A regions for a particular camera. 446 * <p> 447 * Before take a still capture, it triggers an auto focus and lock it first, 448 * then wait for AWB to converge and lock it, then trigger a precapture 449 * metering sequence and wait for AE converged. After capture is received, the 450 * capture result and image are validated. If {@code addAeTriggerCancel} is true, 451 * a precapture trigger cancel will be inserted between two adjacent triggers, which 452 * should effective cancel the first trigger. 453 * </p> 454 * 455 * @param aeRegions AE regions for this capture 456 * @param awbRegions AWB regions for this capture 457 * @param afRegions AF regions for this capture 458 * @param addAeTriggerCancel If a AE precapture trigger cancel is sent after the trigger. 459 */ takePictureTestByCamera( MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions, MeteringRectangle[] afRegions, boolean addAeTriggerCancel)460 private void takePictureTestByCamera( 461 MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions, 462 MeteringRectangle[] afRegions, boolean addAeTriggerCancel) throws Exception { 463 464 boolean hasFocuser = mStaticInfo.hasFocuser(); 465 466 Size maxStillSz = mOrderedStillSizes.get(0); 467 Size maxPreviewSz = mOrderedPreviewSizes.get(0); 468 CaptureResult result; 469 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 470 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 471 CaptureRequest.Builder previewRequest = 472 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 473 CaptureRequest.Builder stillRequest = 474 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 475 prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz, 476 maxStillSz, resultListener, imageListener); 477 478 // Set AE mode to ON_AUTO_FLASH if flash is available. 479 if (mStaticInfo.hasFlash()) { 480 previewRequest.set(CaptureRequest.CONTROL_AE_MODE, 481 CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); 482 stillRequest.set(CaptureRequest.CONTROL_AE_MODE, 483 CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); 484 } 485 486 Camera2Focuser focuser = null; 487 /** 488 * Step 1: trigger an auto focus run, and wait for AF locked. 489 */ 490 boolean canSetAfRegion = hasFocuser && (afRegions != null) && 491 isRegionsSupportedFor3A(MAX_REGIONS_AF_INDEX); 492 if (hasFocuser) { 493 SimpleAutoFocusListener afListener = new SimpleAutoFocusListener(); 494 focuser = new Camera2Focuser(mCamera, mSession, mPreviewSurface, afListener, 495 mStaticInfo.getCharacteristics(), mHandler); 496 if (canSetAfRegion) { 497 stillRequest.set(CaptureRequest.CONTROL_AF_REGIONS, afRegions); 498 } 499 focuser.startAutoFocus(afRegions); 500 afListener.waitForAutoFocusDone(WAIT_FOR_FOCUS_DONE_TIMEOUT_MS); 501 } 502 503 /** 504 * Have to get the current AF mode to be used for other 3A repeating 505 * request, otherwise, the new AF mode in AE/AWB request could be 506 * different with existing repeating requests being sent by focuser, 507 * then it could make AF unlocked too early. Beside that, for still 508 * capture, AF mode must not be different with the one in current 509 * repeating request, otherwise, the still capture itself would trigger 510 * an AF mode change, and the AF lock would be lost for this capture. 511 */ 512 int currentAfMode = CaptureRequest.CONTROL_AF_MODE_OFF; 513 if (hasFocuser) { 514 currentAfMode = focuser.getCurrentAfMode(); 515 } 516 previewRequest.set(CaptureRequest.CONTROL_AF_MODE, currentAfMode); 517 stillRequest.set(CaptureRequest.CONTROL_AF_MODE, currentAfMode); 518 519 /** 520 * Step 2: AF is already locked, wait for AWB converged, then lock it. 521 */ 522 resultListener = new SimpleCaptureCallback(); 523 boolean canSetAwbRegion = 524 (awbRegions != null) && isRegionsSupportedFor3A(MAX_REGIONS_AWB_INDEX); 525 if (canSetAwbRegion) { 526 previewRequest.set(CaptureRequest.CONTROL_AWB_REGIONS, awbRegions); 527 stillRequest.set(CaptureRequest.CONTROL_AWB_REGIONS, awbRegions); 528 } 529 mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler); 530 if (mStaticInfo.isHardwareLevelLimitedOrBetter()) { 531 waitForResultValue(resultListener, CaptureResult.CONTROL_AWB_STATE, 532 CaptureResult.CONTROL_AWB_STATE_CONVERGED, NUM_RESULTS_WAIT_TIMEOUT); 533 } else { 534 // LEGACY Devices don't have the AWB_STATE reported in results, so just wait 535 waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 536 } 537 boolean canSetAwbLock = mStaticInfo.isAwbLockSupported(); 538 if (canSetAwbLock) { 539 previewRequest.set(CaptureRequest.CONTROL_AWB_LOCK, true); 540 } 541 mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler); 542 // Validate the next result immediately for region and mode. 543 result = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 544 mCollector.expectEquals("AWB mode in result and request should be same", 545 previewRequest.get(CaptureRequest.CONTROL_AWB_MODE), 546 result.get(CaptureResult.CONTROL_AWB_MODE)); 547 if (canSetAwbRegion) { 548 MeteringRectangle[] resultAwbRegions = 549 getValueNotNull(result, CaptureResult.CONTROL_AWB_REGIONS); 550 mCollector.expectEquals("AWB regions in result and request should be same", 551 awbRegions, resultAwbRegions); 552 } 553 554 /** 555 * Step 3: trigger an AE precapture metering sequence and wait for AE converged. 556 */ 557 resultListener = new SimpleCaptureCallback(); 558 boolean canSetAeRegion = 559 (aeRegions != null) && isRegionsSupportedFor3A(MAX_REGIONS_AE_INDEX); 560 if (canSetAeRegion) { 561 previewRequest.set(CaptureRequest.CONTROL_AE_REGIONS, aeRegions); 562 stillRequest.set(CaptureRequest.CONTROL_AE_REGIONS, aeRegions); 563 } 564 mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler); 565 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 566 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); 567 mSession.capture(previewRequest.build(), resultListener, mHandler); 568 if (addAeTriggerCancel) { 569 // Cancel the current precapture trigger, then send another trigger. 570 // The camera device should behave as if the first trigger is not sent. 571 // Wait one request to make the trigger start doing something before cancel. 572 waitForNumResults(resultListener, /*numResultsWait*/ 1); 573 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 574 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL); 575 mSession.capture(previewRequest.build(), resultListener, mHandler); 576 waitForResultValue(resultListener, CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER, 577 CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL, 578 NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 579 // Issue another trigger 580 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 581 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); 582 mSession.capture(previewRequest.build(), resultListener, mHandler); 583 } 584 waitForAeStable(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 585 586 // Validate the next result immediately for region and mode. 587 result = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 588 mCollector.expectEquals("AE mode in result and request should be same", 589 previewRequest.get(CaptureRequest.CONTROL_AE_MODE), 590 result.get(CaptureResult.CONTROL_AE_MODE)); 591 if (canSetAeRegion) { 592 MeteringRectangle[] resultAeRegions = 593 getValueNotNull(result, CaptureResult.CONTROL_AE_REGIONS); 594 595 mCollector.expectMeteringRegionsAreSimilar( 596 "AE regions in result and request should be similar", 597 aeRegions, 598 resultAeRegions, 599 METERING_REGION_ERROR_PERCENT_DELTA); 600 } 601 602 /** 603 * Step 4: take a picture when all 3A are in good state. 604 */ 605 resultListener = new SimpleCaptureCallback(); 606 CaptureRequest request = stillRequest.build(); 607 mSession.capture(request, resultListener, mHandler); 608 // Validate the next result immediately for region and mode. 609 result = resultListener.getCaptureResultForRequest(request, WAIT_FOR_RESULT_TIMEOUT_MS); 610 mCollector.expectEquals("AF mode in result and request should be same", 611 stillRequest.get(CaptureRequest.CONTROL_AF_MODE), 612 result.get(CaptureResult.CONTROL_AF_MODE)); 613 if (canSetAfRegion) { 614 MeteringRectangle[] resultAfRegions = 615 getValueNotNull(result, CaptureResult.CONTROL_AF_REGIONS); 616 mCollector.expectMeteringRegionsAreSimilar( 617 "AF regions in result and request should be similar", 618 afRegions, 619 resultAfRegions, 620 METERING_REGION_ERROR_PERCENT_DELTA); 621 } 622 623 if (hasFocuser) { 624 // Unlock auto focus. 625 focuser.cancelAutoFocus(); 626 } 627 628 // validate image 629 Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 630 validateJpegCapture(image, maxStillSz); 631 632 // Free image resources 633 image.close(); 634 635 stopPreview(); 636 } 637 638 /** 639 * Test touch region for focus by camera. 640 */ touchForFocusTestByCamera()641 private void touchForFocusTestByCamera() throws Exception { 642 SimpleCaptureCallback listener = new SimpleCaptureCallback(); 643 CaptureRequest.Builder requestBuilder = 644 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 645 Size maxPreviewSz = mOrderedPreviewSizes.get(0); 646 startPreview(requestBuilder, maxPreviewSz, listener); 647 648 SimpleAutoFocusListener afListener = new SimpleAutoFocusListener(); 649 Camera2Focuser focuser = new Camera2Focuser(mCamera, mSession, mPreviewSurface, afListener, 650 mStaticInfo.getCharacteristics(), mHandler); 651 ArrayList<MeteringRectangle[]> testAfRegions = get3ARegionTestCasesForCamera(); 652 653 for (MeteringRectangle[] afRegions : testAfRegions) { 654 focuser.touchForAutoFocus(afRegions); 655 afListener.waitForAutoFocusDone(WAIT_FOR_FOCUS_DONE_TIMEOUT_MS); 656 focuser.cancelAutoFocus(); 657 } 658 } 659 previewStillCombinationTestByCamera()660 private void previewStillCombinationTestByCamera() throws Exception { 661 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 662 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 663 664 for (Size stillSz : mOrderedStillSizes) 665 for (Size previewSz : mOrderedPreviewSizes) { 666 if (VERBOSE) { 667 Log.v(TAG, "Testing JPEG capture size " + stillSz.toString() 668 + " with preview size " + previewSz.toString() + " for camera " 669 + mCamera.getId()); 670 } 671 CaptureRequest.Builder previewRequest = 672 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 673 CaptureRequest.Builder stillRequest = 674 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 675 prepareStillCaptureAndStartPreview(previewRequest, stillRequest, previewSz, 676 stillSz, resultListener, imageListener); 677 mSession.capture(stillRequest.build(), resultListener, mHandler); 678 Image image = imageListener.getImage((mStaticInfo.isHardwareLevelLegacy()) ? 679 RELAXED_CAPTURE_IMAGE_TIMEOUT_MS : CAPTURE_IMAGE_TIMEOUT_MS); 680 validateJpegCapture(image, stillSz); 681 682 // Free image resources 683 image.close(); 684 685 // stopPreview must be called here to make sure next time a preview stream 686 // is created with new size. 687 stopPreview(); 688 } 689 } 690 691 /** 692 * Basic raw capture test for each camera. 693 */ rawCaptureTestByCamera()694 private void rawCaptureTestByCamera() throws Exception { 695 Size maxPreviewSz = mOrderedPreviewSizes.get(0); 696 Size size = mStaticInfo.getRawDimensChecked(); 697 698 // Prepare raw capture and start preview. 699 CaptureRequest.Builder previewBuilder = 700 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 701 CaptureRequest.Builder rawBuilder = 702 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 703 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 704 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 705 prepareRawCaptureAndStartPreview(previewBuilder, rawBuilder, maxPreviewSz, size, 706 resultListener, imageListener); 707 708 if (VERBOSE) { 709 Log.v(TAG, "Testing Raw capture with size " + size.toString() 710 + ", preview size " + maxPreviewSz); 711 } 712 713 CaptureRequest rawRequest = rawBuilder.build(); 714 mSession.capture(rawRequest, resultListener, mHandler); 715 716 Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 717 validateRaw16Image(image, size); 718 if (DEBUG) { 719 byte[] rawBuffer = getDataFromImage(image); 720 String rawFileName = DEBUG_FILE_NAME_BASE + "/test" + "_" + size.toString() + "_cam" + 721 mCamera.getId() + ".raw16"; 722 Log.d(TAG, "Dump raw file into " + rawFileName); 723 dumpFile(rawFileName, rawBuffer); 724 } 725 726 // Free image resources 727 image.close(); 728 729 stopPreview(); 730 } 731 fullRawCaptureTestByCamera()732 private void fullRawCaptureTestByCamera() throws Exception { 733 Size maxPreviewSz = mOrderedPreviewSizes.get(0); 734 Size maxStillSz = mOrderedStillSizes.get(0); 735 736 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 737 SimpleImageReaderListener jpegListener = new SimpleImageReaderListener(); 738 SimpleImageReaderListener rawListener = new SimpleImageReaderListener(); 739 740 Size size = mStaticInfo.getRawDimensChecked(); 741 742 if (VERBOSE) { 743 Log.v(TAG, "Testing multi capture with size " + size.toString() 744 + ", preview size " + maxPreviewSz); 745 } 746 747 // Prepare raw capture and start preview. 748 CaptureRequest.Builder previewBuilder = 749 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 750 CaptureRequest.Builder multiBuilder = 751 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 752 753 ImageReader rawReader = null; 754 ImageReader jpegReader = null; 755 756 try { 757 // Create ImageReaders. 758 rawReader = makeImageReader(size, 759 ImageFormat.RAW_SENSOR, MAX_READER_IMAGES, rawListener, mHandler); 760 jpegReader = makeImageReader(maxStillSz, 761 ImageFormat.JPEG, MAX_READER_IMAGES, jpegListener, mHandler); 762 updatePreviewSurface(maxPreviewSz); 763 764 // Configure output streams with preview and jpeg streams. 765 List<Surface> outputSurfaces = new ArrayList<Surface>(); 766 outputSurfaces.add(rawReader.getSurface()); 767 outputSurfaces.add(jpegReader.getSurface()); 768 outputSurfaces.add(mPreviewSurface); 769 mSessionListener = new BlockingSessionCallback(); 770 mSession = configureCameraSession(mCamera, outputSurfaces, 771 mSessionListener, mHandler); 772 773 // Configure the requests. 774 previewBuilder.addTarget(mPreviewSurface); 775 multiBuilder.addTarget(mPreviewSurface); 776 multiBuilder.addTarget(rawReader.getSurface()); 777 multiBuilder.addTarget(jpegReader.getSurface()); 778 779 // Start preview. 780 mSession.setRepeatingRequest(previewBuilder.build(), null, mHandler); 781 782 // Poor man's 3A, wait 2 seconds for AE/AF (if any) to settle. 783 // TODO: Do proper 3A trigger and lock (see testTakePictureTest). 784 Thread.sleep(3000); 785 786 multiBuilder.set(CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE, 787 CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE_ON); 788 CaptureRequest multiRequest = multiBuilder.build(); 789 790 mSession.capture(multiRequest, resultListener, mHandler); 791 792 CaptureResult result = resultListener.getCaptureResultForRequest(multiRequest, 793 NUM_RESULTS_WAIT_TIMEOUT); 794 Image jpegImage = jpegListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 795 basicValidateJpegImage(jpegImage, maxStillSz); 796 Image rawImage = rawListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 797 validateRaw16Image(rawImage, size); 798 verifyRawCaptureResult(multiRequest, result); 799 800 801 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 802 try (DngCreator dngCreator = new DngCreator(mStaticInfo.getCharacteristics(), result)) { 803 dngCreator.writeImage(outputStream, rawImage); 804 } 805 806 if (DEBUG) { 807 byte[] rawBuffer = outputStream.toByteArray(); 808 String rawFileName = DEBUG_FILE_NAME_BASE + "/raw16_" + TAG + size.toString() + 809 "_cam_" + mCamera.getId() + ".dng"; 810 Log.d(TAG, "Dump raw file into " + rawFileName); 811 dumpFile(rawFileName, rawBuffer); 812 813 byte[] jpegBuffer = getDataFromImage(jpegImage); 814 String jpegFileName = DEBUG_FILE_NAME_BASE + "/jpeg_" + TAG + size.toString() + 815 "_cam_" + mCamera.getId() + ".jpg"; 816 Log.d(TAG, "Dump jpeg file into " + rawFileName); 817 dumpFile(jpegFileName, jpegBuffer); 818 } 819 820 stopPreview(); 821 } finally { 822 CameraTestUtils.closeImageReader(rawReader); 823 CameraTestUtils.closeImageReader(jpegReader); 824 rawReader = null; 825 jpegReader = null; 826 } 827 } 828 829 /** 830 * Validate that raw {@link CaptureResult}. 831 * 832 * @param rawRequest a {@link CaptureRequest} use to capture a RAW16 image. 833 * @param rawResult the {@link CaptureResult} corresponding to the given request. 834 */ verifyRawCaptureResult(CaptureRequest rawRequest, CaptureResult rawResult)835 private void verifyRawCaptureResult(CaptureRequest rawRequest, CaptureResult rawResult) { 836 assertNotNull(rawRequest); 837 assertNotNull(rawResult); 838 839 Rational[] empty = new Rational[] { Rational.ZERO, Rational.ZERO, Rational.ZERO}; 840 Rational[] neutralColorPoint = mCollector.expectKeyValueNotNull("NeutralColorPoint", 841 rawResult, CaptureResult.SENSOR_NEUTRAL_COLOR_POINT); 842 if (neutralColorPoint != null) { 843 mCollector.expectEquals("NeutralColorPoint length", empty.length, 844 neutralColorPoint.length); 845 mCollector.expectNotEquals("NeutralColorPoint cannot be all zeroes, ", empty, 846 neutralColorPoint); 847 mCollector.expectValuesGreaterOrEqual("NeutralColorPoint", neutralColorPoint, 848 Rational.ZERO); 849 } 850 851 mCollector.expectKeyValueGreaterOrEqual(rawResult, CaptureResult.SENSOR_GREEN_SPLIT, 0.0f); 852 853 Pair<Double, Double>[] noiseProfile = mCollector.expectKeyValueNotNull("NoiseProfile", 854 rawResult, CaptureResult.SENSOR_NOISE_PROFILE); 855 if (noiseProfile != null) { 856 mCollector.expectEquals("NoiseProfile length", noiseProfile.length, 857 /*Num CFA channels*/4); 858 for (Pair<Double, Double> p : noiseProfile) { 859 mCollector.expectTrue("NoiseProfile coefficients " + p + 860 " must have: S > 0, O >= 0", p.first > 0 && p.second >= 0); 861 } 862 } 863 864 Integer hotPixelMode = mCollector.expectKeyValueNotNull("HotPixelMode", rawResult, 865 CaptureResult.HOT_PIXEL_MODE); 866 Boolean hotPixelMapMode = mCollector.expectKeyValueNotNull("HotPixelMapMode", rawResult, 867 CaptureResult.STATISTICS_HOT_PIXEL_MAP_MODE); 868 Point[] hotPixelMap = rawResult.get(CaptureResult.STATISTICS_HOT_PIXEL_MAP); 869 870 Size pixelArraySize = mStaticInfo.getPixelArraySizeChecked(); 871 boolean[] availableHotPixelMapModes = mStaticInfo.getValueFromKeyNonNull( 872 CameraCharacteristics.STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES); 873 874 if (hotPixelMode != null) { 875 Integer requestMode = mCollector.expectKeyValueNotNull(rawRequest, 876 CaptureRequest.HOT_PIXEL_MODE); 877 if (requestMode != null) { 878 mCollector.expectKeyValueEquals(rawResult, CaptureResult.HOT_PIXEL_MODE, 879 requestMode); 880 } 881 } 882 883 if (hotPixelMapMode != null) { 884 Boolean requestMapMode = mCollector.expectKeyValueNotNull(rawRequest, 885 CaptureRequest.STATISTICS_HOT_PIXEL_MAP_MODE); 886 if (requestMapMode != null) { 887 mCollector.expectKeyValueEquals(rawResult, 888 CaptureResult.STATISTICS_HOT_PIXEL_MAP_MODE, requestMapMode); 889 } 890 891 if (!hotPixelMapMode) { 892 mCollector.expectTrue("HotPixelMap must be empty", hotPixelMap == null || 893 hotPixelMap.length == 0); 894 } else { 895 mCollector.expectTrue("HotPixelMap must not be empty", hotPixelMap != null); 896 mCollector.expectNotNull("AvailableHotPixelMapModes must not be null", 897 availableHotPixelMapModes); 898 if (availableHotPixelMapModes != null) { 899 mCollector.expectContains("HotPixelMapMode", availableHotPixelMapModes, true); 900 } 901 902 int height = pixelArraySize.getHeight(); 903 int width = pixelArraySize.getWidth(); 904 for (Point p : hotPixelMap) { 905 mCollector.expectTrue("Hotpixel " + p + " must be in pixelArray " + 906 pixelArraySize, p.x >= 0 && p.x < width && p.y >= 0 && p.y < height); 907 } 908 } 909 } 910 // TODO: profileHueSatMap, and profileToneCurve aren't supported yet. 911 912 } 913 914 /** 915 * Issue a Jpeg capture and validate the exif information. 916 * <p> 917 * TODO: Differentiate full and limited device, some of the checks rely on 918 * per frame control and synchronization, most of them don't. 919 * </p> 920 */ jpegExifTestByCamera()921 private void jpegExifTestByCamera() throws Exception { 922 Size maxPreviewSz = mOrderedPreviewSizes.get(0); 923 Size maxStillSz = mOrderedStillSizes.get(0); 924 if (VERBOSE) { 925 Log.v(TAG, "Testing JPEG exif with jpeg size " + maxStillSz.toString() 926 + ", preview size " + maxPreviewSz); 927 } 928 929 // prepare capture and start preview. 930 CaptureRequest.Builder previewBuilder = 931 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 932 CaptureRequest.Builder stillBuilder = 933 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 934 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 935 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 936 prepareStillCaptureAndStartPreview(previewBuilder, stillBuilder, maxPreviewSz, maxStillSz, 937 resultListener, imageListener); 938 939 // Set the jpeg keys, then issue a capture 940 Size[] thumbnailSizes = mStaticInfo.getAvailableThumbnailSizesChecked(); 941 Size maxThumbnailSize = thumbnailSizes[thumbnailSizes.length - 1]; 942 Size[] testThumbnailSizes = new Size[EXIF_TEST_DATA.length]; 943 Arrays.fill(testThumbnailSizes, maxThumbnailSize); 944 // Make sure thumbnail size (0, 0) is covered. 945 testThumbnailSizes[0] = new Size(0, 0); 946 947 for (int i = 0; i < EXIF_TEST_DATA.length; i++) { 948 setJpegKeys(stillBuilder, EXIF_TEST_DATA[i], testThumbnailSizes[i], mCollector); 949 950 // Capture a jpeg image. 951 CaptureRequest request = stillBuilder.build(); 952 mSession.capture(request, resultListener, mHandler); 953 CaptureResult stillResult = 954 resultListener.getCaptureResultForRequest(request, NUM_RESULTS_WAIT_TIMEOUT); 955 Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 956 957 verifyJpegKeys(image, stillResult, maxStillSz, testThumbnailSizes[i], EXIF_TEST_DATA[i], 958 mStaticInfo, mCollector); 959 960 // Free image resources 961 image.close(); 962 } 963 } 964 aeCompensationTestByCamera()965 private void aeCompensationTestByCamera() throws Exception { 966 Range<Integer> compensationRange = mStaticInfo.getAeCompensationRangeChecked(); 967 // Skip the test if exposure compensation is not supported. 968 if (compensationRange.equals(Range.create(0, 0))) { 969 return; 970 } 971 972 Rational step = mStaticInfo.getAeCompensationStepChecked(); 973 float stepF = (float) step.getNumerator() / step.getDenominator(); 974 int stepsPerEv = (int) Math.round(1.0 / stepF); 975 int numSteps = (compensationRange.getUpper() - compensationRange.getLower()) / stepsPerEv; 976 977 Size maxStillSz = mOrderedStillSizes.get(0); 978 Size maxPreviewSz = mOrderedPreviewSizes.get(0); 979 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 980 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 981 CaptureRequest.Builder previewRequest = 982 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 983 CaptureRequest.Builder stillRequest = 984 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 985 boolean canSetAeLock = mStaticInfo.isAeLockSupported(); 986 987 if (canSetAeLock) { 988 stillRequest.set(CaptureRequest.CONTROL_AE_LOCK, true); 989 } 990 991 CaptureResult normalResult; 992 CaptureResult compensatedResult; 993 994 // The following variables should only be read under the MANUAL_SENSOR capability guard: 995 long minExposureValue = -1; 996 long maxExposureTimeUs = -1; 997 long maxExposureValuePreview = -1; 998 long maxExposureValueStill = -1; 999 if (mStaticInfo.isCapabilitySupported( 1000 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 1001 // Minimum exposure settings is mostly static while maximum exposure setting depends on 1002 // frame rate range which in term depends on capture request. 1003 minExposureValue = mStaticInfo.getSensitivityMinimumOrDefault() * 1004 mStaticInfo.getExposureMinimumOrDefault() / 1000; 1005 long maxSensitivity = mStaticInfo.getSensitivityMaximumOrDefault(); 1006 maxExposureTimeUs = mStaticInfo.getExposureMaximumOrDefault() / 1000; 1007 maxExposureValuePreview = getMaxExposureValue(previewRequest, maxExposureTimeUs, 1008 maxSensitivity); 1009 maxExposureValueStill = getMaxExposureValue(stillRequest, maxExposureTimeUs, 1010 maxSensitivity); 1011 } 1012 1013 // Set the max number of images to be same as the burst count, as the verification 1014 // could be much slower than producing rate, and we don't want to starve producer. 1015 prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz, 1016 maxStillSz, resultListener, numSteps, imageListener); 1017 1018 for (int i = 0; i <= numSteps; i++) { 1019 int exposureCompensation = i * stepsPerEv + compensationRange.getLower(); 1020 double expectedRatio = Math.pow(2.0, exposureCompensation / stepsPerEv); 1021 1022 // Wait for AE to be stabilized before capture: CONVERGED or FLASH_REQUIRED. 1023 waitForAeStable(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 1024 normalResult = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 1025 1026 long normalExposureValue = -1; 1027 if (mStaticInfo.isCapabilitySupported( 1028 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS)) { 1029 // get and check if current exposure value is valid 1030 normalExposureValue = getExposureValue(normalResult); 1031 mCollector.expectInRange("Exposure setting out of bound", normalExposureValue, 1032 minExposureValue, maxExposureValuePreview); 1033 1034 // Only run the test if expectedExposureValue is within valid range 1035 long expectedExposureValue = (long) (normalExposureValue * expectedRatio); 1036 if (expectedExposureValue < minExposureValue || 1037 expectedExposureValue > maxExposureValueStill) { 1038 continue; 1039 } 1040 Log.v(TAG, "Expect ratio: " + expectedRatio + 1041 " normalExposureValue: " + normalExposureValue + 1042 " expectedExposureValue: " + expectedExposureValue + 1043 " minExposureValue: " + minExposureValue + 1044 " maxExposureValuePreview: " + maxExposureValuePreview + 1045 " maxExposureValueStill: " + maxExposureValueStill); 1046 } 1047 1048 // Now issue exposure compensation and wait for AE locked. AE could take a few 1049 // frames to go back to locked state 1050 previewRequest.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, 1051 exposureCompensation); 1052 if (canSetAeLock) { 1053 previewRequest.set(CaptureRequest.CONTROL_AE_LOCK, true); 1054 } 1055 mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler); 1056 if (canSetAeLock) { 1057 waitForAeLocked(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 1058 } else { 1059 waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY); 1060 } 1061 1062 // Issue still capture 1063 if (VERBOSE) { 1064 Log.v(TAG, "Verifying capture result for ae compensation value " 1065 + exposureCompensation); 1066 } 1067 1068 stillRequest.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, exposureCompensation); 1069 CaptureRequest request = stillRequest.build(); 1070 mSession.capture(request, resultListener, mHandler); 1071 1072 compensatedResult = resultListener.getCaptureResultForRequest( 1073 request, WAIT_FOR_RESULT_TIMEOUT_MS); 1074 1075 if (mStaticInfo.isCapabilitySupported( 1076 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS)) { 1077 // Verify the exposure value compensates as requested 1078 long compensatedExposureValue = getExposureValue(compensatedResult); 1079 mCollector.expectInRange("Exposure setting out of bound", compensatedExposureValue, 1080 minExposureValue, maxExposureValueStill); 1081 double observedRatio = (double) compensatedExposureValue / normalExposureValue; 1082 double error = observedRatio / expectedRatio; 1083 String errorString = String.format( 1084 "Exposure compensation ratio exceeds error tolerence:" + 1085 " expected(%f) observed(%f)." + 1086 " Normal exposure time %d us, sensitivity %d." + 1087 " Compensated exposure time %d us, sensitivity %d", 1088 expectedRatio, observedRatio, 1089 (int) (getValueNotNull( 1090 normalResult, CaptureResult.SENSOR_EXPOSURE_TIME) / 1000), 1091 getValueNotNull(normalResult, CaptureResult.SENSOR_SENSITIVITY), 1092 (int) (getValueNotNull( 1093 compensatedResult, CaptureResult.SENSOR_EXPOSURE_TIME) / 1000), 1094 getValueNotNull(compensatedResult, CaptureResult.SENSOR_SENSITIVITY)); 1095 mCollector.expectInRange(errorString, error, 1096 1.0 - AE_COMPENSATION_ERROR_TOLERANCE, 1097 1.0 + AE_COMPENSATION_ERROR_TOLERANCE); 1098 } 1099 1100 mCollector.expectEquals("Exposure compensation result should match requested value.", 1101 exposureCompensation, 1102 compensatedResult.get(CaptureResult.CONTROL_AE_EXPOSURE_COMPENSATION)); 1103 if (canSetAeLock) { 1104 mCollector.expectTrue("Exposure lock should be set", 1105 compensatedResult.get(CaptureResult.CONTROL_AE_LOCK)); 1106 } 1107 1108 Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 1109 validateJpegCapture(image, maxStillSz); 1110 image.close(); 1111 1112 // Recover AE compensation and lock 1113 previewRequest.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, 0); 1114 if (canSetAeLock) { 1115 previewRequest.set(CaptureRequest.CONTROL_AE_LOCK, false); 1116 } 1117 mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler); 1118 } 1119 } 1120 getExposureValue(CaptureResult result)1121 private long getExposureValue(CaptureResult result) throws Exception { 1122 int expTimeUs = (int) (getValueNotNull(result, CaptureResult.SENSOR_EXPOSURE_TIME) / 1000); 1123 int sensitivity = getValueNotNull(result, CaptureResult.SENSOR_SENSITIVITY); 1124 return expTimeUs * sensitivity; 1125 } 1126 getMaxExposureValue(CaptureRequest.Builder request, long maxExposureTimeUs, long maxSensitivity)1127 private long getMaxExposureValue(CaptureRequest.Builder request, long maxExposureTimeUs, 1128 long maxSensitivity) throws Exception { 1129 Range<Integer> fpsRange = request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE); 1130 long maxFrameDurationUs = Math.round(1000000.0 / fpsRange.getLower()); 1131 long currentMaxExposureTimeUs = Math.min(maxFrameDurationUs, maxExposureTimeUs); 1132 return currentMaxExposureTimeUs * maxSensitivity; 1133 } 1134 1135 1136 //---------------------------------------------------------------- 1137 //---------Below are common functions for all tests.-------------- 1138 //---------------------------------------------------------------- 1139 /** 1140 * Validate standard raw (RAW16) capture image. 1141 * 1142 * @param image The raw16 format image captured 1143 * @param rawSize The expected raw size 1144 */ validateRaw16Image(Image image, Size rawSize)1145 private static void validateRaw16Image(Image image, Size rawSize) { 1146 CameraTestUtils.validateImage(image, rawSize.getWidth(), rawSize.getHeight(), 1147 ImageFormat.RAW_SENSOR, /*filePath*/null); 1148 } 1149 1150 /** 1151 * Validate JPEG capture image object sanity and test. 1152 * <p> 1153 * In addition to image object sanity, this function also does the decoding 1154 * test, which is slower. 1155 * </p> 1156 * 1157 * @param image The JPEG image to be verified. 1158 * @param jpegSize The JPEG capture size to be verified against. 1159 */ validateJpegCapture(Image image, Size jpegSize)1160 private static void validateJpegCapture(Image image, Size jpegSize) { 1161 CameraTestUtils.validateImage(image, jpegSize.getWidth(), jpegSize.getHeight(), 1162 ImageFormat.JPEG, /*filePath*/null); 1163 } 1164 1165 private static class SimpleAutoFocusListener implements Camera2Focuser.AutoFocusListener { 1166 final ConditionVariable focusDone = new ConditionVariable(); 1167 @Override onAutoFocusLocked(boolean success)1168 public void onAutoFocusLocked(boolean success) { 1169 focusDone.open(); 1170 } 1171 waitForAutoFocusDone(long timeoutMs)1172 public void waitForAutoFocusDone(long timeoutMs) { 1173 if (focusDone.block(timeoutMs)) { 1174 focusDone.close(); 1175 } else { 1176 throw new TimeoutRuntimeException("Wait for auto focus done timed out after " 1177 + timeoutMs + "ms"); 1178 } 1179 } 1180 } 1181 1182 /** 1183 * Get 5 3A region test cases, each with one square region in it. 1184 * The first one is at center, the other four are at corners of 1185 * active array rectangle. 1186 * 1187 * @return array of test 3A regions 1188 */ get3ARegionTestCasesForCamera()1189 private ArrayList<MeteringRectangle[]> get3ARegionTestCasesForCamera() { 1190 final int TEST_3A_REGION_NUM = 5; 1191 final int DEFAULT_REGION_WEIGHT = 30; 1192 final int DEFAULT_REGION_SCALE_RATIO = 8; 1193 ArrayList<MeteringRectangle[]> testCases = 1194 new ArrayList<MeteringRectangle[]>(TEST_3A_REGION_NUM); 1195 final Rect activeArraySize = mStaticInfo.getActiveArraySizeChecked(); 1196 int regionWidth = activeArraySize.width() / DEFAULT_REGION_SCALE_RATIO - 1; 1197 int regionHeight = activeArraySize.height() / DEFAULT_REGION_SCALE_RATIO - 1; 1198 int centerX = activeArraySize.width() / 2; 1199 int centerY = activeArraySize.height() / 2; 1200 int bottomRightX = activeArraySize.width() - 1; 1201 int bottomRightY = activeArraySize.height() - 1; 1202 1203 // Center region 1204 testCases.add( 1205 new MeteringRectangle[] { 1206 new MeteringRectangle( 1207 centerX - regionWidth / 2, // x 1208 centerY - regionHeight / 2, // y 1209 regionWidth, // width 1210 regionHeight, // height 1211 DEFAULT_REGION_WEIGHT)}); 1212 1213 // Upper left corner 1214 testCases.add( 1215 new MeteringRectangle[] { 1216 new MeteringRectangle( 1217 0, // x 1218 0, // y 1219 regionWidth, // width 1220 regionHeight, // height 1221 DEFAULT_REGION_WEIGHT)}); 1222 1223 // Upper right corner 1224 testCases.add( 1225 new MeteringRectangle[] { 1226 new MeteringRectangle( 1227 bottomRightX - regionWidth, // x 1228 0, // y 1229 regionWidth, // width 1230 regionHeight, // height 1231 DEFAULT_REGION_WEIGHT)}); 1232 1233 // Bottom left corner 1234 testCases.add( 1235 new MeteringRectangle[] { 1236 new MeteringRectangle( 1237 0, // x 1238 bottomRightY - regionHeight, // y 1239 regionWidth, // width 1240 regionHeight, // height 1241 DEFAULT_REGION_WEIGHT)}); 1242 1243 // Bottom right corner 1244 testCases.add( 1245 new MeteringRectangle[] { 1246 new MeteringRectangle( 1247 bottomRightX - regionWidth, // x 1248 bottomRightY - regionHeight, // y 1249 regionWidth, // width 1250 regionHeight, // height 1251 DEFAULT_REGION_WEIGHT)}); 1252 1253 if (VERBOSE) { 1254 StringBuilder sb = new StringBuilder(); 1255 for (MeteringRectangle[] mr : testCases) { 1256 sb.append("{"); 1257 sb.append(Arrays.toString(mr)); 1258 sb.append("}, "); 1259 } 1260 if (sb.length() > 1) 1261 sb.setLength(sb.length() - 2); // Remove the redundant comma and space at the end 1262 Log.v(TAG, "Generated test regions are: " + sb.toString()); 1263 } 1264 1265 return testCases; 1266 } 1267 isRegionsSupportedFor3A(int index)1268 private boolean isRegionsSupportedFor3A(int index) { 1269 int maxRegions = 0; 1270 switch (index) { 1271 case MAX_REGIONS_AE_INDEX: 1272 maxRegions = mStaticInfo.getAeMaxRegionsChecked(); 1273 break; 1274 case MAX_REGIONS_AWB_INDEX: 1275 maxRegions = mStaticInfo.getAwbMaxRegionsChecked(); 1276 break; 1277 case MAX_REGIONS_AF_INDEX: 1278 maxRegions = mStaticInfo.getAfMaxRegionsChecked(); 1279 break; 1280 default: 1281 throw new IllegalArgumentException("Unknown algorithm index"); 1282 } 1283 boolean isRegionsSupported = maxRegions > 0; 1284 if (index == MAX_REGIONS_AF_INDEX && isRegionsSupported) { 1285 mCollector.expectTrue( 1286 "Device reports non-zero max AF region count for a camera without focuser!", 1287 mStaticInfo.hasFocuser()); 1288 isRegionsSupported = isRegionsSupported && mStaticInfo.hasFocuser(); 1289 } 1290 1291 return isRegionsSupported; 1292 } 1293 } 1294