| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.mediaframeworktest.stress; |
| |
| import com.android.ex.camera2.blocking.BlockingSessionCallback; |
| import com.android.ex.camera2.exceptions.TimeoutRuntimeException; |
| import com.android.mediaframeworktest.Camera2SurfaceViewTestCase; |
| import com.android.mediaframeworktest.helpers.Camera2Focuser; |
| import com.android.mediaframeworktest.helpers.CameraTestUtils; |
| import com.android.mediaframeworktest.helpers.CameraTestUtils.SimpleCaptureCallback; |
| |
| import android.graphics.ImageFormat; |
| import android.graphics.Point; |
| import android.hardware.camera2.CameraCharacteristics; |
| import android.hardware.camera2.CameraCaptureSession.CaptureCallback; |
| import android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession; |
| import android.hardware.camera2.CameraDevice; |
| import android.hardware.camera2.CameraAccessException; |
| import android.hardware.camera2.CameraCaptureSession; |
| import android.hardware.camera2.CaptureRequest; |
| import android.hardware.camera2.CaptureResult; |
| import android.hardware.camera2.DngCreator; |
| import android.hardware.camera2.params.MeteringRectangle; |
| import android.media.Image; |
| import android.media.ImageReader; |
| import android.media.CamcorderProfile; |
| import android.media.MediaExtractor; |
| import android.media.MediaFormat; |
| import android.media.MediaRecorder; |
| import android.os.ConditionVariable; |
| import android.os.Environment; |
| import android.util.Log; |
| import android.util.Pair; |
| import android.util.Rational; |
| import android.util.Size; |
| import android.view.Surface; |
| import android.hardware.camera2.params.StreamConfigurationMap; |
| import android.test.suitebuilder.annotation.LargeTest; |
| import android.util.Log; |
| import android.util.Range; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.io.File; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| |
| import static com.android.mediaframeworktest.helpers.CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS; |
| import static com.android.mediaframeworktest.helpers.CameraTestUtils.MAX_READER_IMAGES; |
| import static com.android.mediaframeworktest.helpers.CameraTestUtils.SimpleImageReaderListener; |
| import static com.android.mediaframeworktest.helpers.CameraTestUtils.basicValidateJpegImage; |
| import static com.android.mediaframeworktest.helpers.CameraTestUtils.configureCameraSession; |
| import static com.android.mediaframeworktest.helpers.CameraTestUtils.dumpFile; |
| import static com.android.mediaframeworktest.helpers.CameraTestUtils.getDataFromImage; |
| import static com.android.mediaframeworktest.helpers.CameraTestUtils.getValueNotNull; |
| import static com.android.mediaframeworktest.helpers.CameraTestUtils.makeImageReader; |
| import static com.android.ex.camera2.blocking.BlockingSessionCallback.SESSION_CLOSED; |
| import static com.android.mediaframeworktest.helpers.CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS; |
| import static com.android.mediaframeworktest.helpers.CameraTestUtils.SESSION_CLOSE_TIMEOUT_MS; |
| import static com.android.mediaframeworktest.helpers.CameraTestUtils.SIZE_BOUND_1080P; |
| import static com.android.mediaframeworktest.helpers.CameraTestUtils.SIZE_BOUND_2160P; |
| import static com.android.mediaframeworktest.helpers.CameraTestUtils.getSupportedVideoSizes; |
| |
| import com.android.ex.camera2.blocking.BlockingSessionCallback; |
| import com.android.mediaframeworktest.Camera2SurfaceViewTestCase; |
| import com.android.mediaframeworktest.helpers.CameraTestUtils; |
| |
| import junit.framework.AssertionFailedError; |
| |
| /** |
| * <p>Tests Back/Front camera switching and Camera/Video modes witching.</p> |
| * |
| * adb shell am instrument \ |
| * -e class com.android.mediaframeworktest.stress.Camera2SwitchPreviewTest \ |
| * -e iterations 200 \ |
| * -e waitIntervalMs 1000 \ |
| * -e resultToFile false \ |
| * -r -w com.android.mediaframeworktest/.Camera2InstrumentationTestRunner |
| */ |
| public class Camera2SwitchPreviewTest extends Camera2SurfaceViewTestCase { |
| private static final String TAG = "SwitchPreviewTest"; |
| private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); |
| private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); |
| // 60 second to accommodate the possible long exposure time. |
| private static final int MAX_REGIONS_AE_INDEX = 0; |
| private static final int MAX_REGIONS_AWB_INDEX = 1; |
| private static final int MAX_REGIONS_AF_INDEX = 2; |
| private static final int WAIT_FOR_FOCUS_DONE_TIMEOUT_MS = 6000; |
| private static final double AE_COMPENSATION_ERROR_TOLERANCE = 0.2; |
| // 5 percent error margin for resulting metering regions |
| private static final float METERING_REGION_ERROR_PERCENT_DELTA = 0.05f; |
| private final String VIDEO_FILE_PATH = Environment.getExternalStorageDirectory().getPath(); |
| |
| private static final boolean DEBUG_DUMP = Log.isLoggable(TAG, Log.DEBUG); |
| private static final int RECORDING_DURATION_MS = 3000; |
| private static final float DURATION_MARGIN = 0.2f; |
| private static final double FRAME_DURATION_ERROR_TOLERANCE_MS = 3.0; |
| private static final int BIT_RATE_1080P = 16000000; |
| private static final int BIT_RATE_MIN = 64000; |
| private static final int BIT_RATE_MAX = 40000000; |
| private static final int VIDEO_FRAME_RATE = 30; |
| private static final int[] mCamcorderProfileList = { |
| CamcorderProfile.QUALITY_HIGH, |
| CamcorderProfile.QUALITY_2160P, |
| CamcorderProfile.QUALITY_1080P, |
| CamcorderProfile.QUALITY_720P, |
| CamcorderProfile.QUALITY_480P, |
| CamcorderProfile.QUALITY_CIF, |
| CamcorderProfile.QUALITY_QCIF, |
| CamcorderProfile.QUALITY_QVGA, |
| CamcorderProfile.QUALITY_LOW, |
| }; |
| private static final int MAX_VIDEO_SNAPSHOT_IMAGES = 5; |
| private static final int BURST_VIDEO_SNAPSHOT_NUM = 3; |
| private static final int SLOWMO_SLOW_FACTOR = 4; |
| private static final int MAX_NUM_FRAME_DROP_INTERVAL_ALLOWED = 4; |
| private List<Size> mSupportedVideoSizes; |
| private Surface mRecordingSurface; |
| private Surface mPersistentSurface; |
| private MediaRecorder mMediaRecorder; |
| private String mOutMediaFileName; |
| private int mVideoFrameRate; |
| private Size mVideoSize; |
| private long mRecordingStartTime; |
| |
| @Override |
| protected void setUp() throws Exception { |
| super.setUp(); |
| } |
| |
| @Override |
| protected void tearDown() throws Exception { |
| super.tearDown(); |
| } |
| |
| /** |
| * Test normal still preview switch. |
| * <p> |
| * Preview jpeg output streams are configured. Max still capture |
| * size is used for jpeg capture. |
| * </p> |
| */ |
| public void testPreviewSwitchBackFrontCamera() throws Exception { |
| List<String> mCameraColorOutputIds = cameraColorOutputCheck(); |
| // Test iteration starts... |
| Log.i(TAG, "Testing preview switch back/front camera in still capture mode"); |
| for (int iteration = 0; iteration < getIterationCount(); ++iteration) { |
| for (String id : mCameraColorOutputIds) { |
| try { |
| openDevice(id); |
| // Preview for basic still capture: |
| Log.v(TAG, String.format("Preview pictures: %d/%d", iteration + 1, |
| getIterationCount())); |
| stillCapturePreviewPreparer(id); |
| getResultPrinter().printStatus(getIterationCount(), iteration + 1, id); |
| } finally { |
| closeDevice(); |
| closeImageReader(); |
| } |
| } |
| } |
| } |
| |
| /** |
| * <p> |
| * Test basic video preview switch. |
| * </p> |
| * <p> |
| * This test covers the typical basic use case of video preview switch. |
| * MediaRecorder is used to record the audio and video, CamcorderProfile is |
| * used to configure the MediaRecorder. Preview is set to the video size. |
| * </p> |
| */ |
| public void testPreviewSwitchBackFrontVideo() throws Exception { |
| List<String> mCameraColorOutputIds = cameraColorOutputCheck(); |
| // Test iteration starts... |
| Log.i(TAG, "Testing preview switch back/front camera in video mode"); |
| for (int iteration = 0; iteration < getIterationCount(); ++iteration) { |
| for (String id : mCameraColorOutputIds) { |
| try { |
| openDevice(id); |
| // Preview for basic video recording: |
| Log.v(TAG, String.format("Preview for recording videos: %d/%d", iteration + 1, |
| getIterationCount())); |
| recordingPreviewPreparer(id); |
| getResultPrinter().printStatus(getIterationCount(), iteration + 1, id); |
| } finally { |
| closeDevice(); |
| releaseRecorder(); |
| } |
| } |
| } |
| } |
| |
| |
| /** |
| * Test back camera preview switch between still capture and recording mode. |
| * <p> |
| * This test covers the basic case of preview switch camera mode, between |
| * still capture (photo) and recording (video) mode. The preview settings |
| * are same with the settings in "testPreviewSwitchBackFrontCamera" and |
| * "testPreviewSwitchBackFrontVideo" |
| * </p> |
| */ |
| public void testPreviewSwitchBackCameraVideo() throws Exception { |
| String id = mCameraIds[0]; |
| openDevice(id); |
| if (!mStaticInfo.isColorOutputSupported()) { |
| Log.i(TAG, "Camera " + id + |
| " does not support color outputs, skipping"); |
| return; |
| } |
| closeDevice(); |
| // Test iteration starts... |
| Log.i(TAG, "Testing preview switch between still capture/video modes for back camera"); |
| for (int iteration = 0; iteration < getIterationCount(); ++iteration) { |
| try { |
| openDevice(id); |
| |
| // Preview for basic still capture: |
| Log.v(TAG, String.format("Preview pictures: %d/%d", iteration + 1, |
| getIterationCount())); |
| stillCapturePreviewPreparer(id); |
| getResultPrinter().printStatus(getIterationCount(), iteration + 1, id); |
| |
| // Preview for basic video recording: |
| Log.v(TAG, String.format("Preview for recording videos: %d/%d", iteration + 1, |
| getIterationCount())); |
| recordingPreviewPreparer(id); |
| getResultPrinter().printStatus(getIterationCount(), iteration + 1, id); |
| } finally { |
| closeDevice(); |
| closeImageReader(); |
| } |
| } |
| } |
| |
| /** |
| * Test front camera preview switch between still capture and recording mode. |
| * <p> |
| * This test covers the basic case of preview switch camera mode, between |
| * still capture (photo) and recording (video) mode. The preview settings |
| * are same with the settings in "testPreviewSwitchBackFrontCamera" and |
| * "testPreviewSwitchBackFrontVideo" |
| * </p> |
| */ |
| public void testPreviewSwitchFrontCameraVideo() throws Exception{ |
| String id = mCameraIds[1]; |
| openDevice(id); |
| if (!mStaticInfo.isColorOutputSupported()) { |
| Log.i(TAG, "Camera " + id + |
| " does not support color outputs, skipping"); |
| return; |
| } |
| closeDevice(); |
| // Test iteration starts... |
| Log.i(TAG, "Testing preview switch between still capture/video modes for front camera"); |
| for (int iteration = 0; iteration < getIterationCount(); ++iteration) { |
| try { |
| openDevice(id); |
| |
| // Preview for basic still capture: |
| Log.v(TAG, String.format("Preview pictures: %d/%d", iteration + 1, |
| getIterationCount())); |
| stillCapturePreviewPreparer(id); |
| getResultPrinter().printStatus(getIterationCount(), iteration + 1, id); |
| |
| // Preview for basic video recording: |
| Log.v(TAG, String.format("Preview for recording videos: %d/%d", iteration + 1, |
| getIterationCount())); |
| recordingPreviewPreparer(id); |
| getResultPrinter().printStatus(getIterationCount(), iteration + 1, id); |
| } finally { |
| closeDevice(); |
| closeImageReader(); |
| } |
| } |
| } |
| |
| private void stillCapturePreviewPreparer(String id) throws Exception{ |
| CaptureResult result; |
| SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); |
| SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); |
| CaptureRequest.Builder previewRequest = |
| mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); |
| CaptureRequest.Builder stillRequest = |
| mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); |
| // Preview Setup: |
| prepareCapturePreview(previewRequest, stillRequest, resultListener, imageListener); |
| |
| Thread.sleep(getTestWaitIntervalMs()); |
| } |
| |
| private void recordingPreviewPreparer(String id) throws Exception{ |
| // Re-use the MediaRecorder object for the same camera device. |
| mMediaRecorder = new MediaRecorder(); |
| initSupportedVideoSize(id); |
| // preview Setup: |
| basicRecordingPreviewTestByCamera(mCamcorderProfileList); |
| |
| Thread.sleep(getTestWaitIntervalMs()); |
| } |
| |
| |
| /** |
| * Initialize the supported video sizes. |
| */ |
| private void initSupportedVideoSize(String cameraId) throws Exception { |
| Size maxVideoSize = SIZE_BOUND_1080P; |
| if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_2160P)) { |
| maxVideoSize = SIZE_BOUND_2160P; |
| } |
| mSupportedVideoSizes = |
| getSupportedVideoSizes(cameraId, mCameraManager, maxVideoSize); |
| } |
| |
| |
| /** |
| * Test camera recording preview by using each available CamcorderProfile for a |
| * given camera. preview size is set to the video size. |
| */ |
| private void basicRecordingPreviewTestByCamera(int[] camcorderProfileList) |
| throws Exception { |
| Size maxPreviewSize = mOrderedPreviewSizes.get(0); |
| List<Range<Integer> > fpsRanges = Arrays.asList( |
| mStaticInfo.getAeAvailableTargetFpsRangesChecked()); |
| int cameraId = Integer.parseInt(mCamera.getId()); |
| int maxVideoFrameRate = -1; |
| int profileId = camcorderProfileList[0]; |
| if (!CamcorderProfile.hasProfile(cameraId, profileId) || |
| allowedUnsupported(cameraId, profileId)) { |
| return; |
| } |
| |
| CamcorderProfile profile = CamcorderProfile.get(cameraId, profileId); |
| Size videoSz = new Size(profile.videoFrameWidth, profile.videoFrameHeight); |
| Range<Integer> fpsRange = new Range(profile.videoFrameRate, profile.videoFrameRate); |
| if (maxVideoFrameRate < profile.videoFrameRate) { |
| maxVideoFrameRate = profile.videoFrameRate; |
| } |
| if (mStaticInfo.isHardwareLevelLegacy() && |
| (videoSz.getWidth() > maxPreviewSize.getWidth() || |
| videoSz.getHeight() > maxPreviewSize.getHeight())) { |
| // Skip. Legacy mode can only do recording up to max preview size |
| return; |
| } |
| assertTrue("Video size " + videoSz.toString() + " for profile ID " + profileId + |
| " must be one of the camera device supported video size!", |
| mSupportedVideoSizes.contains(videoSz)); |
| assertTrue("Frame rate range " + fpsRange + " (for profile ID " + profileId + |
| ") must be one of the camera device available FPS range!", |
| fpsRanges.contains(fpsRange)); |
| |
| if (VERBOSE) { |
| Log.v(TAG, "Testing camera recording with video size " + videoSz.toString()); |
| } |
| |
| // Configure preview and recording surfaces. |
| mOutMediaFileName = VIDEO_FILE_PATH + "/test_video.mp4"; |
| if (DEBUG_DUMP) { |
| mOutMediaFileName = VIDEO_FILE_PATH + "/test_video_" + cameraId + "_" |
| + videoSz.toString() + ".mp4"; |
| } |
| |
| prepareRecordingWithProfile(profile); |
| |
| // prepare preview surface by using video size. |
| updatePreviewSurfaceWithVideo(videoSz, profile.videoFrameRate); |
| |
| CaptureRequest.Builder previewRequest = |
| mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); |
| CaptureRequest.Builder recordingRequest = |
| mCamera.createCaptureRequest(CameraDevice.TEMPLATE_RECORD); |
| |
| SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); |
| SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); |
| |
| prepareVideoPreview(previewRequest, recordingRequest, resultListener, imageListener); |
| |
| // Can reuse the MediaRecorder object after reset. |
| mMediaRecorder.reset(); |
| |
| if (maxVideoFrameRate != -1) { |
| // At least one CamcorderProfile is present, check FPS |
| assertTrue("At least one CamcorderProfile must support >= 24 FPS", |
| maxVideoFrameRate >= 24); |
| } |
| } |
| |
| private void releaseRecorder() { |
| if (mMediaRecorder != null) { |
| mMediaRecorder.release(); |
| mMediaRecorder = null; |
| } |
| } |
| |
| private List<String> cameraColorOutputCheck() throws Exception { |
| List<String> mCameraColorOutputIds = new ArrayList<String>(); |
| for (String id : mCameraIds) { |
| openDevice(id); |
| if (!mStaticInfo.isColorOutputSupported()) { |
| Log.i(TAG, "Camera " + id + |
| " does not support color outputs, skipping"); |
| continue; |
| } |
| mCameraColorOutputIds.add(id); |
| closeDevice(); |
| } |
| return mCameraColorOutputIds; |
| } |
| |
| /** |
| * Returns {@code true} if the {@link CamcorderProfile} ID is allowed to be unsupported. |
| * |
| * <p>This only allows unsupported profiles when using the LEGACY mode of the Camera API.</p> |
| * |
| * @param profileId a {@link CamcorderProfile} ID to check. |
| * @return {@code true} if supported. |
| */ |
| private boolean allowedUnsupported(int cameraId, int profileId) { |
| if (!mStaticInfo.isHardwareLevelLegacy()) { |
| return false; |
| } |
| |
| switch(profileId) { |
| case CamcorderProfile.QUALITY_2160P: |
| case CamcorderProfile.QUALITY_1080P: |
| case CamcorderProfile.QUALITY_HIGH: |
| return !CamcorderProfile.hasProfile(cameraId, profileId) || |
| CamcorderProfile.get(cameraId, profileId).videoFrameWidth >= 1080; |
| } |
| return false; |
| } |
| |
| /** |
| * Configure MediaRecorder recording session with CamcorderProfile, prepare |
| * the recording surface. |
| */ |
| private void prepareRecordingWithProfile(CamcorderProfile profile) |
| throws Exception { |
| // Prepare MediaRecorder. |
| mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); |
| mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); |
| mMediaRecorder.setProfile(profile); |
| mMediaRecorder.setOutputFile(mOutMediaFileName); |
| if (mPersistentSurface != null) { |
| mMediaRecorder.setInputSurface(mPersistentSurface); |
| mRecordingSurface = mPersistentSurface; |
| } |
| mMediaRecorder.prepare(); |
| if (mPersistentSurface == null) { |
| mRecordingSurface = mMediaRecorder.getSurface(); |
| } |
| assertNotNull("Recording surface must be non-null!", mRecordingSurface); |
| mVideoFrameRate = profile.videoFrameRate; |
| mVideoSize = new Size(profile.videoFrameWidth, profile.videoFrameHeight); |
| } |
| |
| /** |
| * Update preview size with video size. |
| * |
| * <p>Preview size will be capped with max preview size.</p> |
| * |
| * @param videoSize The video size used for preview. |
| * @param videoFrameRate The video frame rate |
| * |
| */ |
| private void updatePreviewSurfaceWithVideo(Size videoSize, int videoFrameRate) throws Exception { |
| if (mOrderedPreviewSizes == null) { |
| throw new IllegalStateException("supported preview size list is not initialized yet"); |
| } |
| final float FRAME_DURATION_TOLERANCE = 0.01f; |
| long videoFrameDuration = (long) (1e9 / videoFrameRate * |
| (1.0 + FRAME_DURATION_TOLERANCE)); |
| HashMap<Size, Long> minFrameDurationMap = mStaticInfo. |
| getAvailableMinFrameDurationsForFormatChecked(ImageFormat.PRIVATE); |
| Size maxPreviewSize = mOrderedPreviewSizes.get(0); |
| Size previewSize = null; |
| if (videoSize.getWidth() > maxPreviewSize.getWidth() || |
| videoSize.getHeight() > maxPreviewSize.getHeight()) { |
| for (Size s : mOrderedPreviewSizes) { |
| Long frameDuration = minFrameDurationMap.get(s); |
| if (mStaticInfo.isHardwareLevelLegacy()) { |
| // Legacy doesn't report min frame duration |
| frameDuration = new Long(0); |
| } |
| assertTrue("Cannot find minimum frame duration for private size" + s, |
| frameDuration != null); |
| if (frameDuration <= videoFrameDuration && |
| s.getWidth() <= videoSize.getWidth() && |
| s.getHeight() <= videoSize.getHeight()) { |
| Log.w(TAG, "Overwrite preview size from " + videoSize.toString() + |
| " to " + s.toString()); |
| previewSize = s; |
| break; |
| // If all preview size doesn't work then we fallback to video size |
| } |
| } |
| } |
| if (previewSize == null) { |
| previewSize = videoSize; |
| } |
| |
| updatePreviewSurface(previewSize); |
| } |
| |
| protected void prepareVideoPreview(CaptureRequest.Builder previewRequest, |
| CaptureRequest.Builder recordingRequest, |
| CaptureCallback resultListener, |
| ImageReader.OnImageAvailableListener imageListener) throws Exception { |
| |
| // Configure output streams with preview and jpeg streams. |
| List<Surface> outputSurfaces = new ArrayList<Surface>(); |
| outputSurfaces.add(mPreviewSurface); |
| outputSurfaces.add(mRecordingSurface); |
| |
| mSessionListener = new BlockingSessionCallback(); |
| mSession = configureCameraSession(mCamera, outputSurfaces, mSessionListener, mHandler); |
| |
| previewRequest.addTarget(mPreviewSurface); |
| recordingRequest.addTarget(mPreviewSurface); |
| recordingRequest.addTarget(mRecordingSurface); |
| |
| // Start preview. |
| mSession.setRepeatingRequest(previewRequest.build(), null, mHandler); |
| } |
| |
| protected void prepareCapturePreview(CaptureRequest.Builder previewRequest, |
| CaptureRequest.Builder stillRequest, |
| CaptureCallback resultListener, |
| ImageReader.OnImageAvailableListener imageListener) throws Exception { |
| |
| Size captureSz = mOrderedStillSizes.get(0); |
| Size previewSz = mOrderedPreviewSizes.get(1); |
| |
| if (VERBOSE) { |
| Log.v(TAG, String.format("Prepare single capture (%s) and preview (%s)", |
| captureSz.toString(), previewSz.toString())); |
| } |
| |
| // Update preview size. |
| updatePreviewSurface(previewSz); |
| |
| // Create ImageReader. |
| createImageReader(captureSz, ImageFormat.JPEG, MAX_READER_IMAGES, imageListener); |
| |
| // Configure output streams with preview and jpeg streams. |
| List<Surface> outputSurfaces = new ArrayList<Surface>(); |
| outputSurfaces.add(mPreviewSurface); |
| outputSurfaces.add(mReaderSurface); |
| mSessionListener = new BlockingSessionCallback(); |
| mSession = configureCameraSession(mCamera, outputSurfaces, mSessionListener, mHandler); |
| |
| // Configure the requests. |
| previewRequest.addTarget(mPreviewSurface); |
| stillRequest.addTarget(mPreviewSurface); |
| stillRequest.addTarget(mReaderSurface); |
| |
| // Start preview. |
| mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler); |
| } |
| |
| } |