前面说了 HAL3 是一个总线型的设计结构,本文就先对 HAL3 的控制流进行一个提纲挈领式的概述,主要理解整个 HAL3 的主干框架,以便对后续深入各个细节。

主干流程

以下全部都是摘抄 Google 官方网站上面介绍的 Camera 使用流程。

  • 枚举、打开相机设备并创建有效的会话(session)

    1. 在初始化完成之后(这个初始化我觉得是 framework 层的服务初始化完成),framework 就会监听多有的 camera provider,camera provider 是在 ICameraProvider 接口实现的(AIDL 类型的接口),如果发现系统里面有的话就会建立一个连接。
    2. framework 通过 ICameraProvider::getCameraIdList 接口来进行设备的枚举,其实这里并没有调用到具体设备相关的 HAL3 内部,因为在 provider 初始化的时候就已经调用过了,这里只是把 provider 里面保存下来的 camera list 返回给上层的 framework。
    3. framework 实例化一个新的 ICameraDevice,实例化过程是 ICameraProvider::getCameraDeviceInterface_VX_X() 来完成的。
    4. framework 调用 ICameraDevice::open() 接口来打开并且创建一个新的 session 来完成后续的控制过程。
  • 使用刚刚创建好的 session 进行具体的业务逻辑处理
    1. framework 通过 ICameraDeviceSession::configureStreams() 接口来向设备相关的 HAL 层传递用户所需的 stream 配置,同时 HAL 内部会根据传递下来的 stream 来选择具体的业务进行配置。
    2. framework 通过 ICameraDeviceSession::constructDefaultRequestSettings() 接口来获取一个默认的具体业务场景配置,这个操作可以在 ICameraDevice::open() 之后的任何时刻执行,后面说下这个 constructDefaultRequestSettings() 接口的内容。
    3. framework 使用上面构建的默认 setting,再佐以自己需要的特殊配置,然后发送第一个 request 请求到 HAL 里面去。这个 request 里面必须包含至少一个之前配置好的 stream(没错,它们的地址必须相同,不能够使用 copy 的方式重新新建一个 stream,并且这个 stream 地址与使用由 framework&app 去维护),因为要输出 buffer 给 framework 那边。上面的 request 使用 ICameraDeviceSession::processCaptureRequest() 进行传递,HAL 内部需要阻塞本次 request 请求,直到准备好接受下一个 request 的时候才返回。
    4. framework 持续调用 ICameraDeviceSession::processCaptureRequest() 进行 request 的下发,如果需要切换其它场景的话就再次调用 ICameraDeviceSession::constructDefaultRequestSettings() 进行具体场景的默认 setting 构建。
    5. 当本次 request 开始被 HAL 正式执行的时候,也就是 HAL 底下的硬件 sensor 开始曝光本帧的时候(sensor starts exposing for capture),HAL 需要调用 framework 实现的 ICameraDeviceCallback::notify() 函数进行 SHUTTER 消息回调,这个消息里面包含了时间戳数据和 framenumber。这个是 HAL 层主动发起的回调,但是不需要再第一个 request 下发下去之前就开始回调,并且一个 request 的 notify 完成之前,不要返回任何 result 给到 framework。
    6. 经过几个 pipeline 延迟之后,HAL 开始向 framework 返回已经完成的结果,返回过程通过 ICameraDeviceCallback::processCaptureResult() 函数完成。返回的顺序得是按照提交的 request 请求的顺序来,request 也可以一次性下发多个,数量取决于 request 的队列深度,一般 6~8 个吧,也取决于具体的平台和其代码实现。
  • 上面的过程会不断地进行循环,等到一定时刻,会发生下面的事件
    1. framework 停止下发 request 请求,然后等待所有的 buffer 被填充完毕并且所有的 result 全部返回,这个时候再次调用 ICameraDeviceSession::configureStreams() 接口重新配置业务流,这在 HAL 内部会导致整个的硬件被重置一遍,然后用新的 stream 重新配置,接下来继续上面的因果循环。这说白了就是场景的切换,比如从拍照切换到录像(不关闭 camera app)。
    2. framework 可能会调用 ICameraDeviceSession::close() 接口来结束整个会话,该函数可以在任何时候进行调用,但是 framework 在调用该函数的时候不可以继续下发 request,并且所有其它的函数调用都不能够进行下去,在 close 函数返回之后,HAL 层不得再回调 framework 的函数。其实在 close 之前,通常会有 flush 函数调用,这个函数的调用要求与 close 差不多,close 可以认为就是个收尾动作,flush 会等待所有的 request 完成并且所有的 result 全部返回到 framework。
    3. 当发生错误或者其它异步事件的时候,HAL 必须调用 ICameraDeviceCallback::notify() 函数来返回错误消息给 framework。如果 HAL 内部发生了严重的设备错误,HAL 内部在回复完错误消息之后需要按照 close 函数被调用时候的动作来清理案发现场。同时,在调用 notify 之前,也应该停止所有的尚在队列中的 request 请求响应,严重错误传递给 framework 的时候,HAL 不再返回任何结果给到 framework,并且在 framework 尝试调用 close 的时候需要返回 -ENODEV 或者 NULL。

上面就是整体上站在 framework 角度上来描述一个 camera 业务逻辑的生命周期完整的过程,从上面可以知道比较关键的就是下面几个:

  1. 设备枚举
  2. session 创建
  3. stream 配置,request 构建与下发
  4. result 返回和 notify 事件回调
  5. 现场清理

下面会从这些关键点来稍微概述下它们的工作以及基本的实现原理。依然是从大体上进行一次概述,先基本了解下整个的 Camera 的工作流程是什么样子的。

设备枚举

设备的枚举有两个层面意义上的枚举,第一个是在 provider 初始化的时候向 HAL 层内部的枚举,另一个是 framework 向 provider 索要的设备枚举过程,两者是不太一样的,至少其发生的时间是不一样的。

在 provider 创建的时候,也就是 CameraProviderImpl,这里有一个点,就是旧的 Android P 的代码,只有一个 Provider 的实现,但是新的代码里面扩展了两个,这个以后再说。创建的时候会去获取 HAL 内部定义的 camera_module_t 结构体,然后创建一个新的 Google HAL 层的 CameraModule 抽象,以后的很多配置获取相关的操作都是使用这个 CameraModule 进行中转。

在 CameraModule 创建之后,Provider 就会继续获取设备上面枚举出来的 Camera 数量,然后再遍历所有的 Camera,调用其 get_camera_info 回调函数把 camera 的信息给保存起来,注意这个时候 Camera 设备名的枚举还没有送往 framework 层,而是保存在了 Provider 的一个 map 数组里面,这里只是检查下时候 Camera 设备是否兼容,把兼容的设备放在 map 数组里面去。

然后在 framework 想去获取设备列表的时候,就调用 Provider 的 getCameraIdList 进行设备名列表的获取,这个调用过程依然是通过 HIDL 完成的,媒介就是 Binder 这个跨进程通信工具。

在枚举过程完成之后,就会调用 getCameraDeviceInterface_VX_X 进行设备的创建,这个函数的实现也是在 CameraProviderImpl 里面实现的,之后这个设备的构造函数被调用,正式创建一个与 Camera device id 相关联的 CameraDevice 实体类,最后 framework 会调用这个类的 open 接口,在 open 函数里面会调用到 HAL 底层实现的 open,并且会创建一个 Google HAL 层的 CameraDeviceSession。

然后呢,这个 Session 就是后续进行各种骚操作的基础类了,非常重要,等于说是 framework 通过 Provider 搭建了一个平台,然后平台之上催生了 CameraDeviceSession 这个交通枢纽,所有后期与业务逻辑紧密相关的调用操作都是通过这个交通枢纽来完成的,比如 configure_streams,processCaptureRequest,flush,close 等等。

session 的创建

session 附属于 device 下面,很多重要的操作全部都是使用 session 来完成的。

struct camera3_device_ops_t {1. initialize2. configure_streams3. construct_default_request_settings4. process_capture_request5. dump6. flush
}

另外在 session 里面还附加了一些回调函数,比如 notify、processCaptureResult 这样的回调,这些回调函数的实现是从 HAL 内层往 Google HAL 以至于 framework 层进行回调的。session 里面还简单的对 request 进行了队列的创建与管理,还对 stream 与 buffer 进行了简单的构建与管理。

总之 session 的角色就是重要交通枢纽,我个人觉得,很多的重要操作以及数据资源都需要从它这里经过。

另外,上面讨论的 Provider 是 2.4 版本,CameraModule 是 1.0 版本,CameraDevice、CameraDeviceSession 都是基于 3.2 这个版本进行的,其它的版本是有不少改变的,尤其是 3.4 版本的 Device 和 3.2 就有很多的不同。这个在之后的文章里面也会稍稍进行说明。

constructDefaultRequestSettings

这个函数我觉得有必要在这里拎出来说下,这个函数的主要功通过我缜密的推理与验证,结论是它就是创建默认的 request 模板之用的(废话,名字都能看出来了)。

说,在 Camera 的世界里面,它有很多种模式,这个在 Google 的官方文档里面有去定义,比如下面的几种类型:

  1. TEMPLATE_MANUAL
  2. TEMPLATE_PREVIEW
  3. TEMPLATE_RECORD

以及其它的多种模板枚举定义,从它们的名字就可以看出来其基本的使用场景了,这里就说下手机上面的经典使用模式吧,比如普通录像模式就对应的是 TEMPLATE_RECORD,还有一种模式是在录像的时候还可以实时地进行拍照操作,这个在最新的手机上面大多都是有这样的功能的,就算是我的小米6上面也都有这个功能。TEMPLATE_ZERO_SHUTTER_LAG 就是所谓的零延时拍照,这个就是说你按下拍照键之后就立刻给你返回了一个照片,而不是等待那么一会儿延迟,可以知道,这个时候的照片其实并不是你按下拍照键那一刻的照片,而是稍前面一点的,所谓零延时拍照。

底层要构建好这样一个以 CameraMetadata 为载体的默认设置集,该 CameraMetadata 由 CameraDeviceSession 和 HAL 底层各执一份,当然源头还是在 HAL 底层,上面的都是其拷贝体,里面包含的内容就是 Google 规定的 CameraMetadata 的内容项了,当然,更加具体的还是取决于 HAL 底层的实现以及部分 Google 规定好的套路化的东西。

本操作在第一次真正的 request 下发之前就已经应该执行完了,在具体的业务逻辑场景开始的时候,framework 使用默认的 CameraMetadata 进行每一帧的 request 具体参数的构建操作,这样就省去了很多的麻烦并且也能够适配好底层 HAL 的实现。

End

本文主要就是说下对于 HAL 来说,在一个具体的业务逻辑下大致的流程,应该先要怎么样,后来怎么样,然后结果怎样返回等等,主要是对整体流程有一个概念性的了解,之后的文章会尽量的从上到下对 Camera 的初始化和使用进行说明,当然也不一定,有可能会穿插着底层 HAL 的实现来说明。

另外,我觉得此处以及那处以及这里那里都应该加上一张图,一图胜千言,但是无奈画图太费劲了,我这么懒,画一张图半个周就过去了,后面有缘的话就画点图,没有就是正常的。


想做的事情就去做吧

Android Camera HAL3 - 框架流程预览相关推荐

  1. android camera 全屏,Android Camera做全屏预览之最简单方法.doc

    Android Camera做全屏预览之最简单方法 M厂开发五部:刘 博 一.全屏预览与非全屏预览的区别 对于大多数人来说,我们看电影.玩游戏等都喜欢全屏,我们之所以喜欢全屏的一个主要原因就是全屏的感 ...

  2. 玩转Android Camera开发(一):Surfaceview预览Camera,基础拍照功能完整demo

    杂家前文是在2012年的除夕之夜仓促完成,后来很多人指出了一些问题,琐事缠身一直没有进行升级.后来随着我自己的使用,越来越发现不出个升级版的demo是不行了.有时候就连我自己用这个demo测一些性能. ...

  3. Android Camera开发系列:预览镜头缩放(数码变焦)

    写在前面: 这篇文章主要介绍Camera2 API上,如果进行相机镜头的缩放,这里说的缩放指定的数码变焦. 如下图所示,左边是正常情况下的画面,右侧是镜头拉近的画面,接下来,我们就看下代码上是如何实现 ...

  4. Android Camera HAL3 hdr

    HAL3的主要流程 获取现在设备上可用的相机设备,包括相机每一个相机的属性功能,get_number_of_camera. 获取想要打开的相机的Information,在调用中被定为 get_came ...

  5. android 摄像头比例,Android摄像头是全屏预览最简单的方式.doc

    Android摄像头是全屏预览最简单的方式 Android Camera做全屏预览之最简单方法 M厂开发五部:刘 博 一.全屏预览与非全屏预览的区别 对于大多数人来说,我们看电影.玩游戏等都喜欢全屏, ...

  6. Android用MediaCodec将相机预览帧编码成MP4视频

    文章目录 知识预备 实现思路 获取图像数据帧 编码视频 初始化编码器 编码转换 编码视频 问题记录 最近项目中,有一个在扫码同时录视频的需求.扫码框架是通过摄像头 onPreviewFrame方法获取 ...

  7. android 组件消失了,Android 12 2.2 开发者预览版发布:修复桌面小组件消失等问题...

    IT 之家 4 月 8 日消息 据外媒 XDA 论坛消息,Android 12 2.2 开发者预览版今日发布,同时包含安卓 2021 年 4 月安全更新.本次预览版主要修复了一些错误,没有带来重要功能 ...

  8. android xml 预览,解决Android studio xml界面无法预览问题

    解决Android studio xml界面无法预览问题 发布时间:2020-10-05 18:48:37 来源:脚本之家 阅读:140 作者:张雨明 如下图 修改style.xml中的 parent ...

  9. 如何不解锁BL刷入Android 12/安卓程序员预览版或者刷回Android 11

    教程参考的"如何不解锁BL使用adb sideload安装(刷入)android 12(安卓)程序员预览版1/DP1" 最近重新使用回了Pixel 5,前几天突然心血来潮想刷入An ...

最新文章

  1. 在SQL Server中分页结果的最佳方法是什么
  2. ArduinoIDE安装与配置与第一个程序的烧录和运行——人人都能玩硬件
  3. 【discuz x3】源代码中的sql调用
  4. LeetCode 266. 回文排列(计数)
  5. python安卓自动化实现方法_uiautomator +python 实现安卓UI自动化
  6. java103 101 104 101_编写一个java程序将100,101,102,103,104,105这6个数以数组的形式写入到D:\\test.t...
  7. 【机器学习】机器学习从零到掌握之五 -- 教你使用归一化数值准备数据
  8. 自己手写一个Spring MVC框架
  9. NFS+rsync+inotify镜像
  10. 最大后验估计与共轭分布
  11. 短时傅里叶变换STFT(matlab)
  12. linux构建lamp的关键步骤,Linux-LAMP平台搭建详解
  13. 米兔机器人自主编程_可编程米兔机器人 让成年人回归童心的玩具
  14. ctfshow-菜狗杯-web(一)
  15. 多台计算机直接连接打印机,多台电脑如何连接打印机?
  16. 一文搞懂 Redis
  17. 家庭组网 光猫+交换机利用VLAN划分实现客厅IPTV机顶盒与上网路由器单线复用(上)
  18. c语言语法要素,第6章DSP_C语言程序设计要素.ppt
  19. 论ICT技术与数据中心的关系
  20. 安利一个Mac下好用的抓包工具-Charles

热门文章

  1. java-使用 flying-saucer 通过 xhtml 生成 pdf 文档支持 css 和 图片
  2. 电脑崩溃?黑客最爱邮件入侵方式,在双十一也要保护好网络安全!
  3. 固态硬盘数据丢失了该怎么办
  4. linux测试ping值,网站全国各地Ping值测试|在线ping工具—卡卡网 www.webkaka.com
  5. Html5 Egret游戏开发 成语大挑战(九)设置界面和声音管理
  6. ubuntu下重装WIN7
  7. 前三周学习Python的心得与感受
  8. 使用hutool-poi在未安装Office或wps软件的电脑中生成Excel的xls后缀消失问题
  9. 阻塞队列(一):ArrayBlockingQueue
  10. 【离散数学】群论知识点总结