寫在前面:關(guān)于什么是Camera2這里我就不多介紹了倒得,大家可以自行去百度夭禽。公司項目因為需要實現(xiàn)一個類似微信拍小視頻的功能,所以搗騰了一段時間的Camera2菩彬,期間遇到很多坑。今天這篇文章主要是記錄下我所遇到的問題以及對此做出的解決方法骗灶,同時為了方便耙旦,這里我也將此功能封裝成了library供大家使用。
一免都、先看一下效果圖:
二氓鄙、3步集成到自己的項目中:
1.在AndroidManifest.xml申明所需要的權(quán)限:
(注:請確保進入Camera2的時候已經(jīng)擁有這三項權(quán)限了业舍,Android6.0需要動態(tài)去申請權(quán)限)
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
2.在project的build.gradle和app的build.gradle下分別申明如下代碼:
project的build.gradle:
allprojects {
repositories {
maven { url 'https://jitpack.io' }//這句代碼
}
}
app的build.gradle:
dependencies {
compile 'com.github.CKTim:Camera2Record:v1.0.0'
}
3.打開Camera2:
因為每個人對拍完照或者錄完像后的處理都不一樣,所以這里我采用拍完跳轉(zhuǎn)activity的方式态罪,將拍照錄像后的地址傳遞給了下一個activity下面,當然這個activty界面邏輯什么的都是由你自己去編寫的,你可以對獲取到的圖片視頻地址進行你需要的編輯耗啦,例如再次壓縮或者重拍等操作:
getIntent().getStringExtra(Camera2Config.INTENT_PATH_SAVE_PIC);//獲取圖片地址
getIntent().getStringExtra(Camera2Config.INTENT_PATH_SAVE_VIDEO);//獲取視頻地址
如下用法:
//配置Camera2相關(guān)參數(shù)帜讲,
Camera2Config.RECORD_MAX_TIME = 10;//最長錄制時間
Camera2Config.RECORD_MIN_TIME=2;//最短錄制時間
Camera2Config.RECORD_PROGRESS_VIEW_COLOR=R.color.colorAccent;//錄制進度條顏色
Camera2Config.PREVIEW_MAX_HEIGHT=1000;////最大高度預覽尺寸椒拗,默認大于1000的第一個
Camera2Config.PATH_SAVE_VIDEO=;//視頻保存地址,注意需要以/結(jié)束在验,例如Camera2/
Camera2Config.PATH_SAVE_PIC=;圖片保存地址腋舌,注意需要以/結(jié)束渗蟹,例如Camera2/
Camera2Config.ENABLE_CAPTURE=true;//是否開啟拍照功能
Camera2Config.ENABLE_RECORD=true;//是否開啟錄像功能
//拍完照需要跳轉(zhuǎn)的activity赞辩,這個activity自己編寫诗宣,可以獲取到保存的視頻或者圖片地址
Camera2Config.ACTIVITY_AFTER_CAPTURE = Camera2RecordFinishActivity.class;
btnOpenCamera2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//進入Camera2界面
Camera2RecordActivity.start(MainActivity.this);
}
});
三召庞、Camera2Record library的優(yōu)缺點:
缺點:
1.因為Camera2是安卓5.0以后的api来破,所以如果你的應用需要兼顧到5.0以下,這個library就不適合了诅诱。
2.錄制界面不好自定義娘荡,如果對界面沒有特殊需求的可以直接用驶沼,如果你對Camera2有一定了解或者界面需要自己自定義,我建議還是直接copy源碼去用大年,然后自己修改布局翔试,其實核心的代碼就一個Camera2RecordActivity而已。
優(yōu)點:
1.代碼總共4個類垦缅,無其他第三方庫失都,都是系統(tǒng)的api幸冻。
2.拍照和錄制都是參考谷歌官方Demo(這算優(yōu)點?)
2.錄制視頻小咳焚,質(zhì)量還可以,10s大概1.2M左右碑定,可能會存在波動。之前打算采用FFMPEG壓縮漫试,C++不行就沒再研究下去了碘赖,這里采用的是對MediaRecorder進行了一些配置,這里坑也很多播掷,后面我會分析出來歧匈。
3.可以進行預覽尺寸的配置砰嘁,對預覽進行了一些處理矮湘,防止預覽變形。
4.支持錄制中開啟閃關(guān)燈宫静,雙指縮放
四、踩過的坑:
關(guān)于預覽變形
預覽變形是很多人都會遇到的問題孤里,這里主要是因為預覽的尺寸和TextureView或者Surfaceview的尺寸不匹配導致的捌袜,例如你的TextureView是4:3比例的,然后用16:9的預覽尺寸的話炸枣,他就會變形了虏等,必須保證TextureView的尺寸和預覽尺寸是一樣的。像我在library中處理的一樣适肠,先設(shè)置了activity為全屏模式霍衫,包括導航欄,保證TextureView是覆蓋整個屏幕的侯养,然后每次獲取TextureView的寬高比敦跌,再從本機相機所支持的尺寸中獲取和TextureView一樣比例的,以此來避免變形的情況逛揩。
由于預覽尺寸過大導致卡頓
因為一個比例下他是有多個尺寸的柠傍,就像16:9這個比例麸俘,它有1280×720、1920×1080等等的尺寸从媚,如果尺寸過大拜效,就會給我們的預覽造成很大的卡頓,說是預覽預覽稻励,我覺得只要選擇一個合適的尺寸就行了望抽,針對這個,我在庫中也封裝了一個參數(shù)辑奈,即是
Camera2Config.PREVIEW_MAX_HEIGHT=1000
它表示會從在你屏幕的比例下的相機map中鸠窗,取出第一個高度超過1000的尺寸稍计,理論上我們只需要1280×720或者1920×1080這種預覽尺寸就行了,而不需要像在有些三星手機預覽達到3000多那么大硅则,這個看你自己自定義。
錄制視頻過大的問題
視頻壓縮最火的應該就是FFmpeg了吧揪垄,不過這個庫從編譯到運用都不是一件簡單的事,C++功底不行酷愧,弄了兩天沒弄出來就放棄了溶浴。。自帶的MediaRecorder錄制出來的視頻比較大谅将,雖然我們可以通過
mMediaRecorder.setVideoEncodingBitRate(2500000);
mMediaRecorder.setVideoFrameRate(20);
mMediaRecorder.setVideoSize(width,height);
來對MediaRecorder進行一些配置以此來達到壓縮視頻的目的,但是這些方法并不是在所有機型上都是通用的隅熙,有時候會出現(xiàn)一些問題,就像在一加手機上弯淘,我設(shè)置了setVideoSize后就出現(xiàn)無法錄制的現(xiàn)象了,針對這個問題态鳖,我是采用如下方法代碼解決:
// 這里有點投機取巧的方式浆竭,不過證明方法也是不錯的
// 錄制出來10S的視頻,大概1.2M肌索,清晰度不錯,
// 而且避免了因為手動設(shè)置參數(shù)導致無法錄制的情況
// 手機一般都有這個格式CamcorderProfile.QUALITY_480P,
// 因為單單錄制480P的視頻還是很大的站宗,
// 所以我們在手動根據(jù)預覽尺寸配置一下videoBitRate,值越高越大
// QUALITY_QVGA清晰度一般,不過視頻很小或辖,一般10S才幾百K
// 判斷有沒有這個手機有沒有這個參數(shù)
if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_480P)) {
CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_480P);
profile.videoBitRate = mPreviewSize.getWidth() * mPreviewSize.getHeight();
mMediaRecorder.setProfile(profile);
mMediaRecorder.setPreviewDisplay(new Surface(mTextureView.getSurfaceTexture()));
} else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_720P)) {
CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_720P);
profile.videoBitRate = mPreviewSize.getWidth() * mPreviewSize.getHeight();
mMediaRecorder.setProfile(profile);
mMediaRecorder.setPreviewDisplay(new Surface(mTextureView.getSurfaceTexture()));
} else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_QVGA)) {
mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_QVGA));
mMediaRecorder.setPreviewDisplay(new Surface(mTextureView.getSurfaceTexture()));
} else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_CIF)) {
mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_CIF));
mMediaRecorder.setPreviewDisplay(new Surface(mTextureView.getSurfaceTexture()));
} else {
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
mMediaRecorder.setVideoEncodingBitRate(2500000);
mMediaRecorder.setVideoFrameRate(20);
mMediaRecorder.setVideoSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
}
點擊和長按的手勢處理問題
有兩種方式,第一種是監(jiān)聽ontouch事件县爬,在down事件發(fā)生時,延遲個幾百毫秒開啟長按監(jiān)聽線程耳高,在up事件進行統(tǒng)一處理,如果線程已經(jīng)開啟了碌燕,則判斷是長按事件愈捅,否則為點擊事件改鲫,其次壶冒,還有一種方式是使用系統(tǒng)自帶的GestureDetector去監(jiān)聽事件,這里我采用的是第一種方式咸作。
華為榮耀錄制小視頻截圖:
五、總結(jié):
開源出來是好事桐智,但更重要的還是提供一種解決方法和思路給大家刊驴。這是我的第一次開源庫捆憎,可能還有很多做的不好的地方,歡迎大家提建議知举。
聯(lián)系方式:471497226@qq.com
github地址(含Demo和library):https://github.com/CKTim/Camera2Record
Camera2谷歌官方拍照Demo: https://github.com/googlesamples/android-Camera2Basic
Camera2谷歌官方錄像Demo: https://github.com/googlesamples/android-Camera2Video