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