Merge "Updating user restrictions when they are removed" into nyc-dev am: 1893c4cea7
am: a20e7d86ba
* commit 'a20e7d86ba94280422574596a6647f31e5bd2c53':
Created 4 camera preview stress test cases.
Change-Id: Ifc9c7896c5131b524f9073d7316f95c0dc6106f2
This commit is contained in:
@@ -38,6 +38,7 @@ import android.hardware.camera2.CameraMetadata;
|
|||||||
import android.hardware.camera2.CaptureRequest;
|
import android.hardware.camera2.CaptureRequest;
|
||||||
import android.hardware.camera2.CaptureResult;
|
import android.hardware.camera2.CaptureResult;
|
||||||
import android.media.ImageReader;
|
import android.media.ImageReader;
|
||||||
|
import android.graphics.SurfaceTexture;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@@ -67,6 +68,7 @@ import static com.android.mediaframeworktest.helpers.CameraTestUtils.getPreviewS
|
|||||||
import static com.android.mediaframeworktest.helpers.CameraTestUtils.getSupportedPreviewSizes;
|
import static com.android.mediaframeworktest.helpers.CameraTestUtils.getSupportedPreviewSizes;
|
||||||
import static com.android.mediaframeworktest.helpers.CameraTestUtils.getSupportedStillSizes;
|
import static com.android.mediaframeworktest.helpers.CameraTestUtils.getSupportedStillSizes;
|
||||||
import static com.android.mediaframeworktest.helpers.CameraTestUtils.getSupportedVideoSizes;
|
import static com.android.mediaframeworktest.helpers.CameraTestUtils.getSupportedVideoSizes;
|
||||||
|
import static com.android.mediaframeworktest.helpers.CameraTestUtils.getSortedSizesForFormat;
|
||||||
import static com.android.mediaframeworktest.helpers.CameraTestUtils.makeImageReader;
|
import static com.android.mediaframeworktest.helpers.CameraTestUtils.makeImageReader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -122,6 +124,8 @@ public class Camera2SurfaceViewTestCase extends
|
|||||||
protected List<Size> mOrderedPreviewSizes; // In descending order.
|
protected List<Size> mOrderedPreviewSizes; // In descending order.
|
||||||
protected List<Size> mOrderedVideoSizes; // In descending order.
|
protected List<Size> mOrderedVideoSizes; // In descending order.
|
||||||
protected List<Size> mOrderedStillSizes; // In descending order.
|
protected List<Size> mOrderedStillSizes; // In descending order.
|
||||||
|
protected List<Size> mOrderedRAW10Sizes; // In descending order.
|
||||||
|
protected List<Size> mOrderedYUV420888Sizes; // In descending order.
|
||||||
protected HashMap<Size, Long> mMinPreviewFrameDurationMap;
|
protected HashMap<Size, Long> mMinPreviewFrameDurationMap;
|
||||||
|
|
||||||
protected WindowManager mWindowManager;
|
protected WindowManager mWindowManager;
|
||||||
@@ -589,6 +593,7 @@ public class Camera2SurfaceViewTestCase extends
|
|||||||
mReaderSurface = null;
|
mReaderSurface = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a camera device and get the StaticMetadata for a given camera id.
|
* Open a camera device and get the StaticMetadata for a given camera id.
|
||||||
*
|
*
|
||||||
@@ -603,8 +608,13 @@ public class Camera2SurfaceViewTestCase extends
|
|||||||
if (mStaticInfo.isColorOutputSupported()) {
|
if (mStaticInfo.isColorOutputSupported()) {
|
||||||
mOrderedPreviewSizes = getSupportedPreviewSizes(cameraId, mCameraManager,
|
mOrderedPreviewSizes = getSupportedPreviewSizes(cameraId, mCameraManager,
|
||||||
getPreviewSizeBound(mWindowManager, PREVIEW_SIZE_BOUND));
|
getPreviewSizeBound(mWindowManager, PREVIEW_SIZE_BOUND));
|
||||||
mOrderedVideoSizes = getSupportedVideoSizes(cameraId, mCameraManager, PREVIEW_SIZE_BOUND);
|
mOrderedVideoSizes = getSupportedVideoSizes(
|
||||||
|
cameraId, mCameraManager, PREVIEW_SIZE_BOUND);
|
||||||
mOrderedStillSizes = getSupportedStillSizes(cameraId, mCameraManager, null);
|
mOrderedStillSizes = getSupportedStillSizes(cameraId, mCameraManager, null);
|
||||||
|
mOrderedRAW10Sizes = getSortedSizesForFormat(
|
||||||
|
cameraId, mCameraManager, ImageFormat.RAW10, null);
|
||||||
|
mOrderedYUV420888Sizes = getSortedSizesForFormat(
|
||||||
|
cameraId, mCameraManager, ImageFormat.YUV_420_888, null);
|
||||||
// Use ImageFormat.YUV_420_888 for now. TODO: need figure out what's format for preview
|
// Use ImageFormat.YUV_420_888 for now. TODO: need figure out what's format for preview
|
||||||
// in public API side.
|
// in public API side.
|
||||||
mMinPreviewFrameDurationMap =
|
mMinPreviewFrameDurationMap =
|
||||||
|
|||||||
@@ -0,0 +1,578 @@
|
|||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user