13ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin/*
23ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin * Copyright (C) 2016 The Android Open Source Project
33ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin *
43ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin * Licensed under the Apache License, Version 2.0 (the "License");
53ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin * you may not use this file except in compliance with the License.
63ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin * You may obtain a copy of the License at
73ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin *
83ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin *      http://www.apache.org/licenses/LICENSE-2.0
93ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin *
103ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin * Unless required by applicable law or agreed to in writing, software
113ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin * distributed under the License is distributed on an "AS IS" BASIS,
123ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin * See the License for the specific language governing permissions and
143ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin * limitations under the License.
153ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin */
163ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
173ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinpackage com.android.mediaframeworktest.stress;
183ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
193ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport com.android.ex.camera2.blocking.BlockingSessionCallback;
203ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport com.android.ex.camera2.exceptions.TimeoutRuntimeException;
213ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport com.android.mediaframeworktest.Camera2SurfaceViewTestCase;
223ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport com.android.mediaframeworktest.helpers.Camera2Focuser;
233ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport com.android.mediaframeworktest.helpers.CameraTestUtils;
243ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport com.android.mediaframeworktest.helpers.CameraTestUtils.SimpleCaptureCallback;
253ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
263ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.graphics.ImageFormat;
273ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.graphics.Point;
283ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.hardware.camera2.CameraCharacteristics;
293ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.hardware.camera2.CameraCaptureSession.CaptureCallback;
303ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession;
313ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.hardware.camera2.CameraDevice;
323ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.hardware.camera2.CameraAccessException;
333ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.hardware.camera2.CameraCaptureSession;
343ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.hardware.camera2.CaptureRequest;
353ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.hardware.camera2.CaptureResult;
363ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.hardware.camera2.DngCreator;
373ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.hardware.camera2.params.MeteringRectangle;
383ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.media.Image;
393ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.media.ImageReader;
403ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.media.CamcorderProfile;
413ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.media.MediaExtractor;
423ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.media.MediaFormat;
433ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.media.MediaRecorder;
443ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.os.ConditionVariable;
453ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.os.Environment;
463ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.util.Log;
473ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.util.Pair;
483ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.util.Rational;
493ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.util.Size;
503ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.view.Surface;
513ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.hardware.camera2.params.StreamConfigurationMap;
523ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.test.suitebuilder.annotation.LargeTest;
533ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.util.Log;
543ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport android.util.Range;
553ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
563ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport java.io.ByteArrayOutputStream;
573ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport java.util.ArrayList;
583ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport java.util.List;
593ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport java.io.File;
603ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport java.util.Arrays;
613ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport java.util.HashMap;
623ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
633ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport static com.android.mediaframeworktest.helpers.CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS;
643ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport static com.android.mediaframeworktest.helpers.CameraTestUtils.MAX_READER_IMAGES;
653ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport static com.android.mediaframeworktest.helpers.CameraTestUtils.SimpleImageReaderListener;
663ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport static com.android.mediaframeworktest.helpers.CameraTestUtils.basicValidateJpegImage;
673ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport static com.android.mediaframeworktest.helpers.CameraTestUtils.configureCameraSession;
683ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport static com.android.mediaframeworktest.helpers.CameraTestUtils.dumpFile;
693ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport static com.android.mediaframeworktest.helpers.CameraTestUtils.getDataFromImage;
703ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport static com.android.mediaframeworktest.helpers.CameraTestUtils.getValueNotNull;
713ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport static com.android.mediaframeworktest.helpers.CameraTestUtils.makeImageReader;
723ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport static com.android.ex.camera2.blocking.BlockingSessionCallback.SESSION_CLOSED;
733ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport static com.android.mediaframeworktest.helpers.CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS;
743ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport static com.android.mediaframeworktest.helpers.CameraTestUtils.SESSION_CLOSE_TIMEOUT_MS;
753ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport static com.android.mediaframeworktest.helpers.CameraTestUtils.SIZE_BOUND_1080P;
763ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport static com.android.mediaframeworktest.helpers.CameraTestUtils.SIZE_BOUND_2160P;
773ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport static com.android.mediaframeworktest.helpers.CameraTestUtils.getSupportedVideoSizes;
783ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
793ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport com.android.ex.camera2.blocking.BlockingSessionCallback;
803ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport com.android.mediaframeworktest.Camera2SurfaceViewTestCase;
813ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport com.android.mediaframeworktest.helpers.CameraTestUtils;
823ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
833ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinimport junit.framework.AssertionFailedError;
843ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
853ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin/**
863ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin * <p>Tests Back/Front camera switching and Camera/Video modes witching.</p>
873ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin *
883ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin * adb shell am instrument \
893ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin *    -e class com.android.mediaframeworktest.stress.Camera2SwitchPreviewTest \
903ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin *    -e iterations 200 \
913ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin *    -e waitIntervalMs 1000 \
923ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin *    -e resultToFile false \
933ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin *    -r -w com.android.mediaframeworktest/.Camera2InstrumentationTestRunner
943ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin */
953ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yinpublic class Camera2SwitchPreviewTest extends Camera2SurfaceViewTestCase {
963ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private static final String TAG = "SwitchPreviewTest";
973ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
983ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
993ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    // 60 second to accommodate the possible long exposure time.
1003ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private static final int MAX_REGIONS_AE_INDEX = 0;
1013ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private static final int MAX_REGIONS_AWB_INDEX = 1;
1023ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private static final int MAX_REGIONS_AF_INDEX = 2;
1033ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private static final int WAIT_FOR_FOCUS_DONE_TIMEOUT_MS = 6000;
1043ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private static final double AE_COMPENSATION_ERROR_TOLERANCE = 0.2;
1053ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    // 5 percent error margin for resulting metering regions
1063ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private static final float METERING_REGION_ERROR_PERCENT_DELTA = 0.05f;
1073ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private final String VIDEO_FILE_PATH = Environment.getExternalStorageDirectory().getPath();
1083ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
1093ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private static final boolean DEBUG_DUMP = Log.isLoggable(TAG, Log.DEBUG);
1103ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private static final int RECORDING_DURATION_MS = 3000;
1113ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private static final float DURATION_MARGIN = 0.2f;
1123ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private static final double FRAME_DURATION_ERROR_TOLERANCE_MS = 3.0;
1133ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private static final int BIT_RATE_1080P = 16000000;
1143ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private static final int BIT_RATE_MIN = 64000;
1153ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private static final int BIT_RATE_MAX = 40000000;
1163ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private static final int VIDEO_FRAME_RATE = 30;
1173ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private static final int[] mCamcorderProfileList = {
1183ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            CamcorderProfile.QUALITY_HIGH,
1193ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            CamcorderProfile.QUALITY_2160P,
1203ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            CamcorderProfile.QUALITY_1080P,
1213ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            CamcorderProfile.QUALITY_720P,
1223ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            CamcorderProfile.QUALITY_480P,
1233ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            CamcorderProfile.QUALITY_CIF,
1243ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            CamcorderProfile.QUALITY_QCIF,
1253ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            CamcorderProfile.QUALITY_QVGA,
1263ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            CamcorderProfile.QUALITY_LOW,
1273ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    };
1283ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private static final int MAX_VIDEO_SNAPSHOT_IMAGES = 5;
1293ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private static final int BURST_VIDEO_SNAPSHOT_NUM = 3;
1303ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private static final int SLOWMO_SLOW_FACTOR = 4;
1313ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private static final int MAX_NUM_FRAME_DROP_INTERVAL_ALLOWED = 4;
1323ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private List<Size> mSupportedVideoSizes;
1333ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private Surface mRecordingSurface;
1343ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private Surface mPersistentSurface;
1353ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private MediaRecorder mMediaRecorder;
1363ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private String mOutMediaFileName;
1373ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private int mVideoFrameRate;
1383ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private Size mVideoSize;
1393ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private long mRecordingStartTime;
1403ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
1413ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    @Override
1423ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    protected void setUp() throws Exception {
1433ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        super.setUp();
1443ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    }
1453ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
1463ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    @Override
1473ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    protected void tearDown() throws Exception {
1483ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        super.tearDown();
1493ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    }
1503ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
1513ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    /**
1523ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * Test normal still preview switch.
1533ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * <p>
1543ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * Preview jpeg output streams are configured. Max still capture
1553ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * size is used for jpeg capture.
1563ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * </p>
1573ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     */
1583ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    public void testPreviewSwitchBackFrontCamera() throws Exception {
1593ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        List<String> mCameraColorOutputIds = cameraColorOutputCheck();
1603ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        // Test iteration starts...
1613ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        Log.i(TAG, "Testing preview switch back/front camera in still capture mode");
1623ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        for (int iteration = 0; iteration < getIterationCount(); ++iteration) {
1633ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            for (String id : mCameraColorOutputIds) {
1643ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                try {
1653ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    openDevice(id);
1663ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    // Preview for basic still capture:
1673ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    Log.v(TAG, String.format("Preview pictures: %d/%d", iteration + 1,
1683ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                            getIterationCount()));
1693ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    stillCapturePreviewPreparer(id);
1703ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    getResultPrinter().printStatus(getIterationCount(), iteration + 1, id);
1713ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                } finally {
1723ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    closeDevice();
1733ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    closeImageReader();
1743ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                }
1753ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            }
1763ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        }
1773ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    }
1783ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
1793ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    /**
1803ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * <p>
1813ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * Test basic video preview switch.
1823ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * </p>
1833ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * <p>
1843ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * This test covers the typical basic use case of video preview switch.
1853ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * MediaRecorder is used to record the audio and video, CamcorderProfile is
1863ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * used to configure the MediaRecorder. Preview is set to the video size.
1873ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * </p>
1883ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     */
1893ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    public void testPreviewSwitchBackFrontVideo() throws Exception {
1903ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        List<String> mCameraColorOutputIds = cameraColorOutputCheck();
1913ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        // Test iteration starts...
1923ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        Log.i(TAG, "Testing preview switch back/front camera in video mode");
1933ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        for (int iteration = 0; iteration < getIterationCount(); ++iteration) {
1943ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            for (String id : mCameraColorOutputIds) {
1953ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                try {
1963ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    openDevice(id);
1973ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    // Preview for basic video recording:
1983ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    Log.v(TAG, String.format("Preview for recording videos: %d/%d", iteration + 1,
1993ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                            getIterationCount()));
2003ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    recordingPreviewPreparer(id);
2013ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    getResultPrinter().printStatus(getIterationCount(), iteration + 1, id);
2023ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                } finally {
2033ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    closeDevice();
2043ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    releaseRecorder();
2053ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                }
2063ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            }
2073ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        }
2083ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    }
2093ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
2103ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
2113ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    /**
2123ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * Test back camera preview switch between still capture and recording mode.
2133ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * <p>
2143ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * This test covers the basic case of preview switch camera mode, between
2153ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * still capture (photo) and recording (video) mode. The preview settings
2163ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * are same with the settings in "testPreviewSwitchBackFrontCamera" and
2173ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * "testPreviewSwitchBackFrontVideo"
2183ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * </p>
2193ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     */
2203ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    public void testPreviewSwitchBackCameraVideo() throws Exception {
2213ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        String id = mCameraIds[0];
2223ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        openDevice(id);
2233ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        if (!mStaticInfo.isColorOutputSupported()) {
2243ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            Log.i(TAG, "Camera " + id +
2253ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    " does not support color outputs, skipping");
2263ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            return;
2273ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        }
2283ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        closeDevice();
2293ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        // Test iteration starts...
2303ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        Log.i(TAG, "Testing preview switch between still capture/video modes for back camera");
2313ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        for (int iteration = 0; iteration < getIterationCount(); ++iteration) {
2323ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            try {
2333ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                openDevice(id);
2343ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
2353ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                // Preview for basic still capture:
2363ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                Log.v(TAG, String.format("Preview pictures: %d/%d", iteration + 1,
2373ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                        getIterationCount()));
2383ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                stillCapturePreviewPreparer(id);
2393ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                getResultPrinter().printStatus(getIterationCount(), iteration + 1, id);
2403ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
2413ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                // Preview for basic video recording:
2423ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                Log.v(TAG, String.format("Preview for recording videos: %d/%d", iteration + 1,
2433ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                        getIterationCount()));
2443ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                recordingPreviewPreparer(id);
2453ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                getResultPrinter().printStatus(getIterationCount(), iteration + 1, id);
2463ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            } finally {
2473ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                closeDevice();
2483ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                closeImageReader();
2493ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            }
2503ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        }
2513ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    }
2523ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
2533ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    /**
2543ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * Test front camera preview switch between still capture and recording mode.
2553ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * <p>
2563ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * This test covers the basic case of preview switch camera mode, between
2573ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * still capture (photo) and recording (video) mode. The preview settings
2583ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * are same with the settings in "testPreviewSwitchBackFrontCamera" and
2593ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * "testPreviewSwitchBackFrontVideo"
2603ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * </p>
2613ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     */
2623ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    public void testPreviewSwitchFrontCameraVideo() throws Exception{
2633ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        String id = mCameraIds[1];
2643ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        openDevice(id);
2653ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        if (!mStaticInfo.isColorOutputSupported()) {
2663ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            Log.i(TAG, "Camera " + id +
2673ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    " does not support color outputs, skipping");
2683ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            return;
2693ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        }
2703ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        closeDevice();
2713ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        // Test iteration starts...
2723ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        Log.i(TAG, "Testing preview switch between still capture/video modes for front camera");
2733ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        for (int iteration = 0; iteration < getIterationCount(); ++iteration) {
2743ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            try {
2753ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                openDevice(id);
2763ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
2773ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                // Preview for basic still capture:
2783ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                Log.v(TAG, String.format("Preview pictures: %d/%d", iteration + 1,
2793ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                        getIterationCount()));
2803ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                stillCapturePreviewPreparer(id);
2813ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                getResultPrinter().printStatus(getIterationCount(), iteration + 1, id);
2823ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
2833ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                // Preview for basic video recording:
2843ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                Log.v(TAG, String.format("Preview for recording videos: %d/%d", iteration + 1,
2853ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                        getIterationCount()));
2863ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                recordingPreviewPreparer(id);
2873ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                getResultPrinter().printStatus(getIterationCount(), iteration + 1, id);
2883ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            } finally {
2893ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                closeDevice();
2903ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                closeImageReader();
2913ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            }
2923ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        }
2933ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    }
2943ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
2953ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private void stillCapturePreviewPreparer(String id) throws Exception{
2963ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        CaptureResult result;
2973ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
2983ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
2993ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        CaptureRequest.Builder previewRequest =
3003ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
3013ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        CaptureRequest.Builder stillRequest =
3023ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
3033ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        // Preview Setup:
3043ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        prepareCapturePreview(previewRequest, stillRequest, resultListener, imageListener);
3053ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
3063ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        Thread.sleep(getTestWaitIntervalMs());
3073ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    }
3083ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
3093ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private void recordingPreviewPreparer(String id) throws Exception{
3103ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        // Re-use the MediaRecorder object for the same camera device.
3113ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        mMediaRecorder = new MediaRecorder();
3123ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        initSupportedVideoSize(id);
3133ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        // preview Setup:
3143ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        basicRecordingPreviewTestByCamera(mCamcorderProfileList);
3153ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
3163ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        Thread.sleep(getTestWaitIntervalMs());
3173ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    }
3183ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
3193ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
3203ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    /**
3213ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * Initialize the supported video sizes.
3223ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     */
3233ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private void initSupportedVideoSize(String cameraId)  throws Exception {
3243ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        Size maxVideoSize = SIZE_BOUND_1080P;
3253ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_2160P)) {
3263ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            maxVideoSize = SIZE_BOUND_2160P;
3273ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        }
3283ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        mSupportedVideoSizes =
3293ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                getSupportedVideoSizes(cameraId, mCameraManager, maxVideoSize);
3303ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    }
3313ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
3323ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
3333ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    /**
3343ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * Test camera recording preview by using each available CamcorderProfile for a
3353ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * given camera. preview size is set to the video size.
3363ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     */
3373ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private void basicRecordingPreviewTestByCamera(int[] camcorderProfileList)
3383ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            throws Exception {
3393ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        Size maxPreviewSize = mOrderedPreviewSizes.get(0);
3403ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        List<Range<Integer> > fpsRanges = Arrays.asList(
3413ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                mStaticInfo.getAeAvailableTargetFpsRangesChecked());
3423ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        int cameraId = Integer.parseInt(mCamera.getId());
3433ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        int maxVideoFrameRate = -1;
3443ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        int profileId = camcorderProfileList[0];
3453ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        if (!CamcorderProfile.hasProfile(cameraId, profileId) ||
3463ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                allowedUnsupported(cameraId, profileId)) {
3473ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            return;
3483ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        }
3493ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
3503ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        CamcorderProfile profile = CamcorderProfile.get(cameraId, profileId);
3513ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        Size videoSz = new Size(profile.videoFrameWidth, profile.videoFrameHeight);
3523ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        Range<Integer> fpsRange = new Range(profile.videoFrameRate, profile.videoFrameRate);
3533ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        if (maxVideoFrameRate < profile.videoFrameRate) {
3543ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                maxVideoFrameRate = profile.videoFrameRate;
3553ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        }
3563ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        if (mStaticInfo.isHardwareLevelLegacy() &&
3573ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                (videoSz.getWidth() > maxPreviewSize.getWidth() ||
3583ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                        videoSz.getHeight() > maxPreviewSize.getHeight())) {
3593ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            // Skip. Legacy mode can only do recording up to max preview size
3603ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            return;
3613ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        }
3623ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        assertTrue("Video size " + videoSz.toString() + " for profile ID " + profileId +
3633ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                            " must be one of the camera device supported video size!",
3643ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    mSupportedVideoSizes.contains(videoSz));
3653ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        assertTrue("Frame rate range " + fpsRange + " (for profile ID " + profileId +
3663ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                            ") must be one of the camera device available FPS range!",
3673ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                fpsRanges.contains(fpsRange));
3683ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
3693ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        if (VERBOSE) {
3703ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            Log.v(TAG, "Testing camera recording with video size " + videoSz.toString());
3713ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        }
3723ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
3733ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        // Configure preview and recording surfaces.
3743ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        mOutMediaFileName = VIDEO_FILE_PATH + "/test_video.mp4";
3753ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        if (DEBUG_DUMP) {
3763ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            mOutMediaFileName = VIDEO_FILE_PATH + "/test_video_" + cameraId + "_"
3773ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    + videoSz.toString() + ".mp4";
3783ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        }
3793ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
3803ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        prepareRecordingWithProfile(profile);
3813ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
3823ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        // prepare preview surface by using video size.
3833ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        updatePreviewSurfaceWithVideo(videoSz, profile.videoFrameRate);
3843ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
3853ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        CaptureRequest.Builder previewRequest =
3863ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
3873ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        CaptureRequest.Builder recordingRequest =
3883ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                mCamera.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
3893ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
3903ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
3913ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
3923ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
3933ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        prepareVideoPreview(previewRequest, recordingRequest, resultListener, imageListener);
3943ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
3953ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        // Can reuse the MediaRecorder object after reset.
3963ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        mMediaRecorder.reset();
3973ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
3983ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        if (maxVideoFrameRate != -1) {
3993ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            // At least one CamcorderProfile is present, check FPS
4003ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            assertTrue("At least one CamcorderProfile must support >= 24 FPS",
4013ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    maxVideoFrameRate >= 24);
4023ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        }
4033ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    }
4043ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
4053ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private void releaseRecorder() {
4063ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        if (mMediaRecorder != null) {
4073ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            mMediaRecorder.release();
4083ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            mMediaRecorder = null;
4093ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        }
4103ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    }
4113ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
4123ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private List<String> cameraColorOutputCheck() throws Exception {
4133ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        List<String> mCameraColorOutputIds = new ArrayList<String>();
4143ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        for (String id : mCameraIds) {
4153ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            openDevice(id);
4163ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            if (!mStaticInfo.isColorOutputSupported()) {
4173ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                Log.i(TAG, "Camera " + id +
4183ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                        " does not support color outputs, skipping");
4193ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                continue;
4203ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            }
4213ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            mCameraColorOutputIds.add(id);
4223ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            closeDevice();
4233ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        }
4243ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        return mCameraColorOutputIds;
4253ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    }
4263ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
4273ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    /**
4283ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * Returns {@code true} if the {@link CamcorderProfile} ID is allowed to be unsupported.
4293ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     *
4303ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * <p>This only allows unsupported profiles when using the LEGACY mode of the Camera API.</p>
4313ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     *
4323ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * @param profileId a {@link CamcorderProfile} ID to check.
4333ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * @return {@code true} if supported.
4343ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     */
4353ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private boolean allowedUnsupported(int cameraId, int profileId) {
4363ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        if (!mStaticInfo.isHardwareLevelLegacy()) {
4373ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            return false;
4383ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        }
4393ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
4403ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        switch(profileId) {
4413ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            case CamcorderProfile.QUALITY_2160P:
4423ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            case CamcorderProfile.QUALITY_1080P:
4433ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            case CamcorderProfile.QUALITY_HIGH:
4443ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                return !CamcorderProfile.hasProfile(cameraId, profileId) ||
4453ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                        CamcorderProfile.get(cameraId, profileId).videoFrameWidth >= 1080;
4463ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        }
4473ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        return false;
4483ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    }
4493ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
4503ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    /**
4513ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * Configure MediaRecorder recording session with CamcorderProfile, prepare
4523ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * the recording surface.
4533ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     */
4543ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private void prepareRecordingWithProfile(CamcorderProfile profile)
4553ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            throws Exception {
4563ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        // Prepare MediaRecorder.
4573ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
4583ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
4593ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        mMediaRecorder.setProfile(profile);
4603ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        mMediaRecorder.setOutputFile(mOutMediaFileName);
4613ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        if (mPersistentSurface != null) {
4623ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            mMediaRecorder.setInputSurface(mPersistentSurface);
4633ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            mRecordingSurface = mPersistentSurface;
4643ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        }
4653ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        mMediaRecorder.prepare();
4663ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        if (mPersistentSurface == null) {
4673ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            mRecordingSurface = mMediaRecorder.getSurface();
4683ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        }
4693ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        assertNotNull("Recording surface must be non-null!", mRecordingSurface);
4703ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        mVideoFrameRate = profile.videoFrameRate;
4713ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        mVideoSize = new Size(profile.videoFrameWidth, profile.videoFrameHeight);
4723ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    }
4733ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
4743ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    /**
4753ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * Update preview size with video size.
4763ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     *
4773ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * <p>Preview size will be capped with max preview size.</p>
4783ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     *
4793ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * @param videoSize The video size used for preview.
4803ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     * @param videoFrameRate The video frame rate
4813ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     *
4823ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin     */
4833ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    private void updatePreviewSurfaceWithVideo(Size videoSize, int videoFrameRate)  throws Exception {
4843ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        if (mOrderedPreviewSizes == null) {
4853ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            throw new IllegalStateException("supported preview size list is not initialized yet");
4863ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        }
4873ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        final float FRAME_DURATION_TOLERANCE = 0.01f;
4883ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        long videoFrameDuration = (long) (1e9 / videoFrameRate *
4893ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                (1.0 + FRAME_DURATION_TOLERANCE));
4903ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        HashMap<Size, Long> minFrameDurationMap = mStaticInfo.
4913ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                getAvailableMinFrameDurationsForFormatChecked(ImageFormat.PRIVATE);
4923ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        Size maxPreviewSize = mOrderedPreviewSizes.get(0);
4933ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        Size previewSize = null;
4943ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        if (videoSize.getWidth() > maxPreviewSize.getWidth() ||
4953ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                videoSize.getHeight() > maxPreviewSize.getHeight()) {
4963ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            for (Size s : mOrderedPreviewSizes) {
4973ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                Long frameDuration = minFrameDurationMap.get(s);
4983ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                if (mStaticInfo.isHardwareLevelLegacy()) {
4993ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    // Legacy doesn't report min frame duration
5003ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    frameDuration = new Long(0);
5013ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                }
5023ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                assertTrue("Cannot find minimum frame duration for private size" + s,
5033ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                        frameDuration != null);
5043ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                if (frameDuration <= videoFrameDuration &&
5053ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                        s.getWidth() <= videoSize.getWidth() &&
5063ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                        s.getHeight() <= videoSize.getHeight()) {
5073ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    Log.w(TAG, "Overwrite preview size from " + videoSize.toString() +
5083ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                            " to " + s.toString());
5093ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    previewSize = s;
5103ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    break;
5113ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    // If all preview size doesn't work then we fallback to video size
5123ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                }
5133ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            }
5143ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        }
5153ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        if (previewSize == null) {
5163ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            previewSize = videoSize;
5173ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        }
5183ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
5193ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        updatePreviewSurface(previewSize);
5203ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    }
5213ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
5223ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    protected void prepareVideoPreview(CaptureRequest.Builder previewRequest,
5233ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                                                 CaptureRequest.Builder recordingRequest,
5243ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                                                 CaptureCallback resultListener,
5253ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                                                 ImageReader.OnImageAvailableListener imageListener) throws Exception {
5263ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
5273ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        // Configure output streams with preview and jpeg streams.
5283ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        List<Surface> outputSurfaces = new ArrayList<Surface>();
5293ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        outputSurfaces.add(mPreviewSurface);
5303ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        outputSurfaces.add(mRecordingSurface);
5313ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
5323ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        mSessionListener = new BlockingSessionCallback();
5333ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        mSession = configureCameraSession(mCamera, outputSurfaces, mSessionListener, mHandler);
5343ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
5353ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        previewRequest.addTarget(mPreviewSurface);
5363ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        recordingRequest.addTarget(mPreviewSurface);
5373ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        recordingRequest.addTarget(mRecordingSurface);
5383ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
5393ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        // Start preview.
5403ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        mSession.setRepeatingRequest(previewRequest.build(), null, mHandler);
5413ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    }
5423ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
5433ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    protected void prepareCapturePreview(CaptureRequest.Builder previewRequest,
5443ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                                                 CaptureRequest.Builder stillRequest,
5453ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                                                 CaptureCallback resultListener,
5463ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                                                 ImageReader.OnImageAvailableListener imageListener) throws Exception {
5473ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
5483ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        Size captureSz = mOrderedStillSizes.get(0);
5493ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        Size previewSz = mOrderedPreviewSizes.get(1);
5503ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
5513ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        if (VERBOSE) {
5523ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin            Log.v(TAG, String.format("Prepare single capture (%s) and preview (%s)",
5533ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin                    captureSz.toString(), previewSz.toString()));
5543ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        }
5553ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
5563ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        // Update preview size.
5573ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        updatePreviewSurface(previewSz);
5583ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
5593ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        // Create ImageReader.
5603ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        createImageReader(captureSz, ImageFormat.JPEG, MAX_READER_IMAGES, imageListener);
5613ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
5623ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        // Configure output streams with preview and jpeg streams.
5633ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        List<Surface> outputSurfaces = new ArrayList<Surface>();
5643ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        outputSurfaces.add(mPreviewSurface);
5653ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        outputSurfaces.add(mReaderSurface);
5663ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        mSessionListener = new BlockingSessionCallback();
5673ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        mSession = configureCameraSession(mCamera, outputSurfaces, mSessionListener, mHandler);
5683ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
5693ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        // Configure the requests.
5703ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        previewRequest.addTarget(mPreviewSurface);
5713ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        stillRequest.addTarget(mPreviewSurface);
5723ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        stillRequest.addTarget(mReaderSurface);
5733ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
5743ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        // Start preview.
5753ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin        mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
5763ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin    }
5773ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin
5783ed27cc2b27a336590be6bd95e0ee4a75b25be70Hang Yin}
579