最近,在使用Android做一个照相机的开发。因为不能使用系统提供的相机应用,所以只能自己写一个。Android以前提供相机的api叫camera,不过在level 21被Google抛弃了。网上的教程,还有很多都是使用camera的,为了好好学习一下camera2,就去扒了Google提供的官方示例。下面给一个github的连接,可以找到全部的源码。
Camera2Basic Sample
下述的例子主要提供的功能是:相机预览、拍照、照片保存。具体如下:进入该应用后,可以看到相机的预览画面,提供一个按钮用于拍照,拍完照片后照片会保存在SD卡的根目录下。
首先来了解一下camera2的整体结构:
如上所示,整个camera2由一个CameraManager来进行统一管理,通过Context的getSystemService方法可以实例化CameraManager,然后该类主要通过三个类来对Camera进行操作。下面分别介绍一下:
CameraDevice:描述一个照相机设备,一个Android设备可能会有多个摄像头,通过CameraId可以进行区别。它最主要有一个相机状态的回调函数,当下达打开相机的命令后,若相机正确的打开便会回调该函数。
CameraCharacteristic:某个照相机设备的具体参数。本例主要用到它提供的输出格式(即输出数据的格式)。
CameraCaptureSession:相机捕获会话,通过这个类可以和相机进行对话(预览还是单张拍照还是录像等)。这里有两个回调函数,捕获状态的回调,和捕获数据的回调(后文会有详述)。
上图左上部分所示的时Android设备和camera设备的通信情况,两者之间通过pipeline(管道)进行数据交换。当需要尽心不同的操作时,将CameraCaptureRequest通过管道传给camera,接收到请求后,camera做出相应的反应,将获取到得数据CmaeraMetadata通过管道传回给Android设备。
本例,需要使用比较多的权限,请参看源码AndroidManifest.xml。
Android设备的屏幕方向,与摄像头的原始方向并不一致,需要做方向转换。一般而言,当Android设备横着放时,与摄像头的方向是一致的。
为了避免照片失真(照片被拉长或者压扁),需要保证预览的长宽比例、照片的长宽比例和相机输出格式的长宽比例三者保持一致。
本例当中,用一个activity承载一个fragment。所有的代码都写在fragment里面,重写了fragment的几个生命周期函数:
onCreateView:加载fragment的布局文件;
onViewCreated:实例化布局控件;
onActivityCreated:在SD卡的目录下建立jpg文件等待待将拍到的照片写进去;
onResume:开始照相机线程,执行一些逻辑判断;
onPause:关闭照相机,停止照相机线程;
正常来说,代码的整体流程如图2所示,activity将需要的fragment加载进来后,开始加载显示预览的控件texture,当控件加载完毕会执行一个回调函数
onSurfaceTextureAvailable()
,在这个回调函数里面,打开摄像头(即执行
openCamera()
)。
openCamera()
里面,首先要配置相机的输出,预览图像和拍照的图片要作不同的处理,然后根据当前的设备屏幕环境,判断是否需要进行数据的转换,最后通过cameraManager打开摄像头(调用
cameraManager.openCamera()
方法)。
更详细的方法请看后面的源码,图2当中,中间是判断屏幕方向的逻辑,右边是自动选择最合适的显示逻辑。