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