简介
Android 调用相机拍照,相信大家已经很熟悉了,通过Intent指定Action和Category,再通过startActivityForResult()获取到拍照的回调,这样获取的是系统相机,我们只能得到它拍摄的图片,再进行后续处理。有些功能,比如视频直播,美颜相机,需要对相机预览的图像进行处理,这时候我们就需要通过Android的相机Camera来进行操作。文章主要偏使用,不会过多的将原理,想要了解原理的,后续我会写一篇关于Android Usb相机的实现,当然这是后话了。
获取相机预览的视频主要需要三个东西
1.Camera 不说了,既然相机当然需要他
2.Surfaceview 说的浅显一点,就是一个View,用来显示预览视频的控件,具体可以看一下官方文档,当然也可以用TextureView,后续会进行比较。
3.SurfaceHolder 我的理解,Holder在其中扮演了纽带的作用,控制着Camera和Surface之间的联系。
实现过程分三步:
1.创建SurfaceView
首先,我们需要准备好布局对吧,很简单,就一个SurfaceView,这儿我就截图了,文章后面会放上Demo链接
同时获取Holder,并添加监听addCallBack() 用于监听SurfaceView的生命周期,三个阶段create,change,destory。
2.初始化相机
布局创建好了,就该相机出场了,一贯的习惯,开相机,设置一堆参数,最后再开始预览,6.0之后需要申请权限,同时需要检查相机固件是否存在,这儿就不赘述了,Demo里面有。具体操作方式,我会一步步解析。
看上面的截图,可以看到camera.open(cameraID),简单说一下,其实在Linux中,一切都是文件。相机也不例外,而open其实最终打开的是/dev/video这个文件。感兴趣的朋友可以了解一下。
打开成功之后,就可以获取到Camera的实例了,这时候我们就需要去设置一些列的参数,包括分辨率,帧率,是否对焦,旋转等参数,具体看下面截图:
注意 parameters.setPreviewFormat(ImageFormat.NV21); 表示相机的预览数据格式,NV21,感兴趣的可以了解一下。
3.开启预览,获取回调
这儿有几个点,
1.首先尽量用setPreviewCallbackWithBuffer()这个回调,因为他在回调前先做了addCallbackBuffer()的操作,该操作的目的是分配一块内存空间,用于临时存放回调的buffer,当每次camera.addCallbackBuffer(datas)的时候会复用之前分配的内存地址,避免了频繁的创建buffer造成不必要的GC。
2.不知道有没有留意到
,new byte[]的时候做了计算,其实我这儿是有点错的,现在才发现。byte[]的大小是装一帧NV21的大小,当然可以适当的大一点点,但是不能小。NV21是YUV的一种,大小计算方式为width*height*3/2 这样才是正确的大小。所以这儿可以修改一下。byte[]过大,可能会导致CPU的占用率升高,所以最好是一样大小。
最后拿到了回调数据,就可以自由发挥了,可以编码之后推流出去,也就是直播使用,也可以加点滤镜,每个图再重新渲染,总之就是为所欲为。当然这些操作,等你的就是一堆格式转换,编码解码的问题,后续我也会一一介绍。好了,附上demo链接
GitHub: https://github.com/renlei521/CameraDemo.git