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