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