android mediareorder 使用实践总结


 这里对这段时间以来mediarecorder的学习进行一下总结。先对mediarecorder的基本用法进行一些说明。
                   
  private void createCamera(int type){
	cameraType = type;
	mCamera = openCamera(type);
	if (mCamera==null){
		UiHelper.shortToast(this, "请尝试关闭其他相机软件再打开");
		return;
	}
	orientation = CameraUtil.setCameraDisplayOrientation(this, 0, mCamera);
	Camera.Parameters mParameters = mCamera.getParameters();

	Size size = getOptimalPreviewSize(mParameters.getSupportedPreviewSizes());
	curPreviewWidth = size.width;
	curPreviewHeight = size.height;
	mParameters.setPreviewSize(curPreviewWidth, curPreviewHeight);
	// 因为CamcorderProfile是以横屏为标准的,而当前屏幕录像时竖屏。所以要把Height和Width要反过来传

	// 如果支持变焦,把变焦设置为0
	if (mParameters.isZoomSupported()) mParameters.setZoom(0);
	// 设置为自动连续对焦
	List<String> mFocusModes = mParameters.getSupportedFocusModes();
	if (mFocusModes.contains(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
		mParameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
		mSupportContinuousVideo = true;
	} else {
		mSupportContinuousVideo = false;
	}

	if (mFocusModes.contains(Parameters.FOCUS_MODE_AUTO)) {
		mSupportAutoFocus = true;
	} else {
		mSupportAutoFocus = false;
	}
	mVideoFrame = getVideoFrame(mParameters.getSupportedPreviewFpsRange());
	// 设置为多媒体录制,加快打开的速度 
	mParameters.setRecordingHint(true);
	// 是否支持视频防抖,在小米4上会造成画面抖动
	if (mParameters.isVideoStabilizationSupported()){
	// mParameters.setVideoStabilization(true);
	}
	mCamera.setParameters(mParameters);
	try {
		mCamera.setPreviewDisplay(mSurfaceHolder);
	} catch (IOException e) {
		e.printStackTrace();
		mCamera.release();
	}
	mCamera.startPreview();
	// 因为CamcorderProfile是以横屏为标准的,而当前屏幕录像时竖屏。所以要把Height和Width要反过来传
	setSurfaceViewLayoutParams(curPreviewHeight,curPreviewWidth);
	initFlash();
	UiHelper.shortToast(this, " preview heith = " + curPreviewHeight+" width "+curPreviewWidth);

}	

	rivate void createMediaRecorder() {

          	if (mCamera == null)return;
		StartMediaRecord = true;
		if(mMediaRecorder == null){
		mMediaRecorder = new MediaRecorder();
		else {
			diaRecorder.reset();
		}
		mCamera.unlock();
		mMediaRecorder.setCamera(mCamera);
		// 获得预览界面
		mMediaRecorder.setOnErrorListener(errorListener);

		mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());

                // 因为我对camera设置了旋转90度,所以这里要做相应的处理


		mMediaRecorder.setOrientationHint(getCameraOrientation());

		mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
		mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
		mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
		mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
		mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
		// 录制视频的最大时长, 在小米4上面会造成视频提前暂停
		// mMediaRecorder.setMaxDuration(MAX_DURATION);
		// 视频大小
		try{
			mMediaRecorder.setVideoSize(curPreviewWidth, curPreviewHeight);
			mVideoWidth  = curPreviewHeight;
			mVideoHeight = curPreviewWidth;
		}catch(Exception e){
			CamcorderProfile profile = getProFile();
			mMediaRecorder.setVideoSize(profile.videoFrameWidth, profile.videoFrameHeight);
			mVideoWidth  = profile.videoFrameHeight;
			mVideoHeight = profile.videoFrameWidth;
		}
		//TODO 这段代码在Nexus 5会出错
		// if(AppContext.getSysCode().getCustomframerate()>14){
		// mMediaRecorder.setVideoFrameRate(AppContext.getSysCode().getCustomframerate());
		// }else{
		// mMediaRecorder.setVideoFrameRate(mVideoFrame);
		// }
		// 视频码率
		setVideoEncodingBitRate(mMediaRecorder);
		// 视频文件储存路径
		VideoTmp videoTmp = new VideoTmp(cameraType, createVideoUrl());
		mVideoTmps.add(videoTmp);
		mMediaRecorder.setOutputFile(videoTmp.getVideoTmpPath());
		try {
			mMediaRecorder.prepare();
			mHandler.sendEmptyMessage(MEDIA_RECORDER_START);
		} catch (Exception e) {

			Log.e(TAG, "启动拍摄失败");
	
			releaseMediaRecorder();
		} finally{
			mIsStartMediaRecord = false;
		}

          }



     上述就是mediarecorder的基本用法了,这里对说一下使用过程中一些莫名其妙的问题。
     1、拍摄和预览画面不一样的问题。
          我们所编写的录制页面,在点击拍摄之前一般都提供预览的。所以我们使用camera进行预览,同时我们是使用了surface而不是texture,因为我们发现虽然google的官方demo中,已经是使用了textture进行预览,但是我们在实际中发现了有极个别机型不支持预览。在我们通过mediarecorder.setPreviewDisplay的时候,是设置了录制的时候的预览画面,如果我们不设置这个方法,是默认使用camera的预览画面的。如果我们是使用和平面比例一样的分辨率进行拍摄的话,是一切正常的。但是在使用其他分辨率进行拍摄的时候,就出现了一些无法解决的问题。
          我们希望不使用过高的分辨率进行拍摄,所以选用了640*480的分辨率拍摄(虽然我们看到大部分机型有都这个分辨率,但是不一定全部支持,因为在mediarecorder的Profile中,使用480P拍摄的时候,高度可以是640和720的两种选择)。由于这个拍摄分辨率和屏幕分辨率的比例不一样,所以需要将预览的surface拉伸,使得预览的画面不足以失真。所以我们使用了以下这段代码进行放大:
  <span style="white-space:pre">	</span>private void setSurfaceViewLayoutParams(float width, float height){
		final int screenHeight = AppContext.deviceInfo.getScreenHeight();
		final int screenWidth = AppContext.deviceInfo.getScreenWidth();
		FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) mSurfaceView
				.getLayoutParams();
		if (screenHeight - height > screenWidth - width) {
			// 高度适配
			params.width = (int) (width * (screenHeight / height));
			params.height = screenHeight;
		} else {
			// 宽度适配
			params.width = screenWidth;
			params.height = (int) (height * (screenWidth / width));
		}
		// 这里需要注意的一点是,如果surface的布局不是framelayout的话,需要同时改变它的父layout的width和height才有效果
		params.gravity = Gravity.CENTER;
		mSurfaceView.setLayoutParams(params);
		mSurfaceView.requestLayout();
	}


     通过这个拉伸处理之后,surface的尺寸是要比当前屏幕要大的,并且居中显示,所以在输出视频的时候,其实视频是要比用户所看到的要大的,所以需要在播放的时候,对播放的surface进行同样的处理,那么用户拍摄时看到的画面和播放时看到的就会试一样。
     使用这样的处理后,我们发现在htc one,nexus5和华为的一款手机上都是正常的,surface的画面正常的放大,画面比例正常。但是在小米3和oppo find 7 和三星galaxy note2上,我们发现虽然使用了setSurfaceViewLayoutParams进行了surface的layout调整,确发现了这几款手机在预览和拍摄时的画面是不一样的,预览的时候画面比例不正常,在点击拍摄,开始录制的时候,画面比例才恢复正常。我尝试将setSurfaceViewLayoutParams放在点击拍摄之后才执行,调整surface的layout,发现这几款记性在预览的时候,画面比例也是正常的,初步猜测是手机对拍摄camera的捕捉画面进行了处理,自动适应了屏幕的分辨率,避免画面的失真。但是在点击拍摄的一刻,确使用了代码中真正设置的参数,导致拍摄的时候显示的画面比例不正常。虽然我在开始拍摄之后使用setSurfaceViewLayoutparam进行了修正,但是画面会出现闪烁,就是从正常,点击拍摄时画面比例失真,再到恢复画面比例,这三个操作的时候可以看到明显的画面过度。

     真没有想到使用一个系统自带的类拍摄会如此的复杂,出现的兼容问题会这么多,在耗费了两天多后,尝试各种办法后依然没有效果,最终放弃了使用640*480这种固定分辨率的方式拍摄,而是使用最接近屏幕比例的分辨率进行拍摄,最后勉强成功。
     
     而在网上找的关于mediarecorder的拍摄资料,真的有点郁闷,各种文章互相转载,最全面的就是谷歌的官方demo,但是这个demo过于粗糙,根本没有办法直接拿来使用,也不会出现实际使用中的各种问题,所以想些一篇文章进行总结。来github上面关于mediarecorder的项目也是少得可怜,所以我也特意建立了一个,希望在构建一个相对简单的拍摄app的时候,大家不需要去看ffmpeg和opencv等这么重的东西。有兴趣的同学可以fork一起完善。
     如果上述的问题有解决方案,跪求大神github上联系,求做朋友。 


你可能感兴趣的:(android,视频,多媒体)