从 Android10 开始,camera 系统加入了一个可选地 buffer 管理方式,可以在 Vendor HAL 这边灵活使用这个选项进行 buffer 管理,以此达到减少 buffer 使用峰值,改变 request 执行速度等优点。具体的来说就是对于 HAL request queue 中的每一个 request 来讲,并不是每一个 request 的每一个 buffer 都是被使用到的,有些 request 可能就没有用到 buffer。说到这里想起关于 buffer 使用量的几个问题,一个是 buffer 使用总量,一个是 buffer 使用峰值。

Buffer 使用总量顾名思义就是一个系统中最多可能用到的 buffer 数量,这个是系统设计之初就已经定好的,申请 buffer pool 的时候应该申请等量的 buffer 空间,不然就可能会造成处理错误。Buffer 使用峰值就是某一时刻整个系统同时在用的 buffer 最大值,这个值是小于等于 Buffer 使用总量这个值的。那我们要优化一个系统就需要同时减少两者的值,使用总量减少很能够理解,可以节省空间,但是峰值为什么要减少呢?如果某一时刻系统处理达到了峰值,那么就可能会阻塞接下来的处理请求,因为要等待空闲出来的 buffer 嘛,想象下如果我们是一个流式处理系统,如果总是一开始就全部申请设置好 buffer,那就会导致大量的 buffer 在大部分时间状况下没有用到,这浪费了很多的等待时间,所以也是为什么要减少峰值的原因。

对于 Google Android 的文档介绍,举了一个例子:假设说 HAL 可能有 8 个 request 正在队列里面等待处理,但是只在最后两个 request 才需要申请 buffer。在 Android 9 和 9 以下的版本,这 8 个 request 的 buffer 都是提前分配好的,所以这个时候有 6 个 request 的 buffer 都是没用使用的,Android 10 往后的版本就支持把 buffer 使用和 request 分离开,不用每次都提前绑定,而是用到了才进行绑定。这在高端平台可以节省很多 buffer 使用,并且对于低内存的平台也是很有帮助的,至于为什么会有帮助,就是上面说的峰值这块,减少峰值一定程度上也是可以减少最大值的。

下面两个图是从官网搞过来的:

可以看到第二个图里面的 buffer 是实际使用到的时候才进行配对处理的,这样可以节省很多 buffer 的使用,甚至对于每次申请不同类型 buffer 的 request 来说也可以针对 buffer 类型的不同来申请,因为同一个 request 里面的 buffer 是有一定可能并非全部都用得上的,有些用不上的就可以不去申请空间了。

实现 buffer management

对于 HAL 层来讲需要实现下面几个点:

  1. 实现 HIDL 接口,ICameraDevice@3.5,这部分其实是 Android HAL 层的部分,Vendor HAL 不用管这里先。
  2. android.info.supportedBufferManagementVersion 的值改为 HIDL_DEVICE_3_5。这个值在 /platform/hardware/interfaces/camera/metadata/3.4/types.hal 里面。

Vendor HAl 可以使用的接口有:requestStreamBuffers, returnStreamBuffers 两个分别用于请求、释放 buffer,另外还需要 signalStreamFlush 接口,这个接口是在 Vendor HAL 那边实现的,前面两个接口都是 Android HAL 实现好了给到 Vendor HAL 那边进行回调的,最后一个是 framework 往 Vendor HAL 调用的,用于返还全部 Vendor HAL 持有的 buffer,这个调用明显就是要在 configure_stream 或者 flush 前后进行的,用于一次性回收全部的 buffer。

requestStreamBuffers

这个是由 Vendor HAL 主动调用的,其函数实体是在 Android HAL 那边实现的,会在 device 初始化的时候作为 camera3_callback_ops_t 类型结构体成员传递 Vendor HAL,通常情况下这个需要在 process_capture_request 的时候进行调用,用以申请相关所需要的 buffer。如果设置了使用 Android HAL 的 buffer manager,在下发 request 的时候是不会带 buffer 的,这个时候必须得使用该接口去获取 buffer,否则会造成致命错误。

该函数可以一次请求多个 stream 类型的多个 buffer,该函数的参数主要包含了一对输入,一对输出,其中关键结构体如下所示:

struct camera3_buffer_request {camera3_stream_t *stream;uint32_t num_buffers_requested;
}struct camera3_stream_buffer_ret {camera3_stream_t *stream;camera3_stream_buffer_req_status_t status;uint32_t num_output_buffers;camera3_stream_buffer_t *output_buffers;
}
  1. 输入:需请求的 camera2_buffer_request 数量,以及存放该结构体信息的数组。
  2. 输出:返回的 camera3_stream_buffer_ret 数量,以及存放该结构体信息的数组。

输入输出基本上都是一个套路,就是首先区分 stream,不同的 stream buffer 归拢到一块,设置其数量,然后把不同 stream 再放在一个结构体里面排排队作为数组传递给 Android HAL。需要注意的是返回的信息里面有一个 camera3_stream_buffer_req_status_t 信息,这个是表明本次 buffer 申请成功与否的标志,大致上包含以下几个方面:

  1. OK:不用说看长相就是很成功了。
  2. FAILED_PARTIAL:这个就要 check 下每一个返回的 camera3_stream_buffer_ret 结构体了,说明是有的成功有的失败了,但是这个不是细化到每一个 camera3_stream_buffer_t 层级的,一个 stream 类型失败那就说明这个类型下面全部的 buffer 都不可用。
  3. FAILED_CONFIGURING:没有任何一个 buffer 返回,一个都没有。据注解是说这个时候可能 Android HAL 那边正在进行或者将要进行 configure_streams 操作了,Vendor HAL 需要等到最近一次 configure_streams 操作完成之后再去请求。
  4. FAILED_ILLEGAL_ARGUMENTS:是说明我们输入的参数不对,比如根本找不到输入的 stream 类型,这个时候也是一个 buffer 返回都没有的,我们请求的 stream 必须是 configure_streams 的时候传递下来的 stream,不能是其它的。
  5. FAILED_UNKNOW:不知名错误,或者每一个 stream 的错误类型都不一样,这种错误说明也是一个 buffer 都没回来,需要检查每一个 stream 对应的错误情况。

由于该函数请求在 camera service 那边是串行化的,也就是会 block 多个的请求,并且请求的 buffer 越多就越可能会导致更长的等待时间,综合来讲,需要 Vendor HAL 以及 Android HAL 那边使用同一个高优先级的线程进行该调用。对于输出参数而言,Vendor HAL 需要申请好预先设定的空间,然后交给 Android HAL 去进行数据填充。

该请求可能会出现一些非致命的问题,调用者也需要能够适当进行处理,下面的错误都是整个函数的返回值决定的,返回值类型是 camera3_buffer_request_status_t

  1. App disconnects from the output stream:这个是非致命的错误,如果出现该种情况,Vendor HAL 需要返回一个 ERROR_REQUEST 错误,只要该 request 包含有 disconnect stream,那就得返回一个这样的错误值。
  2. Timeout:这个可能是因为 APP 正忙着做别的事情,所以也要返回一个 ERROR_REQUEST 错误,但是这个并不影响后续的处理流程,只在当前 request 返回一个错误即可,后续的还按照正常的步骤进行处理。
  3. Camera framework is preparing a new stream configuration:这个就需要先等待 configure_streams 跑完之后再进行 buffer 申请。
  4. The camera HAL has reached its buffer limit (the maxBuffers field):说明 buffer 用量达到最大值了,这个时候应该等着,知道有新的 buffer 可用再去申请。关于怎么知道可用这个问题,一般我们返回 buffer 是用 process_capture_result 返回的,所以可以在每一个 process_capture_result 调用之后唤醒重新请求 buffer。

returnStreamBuffers

该接口可以返回 buffer 给到 framework,正常情况下来讲,都是通过 process_capture_result 函数来进行 buffer 返回的,但是有些时候 Vendor HAL 可能请求了多于实际用到的 buffer 数量,这个时候正常返回接口就没有办法返回全部的 buffer,只能通过该接口进行剩余 buffer 的返还操作。如果 Vendor HAL 在实现上就不会 hold 多余 buffer,那么本接口就可以忽略掉。

signalStreamFlush

这个有一点类似于 returnStreamBuffers,只不过本接口表明 framework 想要拿回所有的 buffer,此时一般都是在 configure_streams 前后,当然如果 Vendor HAL 也还是从不拿多余的 buffer,那么该接口也可以不用实现,就置为空就可以了。当 framework 调用该接口的时候,就不会再继续下发 request 了,并且等到所有的 buffer 返回到 framework 之后,Vendor HAL request buffer 也是会失败的。

本接口与 flush 有所区别,flush 是需要给所有 pending 的 request 返回一个 ERROR_REQUEST 的错误,而本接口是需要正常完成所有的 request 的。并且有一个很重要的一点,就是本接口它是相对独立的一个 HIDL 接口,调用的时候可能本接口先调用,但是 configure_streams 调用先被执行,如果没有任何同步装置的话,就会造成执行错乱继而引起程序崩溃,一个方法是 framework 在本接口的参数里面加入了一个 streamConfigCounter 参数,Vendor HAL 需要判断这个参数来看是否是在 configure_streams 调用之后的时间调用的,看下图示例:

行为变化

使用 buffer management API 实现 buffer 管理逻辑,需要考虑下以下的行为改变:

  • Capture request:framework 会更快的发 request 到 camera Vendor HAL 那边,如果没有 buffer management,framework 由于不需要绑定 buffer 到 request 那边,所以下发 request 的速度会更快。并且没有 buffer management 的话,framework 在达到 buffer 最大数量的时候会停止下发 request 到 Vendor HAL 那边,但是有了 buffer management,这个机制就不存在了,也就是说 framework 会持续不断地下发 request,当然 Vendor HAL 那边一定要在 request Queue 达到 Vendor HAL 的最大值的时候拒绝接受新的下发 request。
  • requestStreamBuffers 调用延迟:在以下几种情况下可能会发生调用被阻塞延迟:
    • 对于第一次创建 buffer 的 stream 来说,需要更长时间来分配 buffer 空间。
    • 申请越多的 buffer 就会导致越长的时间延迟。
    • APP 正在忙于其它事情,这个时候可能会造成 buffer request 速度变慢,并且有一定可能触发 timeout。

Buffer management 策略

Buffer management API 允许不同的策略实现,下面就是一些例子:

  • 后向兼容:Vendor HAL 在 process_capture_request 的时候就去申请 buffer,这样做并不会节省 buffer 使用,但是可以作为一个初步的实现,这部分只需要更改很少量的代码即可。
  • 最大化节省内存:只有在真正用到 buffer 时才去申请,这个要结合 Vendor HAL 内部 pipeline 的实现去整合,这部分是需要一个系统性的改动的,我立刻就能想到两种解决方向,一种是在 request 的时候就请求多个 buffer 作为缓冲池,然后内部 pipeline 在用到的时候去缓冲池里面取 buffer,这个重点是如何控制缓冲池 buffer 数量。第二种就是用到了的时候去 framework 取,这种需要一个贯穿 Vendor HAL 底层到 framework 的调用来实现才可以。
  • 缓存 buffer:Vendor HAL 可以 cache 一些 buffer 以避免用到的时候才去取用会导致的延迟问题(这里也就凸显了 signalStreamFlush 的作用)。

End

这个一定程度上来讲是个挺有用的 feature,应该是慢慢标准化并且支持进去,现在我看还是可选的一个选项,并且是有一部分示例代码,还不是标准化流程代码。说起 buffer 管理这玩意儿,我觉得对于视频流产品模块来讲,有 70% 以上的代码都是在实现 buffer 的流转、管理,掌握一个视频流模块框架,一部分程度上等同于掌握其 buffer 管理的设计与实现。


Android Camera HAL3 - MultiCamera-HALBufferManager相关推荐

  1. Android Camera HAL3 - Multi Camera(1)

    本文介绍下 Google Android 在其文档中对于 Multi-Camera 的描述,以及 Android R 中对 Camera HAL3 的一些新增内容,Multi-Camera 从 And ...

  2. 基于Mtk平台的android camera hal3学习

     框架 Android Camera硬件抽象层(HAL,Hardware Abstraction Layer)主要用于把底层camera driver的实现接口进行封装,再经过算法处理,提供接口给f ...

  3. Android Camera HAL3 - 框架流程预览

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

  4. android camera hal3 分析,HAL3 enabler下载-HAL3 enabler(开启camera2 api)下载v5.0 安卓版-西西软件下载...

    HAL3 enabler(开启camera2 api)让你无需Magisk模块就能够轻松的开启手机当中的camera2 api功能.对于想要将手机当中的相机功能玩出更多花样的人来说,这绝对是一款极为便 ...

  5. Android Camera HAL3 -架构设计

    其实从 APP 到 Google HAL 再到 Vendor HAL 的通用 interface,这些地方的架构都是包含在 Android 包里面的,基本上是有迹可循的,在开发的时候即使是什么都不没有 ...

  6. Android Camera HAL3 -SessionParameter

    本文参考: https://source.android.google.cn/devices/camera/session-parameters https://source.android.goog ...

  7. Android Camera HAL3 hdr

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

  8. 我心依旧之Android Camera模块FW/HAL3探学序

    前沿: 目前对于Android Camera软硬件技术发展的主流方向是高像素.高帧率.多摄像头.超强的ISP以及各种视频图形处理算法等等.当前主流的Android系统中较为常见的Camera模块还均是 ...

  9. Android [Camera 源码] 相机 HAL3(Camera3) Google官方文档(二)

    Google源码网地址链接:https://source.android.com/devices/camera 该Google Camera的文档为系列文章,文章列表: overview Camera ...

  10. Camera HAL3学习: Android Camera System

    Android Camera硬件抽象层(HAL,Hardware Abstraction Layer)主要用于把底层camera drive与硬件和位于android.hardware中的framew ...

最新文章

  1. android java包_android SDk中常用的java包介绍
  2. 【算法与数据结构】中缀表达式转为后缀表达式
  3. 利用PHP SOAP实现web service
  4. python网络爬虫系列(九)——打码平台的使用
  5. 卷的作用_还在盲目的制作蛋糕卷吗?先来搞懂这几种蛋糕卷面糊~
  6. 遍历一个文件下的所有目录和文件
  7. matlab图像处理 推荐,Matlab计算机视觉、图像处理工具箱推荐
  8. cad在线转换低版本_别再傻瓜式操作了,工作效率上不去?这6个小技巧带你玩转CAD...
  9. 替换换行符:回车换行CR/LF
  10. GitHub使用教程
  11. javaweb入门教程
  12. HDL.Companion.v2.8.R1.for.Windows linux64 编程开发软件
  13. 数电中一些常用的逻辑门符号
  14. python火车票分析_通过python splinter分析12306网站
  15. CKEditor 修改编辑器 字体大小和行高
  16. 【经典】双子男与天蝎女的爱情故事
  17. python计算器程序_python练习 计算器模拟程序
  18. LeetCode——974.和可被K整除的子数组
  19. Android传感器介绍及指南针的实现
  20. 实现一个简单的语音聊天室(源码)

热门文章

  1. 关于chm提示 已取消到该网页的导航的解决方法
  2. 分布式监控系统——Zabbix(2)部署
  3. spring默认redis连接库lettuce性能优化,突破性能天花板,获得官方建议方式2倍吞吐量
  4. OKHttp源码详解_tony_851122
  5. mysql存储过程 outfile_mysql存储过程 outfile
  6. Unix环境高级编程—进程控制(三)
  7. html在搜索按钮中加放大镜,CSS3 搜索按钮动效 - 放大镜图标变叉叉
  8. 遥感影像人口数据、气象数据、社会统计数据、GDP空间分布数据
  9. How to install VIB on VMware ESXi
  10. 欢迎页面welcome.jsp