android mediareorder 使用实践总结

来源:互联网 发布:java培训介绍 编辑:程序博客网 时间:2024/04/28 16:56

 这里对这段时间以来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要反过来传// 如果支持变焦,把变焦设置为0if (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上联系,求做朋友。 


0 0
原创粉丝点击