Camera API2的预览实现在网上有非常多的代码可以参考,包括Google官方提供的Demo。直接看代码,模仿、改写当然是最快的实现方式,但如果其中的逻辑关系可能没有捋顺清楚,在没有参考代码的情况下,能否同样实现相关功能就值得商榷了。
1API2架构图
这个图是一个常见的用于展示API2架构的图,但事实上这个图并不能对架构和开发起到很好的帮助。这个图的主要问题是无法搞清楚Camera APP与Camera Device之间到底是什么逻辑关系。本文中,我将从类逻辑出发,逐步串起preview的全过程。
PS:想直接看结论的可以到最后看总结的部分,跳过中间的实现环节,和代码分析。
一、Camera Manager类和open camera的方法
我们在上一节中说过,CameraManager是一个System Service,也就是Camera Service,Camera的软件行为都是发生在这个Service中的。所以当我们想要使用Camera、想要获取Camera信息时,首先要获取到CameraManager对象。2CameraManager类
Kotlin代码
val manager = activity!!.getSystemService(Context.CAMERA_SERVICE) as CameraManager
此时,我们来详细的看一下CameraManager类的属性和方法,在图2中可以看到有4个方法以openCamera开头,区别仅仅是参数不同。此处选择
方法,这个方法应该时使用频率最高的一个open方法。
manager.openCamera(mCameraId!!, mStateCallback, mBackgroundHandler)
源码:
可以看到对内部直接调用了openCameraForUid方法,并且出现了CameraDeviceImpl类,这个类前面提到过是非公开API暂时不管,继续查看该方法源码。
该方法在进行了非空和异常处理之后调用了openCameraDeviceUserAsync方法。如果我们查看剩下的一个open方法,会发现也是调用的openCameraForUid方法。换言之,Camera的真正open方法只有一个,就是openCameraDeviceUserAsync()方法。
该方法的核心部分进行了一次API support的判断,如果支持将进入HAL3.2以上通道;如果不支持将进入legacy HAL1通道。至此Camera open已经完成,方法返回CameraDevice对象。
我们回溯到最初的方法。可以看到三个需要传入的参数,除了第一个Camera id,还需要传入一个CameraDevice.StateCallback对象。
如前所述,StateCallback是表示CameraDevice状态的回调,分别对应已打开、已关闭、失去连接、出错四种状态。对于预览来说,需要在onOpened方法中进行处理,并获得CameraDevice对象。
二、CameraDevice类和创建会话
CameraDevice对象可以理解为设备本身。
从提供的公开方法可以看出,CameraDevice的主要行为就是创建不同作用的session,会话机制作为API2中引入的新机制,是区别于API1的主要特点,关于session机制将在下一节专门进行分析。
首选我们选择方法作为创建session方法。
之所以选择这个方法是因为这个方法的第一个参数是Surface的List,而我们知道SurfaceVIew/TextureView/GLSurfaceView等都是我们通常用来显示Preview的载体,很容易才想到二者之间存在某种关系
Kotlin代码
所以这个List的第一个值代表的就是SurfaceVIew的surface。这里再多提一句第二个值是ImageReader的surface,第三个值一般是缩略图的surface。
方法的第二个参数是StateCallback,类似于openCamera方法中的StateCallback,这里是CameraCaptureSession的状态回调,内部的方法代表了会话的各种状态。
其中onConfigured()方法,即Camera配置完成的回调无疑就是处理后续逻辑的方法,在这个方法中我们将得到CameraDevice建立的session对象。
至此,在整个逻辑上就只有最后一步生成预览。
三、生成预览
在上一步我们得到了CameraCaptureSession对象。
可以看到用于拍照的capture方法,以及用于连续捕捉的方法。对于preview无疑是连续捕捉画面,所以setRepeatingRequest方法就是我们所需要的方法。
Kotlin代码
mCaptureSession!!.setRepeatingRequest(
mPreviewRequest!!,
mCaptureCallback, mBackgroundHandler
)
方法中的第一个参数CaptureRequest就是用来表述要捕获的单幅图像的,所以通过配置CaptureRequest的参数,就完成了对preview画面的配置,包括对焦、白平衡等配置,具体的配置将在后续章节中展开讲解。
四、总结
在实现Camera Preview功能的过程中,通过层层推进的方式,我们可以看到API2的逻辑是:
- CameraManager管理CameraDevice
- CameraDevice管理CameraCaptureSession
- CameraDevice、CameraCaptureSession的状态反馈到各自的StateCallback回调中,用户需要实现的部分都在这些回调中。
这里给出一个完整的流程图例。
经过分析后,再回头看图一,就会发现最初的图很有迷惑性,左侧的APP是指实现了全部API的整个相机实现,而右侧的Device是指实体硬件。
下一节将详细分析API2 session机制。
附一:相机模型
附二:API 用途摘要
- 监听和枚举相机设备。
- 打开设备并连接监听器。
- 配置目标使用情形的输出(如静态捕获、录制等)。
- 为目标使用情形创建请求。
- 捕获/重复请求和连拍。
- 接收结果元数据和图片数据。
- 切换使用情形时,返回到第 3 步。