1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.mediastress.cts; 18 19 import android.content.pm.PackageManager; 20 import android.hardware.Camera; 21 import android.media.CamcorderProfile; 22 import android.media.MediaPlayer; 23 import android.media.MediaRecorder; 24 import android.os.Handler; 25 import android.os.Looper; 26 import android.test.ActivityInstrumentationTestCase2; 27 import android.test.suitebuilder.annotation.LargeTest; 28 import android.util.Log; 29 import android.view.SurfaceHolder; 30 31 import java.io.BufferedWriter; 32 import java.io.File; 33 import java.io.FileWriter; 34 import java.io.Writer; 35 import java.util.List; 36 import java.util.concurrent.Semaphore; 37 import java.util.concurrent.TimeUnit; 38 39 public class MediaRecorderStressTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> { 40 41 private static final String TAG = "MediaRecorderStressTest"; 42 private static final int NUMBER_OF_CAMERA_STRESS_LOOPS = 50; 43 private static final int NUMBER_OF_RECORDER_STRESS_LOOPS = 50; 44 private static final int NUMBER_OF_RECORDERANDPLAY_STRESS_LOOPS = 25; 45 private static final int NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER = 50; 46 private static final long WAIT_TIME_CAMERA_TEST = 3000; // in ms 47 private static final long WAIT_TIME_RECORDER_TEST = 5000; // in ms 48 private final String OUTPUT_FILE = WorkDir.getTopDirString() + "temp"; 49 private static final String OUTPUT_FILE_EXT = ".3gp"; 50 private static final String MEDIA_STRESS_OUTPUT ="mediaStressOutput.txt"; 51 private final CameraErrorCallback mCameraErrorCallback = new CameraErrorCallback(); 52 private final RecorderErrorCallback mRecorderErrorCallback = new RecorderErrorCallback(); 53 private final static int WAIT_TIMEOUT = 10000; 54 private static final int VIDEO_WIDTH = 176; 55 private static final int VIDEO_HEIGHT = 144; 56 57 private MediaRecorder mRecorder; 58 private Camera mCamera; 59 private Thread mLooperThread; 60 private Handler mHandler; 61 62 private static int mCameraId; 63 private static int mProfileQuality = CamcorderProfile.QUALITY_HIGH; 64 private static CamcorderProfile profile = 65 CamcorderProfile.get(mCameraId, mProfileQuality); 66 67 private int mVideoEncoder; 68 private int mAudioEncoder; 69 private int mFrameRate; 70 private int mVideoWidth; 71 private int mVideoHeight; 72 private int mBitRate; 73 private boolean mRemoveVideo = true; 74 private int mRecordDuration = 5000; 75 76 private boolean mHasRearCamera = false; 77 private boolean mHasFrontCamera = false; 78 79 public MediaRecorderStressTest() { 80 super(MediaFrameworkTest.class); 81 } 82 83 protected void setUp() throws Exception { 84 PackageManager packageManager = 85 getInstrumentation().getTargetContext().getPackageManager(); 86 mHasRearCamera = packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA); 87 mHasFrontCamera = packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT); 88 int cameraId = 0; 89 CamcorderProfile profile = CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_HIGH); 90 mVideoEncoder = profile.videoCodec; 91 mAudioEncoder = profile.audioCodec; 92 mFrameRate = profile.videoFrameRate; 93 mVideoWidth = profile.videoFrameWidth; 94 mVideoHeight = profile.videoFrameHeight; 95 mBitRate = profile.videoBitRate; 96 97 final Semaphore sem = new Semaphore(0); 98 mLooperThread = new Thread() { 99 @Override 100 public void run() { 101 Log.v(TAG, "starting looper"); 102 Looper.prepare(); 103 mHandler = new Handler(); 104 sem.release(); 105 Looper.loop(); 106 Log.v(TAG, "quit looper"); 107 } 108 }; 109 mLooperThread.start(); 110 if (!sem.tryAcquire(WAIT_TIMEOUT, TimeUnit.MILLISECONDS)) { 111 fail("Failed to start the looper."); 112 } 113 114 getActivity(); 115 super.setUp(); 116 } 117 118 @Override 119 protected void tearDown() throws Exception { 120 if (mHandler != null) { 121 mHandler.getLooper().quit(); 122 mHandler = null; 123 } 124 if (mLooperThread != null) { 125 mLooperThread.join(WAIT_TIMEOUT); 126 if (mLooperThread.isAlive()) { 127 fail("Failed to stop the looper."); 128 } 129 mLooperThread = null; 130 } 131 132 super.tearDown(); 133 } 134 135 private void runOnLooper(final Runnable command) throws InterruptedException { 136 final Semaphore sem = new Semaphore(0); 137 mHandler.post(new Runnable() { 138 @Override 139 public void run() { 140 try { 141 command.run(); 142 } finally { 143 sem.release(); 144 } 145 } 146 }); 147 if (! sem.tryAcquire(WAIT_TIMEOUT, TimeUnit.MILLISECONDS)) { 148 fail("Failed to run the command on the looper."); 149 } 150 } 151 152 private final class CameraErrorCallback implements android.hardware.Camera.ErrorCallback { 153 public void onError(int error, android.hardware.Camera camera) { 154 assertTrue("Camera test mediaserver died", error != 155 android.hardware.Camera.CAMERA_ERROR_SERVER_DIED); 156 } 157 } 158 159 private final class RecorderErrorCallback implements MediaRecorder.OnErrorListener { 160 public void onError(MediaRecorder mr, int what, int extra) { 161 // fail the test case no matter what error come up 162 fail("mediaRecorder error"); 163 } 164 } 165 166 //Test case for stressing the camera preview. 167 @LargeTest 168 public void testStressCamera() throws Exception { 169 if (Camera.getNumberOfCameras() < 1) { 170 return; 171 } 172 173 SurfaceHolder mSurfaceHolder; 174 mSurfaceHolder = MediaFrameworkTest.getSurfaceView().getHolder(); 175 File stressOutFile = new File(WorkDir.getTopDir(), MEDIA_STRESS_OUTPUT); 176 Writer output = new BufferedWriter(new FileWriter(stressOutFile, true)); 177 output.write("Camera start preview stress:\n"); 178 output.write("Total number of loops:" + 179 NUMBER_OF_CAMERA_STRESS_LOOPS + "\n"); 180 181 Log.v(TAG, "Start preview"); 182 output.write("No of loop: "); 183 184 for (int i = 0; i< NUMBER_OF_CAMERA_STRESS_LOOPS; i++) { 185 runOnLooper(new Runnable() { 186 @Override 187 public void run() { 188 if (mHasRearCamera) { 189 mCamera = Camera.open(); 190 } else if (mHasFrontCamera) { 191 mCamera = Camera.open(0); 192 } else { 193 mCamera = null; 194 } 195 } 196 }); 197 if (mCamera == null) { 198 break; 199 } 200 mCamera.setErrorCallback(mCameraErrorCallback); 201 mCamera.setPreviewDisplay(mSurfaceHolder); 202 mCamera.startPreview(); 203 Thread.sleep(WAIT_TIME_CAMERA_TEST); 204 mCamera.stopPreview(); 205 mCamera.release(); 206 output.write(" ," + i); 207 } 208 209 output.write("\n\n"); 210 output.close(); 211 } 212 213 //Test case for stressing the camera preview. 214 @LargeTest 215 public void testStressRecorder() throws Exception { 216 String filename; 217 SurfaceHolder mSurfaceHolder; 218 mSurfaceHolder = MediaFrameworkTest.getSurfaceView().getHolder(); 219 File stressOutFile = new File(WorkDir.getTopDir(), MEDIA_STRESS_OUTPUT); 220 Writer output = new BufferedWriter(new FileWriter(stressOutFile, true)); 221 int width; 222 int height; 223 Camera camera = null; 224 225 if (!mHasRearCamera && !mHasFrontCamera) { 226 output.write("No camera found. Skipping recorder stress test\n"); 227 return; 228 } 229 // Try to get camera smallest supported resolution. 230 // If we fail for any reason, set the video size to default value. 231 try { 232 camera = Camera.open(0); 233 List<Camera.Size> previewSizes = camera.getParameters().getSupportedPreviewSizes(); 234 width = previewSizes.get(0).width; 235 height = previewSizes.get(0).height; 236 for (Camera.Size size : previewSizes) { 237 if (size.width < width || size.height < height) { 238 width = size.width; 239 height = size.height; 240 } 241 } 242 } catch (Exception e) { 243 width = VIDEO_WIDTH; 244 height = VIDEO_HEIGHT; 245 } 246 if (camera != null) { 247 camera.release(); 248 } 249 Log.v(TAG, String.format("Camera video size used for test %dx%d", width, height)); 250 output.write("H263 video record- reset after prepare Stress test\n"); 251 output.write("Total number of loops:" + 252 NUMBER_OF_RECORDER_STRESS_LOOPS + "\n"); 253 254 output.write("No of loop: "); 255 Log.v(TAG, "Start preview"); 256 for (int i = 0; i < NUMBER_OF_RECORDER_STRESS_LOOPS; i++) { 257 runOnLooper(new Runnable() { 258 @Override 259 public void run() { 260 mRecorder = new MediaRecorder(); 261 } 262 }); 263 Log.v(TAG, "counter = " + i); 264 filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT; 265 Log.v(TAG, filename); 266 mRecorder.setOnErrorListener(mRecorderErrorCallback); 267 mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 268 mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); 269 mRecorder.setOutputFile(filename); 270 mRecorder.setVideoFrameRate(mFrameRate); 271 mRecorder.setVideoSize(width, height); 272 Log.v(TAG, "setEncoder"); 273 mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263); 274 mSurfaceHolder = MediaFrameworkTest.getSurfaceView().getHolder(); 275 Log.v(TAG, "setPreview"); 276 mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); 277 Log.v(TAG, "prepare"); 278 mRecorder.prepare(); 279 Log.v(TAG, "before release"); 280 Thread.sleep(WAIT_TIME_RECORDER_TEST); 281 mRecorder.reset(); 282 mRecorder.release(); 283 output.write(", " + i); 284 } 285 286 output.write("\n\n"); 287 output.close(); 288 } 289 290 //Stress test case for switching camera and video recorder preview. 291 @LargeTest 292 public void testStressCameraSwitchRecorder() throws Exception { 293 if (Camera.getNumberOfCameras() < 1) { 294 return; 295 } 296 297 String filename; 298 int width; 299 int height; 300 SurfaceHolder mSurfaceHolder; 301 mSurfaceHolder = MediaFrameworkTest.getSurfaceView().getHolder(); 302 File stressOutFile = new File(WorkDir.getTopDir(), MEDIA_STRESS_OUTPUT); 303 Writer output = new BufferedWriter(new FileWriter(stressOutFile, true)); 304 output.write("Camera and video recorder preview switching\n"); 305 output.write("Total number of loops:" 306 + NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER + "\n"); 307 308 Log.v(TAG, "Start preview"); 309 output.write("No of loop: "); 310 for (int i = 0; i < NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER; i++) { 311 runOnLooper(new Runnable() { 312 @Override 313 public void run() { 314 if (mHasRearCamera) { 315 mCamera = Camera.open(); 316 } else if (mHasFrontCamera) { 317 mCamera = Camera.open(0); 318 } else { 319 mCamera = null; 320 } 321 } 322 }); 323 if (mCamera == null) { 324 break; 325 } 326 // Try to get camera smallest supported resolution. 327 // If we fail for any reason, set the video size to default value. 328 List<Camera.Size> previewSizes = mCamera.getParameters().getSupportedPreviewSizes(); 329 width = previewSizes.get(0).width; 330 height = previewSizes.get(0).height; 331 for (Camera.Size size : previewSizes) { 332 if (size.width < width || size.height < height) { 333 width = size.width; 334 height = size.height; 335 } 336 } 337 Log.v(TAG, String.format("Camera video size used for test %dx%d", width, height)); 338 339 mCamera.setErrorCallback(mCameraErrorCallback); 340 mCamera.setPreviewDisplay(mSurfaceHolder); 341 mCamera.startPreview(); 342 Thread.sleep(WAIT_TIME_CAMERA_TEST); 343 mCamera.stopPreview(); 344 mCamera.release(); 345 mCamera = null; 346 Log.v(TAG, "release camera"); 347 filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT; 348 Log.v(TAG, filename); 349 runOnLooper(new Runnable() { 350 @Override 351 public void run() { 352 mRecorder = new MediaRecorder(); 353 } 354 }); 355 mRecorder.setOnErrorListener(mRecorderErrorCallback); 356 mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 357 mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); 358 mRecorder.setOutputFile(filename); 359 mRecorder.setVideoFrameRate(mFrameRate); 360 mRecorder.setVideoSize(width, height); 361 Log.v(TAG, "Media recorder setEncoder"); 362 mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263); 363 Log.v(TAG, "mediaRecorder setPreview"); 364 mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); 365 Log.v(TAG, "prepare"); 366 mRecorder.prepare(); 367 Log.v(TAG, "before release"); 368 Thread.sleep(WAIT_TIME_CAMERA_TEST); 369 mRecorder.reset(); 370 mRecorder.release(); 371 Log.v(TAG, "release video recorder"); 372 output.write(", " + i); 373 } 374 375 output.write("\n\n"); 376 output.close(); 377 } 378 379 public void validateRecordedVideo(String recordedFile) throws Exception { 380 MediaPlayer mp = new MediaPlayer(); 381 mp.setDataSource(recordedFile); 382 mp.prepare(); 383 int duration = mp.getDuration(); 384 if (duration <= 0){ 385 assertTrue("stressRecordAndPlayback", false); 386 } 387 mp.release(); 388 } 389 390 public void removeRecodedVideo(String filename){ 391 File video = new File(filename); 392 Log.v(TAG, "remove recorded video " + filename); 393 video.delete(); 394 } 395 396 //Stress test case for record a video and play right away. 397 @LargeTest 398 public void testStressRecordVideoAndPlayback() throws Exception { 399 if (Camera.getNumberOfCameras() < 1) { 400 return; 401 } 402 403 String filename; 404 SurfaceHolder mSurfaceHolder; 405 mSurfaceHolder = MediaFrameworkTest.getSurfaceView().getHolder(); 406 File stressOutFile = new File(WorkDir.getTopDir(), MEDIA_STRESS_OUTPUT); 407 Writer output = new BufferedWriter( 408 new FileWriter(stressOutFile, true)); 409 410 output.write("Video record and play back stress test:\n"); 411 output.write("Total number of loops:" 412 + NUMBER_OF_RECORDERANDPLAY_STRESS_LOOPS + "\n"); 413 414 output.write("No of loop: "); 415 for (int i = 0; i < NUMBER_OF_RECORDERANDPLAY_STRESS_LOOPS; i++){ 416 filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT; 417 Log.v(TAG, filename); 418 runOnLooper(new Runnable() { 419 @Override 420 public void run() { 421 mRecorder = new MediaRecorder(); 422 } 423 }); 424 Log.v(TAG, "iterations : " + i); 425 Log.v(TAG, "videoEncoder : " + mVideoEncoder); 426 Log.v(TAG, "audioEncoder : " + mAudioEncoder); 427 Log.v(TAG, "frameRate : " + mFrameRate); 428 Log.v(TAG, "videoWidth : " + mVideoWidth); 429 Log.v(TAG, "videoHeight : " + mVideoHeight); 430 Log.v(TAG, "bitRate : " + mBitRate); 431 Log.v(TAG, "recordDuration : " + mRecordDuration); 432 433 mRecorder.setOnErrorListener(mRecorderErrorCallback); 434 mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 435 mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); 436 mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); 437 mRecorder.setOutputFile(filename); 438 mRecorder.setVideoFrameRate(mFrameRate); 439 mRecorder.setVideoSize(mVideoWidth, mVideoHeight); 440 mRecorder.setVideoEncoder(mVideoEncoder); 441 mRecorder.setAudioEncoder(mAudioEncoder); 442 Log.v(TAG, "mediaRecorder setPreview"); 443 mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); 444 mRecorder.prepare(); 445 mRecorder.start(); 446 Thread.sleep(mRecordDuration); 447 Log.v(TAG, "Before stop"); 448 mRecorder.stop(); 449 mRecorder.release(); 450 //start the playback 451 MediaPlayer mp = new MediaPlayer(); 452 mp.setDataSource(filename); 453 mp.setDisplay(MediaFrameworkTest.getSurfaceView().getHolder()); 454 mp.prepare(); 455 mp.start(); 456 Thread.sleep(mRecordDuration); 457 mp.release(); 458 validateRecordedVideo(filename); 459 if (mRemoveVideo) { 460 removeRecodedVideo(filename); 461 } 462 output.write(", " + i); 463 } 464 465 output.write("\n\n"); 466 output.close(); 467 } 468 } 469