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