Home | History | Annotate | Download | only in stress
      1 /*
      2  * Copyright (C) 2016 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 com.android.mediaframeworktest.stress;
     18 
     19 import com.android.ex.camera2.blocking.BlockingSessionCallback;
     20 import com.android.ex.camera2.exceptions.TimeoutRuntimeException;
     21 import com.android.mediaframeworktest.Camera2SurfaceViewTestCase;
     22 import com.android.mediaframeworktest.helpers.Camera2Focuser;
     23 import com.android.mediaframeworktest.helpers.CameraTestUtils;
     24 import com.android.mediaframeworktest.helpers.CameraTestUtils.SimpleCaptureCallback;
     25 
     26 import android.graphics.ImageFormat;
     27 import android.graphics.Point;
     28 import android.hardware.camera2.CameraCharacteristics;
     29 import android.hardware.camera2.CameraCaptureSession.CaptureCallback;
     30 import android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession;
     31 import android.hardware.camera2.CameraDevice;
     32 import android.hardware.camera2.CameraAccessException;
     33 import android.hardware.camera2.CameraCaptureSession;
     34 import android.hardware.camera2.CaptureRequest;
     35 import android.hardware.camera2.CaptureResult;
     36 import android.hardware.camera2.DngCreator;
     37 import android.hardware.camera2.params.MeteringRectangle;
     38 import android.media.Image;
     39 import android.media.ImageReader;
     40 import android.media.CamcorderProfile;
     41 import android.media.MediaExtractor;
     42 import android.media.MediaFormat;
     43 import android.media.MediaRecorder;
     44 import android.os.ConditionVariable;
     45 import android.os.Environment;
     46 import android.util.Log;
     47 import android.util.Pair;
     48 import android.util.Rational;
     49 import android.util.Size;
     50 import android.view.Surface;
     51 import android.hardware.camera2.params.StreamConfigurationMap;
     52 import android.test.suitebuilder.annotation.LargeTest;
     53 import android.util.Log;
     54 import android.util.Range;
     55 
     56 import java.io.ByteArrayOutputStream;
     57 import java.util.ArrayList;
     58 import java.util.List;
     59 import java.io.File;
     60 import java.util.Arrays;
     61 import java.util.HashMap;
     62 
     63 import static com.android.mediaframeworktest.helpers.CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS;
     64 import static com.android.mediaframeworktest.helpers.CameraTestUtils.MAX_READER_IMAGES;
     65 import static com.android.mediaframeworktest.helpers.CameraTestUtils.SimpleImageReaderListener;
     66 import static com.android.mediaframeworktest.helpers.CameraTestUtils.basicValidateJpegImage;
     67 import static com.android.mediaframeworktest.helpers.CameraTestUtils.configureCameraSession;
     68 import static com.android.mediaframeworktest.helpers.CameraTestUtils.dumpFile;
     69 import static com.android.mediaframeworktest.helpers.CameraTestUtils.getDataFromImage;
     70 import static com.android.mediaframeworktest.helpers.CameraTestUtils.getValueNotNull;
     71 import static com.android.mediaframeworktest.helpers.CameraTestUtils.makeImageReader;
     72 import static com.android.ex.camera2.blocking.BlockingSessionCallback.SESSION_CLOSED;
     73 import static com.android.mediaframeworktest.helpers.CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS;
     74 import static com.android.mediaframeworktest.helpers.CameraTestUtils.SESSION_CLOSE_TIMEOUT_MS;
     75 import static com.android.mediaframeworktest.helpers.CameraTestUtils.SIZE_BOUND_1080P;
     76 import static com.android.mediaframeworktest.helpers.CameraTestUtils.SIZE_BOUND_2160P;
     77 import static com.android.mediaframeworktest.helpers.CameraTestUtils.getSupportedVideoSizes;
     78 
     79 import com.android.ex.camera2.blocking.BlockingSessionCallback;
     80 import com.android.mediaframeworktest.Camera2SurfaceViewTestCase;
     81 import com.android.mediaframeworktest.helpers.CameraTestUtils;
     82 
     83 import junit.framework.AssertionFailedError;
     84 
     85 /**
     86  * <p>Tests Back/Front camera switching and Camera/Video modes witching.</p>
     87  *
     88  * adb shell am instrument \
     89  *    -e class com.android.mediaframeworktest.stress.Camera2SwitchPreviewTest \
     90  *    -e iterations 200 \
     91  *    -e waitIntervalMs 1000 \
     92  *    -e resultToFile false \
     93  *    -r -w com.android.mediaframeworktest/.Camera2InstrumentationTestRunner
     94  */
     95 public class Camera2SwitchPreviewTest extends Camera2SurfaceViewTestCase {
     96     private static final String TAG = "SwitchPreviewTest";
     97     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
     98     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     99     // 60 second to accommodate the possible long exposure time.
    100     private static final int MAX_REGIONS_AE_INDEX = 0;
    101     private static final int MAX_REGIONS_AWB_INDEX = 1;
    102     private static final int MAX_REGIONS_AF_INDEX = 2;
    103     private static final int WAIT_FOR_FOCUS_DONE_TIMEOUT_MS = 6000;
    104     private static final double AE_COMPENSATION_ERROR_TOLERANCE = 0.2;
    105     // 5 percent error margin for resulting metering regions
    106     private static final float METERING_REGION_ERROR_PERCENT_DELTA = 0.05f;
    107     private final String VIDEO_FILE_PATH = Environment.getExternalStorageDirectory().getPath();
    108 
    109     private static final boolean DEBUG_DUMP = Log.isLoggable(TAG, Log.DEBUG);
    110     private static final int RECORDING_DURATION_MS = 3000;
    111     private static final float DURATION_MARGIN = 0.2f;
    112     private static final double FRAME_DURATION_ERROR_TOLERANCE_MS = 3.0;
    113     private static final int BIT_RATE_1080P = 16000000;
    114     private static final int BIT_RATE_MIN = 64000;
    115     private static final int BIT_RATE_MAX = 40000000;
    116     private static final int VIDEO_FRAME_RATE = 30;
    117     private static final int[] mCamcorderProfileList = {
    118             CamcorderProfile.QUALITY_HIGH,
    119             CamcorderProfile.QUALITY_2160P,
    120             CamcorderProfile.QUALITY_1080P,
    121             CamcorderProfile.QUALITY_720P,
    122             CamcorderProfile.QUALITY_480P,
    123             CamcorderProfile.QUALITY_CIF,
    124             CamcorderProfile.QUALITY_QCIF,
    125             CamcorderProfile.QUALITY_QVGA,
    126             CamcorderProfile.QUALITY_LOW,
    127     };
    128     private static final int MAX_VIDEO_SNAPSHOT_IMAGES = 5;
    129     private static final int BURST_VIDEO_SNAPSHOT_NUM = 3;
    130     private static final int SLOWMO_SLOW_FACTOR = 4;
    131     private static final int MAX_NUM_FRAME_DROP_INTERVAL_ALLOWED = 4;
    132     private List<Size> mSupportedVideoSizes;
    133     private Surface mRecordingSurface;
    134     private Surface mPersistentSurface;
    135     private MediaRecorder mMediaRecorder;
    136     private String mOutMediaFileName;
    137     private int mVideoFrameRate;
    138     private Size mVideoSize;
    139     private long mRecordingStartTime;
    140 
    141     @Override
    142     protected void setUp() throws Exception {
    143         super.setUp();
    144     }
    145 
    146     @Override
    147     protected void tearDown() throws Exception {
    148         super.tearDown();
    149     }
    150 
    151     /**
    152      * Test normal still preview switch.
    153      * <p>
    154      * Preview jpeg output streams are configured. Max still capture
    155      * size is used for jpeg capture.
    156      * </p>
    157      */
    158     public void testPreviewSwitchBackFrontCamera() throws Exception {
    159         List<String> mCameraColorOutputIds = cameraColorOutputCheck();
    160         // Test iteration starts...
    161         Log.i(TAG, "Testing preview switch back/front camera in still capture mode");
    162         for (int iteration = 0; iteration < getIterationCount(); ++iteration) {
    163             for (String id : mCameraColorOutputIds) {
    164                 try {
    165                     openDevice(id);
    166                     // Preview for basic still capture:
    167                     Log.v(TAG, String.format("Preview pictures: %d/%d", iteration + 1,
    168                             getIterationCount()));
    169                     stillCapturePreviewPreparer(id);
    170                     getResultPrinter().printStatus(getIterationCount(), iteration + 1, id);
    171                 } finally {
    172                     closeDevice();
    173                     closeImageReader();
    174                 }
    175             }
    176         }
    177     }
    178 
    179     /**
    180      * <p>
    181      * Test basic video preview switch.
    182      * </p>
    183      * <p>
    184      * This test covers the typical basic use case of video preview switch.
    185      * MediaRecorder is used to record the audio and video, CamcorderProfile is
    186      * used to configure the MediaRecorder. Preview is set to the video size.
    187      * </p>
    188      */
    189     public void testPreviewSwitchBackFrontVideo() throws Exception {
    190         List<String> mCameraColorOutputIds = cameraColorOutputCheck();
    191         // Test iteration starts...
    192         Log.i(TAG, "Testing preview switch back/front camera in video mode");
    193         for (int iteration = 0; iteration < getIterationCount(); ++iteration) {
    194             for (String id : mCameraColorOutputIds) {
    195                 try {
    196                     openDevice(id);
    197                     // Preview for basic video recording:
    198                     Log.v(TAG, String.format("Preview for recording videos: %d/%d", iteration + 1,
    199                             getIterationCount()));
    200                     recordingPreviewPreparer(id);
    201                     getResultPrinter().printStatus(getIterationCount(), iteration + 1, id);
    202                 } finally {
    203                     closeDevice();
    204                     releaseRecorder();
    205                 }
    206             }
    207         }
    208     }
    209 
    210 
    211     /**
    212      * Test back camera preview switch between still capture and recording mode.
    213      * <p>
    214      * This test covers the basic case of preview switch camera mode, between
    215      * still capture (photo) and recording (video) mode. The preview settings
    216      * are same with the settings in "testPreviewSwitchBackFrontCamera" and
    217      * "testPreviewSwitchBackFrontVideo"
    218      * </p>
    219      */
    220     public void testPreviewSwitchBackCameraVideo() throws Exception {
    221         String id = mCameraIds[0];
    222         openDevice(id);
    223         if (!mStaticInfo.isColorOutputSupported()) {
    224             Log.i(TAG, "Camera " + id +
    225                     " does not support color outputs, skipping");
    226             return;
    227         }
    228         closeDevice();
    229         // Test iteration starts...
    230         Log.i(TAG, "Testing preview switch between still capture/video modes for back camera");
    231         for (int iteration = 0; iteration < getIterationCount(); ++iteration) {
    232             try {
    233                 openDevice(id);
    234 
    235                 // Preview for basic still capture:
    236                 Log.v(TAG, String.format("Preview pictures: %d/%d", iteration + 1,
    237                         getIterationCount()));
    238                 stillCapturePreviewPreparer(id);
    239                 getResultPrinter().printStatus(getIterationCount(), iteration + 1, id);
    240 
    241                 // Preview for basic video recording:
    242                 Log.v(TAG, String.format("Preview for recording videos: %d/%d", iteration + 1,
    243                         getIterationCount()));
    244                 recordingPreviewPreparer(id);
    245                 getResultPrinter().printStatus(getIterationCount(), iteration + 1, id);
    246             } finally {
    247                 closeDevice();
    248                 closeImageReader();
    249             }
    250         }
    251     }
    252 
    253     /**
    254      * Test front camera preview switch between still capture and recording mode.
    255      * <p>
    256      * This test covers the basic case of preview switch camera mode, between
    257      * still capture (photo) and recording (video) mode. The preview settings
    258      * are same with the settings in "testPreviewSwitchBackFrontCamera" and
    259      * "testPreviewSwitchBackFrontVideo"
    260      * </p>
    261      */
    262     public void testPreviewSwitchFrontCameraVideo() throws Exception{
    263         String id = mCameraIds[1];
    264         openDevice(id);
    265         if (!mStaticInfo.isColorOutputSupported()) {
    266             Log.i(TAG, "Camera " + id +
    267                     " does not support color outputs, skipping");
    268             return;
    269         }
    270         closeDevice();
    271         // Test iteration starts...
    272         Log.i(TAG, "Testing preview switch between still capture/video modes for front camera");
    273         for (int iteration = 0; iteration < getIterationCount(); ++iteration) {
    274             try {
    275                 openDevice(id);
    276 
    277                 // Preview for basic still capture:
    278                 Log.v(TAG, String.format("Preview pictures: %d/%d", iteration + 1,
    279                         getIterationCount()));
    280                 stillCapturePreviewPreparer(id);
    281                 getResultPrinter().printStatus(getIterationCount(), iteration + 1, id);
    282 
    283                 // Preview for basic video recording:
    284                 Log.v(TAG, String.format("Preview for recording videos: %d/%d", iteration + 1,
    285                         getIterationCount()));
    286                 recordingPreviewPreparer(id);
    287                 getResultPrinter().printStatus(getIterationCount(), iteration + 1, id);
    288             } finally {
    289                 closeDevice();
    290                 closeImageReader();
    291             }
    292         }
    293     }
    294 
    295     private void stillCapturePreviewPreparer(String id) throws Exception{
    296         CaptureResult result;
    297         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
    298         SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
    299         CaptureRequest.Builder previewRequest =
    300                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
    301         CaptureRequest.Builder stillRequest =
    302                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
    303         // Preview Setup:
    304         prepareCapturePreview(previewRequest, stillRequest, resultListener, imageListener);
    305 
    306         Thread.sleep(getTestWaitIntervalMs());
    307     }
    308 
    309     private void recordingPreviewPreparer(String id) throws Exception{
    310         // Re-use the MediaRecorder object for the same camera device.
    311         mMediaRecorder = new MediaRecorder();
    312         initSupportedVideoSize(id);
    313         // preview Setup:
    314         basicRecordingPreviewTestByCamera(mCamcorderProfileList);
    315 
    316         Thread.sleep(getTestWaitIntervalMs());
    317     }
    318 
    319 
    320     /**
    321      * Initialize the supported video sizes.
    322      */
    323     private void initSupportedVideoSize(String cameraId)  throws Exception {
    324         Size maxVideoSize = SIZE_BOUND_1080P;
    325         if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_2160P)) {
    326             maxVideoSize = SIZE_BOUND_2160P;
    327         }
    328         mSupportedVideoSizes =
    329                 getSupportedVideoSizes(cameraId, mCameraManager, maxVideoSize);
    330     }
    331 
    332 
    333     /**
    334      * Test camera recording preview by using each available CamcorderProfile for a
    335      * given camera. preview size is set to the video size.
    336      */
    337     private void basicRecordingPreviewTestByCamera(int[] camcorderProfileList)
    338             throws Exception {
    339         Size maxPreviewSize = mOrderedPreviewSizes.get(0);
    340         List<Range<Integer> > fpsRanges = Arrays.asList(
    341                 mStaticInfo.getAeAvailableTargetFpsRangesChecked());
    342         int cameraId = Integer.parseInt(mCamera.getId());
    343         int maxVideoFrameRate = -1;
    344         int profileId = camcorderProfileList[0];
    345         if (!CamcorderProfile.hasProfile(cameraId, profileId) ||
    346                 allowedUnsupported(cameraId, profileId)) {
    347             return;
    348         }
    349 
    350         CamcorderProfile profile = CamcorderProfile.get(cameraId, profileId);
    351         Size videoSz = new Size(profile.videoFrameWidth, profile.videoFrameHeight);
    352         Range<Integer> fpsRange = new Range(profile.videoFrameRate, profile.videoFrameRate);
    353         if (maxVideoFrameRate < profile.videoFrameRate) {
    354                 maxVideoFrameRate = profile.videoFrameRate;
    355         }
    356         if (mStaticInfo.isHardwareLevelLegacy() &&
    357                 (videoSz.getWidth() > maxPreviewSize.getWidth() ||
    358                         videoSz.getHeight() > maxPreviewSize.getHeight())) {
    359             // Skip. Legacy mode can only do recording up to max preview size
    360             return;
    361         }
    362         assertTrue("Video size " + videoSz.toString() + " for profile ID " + profileId +
    363                             " must be one of the camera device supported video size!",
    364                     mSupportedVideoSizes.contains(videoSz));
    365         assertTrue("Frame rate range " + fpsRange + " (for profile ID " + profileId +
    366                             ") must be one of the camera device available FPS range!",
    367                 fpsRanges.contains(fpsRange));
    368 
    369         if (VERBOSE) {
    370             Log.v(TAG, "Testing camera recording with video size " + videoSz.toString());
    371         }
    372 
    373         // Configure preview and recording surfaces.
    374         mOutMediaFileName = VIDEO_FILE_PATH + "/test_video.mp4";
    375         if (DEBUG_DUMP) {
    376             mOutMediaFileName = VIDEO_FILE_PATH + "/test_video_" + cameraId + "_"
    377                     + videoSz.toString() + ".mp4";
    378         }
    379 
    380         prepareRecordingWithProfile(profile);
    381 
    382         // prepare preview surface by using video size.
    383         updatePreviewSurfaceWithVideo(videoSz, profile.videoFrameRate);
    384 
    385         CaptureRequest.Builder previewRequest =
    386                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
    387         CaptureRequest.Builder recordingRequest =
    388                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
    389 
    390         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
    391         SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
    392 
    393         prepareVideoPreview(previewRequest, recordingRequest, resultListener, imageListener);
    394 
    395         // Can reuse the MediaRecorder object after reset.
    396         mMediaRecorder.reset();
    397 
    398         if (maxVideoFrameRate != -1) {
    399             // At least one CamcorderProfile is present, check FPS
    400             assertTrue("At least one CamcorderProfile must support >= 24 FPS",
    401                     maxVideoFrameRate >= 24);
    402         }
    403     }
    404 
    405     private void releaseRecorder() {
    406         if (mMediaRecorder != null) {
    407             mMediaRecorder.release();
    408             mMediaRecorder = null;
    409         }
    410     }
    411 
    412     private List<String> cameraColorOutputCheck() throws Exception {
    413         List<String> mCameraColorOutputIds = new ArrayList<String>();
    414         for (String id : mCameraIds) {
    415             openDevice(id);
    416             if (!mStaticInfo.isColorOutputSupported()) {
    417                 Log.i(TAG, "Camera " + id +
    418                         " does not support color outputs, skipping");
    419                 continue;
    420             }
    421             mCameraColorOutputIds.add(id);
    422             closeDevice();
    423         }
    424         return mCameraColorOutputIds;
    425     }
    426 
    427     /**
    428      * Returns {@code true} if the {@link CamcorderProfile} ID is allowed to be unsupported.
    429      *
    430      * <p>This only allows unsupported profiles when using the LEGACY mode of the Camera API.</p>
    431      *
    432      * @param profileId a {@link CamcorderProfile} ID to check.
    433      * @return {@code true} if supported.
    434      */
    435     private boolean allowedUnsupported(int cameraId, int profileId) {
    436         if (!mStaticInfo.isHardwareLevelLegacy()) {
    437             return false;
    438         }
    439 
    440         switch(profileId) {
    441             case CamcorderProfile.QUALITY_2160P:
    442             case CamcorderProfile.QUALITY_1080P:
    443             case CamcorderProfile.QUALITY_HIGH:
    444                 return !CamcorderProfile.hasProfile(cameraId, profileId) ||
    445                         CamcorderProfile.get(cameraId, profileId).videoFrameWidth >= 1080;
    446         }
    447         return false;
    448     }
    449 
    450     /**
    451      * Configure MediaRecorder recording session with CamcorderProfile, prepare
    452      * the recording surface.
    453      */
    454     private void prepareRecordingWithProfile(CamcorderProfile profile)
    455             throws Exception {
    456         // Prepare MediaRecorder.
    457         mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
    458         mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
    459         mMediaRecorder.setProfile(profile);
    460         mMediaRecorder.setOutputFile(mOutMediaFileName);
    461         if (mPersistentSurface != null) {
    462             mMediaRecorder.setInputSurface(mPersistentSurface);
    463             mRecordingSurface = mPersistentSurface;
    464         }
    465         mMediaRecorder.prepare();
    466         if (mPersistentSurface == null) {
    467             mRecordingSurface = mMediaRecorder.getSurface();
    468         }
    469         assertNotNull("Recording surface must be non-null!", mRecordingSurface);
    470         mVideoFrameRate = profile.videoFrameRate;
    471         mVideoSize = new Size(profile.videoFrameWidth, profile.videoFrameHeight);
    472     }
    473 
    474     /**
    475      * Update preview size with video size.
    476      *
    477      * <p>Preview size will be capped with max preview size.</p>
    478      *
    479      * @param videoSize The video size used for preview.
    480      * @param videoFrameRate The video frame rate
    481      *
    482      */
    483     private void updatePreviewSurfaceWithVideo(Size videoSize, int videoFrameRate)  throws Exception {
    484         if (mOrderedPreviewSizes == null) {
    485             throw new IllegalStateException("supported preview size list is not initialized yet");
    486         }
    487         final float FRAME_DURATION_TOLERANCE = 0.01f;
    488         long videoFrameDuration = (long) (1e9 / videoFrameRate *
    489                 (1.0 + FRAME_DURATION_TOLERANCE));
    490         HashMap<Size, Long> minFrameDurationMap = mStaticInfo.
    491                 getAvailableMinFrameDurationsForFormatChecked(ImageFormat.PRIVATE);
    492         Size maxPreviewSize = mOrderedPreviewSizes.get(0);
    493         Size previewSize = null;
    494         if (videoSize.getWidth() > maxPreviewSize.getWidth() ||
    495                 videoSize.getHeight() > maxPreviewSize.getHeight()) {
    496             for (Size s : mOrderedPreviewSizes) {
    497                 Long frameDuration = minFrameDurationMap.get(s);
    498                 if (mStaticInfo.isHardwareLevelLegacy()) {
    499                     // Legacy doesn't report min frame duration
    500                     frameDuration = new Long(0);
    501                 }
    502                 assertTrue("Cannot find minimum frame duration for private size" + s,
    503                         frameDuration != null);
    504                 if (frameDuration <= videoFrameDuration &&
    505                         s.getWidth() <= videoSize.getWidth() &&
    506                         s.getHeight() <= videoSize.getHeight()) {
    507                     Log.w(TAG, "Overwrite preview size from " + videoSize.toString() +
    508                             " to " + s.toString());
    509                     previewSize = s;
    510                     break;
    511                     // If all preview size doesn't work then we fallback to video size
    512                 }
    513             }
    514         }
    515         if (previewSize == null) {
    516             previewSize = videoSize;
    517         }
    518 
    519         updatePreviewSurface(previewSize);
    520     }
    521 
    522     protected void prepareVideoPreview(CaptureRequest.Builder previewRequest,
    523                                                  CaptureRequest.Builder recordingRequest,
    524                                                  CaptureCallback resultListener,
    525                                                  ImageReader.OnImageAvailableListener imageListener) throws Exception {
    526 
    527         // Configure output streams with preview and jpeg streams.
    528         List<Surface> outputSurfaces = new ArrayList<Surface>();
    529         outputSurfaces.add(mPreviewSurface);
    530         outputSurfaces.add(mRecordingSurface);
    531 
    532         mSessionListener = new BlockingSessionCallback();
    533         mSession = configureCameraSession(mCamera, outputSurfaces, mSessionListener, mHandler);
    534 
    535         previewRequest.addTarget(mPreviewSurface);
    536         recordingRequest.addTarget(mPreviewSurface);
    537         recordingRequest.addTarget(mRecordingSurface);
    538 
    539         // Start preview.
    540         mSession.setRepeatingRequest(previewRequest.build(), null, mHandler);
    541     }
    542 
    543     protected void prepareCapturePreview(CaptureRequest.Builder previewRequest,
    544                                                  CaptureRequest.Builder stillRequest,
    545                                                  CaptureCallback resultListener,
    546                                                  ImageReader.OnImageAvailableListener imageListener) throws Exception {
    547 
    548         Size captureSz = mOrderedStillSizes.get(0);
    549         Size previewSz = mOrderedPreviewSizes.get(1);
    550 
    551         if (VERBOSE) {
    552             Log.v(TAG, String.format("Prepare single capture (%s) and preview (%s)",
    553                     captureSz.toString(), previewSz.toString()));
    554         }
    555 
    556         // Update preview size.
    557         updatePreviewSurface(previewSz);
    558 
    559         // Create ImageReader.
    560         createImageReader(captureSz, ImageFormat.JPEG, MAX_READER_IMAGES, imageListener);
    561 
    562         // Configure output streams with preview and jpeg streams.
    563         List<Surface> outputSurfaces = new ArrayList<Surface>();
    564         outputSurfaces.add(mPreviewSurface);
    565         outputSurfaces.add(mReaderSurface);
    566         mSessionListener = new BlockingSessionCallback();
    567         mSession = configureCameraSession(mCamera, outputSurfaces, mSessionListener, mHandler);
    568 
    569         // Configure the requests.
    570         previewRequest.addTarget(mPreviewSurface);
    571         stillRequest.addTarget(mPreviewSurface);
    572         stillRequest.addTarget(mReaderSurface);
    573 
    574         // Start preview.
    575         mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
    576     }
    577 
    578 }
    579