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