深入淺出CameraServer的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類圖:
Camera3OutputStream 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的申請和釋放

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的申請和釋放
對應上述流程圖,可以看出OutputBuffer的申請有三種情況:

  1. 當mUseBufferManager爲TRUE時,從 Camera3BufferManager 中申請。
  2. 當mUseBufferManager爲TRUE,但是無法從 Camera3BufferManager 中申請時(有空閒可用buffer),從 ANativeWindow 中dequeue buffer。這個buffer實際上也是 Camera3BufferManager 申請的,然後將其attach到 ANativeWindow
  3. 當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” 。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章