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