MediaRecorderTest.java revision daa98ca8d7c85b77ad794cc8d9f17e262ac41d96
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of 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,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.mediaframeworktest.functional.mediarecorder;
18
19import com.android.mediaframeworktest.MediaFrameworkTest;
20import com.android.mediaframeworktest.MediaNames;
21
22import java.io.*;
23
24import android.content.Context;
25import android.graphics.Canvas;
26import android.graphics.Color;
27import android.graphics.Paint;
28import android.graphics.Typeface;
29import android.hardware.Camera;
30import android.media.MediaPlayer;
31import android.media.MediaRecorder;
32import android.media.EncoderCapabilities;
33import android.media.EncoderCapabilities.VideoEncoderCap;
34import android.media.EncoderCapabilities.AudioEncoderCap;
35import android.test.ActivityInstrumentationTestCase2;
36import android.util.Log;
37import android.view.Surface;
38import android.view.SurfaceHolder;
39import android.view.SurfaceView;
40import com.android.mediaframeworktest.MediaProfileReader;
41import com.android.mediaframeworktest.MediaFrameworkTestRunner;
42
43import android.test.suitebuilder.annotation.LargeTest;
44import android.test.suitebuilder.annotation.Suppress;
45import java.util.List;
46
47
48/**
49 * Junit / Instrumentation test case for the media recorder api
50 */
51public class MediaRecorderTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
52    private String TAG = "MediaRecorderTest";
53    private int mOutputDuration =0;
54    private int mOutputVideoWidth = 0;
55    private int mOutputVideoHeight= 0 ;
56
57    private SurfaceHolder mSurfaceHolder = null;
58    private MediaRecorder mRecorder;
59
60    private int MIN_VIDEO_FPS = 5;
61    private int HIGH_SPEED_FPS = 120;
62
63    private static final int CAMERA_ID = 0;
64
65    Context mContext;
66    Camera mCamera;
67
68    public MediaRecorderTest() {
69        super(MediaFrameworkTest.class);
70
71    }
72
73    protected void setUp() throws Exception {
74        getActivity();
75        mRecorder = new MediaRecorder();
76        super.setUp();
77    }
78
79    private void recordVideo(int frameRate, int width, int height,
80            int videoFormat, int outFormat, String outFile, boolean videoOnly) {
81        Log.v(TAG,"startPreviewAndPrepareRecording");
82        try {
83            if (!videoOnly) {
84                Log.v(TAG, "setAudioSource");
85                mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
86            }
87            mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
88            mRecorder.setOutputFormat(outFormat);
89            Log.v(TAG, "output format " + outFormat);
90            mRecorder.setOutputFile(outFile);
91            mRecorder.setVideoFrameRate(frameRate);
92            mRecorder.setVideoSize(width, height);
93            Log.v(TAG, "setEncoder");
94            mRecorder.setVideoEncoder(videoFormat);
95            if (!videoOnly) {
96                mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
97            }
98            mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
99            Log.v(TAG, "setPreview");
100            mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
101            Log.v(TAG, "prepare");
102            mRecorder.prepare();
103            Log.v(TAG, "start");
104            mRecorder.start();
105            Thread.sleep(MediaNames.RECORDED_TIME);
106            Log.v(TAG, "stop");
107            mRecorder.stop();
108            mRecorder.release();
109        } catch (Exception e) {
110            Log.v("record video failed ", e.toString());
111            mRecorder.release();
112        }
113    }
114
115    private boolean validateGetSurface(boolean useSurface) {
116        Log.v(TAG,"validateGetSurface, useSurface=" + useSurface);
117        MediaRecorder recorder = new MediaRecorder();
118        Surface surface;
119        boolean success = true;
120        try {
121            /* initialization */
122            if (!useSurface) {
123                mCamera = Camera.open(CAMERA_ID);
124                Camera.Parameters parameters = mCamera.getParameters();
125                parameters.setPreviewSize(352, 288);
126                parameters.set("orientation", "portrait");
127                mCamera.setParameters(parameters);
128                mCamera.unlock();
129                recorder.setCamera(mCamera);
130                mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
131                recorder.setPreviewDisplay(mSurfaceHolder.getSurface());
132            }
133
134            recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
135            int videoSource = useSurface ?
136                    MediaRecorder.VideoSource.SURFACE :
137                    MediaRecorder.VideoSource.CAMERA;
138            recorder.setVideoSource(videoSource);
139            recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
140            recorder.setOutputFile(MediaNames.RECORDED_SURFACE_3GP);
141            recorder.setVideoFrameRate(30);
142            recorder.setVideoSize(352, 288);
143            recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
144            recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
145
146            /* Test: getSurface() before prepare()
147             * should throw IllegalStateException
148             */
149            try {
150                surface = recorder.getSurface();
151                throw new Exception("getSurface failed to throw IllegalStateException");
152            } catch (IllegalStateException e) {
153                // OK
154            }
155
156            recorder.prepare();
157
158            /* Test: getSurface() after prepare()
159             * should succeed for surface source
160             * should fail for camera source
161             */
162            try {
163                surface = recorder.getSurface();
164                if (!useSurface) {
165                    throw new Exception("getSurface failed to throw IllegalStateException");
166                }
167            } catch (IllegalStateException e) {
168                if (useSurface) {
169                    throw new Exception("getSurface failed to throw IllegalStateException");
170                }
171            }
172
173            recorder.start();
174
175            /* Test: getSurface() after start()
176             * should succeed for surface source
177             * should fail for camera source
178             */
179            try {
180                surface = recorder.getSurface();
181                if (!useSurface) {
182                    throw new Exception("getSurface failed to throw IllegalStateException");
183                }
184            } catch (IllegalStateException e) {
185                if (useSurface) {
186                    throw new Exception("getSurface failed to throw IllegalStateException");
187                }
188            }
189
190            try {
191                recorder.stop();
192            } catch (Exception e) {
193                // stop() could fail if the recording is empty, as we didn't render anything.
194                // ignore any failure in stop, we just want it stopped.
195            }
196
197            /* Test: getSurface() after stop()
198             * should throw IllegalStateException
199             */
200            try {
201                surface = recorder.getSurface();
202                throw new Exception("getSurface failed to throw IllegalStateException");
203            } catch (IllegalStateException e) {
204                // OK
205            }
206        } catch (Exception e) {
207            // fail
208            success = false;
209        }
210
211        try {
212            if (mCamera != null) {
213                mCamera.lock();
214                mCamera.release();
215                mCamera = null;
216            }
217            recorder.release();
218        } catch (Exception e) {
219            success = false;
220        }
221
222        return success;
223    }
224
225    private boolean recordVideoFromSurface(
226            int frameRate, int captureRate, int width, int height,
227            int videoFormat, int outFormat, String outFile, boolean videoOnly) {
228        Log.v(TAG,"recordVideoFromSurface");
229        MediaRecorder recorder = new MediaRecorder();
230        int sleepTime = 33; // normal capture at 33ms / frame
231        try {
232            if (!videoOnly) {
233                recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
234            }
235            recorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
236            recorder.setOutputFormat(outFormat);
237            recorder.setOutputFile(outFile);
238            recorder.setVideoFrameRate(frameRate);
239            if (captureRate > 0) {
240                recorder.setCaptureRate(captureRate);
241                sleepTime = 1000 / captureRate;
242            }
243            recorder.setVideoSize(width, height);
244            recorder.setVideoEncoder(videoFormat);
245            if (!videoOnly) {
246                recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
247            }
248            recorder.prepare();
249            Surface surface = recorder.getSurface();
250
251            Paint paint = new Paint();
252            paint.setTextSize(16);
253            paint.setColor(Color.RED);
254            int i;
255
256            /* Test: draw 10 frames at 30fps before start
257             * these should be dropped and not causing malformed stream.
258             */
259            for(i = 0; i < 10; i++) {
260                Canvas canvas = surface.lockCanvas(null);
261                int background = (i * 255 / 99);
262                canvas.drawARGB(255, background, background, background);
263                String text = "Frame #" + i;
264                canvas.drawText(text, 100, 100, paint);
265                surface.unlockCanvasAndPost(canvas);
266                Thread.sleep(sleepTime);
267            }
268
269            Log.v(TAG, "start");
270            recorder.start();
271
272            /* Test: draw another 90 frames at 30fps after start */
273            for(i = 10; i < 100; i++) {
274                Canvas canvas = surface.lockCanvas(null);
275                int background = (i * 255 / 99);
276                canvas.drawARGB(255, background, background, background);
277                String text = "Frame #" + i;
278                canvas.drawText(text, 100, 100, paint);
279                surface.unlockCanvasAndPost(canvas);
280                Thread.sleep(sleepTime);
281            }
282
283            Log.v(TAG, "stop");
284            recorder.stop();
285            recorder.release();
286        } catch (Exception e) {
287            Log.v("record video failed ", e.toString());
288            recorder.release();
289            return false;
290        }
291        return true;
292    }
293
294    private boolean recordVideoWithPara(VideoEncoderCap videoCap, AudioEncoderCap audioCap, boolean highQuality){
295        boolean recordSuccess = false;
296        int videoEncoder = videoCap.mCodec;
297        int audioEncoder = audioCap.mCodec;
298        int videoWidth = highQuality? videoCap.mMaxFrameWidth: videoCap.mMinFrameWidth;
299        int videoHeight = highQuality? videoCap.mMaxFrameHeight: videoCap.mMinFrameHeight;
300        int videoFps = highQuality? videoCap.mMaxFrameRate: videoCap.mMinFrameRate;
301        int videoBitrate = highQuality? videoCap.mMaxBitRate: videoCap.mMinBitRate;
302        int audioBitrate = highQuality? audioCap.mMaxBitRate: audioCap.mMinBitRate;
303        int audioChannels = highQuality? audioCap.mMaxChannels: audioCap.mMinChannels ;
304        int audioSamplingRate = highQuality? audioCap.mMaxSampleRate: audioCap.mMinSampleRate;
305
306        //Overide the fps if the min_camera_fps is set
307        if (MediaFrameworkTestRunner.mMinCameraFps != 0 &&
308            MediaFrameworkTestRunner.mMinCameraFps > videoFps){
309            videoFps = MediaFrameworkTestRunner.mMinCameraFps;
310        }
311
312        if (videoFps < MIN_VIDEO_FPS) {
313            videoFps = MIN_VIDEO_FPS;
314        }
315
316        mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
317        String filename = ("/sdcard/" + videoEncoder + "_" + audioEncoder + "_" + highQuality + ".3gp");
318        try {
319            Log.v(TAG, "video encoder : " + videoEncoder);
320            Log.v(TAG, "audio encoder : " + audioEncoder);
321            Log.v(TAG, "quality : " + (highQuality?"high": "low"));
322            Log.v(TAG, "encoder : " + MediaProfileReader.getVideoCodecName(videoEncoder));
323            Log.v(TAG, "audio : " + MediaProfileReader.getAudioCodecName(audioEncoder));
324            Log.v(TAG, "videoWidth : " + videoWidth);
325            Log.v(TAG, "videoHeight : " + videoHeight);
326            Log.v(TAG, "videoFPS : " + videoFps);
327            Log.v(TAG, "videobitrate : " + videoBitrate);
328            Log.v(TAG, "audioBitrate : " + audioBitrate);
329            Log.v(TAG, "audioChannel : " + audioChannels);
330            Log.v(TAG, "AudioSampleRate : " + audioSamplingRate);
331
332            MediaRecorder mMediaRecorder = new MediaRecorder();
333            mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
334            mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
335            mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
336            mMediaRecorder.setOutputFile(filename);
337            mMediaRecorder.setVideoFrameRate(videoFps);
338            mMediaRecorder.setVideoSize(videoWidth, videoHeight);
339            mMediaRecorder.setVideoEncodingBitRate(videoBitrate);
340            mMediaRecorder.setAudioEncodingBitRate(audioBitrate);
341            mMediaRecorder.setAudioChannels(audioChannels);
342            mMediaRecorder.setAudioSamplingRate(audioSamplingRate);
343            mMediaRecorder.setVideoEncoder(videoEncoder);
344            mMediaRecorder.setAudioEncoder(audioEncoder);
345            mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
346            mMediaRecorder.prepare();
347            mMediaRecorder.start();
348            Thread.sleep(MediaNames.RECORDED_TIME);
349            mMediaRecorder.stop();
350            mMediaRecorder.release();
351            recordSuccess = validateVideo(filename, videoWidth, videoHeight);
352        } catch (Exception e) {
353            Log.v(TAG, e.toString());
354            return false;
355        }
356        return recordSuccess;
357    }
358
359    private boolean invalidRecordSetting(int frameRate, int width, int height,
360            int videoFormat, int outFormat, String outFile, boolean videoOnly) {
361        try {
362            if (!videoOnly) {
363                Log.v(TAG, "setAudioSource");
364                mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
365            }
366            mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
367            mRecorder.setOutputFormat(outFormat);
368            Log.v(TAG, "output format " + outFormat);
369            mRecorder.setOutputFile(outFile);
370            mRecorder.setVideoFrameRate(frameRate);
371            mRecorder.setVideoSize(width, height);
372            Log.v(TAG, "setEncoder");
373            mRecorder.setVideoEncoder(videoFormat);
374            if (!videoOnly) {
375                mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
376            }
377            mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
378            Log.v(TAG, "setPreview");
379            mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
380            Log.v(TAG, "prepare");
381            mRecorder.prepare();
382            Log.v(TAG, "start");
383            mRecorder.start();
384            Thread.sleep(MediaNames.RECORDED_TIME);
385            Log.v(TAG, "stop");
386            mRecorder.stop();
387            mRecorder.release();
388        } catch (Exception e) {
389            Log.v("record video failed ", e.toString());
390            mRecorder.release();
391            Log.v(TAG, "reset and release");
392            return true;
393        }
394        return false;
395    }
396
397    private void getOutputVideoProperty(String outputFilePath) {
398        MediaPlayer mediaPlayer = new MediaPlayer();
399        try {
400            mediaPlayer.setDataSource(outputFilePath);
401            Log.v(TAG, "file Path = " + outputFilePath);
402            mediaPlayer.setDisplay(MediaFrameworkTest.mSurfaceView.getHolder());
403            Log.v(TAG, "before player prepare");
404            mediaPlayer.prepare();
405            Log.v(TAG, "before getduration");
406            mOutputDuration = mediaPlayer.getDuration();
407            Log.v(TAG, "get video dimension");
408            Thread.sleep(1000);
409            mOutputVideoHeight = mediaPlayer.getVideoHeight();
410            mOutputVideoWidth = mediaPlayer.getVideoWidth();
411            mediaPlayer.release();
412        } catch (Exception e) {
413            Log.v(TAG, e.toString());
414            mediaPlayer.release();
415        }
416    }
417
418    private boolean validateVideo(String filePath, int width, int height) {
419        boolean validVideo = false;
420        getOutputVideoProperty(filePath);
421        if (mOutputVideoWidth == width && mOutputVideoHeight == height &&
422                mOutputDuration > MediaNames.VALID_VIDEO_DURATION ) {
423            validVideo = true;
424        }
425        Log.v(TAG, "width = " + mOutputVideoWidth + " height = " + mOutputVideoHeight + " Duration = " + mOutputDuration);
426        return validVideo;
427    }
428
429    @LargeTest
430    /*
431     * This test case set the camera in portrait mode.
432     * Verification: validate the video dimension and the duration.
433     */
434    public void testPortraitH263() throws Exception {
435        boolean videoRecordedResult = false;
436        try {
437            mCamera = Camera.open(CAMERA_ID);
438            Camera.Parameters parameters = mCamera.getParameters();
439            parameters.setPreviewSize(352, 288);
440            parameters.set("orientation", "portrait");
441            mCamera.setParameters(parameters);
442            mCamera.unlock();
443            mRecorder.setCamera(mCamera);
444            Thread.sleep(1000);
445            int codec = MediaRecorder.VideoEncoder.H263;
446            int frameRate = MediaProfileReader.getMaxFrameRateForCodec(codec);
447            recordVideo(frameRate, 352, 288, codec,
448                    MediaRecorder.OutputFormat.THREE_GPP,
449                    MediaNames.RECORDED_PORTRAIT_H263, true);
450            mCamera.lock();
451            mCamera.release();
452            videoRecordedResult =
453                validateVideo(MediaNames.RECORDED_PORTRAIT_H263, 352, 288);
454        } catch (Exception e) {
455            Log.v(TAG, e.toString());
456        }
457        assertTrue("PortraitH263", videoRecordedResult);
458    }
459
460    @LargeTest
461    public void testInvalidVideoPath() throws Exception {
462        boolean isTestInvalidVideoPathSuccessful = false;
463        isTestInvalidVideoPathSuccessful = invalidRecordSetting(15, 176, 144, MediaRecorder.VideoEncoder.H263,
464               MediaRecorder.OutputFormat.THREE_GPP, MediaNames.INVALD_VIDEO_PATH, false);
465        assertTrue("Invalid outputFile Path", isTestInvalidVideoPathSuccessful);
466    }
467
468    @LargeTest
469    //test cases for the new codec
470    public void testDeviceSpecificCodec() throws Exception {
471        int noOfFailure = 0;
472        boolean recordSuccess = false;
473        String deviceType = MediaProfileReader.getDeviceType();
474        Log.v(TAG, "deviceType = " + deviceType);
475        List<VideoEncoderCap> videoEncoders = MediaProfileReader.getVideoEncoders();
476        List<AudioEncoderCap> audioEncoders = MediaProfileReader.getAudioEncoders();
477        for (int k = 0; k < 2; k++) {
478            for (VideoEncoderCap videoEncoder: videoEncoders) {
479                for (AudioEncoderCap audioEncoder: audioEncoders) {
480                    if (k == 0) {
481                        recordSuccess = recordVideoWithPara(videoEncoder, audioEncoder, true);
482                    } else {
483                        recordSuccess = recordVideoWithPara(videoEncoder, audioEncoder, false);
484                    }
485                    if (!recordSuccess) {
486                        Log.v(TAG, "testDeviceSpecificCodec failed");
487                        Log.v(TAG, "Encoder = " + videoEncoder.mCodec + "Audio Encoder = " + audioEncoder.mCodec);
488                        noOfFailure++;
489                    }
490                }
491            }
492        }
493        if (noOfFailure != 0) {
494            assertTrue("testDeviceSpecificCodec", false);
495        }
496    }
497
498    // Test MediaRecorder.getSurface() api with surface or camera source
499    public void testGetSurfaceApi() {
500        boolean success = false;
501        int noOfFailure = 0;
502        try {
503            for (int k = 0; k < 2; k++) {
504                success = validateGetSurface(
505                        k == 0 ? true : false /* useSurface */);
506                if (!success) {
507                    noOfFailure++;
508                }
509            }
510        } catch (Exception e) {
511            Log.v(TAG, e.toString());
512        }
513        assertTrue("testGetSurfaceApi", noOfFailure == 0);
514    }
515
516    // Test recording from surface source with/without audio
517    public void testSurfaceRecording() {
518        boolean success = false;
519        int noOfFailure = 0;
520        try {
521            int codec = MediaRecorder.VideoEncoder.H264;
522            int frameRate = MediaProfileReader.getMaxFrameRateForCodec(codec);
523            for (int k = 0; k < 2; k++) {
524                String filename = "/sdcard/surface_" +
525                            (k==0?"video_only":"with_audio") + ".3gp";
526
527                success = recordVideoFromSurface(frameRate, 0, 352, 288, codec,
528                        MediaRecorder.OutputFormat.THREE_GPP, filename,
529                        k == 0 ? true : false /* videoOnly */);
530                if (success) {
531                    success = validateVideo(filename, 352, 288);
532                }
533                if (!success) {
534                    noOfFailure++;
535                }
536            }
537        } catch (Exception e) {
538            Log.v(TAG, e.toString());
539        }
540        assertTrue("testSurfaceRecording", noOfFailure == 0);
541    }
542
543    // Test recording from surface source with/without audio
544    public void testSurfaceRecordingTimeLapse() {
545        boolean success = false;
546        int noOfFailure = 0;
547        try {
548            int codec = MediaRecorder.VideoEncoder.H264;
549            int frameRate = MediaProfileReader.getMaxFrameRateForCodec(codec);
550            for (int k = 0; k < 2; k++) {
551                // k==0: time lapse test, set capture rate to MIN_VIDEO_FPS
552                // k==1: slow motion test, set capture rate to HIGH_SPEED_FPS
553                String filename = "/sdcard/surface_" +
554                            (k==0 ? "time_lapse" : "slow_motion") + ".3gp";
555
556                // always set videoOnly=false, MediaRecorder should disable
557                // audio automatically with time lapse/slow motion
558                success = recordVideoFromSurface(frameRate,
559                        k==0 ? MIN_VIDEO_FPS : HIGH_SPEED_FPS,
560                        352, 288, codec,
561                        MediaRecorder.OutputFormat.THREE_GPP,
562                        filename, false /* videoOnly */);
563                if (success) {
564                    success = validateVideo(filename, 352, 288);
565                }
566                if (!success) {
567                    noOfFailure++;
568                }
569            }
570        } catch (Exception e) {
571            Log.v(TAG, e.toString());
572        }
573        assertTrue("testSurfaceRecordingTimeLapse", noOfFailure == 0);
574    }
575
576}
577