最近项目中有用到视频录制的功能,所以就有了一番探索。下面将遇到的一些问题以及解决办法记录下来。
其实,我们项目中的视频录制是高仿微信朋友圈小视频的(我不会告诉你,ui设计师就告诉我们让我们参照微信小视频录制来做,哈哈,当然我们ui设计师还是做了一些很个性的改动的)。大家都知道微信朋友圈小视频录制时是竖屏录制的,且比例很协调。那么视频过程就分为录制之前的预览界面,以及开始录制时候的录制页面了。所以竖屏录制关键就在于这两个阶段的宽高设置了。
如下就是预览界面的一些设置,最主要的就是摄像头的设置了。
private int videoWidth,videoHeight;//视频录制的宽高
/**
* 初始化相机
*/
private void initCamera() {
try {
//如果有两个摄像头那么开启后置的摄像头
if (Camera.getNumberOfCameras() == 2) {
mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
} else {
mCamera = Camera.open();
}
Camera.Parameters parameters = mCamera.getParameters();//获取相机参数
if (mSize == null) {
List<Camera.Size> vSizeList = parameters.getSupportedPreviewSizes();//Gets the supported preview sizes
for (Camera.Size size : vSizeList) {
if (size.width == 640 && size.height == 480) {
this.mSize = size;
break;
}
}
List<String> focusModesList = parameters.getSupportedFocusModes();
//增加对聚焦模式的判断
if (focusModesList.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
} else if (focusModesList.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
}
//因为我们是竖屏录制,所以就宽设置成高了
if(mSize == null){
mSize = vSizeList.get(0);
}
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) surfaceviewSf.getLayoutParams();
layoutParams.width = DevUtils.getScreenWidth(this);
layoutParams.height = layoutParams.width * 4 / 3;
surfaceviewSf.setLayoutParams(layoutParams);
//因为用正常宽高比在某些手机上面会抛出异常,所以有了特殊判断
/* if(Build.MODEL.equals("CHM-UL00") || Build.MODEL.contains("MI 4") || Build.MODEL.equals("m6010")){
parameters.setPreviewSize(mSize.width,mSize.height);
}else{
parameters.setPreviewSize(mSize.height,mSize.width);
}*/
videoWidth = mSize.height;
videoHeight = mSize.width;
parameters.setPreviewSize(mSize.height,mSize.width);
//如果设置参数出错一般是预览参数不支持,所以我们就
try {
mCamera.setParameters(parameters);
} catch (Exception e) {
LogUtils.e(e);
parameters.setPreviewSize(mSize.width,mSize.height);
mCamera.setParameters(parameters);
videoWidth = mSize.width;
videoHeight = mSize.height;
}
}
mCamera.setDisplayOrientation(90);
} catch (Exception e) {
LogUtils.e(e);
LogUtils.d("nihao", "初始化camera摄像头出错");
MToast.show("初始化相机出错,请查看是否开启了摄像权限。");
onBackKeyPressed();
}
}
在代码中能够看到我们首先获取的是手机支持的预览size了。我们需要的是size.width == 640 && size.height == 480,其实将以上的List<Camera.Size> vSizeList打印出来就可以 看到手机输出的宽比高的值都是要大的,例如下面截图是一款测试机支持的预览宽高值。
所以我们有了这行代码parameters.setPreviewSize(mSize.height,mSize.width)(我设置的是预览的宽是480,高是640了,细心的同学发现我是讲宽高调换位置了);当然我是假设手机支持这种参数设置,但是实际测试出来结果是一些手机是不支持这样设置宽的值比高的值小的,我上面有段代码是注释掉的,那个就是我对于一些手机型号的判断,在这些手机上面会抛出异常的,因为他们不支持我设置的这种参数。但是后来发现我们只是加了这几种手机的判断,万一将来有款手机我们没有测试到,然后它也不支持我们设置的参数,那么就直接报错,无法预览了。所以我对于下面这行代码mCamera.setParameters(parameters)加了trycatch了。然后遇到不支持我们设置的参数的时候,代码就会走进catch里面了。然后就设置一个手机一定支持的预览size。但是这个时候预览的比例可能是不协调的了。但也是无奈之举了。好的以上就是预览部分的设置了。
记下来看下录制部分的代码了。
//初始化mediaRecorder,不要在一进入页面开始就初始化,否则会造成黑屏的
private void initRecord() {
try {
if (mRecorder == null) {
mRecorder = new MediaRecorder(); // 创建MediaRecorder
}
if (mCamera != null) {
mCamera.stopPreview();
mCamera.unlock();
mRecorder.setCamera(mCamera);
}
// 设置音频采集方式
mRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
//设置视频的采集方式
mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
//设置文件的输出格式
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);//aac_adif, aac_adts, output_format_rtp_avp, output_format_mpeg2ts ,webm
//设置audio的编码格式
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
//设置video的编码格式
mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
//设置录制的视频编码比特率
mRecorder.setVideoEncodingBitRate(1024 * 1024);
//设置录制的视频帧率,注意文档的说明:
mRecorder.setVideoFrameRate(30);
//设置要捕获的视频的宽度和高度
/* if(Build.MODEL.equals("CHM-UL00") || Build.MODEL.contains("MI 4") || Build.MODEL.equals("m6010") || Build.MODEL.equals("HUAWEI MT7-TL10")){
mSurfaceHolder.setFixedSize(640, 480);//最高只能设置640x480
mRecorder.setVideoSize(640, 480);//最高只能设置640x480
}else{
mSurfaceHolder.setFixedSize(480, 640);//最高只能设置640x480
mRecorder.setVideoSize(480, 640);//最高只能设置640x480
}*/
/**
* 其实这里讨了个巧,因为设置相机参数时候如果抛出异常是会被捕获的。但是如果下面设置参数抛出异常时候
* 是不能被捕获的。但是如果相机设置成功的参数(主要是previewSize了)没有报错,那么下面的设置录制视频
* 宽高的时候也用那个参数也是不会报错的了
*/
mSurfaceHolder.setFixedSize(videoWidth, videoHeight);//最高只能设置640x480
mRecorder.setVideoSize(videoWidth, videoHeight);//最高只能设置640x480
//设置记录会话的最大持续时间(毫秒),如果超过了这一时间,那么继续录制是无效的,最终的视频只会有前60秒
mRecorder.setMaxDuration(Const.RECORDVIDEO_MAXTIME);
mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
File dir = new File(FormatUtils.resolveBuild(FileUtils.getBaseFilePath(),Const.VIDEORECORD_DIR));
if (!dir.exists()) {
dir.mkdir();
}
currentPath = FormatUtils.resolveBuild(dir,"/",System.currentTimeMillis(),".mp4");
//设置输出文件的路径
mRecorder.setOutputFile(currentPath);
mRecorder.setOnInfoListener(this);
mRecorder.setOnErrorListener(this);
//这样设置输出的视频的旋转方向,不过在mac上以及自己的播放器上是好的。在windows上。
mRecorder.setOrientationHint(90);
} catch (Exception e) {
LogUtils.d("nihao", "初始化MediaRecorder出错");
LogUtils.e(e);
}
}
其实,注释写的比较清楚了。最主要的就是设置录制的视频的宽高的地方就是以及录制出来文件宽高的两个属性了,就是setFixedSize和setVideoSize,sdk中对于前者的解释是/**
* Make the surface a fixed size. It will never change from this size.
* When working with a {@link SurfaceView}, this must be called from the
* same thread running the SurfaceView's window.
*
* @param width The surface's width.
* @param height The surface's height.
*/
大意录制时候是一个固定的尺寸,这个方法被调用时候,必须被surfaceview所在的线程调用。对于后者的解释是:
/**
* Sets the width and height of the video to be captured. Must be called
* after setVideoSource(). Call this after setOutFormat() but before
* prepare().
*
* @param width the width of the video to be captured
* @param height the height of the video to be captured
* @throws IllegalStateException if it is called after
* prepare() or before setOutputFormat()
*/
就是要录制的video的宽高(这个应该就是最终录制出来的视频的宽高了)。同时对于此方法的调用时机也做了严格的限制。这俩方法如果设置的参数不支持的话,同样是会抛出异常,但是不同于上面预览时候,这种情况抛出的异常是无法捕获的。然后,我们就讨了个巧,就是将上面的预览尺寸拿来在这里直接用了(因为只要预览成功了,那么这个尺寸一定是这个手机所支持的了)。同时代码中最后一行对于视频录制的方向也是做了限定,如果不限定的话,录制出来的视频在手机上面播放时候方向会是倒着的。当然上面也说了,在手机自己的播放器以及windows电脑上播放时候即使这样设置也是倒着的(虽然有的播放器可以对视频播放方向进行旋转)。但是这种设置在我自己写的播放视频的代码里面方向是对的,这个对于我就可以了。在mac上面也是对的(看来mac对于视频的支持性要高于windows呀,哈哈哈)。
以上就是这一次做视频录制的一些发现。当然对于视频宽高的设置以及视频方向的设置还是有欠缺的地方。真是不知道微信是怎么做的竖屏录制的,且不变形的。有知道的同学,欢迎指教。
以上如有不对之处,欢迎批评指正。有好的建议,也请提,好共同提高。