目录
3.2.2 使用 Android Camera API 的步骤
引言
为了更深入理解相机体系,不断地反复地对相机架构的内容进行梳理和理解。
1. Android相机的整体架构
下面主要是从结构层次方面来理解Android相机体系的架构原理。先看看这个熟悉的架构图:
图1. 相机的整体架构图
这个架构图说明的是从 应用层 到 HAL层的原理
应用框架:通过Activity 或者 Service 调用 Camera API v2来实现应用的业务逻辑开发,比如相机应用的拍照逻辑,预览逻辑,录像逻辑等等。其中涉及到的两个核心组件:CameraDevice 和 CameraManager
Native框架:提供了CameraDevice 和CameraCaptureSession的实现
Native框架通过HAL层进行硬件的管理和控制。换句话说,应用之所以能够正确操作相机硬件,就是因为HAL层提供了接口。典型的接口包括:
1)枚举单个设备并管理器状态的接口:ICameraProvider
2)相机设备的接口:ICameraDevice
3)激活的相机设备会话接口:ICameraDeviceSession
相机的一些能力还需要通过Service服务的方式向上层提供出去的。具体的实际代码在:
frameworks/av/services/camera/libcameraservice/CameraService.cpp
这样,我们使用相机的时候就会有3个运行的进程交互协作共同完成用户的业务需求。而这3个进程之间的通信是通过AIDL的方式来实现的。实现的IPC binder接口包括:
1)已打开的特定相机设备接口:ICameraDevice
2)相机服务的接口:ICameraService;
3)应用框架中CameraDevice的回调接口:ICameraDeviceCallbacks,
4)应用框架中CameraService的回调接口:ICameraServiceListener
就这样,Android相机体系架构中,Android应用的业务逻辑的实现是通过Camera API v2来实现,而Camera API v2 又是通过Native框架实现,Native框架通过再硬件抽象层(Camera HAL 层)控制和管理应用,Camera HAL则是通过内核驱动直接操作硬件。通过这样的一种关联交互的方式实现了相机的业务逻辑与硬件的交互。
2. 相机 HAL
从整体架构中,可以发现,Android相机的实现主要是依靠 相机 HAL实现的。换句话说,Android的相机HAL 是连接 android.hardware.camera2 上层相机框架 API 与 底层相机驱动和硬件的 桥梁。从Android8.0引入了Treble,用于将相机HAL API切换到由HAL接口语言HIDL定义的稳定接口,从Android 13开始,相机HAL接口使用AIDL进行开发。
2.1 AIDL相机HAL
对于搭载 Android 13 或更高版本的设备,该相机框架包含对 AIDL 相机 HAL 的支持。该相机框架还支持 HIDL 相机 HAL,不过,在 Android 13 或更高版本中添加的相机功能只能通过 AIDL 相机 HAL 接口使用。如需在升级到 Android 13 或更高版本的设备上实现此类功能,设备制造商必须将其 HAL 进程从使用 HIDL 相机接口迁移到使用 AIDL 相机接口。
补充说明:Android中,适用于HAL的AIDL是从Android11开始的。设计初衷其实是由于AIDL和HIDL都是为了跨进程通信设计的。由于AIDL具备了稳定性的支持,这样如果只是用一个方式设计的话就意味着仅使用一个IPC运行时环境来实现整个堆栈。化繁为简更易于调试,优化和维护。同时AIDL的版本控制系统也由于HIDL。
AIDL 相机 HAL 规范位于以下位置:
相机提供程序: hardware/interfaces/camera/provider/aidl/
相机设备: hardware/interfaces/camera/device/aidl/
相机元数据: hardware/interfaces/camera/metadata/aidl/
常见数据类型: hardware/interfaces/camera/common/aidl/
对于迁移到 AIDL 的设备,设备制造商可能需要修改 Android SELinux 政策 (sepolicy) 和 RC 文件,具体取决于代码结构。
验证 AIDL 相机 HAL
如需测试 AIDL 相机 HAL 实现,请确保设备已通过所有 CTS 和 VTS 测试。Android 13 引入了 AIDL VTS 测试 VtsAidlHalCameraProvider_TargetTest.cpp。
2.2 相机 HAL3 功能
我们已经知道相机HAL是连接应用和底层驱动硬件的桥梁。下面我们继续聊聊 相机HAL 的功能。
HAL从HAL1发展到HAL3,从而也就意味着重新设计了Android Camer API,而其中的目标都是为了在Android设备上构建高质量的相机应用,更稳定,性能更好。
相机HAL3 的子系统将操作模式构建为单个统一视图,该视图可用于实现之前的任何模式和其他几种模式,例如连拍模式。这使得用户可以更好地控制焦点和曝光,并进行更多的后处理,如降噪、对比度和锐化。此外,这种简化的视图使应用程序开发人员更容易使用相机的各种功能。
API将摄像机子系统建模为一个管道,以1:1的基础将传入的帧捕获请求转换为帧。请求封装了关于帧的捕获和处理的所有配置信息。这包括分辨率和像素格式;手动传感器、镜头和闪光灯控制;3A操作模式;RAW->YUV处理控制;统计生成;等等
简单地说,应用程序框架从相机子系统请求帧,相机子系统将结果返回到输出流。此外,为每组结果生成包含诸如颜色空间和镜头明暗处理之类的信息的元数据。可以将相机HAL3视为相机HAL1的单向流的管道。它将每个捕获请求转换为传感器捕获的一张图像,并将其处理为:
- 包含有关捕获的元数据的 Result 对象。
- 图像数据的 1 到 N 个缓冲区,每个缓冲区会进入自己的目标 Surface。
可能的输出 Surface 组经过预配置:
- 每个 Surface 都是一个固定分辨率的图像缓冲区数据流的目标位置。
- 一次只能将少量 Surface 配置为输出(约 3 个)。
一个请求中包含所需的全部捕获设置,以及要针对该请求将图像缓冲区(从总配置组)推送到其中的输出 Surface 的列表。
请求可以只发生一次(使用 capture()
),也可以无限重复(使用 setRepeatingRequest()
)。
捕获的优先级高于重复请求的优先级。
图2. 相机的核心操作模型
3. HAL子系统
3.1 请求
应用框架向相机子系统发出请求
一个请求对应一组结果
请求包含的信息:
1)分辨率和像素格式
2)手动传感器,镜头,闪光灯等控件
3)3A操作模式;
4)RAW到YUV处理控制
5)统计信息
一次可以发出多个请求
提交请求不会阻塞
请求始终按照接收的顺序进行处理。
图3. 相机模型
此相机模型可以看到从应用请求到HAL层返回结果的整个流程。结合我们上面架构和HAL的知识梳理,会更容易理解图3 所描述的相机模型。暂且只需要直观地了解一下大致的请求与结果返回的路径。我们继续梳理。
3.2 HAL和相机子系统
3.2.1 相机的管道
HAL子系统包括了相机管道中的组件的实现
HAL子系统提供实现组件的接口,如:3A算法和处理控件
HAL子系统可以支持不同设备制造商,不同信号处理器的跨平台兼容性
HAL子系统支持不同的算法和运算顺序,不影响质量,效率或者跨设备的兼容性
相机管道还支持应用框架可以启动触发器来开启自动对焦等功能。它还会将通知发送回应用框架,以通知应用自动对焦锁定或错误等事件。
所以理解的相机的管道,就基本理解了相机的HAL 子系统了。
图4. 相机管道
从图4的相机管道模型图中,可以了解到:
1)RAW Bayer 输出在 ISP 内部不经过任何处理。
2)统计信息根据原始传感器数据生成。
3)将原始传感器数据转换为 YUV 的各种处理块按任意顺序排列。
4)当显示多个刻度和剪裁单元时,所有缩放器单元共享输出区域控件(数字缩放)。不过,每个单元都可能具有不同的输出分辨率和像素格式。
3.2.2 使用 Android Camera API 的步骤
下面先简要介绍了使用 Android Camera API 的步骤。
1)监听和枚举相机设备。
2)打开设备并连接监听器。
3)配置目标使用情形的输出(如静态捕获、录制等)。
4)为目标使用情形创建请求。
5)捕获/重复请求和连拍。
6)接收结果元数据和图片数据。
7)切换使用情形时,返回到第 3 步。
3.2.3 HAL 操作摘要
1)捕获的异步请求来自于框架。
2)HAL 设备必须按顺序处理请求。对于每个请求,均生成输出结果元数据以及一个或多个输出图像缓冲区。
3)请求和结果以及后续请求引用的信息流遵守先进先出规则。
4)指定请求的所有输出的时间戳必须完全相同,以便框架可以根据需要将它们匹配在一起。
5)所有捕获配置和状态(不包括 3A 例程)都包含在请求和结果中。
图5. 相机HAL
图中的 1-9 代表这从request到result的顺序,最先的请求1,得到了结果也是排在最前面的。
3.3 启动和预期操作顺序
先看看我们操作的流程图:
图6. 相机的操作流程
3.3.1 枚举、打开相机设备并创建有效会话
1)初始化后,框架开始监听实现 ICameraProvider 接口的任何现有CameraProvider。如果存在一个或多个CameraProvider,框架将尝试建立 connection。
2)框架通过 ICameraProvider::getCameraIdList() 枚举相机设备。
3)框架通过调用相应的 ICameraProvider::getCameraDeviceInterface_VX_X() 来实例化一个新的 ICameraDevice。
4)框架调用 ICameraDevice::open() 来创建一个新的有效捕获会话 ICameraDeviceSession。
3.3.2 使用有效相机会话
1)框架调用 ICameraDeviceSession::configureStreams() 并传入到 HAL 设备的输入/输出流列表。
2)框架通过调用 ICameraDeviceSession::constructDefaultRequestSettings() 为某些用例请求默认设置。这可能会在 ICameraDevice::open 创建 ICameraDeviceSession 之后的任何时间发生。
3)框架通过基于某一组默认设置的设置以及框架之前注册的至少一个输出流来构造第一个捕获请求并将其发送到 HAL。此请求通过 ICameraDeviceSession::processCaptureRequest() 发送到 HAL。HAL 必须阻止此调用返回,直到准备好发送下一个请求为止。
4)框架继续提交请求并根据需要调用 ICameraDeviceSession::constructDefaultRequestSettings() 以获取其他用例的默认设置缓冲区。
5)当请求捕获开始(传感器开始曝光以进行捕获)时,HAL 会调用 ICameraDeviceCallback::notify() 并显示 SHUTTER 消息,包括帧号和开始曝光的时间戳。此通知回调不必在对请求第一次调用 processCaptureResult() 之前发生,但直到针对相应的捕获调用 notify() 之后,才会向应用提供有关该捕获的结果。
6)经过一定的 pipeline 延迟后,HAL 开始使用 ICameraDeviceCallback::processCaptureResult() 将完成的捕获返回到框架。这些捕获按照与提交请求相同的顺序返回。一次可发起多个请求,具体取决于相机 HAL 设备的管道深度。
启动之后可能的三种状态:
1)框架停止提交新的请求,等待现有的捕获完成,然后再次调用。
2)正常结束:框架结束相机会话
3)异常结束:发生错误或者其他异步事件而返回。