Camera API2 Overview 01 架构
1引言
1.1编写目的
本篇算是加深理解 Camera 2。
Android 的相机硬件抽象层 (HAL Hardware Abstraction Layer) 可将 Camera 2 中较高层级的相机框架 API 连接到底层的相机驱动程序和硬件。相机子系统包括相机管道组件的实现,而相机 HAL 可提供用于实现您的这些组件版本的接口。
1.2适用范围
Camera API2的使用。
2 主要架构流程
2.1 Android Camera架构
2.1.1 先上图,看图讲故事
图1 Camera 架构查看源码网站:
https://cs.android.com/
https://www.androidos.net.cn/sourcecode
http://androidxref.com/
-
应用框架
应用代码位于应用框架级别,它使用 Camera 2 API 与相机硬件进行交互。在内部,这些代码会调用相应的 Binder 接口,以访问与相机互动的原生代码。 -
AIDL
与CameraService
关联的Binder
接口可在 frameworks/av/camera/aidl/android/hardware 中找到。生成的代码会调用较低级别的原生代码以获取对实体相机的访问权限,并返回用于在框架级别创建 CameraDevice 并最终创建 CameraCaptureSession 对象的数据。 -
原生框架
此框架位于frameworks/av/
中,并提供相当于 CameraDevice 和 CameraCaptureSession 类的原生类。另请参阅 NDK camera2 参考。 -
Binder IPC 接口
IPC binder
接口用于实现跨越进程边界的通信。调用相机服务的若干个相机Binder
类位于frameworks/av/camera/camera/aidl/android/hardware
目录中。 ICameraService 是相机服务的接口;
ICameraDeviceUser 是已打开的特定相机设备的接口;
ICameraServiceListener 和 ICameraDeviceCallbacks 分别是对应用框架的CameraService
和CameraDevice
回调。 -
相机服务
位于 frameworks/av/services/camera/libcameraservice/CameraService.cpp 下的相机服务是与 HAL 进行互动的实际代码。 -
HAL
硬件抽象层定义了由相机服务调用、且您必须实现以确保相机硬件正常运行的标准接口。
实现 HAL
HAL
位于相机驱动程序和更高级别的 Android
框架之间,它定义您必须实现的接口,以便应用可以正确地操作相机硬件。相机 HAL
的 HIDL(HAL 接口定义语言 , HAL Interface Definition Language)
接口在 hardware/interfaces/camera
中定义。
典型的绑定式 HAL 必须实现以下 HIDL 接口:
ICameraProvider:用于枚举单个设备并管理其状态。
ICameraDevice:相机设备接口。
ICameraDeviceSession:活跃的相机设备会话接口。
参考 HIDL 实现适用于CameraProvider.cpp
、CameraDevice.cpp 和 CameraDeviceSession.cpp。该实现封装了仍使用旧版 API 的旧 HAL。从 Android 8.0 开始,相机 HAL 实现必须使用 HIDL API;不支持使用旧版接口。
2.2 相机 HAL3
Android 的相机硬件抽象层 (HAL) 可将 android.hardware.camera2
中较高级别的相机框架 API 连接到底层的相机驱动程序和硬件。
Android 8.0 引入了 Treble,用于将 CameraHal API 切换到由 HAL 接口描述语言 (HIDL) 定义的稳定接口。
2.2.1 相机 HAL3 功能
重新设计 Android Camera API 的目的::在于大幅提高应用对于 Android 设备上的相机子系统的控制能力,同时重新组织 API,提高其效率和可维护性。借助额外的控制能力,您可以更轻松地在 Android 设备上构建高品质的相机应用,这些应用可在多种产品上稳定运行,同时仍会尽可能使用设备专用算法来最大限度地提升质量和性能。
版本 3 相机子系统将多个运行模式整合为一个统一的视图,您可以使用这种视图实现之前的任何模式以及一些其他模式,例如连拍模式。这样一来,便可以提高用户对聚焦、曝光以及更多后期处理(例如降噪、对比度和锐化)效果的控制能力。此外,这种简化的视图还能够使应用开发者更轻松地使用相机的各种功能。
API 将相机子系统塑造为一个管道,该管道可按照 1:1 的基准将传入的帧捕获请求转化为帧。这些请求包含有关帧的捕获和处理的所有配置信息,其中包括分辨率和像素格式
;手动传感器
、镜头和闪光灯控件
;3A 操作模式
;RAW 到 YUV 处理控件
;统计信息生成
等等。
简单来说,应用框架从相机子系统请求帧,然后相机子系统将结果返回到输出流。此外,系统还会针对每组结果生成包含色彩空间和镜头遮蔽等信息的元数据。您可以将相机版本 3 看作相机版本 1 的单向流管道。它会将每个捕获请求转化为传感器捕获的一张图像,这张图像将被处理成::
- 包含有关捕获的元数据的 Result 对象。
- 图像数据的 1 到 N 个缓冲区,每个缓冲区会进入自己的目标 Surface。
可能的输出 Surface 组经过预配置:
- 每个 Surface 都是一个固定分辨率的图像缓冲区流的目标位置。
- 一次只能将少量 Surface 配置为输出(约 3 个)。
一个请求中包含所需的全部捕获设置,以及要针对该请求将图像缓冲区(从总配置组)推送到其中的输出 Surface 的列表。请求可以只发生一次(使用 capture()),也可以无限重复(使用 setRepeatingRequest())。捕获的优先级高于重复请求的优先级。
图2 相机核心操作模型2.3 HAL子系统
2.3.1 capture请求
应用框架会针对捕获的结果向相机子系统发出请求。一个请求对应一组结果。请求包含有关捕获和处理这些结果的所有配置信息。其中包括分辨率和像素格式;手动传感器、镜头和闪光灯控件;3A 操作模式;RAW 到 YUV 处理控件;以及统计信息的生成等。这样一来,便可更好地控制结果的输出和处理。一次可发起多个请求,而且提交请求时不会出现阻塞。请求始终按照接收的顺序进行处理。
图3 相机模型2.3.2 HAL 和相机子系统
相机子系统包括相机管道中组件的实现,例如 3A 算法和处理控件。相机 HAL 为您提供了用于实现您的这些组件版本的接口。为了保持多个设备制造商和图像信号处理器(ISP,也称为相机传感器)供应商之间的跨平台兼容性,相机管道模型是虚拟的,且不直接对应于任何真正的 ISP。不过,它与真正的处理管道足够相似,因此您可以有效地将其映射到硬件。此外,它足够抽象,可支持多种不同的算法和运算顺序,而不会影响质量、效率或跨设备兼容性。
相机管道还支持应用框架可以启动来开启自动对焦等功能的触发器。它还会将通知发送回应用框架,以通知应用自动对焦锁定或错误等事件。
图4 相机管道请注意,上图所示的一些图像处理块在初始版本中没有明确定义。
相机管道做出以下假设:
- RAW Bayer 输出在 ISP 内部不经过任何处理。
- 统计信息根据原始传感器数据生成。
- 将原始传感器数据转换为 YUV 的各种处理块按任意顺序排列。
- 当显示多个刻度和剪裁单元时,所有缩放器单元共享输出区域控件(数字缩放)。不过,每个单元都可能具有不同的输出分辨率和像素格式。
API 用途摘要
下面简要介绍了使用 Android Camera API 的步骤。有关这些步骤(包括 API 调用)的详细说明,请参阅“启动和预期操作顺序”部分。
- 监听和枚举相机设备。
- 打开设备并连接监听器。
- 配置目标使用情形的输出(如静态捕获、录制等)。
- 为目标使用情形创建请求。
- 捕获/重复请求和连拍。
- 接收结果元数据和图片数据。
- 切换使用情形时,返回到第 3 步。
HAL 操作摘要
捕获的异步请求来自于框架。
- HAL 设备必须按顺序处理请求。对于每个请求,均生成输出结果元数据以及一个或多个输出图像缓冲区。
- 请求和结果以及后续请求引用的信息流遵守先进先出规则。
- 指定请求的所有输出的时间戳必须完全相同,以便框架可以根据需要将它们匹配在一起。
- 所有捕获配置和状态(不包括 3A 例程)都包含在请求和结果中。
2.3.3 启动和预期操作顺序
本部分详细说明了使用 Camera API 时应遵循的步骤。有关 HIDL 接口的定义,请参阅 platform/hardware/interfaces/camera/ 。
枚举、打开相机设备并创建有效会话
- 初始化后,框架开始监听实现
ICameraProvider
接口的任何现有相机提供程序。如果存在一个或多个此类提供程序,框架将尝试建立连接。 - 框架通过
ICameraProvider::getCameraIdList()
枚举相机设备。 - 框架通过调用相应的
ICameraProvider::getCameraDeviceInterface_VX_X()
来实例化一个新的ICameraDevice
。 - 框架调用
ICameraDevice::open()
来创建一个新的有效捕获会话ICameraDeviceSession
。
使用有效相机会话
- 框架调用
ICameraDeviceSession::configureStreams()
并传入到 HAL 设备的输入/输出流列表。 - 框架通过调用
ICameraDeviceSession::constructDefaultRequestSettings()
来为某些使用情形请求默认设置。这可能会在ICameraDevice::open
创建ICameraDeviceSession
之后的任何时间发生。 - 框架通过基于某一组默认设置的设置以及框架之前注册的至少一个输出流来构建第一个捕获请求并将其发送到 HAL。此请求通过
ICameraDeviceSession::processCaptureRequest()
发送到 HAL。HAL 必须阻止此调用返回,直到准备好发送下一个请求为止。 - 框架继续提交请求并根据需要调用
ICameraDeviceSession::constructDefaultRequestSettings()
以获取其他使用情形的默认设置缓冲区。 - 当请求捕获开始(传感器开始曝光以进行捕获)时,HAL 会调用
ICameraDeviceCallback::notify()
并显示 SHUTTER 消息,包括帧号和开始曝光的时间戳。此通知回调不必在对请求第一次调用processCaptureResult()
之前发生,但直到针对相应的捕获调用 notify() 之后,才会向应用提供有关该捕获的结果。 - 经过一定的管道延迟后,HAL 开始使用
ICameraDeviceCallback::processCaptureResult()
将完成的捕获返回到框架。这些捕获按照与提交请求相同的顺序返回。一次可发起多个请求,具体取决于相机 HAL 设备的管道深度。
一段时间后,会出现以下某种情况:
- 框架可能会停止提交新的请求,等待现有捕获完成(所有缓冲区都已填充,所有结果都已返回),然后再次调用
ICameraDeviceSession::configureStreams()
。这会重置相机硬件和管道,以获得一组新的输入/输出流。可重复使用先前配置中的部分信息流。如果至少还有一个已注册的输出流,则框架将从发送到 HAL 的第一个捕获请求继续。(否则,需要先调用ICameraDeviceSession::configureStreams()
。) - 框架可能会调用
ICameraDeviceSession::close()
以结束相机会话。当框架中没有其他处于有效状态的调用时,可能随时会调用此函数;不过,在所有发起的捕获完成(所有结果都已返回,所有缓冲区都已填充)之前,调用可能会阻塞。close() 调用返回后,不允许再从 HAL 对 ICameraDeviceCallback 进行调用。一旦进行 close() 调用,框架便不能再调用其他任何 HAL 设备函数。 - 在发生错误或其他异步事件时,HAL 必须调用
ICameraDeviceCallback::notify()
并返回相应的错误/事件消息。从严重的设备范围错误通知返回后,HAL 的行为方式应像对其调用了 close() 一样。但是,HAL 必须在调用 notify() 之前取消或完成所有待处理的捕获,以便在调用 notify() 并返回严重错误时,框架不会收到来自设备的更多回调。在 notify() 方法从严重错误消息返回后,close() 之外的方法应返回 -ENODEV 或 NULL。
2.3.4 应用捕获请求、3A 控件和处理管道之间的交互
根据 3A 控件块中的设置,相机管道会忽略应用捕获请求中的某些参数,而改用 3A 控件例程提供的值。例如,启用自动曝光后,传感器的曝光时间、帧时长和感光度参数由平台 3A 算法控制,所有应用指定的值都会被忽略。必须在输出元数据中报告由 3A 例程为帧选择的值。
下表描述了 3A 控件块的不同模式以及由这些模式控制的属性。有关这些属性的定义,请参阅 platform/system/media/camera/docs/docs.html 文件。
图4 相机管道 中,图像处理块中的控件都以类似的原理操作,并且每个块一般都具有 3 种模式:
- OFF:该处理块处于停用状态。无法停用去马赛克、色彩校正和色调曲线调整块。
- FAST:与 OFF 模式相比,在这种模式下,处理块可能不会降低输出帧速率,但是考虑到限制条件,它应该会产生能够产生的最优质输出。通常,该模式会用于预览或视频录制模式,或用于连拍静态图像。在一些设备上,该模式可能等同于 OFF 模式(进行任何处理都会降低帧速率);而在另外一些设备上,该模式可能等同于 HIGH_QUALITY 模式(最佳质量仍不会降低帧速率)。
- HIGH_QUALITY:在这种模式下,处理块应尽可能产生最优质结果,根据需要降低输出帧速率。通常,该模式会用于拍摄优质静态图像。一些块包括可以被选中的手动控件(而非 FAST 或 HIGH_QUALITY)。例如,色彩校正块支持颜色变换矩阵,而色调曲线调整支持任意的全局色调映射曲线。
相机子系统可以支持的最大帧速率受到多种因素的影响:
- 所请求的输出图像流的分辨率
- 成像器上像素组合/跳过模式的可用性
- 成像器接口的带宽
- 各种 ISP 处理块的带宽
由于这些因素在不同的 ISP 和传感器之间可能有很大差异,因此相机 HAL 接口会设法将带宽限制抽象为尽可能简单的模型。
显示的模型具有以下特性:
- 考虑到应用的请求输出流大小,图像传感器始终配置为输出尽可能最小的分辨率。最小分辨率定义为至少与请求的最大输出流一样大。
- 因为任何请求都可能使用当前配置的任意或所有输出流,所以传感器和 ISP 必须配置为-支持将单个捕获同时扩展到所有信息流。
- 对于不包含 JPEG 流的请求,JPEG 流表现得像经过处理的 YUV 流一样;在直接引用它们的请求中,它们用作 JPEG 流。
- JPEG 处理器可以并行运行到相机管道的剩余部分,但不能一次处理多个捕获。
3 进程间通信类总结
我们直达camera模块的代码根据层次可以分为下面几层,开发者直接接触的是Camera api的部分,Camera api会通过Binder IPC方式调用到Camera服务部分,但是这部分代码实在繁杂,需要将这部分IPC联系的方式总结一些,方便后来人方便的学习这一块的内容。
- Camera api部分:
frameworks/base/core/java/android/hardware/camera2- Camera JNI部分:
frameworks/base/core/jni/android_hardware_Camera.cpp
编译选项在目录下的Android.bp
make libandroid_runtime -j1
- Camera UI库部分:
frameworks/av/camera/
编译选项在目录下的Android.bp
make libcamera_client -j1- Camera服务部分:
frameworks/av/services/camera/libcameraservice/
编译选项在目录下的Android.mk
make libcameraservice -j1
- Camera HAL部分:
hardware/interfaces/camera/
加深两个路径:
1,首先大家关注一下这个代码路径:frameworks/av/camera/aidl/
这里是和cameraservice
端交互的桥梁。
2, cameraservice
端的代码在frameworks/av/services/camera/libcameraservice/
下面。