/* * 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; /** *
Tests Back/Front camera switching and Camera/Video modes witching.
* * 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* Preview jpeg output streams are configured. Max still capture * size is used for jpeg capture. *
*/ public void testPreviewSwitchBackFrontCamera() throws Exception { List* Test basic video preview switch. *
** 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. *
*/ public void testPreviewSwitchBackFrontVideo() throws Exception { List* 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" *
*/ 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. ** 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" *
*/ 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); ListThis only allows unsupported profiles when using the LEGACY mode of the Camera API.
* * @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. * *Preview size will be capped with max preview size.
* * @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