写在前面:关于什么是Camera2这里我就不多介绍了,大家可以自行去百度。公司项目因为需要实现一个类似微信拍小视频的功能,所以捣腾了一段时间的Camera2,期间遇到很多坑。今天这篇文章主要是记录下我所遇到的问题以及对此做出的解决方法,同时为了方便,这里我也将此功能封装成了library供大家使用。
一、先看一下效果图:
二、3步集成到自己的项目中:
1.在AndroidManifest.xml申明所需要的权限:
(注:请确保进入Camera2的时候已经拥有这三项权限了,Android6.0需要动态去申请权限)
<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:
因为每个人对拍完照或者录完像后的处理都不一样,所以这里我采用拍完跳转activity的方式,将拍照录像后的地址传递给了下一个activity,当然这个activty界面逻辑什么的都是由你自己去编写的,你可以对获取到的图片视频地址进行你需要的编辑,例如再次压缩或者重拍等操作:
getIntent().getStringExtra(Camera2Config.INTENT_PATH_SAVE_PIC);//获取图片地址
getIntent().getStringExtra(Camera2Config.INTENT_PATH_SAVE_VIDEO);//获取视频地址
如下用法:
//配置Camera2相关参数,
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=;//视频保存地址,注意需要以/结束,例如Camera2/
Camera2Config.PATH_SAVE_PIC=;图片保存地址,注意需要以/结束,例如Camera2/
Camera2Config.ENABLE_CAPTURE=true;//是否开启拍照功能
Camera2Config.ENABLE_RECORD=true;//是否开启录像功能
//拍完照需要跳转的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的优缺点:
缺点:
1.因为Camera2是安卓5.0以后的api,所以如果你的应用需要兼顾到5.0以下,这个library就不适合了。
2.录制界面不好自定义,如果对界面没有特殊需求的可以直接用,如果你对Camera2有一定了解或者界面需要自己自定义,我建议还是直接copy源码去用,然后自己修改布局,其实核心的代码就一个Camera2RecordActivity而已。
优点:
1.代码总共4个类,无其他第三方库,都是系统的api。
2.拍照和录制都是参考谷歌官方Demo(这算优点?)
2.录制视频小,质量还可以,10s大概1.2M左右,可能会存在波动。之前打算采用FFMPEG压缩,C++不行就没再研究下去了,这里采用的是对MediaRecorder进行了一些配置,这里坑也很多,后面我会分析出来。
3.可以进行预览尺寸的配置,对预览进行了一些处理,防止预览变形。
4.支持录制中开启闪关灯,双指缩放
四、踩过的坑:
关于预览变形
预览变形是很多人都会遇到的问题,这里主要是因为预览的尺寸和TextureView或者Surfaceview的尺寸不匹配导致的,例如你的TextureView是4:3比例的,然后用16:9的预览尺寸的话,他就会变形了,必须保证TextureView的尺寸和预览尺寸是一样的。像我在library中处理的一样,先设置了activity为全屏模式,包括导航栏,保证TextureView是覆盖整个屏幕的,然后每次获取TextureView的宽高比,再从本机相机所支持的尺寸中获取和TextureView一样比例的,以此来避免变形的情况。
由于预览尺寸过大导致卡顿
因为一个比例下他是有多个尺寸的,就像16:9这个比例,它有1280×720、1920×1080等等的尺寸,如果尺寸过大,就会给我们的预览造成很大的卡顿,说是预览预览,我觉得只要选择一个合适的尺寸就行了,针对这个,我在库中也封装了一个参数,即是
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进行一些配置以此来达到压缩视频的目的,但是这些方法并不是在所有机型上都是通用的,有时候会出现一些问题,就像在一加手机上,我设置了setVideoSize后就出现无法录制的现象了,针对这个问题,我是采用如下方法代码解决:
// 这里有点投机取巧的方式,不过证明方法也是不错的
// 录制出来10S的视频,大概1.2M,清晰度不错,
// 而且避免了因为手动设置参数导致无法录制的情况
// 手机一般都有这个格式CamcorderProfile.QUALITY_480P,
// 因为单单录制480P的视频还是很大的,
// 所以我们在手动根据预览尺寸配置一下videoBitRate,值越高越大
// QUALITY_QVGA清晰度一般,不过视频很小,一般10S才几百K
// 判断有没有这个手机有没有这个参数
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());
}
点击和长按的手势处理问题
有两种方式,第一种是监听ontouch事件,在down事件发生时,延迟个几百毫秒开启长按监听线程,在up事件进行统一处理,如果线程已经开启了,则判断是长按事件,否则为点击事件,其次,还有一种方式是使用系统自带的GestureDetector去监听事件,这里我采用的是第一种方式。
华为荣耀录制小视频截图:
五、总结:
开源出来是好事,但更重要的还是提供一种解决方法和思路给大家。这是我的第一次开源库,可能还有很多做的不好的地方,欢迎大家提建议。
联系方式: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