MediaPlayerPerformance.java revision 003a7569745640d700c318a463385ca5feb08728
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17package com.android.mediaframeworktest.performance; 18 19import com.android.mediaframeworktest.MediaFrameworkTest; 20import com.android.mediaframeworktest.MediaFrameworkPerfTestRunner; 21import com.android.mediaframeworktest.MediaNames; 22import com.android.mediaframeworktest.MediaTestUtil; 23 24import android.database.sqlite.SQLiteDatabase; 25import android.hardware.Camera; 26import android.hardware.Camera.PreviewCallback; 27import android.media.MediaPlayer; 28import android.media.MediaRecorder; 29import android.media.EncoderCapabilities.VideoEncoderCap; 30import android.os.ConditionVariable; 31import android.os.Looper; 32import android.os.SystemClock; 33import android.test.ActivityInstrumentationTestCase2; 34import android.test.suitebuilder.annotation.LargeTest; 35import android.test.suitebuilder.annotation.Suppress; 36import android.util.Log; 37import android.view.SurfaceHolder; 38 39import java.util.List; 40import java.io.BufferedReader; 41import java.io.FileDescriptor; 42import java.io.FileInputStream; 43import java.io.FileOutputStream; 44import java.io.IOException; 45import java.io.InputStream; 46import java.io.InputStreamReader; 47import java.io.Writer; 48import java.io.File; 49import java.io.FileWriter; 50import java.io.BufferedWriter; 51 52import android.media.MediaMetadataRetriever; 53import com.android.mediaframeworktest.MediaProfileReader; 54 55/** 56 * Junit / Instrumentation - performance measurement for media player and 57 * recorder 58 * 59 * FIXME: 60 * Add tests on H264 video encoder 61 */ 62public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<MediaFrameworkTest> { 63 64 private String TAG = "MediaPlayerPerformance"; 65 66 private SQLiteDatabase mDB; 67 private SurfaceHolder mSurfaceHolder = null; 68 private static final int NUM_STRESS_LOOP = 10; 69 private static final int NUM_PLAYBACk_IN_EACH_LOOP = 20; 70 private static final long MEDIA_STRESS_WAIT_TIME = 5000; //5 seconds 71 private static final String MEDIA_MEMORY_OUTPUT = 72 "/sdcard/mediaMemOutput.txt"; 73 private static final String MEDIA_PROCMEM_OUTPUT = 74 "/sdcard/mediaProcmemOutput.txt"; 75 76 private static int mStartMemory = 0; 77 private static int mEndMemory = 0; 78 private static int mStartPid = 0; 79 private static int mEndPid = 0; 80 81 private Looper mLooper = null; 82 private RawPreviewCallback mRawPreviewCallback = new RawPreviewCallback(); 83 private final ConditionVariable mPreviewDone = new ConditionVariable(); 84 private static int WAIT_FOR_COMMAND_TO_COMPLETE = 10000; // Milliseconds. 85 86 //the tolerant memory leak 87 private static int ENCODER_LIMIT = 150; 88 private static int DECODER_LIMIT = 150; 89 private static int CAMERA_LIMIT = 80; 90 91 private Writer mProcMemWriter; 92 private Writer mMemWriter; 93 94 private static List<VideoEncoderCap> videoEncoders = MediaProfileReader.getVideoEncoders(); 95 96 Camera mCamera; 97 98 public MediaPlayerPerformance() { 99 super("com.android.mediaframeworktest", MediaFrameworkTest.class); 100 } 101 102 protected void setUp() throws Exception { 103 super.setUp(); 104 //Insert a 2 second before launching the test activity. This is 105 //the workaround for the race condition of requesting the updated surface. 106 Thread.sleep(2000); 107 getActivity(); 108 if (MediaFrameworkPerfTestRunner.mGetNativeHeapDump) 109 MediaTestUtil.getNativeHeapDump(this.getName() + "_before"); 110 111 mProcMemWriter = new BufferedWriter(new FileWriter 112 (new File(MEDIA_PROCMEM_OUTPUT), true)); 113 mProcMemWriter.write(this.getName() + "\n"); 114 mMemWriter = new BufferedWriter(new FileWriter 115 (new File(MEDIA_MEMORY_OUTPUT), true)); 116 117 } 118 119 protected void tearDown() throws Exception { 120 if (MediaFrameworkPerfTestRunner.mGetNativeHeapDump) 121 MediaTestUtil.getNativeHeapDump(this.getName() + "_after"); 122 mProcMemWriter.close(); 123 mMemWriter.close(); 124 super.tearDown(); 125 } 126 127 private void initializeMessageLooper() { 128 final ConditionVariable startDone = new ConditionVariable(); 129 new Thread() { 130 @Override 131 public void run() { 132 Looper.prepare(); 133 Log.v(TAG, "start loopRun"); 134 mLooper = Looper.myLooper(); 135 mCamera = Camera.open(); 136 startDone.open(); 137 Looper.loop(); 138 Log.v(TAG, "initializeMessageLooper: quit."); 139 } 140 }.start(); 141 142 if (!startDone.block(WAIT_FOR_COMMAND_TO_COMPLETE)) { 143 fail("initializeMessageLooper: start timeout"); 144 } 145 } 146 147 private void terminateMessageLooper() throws Exception { 148 mLooper.quit(); 149 // Looper.quit() is asynchronous. The looper may still has some 150 // preview callbacks in the queue after quit is called. The preview 151 // callback still uses the camera object (setHasPreviewCallback). 152 // After camera is released, RuntimeException will be thrown from 153 // the method. So we need to join the looper thread here. 154 mLooper.getThread().join(); 155 mCamera.release(); 156 } 157 158 private final class RawPreviewCallback implements PreviewCallback { 159 public void onPreviewFrame(byte[] rawData, Camera camera) { 160 mPreviewDone.open(); 161 } 162 } 163 164 private void waitForPreviewDone() { 165 if (!mPreviewDone.block(WAIT_FOR_COMMAND_TO_COMPLETE)) { 166 Log.v(TAG, "waitForPreviewDone: timeout"); 167 } 168 mPreviewDone.close(); 169 } 170 171 public void stressCameraPreview() { 172 for (int i = 0; i < NUM_PLAYBACk_IN_EACH_LOOP; i++) { 173 try { 174 initializeMessageLooper(); 175 mCamera.setPreviewCallback(mRawPreviewCallback); 176 mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); 177 mCamera.setPreviewDisplay(mSurfaceHolder); 178 mCamera.startPreview(); 179 waitForPreviewDone(); 180 Thread.sleep(1000); 181 mCamera.stopPreview(); 182 terminateMessageLooper(); 183 } catch (Exception e) { 184 Log.v(TAG, e.toString()); 185 } 186 } 187 } 188 189 // Note: This test is to assume the mediaserver's pid is 34 190 public void mediaStressPlayback(String testFilePath) { 191 for (int i = 0; i < NUM_PLAYBACk_IN_EACH_LOOP; i++) { 192 MediaPlayer mp = new MediaPlayer(); 193 try { 194 mp.setDataSource(testFilePath); 195 mp.setDisplay(MediaFrameworkTest.mSurfaceView.getHolder()); 196 mp.prepare(); 197 mp.start(); 198 Thread.sleep(MEDIA_STRESS_WAIT_TIME); 199 mp.release(); 200 } catch (Exception e) { 201 mp.release(); 202 Log.v(TAG, e.toString()); 203 } 204 } 205 } 206 207 // Note: This test is to assume the mediaserver's pid is 34 208 private boolean stressVideoRecord(int frameRate, int width, int height, int videoFormat, 209 int outFormat, String outFile, boolean videoOnly) { 210 // Video recording 211 boolean doesTestFail = false; 212 for (int i = 0; i < NUM_PLAYBACk_IN_EACH_LOOP; i++) { 213 MediaRecorder mRecorder = new MediaRecorder(); 214 try { 215 if (!videoOnly) { 216 Log.v(TAG, "setAudioSource"); 217 mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); 218 } 219 mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 220 mRecorder.setOutputFormat(outFormat); 221 Log.v(TAG, "output format " + outFormat); 222 mRecorder.setOutputFile(outFile); 223 mRecorder.setVideoFrameRate(frameRate); 224 mRecorder.setVideoSize(width, height); 225 Log.v(TAG, "setEncoder"); 226 mRecorder.setVideoEncoder(videoFormat); 227 if (!videoOnly) { 228 mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); 229 } 230 mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); 231 mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); 232 mRecorder.prepare(); 233 mRecorder.start(); 234 Thread.sleep(MEDIA_STRESS_WAIT_TIME); 235 mRecorder.stop(); 236 mRecorder.release(); 237 } catch (Exception e) { 238 Log.v("record video failed ", e.toString()); 239 mRecorder.release(); 240 doesTestFail = true; 241 break; 242 } 243 } 244 return !doesTestFail; 245 } 246 247 public void stressAudioRecord(String filePath) { 248 // This test is only for the short media file 249 for (int i = 0; i < NUM_PLAYBACk_IN_EACH_LOOP; i++) { 250 MediaRecorder mRecorder = new MediaRecorder(); 251 try { 252 mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); 253 mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); 254 mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); 255 mRecorder.setOutputFile(filePath); 256 mRecorder.prepare(); 257 mRecorder.start(); 258 Thread.sleep(MEDIA_STRESS_WAIT_TIME); 259 mRecorder.stop(); 260 mRecorder.release(); 261 } catch (Exception e) { 262 Log.v(TAG, e.toString()); 263 mRecorder.release(); 264 } 265 } 266 } 267 268 //Write the ps output to the file 269 public void getMemoryWriteToLog(int writeCount) { 270 String memusage = null; 271 try { 272 if (writeCount == 0) { 273 mStartMemory = getMediaserverVsize(); 274 mMemWriter.write("Start memory : " + mStartMemory + "\n"); 275 } 276 memusage = captureMediaserverInfo(); 277 mMemWriter.write(memusage); 278 if (writeCount == NUM_STRESS_LOOP - 1) { 279 mEndMemory = getMediaserverVsize(); 280 mMemWriter.write("End Memory :" + mEndMemory + "\n"); 281 } 282 } catch (Exception e) { 283 e.toString(); 284 } 285 } 286 287 public void writeProcmemInfo() throws Exception{ 288 String cmd = "procmem " + getMediaserverPid(); 289 Process p = Runtime.getRuntime().exec(cmd); 290 291 InputStream inStream = p.getInputStream(); 292 InputStreamReader inReader = new InputStreamReader(inStream); 293 BufferedReader inBuffer = new BufferedReader(inReader); 294 String s; 295 while ((s = inBuffer.readLine()) != null) { 296 mProcMemWriter.write(s); 297 mProcMemWriter.write("\n"); 298 } 299 mProcMemWriter.write("\n\n"); 300 } 301 302 public String captureMediaserverInfo() { 303 String cm = "ps mediaserver"; 304 String memoryUsage = null; 305 306 int ch; 307 try { 308 Process p = Runtime.getRuntime().exec(cm); 309 InputStream in = p.getInputStream(); 310 StringBuffer sb = new StringBuffer(512); 311 while ((ch = in.read()) != -1) { 312 sb.append((char) ch); 313 } 314 memoryUsage = sb.toString(); 315 } catch (IOException e) { 316 Log.v(TAG, e.toString()); 317 } 318 String[] poList = memoryUsage.split("\r|\n|\r\n"); 319 String memusage = poList[1].concat("\n"); 320 return memusage; 321 } 322 323 public int getMediaserverPid(){ 324 String memoryUsage = null; 325 int pidvalue = 0; 326 memoryUsage = captureMediaserverInfo(); 327 String[] poList2 = memoryUsage.split("\t|\\s+"); 328 String pid = poList2[1]; 329 pidvalue = Integer.parseInt(pid); 330 Log.v(TAG, "PID = " + pidvalue); 331 return pidvalue; 332 } 333 334 public int getMediaserverVsize(){ 335 String memoryUsage = captureMediaserverInfo(); 336 String[] poList2 = memoryUsage.split("\t|\\s+"); 337 String vsize = poList2[3]; 338 int vsizevalue = Integer.parseInt(vsize); 339 Log.v(TAG, "VSIZE = " + vsizevalue); 340 return vsizevalue; 341 } 342 343 public boolean validateMemoryResult(int startPid, int startMemory, int limit) 344 throws Exception { 345 // Wait for 10 seconds to make sure the memory settle. 346 Thread.sleep(10000); 347 mEndPid = getMediaserverPid(); 348 int memDiff = mEndMemory - startMemory; 349 if (memDiff < 0) { 350 memDiff = 0; 351 } 352 mMemWriter.write("The total diff = " + memDiff); 353 mMemWriter.write("\n\n"); 354 // mediaserver crash 355 if (startPid != mEndPid) { 356 mMemWriter.write("mediaserver died. Test failed\n"); 357 return false; 358 } 359 // memory leak greter than the tolerant 360 if (memDiff > limit) return false; 361 return true; 362 } 363 364 // Test case 1: Capture the memory usage after every 20 h263 playback 365 @LargeTest 366 public void testH263VideoPlaybackMemoryUsage() throws Exception { 367 boolean memoryResult = false; 368 369 mStartPid = getMediaserverPid(); 370 mMemWriter.write("H263 Video Playback Only\n"); 371 for (int i = 0; i < NUM_STRESS_LOOP; i++) { 372 mediaStressPlayback(MediaNames.VIDEO_HIGHRES_H263); 373 getMemoryWriteToLog(i); 374 writeProcmemInfo(); 375 } 376 mMemWriter.write("\n"); 377 memoryResult = validateMemoryResult(mStartPid, mStartMemory, DECODER_LIMIT); 378 assertTrue("H263 playback memory test", memoryResult); 379 } 380 381 // Test case 2: Capture the memory usage after every 20 h264 playback 382 @LargeTest 383 public void testH264VideoPlaybackMemoryUsage() throws Exception { 384 boolean memoryResult = false; 385 386 mStartPid = getMediaserverPid(); 387 mMemWriter.write("H264 Video Playback only\n"); 388 for (int i = 0; i < NUM_STRESS_LOOP; i++) { 389 mediaStressPlayback(MediaNames.VIDEO_H264_AMR); 390 getMemoryWriteToLog(i); 391 writeProcmemInfo(); 392 } 393 mMemWriter.write("\n"); 394 memoryResult = validateMemoryResult(mStartPid, mStartMemory, DECODER_LIMIT); 395 assertTrue("H264 playback memory test", memoryResult); 396 } 397 398 // Test case 4: Capture the memory usage after every 20 video only recorded 399 @LargeTest 400 public void testH263RecordVideoOnlyMemoryUsage() throws Exception { 401 boolean memoryResult = false; 402 403 mStartPid = getMediaserverPid(); 404 mMemWriter.write("H263 video record only\n"); 405 int frameRate = MediaProfileReader.getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.H263); 406 assertTrue("H263 video recording frame rate", frameRate != -1); 407 for (int i = 0; i < NUM_STRESS_LOOP; i++) { 408 assertTrue(stressVideoRecord(frameRate, 352, 288, MediaRecorder.VideoEncoder.H263, 409 MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true)); 410 getMemoryWriteToLog(i); 411 writeProcmemInfo(); 412 } 413 mMemWriter.write("\n"); 414 memoryResult = validateMemoryResult(mStartPid, mStartMemory, ENCODER_LIMIT); 415 assertTrue("H263 record only memory test", memoryResult); 416 } 417 418 // Test case 5: Capture the memory usage after every 20 video only recorded 419 @LargeTest 420 public void testMpeg4RecordVideoOnlyMemoryUsage() throws Exception { 421 boolean memoryResult = false; 422 423 mStartPid = getMediaserverPid(); 424 mMemWriter.write("MPEG4 video record only\n"); 425 int frameRate = MediaProfileReader.getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.MPEG_4_SP); 426 assertTrue("MPEG4 video recording frame rate", frameRate != -1); 427 for (int i = 0; i < NUM_STRESS_LOOP; i++) { 428 assertTrue(stressVideoRecord(frameRate, 352, 288, MediaRecorder.VideoEncoder.MPEG_4_SP, 429 MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true)); 430 getMemoryWriteToLog(i); 431 writeProcmemInfo(); 432 } 433 mMemWriter.write("\n"); 434 memoryResult = validateMemoryResult(mStartPid, mStartMemory, ENCODER_LIMIT); 435 assertTrue("mpeg4 record only memory test", memoryResult); 436 } 437 438 // Test case 6: Capture the memory usage after every 20 video and audio 439 // recorded 440 @LargeTest 441 public void testRecordVideoAudioMemoryUsage() throws Exception { 442 boolean memoryResult = false; 443 444 mStartPid = getMediaserverPid(); 445 int frameRate = MediaProfileReader.getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.H263); 446 assertTrue("H263 video recording frame rate", frameRate != -1); 447 mMemWriter.write("Audio and h263 video record\n"); 448 for (int i = 0; i < NUM_STRESS_LOOP; i++) { 449 assertTrue(stressVideoRecord(frameRate, 352, 288, MediaRecorder.VideoEncoder.H263, 450 MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, false)); 451 getMemoryWriteToLog(i); 452 writeProcmemInfo(); 453 } 454 mMemWriter.write("\n"); 455 memoryResult = validateMemoryResult(mStartPid, mStartMemory, ENCODER_LIMIT); 456 assertTrue("H263 audio video record memory test", memoryResult); 457 } 458 459 // Test case 7: Capture the memory usage after every 20 audio only recorded 460 @LargeTest 461 public void testRecordAudioOnlyMemoryUsage() throws Exception { 462 boolean memoryResult = false; 463 464 mStartPid = getMediaserverPid(); 465 mMemWriter.write("Audio record only\n"); 466 for (int i = 0; i < NUM_STRESS_LOOP; i++) { 467 stressAudioRecord(MediaNames.RECORDER_OUTPUT); 468 getMemoryWriteToLog(i); 469 writeProcmemInfo(); 470 } 471 mMemWriter.write("\n"); 472 memoryResult = validateMemoryResult(mStartPid, mStartMemory, ENCODER_LIMIT); 473 assertTrue("audio record only memory test", memoryResult); 474 } 475 476 // Test case 8: Capture the memory usage after every 20 camera preview 477 @LargeTest 478 public void testCameraPreviewMemoryUsage() throws Exception { 479 boolean memoryResult = false; 480 481 mStartPid = getMediaserverPid(); 482 mMemWriter.write("Camera Preview Only\n"); 483 for (int i = 0; i < NUM_STRESS_LOOP; i++) { 484 stressCameraPreview(); 485 getMemoryWriteToLog(i); 486 writeProcmemInfo(); 487 } 488 mMemWriter.write("\n"); 489 memoryResult = validateMemoryResult(mStartPid, mStartMemory, CAMERA_LIMIT); 490 assertTrue("camera preview memory test", memoryResult); 491 } 492} 493