与旧的Camera API相比,L中引入的Camera2 API要复杂得多:涉及十多个类,通过callback进行异步操作,同时增加了许多令人困惑的捕获控制(capture controls)和元数据(meta data)。
面对一个复杂的系统时,通常用UML类图来进行一下概览。以下是Camera2 API的类图。
按照上图中的步骤编号,我们一一对应起来分析:
1.CameraManager
这个类, 我们可以通过它来获取系统中所有可用的camer设备,每个camera都有一个指定的cameraId
来标识。通过cameraId
,我们可以获得指定camera设备的属性, 这些属性由CameraCharacteristics
类存储,其中包括了“前置或后置摄像头”,“支持的输出分辨率”等属性。
2.对于camera捕获的图像数据,应该有一个最终的接收者来处理:比如使用SurfaceView
或SurfaceTexture
进行预览处理、使用ImageReader
进行静态图片处理、或者使用MediaRecoder
进行视频录制处理,这些处理操作都会有一个接收者——Surface
。也就是说,对于这些操作来说,我们需要想办法获取到一个Surface
,然后设置到CamerDevice
中,才可以接收到camera捕获的图像数据。 在下面的步骤中会讲述如何创建CaptureSession
列表、如何将Surface
添加到CaptureRequest
中,届时将会明白Surface
的作用。
3.通过调用CameraManager.open(cameraId,callback)
来获取CameraDevice
。 由于调用是异步的,因此需要在onOpened()
回调中获取CameraDevice
。
4.从CameraDevice
创建CaptureRequest
,CaptureRequest
实际上是一个固定的数据包(immutable package),我们从camera获取单张图像后,通过CaptureRequest
对其设置和输出。这里应用了Builder模式,如上面的类图所示,CaptureReques.Builder
是从CameraDevice
中的createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
方法来创建的。 然后,我们使用构建器来设置变其他属性,比如addTarget(Surface)
来设置CaptureRequest
的接收者。注意,我们通常不直接创建CaptureRequest
,因为这样比较容易出错。
5.从CameraDevice
创建CaptureRequestSession
, CaptureRequestSession
用于提交上面创建好的CaptureRequest
。要初始化CaptureRequestSession
,必须提供初始化好的Surface
,这在步骤2中已经讨论过。另请注意,CaptureRequestSession
的创建也是异步的。
6.通过CaptureRequestSession
发送CaptureRequest
,有几个API可以做到这一点:capture()
用于发出一次性拍照命令,setRepeatingRequest()
用于发出显示预览的重复请求。此外,在发送CaptureRequest
请求之前,需要设置自动对焦模式、白平衡模式等内容。
7.获取捕获的图像结果。捕获到的结果将通过CameraCaptureSession.CaptureCallback
异步返回,你可以在这个回调中播放拍照声音(例如“咔嚓”的声音),也可以在onCaptureProcessed
方法里接收一张张的CaptureResult
。
8.对于步骤7来说,我们也可以在onCaptureComplete
方法的TotalCaptureResult
中一次性获取所有数据。
最后总结一下,camera捕获到的图像数据输出到surface处理,正如步骤2中所讨论的。camera是生产者,surface是消费者。camera保持对图像数据进行排队,一旦数据可用,将通知消费者surface处理它们:TextureView会将图片数据转换为纹理,并在绘制到屏幕;MediaRecoder会将图像传递给编解码器进行处理;对于ImageReader,由我们自己处理数据。