2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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
17 package com
.android
.mediaframeworktest
.performance
;
19 import com
.android
.mediaframeworktest
.MediaFrameworkTest
;
20 import com
.android
.mediaframeworktest
.MediaFrameworkPerfTestRunner
;
21 import com
.android
.mediaframeworktest
.MediaNames
;
22 import com
.android
.mediaframeworktest
.MediaTestUtil
;
24 import android
.database
.sqlite
.SQLiteDatabase
;
25 import android
.hardware
.Camera
;
26 import android
.hardware
.Camera
.PreviewCallback
;
27 import android
.media
.CamcorderProfile
;
28 import android
.media
.MediaPlayer
;
29 import android
.media
.MediaRecorder
;
30 import android
.media
.EncoderCapabilities
.VideoEncoderCap
;
31 import android
.os
.ConditionVariable
;
32 import android
.os
.Looper
;
33 import android
.test
.ActivityInstrumentationTestCase2
;
34 import android
.test
.suitebuilder
.annotation
.LargeTest
;
35 import android
.util
.Log
;
36 import android
.view
.SurfaceHolder
;
38 import java
.util
.List
;
39 import java
.io
.BufferedReader
;
40 import java
.io
.IOException
;
41 import java
.io
.InputStream
;
42 import java
.io
.InputStreamReader
;
43 import java
.io
.Writer
;
45 import java
.io
.FileWriter
;
46 import java
.io
.BufferedWriter
;
48 import com
.android
.mediaframeworktest
.MediaProfileReader
;
51 * Junit / Instrumentation - performance measurement for media player and
55 * Add tests on H264 video encoder
57 public class MediaPlayerPerformance
extends ActivityInstrumentationTestCase2
<MediaFrameworkTest
> {
59 private String TAG
= "MediaPlayerPerformance";
61 private SurfaceHolder mSurfaceHolder
= null;
62 private static final int NUM_STRESS_LOOP
= 10;
63 private static final int NUM_PLAYBACk_IN_EACH_LOOP
= 20;
64 private static final int SHORT_WAIT
= 2 * 1000; // 2 seconds
65 private static final long MEDIA_STRESS_WAIT_TIME
= 5000; //5 seconds
66 private static final String MEDIA_MEMORY_OUTPUT
=
67 "/sdcard/mediaMemOutput.txt";
68 private static final String MEDIA_PROCMEM_OUTPUT
=
69 "/sdcard/mediaProcmemOutput.txt";
70 private static final int CAMERA_ID
= 0;
72 private static int mStartMemory
= 0;
73 private static int mEndMemory
= 0;
74 private static int mStartPid
= 0;
75 private static int mEndPid
= 0;
77 private Looper mLooper
= null;
78 private RawPreviewCallback mRawPreviewCallback
= new RawPreviewCallback();
79 private final ConditionVariable mPreviewDone
= new ConditionVariable();
80 private static int WAIT_FOR_COMMAND_TO_COMPLETE
= 10000; // Milliseconds.
82 //the tolerant memory leak
83 private static int ENCODER_LIMIT
= 150;
84 private static int DECODER_LIMIT
= 150;
85 private static int CAMERA_LIMIT
= 80;
87 private Writer mProcMemWriter
;
88 private Writer mMemWriter
;
90 private CamcorderProfile mCamcorderProfile
;
91 private int mVideoWidth
;
92 private int mVideoHeight
;
96 public MediaPlayerPerformance() {
97 super("com.android.mediaframeworktest", MediaFrameworkTest
.class);
101 protected void setUp() throws Exception
{
103 //Insert a 2 second before launching the test activity. This is
104 //the workaround for the race condition of requesting the updated surface.
105 Thread
.sleep(SHORT_WAIT
);
107 //Check if the device support the camcorder
108 mCamcorderProfile
= CamcorderProfile
.get(CAMERA_ID
);
109 if (mCamcorderProfile
!= null) {
110 mVideoWidth
= mCamcorderProfile
.videoFrameWidth
;
111 mVideoHeight
= mCamcorderProfile
.videoFrameHeight
;
112 Log
.v(TAG
, "height = " + mVideoHeight
+ " width= " + mVideoWidth
);
114 if (MediaFrameworkPerfTestRunner
.mGetNativeHeapDump
)
115 MediaTestUtil
.getNativeHeapDump(this.getName() + "_before");
117 if (MediaFrameworkPerfTestRunner
.mGetProcmem
) {
118 mProcMemWriter
= new BufferedWriter(new FileWriter
119 (new File(MEDIA_PROCMEM_OUTPUT
), true));
120 mProcMemWriter
.write(this.getName() + "\n");
122 mMemWriter
= new BufferedWriter(new FileWriter
123 (new File(MEDIA_MEMORY_OUTPUT
), true));
124 mMemWriter
.write(this.getName() + "\n");
128 protected void tearDown() throws Exception
{
129 if (MediaFrameworkPerfTestRunner
.mGetNativeHeapDump
)
130 MediaTestUtil
.getNativeHeapDump(this.getName() + "_after");
132 if (MediaFrameworkPerfTestRunner
.mGetProcmem
) {
133 mProcMemWriter
.close();
135 mMemWriter
.write("\n");
140 private void initializeMessageLooper() {
141 final ConditionVariable startDone
= new ConditionVariable();
146 Log
.v(TAG
, "start loopRun");
147 mLooper
= Looper
.myLooper();
148 mCamera
= Camera
.open(CAMERA_ID
);
151 Log
.v(TAG
, "initializeMessageLooper: quit.");
155 if (!startDone
.block(WAIT_FOR_COMMAND_TO_COMPLETE
)) {
156 fail("initializeMessageLooper: start timeout");
160 private void terminateMessageLooper() throws Exception
{
162 // Looper.quit() is asynchronous. The looper may still has some
163 // preview callbacks in the queue after quit is called. The preview
164 // callback still uses the camera object (setHasPreviewCallback).
165 // After camera is released, RuntimeException will be thrown from
166 // the method. So we need to join the looper thread here.
167 mLooper
.getThread().join();
171 private final class RawPreviewCallback
implements PreviewCallback
{
173 public void onPreviewFrame(byte[] rawData
, Camera camera
) {
178 private void waitForPreviewDone() {
179 if (!mPreviewDone
.block(WAIT_FOR_COMMAND_TO_COMPLETE
)) {
180 Log
.v(TAG
, "waitForPreviewDone: timeout");
182 mPreviewDone
.close();
185 public void stressCameraPreview() {
186 for (int i
= 0; i
< NUM_PLAYBACk_IN_EACH_LOOP
; i
++) {
188 initializeMessageLooper();
189 mCamera
.setPreviewCallback(mRawPreviewCallback
);
190 mSurfaceHolder
= MediaFrameworkTest
.mSurfaceView
.getHolder();
191 mCamera
.setPreviewDisplay(mSurfaceHolder
);
192 mCamera
.startPreview();
193 waitForPreviewDone();
195 mCamera
.stopPreview();
196 terminateMessageLooper();
197 } catch (Exception e
) {
198 Log
.v(TAG
, e
.toString());
203 // Note: This test is to assume the mediaserver's pid is 34
204 public void mediaStressPlayback(String testFilePath
) {
205 for (int i
= 0; i
< NUM_PLAYBACk_IN_EACH_LOOP
; i
++) {
206 MediaPlayer mp
= new MediaPlayer();
208 mp
.setDataSource(testFilePath
);
209 mp
.setDisplay(MediaFrameworkTest
.mSurfaceView
.getHolder());
212 Thread
.sleep(MEDIA_STRESS_WAIT_TIME
);
214 } catch (Exception e
) {
216 Log
.v(TAG
, e
.toString());
221 // Note: This test is to assume the mediaserver's pid is 34
222 private boolean stressVideoRecord(int frameRate
, int width
, int height
, int videoFormat
,
223 int outFormat
, String outFile
, boolean videoOnly
) {
225 boolean doesTestFail
= false;
226 for (int i
= 0; i
< NUM_PLAYBACk_IN_EACH_LOOP
; i
++) {
227 MediaRecorder mRecorder
= new MediaRecorder();
230 Log
.v(TAG
, "setAudioSource");
231 mRecorder
.setAudioSource(MediaRecorder
.AudioSource
.MIC
);
233 mRecorder
.setVideoSource(MediaRecorder
.VideoSource
.CAMERA
);
234 mRecorder
.setOutputFormat(outFormat
);
235 Log
.v(TAG
, "output format " + outFormat
);
236 mRecorder
.setOutputFile(outFile
);
237 mRecorder
.setVideoFrameRate(frameRate
);
238 mRecorder
.setVideoSize(width
, height
);
239 Log
.v(TAG
, "setEncoder");
240 mRecorder
.setVideoEncoder(videoFormat
);
242 mRecorder
.setAudioEncoder(MediaRecorder
.AudioEncoder
.AMR_NB
);
244 mSurfaceHolder
= MediaFrameworkTest
.mSurfaceView
.getHolder();
245 mRecorder
.setPreviewDisplay(mSurfaceHolder
.getSurface());
248 Thread
.sleep(MEDIA_STRESS_WAIT_TIME
);
251 //Insert 2 seconds to make sure the camera released.
252 Thread
.sleep(SHORT_WAIT
);
253 } catch (Exception e
) {
254 Log
.v("record video failed ", e
.toString());
260 return !doesTestFail
;
263 public void stressAudioRecord(String filePath
) {
264 // This test is only for the short media file
265 for (int i
= 0; i
< NUM_PLAYBACk_IN_EACH_LOOP
; i
++) {
266 MediaRecorder mRecorder
= new MediaRecorder();
268 mRecorder
.setAudioSource(MediaRecorder
.AudioSource
.MIC
);
269 mRecorder
.setOutputFormat(MediaRecorder
.OutputFormat
.THREE_GPP
);
270 mRecorder
.setAudioEncoder(MediaRecorder
.AudioEncoder
.AMR_NB
);
271 mRecorder
.setOutputFile(filePath
);
274 Thread
.sleep(MEDIA_STRESS_WAIT_TIME
);
277 } catch (Exception e
) {
278 Log
.v(TAG
, e
.toString());
284 //Write the ps output to the file
285 public void getMemoryWriteToLog(int writeCount
) {
286 String memusage
= null;
288 if (writeCount
== 0) {
289 mStartMemory
= getMediaserverVsize();
290 mMemWriter
.write("Start memory : " + mStartMemory
+ "\n");
292 memusage
= captureMediaserverInfo();
293 mMemWriter
.write(memusage
);
294 if (writeCount
== NUM_STRESS_LOOP
- 1) {
295 mEndMemory
= getMediaserverVsize();
296 mMemWriter
.write("End Memory :" + mEndMemory
+ "\n");
298 } catch (Exception e
) {
303 public void writeProcmemInfo() throws Exception
{
304 if (MediaFrameworkPerfTestRunner
.mGetProcmem
) {
305 String cmd
= "procmem " + getMediaserverPid();
306 Process p
= Runtime
.getRuntime().exec(cmd
);
308 InputStream inStream
= p
.getInputStream();
309 InputStreamReader inReader
= new InputStreamReader(inStream
);
310 BufferedReader inBuffer
= new BufferedReader(inReader
);
312 while ((s
= inBuffer
.readLine()) != null) {
313 mProcMemWriter
.write(s
);
314 mProcMemWriter
.write("\n");
316 mProcMemWriter
.write("\n\n");
320 public String
captureMediaserverInfo() {
321 String cm
= "ps mediaserver";
322 String memoryUsage
= null;
326 Process p
= Runtime
.getRuntime().exec(cm
);
327 InputStream in
= p
.getInputStream();
328 StringBuffer sb
= new StringBuffer(512);
329 while ((ch
= in
.read()) != -1) {
330 sb
.append((char) ch
);
332 memoryUsage
= sb
.toString();
333 } catch (IOException e
) {
334 Log
.v(TAG
, e
.toString());
336 String
[] poList
= memoryUsage
.split("\r|\n|\r\n");
337 // A new media.log is enabled with ro.test_harness is set.
338 // The output of "ps mediaserver" will include the
339 // media.log process in the first line. Update the parsing
340 // to only read the thrid line.
341 // Smaple ps mediaserver output:
342 // USER PID PPID VSIZE RSS WCHAN PC NAME
343 // media 131 1 13676 4796 ffffffff 400b1bd0 S media.log
344 // media 219 131 37768 6892 ffffffff 400b236c S /system/bin/mediaserver
345 String memusage
= poList
[poList
.length
-1].concat("\n");
349 public int getMediaserverPid(){
350 String memoryUsage
= null;
352 memoryUsage
= captureMediaserverInfo();
353 String
[] poList2
= memoryUsage
.split("\t|\\s+");
354 String pid
= poList2
[1];
355 pidvalue
= Integer
.parseInt(pid
);
356 Log
.v(TAG
, "PID = " + pidvalue
);
360 public int getMediaserverVsize(){
361 String memoryUsage
= captureMediaserverInfo();
362 String
[] poList2
= memoryUsage
.split("\t|\\s+");
363 String vsize
= poList2
[3];
364 int vsizevalue
= Integer
.parseInt(vsize
);
365 Log
.v(TAG
, "VSIZE = " + vsizevalue
);
369 public boolean validateMemoryResult(int startPid
, int startMemory
, int limit
)
371 // Wait for 10 seconds to make sure the memory settle.
373 mEndPid
= getMediaserverPid();
374 int memDiff
= mEndMemory
- startMemory
;
378 mMemWriter
.write("The total diff = " + memDiff
);
379 mMemWriter
.write("\n\n");
381 if (startPid
!= mEndPid
) {
382 mMemWriter
.write("mediaserver died. Test failed\n");
385 // memory leak greter than the tolerant
386 if (memDiff
> limit
) return false;
390 // Test case 1: Capture the memory usage after every 20 h263 playback
392 public void testH263VideoPlaybackMemoryUsage() throws Exception
{
393 boolean memoryResult
= false;
395 mStartPid
= getMediaserverPid();
396 for (int i
= 0; i
< NUM_STRESS_LOOP
; i
++) {
397 mediaStressPlayback(MediaNames
.VIDEO_HIGHRES_H263
);
398 getMemoryWriteToLog(i
);
401 memoryResult
= validateMemoryResult(mStartPid
, mStartMemory
, DECODER_LIMIT
);
402 assertTrue("H263 playback memory test", memoryResult
);
405 // Test case 2: Capture the memory usage after every 20 h264 playback
407 public void testH264VideoPlaybackMemoryUsage() throws Exception
{
408 boolean memoryResult
= false;
410 mStartPid
= getMediaserverPid();
411 for (int i
= 0; i
< NUM_STRESS_LOOP
; i
++) {
412 mediaStressPlayback(MediaNames
.VIDEO_H264_AMR
);
413 getMemoryWriteToLog(i
);
416 memoryResult
= validateMemoryResult(mStartPid
, mStartMemory
, DECODER_LIMIT
);
417 assertTrue("H264 playback memory test", memoryResult
);
420 // Test case 3: Capture the memory usage after every 20 hevc playback
422 public void testHEVCVideoPlaybackMemoryUsage() throws Exception
{
423 boolean memoryResult
= false;
425 mStartPid
= getMediaserverPid();
426 for (int i
= 0; i
< NUM_STRESS_LOOP
; i
++) {
427 mediaStressPlayback(MediaNames
.VIDEO_HEVC_AAC
);
428 getMemoryWriteToLog(i
);
431 memoryResult
= validateMemoryResult(mStartPid
, mStartMemory
, DECODER_LIMIT
);
432 assertTrue("HEVC playback memory test", memoryResult
);
435 // Test case 4: Capture the memory usage after every 20 mpeg2 playback
437 public void testMPEG2VideoPlaybackMemoryUsage() throws Exception
{
438 boolean memoryResult
= false;
440 mStartPid
= getMediaserverPid();
441 for (int i
= 0; i
< NUM_STRESS_LOOP
; i
++) {
442 mediaStressPlayback(MediaNames
.VIDEO_MPEG2_AAC
);
443 getMemoryWriteToLog(i
);
446 memoryResult
= validateMemoryResult(mStartPid
, mStartMemory
, DECODER_LIMIT
);
447 assertTrue("MPEG2 playback memory test", memoryResult
);
450 // Test case 5: Capture the memory usage after every 20 video only recorded
452 public void testH263RecordVideoOnlyMemoryUsage() throws Exception
{
453 if (mCamcorderProfile
!= null) {
454 boolean memoryResult
= false;
455 mStartPid
= getMediaserverPid();
456 int frameRate
= MediaProfileReader
457 .getMaxFrameRateForCodec(MediaRecorder
.VideoEncoder
.H263
);
458 assertTrue("H263 video recording frame rate", frameRate
!= -1);
459 for (int i
= 0; i
< NUM_STRESS_LOOP
; i
++) {
460 assertTrue(stressVideoRecord(frameRate
, mVideoWidth
, mVideoHeight
,
461 MediaRecorder
.VideoEncoder
.H263
, MediaRecorder
.OutputFormat
.MPEG_4
,
462 MediaNames
.RECORDED_VIDEO_3GP
, true));
463 getMemoryWriteToLog(i
);
466 memoryResult
= validateMemoryResult(mStartPid
, mStartMemory
, ENCODER_LIMIT
);
467 assertTrue("H263 record only memory test", memoryResult
);
471 // Test case 6: Capture the memory usage after every 20 video only recorded
473 public void testMpeg4RecordVideoOnlyMemoryUsage() throws Exception
{
474 if (mCamcorderProfile
!= null) {
475 boolean memoryResult
= false;
476 mStartPid
= getMediaserverPid();
477 int frameRate
= MediaProfileReader
.getMaxFrameRateForCodec
478 (MediaRecorder
.VideoEncoder
.MPEG_4_SP
);
479 assertTrue("MPEG4 video recording frame rate", frameRate
!= -1);
480 for (int i
= 0; i
< NUM_STRESS_LOOP
; i
++) {
481 assertTrue(stressVideoRecord(frameRate
, mVideoWidth
, mVideoHeight
,
482 MediaRecorder
.VideoEncoder
.MPEG_4_SP
, MediaRecorder
.OutputFormat
.MPEG_4
,
483 MediaNames
.RECORDED_VIDEO_3GP
, true));
484 getMemoryWriteToLog(i
);
487 memoryResult
= validateMemoryResult(mStartPid
, mStartMemory
, ENCODER_LIMIT
);
488 assertTrue("mpeg4 record only memory test", memoryResult
);
492 // Test case 7: Capture the memory usage after every 20 video and audio
495 public void testRecordVideoAudioMemoryUsage() throws Exception
{
496 if (mCamcorderProfile
!= null) {
497 boolean memoryResult
= false;
498 mStartPid
= getMediaserverPid();
499 int frameRate
= MediaProfileReader
500 .getMaxFrameRateForCodec(MediaRecorder
.VideoEncoder
.H263
);
501 assertTrue("H263 video recording frame rate", frameRate
!= -1);
502 for (int i
= 0; i
< NUM_STRESS_LOOP
; i
++) {
503 assertTrue(stressVideoRecord(frameRate
, mVideoWidth
, mVideoHeight
,
504 MediaRecorder
.VideoEncoder
.H263
, MediaRecorder
.OutputFormat
.MPEG_4
,
505 MediaNames
.RECORDED_VIDEO_3GP
, false));
506 getMemoryWriteToLog(i
);
509 memoryResult
= validateMemoryResult(mStartPid
, mStartMemory
, ENCODER_LIMIT
);
510 assertTrue("H263 audio video record memory test", memoryResult
);
514 // Test case 8: Capture the memory usage after every 20 audio only recorded
516 public void testRecordAudioOnlyMemoryUsage() throws Exception
{
517 boolean memoryResult
= false;
519 mStartPid
= getMediaserverPid();
520 for (int i
= 0; i
< NUM_STRESS_LOOP
; i
++) {
521 stressAudioRecord(MediaNames
.RECORDER_OUTPUT
);
522 getMemoryWriteToLog(i
);
525 memoryResult
= validateMemoryResult(mStartPid
, mStartMemory
, ENCODER_LIMIT
);
526 assertTrue("audio record only memory test", memoryResult
);
529 // Test case 9: Capture the memory usage after every 20 camera preview
531 public void testCameraPreviewMemoryUsage() throws Exception
{
532 boolean memoryResult
= false;
534 mStartPid
= getMediaserverPid();
535 for (int i
= 0; i
< NUM_STRESS_LOOP
; i
++) {
536 stressCameraPreview();
537 getMemoryWriteToLog(i
);
540 memoryResult
= validateMemoryResult(mStartPid
, mStartMemory
, CAMERA_LIMIT
);
541 assertTrue("camera preview memory test", memoryResult
);