文章目录
- 前言
- request流程
- result流程
- Camera3Stream
- InputBuffer的申请和释放
- OutputBuffer的申请和释放
- request携带的buffer到底是什么?
前言
Camera的buffer用途上主要分为两类:input buffer和output buffer。
- input buffer是有实际内容的buffer,通过reprocess流程将其送到hal,hal读取它并进行一系列的处理。
- output buffer是仅有一块buffer内存,里面没有具体数据,hal会将生成的数据填入到output buffer中。
在Camera2+HAL3的架构中,buffer是交由stream来管理的,configure stream流程配置的stream定义了HAL可以处理的buffer的类型,每一个stream对应了系列同类型的buffer。看下Google对stream的定义:
什么是stream? (定义:hardware/libhardware/include/hardware/camera3.h)
A handle to a single camera input or output stream. A stream is defined by the framework by its buffer resolution and format, and additionally by the HAL with the gralloc usage flags and the maximum in-flight buffer count.
The stream structures are owned by the framework, but pointers to a camera3_stream passed into the HAL by configure_streams() are valid until the end of the first subsequent configure_streams() call that does not include that camera3_stream as an argument, or until the end of the close() call.
All camera3_stream framework-controlled members are immutable once the camera3_stream is passed into configure_streams(). The HAL may only change the HAL-controlled parameters during a configure_streams() call, except for the contents of the private pointer.
If a configure_streams() call returns a non-fatal error, all active streams remain valid as if configure_streams() had not been called.
The endpoint of the stream is not visible to the camera HAL device. In DEVICE_API_VERSION_3_1, this was changed to share consumer usage flags on streams where the camera is a producer (OUTPUT and BIDIRECTIONAL stream types) see the usage field below.
简单来说就是,stream有input stream和output stream两种类型,它定义了buffer的四个基本属性:(1) resolution (2) format (3) gralloc usage flags (4) maximun in-flight buffer count。
什么是 in-flight buffer ?
参考: Android Camera2+HAL3架构 中 request在HAL的处理方式 这一章节。我们可以知道HAL在处理request的过程中,可以有很多个request并存在hal,这些request都在排队等待hal的各个流程处理,这些request就是in-flight request,相应的其携带的buffer就是inflight buffer。
所以,maximun in-flight buffer count 就是定义了这类buffer可以同时在hal存在的最大数量。这个值由HAL确定。
Camera buffer的使用都是跟随request流程和result流程走的,下文会通过梳理camera server的request和result流程来分析camera server的buffer使用机制。
request流程
简要概述上图所画的关键函数的作用:
- threadLoop:open camera时启动的线程函数,用于向HAL发request,close camera时结束该线程。当App没有下发request到framework时,该函数会wait在waitForNextRequestLocked中,等待requets的到来。
- waitForNextRequestLocked: 该函数的作用是从RequestQueue(RequestQueue的概念参考 Android Camera2+HAL3架构的request整体流程图,对应的是图中的PendingRequestQueue)中拿出一个request并返回。如果RequestQueue没有request,则从RepeatingRequestQueue中拿一个request出来。
- getInputBuffer && getBuffer:前者仅当request携带input stream才会触发,用于获取input buffer;后者用于获取request携带的output stream的buffer。(注意:无论是input buffer还是output buffer,都有最大数量限制,由stream的max_buffers来确定,即上文提到的maximun in-flight buffer count,这个值由HAL设置。当buffer数量不够时,会触发wait等待)
result流程
简要概述上图所画的关键函数的作用:
- processCaptureResult: HAL返回result到framework一定会触发该函数。该函数会将metadata返回给app,以及将output buffer和input buffer返回给stream。
- returnBuffer && returnInputBuffer:前者将output buffer还给stream,后者将input buffer还给stream。
Camera3Stream
如前言章节提到“在Camera2+HAL3的架构中,buffer是交由stream来管理的”,本章节从stream出发,研究框架是如何通过stream来管理buffer的。下图是Stream3Stream的UML类图:
各个关键类的用途如下:
类名 | 用途 |
---|---|
camera3_stream | stream基础类型,定义了buffer的四个基本属性:(1) resolution (2) format (3) gralloc usage flags (4) maximun in-flight buffer count。 |
Camera3StreamInterface | 定义了一系列操作stream的接口,如:configure stream、get buffer、return buffer等。 |
Camera3Stream | 用于管理来自摄像机设备的单个输入或输出数据流的类,并定义了一个内部状态机用于追踪stream的状态,如:connected、configured等状态。 |
Camera3IOStreamBase | 维护了一系列用于管理buffer的成员,如:mTotalBufferCount(该stream允许的最大buffer数量)、mHandoutTotalBufferCount(发送给HAL的buffer总数,包括input buffer和output buffer)等 |
Camera3InputStream | 用于管理相机设备的单一输入数据流的类,该类充当HAL的消费者适配器(HAL是消费者,该类用于获取Input Buffer,然后分发给HAL使用),当HAL消费完成后,Input Buffer则会通过该类释放。 |
Camera3OutputStream | 用于管理相机设备的单一输出数据流的类 |
InputBuffer的申请和释放
上述流程图描述了通过Camera3Stream申请/释放 InputBuffer的逻辑,从图中可以看出,最终buffer的实际申请和释放都是通过BufferItemConsumer的acquireBuffer和releaseBuffer来实现的。
BufferItemConsumer是一个什么样的类?
BufferItemConsumer实际上不属于camera模块,它定义在/frameworks/native/include/gui/BufferItemConsumer.h中。定义如下:
ConsumerBase is a base class for BufferQueue consumer end-points. It handles common tasks like management of the connection to the BufferQueue and the buffer pool.
从上述定义以及文件位置来看,这里的逻辑是从属于 display 模块的,***BufferQueue***在 display 也是一个很重要的概念。它将可生成图形数据buffer的组件(生产方)连接到接受数据以便进行显示或进一步处理的组件(使用方)。几乎所有在系统中移动图形数据buffer的内容都依赖于 BufferQueue。
简言之,BufferQueue是Android显示系统的核心,只要显示内容到“屏幕”(此处指抽象的屏幕,有时候还可以包含编码器),就一定需要用到BufferQueue。BufferQueue是一个生产者消费者模型又是GraphicBuffer管理者,它和显示系统以及Camera流媒体紧密关系着。
有关BufferQueue的具体概念,有一篇很好文章,参考:BufferQueue 学习总结
OutputBuffer的申请和释放
对应上述流程图,可以看出OutputBuffer的申请有三种情况:
- 当mUseBufferManager为TRUE时,从 Camera3BufferManager 中申请。
- 当mUseBufferManager为TRUE,但是无法从 Camera3BufferManager 中申请时(有空闲可用buffer),从 ANativeWindow 中dequeue buffer。这个buffer实际上也是 Camera3BufferManager 申请的,然后将其attach到 ANativeWindow。
- 当mUseBufferManager为FALSE时,直接从 ANativeWindow 中dequeue buffer,这个buffer则是由 ANativeWindow 申请。
那么问题来了,如何控制是通过 Camera3BufferManager 还是 ANativeWindow 来申请buffer?
主要是这两个条件:
mSetId > CAMERA3_STREAM_SET_ID_INVALID
!(isConsumedByHWComposer() || isConsumedByHWTexture())
即 mSetId > -1 && 不是display/texture streams
App在创建session的时候,会使用这个API(public OutputConfiguration (int surfaceGroupId, Surface surface)),来创建OutputConfiguration,mSetId就是对应surfaceGroupId。该参数的默认值为-1,就是不enable Camera3BufferManager。
总结一下,output buffer的来源要么从 Camera3BufferManager 中申请,要么从 ANativeWindow 申请。 从前者申请的话,Camera Server会拥有对output buffer更多的控制权,如动态申请释放buffer来省内存。Camera3BufferManager 的定义如下:
A class managing the graphic buffers that is used by camera output streams. It allocates and hands out Gralloc buffers to the clients (e.g., Camera3OutputStream) based on the requests. When clients request a buffer, buffer manager will pick a buffer if there are some already allocated buffer available, will allocate a buffer otherwise. When there are too many allocated buffer maintained by the buffer manager, it will dynamically deallocate some buffers that are solely owned by this buffer manager.
In doing so, it reduces the memory footprint unless it is already minimal without impacting performance.
request携带的buffer到底是什么?
request携带的buffer类型是buffer_handle_t *,buffer_handle_t实际上是一个native_handle_t的指针。private_handle_t是Gralloc分配buffer的描述,在不同的平台的实现上,private_handle_t可能会有不同的定义。所以都是用native_handle_t来描述,从而消除平台差异性。
GraphicBuffer实际上是对native_handle_t的封装,Surface提供了两个关键的接口:(1) dequeueBuffer (2) queueBuffer。 前者用于获取buffer(即用于生产),后者用于归还buffer(即用于消费),但是后者的操作不会释放buffer的引用。
以高通平台为例,reques携带的buffer来源实际上是”通过Surface向display service(进程名:vendor.qti.hardware.display.allocator-service)申请的GraphicBuffer” 。