MediaPlayerPerformance.java revision 30a13908197c03c7f660f443064575c7baa889bb
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.MediaNames; 21 22import android.database.sqlite.SQLiteDatabase; 23import android.hardware.Camera; 24import android.hardware.Camera.PreviewCallback; 25import android.media.MediaPlayer; 26import android.media.MediaRecorder; 27import android.os.Looper; 28import android.os.SystemClock; 29import android.test.ActivityInstrumentationTestCase; 30import android.test.suitebuilder.annotation.LargeTest; 31import android.test.suitebuilder.annotation.Suppress; 32import android.util.Log; 33import android.view.SurfaceHolder; 34 35import java.io.FileDescriptor; 36import java.io.FileInputStream; 37import java.io.FileOutputStream; 38import java.io.IOException; 39import java.io.InputStream; 40import java.io.Writer; 41import java.io.File; 42import java.io.FileWriter; 43import java.io.BufferedWriter; 44 45import android.media.MediaMetadataRetriever; 46import com.android.mediaframeworktest.MediaProfileReader; 47 48import android.hardware.Camera.PreviewCallback; 49 50/** 51 * Junit / Instrumentation - performance measurement for media player and 52 * recorder 53 */ 54public class MediaPlayerPerformance extends ActivityInstrumentationTestCase<MediaFrameworkTest> { 55 56 private String TAG = "MediaPlayerPerformance"; 57 58 private SQLiteDatabase mDB; 59 private SurfaceHolder mSurfaceHolder = null; 60 private static final int NUM_STRESS_LOOP = 10; 61 private static final int NUM_PLAYBACk_IN_EACH_LOOP = 20; 62 private static final long MEDIA_STRESS_WAIT_TIME = 5000; //5 seconds 63 private static final String MEDIA_MEMORY_OUTPUT = 64 "/sdcard/mediaMemOutput.txt"; 65 66 private static int mStartMemory = 0; 67 private static int mEndMemory = 0; 68 private static int mStartPid = 0; 69 private static int mEndPid = 0; 70 71 private boolean mInitialized = false; 72 private Looper mLooper = null; 73 private RawPreviewCallback mRawPreviewCallback = new RawPreviewCallback(); 74 private final Object lock = new Object(); 75 private final Object previewDone = new Object(); 76 private static int WAIT_FOR_COMMAND_TO_COMPLETE = 10000; // Milliseconds. 77 78 //the tolerant memory leak 79 private static int ENCODER_LIMIT = 150; 80 private static int DECODER_LIMIT = 150; 81 private static int CAMERA_LIMIT = 80; 82 83 Camera mCamera; 84 85 public MediaPlayerPerformance() { 86 super("com.android.mediaframeworktest", MediaFrameworkTest.class); 87 } 88 89 protected void setUp() throws Exception { 90 super.setUp(); 91 } 92 93 public void createDB() { 94 mDB = SQLiteDatabase.openOrCreateDatabase("/sdcard/perf.db", null); 95 mDB.execSQL("CREATE TABLE IF NOT EXISTS perfdata (_id INTEGER PRIMARY KEY," + 96 "file TEXT," + "setdatatime LONG," + "preparetime LONG," + 97 "playtime LONG" + ");"); 98 //clean the table before adding new data 99 mDB.execSQL("DELETE FROM perfdata"); 100 } 101 102 public void audioPlaybackStartupTime(String[] testFile) { 103 long t1 = 0; 104 long t2 = 0; 105 long t3 = 0; 106 long t4 = 0; 107 long setDataSourceDuration = 0; 108 long prepareDuration = 0; 109 long startDuration = 0; 110 long totalSetDataTime = 0; 111 long totalPrepareTime = 0; 112 long totalStartDuration = 0; 113 114 int numberOfFiles = testFile.length; 115 Log.v(TAG, "File length " + numberOfFiles); 116 for (int k = 0; k < numberOfFiles; k++) { 117 MediaPlayer mp = new MediaPlayer(); 118 try { 119 t1 = SystemClock.uptimeMillis(); 120 FileInputStream fis = new FileInputStream(testFile[k]); 121 FileDescriptor fd = fis.getFD(); 122 mp.setDataSource(fd); 123 fis.close(); 124 t2 = SystemClock.uptimeMillis(); 125 mp.prepare(); 126 t3 = SystemClock.uptimeMillis(); 127 mp.start(); 128 t4 = SystemClock.uptimeMillis(); 129 } catch (Exception e) { 130 Log.v(TAG, e.toString()); 131 } 132 setDataSourceDuration = t2 - t1; 133 prepareDuration = t3 - t2; 134 startDuration = t4 - t3; 135 totalSetDataTime = totalSetDataTime + setDataSourceDuration; 136 totalPrepareTime = totalPrepareTime + prepareDuration; 137 totalStartDuration = totalStartDuration + startDuration; 138 mDB.execSQL("INSERT INTO perfdata (file, setdatatime, preparetime," + 139 " playtime) VALUES (" + '"' + testFile[k] + '"' + ',' + 140 setDataSourceDuration + ',' + prepareDuration + 141 ',' + startDuration + ");"); 142 Log.v(TAG, "File name " + testFile[k]); 143 mp.stop(); 144 mp.release(); 145 } 146 Log.v(TAG, "setDataSource average " + totalSetDataTime / numberOfFiles); 147 Log.v(TAG, "prepare average " + totalPrepareTime / numberOfFiles); 148 Log.v(TAG, "start average " + totalStartDuration / numberOfFiles); 149 150 } 151 152 @Suppress 153 public void testStartUpTime() throws Exception { 154 createDB(); 155 audioPlaybackStartupTime(MediaNames.MP3FILES); 156 audioPlaybackStartupTime(MediaNames.AACFILES); 157 158 //close the database after all transactions 159 if (mDB.isOpen()) { 160 mDB.close(); 161 } 162 } 163 164 public void wmametadatautility(String[] testFile) { 165 long t1 = 0; 166 long t2 = 0; 167 long sum = 0; 168 long duration = 0; 169 MediaMetadataRetriever retriever = new MediaMetadataRetriever(); 170 String value; 171 for (int i = 0, n = testFile.length; i < n; ++i) { 172 try { 173 t1 = SystemClock.uptimeMillis(); 174 retriever.setDataSource(testFile[i]); 175 value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM); 176 value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST); 177 value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_COMPOSER); 178 value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE); 179 value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE); 180 value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_YEAR); 181 value = 182 retriever 183 .extractMetadata(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER); 184 t2 = SystemClock.uptimeMillis(); 185 duration = t2 - t1; 186 Log.v(TAG, "Time taken = " + duration); 187 sum = sum + duration; 188 } catch (Exception e) { 189 Log.v(TAG, e.getMessage()); 190 } 191 192 } 193 Log.v(TAG, "Average duration = " + sum / testFile.length); 194 } 195 196 private void initializeMessageLooper() { 197 new Thread() { 198 @Override 199 public void run() { 200 Looper.prepare(); 201 Log.v(TAG, "start loopRun"); 202 mLooper = Looper.myLooper(); 203 mCamera = Camera.open(); 204 synchronized (lock) { 205 mInitialized = true; 206 lock.notify(); 207 } 208 Looper.loop(); 209 Log.v(TAG, "initializeMessageLooper: quit."); 210 } 211 }.start(); 212 } 213 214 private void terminateMessageLooper() { 215 mLooper.quit(); 216 mCamera.release(); 217 } 218 219 private final class RawPreviewCallback implements PreviewCallback { 220 public void onPreviewFrame(byte[] rawData, Camera camera) { 221 synchronized (previewDone) { 222 previewDone.notify(); 223 } 224 } 225 } 226 227 public void stressCameraPreview() { 228 try { 229 synchronized (lock) { 230 initializeMessageLooper(); 231 try { 232 lock.wait(WAIT_FOR_COMMAND_TO_COMPLETE); 233 } catch (Exception e) { 234 Log.v(TAG, "runTestOnMethod: wait was interrupted."); 235 } 236 } 237 mCamera.setPreviewCallback(mRawPreviewCallback); 238 mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); 239 mCamera.setPreviewDisplay(mSurfaceHolder); 240 mCamera.startPreview(); 241 synchronized (previewDone) { 242 try { 243 previewDone.wait(WAIT_FOR_COMMAND_TO_COMPLETE); 244 Log.v(TAG, "Preview Done"); 245 } catch (Exception e) { 246 Log.v(TAG, "wait was interrupted."); 247 } 248 } 249 Thread.sleep(1000); 250 mCamera.stopPreview(); 251 terminateMessageLooper(); 252 } catch (Exception e) { 253 Log.v(TAG, e.toString()); 254 } 255 } 256 257 // Note: This test is to assume the mediaserver's pid is 34 258 public void mediaStressPlayback(String testFilePath) { 259 for (int i = 0; i < NUM_PLAYBACk_IN_EACH_LOOP; i++) { 260 MediaPlayer mp = new MediaPlayer(); 261 try { 262 mp.setDataSource(testFilePath); 263 mp.setDisplay(MediaFrameworkTest.mSurfaceView.getHolder()); 264 mp.prepare(); 265 mp.start(); 266 Thread.sleep(MEDIA_STRESS_WAIT_TIME); 267 mp.release(); 268 } catch (Exception e) { 269 mp.release(); 270 Log.v(TAG, e.toString()); 271 } 272 } 273 } 274 275 // Note: This test is to assume the mediaserver's pid is 34 276 private void stressVideoRecord(int frameRate, int width, int height, int videoFormat, 277 int outFormat, String outFile, boolean videoOnly) { 278 // Video recording 279 for (int i = 0; i < NUM_PLAYBACk_IN_EACH_LOOP; i++) { 280 MediaRecorder mRecorder = new MediaRecorder(); 281 try { 282 if (!videoOnly) { 283 Log.v(TAG, "setAudioSource"); 284 mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); 285 } 286 mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 287 mRecorder.setOutputFormat(outFormat); 288 Log.v(TAG, "output format " + outFormat); 289 mRecorder.setOutputFile(outFile); 290 mRecorder.setVideoFrameRate(frameRate); 291 mRecorder.setVideoSize(width, height); 292 Log.v(TAG, "setEncoder"); 293 mRecorder.setVideoEncoder(videoFormat); 294 if (!videoOnly) { 295 mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); 296 } 297 mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); 298 mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); 299 mRecorder.prepare(); 300 mRecorder.start(); 301 Thread.sleep(MEDIA_STRESS_WAIT_TIME); 302 mRecorder.stop(); 303 mRecorder.release(); 304 } catch (Exception e) { 305 Log.v("record video failed ", e.toString()); 306 mRecorder.release(); 307 } 308 } 309 } 310 311 public void stressAudioRecord(String filePath) { 312 // This test is only for the short media file 313 for (int i = 0; i < NUM_PLAYBACk_IN_EACH_LOOP; i++) { 314 MediaRecorder mRecorder = new MediaRecorder(); 315 try { 316 mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); 317 mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); 318 mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); 319 mRecorder.setOutputFile(filePath); 320 mRecorder.prepare(); 321 mRecorder.start(); 322 Thread.sleep(MEDIA_STRESS_WAIT_TIME); 323 mRecorder.stop(); 324 mRecorder.release(); 325 } catch (Exception e) { 326 Log.v(TAG, e.toString()); 327 mRecorder.release(); 328 } 329 } 330 } 331 332 //Write the ps output to the file 333 public void getMemoryWriteToLog(Writer output, int writeCount) { 334 String memusage = null; 335 try { 336 if (writeCount == 0) { 337 mStartMemory = getMediaserverVsize(); 338 output.write("Start memory : " + mStartMemory + "\n"); 339 } 340 memusage = captureMediaserverInfo(); 341 output.write(memusage); 342 if (writeCount == NUM_STRESS_LOOP - 1) { 343 mEndMemory = getMediaserverVsize(); 344 output.write("End Memory :" + mEndMemory + "\n"); 345 } 346 } catch (Exception e) { 347 e.toString(); 348 } 349 } 350 351 public String captureMediaserverInfo() { 352 String cm = "ps mediaserver"; 353 String memoryUsage = null; 354 355 int ch; 356 try { 357 Process p = Runtime.getRuntime().exec(cm); 358 InputStream in = p.getInputStream(); 359 StringBuffer sb = new StringBuffer(512); 360 while ((ch = in.read()) != -1) { 361 sb.append((char) ch); 362 } 363 memoryUsage = sb.toString(); 364 } catch (IOException e) { 365 Log.v(TAG, e.toString()); 366 } 367 String[] poList = memoryUsage.split("\r|\n|\r\n"); 368 String memusage = poList[1].concat("\n"); 369 return memusage; 370 } 371 372 public int getMediaserverPid(){ 373 String memoryUsage = null; 374 int pidvalue = 0; 375 memoryUsage = captureMediaserverInfo(); 376 String[] poList2 = memoryUsage.split("\t|\\s+"); 377 String pid = poList2[1]; 378 pidvalue = Integer.parseInt(pid); 379 Log.v(TAG, "PID = " + pidvalue); 380 return pidvalue; 381 } 382 383 public int getMediaserverVsize(){ 384 String memoryUsage = captureMediaserverInfo(); 385 String[] poList2 = memoryUsage.split("\t|\\s+"); 386 String vsize = poList2[3]; 387 int vsizevalue = Integer.parseInt(vsize); 388 Log.v(TAG, "VSIZE = " + vsizevalue); 389 return vsizevalue; 390 } 391 392 public boolean validateMemoryResult(int startPid, int startMemory, Writer output, int limit) 393 throws Exception { 394 // Wait for 10 seconds to make sure the memory settle. 395 Thread.sleep(10000); 396 mEndPid = getMediaserverPid(); 397 int memDiff = mEndMemory - startMemory; 398 if (memDiff < 0) 399 memDiff = 0; 400 else 401 output.write("The total diff = " + memDiff); 402 output.write("\n\n"); 403 // mediaserver crash 404 if (startPid != mEndPid) { 405 output.write("mediaserver died. Test failed\n"); 406 return false; 407 } 408 // memory leak greter than the tolerant 409 if (memDiff > limit) return false; 410 return true; 411 } 412 413 @Suppress 414 public void testWmaParseTime() throws Exception { 415 // createDB(); 416 wmametadatautility(MediaNames.WMASUPPORTED); 417 } 418 419 420 // Test case 1: Capture the memory usage after every 20 h263 playback 421 @LargeTest 422 public void testH263VideoPlaybackMemoryUsage() throws Exception { 423 boolean memoryResult = false; 424 mStartPid = getMediaserverPid(); 425 426 File h263MemoryOut = new File(MEDIA_MEMORY_OUTPUT); 427 Writer output = new BufferedWriter(new FileWriter(h263MemoryOut, true)); 428 output.write("H263 Video Playback Only\n"); 429 for (int i = 0; i < NUM_STRESS_LOOP; i++) { 430 mediaStressPlayback(MediaNames.VIDEO_HIGHRES_H263); 431 getMemoryWriteToLog(output, i); 432 } 433 output.write("\n"); 434 memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, DECODER_LIMIT); 435 output.close(); 436 assertTrue("H263 playback memory test", memoryResult); 437 } 438 439 // Test case 2: Capture the memory usage after every 20 h264 playback 440 @LargeTest 441 public void testH264VideoPlaybackMemoryUsage() throws Exception { 442 boolean memoryResult = false; 443 mStartPid = getMediaserverPid(); 444 445 File h264MemoryOut = new File(MEDIA_MEMORY_OUTPUT); 446 Writer output = new BufferedWriter(new FileWriter(h264MemoryOut, true)); 447 output.write("H264 Video Playback only\n"); 448 for (int i = 0; i < NUM_STRESS_LOOP; i++) { 449 mediaStressPlayback(MediaNames.VIDEO_H264_AMR); 450 getMemoryWriteToLog(output, i); 451 } 452 output.write("\n"); 453 memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, DECODER_LIMIT); 454 output.close(); 455 assertTrue("H264 playback memory test", memoryResult); 456 } 457 458 // Test case 3: Capture the memory usage after each 20 WMV playback 459 @LargeTest 460 public void testWMVVideoPlaybackMemoryUsage() throws Exception { 461 boolean memoryResult = false; 462 if (MediaProfileReader.getWMVEnable()){ 463 mStartPid = getMediaserverPid(); 464 File wmvMemoryOut = new File(MEDIA_MEMORY_OUTPUT); 465 Writer output = new BufferedWriter(new FileWriter(wmvMemoryOut, true)); 466 output.write("WMV video playback only\n"); 467 for (int i = 0; i < NUM_STRESS_LOOP; i++) { 468 mediaStressPlayback(MediaNames.VIDEO_WMV); 469 getMemoryWriteToLog(output, i); 470 } 471 output.write("\n"); 472 memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, DECODER_LIMIT); 473 output.close(); 474 assertTrue("wmv playback memory test", memoryResult); 475 } 476 } 477 478 // Test case 4: Capture the memory usage after every 20 video only recorded 479 @LargeTest 480 public void testH263RecordVideoOnlyMemoryUsage() throws Exception { 481 boolean memoryResult = false; 482 mStartPid = getMediaserverPid(); 483 484 File videoH263RecordOnlyMemoryOut = new File(MEDIA_MEMORY_OUTPUT); 485 Writer output = new BufferedWriter(new FileWriter(videoH263RecordOnlyMemoryOut, true)); 486 output.write("H263 video record only\n"); 487 for (int i = 0; i < NUM_STRESS_LOOP; i++) { 488 stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.H263, 489 MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true); 490 getMemoryWriteToLog(output, i); 491 } 492 output.write("\n"); 493 memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, ENCODER_LIMIT); 494 output.close(); 495 assertTrue("H263 record only memory test", memoryResult); 496 } 497 498 // Test case 5: Capture the memory usage after every 20 video only recorded 499 @LargeTest 500 public void testMpeg4RecordVideoOnlyMemoryUsage() throws Exception { 501 boolean memoryResult = false; 502 mStartPid = getMediaserverPid(); 503 504 File videoMp4RecordOnlyMemoryOut = new File(MEDIA_MEMORY_OUTPUT); 505 Writer output = new BufferedWriter(new FileWriter(videoMp4RecordOnlyMemoryOut, true)); 506 output.write("MPEG4 video record only\n"); 507 for (int i = 0; i < NUM_STRESS_LOOP; i++) { 508 stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.MPEG_4_SP, 509 MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true); 510 getMemoryWriteToLog(output, i); 511 } 512 output.write("\n"); 513 memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, ENCODER_LIMIT); 514 output.close(); 515 assertTrue("mpeg4 record only memory test", memoryResult); 516 } 517 518 // Test case 6: Capture the memory usage after every 20 video and audio 519 // recorded 520 @LargeTest 521 public void testRecordVidedAudioMemoryUsage() throws Exception { 522 boolean memoryResult = false; 523 mStartPid = getMediaserverPid(); 524 525 File videoRecordAudioMemoryOut = new File(MEDIA_MEMORY_OUTPUT); 526 Writer output = new BufferedWriter(new FileWriter(videoRecordAudioMemoryOut, true)); 527 output.write("Audio and h263 video record\n"); 528 for (int i = 0; i < NUM_STRESS_LOOP; i++) { 529 stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.H263, 530 MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, false); 531 getMemoryWriteToLog(output, i); 532 } 533 output.write("\n"); 534 memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, ENCODER_LIMIT); 535 output.close(); 536 assertTrue("H263 audio video record memory test", memoryResult); 537 } 538 539 // Test case 7: Capture the memory usage after every 20 audio only recorded 540 @LargeTest 541 public void testRecordAudioOnlyMemoryUsage() throws Exception { 542 boolean memoryResult = false; 543 mStartPid = getMediaserverPid(); 544 545 File audioOnlyMemoryOut = new File(MEDIA_MEMORY_OUTPUT); 546 Writer output = new BufferedWriter(new FileWriter(audioOnlyMemoryOut, true)); 547 output.write("Audio record only\n"); 548 for (int i = 0; i < NUM_STRESS_LOOP; i++) { 549 stressAudioRecord(MediaNames.RECORDER_OUTPUT); 550 getMemoryWriteToLog(output, i); 551 } 552 output.write("\n"); 553 memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, ENCODER_LIMIT); 554 output.close(); 555 assertTrue("audio record only memory test", memoryResult); 556 } 557 558 // Test case 8: Capture the memory usage after every 20 camera preview 559 @LargeTest 560 public void testCameraPreviewMemoryUsage() throws Exception { 561 boolean memoryResult = false; 562 mStartPid = getMediaserverPid(); 563 564 File cameraPreviewMemoryOut = new File(MEDIA_MEMORY_OUTPUT); 565 Writer output = new BufferedWriter(new FileWriter(cameraPreviewMemoryOut, true)); 566 output.write("Camera Preview Only\n"); 567 for (int i = 0; i < NUM_STRESS_LOOP; i++) { 568 stressCameraPreview(); 569 getMemoryWriteToLog(output, i); 570 } 571 output.write("\n"); 572 memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, CAMERA_LIMIT); 573 output.close(); 574 assertTrue("camera preview memory test", memoryResult); 575 } 576} 577