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