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 21 import android.graphics.ImageFormat; 22 import android.graphics.Rect; 23 import android.hardware.camera2.CameraCharacteristics; 24 import android.hardware.camera2.CameraDevice; 25 import android.hardware.camera2.CaptureRequest; 26 import android.hardware.camera2.CaptureRequest.Builder; 27 import android.hardware.camera2.CaptureResult; 28 import android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback; 29 import android.hardware.camera2.cts.CameraTestUtils.SimpleImageReaderListener; 30 import android.hardware.camera2.cts.helpers.StaticMetadata; 31 import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase; 32 import android.hardware.camera2.params.StreamConfigurationMap; 33 import android.media.Image; 34 import android.util.Log; 35 import android.util.Range; 36 import android.util.Size; 37 38 import java.util.ArrayList; 39 40 import org.junit.runner.RunWith; 41 import org.junit.runners.Parameterized; 42 import org.junit.Test; 43 44 /** 45 * Basic tests for burst capture in RAW formats. 46 */ 47 @RunWith(Parameterized.class) 48 public class BurstCaptureRawTest extends Camera2SurfaceViewTestCase { 49 private static final String TAG = "BurstCaptureRawTest"; 50 private static final int RAW_FORMATS[] = { 51 ImageFormat.RAW10, ImageFormat.RAW12, ImageFormat.RAW_SENSOR }; 52 private static final int NONSTALL_RAW_FORMATS[] = { 53 ImageFormat.RAW10, ImageFormat.RAW12 }; 54 private static final long EXPOSURE_MULTIPLIERS[] = { 55 1, 3, 5 }; 56 private static final int SENSITIVITY_MLTIPLIERS[] = { 57 1, 3, 5 }; 58 private static final int MAX_FRAMES_BURST = 59 EXPOSURE_MULTIPLIERS.length * SENSITIVITY_MLTIPLIERS.length; 60 61 @Override setUp()62 public void setUp() throws Exception { 63 super.setUp(); 64 } 65 66 @Override tearDown()67 public void tearDown() throws Exception { 68 super.tearDown(); 69 } 70 71 /** 72 * Verify raw sensor size information is correctly configured. 73 */ 74 @Test testRawSensorSize()75 public void testRawSensorSize() throws Exception { 76 Log.i(TAG, "Begin testRawSensorSize"); 77 for (String id : getCameraIdsUnderTest()) { 78 try { 79 ArrayList<Integer> supportedRawList = new ArrayList<Integer>(RAW_FORMATS.length); 80 if (!checkCapability(id, supportedRawList, RAW_FORMATS)) { 81 Log.i(TAG, "Capability is not supported on camera " + id 82 + ". Skip the test."); 83 continue; 84 } 85 86 openDevice(id); 87 Size[] rawSizes = mStaticInfo.getRawOutputSizesChecked(); 88 assertTrue("No capture sizes available for RAW format!", rawSizes.length != 0); 89 90 // Check happens in getRawDimensChecked. 91 Size rawSize = mStaticInfo.getRawDimensChecked(); 92 } finally { 93 closeDevice(); 94 } 95 } 96 Log.i(TAG, "End testRawSensorSize"); 97 } 98 99 /** 100 * Round [exposure, gain] down, rather than to the nearest, in RAW 10/16 101 * <p> 102 * Verify the value of metadata (exposure and sensitivity) is rounded down if the request cannot 103 * be honored. 104 * </p> 105 */ 106 @Test testMetadataRoundDown()107 public void testMetadataRoundDown() throws Exception { 108 Log.i(TAG, "Begin testMetadataRoundDown"); 109 110 performTestRoutine(new TestMetaDataRoundDownRoutine(), RAW_FORMATS); 111 112 Log.i(TAG, "End testMetadataRoundDown"); 113 } 114 115 /** 116 * Manual and Auto setting test in RAW formats 117 * <p> 118 * Make sure switching between manual and auto setting would not make the capture results out of 119 * sync. 120 * </p> 121 */ 122 @Test testManualAutoSwitch()123 public void testManualAutoSwitch() throws Exception { 124 Log.i(TAG, "Begin testManualAutoSwitch"); 125 126 performTestRoutine(new TestManualAutoSwitch(), RAW_FORMATS); 127 128 Log.i(TAG, "End testManualAutoSwitch"); 129 } 130 131 /** 132 * Per frame timestamp test in non-stalled RAW formats 133 */ 134 @Test testTimestamp()135 public void testTimestamp() throws Exception { 136 Log.i(TAG, "Begin testTimestamp"); 137 138 performTestRoutine(new TestTimestamp(), NONSTALL_RAW_FORMATS); 139 140 Log.i(TAG, "End testTimestamp"); 141 } 142 143 /* 144 * Below are private infrastructure for all tests 145 */ 146 147 /** 148 * A structure encapsulates all the parameters for setting up preview, and RAW capture. 149 */ 150 class CaptureSetup 151 { CaptureSetup(Size previewCaptureSize, Size rawCaptureSize, CaptureRequest.Builder previewRequestBuilder, CaptureRequest.Builder rawRequestBuilder, SimpleCaptureCallback previewCaptureCallback, SimpleCaptureCallback rawCaptureCallback, SimpleImageReaderListener rawReaderListener)152 public CaptureSetup(Size previewCaptureSize, Size rawCaptureSize, 153 CaptureRequest.Builder previewRequestBuilder, 154 CaptureRequest.Builder rawRequestBuilder, 155 SimpleCaptureCallback previewCaptureCallback, 156 SimpleCaptureCallback rawCaptureCallback, 157 SimpleImageReaderListener rawReaderListener) 158 { 159 mPreviewCaptureSize = previewCaptureSize; 160 mRawCaptureSize = rawCaptureSize; 161 mPreviewRequestBuilder = previewRequestBuilder; 162 mRawRequestBuilder = rawRequestBuilder; 163 mPreviewCaptureCallback = previewCaptureCallback; 164 mRawCaptureCallback = rawCaptureCallback; 165 mRawReaderListener = rawReaderListener; 166 } 167 getPreviewCaptureSize()168 public Size getPreviewCaptureSize() 169 { 170 return mPreviewCaptureSize; 171 } 172 getRawCaptureSize()173 public Size getRawCaptureSize() 174 { 175 return mRawCaptureSize; 176 } 177 getPreviewRequestBuilder()178 public CaptureRequest.Builder getPreviewRequestBuilder() 179 { 180 return mPreviewRequestBuilder; 181 } 182 getRawRequestBuilder()183 public CaptureRequest.Builder getRawRequestBuilder() { 184 return mRawRequestBuilder; 185 } 186 getPreviewCaptureCallback()187 public SimpleCaptureCallback getPreviewCaptureCallback() { 188 return mPreviewCaptureCallback; 189 } 190 getRawCaptureCallback()191 public SimpleCaptureCallback getRawCaptureCallback() { 192 return mRawCaptureCallback; 193 } 194 getRawReaderListener()195 public SimpleImageReaderListener getRawReaderListener() { 196 return mRawReaderListener; 197 } 198 199 private Size mPreviewCaptureSize; 200 private Size mRawCaptureSize; 201 private CaptureRequest.Builder mPreviewRequestBuilder; 202 private CaptureRequest.Builder mRawRequestBuilder; 203 204 /** all the non-testing requests are sent to here */ 205 private SimpleCaptureCallback mPreviewCaptureCallback; 206 /** all the testing requests are sent to here */ 207 private SimpleCaptureCallback mRawCaptureCallback; 208 /** all the testing framebuffers are sent to here */ 209 private SimpleImageReaderListener mRawReaderListener; 210 } 211 212 /** 213 * Interface for the test routines that are being called by performTestRoutines(). Implement 214 * different test cases in execute(). 215 */ 216 interface TestRoutine { execute(CaptureRequest.Builder rawBurstBuilder, SimpleCaptureCallback rawCaptureCallback, SimpleImageReaderListener rawReaderListener, int rawFormat)217 public void execute(CaptureRequest.Builder rawBurstBuilder, 218 SimpleCaptureCallback rawCaptureCallback, 219 SimpleImageReaderListener rawReaderListener, int rawFormat) throws Exception; 220 } 221 222 /** 223 * Implementation of metadata round down test. 224 */ 225 class TestMetaDataRoundDownRoutine implements TestRoutine 226 { 227 @Override execute(CaptureRequest.Builder rawBurstBuilder, SimpleCaptureCallback rawCaptureCallback, SimpleImageReaderListener rawReaderListener, int rawFormat)228 public void execute(CaptureRequest.Builder rawBurstBuilder, 229 SimpleCaptureCallback rawCaptureCallback, 230 SimpleImageReaderListener rawReaderListener, int rawFormat) throws Exception 231 { 232 // build burst capture 233 ArrayList<CaptureRequest> rawRequestList = createBurstRequest(rawBurstBuilder); 234 235 // submit capture 236 Log.i(TAG, "Submitting Burst Request."); 237 mSession.captureBurst(rawRequestList, rawCaptureCallback, mHandler); 238 239 // verify metadata 240 for (int i = 0; i < MAX_FRAMES_BURST; i++) { 241 CaptureResult result = rawCaptureCallback.getCaptureResult( 242 CAPTURE_IMAGE_TIMEOUT_MS); 243 244 long resultExposure = result.get(CaptureResult.SENSOR_EXPOSURE_TIME); 245 int resultSensitivity = result.get(CaptureResult.SENSOR_SENSITIVITY); 246 long desiredExposure = rawRequestList.get(i).get( 247 CaptureRequest.SENSOR_EXPOSURE_TIME); 248 int desiredSensitivity = rawRequestList.get(i).get( 249 CaptureRequest.SENSOR_SENSITIVITY); 250 251 Log.i(TAG, String.format( 252 "Received capture result, exposure = %d, sensitivity = %d. " 253 + "Requested exposure = %d, sensitivity = %d.", 254 resultExposure, 255 resultSensitivity, desiredExposure, desiredSensitivity)); 256 257 mCollector.expectTrue( 258 String.format("Exposure value is greater than requested: " 259 + "requested = %d, result = %d.", 260 desiredExposure, resultExposure), 261 resultExposure <= desiredExposure); 262 263 mCollector.expectTrue( 264 String.format("Sensitivity value is greater than requested: " 265 + "requested = %d, result = %d.", 266 desiredSensitivity, resultSensitivity), 267 resultSensitivity <= desiredSensitivity); 268 } 269 } 270 } 271 272 /** 273 * Implementation of manual-auto switching test. 274 */ 275 class TestManualAutoSwitch implements TestRoutine 276 { 277 @Override execute(CaptureRequest.Builder rawBurstBuilder, SimpleCaptureCallback rawCaptureCallback, SimpleImageReaderListener rawReaderListener, int rawFormat)278 public void execute(CaptureRequest.Builder rawBurstBuilder, 279 SimpleCaptureCallback rawCaptureCallback, 280 SimpleImageReaderListener rawReaderListener, int rawFormat) throws Exception 281 { 282 // create a capture request builder to preserve all the original values 283 CaptureRequest.Builder originBuilder = mCamera.createCaptureRequest( 284 CameraDevice.TEMPLATE_STILL_CAPTURE); 285 copyBurstRequetBuilder(originBuilder, rawBurstBuilder); 286 287 // build burst capture 288 ArrayList<CaptureRequest> rawRequestList = createBurstRequest(rawBurstBuilder); 289 290 // submit capture but ignore 291 mSession.captureBurst(rawRequestList, rawCaptureCallback, mHandler); 292 293 // drain the capture result 294 drainQueues(rawReaderListener, rawCaptureCallback); 295 296 // reset and build capture with 3A 297 copyBurstRequetBuilder(rawBurstBuilder, originBuilder); 298 rawRequestList = createBurstRequestWith3A(rawBurstBuilder); 299 300 // submit capture but ignore 301 mSession.captureBurst(rawRequestList, rawCaptureCallback, mHandler); 302 303 // drain the capture result 304 drainQueues(rawReaderListener, rawCaptureCallback); 305 306 // reset and rebuild manual raw burst capture 307 copyBurstRequetBuilder(rawBurstBuilder, originBuilder); 308 rawRequestList = createBurstRequest(rawBurstBuilder); 309 310 // submit capture 311 Log.i(TAG, "Submitting Burst Request."); 312 mSession.captureBurst(rawRequestList, rawCaptureCallback, mHandler); 313 314 // verify metadata 315 for (int i = 0; i < MAX_FRAMES_BURST; i++) { 316 CaptureResult result = rawCaptureCallback.getCaptureResult( 317 CAPTURE_IMAGE_TIMEOUT_MS); 318 319 long resultExposure = result.get(CaptureResult.SENSOR_EXPOSURE_TIME); 320 int resultSensitivity = result.get(CaptureResult.SENSOR_SENSITIVITY); 321 int resultEdgeMode = result.get(CaptureResult.EDGE_MODE); 322 int resultNoiseReductionMode = result.get( 323 CaptureResult.NOISE_REDUCTION_MODE); 324 long desiredExposure = rawRequestList.get(i).get( 325 CaptureRequest.SENSOR_EXPOSURE_TIME); 326 int desiredSensitivity = rawRequestList.get(i).get( 327 CaptureRequest.SENSOR_SENSITIVITY); 328 329 Log.i(TAG, String.format( 330 "Received capture result, exposure = %d, sensitivity = %d. " 331 + "Requested exposure = %d, sensitivity = %d.", 332 resultExposure, 333 resultSensitivity, desiredExposure, desiredSensitivity)); 334 335 mCollector.expectTrue(String.format("Edge mode is not turned off."), 336 resultEdgeMode == CaptureRequest.EDGE_MODE_OFF); 337 338 mCollector.expectTrue(String.format("Noise reduction is not turned off."), 339 resultNoiseReductionMode 340 == CaptureRequest.NOISE_REDUCTION_MODE_OFF); 341 342 mCollector.expectTrue( 343 String.format("Exposure value is greater than requested: " 344 + "requested = %d, result = %d.", 345 desiredExposure, resultExposure), 346 resultExposure <= desiredExposure); 347 348 mCollector.expectTrue( 349 String.format("Sensitivity value is greater than requested: " 350 + "requested = %d, result = %d.", 351 desiredSensitivity, resultSensitivity), 352 resultSensitivity <= desiredSensitivity); 353 } 354 355 } 356 } 357 358 /** 359 * Implementation of timestamp test 360 */ 361 class TestTimestamp implements TestRoutine 362 { 363 private final double THRESHOLD = 5000000.0; // 5ms 364 private final long EXPOSURE_MULTIPLIERS_PRIVATE[] = { 365 1, 1, 1 }; 366 private final int SENSITIVITY_MLTIPLIERS_PRIVATE[] = { 367 1, 1, 1 }; 368 private final int MAX_FRAMES_BURST_PRIVATE = 369 EXPOSURE_MULTIPLIERS_PRIVATE.length * SENSITIVITY_MLTIPLIERS_PRIVATE.length; 370 371 @Override execute(Builder rawBurstBuilder, SimpleCaptureCallback rawCaptureCallback, SimpleImageReaderListener rawReaderListener, int rawFormat)372 public void execute(Builder rawBurstBuilder, SimpleCaptureCallback rawCaptureCallback, 373 SimpleImageReaderListener rawReaderListener, int rawFormat) throws Exception { 374 // prepare some local variables 375 ArrayList<Long> sensorTime = new ArrayList<Long>(MAX_FRAMES_BURST_PRIVATE); 376 377 // build burst capture 378 ArrayList<CaptureRequest> rawRequestList = createBurstRequest(rawBurstBuilder, 379 EXPOSURE_MULTIPLIERS_PRIVATE, SENSITIVITY_MLTIPLIERS_PRIVATE); 380 381 // submit capture while recording timestamp 382 Log.i(TAG, "Submitting Burst Request."); 383 mSession.captureBurst(rawRequestList, rawCaptureCallback, mHandler); 384 385 // receive frames while recording timestamp 386 for (int i = 0; i < MAX_FRAMES_BURST_PRIVATE; i++) { 387 CaptureResult result = rawCaptureCallback.getCaptureResult( 388 CAPTURE_IMAGE_TIMEOUT_MS); 389 long resultExposure = result.get(CaptureResult.SENSOR_EXPOSURE_TIME); 390 int resultSensitivity = result.get(CaptureResult.SENSOR_SENSITIVITY); 391 long resultTimestamp = result.get(CaptureResult.SENSOR_TIMESTAMP); 392 Log.i(TAG, String.format( 393 "Received capture result, exposure = %d, sensitivity = %d, timestamp = %d", 394 resultExposure, resultSensitivity, resultTimestamp)); 395 396 sensorTime.add(resultTimestamp); 397 } 398 399 // compare sensor time and compute the difference 400 ArrayList<Long> deltaList = new ArrayList<Long>(); 401 for (int i = 1; i < MAX_FRAMES_BURST_PRIVATE; i++) 402 { 403 deltaList.add(sensorTime.get(i) - sensorTime.get(i - 1)); 404 } 405 406 // compute the average and standard deviation of the differences 407 double average = 0.0; 408 for (int i = 0; i < deltaList.size(); i++) 409 { 410 average += deltaList.get(i); 411 } 412 average /= deltaList.size(); 413 414 double stddev = 0.0; 415 for (int i = 0; i < deltaList.size(); i++) 416 { 417 double diff = deltaList.get(i) - average; 418 stddev += diff * diff; 419 } 420 stddev = Math.sqrt(stddev / deltaList.size()); 421 422 Log.i(TAG, String.format("average = %.2f, stddev = %.2f", average, stddev)); 423 424 StringBuilder sensorTimestampMessage = new StringBuilder(); 425 for (int i = 0; i < sensorTime.size(); i++) 426 { 427 sensorTimestampMessage.append("frame ["); 428 sensorTimestampMessage.append(i); 429 sensorTimestampMessage.append("] SENSOR_TIMESTAMP = "); 430 sensorTimestampMessage.append(sensorTime.get(i)); 431 sensorTimestampMessage.append("\n"); 432 } 433 434 mCollector.expectLessOrEqual( 435 "The standard deviation of frame interval is larger then threshold: " + 436 String.format("stddev = %.2f, threshold = %.2f.\n", stddev, THRESHOLD) + 437 sensorTimestampMessage.toString(), 438 THRESHOLD, stddev); 439 } 440 } 441 442 /** 443 * Check sensor capability prior to the test. 444 * 445 * @return true if the it is has the capability to execute the test. 446 */ checkCapability(String id, ArrayList<Integer> supportedRawList, int[] testedFormats)447 private boolean checkCapability(String id, ArrayList<Integer> supportedRawList, 448 int[] testedFormats) { 449 StaticMetadata staticInfo = mAllStaticInfo.get(id); 450 // make sure the sensor has manual support 451 if (!staticInfo.isHardwareLevelAtLeastFull()) { 452 Log.w(TAG, "Full hardware level is not supported"); 453 return false; 454 } 455 456 // get the list of supported RAW format 457 StreamConfigurationMap config = staticInfo.getValueFromKeyNonNull( 458 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 459 460 // check for the RAW support 461 supportedRawList.clear(); 462 for (int rawFormat : testedFormats) { 463 if (!config.isOutputSupportedFor(rawFormat)) { 464 continue; 465 } 466 supportedRawList.add(rawFormat); 467 } 468 469 if (supportedRawList.size() == 0) 470 { 471 Log.w(TAG, "RAW output is not supported!"); 472 return false; 473 } 474 475 return true; 476 } 477 478 /** 479 * Return the sensor format to human readable string. 480 * 481 * @param format Sensor image format. 482 * @return Human readable string. 483 */ imageFormatToString(int format)484 private String imageFormatToString(int format) { 485 switch (format) { 486 case ImageFormat.RAW10: 487 return "RAW10"; 488 case ImageFormat.RAW12: 489 return "RAW12"; 490 case ImageFormat.RAW_SENSOR: 491 return "RAW_SENSOR"; 492 } 493 494 return "Unknown"; 495 } 496 497 /** 498 * Setting up various classes prior to the request, e.g.: capture size, builder, callback and 499 * listener 500 * 501 * @return initialized variables that can be directly fed into prepareCaptureAndStartPreview(). 502 */ initCaptureSetupForPreviewAndRaw()503 private CaptureSetup initCaptureSetupForPreviewAndRaw() throws Exception 504 { 505 // capture size 506 Size previewSize = mOrderedPreviewSizes.get(0); 507 Size rawSize = mStaticInfo.getRawDimensChecked(); 508 509 // builder 510 CaptureRequest.Builder previewCaptureBuilder = mCamera.createCaptureRequest( 511 CameraDevice.TEMPLATE_PREVIEW); 512 CaptureRequest.Builder rawCaptureBuilder = mCamera.createCaptureRequest( 513 CameraDevice.TEMPLATE_STILL_CAPTURE); 514 515 // callback 516 SimpleCaptureCallback previewCaptureCallback = new SimpleCaptureCallback(); 517 SimpleCaptureCallback rawCaptureCallback = new SimpleCaptureCallback(); 518 SimpleImageReaderListener rawReaderListener = new SimpleImageReaderListener(); 519 520 CaptureSetup setup = new CaptureSetup(previewSize, rawSize, previewCaptureBuilder, 521 rawCaptureBuilder, previewCaptureCallback, rawCaptureCallback, rawReaderListener); 522 523 return setup; 524 } 525 526 /** 527 * Construct an array of burst request with manual exposure and sensitivity. 528 * <p> 529 * For each capture request, 3A and post processing (noise reduction, sharpening, etc) will be 530 * turned off. Then exposure and sensitivity value will be configured, which are determined by 531 * EXPOSURE_MULIPLIERS and SENSITIVITY_MULTIPLIERS. 532 * </p> 533 * 534 * @param rawBurstBuilder The builder needs to have targets setup. 535 * @return An array list capture request for burst. 536 */ createBurstRequest(CaptureRequest.Builder rawBurstBuilder)537 private ArrayList<CaptureRequest> createBurstRequest(CaptureRequest.Builder rawBurstBuilder) 538 { 539 return createBurstRequest(rawBurstBuilder, EXPOSURE_MULTIPLIERS, SENSITIVITY_MLTIPLIERS); 540 } 541 createBurstRequest(CaptureRequest.Builder rawBurstBuilder, long[] exposureMultipliers, int[] sensitivityMultipliers)542 private ArrayList<CaptureRequest> createBurstRequest(CaptureRequest.Builder rawBurstBuilder, 543 long[] exposureMultipliers, int[] sensitivityMultipliers) { 544 // set manual mode 545 rawBurstBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF); 546 rawBurstBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_OFF); 547 rawBurstBuilder.set(CaptureRequest.NOISE_REDUCTION_MODE, 548 CaptureRequest.NOISE_REDUCTION_MODE_OFF); 549 rawBurstBuilder.set(CaptureRequest.EDGE_MODE, CaptureRequest.EDGE_MODE_OFF); 550 // exposure has higher priority over frame duration; therefore the frame readout time: 551 // exposure time + overhead 552 rawBurstBuilder.set(CaptureRequest.SENSOR_FRAME_DURATION, 0L); 553 554 // get the exposure and sensitivity range 555 Range<Long> exposureRangeNs = new Range<Long>(mStaticInfo.getExposureMinimumOrDefault(), 556 mStaticInfo.getExposureMaximumOrDefault()); 557 558 Range<Integer> isoRange = new Range<Integer>(mStaticInfo.getSensitivityMinimumOrDefault(), 559 mStaticInfo.getSensitivityMaximumOrDefault()); 560 561 Log.i(TAG, String.format("Exposure time - max: %d, min: %d.", exposureRangeNs.getUpper(), 562 exposureRangeNs.getLower())); 563 Log.i(TAG, String.format("Sensitivity - max: %d, min: %d.", isoRange.getUpper(), 564 isoRange.getLower())); 565 566 // building burst request 567 int maxFramesBurst = exposureMultipliers.length * sensitivityMultipliers.length; 568 Log.i(TAG, String.format("Setting up burst = %d frames.", maxFramesBurst)); 569 ArrayList<CaptureRequest> rawRequestList = new ArrayList<CaptureRequest>(maxFramesBurst); 570 571 for (int i = 0; i < exposureMultipliers.length; i++) { 572 for (int j = 0; j < sensitivityMultipliers.length; j++) { 573 long desiredExposure = Math.min( 574 exposureRangeNs.getLower() * exposureMultipliers[i], 575 exposureRangeNs.getUpper()); 576 577 int desiredSensitivity = 578 Math.min(isoRange.getLower() * sensitivityMultipliers[j], 579 isoRange.getUpper()); 580 581 rawBurstBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, desiredExposure); 582 rawBurstBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, desiredSensitivity); 583 584 rawRequestList.add(rawBurstBuilder.build()); 585 } 586 } 587 return rawRequestList; 588 } 589 590 /** 591 * Construct an array of burst request with 3A 592 * <p> 593 * For each capture request, 3A and post processing (noise reduction, sharpening, etc) will be 594 * turned on. 595 * </p> 596 * 597 * @param rawBurstBuilder The builder needs to have targets setup. 598 * @return An array list capture request for burst. 599 */ createBurstRequestWith3A( CaptureRequest.Builder rawBurstBuilder)600 private ArrayList<CaptureRequest> createBurstRequestWith3A( 601 CaptureRequest.Builder rawBurstBuilder) 602 { 603 // set 3A mode to simulate regular still capture 604 rawBurstBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); 605 rawBurstBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_AUTO); 606 rawBurstBuilder.set(CaptureRequest.NOISE_REDUCTION_MODE, 607 CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY); 608 rawBurstBuilder.set(CaptureRequest.EDGE_MODE, CaptureRequest.EDGE_MODE_HIGH_QUALITY); 609 610 // building burst request 611 Log.i(TAG, String.format("Setting up burst = %d frames.", MAX_FRAMES_BURST)); 612 ArrayList<CaptureRequest> rawRequestList = new ArrayList<CaptureRequest>(MAX_FRAMES_BURST); 613 614 for (int i = 0; i < MAX_FRAMES_BURST; i++) { 615 rawRequestList.add(rawBurstBuilder.build()); 616 } 617 618 return rawRequestList; 619 } 620 621 /** 622 * An utility method to copy capture request builders. This is used for recovery purpose to 623 * reverse the changes we made to the builder. 624 * 625 * @param dst the builder to write into. 626 * @param src the builder that needs to be copied. 627 */ copyBurstRequetBuilder(CaptureRequest.Builder dst, CaptureRequest.Builder src)628 private void copyBurstRequetBuilder(CaptureRequest.Builder dst, CaptureRequest.Builder src) 629 { 630 dst.set(CaptureRequest.CONTROL_AE_MODE, src.get(CaptureRequest.CONTROL_AE_MODE)); 631 dst.set(CaptureRequest.CONTROL_AWB_MODE, src.get(CaptureRequest.CONTROL_AWB_MODE)); 632 dst.set(CaptureRequest.NOISE_REDUCTION_MODE, src.get(CaptureRequest.NOISE_REDUCTION_MODE)); 633 dst.set(CaptureRequest.EDGE_MODE, src.get(CaptureRequest.EDGE_MODE)); 634 dst.set(CaptureRequest.SENSOR_FRAME_DURATION, 635 src.get(CaptureRequest.SENSOR_FRAME_DURATION)); 636 dst.set(CaptureRequest.SENSOR_EXPOSURE_TIME, src.get(CaptureRequest.SENSOR_EXPOSURE_TIME)); 637 dst.set(CaptureRequest.SENSOR_SENSITIVITY, src.get(CaptureRequest.SENSOR_SENSITIVITY)); 638 } 639 640 /** 641 * Draining the image reader and capture callback queue 642 * 643 * @param readerListener Image reader listener needs to be drained. 644 * @param captureCallback Capture callback needs to be drained. 645 * @throws Exception Exception from the queue. 646 */ drainQueues(SimpleImageReaderListener readerListener, SimpleCaptureCallback captureCallback)647 private void drainQueues(SimpleImageReaderListener readerListener, 648 SimpleCaptureCallback captureCallback) throws Exception 649 { 650 for (int i = 0; i < MAX_FRAMES_BURST; i++) { 651 Image image = readerListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 652 image.close(); 653 654 CaptureResult result = captureCallback.getCaptureResult( 655 CAPTURE_IMAGE_TIMEOUT_MS); 656 long timestamp = result.get(CaptureResult.SENSOR_TIMESTAMP); 657 Log.d(TAG, String.format("timestamp = %d", timestamp)); 658 } 659 } 660 661 /** 662 * Stop preview and remove the target surfaces inside the CaptureRequest.Builder. 663 * 664 * @param previewBuilder Configured builder for preview. 665 * @param rawBurstBuilder Configured builder for RAW. 666 * @throws Exception Exceptions from stopPreview. 667 */ stopPreviewAndClearSurface(CaptureRequest.Builder previewBuilder, CaptureRequest.Builder rawBurstBuilder)668 private void stopPreviewAndClearSurface(CaptureRequest.Builder previewBuilder, 669 CaptureRequest.Builder rawBurstBuilder) throws Exception 670 { 671 previewBuilder.removeTarget(mPreviewSurface); 672 rawBurstBuilder.removeTarget(mPreviewSurface); 673 rawBurstBuilder.removeTarget(mReaderSurface); 674 675 stopPreview(); 676 } 677 performTestRoutine(TestRoutine routine, int[] testedFormats)678 private void performTestRoutine(TestRoutine routine, int[] testedFormats) throws Exception 679 { 680 final int PREPARE_TIMEOUT_MS = 10000; 681 for (String id : getCameraIdsUnderTest()) { 682 try { 683 ArrayList<Integer> supportedRawList = new ArrayList<Integer>(RAW_FORMATS.length); 684 if (!checkCapability(id, supportedRawList, testedFormats)) { 685 Log.i(TAG, "Capability is not supported on camera " + id 686 + ". Skip the test."); 687 continue; 688 } 689 690 openDevice(id); 691 // test each supported RAW format 692 for (int rawFormat : supportedRawList) { 693 Log.i(TAG, "Testing format " + imageFormatToString(rawFormat) + "."); 694 695 // prepare preview and still RAW capture 696 CaptureSetup captureSetup = initCaptureSetupForPreviewAndRaw(); 697 698 Size previewCaptureSize = captureSetup.getPreviewCaptureSize(); 699 Size rawCaptureSize = captureSetup.getRawCaptureSize(); 700 701 CaptureRequest.Builder previewBuilder = captureSetup.getPreviewRequestBuilder(); 702 CaptureRequest.Builder rawBurstBuilder = captureSetup.getRawRequestBuilder(); 703 704 SimpleCaptureCallback previewCaptureCallback = 705 captureSetup.getPreviewCaptureCallback(); 706 SimpleCaptureCallback rawCaptureCallback = captureSetup.getRawCaptureCallback(); 707 SimpleImageReaderListener rawReaderListener = captureSetup 708 .getRawReaderListener(); 709 710 // start preview and prepare RAW capture 711 prepareCaptureAndStartPreview(previewBuilder, rawBurstBuilder, 712 previewCaptureSize, rawCaptureSize, rawFormat, previewCaptureCallback, 713 MAX_FRAMES_BURST, rawReaderListener); 714 715 // Prepare still surface to prevent large allocations slow down capture 716 mSession.prepare(mReaderSurface); 717 mSessionListener.waitForSurfacePrepared( 718 mSession, mReaderSurface, PREPARE_TIMEOUT_MS); 719 720 // execute test routine 721 routine.execute(rawBurstBuilder, rawCaptureCallback, rawReaderListener, 722 rawFormat); 723 724 // clear out the surface and camera session 725 stopPreviewAndClearSurface(previewBuilder, rawBurstBuilder); 726 rawReaderListener.drain(); 727 closeImageReader(); 728 } 729 } finally { 730 closeDevice(); 731 } 732 } 733 } 734 } 735