以前項目中拍照和錄像是分開的,現(xiàn)在有個需求是仿照微信,把拍照和錄制視頻合并,實現(xiàn)短按拍照,長按錄像。之前看到過一個開源庫 JCamera ,這個基本已經(jīng)實現(xiàn)了,但是沒仔細看過代碼,于是從github上把代碼clone到本地,結(jié)合公司項目,把源碼進行了一部分修改。關于JCamera,網(wǎng)上可以搜到它的介紹和用法,這里就不多說了,現(xiàn)在說一下自己遇到的一些問題和解決方案。
1、JCamera基本可以滿足短按拍照和長按錄制視頻的需求,但是存在一些小問題,在項目中是需要解決的
a.部分機型是可以支持鏡頭的縮放問題
b.部分機型開始錄像和結(jié)束錄像都有個系統(tǒng)的“滴”的一聲
針對第一個問題,源碼中的判斷如下
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;
}
}
這樣之后就可以進行縮放鏡頭了
第二個問題,錄像的開始和結(jié)束會播放一下系統(tǒng)的“滴”的一聲,這個著實是頭疼了,沒找到什么好的解決方案,再一個因為項目中以前在錄像本身就進行了一個android系統(tǒng)版本的判斷,5.0以上使用最新的Camera2 API,5.0以下還是用以前的Camera。使用Camera2是不存在這個問題的,JCamera并沒有使用 Camera2,自己對Camera2不太了解,而且錄像功能一開始不是自己著手做的,現(xiàn)在只是根據(jù)需求進行功能優(yōu)化。所以沒辦法,為了解決這個問題,只能找一些關于Camera2的使用介紹。5.0一下使用JCamera,5.0以上使用Camera2。
關于Camera2,網(wǎng)上的一些資料并不是很多,而最快的了解使用方式就是通過Demo,看看別人怎么對API進行使用的。搜到一篇簡書上介紹Camera2的文章http://www.itdecent.cn/p/f8c694a4fb57,也是在同一個界面進行長按錄像和短按拍照的操作,于是下載下來進行了一番研究,由于作者對拍攝結(jié)果并沒有做過多的處理,不過,對于我來說,完全可以在這個基礎上進行更進一步的處理了。
處理過程中遇到的問題:
a.UI上使用和微信類似的樣式
b.功能上,拍照和錄像之間來回切換會崩潰問題
c.上下滑動縮放問題
解決方案:
a.UI上,可以使用JCamera的就可以了,可以使用里面封裝的控件,在基礎上修改就可以
b.這個沒好的方法,只能根據(jù)log日志進行問題定位,和不斷的調(diào)試,不懂的搜一下網(wǎng)上別的小伙伴怎么解決的。這個耗費了我兩三天,過程真的是爽歪歪的。
c.對于Camera2的縮放問題,網(wǎng)上說的都是兩指縮放,這個在拍照的時候可以雙指,在錄制的時候,是需要上下滑動進行縮放鏡頭的,我的解決方法是,按下拍的時候,是可以確定一個點的做一個全局變量,然后與滑動的位置點進行配合處理,這樣就可以類似雙指動作了。關鍵代碼如下:
@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; //修改當前狀態(tài)為點擊按下
//判斷按鈕狀態(tài)是否為可錄制狀態(tài)
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) {
//活動區(qū)域?qū)挾群妥魑飬^(qū)域?qū)挾戎群突顒訁^(qū)域高度和作物區(qū)域高度之比的最大比率
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);
//調(diào)用縮放回調(diào)接口
captureListener.recordZoom(zoom);
}
finger_spacing = current_finger_spacing;
}
break;
case MotionEvent.ACTION_UP:
//根據(jù)當前按鈕的狀態(tài)進行相應的處理
handlerUnpressByState();
break;
}
return true;
}
最終實現(xiàn)了個5.0一下使用JCamera,5.0以上使用Camera2 的效果。抽空做了個demo,上傳到了CSDN上,demo下載需要5積分,下載地址https://download.csdn.net/my,當然大家也可以到github上下載免費的,demo地址:
https://github.com/Alvin9234/CaptureDemo
歡迎大家一起討論,共同學習