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