/* * Copyright (C) 2009 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.mediaframeworktest.MediaFrameworkTest; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import android.hardware.Camera; import android.media.CamcorderProfile; import android.media.MediaPlayer; import android.media.MediaRecorder; import android.os.Handler; import android.os.Looper; import android.test.ActivityInstrumentationTestCase2; import android.test.suitebuilder.annotation.LargeTest; import android.util.Log; import android.view.SurfaceHolder; import com.android.mediaframeworktest.MediaRecorderStressTestRunner; /** * Junit / Instrumentation test case for the media player api */ public class MediaRecorderStressTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> { private String TAG = "MediaRecorderStressTest"; private MediaRecorder mRecorder; private Camera mCamera; private static final int NUMBER_OF_CAMERA_STRESS_LOOPS = 100; private static final int NUMBER_OF_RECORDER_STRESS_LOOPS = 100; private static final int NUMBER_OF_RECORDERANDPLAY_STRESS_LOOPS = 50; private static final int NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER = 200; private static final int NUMBER_OF_TIME_LAPSE_LOOPS = 25; private static final int TIME_LAPSE_PLAYBACK_WAIT_TIME = 5* 1000; // 5 seconds private static final long WAIT_TIME_CAMERA_TEST = 3 * 1000; // 3 seconds private static final long WAIT_TIME_RECORDER_TEST = 6 * 1000; // 6 seconds private static final String OUTPUT_FILE = "/sdcard/temp"; private static final String OUTPUT_FILE_EXT = ".3gp"; private static final String MEDIA_STRESS_OUTPUT = "/sdcard/mediaStressOutput.txt"; private final CameraErrorCallback mCameraErrorCallback = new CameraErrorCallback(); private final RecorderErrorCallback mRecorderErrorCallback = new RecorderErrorCallback(); private final static int WAIT_TIMEOUT = 10 * 1000; // 10 seconds private Thread mLooperThread; private Handler mHandler; public MediaRecorderStressTest() { super("com.android.mediaframeworktest", MediaFrameworkTest.class); } protected void setUp() throws Exception { final Semaphore sem = new Semaphore(0); mLooperThread = new Thread() { @Override public void run() { Log.v(TAG, "starting looper"); Looper.prepare(); mHandler = new Handler(); sem.release(); Looper.loop(); Log.v(TAG, "quit looper"); } }; mLooperThread.start(); if (! sem.tryAcquire(WAIT_TIMEOUT, TimeUnit.MILLISECONDS)) { fail("Failed to start the looper."); } getActivity(); super.setUp(); } @Override protected void tearDown() throws Exception { if (mHandler != null) { mHandler.getLooper().quit(); mHandler = null; } if (mLooperThread != null) { mLooperThread.join(WAIT_TIMEOUT); if (mLooperThread.isAlive()) { fail("Failed to stop the looper."); } mLooperThread = null; } super.tearDown(); } private void runOnLooper(final Runnable command) throws InterruptedException { final Semaphore sem = new Semaphore(0); mHandler.post(new Runnable() { @Override public void run() { try { command.run(); } finally { sem.release(); } } }); if (! sem.tryAcquire(WAIT_TIMEOUT, TimeUnit.MILLISECONDS)) { fail("Failed to run the command on the looper."); } } private final class CameraErrorCallback implements android.hardware.Camera.ErrorCallback { public void onError(int error, android.hardware.Camera camera) { if (error == android.hardware.Camera.CAMERA_ERROR_SERVER_DIED) { assertTrue("Camera test mediaserver died", false); } } } private final class RecorderErrorCallback implements MediaRecorder.OnErrorListener { public void onError(MediaRecorder mr, int what, int extra) { // fail the test case no matter what error come up assertTrue("mediaRecorder error", false); } } //Test case for stressing the camera preview. @LargeTest public void testStressCamera() throws Exception { SurfaceHolder mSurfaceHolder; mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); File stressOutFile = new File(MEDIA_STRESS_OUTPUT); Writer output = new BufferedWriter(new FileWriter(stressOutFile, true)); output.write("Camera start preview stress:\n"); output.write("Total number of loops:" + NUMBER_OF_CAMERA_STRESS_LOOPS + "\n"); try { Log.v(TAG, "Start preview"); output.write("No of loop: "); for (int i = 0; i< NUMBER_OF_CAMERA_STRESS_LOOPS; i++) { runOnLooper(new Runnable() { @Override public void run() { mCamera = Camera.open(); } }); mCamera.setErrorCallback(mCameraErrorCallback); mCamera.setPreviewDisplay(mSurfaceHolder); mCamera.startPreview(); Thread.sleep(WAIT_TIME_CAMERA_TEST); mCamera.stopPreview(); mCamera.release(); output.write(" ," + i); } } catch (Exception e) { assertTrue("CameraStressTest", false); Log.v(TAG, e.toString()); } output.write("\n\n"); output.close(); } //Test case for stressing the camera preview. @LargeTest public void testStressRecorder() throws Exception { String filename; SurfaceHolder mSurfaceHolder; mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); File stressOutFile = new File(MEDIA_STRESS_OUTPUT); Writer output = new BufferedWriter(new FileWriter(stressOutFile, true)); output.write("H263 video record- reset after prepare Stress test\n"); output.write("Total number of loops:" + NUMBER_OF_RECORDER_STRESS_LOOPS + "\n"); try { output.write("No of loop: "); Log.v(TAG, "Start preview"); for (int i = 0; i < NUMBER_OF_RECORDER_STRESS_LOOPS; i++) { runOnLooper(new Runnable() { @Override public void run() { mRecorder = new MediaRecorder(); } }); Log.v(TAG, "counter = " + i); filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT; Log.v(TAG, filename); mRecorder.setOnErrorListener(mRecorderErrorCallback); mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); mRecorder.setOutputFile(filename); mRecorder.setVideoFrameRate(MediaRecorderStressTestRunner.mFrameRate); mRecorder.setVideoSize(176,144); Log.v(TAG, "setEncoder"); mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263); mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); Log.v(TAG, "setPreview"); mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); Log.v(TAG, "prepare"); mRecorder.prepare(); Log.v(TAG, "before release"); Thread.sleep(WAIT_TIME_RECORDER_TEST); mRecorder.reset(); mRecorder.release(); output.write(", " + i); } } catch (Exception e) { assertTrue("Recorder Stress test", false); Log.v(TAG, e.toString()); } output.write("\n\n"); output.close(); } //Stress test case for switching camera and video recorder preview. @LargeTest public void testStressCameraSwitchRecorder() throws Exception { String filename; SurfaceHolder mSurfaceHolder; mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); File stressOutFile = new File(MEDIA_STRESS_OUTPUT); Writer output = new BufferedWriter(new FileWriter(stressOutFile, true)); output.write("Camera and video recorder preview switching\n"); output.write("Total number of loops:" + NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER + "\n"); try { Log.v(TAG, "Start preview"); output.write("No of loop: "); for (int i = 0; i < NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER; i++) { runOnLooper(new Runnable() { @Override public void run() { mCamera = Camera.open(); } }); mCamera.setErrorCallback(mCameraErrorCallback); mCamera.setPreviewDisplay(mSurfaceHolder); mCamera.startPreview(); Thread.sleep(WAIT_TIME_CAMERA_TEST); mCamera.stopPreview(); mCamera.release(); mCamera = null; Log.v(TAG, "release camera"); filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT; Log.v(TAG, filename); runOnLooper(new Runnable() { @Override public void run() { mRecorder = new MediaRecorder(); } }); mRecorder.setOnErrorListener(mRecorderErrorCallback); mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); mRecorder.setOutputFile(filename); mRecorder.setVideoFrameRate(MediaRecorderStressTestRunner.mFrameRate); mRecorder.setVideoSize(176,144); Log.v(TAG, "Media recorder setEncoder"); mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263); Log.v(TAG, "mediaRecorder setPreview"); mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); Log.v(TAG, "prepare"); mRecorder.prepare(); Log.v(TAG, "before release"); Thread.sleep(WAIT_TIME_CAMERA_TEST); mRecorder.release(); Log.v(TAG, "release video recorder"); output.write(", " + i); } } catch (Exception e) { assertTrue("Camer and recorder switch mode", false); Log.v(TAG, e.toString()); } output.write("\n\n"); output.close(); } public void validateRecordedVideo(String recorded_file) { try { MediaPlayer mp = new MediaPlayer(); mp.setDataSource(recorded_file); mp.prepare(); int duration = mp.getDuration(); if (duration <= 0){ assertTrue("stressRecordAndPlayback", false); } mp.release(); } catch (Exception e) { assertTrue("stressRecordAndPlayback", false); } } public void removeRecordedVideo(String filename){ File video = new File(filename); Log.v(TAG, "remove recorded video " + filename); video.delete(); } //Stress test case for record a video and play right away. @LargeTest public void testStressRecordVideoAndPlayback() throws Exception { int iterations = MediaRecorderStressTestRunner.mIterations; int video_encoder = MediaRecorderStressTestRunner.mVideoEncoder; int audio_encoder = MediaRecorderStressTestRunner.mAudioEncdoer; int frame_rate = MediaRecorderStressTestRunner.mFrameRate; int video_width = MediaRecorderStressTestRunner.mVideoWidth; int video_height = MediaRecorderStressTestRunner.mVideoHeight; int bit_rate = MediaRecorderStressTestRunner.mBitRate; boolean remove_video = MediaRecorderStressTestRunner.mRemoveVideo; int record_duration = MediaRecorderStressTestRunner.mDuration; String filename; SurfaceHolder mSurfaceHolder; mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); File stressOutFile = new File(MEDIA_STRESS_OUTPUT); Writer output = new BufferedWriter( new FileWriter(stressOutFile, true)); output.write("Video record and play back stress test:\n"); output.write("Total number of loops:" + NUMBER_OF_RECORDERANDPLAY_STRESS_LOOPS + "\n"); try { output.write("No of loop: "); for (int i = 0; i < iterations; i++){ filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT; Log.v(TAG, filename); runOnLooper(new Runnable() { @Override public void run() { mRecorder = new MediaRecorder(); } }); Log.v(TAG, "iterations : " + iterations); Log.v(TAG, "video_encoder : " + video_encoder); Log.v(TAG, "audio_encoder : " + audio_encoder); Log.v(TAG, "frame_rate : " + frame_rate); Log.v(TAG, "video_width : " + video_width); Log.v(TAG, "video_height : " + video_height); Log.v(TAG, "bit rate : " + bit_rate); Log.v(TAG, "record_duration : " + record_duration); mRecorder.setOnErrorListener(mRecorderErrorCallback); mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); mRecorder.setOutputFile(filename); mRecorder.setVideoFrameRate(frame_rate); mRecorder.setVideoSize(video_width, video_height); mRecorder.setVideoEncoder(video_encoder); mRecorder.setAudioEncoder(audio_encoder); mRecorder.setVideoEncodingBitRate(bit_rate); Log.v(TAG, "mediaRecorder setPreview"); mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); mRecorder.prepare(); mRecorder.start(); Thread.sleep(record_duration); Log.v(TAG, "Before stop"); mRecorder.stop(); mRecorder.release(); //start the playback MediaPlayer mp = new MediaPlayer(); mp.setDataSource(filename); mp.setDisplay(MediaFrameworkTest.mSurfaceView.getHolder()); mp.prepare(); mp.start(); Thread.sleep(record_duration); mp.release(); validateRecordedVideo(filename); if (remove_video) { removeRecordedVideo(filename); } output.write(", " + i); } } catch (Exception e) { Log.v(TAG, e.toString()); assertTrue("record and playback", false); } output.write("\n\n"); output.close(); } // Test case for stressing time lapse @LargeTest public void testStressTimeLapse() throws Exception { SurfaceHolder mSurfaceHolder; mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); int record_duration = MediaRecorderStressTestRunner.mTimeLapseDuration; boolean remove_video = MediaRecorderStressTestRunner.mRemoveVideo; double captureRate = MediaRecorderStressTestRunner.mCaptureRate; String filename; File stressOutFile = new File(MEDIA_STRESS_OUTPUT); Writer output = new BufferedWriter(new FileWriter(stressOutFile, true)); output.write("Start camera time lapse stress:\n"); output.write("Total number of loops: " + NUMBER_OF_TIME_LAPSE_LOOPS + "\n"); try { output.write("No of loop: "); for (int i = 0; i < NUMBER_OF_TIME_LAPSE_LOOPS; i++) { filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT; Log.v(TAG, filename); runOnLooper(new Runnable() { @Override public void run() { mRecorder = new MediaRecorder(); } }); // Set callback mRecorder.setOnErrorListener(mRecorderErrorCallback); // Set video source mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); // Set camcorder profile for time lapse CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH); mRecorder.setProfile(profile); // Set the timelapse setting; 0.1 = 10 sec timelapse, 0.5 = 2 sec timelapse, etc. // http://developer.android.com/guide/topics/media/camera.html#time-lapse-video mRecorder.setCaptureRate(captureRate); // Set output file mRecorder.setOutputFile(filename); // Set the preview display Log.v(TAG, "mediaRecorder setPreviewDisplay"); mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); mRecorder.prepare(); mRecorder.start(); Thread.sleep(record_duration); Log.v(TAG, "Before stop"); mRecorder.stop(); mRecorder.release(); // Start the playback MediaPlayer mp = new MediaPlayer(); mp.setDataSource(filename); mp.setDisplay(mSurfaceHolder); mp.prepare(); mp.start(); Thread.sleep(TIME_LAPSE_PLAYBACK_WAIT_TIME); mp.release(); validateRecordedVideo(filename); if(remove_video) { removeRecordedVideo(filename); } output.write(", " + i); } } catch (IllegalStateException e) { assertTrue("Camera time lapse stress test IllegalStateException", false); Log.v(TAG, e.toString()); } catch (IOException e) { assertTrue("Camera time lapse stress test IOException", false); Log.v(TAG, e.toString()); } catch (Exception e) { assertTrue("Camera time lapse stress test Exception", false); Log.v(TAG, e.toString()); } output.write("\n\n"); output.close(); } }