Home | History | Annotate | Download | only in cts
      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
     59     public void setUp() throws Exception {
     60         super.setUp();
     61     }
     62 
     63     @Override
     64     public void tearDown() throws Exception {
     65         super.tearDown();
     66     }
     67 
     68     /**
     69      * Verify raw sensor size information is correctly configured.
     70      */
     71     @Test
     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
    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
    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
    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     {
    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 
    165         public Size getPreviewCaptureSize()
    166         {
    167             return mPreviewCaptureSize;
    168         }
    169 
    170         public Size getRawCaptureSize()
    171         {
    172             return mRawCaptureSize;
    173         }
    174 
    175         public CaptureRequest.Builder getPreviewRequestBuilder()
    176         {
    177             return mPreviewRequestBuilder;
    178         }
    179 
    180         public CaptureRequest.Builder getRawRequestBuilder() {
    181             return mRawRequestBuilder;
    182         }
    183 
    184         public SimpleCaptureCallback getPreviewCaptureCallback() {
    185             return mPreviewCaptureCallback;
    186         }
    187 
    188         public SimpleCaptureCallback getRawCaptureCallback() {
    189             return mRawCaptureCallback;
    190         }
    191 
    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 {
    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
    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
    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
    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      */
    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      */
    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      */
    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      */
    534     private ArrayList<CaptureRequest> createBurstRequest(CaptureRequest.Builder rawBurstBuilder)
    535     {
    536         return createBurstRequest(rawBurstBuilder, EXPOSURE_MULTIPLIERS, SENSITIVITY_MLTIPLIERS);
    537     }
    538 
    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      */
    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      */
    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      */
    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      */
    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 
    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