几行代码利用Camera2实现点击拍照,长按录像!

写在前面:关于什么是Camera2这里我就不多介绍了,大家可以自行去百度。公司项目因为需要实现一个类似微信拍小视频的功能,所以捣腾了一段时间的Camera2,期间遇到很多坑。今天这篇文章主要是记录下我所遇到的问题以及对此做出的解决方法,同时为了方便,这里我也将此功能封装成了library供大家使用。

一、先看一下效果图:

capture.gif
record.gif

二、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去监听事件,这里我采用的是第一种方式。

华为荣耀录制小视频截图:


视频截图.png

五、总结:

开源出来是好事,但更重要的还是提供一种解决方法和思路给大家。这是我的第一次开源库,可能还有很多做的不好的地方,欢迎大家提建议。
联系方式: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

确保开启前app已经获取到上面所说的三个权限!!!!!!!!!!!!!!!!!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,062评论 25 707
  • 喜欢坐火车,坐在火车上一站一站的慢慢南下或者北上。在旅途中,我既不属于起点也不属于终点。在只属于我的时刻,我...
    Mystery阿翔阅读 373评论 8 4
  • 接触式,而非控制式的 互联网多边节点生存机制与关键通讯协议与接口API 没有疆域,只有管道没有边界,只有核心
    咸叔说阅读 314评论 0 2
  • //www.greatytc.com/p/42e11515c10f
    上海第一撸码少年阅读 171评论 0 0