1/* 2 * Copyright (C) 2009 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 17package com.android.mediaframeworktest.stress; 18 19 20import com.android.mediaframeworktest.MediaFrameworkTest; 21 22import java.io.BufferedWriter; 23import java.io.File; 24import java.io.FileWriter; 25import java.io.IOException; 26import java.io.Writer; 27import java.util.concurrent.Semaphore; 28import java.util.concurrent.TimeUnit; 29 30import android.hardware.Camera; 31import android.media.CamcorderProfile; 32import android.media.MediaPlayer; 33import android.media.MediaRecorder; 34import android.os.Handler; 35import android.os.Looper; 36import android.test.ActivityInstrumentationTestCase2; 37import android.test.suitebuilder.annotation.LargeTest; 38import android.util.Log; 39import android.view.SurfaceHolder; 40import com.android.mediaframeworktest.MediaRecorderStressTestRunner; 41 42/** 43 * Junit / Instrumentation test case for the media player api 44 */ 45public class MediaRecorderStressTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> { 46 47 private String TAG = "MediaRecorderStressTest"; 48 private MediaRecorder mRecorder; 49 private Camera mCamera; 50 51 private static final int NUMBER_OF_CAMERA_STRESS_LOOPS = 100; 52 private static final int NUMBER_OF_RECORDER_STRESS_LOOPS = 100; 53 private static final int NUMBER_OF_RECORDERANDPLAY_STRESS_LOOPS = 50; 54 private static final int NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER = 200; 55 private static final int NUMBER_OF_TIME_LAPSE_LOOPS = 25; 56 private static final int TIME_LAPSE_PLAYBACK_WAIT_TIME = 5* 1000; // 5 seconds 57 private static final long WAIT_TIME_CAMERA_TEST = 3 * 1000; // 3 seconds 58 private static final long WAIT_TIME_RECORDER_TEST = 6 * 1000; // 6 seconds 59 private static final String OUTPUT_FILE = "/sdcard/temp"; 60 private static final String OUTPUT_FILE_EXT = ".3gp"; 61 private static final String MEDIA_STRESS_OUTPUT = 62 "/sdcard/mediaStressOutput.txt"; 63 private static final int CAMERA_ID = 0; 64 65 private final CameraErrorCallback mCameraErrorCallback = new CameraErrorCallback(); 66 private final RecorderErrorCallback mRecorderErrorCallback = new RecorderErrorCallback(); 67 68 private final static int WAIT_TIMEOUT = 10 * 1000; // 10 seconds 69 private Thread mLooperThread; 70 private Handler mHandler; 71 72 public MediaRecorderStressTest() { 73 super("com.android.mediaframeworktest", MediaFrameworkTest.class); 74 } 75 76 protected void setUp() throws Exception { 77 final Semaphore sem = new Semaphore(0); 78 mLooperThread = new Thread() { 79 @Override 80 public void run() { 81 Log.v(TAG, "starting looper"); 82 Looper.prepare(); 83 mHandler = new Handler(); 84 sem.release(); 85 Looper.loop(); 86 Log.v(TAG, "quit looper"); 87 } 88 }; 89 mLooperThread.start(); 90 if (! sem.tryAcquire(WAIT_TIMEOUT, TimeUnit.MILLISECONDS)) { 91 fail("Failed to start the looper."); 92 } 93 //Insert a 2 second before launching the test activity. This is 94 //the workaround for the race condition of requesting the updated surface. 95 Thread.sleep(2000); 96 getActivity(); 97 super.setUp(); 98 } 99 100 @Override 101 protected void tearDown() throws Exception { 102 if (mHandler != null) { 103 mHandler.getLooper().quit(); 104 mHandler = null; 105 } 106 if (mLooperThread != null) { 107 mLooperThread.join(WAIT_TIMEOUT); 108 if (mLooperThread.isAlive()) { 109 fail("Failed to stop the looper."); 110 } 111 mLooperThread = null; 112 } 113 114 super.tearDown(); 115 } 116 117 private void runOnLooper(final Runnable command) throws InterruptedException { 118 final Semaphore sem = new Semaphore(0); 119 mHandler.post(new Runnable() { 120 @Override 121 public void run() { 122 try { 123 command.run(); 124 } finally { 125 sem.release(); 126 } 127 } 128 }); 129 if (! sem.tryAcquire(WAIT_TIMEOUT, TimeUnit.MILLISECONDS)) { 130 fail("Failed to run the command on the looper."); 131 } 132 } 133 134 private final class CameraErrorCallback implements android.hardware.Camera.ErrorCallback { 135 public void onError(int error, android.hardware.Camera camera) { 136 if (error == android.hardware.Camera.CAMERA_ERROR_SERVER_DIED) { 137 assertTrue("Camera test mediaserver died", false); 138 } 139 } 140 } 141 142 private final class RecorderErrorCallback implements MediaRecorder.OnErrorListener { 143 public void onError(MediaRecorder mr, int what, int extra) { 144 // fail the test case no matter what error come up 145 assertTrue("mediaRecorder error", false); 146 } 147 } 148 149 //Test case for stressing the camera preview. 150 @LargeTest 151 public void testStressCamera() throws Exception { 152 SurfaceHolder mSurfaceHolder; 153 mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); 154 File stressOutFile = new File(MEDIA_STRESS_OUTPUT); 155 Writer output = new BufferedWriter(new FileWriter(stressOutFile, true)); 156 output.write("Camera start preview stress:\n"); 157 output.write("Total number of loops:" + 158 NUMBER_OF_CAMERA_STRESS_LOOPS + "\n"); 159 try { 160 Log.v(TAG, "Start preview"); 161 output.write("No of loop: "); 162 163 for (int i = 0; i< NUMBER_OF_CAMERA_STRESS_LOOPS; i++) { 164 runOnLooper(new Runnable() { 165 @Override 166 public void run() { 167 mCamera = Camera.open(CAMERA_ID); 168 } 169 }); 170 mCamera.setErrorCallback(mCameraErrorCallback); 171 mCamera.setPreviewDisplay(mSurfaceHolder); 172 mCamera.startPreview(); 173 Thread.sleep(WAIT_TIME_CAMERA_TEST); 174 mCamera.stopPreview(); 175 mCamera.release(); 176 output.write(" ," + i); 177 } 178 } catch (Exception e) { 179 assertTrue("CameraStressTest", false); 180 Log.v(TAG, e.toString()); 181 } 182 output.write("\n\n"); 183 output.close(); 184 } 185 186 //Test case for stressing the camera preview. 187 @LargeTest 188 public void testStressRecorder() throws Exception { 189 String filename; 190 SurfaceHolder mSurfaceHolder; 191 mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); 192 File stressOutFile = new File(MEDIA_STRESS_OUTPUT); 193 Writer output = new BufferedWriter(new FileWriter(stressOutFile, true)); 194 output.write("H263 video record- reset after prepare Stress test\n"); 195 output.write("Total number of loops:" + 196 NUMBER_OF_RECORDER_STRESS_LOOPS + "\n"); 197 try { 198 output.write("No of loop: "); 199 Log.v(TAG, "Start preview"); 200 for (int i = 0; i < NUMBER_OF_RECORDER_STRESS_LOOPS; i++) { 201 runOnLooper(new Runnable() { 202 @Override 203 public void run() { 204 mRecorder = new MediaRecorder(); 205 } 206 }); 207 Log.v(TAG, "counter = " + i); 208 filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT; 209 Log.v(TAG, filename); 210 mRecorder.setOnErrorListener(mRecorderErrorCallback); 211 mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 212 mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); 213 mRecorder.setOutputFile(filename); 214 mRecorder.setVideoFrameRate(MediaRecorderStressTestRunner.mFrameRate); 215 mRecorder.setVideoSize(176,144); 216 Log.v(TAG, "setEncoder"); 217 mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263); 218 mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); 219 Log.v(TAG, "setPreview"); 220 mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); 221 Log.v(TAG, "prepare"); 222 mRecorder.prepare(); 223 Log.v(TAG, "before release"); 224 Thread.sleep(WAIT_TIME_RECORDER_TEST); 225 mRecorder.reset(); 226 mRecorder.release(); 227 output.write(", " + i); 228 } 229 } catch (Exception e) { 230 assertTrue("Recorder Stress test", false); 231 Log.v(TAG, e.toString()); 232 } 233 output.write("\n\n"); 234 output.close(); 235 } 236 237 //Stress test case for switching camera and video recorder preview. 238 @LargeTest 239 public void testStressCameraSwitchRecorder() throws Exception { 240 String filename; 241 SurfaceHolder mSurfaceHolder; 242 mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); 243 File stressOutFile = new File(MEDIA_STRESS_OUTPUT); 244 Writer output = new BufferedWriter(new FileWriter(stressOutFile, true)); 245 output.write("Camera and video recorder preview switching\n"); 246 output.write("Total number of loops:" 247 + NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER + "\n"); 248 try { 249 Log.v(TAG, "Start preview"); 250 output.write("No of loop: "); 251 for (int i = 0; i < NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER; i++) { 252 runOnLooper(new Runnable() { 253 @Override 254 public void run() { 255 mCamera = Camera.open(CAMERA_ID); 256 } 257 }); 258 mCamera.setErrorCallback(mCameraErrorCallback); 259 mCamera.setPreviewDisplay(mSurfaceHolder); 260 mCamera.startPreview(); 261 Thread.sleep(WAIT_TIME_CAMERA_TEST); 262 mCamera.stopPreview(); 263 mCamera.release(); 264 mCamera = null; 265 Log.v(TAG, "release camera"); 266 filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT; 267 Log.v(TAG, filename); 268 runOnLooper(new Runnable() { 269 @Override 270 public void run() { 271 mRecorder = new MediaRecorder(); 272 } 273 }); 274 mRecorder.setOnErrorListener(mRecorderErrorCallback); 275 mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 276 mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); 277 mRecorder.setOutputFile(filename); 278 mRecorder.setVideoFrameRate(MediaRecorderStressTestRunner.mFrameRate); 279 mRecorder.setVideoSize(176,144); 280 Log.v(TAG, "Media recorder setEncoder"); 281 mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263); 282 Log.v(TAG, "mediaRecorder setPreview"); 283 mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); 284 Log.v(TAG, "prepare"); 285 mRecorder.prepare(); 286 Log.v(TAG, "before release"); 287 Thread.sleep(WAIT_TIME_CAMERA_TEST); 288 mRecorder.release(); 289 Log.v(TAG, "release video recorder"); 290 output.write(", " + i); 291 } 292 } catch (Exception e) { 293 assertTrue("Camer and recorder switch mode", false); 294 Log.v(TAG, e.toString()); 295 } 296 output.write("\n\n"); 297 output.close(); 298 } 299 300 public void validateRecordedVideo(String recorded_file) { 301 try { 302 MediaPlayer mp = new MediaPlayer(); 303 mp.setDataSource(recorded_file); 304 mp.prepare(); 305 int duration = mp.getDuration(); 306 if (duration <= 0){ 307 assertTrue("stressRecordAndPlayback", false); 308 } 309 mp.release(); 310 } catch (Exception e) { 311 assertTrue("stressRecordAndPlayback", false); 312 } 313 } 314 315 public void removeRecordedVideo(String filename){ 316 File video = new File(filename); 317 Log.v(TAG, "remove recorded video " + filename); 318 video.delete(); 319 } 320 321 //Stress test case for record a video and play right away. 322 @LargeTest 323 public void testStressRecordVideoAndPlayback() throws Exception { 324 int iterations = MediaRecorderStressTestRunner.mIterations; 325 int video_encoder = MediaRecorderStressTestRunner.mVideoEncoder; 326 int audio_encoder = MediaRecorderStressTestRunner.mAudioEncdoer; 327 int frame_rate = MediaRecorderStressTestRunner.mFrameRate; 328 int video_width = MediaRecorderStressTestRunner.mVideoWidth; 329 int video_height = MediaRecorderStressTestRunner.mVideoHeight; 330 int bit_rate = MediaRecorderStressTestRunner.mBitRate; 331 boolean remove_video = MediaRecorderStressTestRunner.mRemoveVideo; 332 int record_duration = MediaRecorderStressTestRunner.mDuration; 333 334 String filename; 335 SurfaceHolder mSurfaceHolder; 336 mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); 337 File stressOutFile = new File(MEDIA_STRESS_OUTPUT); 338 Writer output = new BufferedWriter( 339 new FileWriter(stressOutFile, true)); 340 output.write("Video record and play back stress test:\n"); 341 output.write("Total number of loops:" 342 + NUMBER_OF_RECORDERANDPLAY_STRESS_LOOPS + "\n"); 343 try { 344 output.write("No of loop: "); 345 for (int i = 0; i < iterations; i++){ 346 filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT; 347 Log.v(TAG, filename); 348 runOnLooper(new Runnable() { 349 @Override 350 public void run() { 351 mRecorder = new MediaRecorder(); 352 } 353 }); 354 Log.v(TAG, "iterations : " + iterations); 355 Log.v(TAG, "video_encoder : " + video_encoder); 356 Log.v(TAG, "audio_encoder : " + audio_encoder); 357 Log.v(TAG, "frame_rate : " + frame_rate); 358 Log.v(TAG, "video_width : " + video_width); 359 Log.v(TAG, "video_height : " + video_height); 360 Log.v(TAG, "bit rate : " + bit_rate); 361 Log.v(TAG, "record_duration : " + record_duration); 362 363 mRecorder.setOnErrorListener(mRecorderErrorCallback); 364 mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 365 mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); 366 mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); 367 mRecorder.setOutputFile(filename); 368 mRecorder.setVideoFrameRate(frame_rate); 369 mRecorder.setVideoSize(video_width, video_height); 370 mRecorder.setVideoEncoder(video_encoder); 371 mRecorder.setAudioEncoder(audio_encoder); 372 mRecorder.setVideoEncodingBitRate(bit_rate); 373 Log.v(TAG, "mediaRecorder setPreview"); 374 mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); 375 mRecorder.prepare(); 376 mRecorder.start(); 377 Thread.sleep(record_duration); 378 Log.v(TAG, "Before stop"); 379 mRecorder.stop(); 380 mRecorder.release(); 381 //start the playback 382 MediaPlayer mp = new MediaPlayer(); 383 mp.setDataSource(filename); 384 mp.setDisplay(MediaFrameworkTest.mSurfaceView.getHolder()); 385 mp.prepare(); 386 mp.start(); 387 Thread.sleep(record_duration); 388 mp.release(); 389 validateRecordedVideo(filename); 390 if (remove_video) { 391 removeRecordedVideo(filename); 392 } 393 output.write(", " + i); 394 } 395 } catch (Exception e) { 396 Log.v(TAG, e.toString()); 397 assertTrue("record and playback", false); 398 } 399 output.write("\n\n"); 400 output.close(); 401 } 402 403 // Test case for stressing time lapse 404 @LargeTest 405 public void testStressTimeLapse() throws Exception { 406 SurfaceHolder mSurfaceHolder; 407 mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); 408 int record_duration = MediaRecorderStressTestRunner.mTimeLapseDuration; 409 boolean remove_video = MediaRecorderStressTestRunner.mRemoveVideo; 410 double captureRate = MediaRecorderStressTestRunner.mCaptureRate; 411 String filename; 412 File stressOutFile = new File(MEDIA_STRESS_OUTPUT); 413 Writer output = new BufferedWriter(new FileWriter(stressOutFile, true)); 414 output.write("Start camera time lapse stress:\n"); 415 output.write("Total number of loops: " + NUMBER_OF_TIME_LAPSE_LOOPS + "\n"); 416 417 try { 418 for (int j = 0, n = Camera.getNumberOfCameras(); j < n; j++) { 419 output.write("No of loop: camera " + j); 420 for (int i = 0; i < NUMBER_OF_TIME_LAPSE_LOOPS; i++) { 421 filename = OUTPUT_FILE + j + "_" + i + OUTPUT_FILE_EXT; 422 Log.v(TAG, filename); 423 runOnLooper(new Runnable() { 424 @Override 425 public void run() { 426 mRecorder = new MediaRecorder(); 427 } 428 }); 429 430 // Set callback 431 mRecorder.setOnErrorListener(mRecorderErrorCallback); 432 433 // Set video source 434 mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 435 436 // Set camcorder profile for time lapse 437 CamcorderProfile profile = 438 CamcorderProfile.get(j, CamcorderProfile.QUALITY_TIME_LAPSE_HIGH); 439 mRecorder.setProfile(profile); 440 441 // Set the timelapse setting; 0.1 = 10 sec timelapse, 0.5 = 2 sec timelapse, etc. 442 // http://developer.android.com/guide/topics/media/camera.html#time-lapse-video 443 mRecorder.setCaptureRate(captureRate); 444 445 // Set output file 446 mRecorder.setOutputFile(filename); 447 448 // Set the preview display 449 Log.v(TAG, "mediaRecorder setPreviewDisplay"); 450 mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); 451 452 mRecorder.prepare(); 453 mRecorder.start(); 454 Thread.sleep(record_duration); 455 Log.v(TAG, "Before stop"); 456 mRecorder.stop(); 457 mRecorder.release(); 458 459 // Start the playback 460 MediaPlayer mp = new MediaPlayer(); 461 mp.setDataSource(filename); 462 mp.setDisplay(mSurfaceHolder); 463 mp.prepare(); 464 mp.start(); 465 Thread.sleep(TIME_LAPSE_PLAYBACK_WAIT_TIME); 466 mp.release(); 467 validateRecordedVideo(filename); 468 if (remove_video) { 469 removeRecordedVideo(filename); 470 } 471 output.write(", " + i); 472 } 473 } 474 } 475 catch (IllegalStateException e) { 476 assertTrue("Camera time lapse stress test IllegalStateException", false); 477 Log.v(TAG, e.toString()); 478 } 479 catch (IOException e) { 480 assertTrue("Camera time lapse stress test IOException", false); 481 Log.v(TAG, e.toString()); 482 } 483 catch (Exception e) { 484 assertTrue("Camera time lapse stress test Exception", false); 485 Log.v(TAG, e.toString()); 486 } 487 output.write("\n\n"); 488 output.close(); 489 } 490} 491