以前项目中拍照和录像是分开的,现在有个需求是仿照微信,把拍照和录制视频合并,实现短按拍照,长按录像。之前看到过一个开源库 JCamera ,这个基本已经实现了,但是没仔细看过代码,于是从github上把代码clone到本地,结合公司项目,把源码进行了一部分修改。关于JCamera,网上可以搜到它的介绍和用法,这里就不多说了,现在说一下自己遇到的一些问题和解决方案。
1、JCamera基本可以满足短按拍照和长按录制视频的需求,但是存在一些小问题,在项目中是需要解决的
a.部分机型是可以支持镜头的缩放问题
b.部分机型开始录像和结束录像都有个系统的“滴”的一声
针对第一个问题,源码中的判断如下
if (!mParams.isZoomSupported() || !mParams.isSmoothZoomSupported()) {
return;
}
isZoomSupported()是判断设备是否支持缩放,isSmoothZoomSupported()是判断是否支持平滑缩放,android的部分机型这两个返回一个是:isZoomSupported()放回true,isSmoothZoomSupported()返回false,也就是说支持缩放,但是不支持平滑缩放,于是我把setZoom() 方法改成了:
public void setZoom(float zoom, int type) {
if (mCamera == null) {
return;
}
if (mParams == null) {
mParams = mCamera.getParameters();
}
/*if (!mParams.isZoomSupported() || !mParams.isSmoothZoomSupported()) {
return;
}*/
if (!mParams.isZoomSupported()) {
return;
}
switch (type) {
case TYPE_RECORDER:
//如果不是录制视频中,上滑不会缩放
if (!isRecorder) {
return;
}
if (zoom >= 0) {
//每移动50个像素缩放一个级别
int scaleRate = (int) (zoom / 40);
float getMaxZoom = mParams.getMaxZoom();
if (scaleRate <= getMaxZoom && scaleRate >= nowScaleRate && recordScleRate != scaleRate) {
if(mParams.isSmoothZoomSupported()){
mCamera.startSmoothZoom(scaleRate);
}else{
if(scaleRate+10<=getMaxZoom){
mParams.setZoom(scaleRate+10);
}else{
mParams.setZoom((int)getMaxZoom);
}
mCamera.setParameters(mParams);
}
recordScleRate = scaleRate;
}
}
break;
case TYPE_CAPTURE:
if (isRecorder) {
return;
}
//每移动50个像素缩放一个级别
int scaleRate = (int) (zoom / 50);
if (scaleRate < mParams.getMaxZoom()) {
nowScaleRate += scaleRate;
if (nowScaleRate < 0) {
nowScaleRate = 0;
} else if (nowScaleRate > mParams.getMaxZoom()) {
nowScaleRate = mParams.getMaxZoom();
}
if(mParams.isSmoothZoomSupported()){
mCamera.startSmoothZoom(nowScaleRate);
}else{
mParams.setZoom(nowScaleRate);
mCamera.setParameters(mParams);
}
}
Log.i("","setZoom = " + nowScaleRate);
break;
}
}
这样之后就可以进行缩放镜头了
第二个问题,录像的开始和结束会播放一下系统的“滴”的一声,这个着实是头疼了,没找到什么好的解决方案,再一个因为项目中以前在录像本身就进行了一个android系统版本的判断,5.0以上使用最新的Camera2 API,5.0以下还是用以前的Camera。使用Camera2是不存在这个问题的,JCamera并没有使用 Camera2,自己对Camera2不太了解,而且录像功能一开始不是自己着手做的,现在只是根据需求进行功能优化。所以没办法,为了解决这个问题,只能找一些关于Camera2的使用介绍。5.0一下使用JCamera,5.0以上使用Camera2。
关于Camera2,网上的一些资料并不是很多,而最快的了解使用方式就是通过Demo,看看别人怎么对API进行使用的。搜到一篇简书上介绍Camera2的文章https://www.jianshu.com/p/f8c694a4fb57,也是在同一个界面进行长按录像和短按拍照的操作,于是下载下来进行了一番研究,由于作者对拍摄结果并没有做过多的处理,不过,对于我来说,完全可以在这个基础上进行更进一步的处理了。
处理过程中遇到的问题:
a.UI上使用和微信类似的样式
b.功能上,拍照和录像之间来回切换会崩溃问题
c.上下滑动缩放问题
解决方案:
a.UI上,可以使用JCamera的就可以了,可以使用里面封装的控件,在基础上修改就可以
b.这个没好的方法,只能根据log日志进行问题定位,和不断的调试,不懂的搜一下网上别的小伙伴怎么解决的。这个耗费了我两三天,过程真的是爽歪歪的。
c.对于Camera2的缩放问题,网上说的都是两指缩放,这个在拍照的时候可以双指,在录制的时候,是需要上下滑动进行缩放镜头的,我的解决方法是,按下拍的时候,是可以确定一个点的做一个全局变量,然后与滑动的位置点进行配合处理,这样就可以类似双指动作了。关键代码如下:
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i("","state = " + state);
if (event.getPointerCount() > 1 || state != STATE_IDLE)
break;
state = STATE_PRESS; //修改当前状态为点击按下
//判断按钮状态是否为可录制状态
if ((button_state == BUTTON_STATE_ONLY_RECORDER || button_state == BUTTON_STATE_BOTH))
postDelayed(longPressRunnable, 500); //同时延长500启动长按后处理的逻辑Runnable
break;
case MotionEvent.ACTION_MOVE:
if (captureListener != null
&& (state == STATE_RECORDERING)
&& (button_state == BUTTON_STATE_ONLY_RECORDER || button_state == BUTTON_STATE_BOTH)
&& cameraCharacteristics!=null && event.getY()<center_Y-10) {
//活动区域宽度和作物区域宽度之比和活动区域高度和作物区域高度之比的最大比率
float maxZoom = (cameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM)) * 10;
Rect m = cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
float current_finger_spacing;
//计算两个触摸点的距离
current_finger_spacing = getFingerSpacing(event);
if (finger_spacing != 0) {
if (current_finger_spacing > finger_spacing && maxZoom > zoom_level) {
zoom_level++;
} else if (current_finger_spacing < finger_spacing && zoom_level > 1) {
zoom_level--;
}
int minW = (int) (m.width() / maxZoom);
int minH = (int) (m.height() / maxZoom);
int difW = m.width() - minW;
int difH = m.height() - minH;
int cropW = difW / 100 * zoom_level;
int cropH = difH / 100 * zoom_level;
cropW -= cropW & 3;
cropH -= cropH & 3;
zoom = new Rect(cropW, cropH, m.width() - cropW, m.height() - cropH);
//调用缩放回调接口
captureListener.recordZoom(zoom);
}
finger_spacing = current_finger_spacing;
}
break;
case MotionEvent.ACTION_UP:
//根据当前按钮的状态进行相应的处理
handlerUnpressByState();
break;
}
return true;
}
最终实现了个5.0一下使用JCamera,5.0以上使用Camera2 的效果。抽空做了个demo,上传到了CSDN上,demo下载需要5积分,下载地址https://download.csdn.net/my,当然大家也可以到github上下载免费的,demo地址:
https://github.com/Alvin9234/CaptureDemo
欢迎大家一起讨论,共同学习
网友评论