海思MPP視頻處理平台流程簡介
hisi芯片系統概述
首先先來了解一下海思芯片SOC,下圖是hi3519A芯片設計圖
圖1 hi3519AV100 芯片設計圖
芯片的設計圖有助於我們對海思的圖像處理有一個大致的了解,從上圖中我們可以看到,芯片SOC里集成了眾多控制芯片,比如負責深度學習的NNIE硬核,負責圖像處理的IVE硬核,視頻編解碼單元H265/H264Codec,以及圖像處理單元ISP等。
為了減少用戶對於硬件的直接操作,海思為用戶封裝了許多對於硬件的操作接口,能夠控制芯片完成相應的媒體處理功能,對上屏蔽了硬件的處理細節,用戶能夠將精力集中在業務功能上,達到快速開發的目的。這些相關硬件接口就構成了下圖中的媒體軟件處理平台層。我們進行視頻圖像的處理主要是要調用該層提供的相關接口來完成相應的功能,也必須要按照它提供的操作流程來執行相關功能的完成,所以需要熟悉它提供的相關接口的使用方法和使用限制,開發手冊中提供了系統的處理流程以及具體的API描述,仔細閱讀該文檔能幫助我們更好地完成開發工作。
圖2 海思35xx 系統層次圖
海思媒體軟件處理平台概述
海思媒體處理平台的主要內部處理流程如圖3所示,主要分為 VI-視頻輸入,VPSS-視頻處理,VENC-視頻編碼,VDEC-視頻解碼,VO-視頻輸出,AVS-視頻拼接等模塊
圖 3 mpp 內部處理流程圖
從上圖可以看出,可以根據用戶需求完成多種方案實現,比如視頻輸出,視頻監控等方案。有的功能單個模塊就能完成,而更多的功能則需要依賴模塊之間“聯動”完成。各個模塊之間的關系,比如,第一條pipeline是:sensor -> VI -> VPSS -> VENC -> 壓縮碼流 或者 sensor -> VI -> VPSS -> VO -> 顯示屏,這應該是單目相機上常用的pipeline。第二條pipeline是:存儲介質 -> VDEC -> VPSS -> VENC ->壓縮碼流 或者 存儲介質 -> VDEC -> VPSS -> VO -> 顯示屏,這個應該是在智能盒子上做視頻文件相關應用常見的pipeline。至於第三條pipeline:sensors -> VI -> VPSS -> AVS ->VENC -> 壓縮碼流,這個是多目相機、拼接碼流常見的pipeline。最后一組則是音頻的單獨應用,音頻編解碼。
海思媒體處理芯片內部幾個重要的硬件模塊的主要功能描述如下:
VI:捕獲視頻圖像,可做剪切,去噪等處理,並輸出多路不同分辨率的圖像數據,主要是bayer圖像數據(可認為是對應芯片圖中的Image Subsystem)
VPSS: 接收其他模塊發送的圖像數據,可對圖像進行圖像增強、銳化等處理,並同源輸出多路不同分辨率的圖像數據
VENC:編碼模塊負責接收其他模塊處理輸出的數據,可疊加用戶通過Region模塊設置的OSD圖像,然后輸出不同協議編碼的碼流數據(可做視頻OSD疊加)
下面分別從系統控制,以及VI,VPSS,VENC這三個模塊進行介紹。
系統控制
主要是需要完成系統硬件的復位,基本的初始化,MPP系統業務模塊的初始化等
hisi芯片的內存管理機制
hisi35系列芯片將內存划分為OS內存和MMZ(Media Memory Zone)內存,而且用戶可以通過load腳本繼續划分MMZ內存以供某功能某塊單獨使用。
OS內存:是指由操作系統管理的內存,MMZ內存是指由MMZ驅動模塊進行管理供媒體業務單獨使用的內存,在驅動加載時可以指定該模塊管理內存的大小。
MMZ全稱Media Memory Zone:中文名“多媒體內存區域”,海思整套系統(MPP\NNIE\IVE等)都是基於其專有內存進行數據傳輸、存儲的。OS內存可以用free命令查看,而MMZ則使用cat /proc/media-mem可以查看到系統總共、已使用的、剩余的MMZ,包括每一塊已經使用的MMZ的使用情況。
圖 4 MMZ內存實例
圖4中的flags表示什么,不是很清楚,有知道的可以告知一聲(kvirt是否表示虛擬地址?)。
圖 5 kernel 內存分布
另外,kernel的內存分布中,有一塊vmalloc區域,大小申請了496M,對應的虛擬地址為:0xe0800000-0xff800000,從上面MMZ內存的虛擬地址來看,有很多塊內存的虛擬地址落在了vmalloc申請的地址段,所以猜測這塊內存應該是用來load內核ko文件的,而且映射的應該是MMZ的內存,另外發現有name為vb的內存也虛擬地址也在vmalloc,這是海思在load MMZ ko驅動的時候就分配好的VB內存么?
有關於MMZ內存的具體實現可以參考一下這篇MMZ內存驅動
VB:video buffer
VB在海思媒體處理中也是一個重要的概念,VB的本質上就是一個物理地址連續的MMZ內存塊,只不過在MPP層里提供了一系列初始化,申請,釋放操作的接口,所以VB其實也屬於MMZ內存。
一組大小相同,物理地址連續的緩存塊(VB)組成一個視頻緩存池(VB POOL)。這個視頻緩存池的作用就是給MPP提供大塊物理內存管理功能,負責內存的分配和回收。因為VB的使用者主要是海思的硬件模塊,比如vi/vpss/venc等等, 需要連續的物理地址, 有點類似早期的linux為硬件DMA分配內存也要求物理地址連續。
海思文檔提供了一張公共VB緩存池的數據流圖。公共緩沖池是在系統初始化中分配的,具體分配的接口就是HI_MPI_VB_SetConf()和HI_MPI_VB_Init()。我們可以通過這兩個接口按照所需VB數量和VB大小不同的緩沖池,比如下圖,A和B都是緩存池,緩存池內的每個緩存塊的大小都一致,而A1和B1的緩存塊大小一般不一樣。這里假設A緩存池里的緩存塊大小為100k,B中的緩存塊大小為200k,而海思模塊使用VB的原則是選擇滿足要求的最小的VB,就是當海思模塊要用一個90k的VB時,會優先從100k的那個vb pool中去申請,有就用,沒有就去200k那個vb pool中申請,再沒有就會報vb fail的錯誤。
公共緩存池中的VB使用者是VI/VPSS/VENC/VDA/VO,而且以VI為主要的使用者,文檔中也說所有的視頻輸入通道都可以從公共視頻緩存池中獲取視頻緩存塊用於保存采集的圖像。
圖 6 公共VB緩沖池數據流圖
除了通過HI_MPI_VB_Init建立的公共視頻緩存池,用戶也可以調用接口HI_MPI_VB_CreatePool創建一個視頻緩存VB池。然后配合某模塊通道的xxx_attachPool(VPSS,VENC,VDEC有該接口)綁定到某個通道上,那么就只有該通道可以使用,比如HI_MPI_VENC_AttachVbPool被VENC的0通道綁定之后,就只有VENC CHN 0可以使用該VB。
typedef enum hiVB_SOURCE_E{ VB_SOURCE_COMMON = 0, VB_SOURCE_MODULE = 1, VB_SOURCE_PRIVATE = 2, VB_SOURCE_USER = 3, VB_SOURCE_BUTT} VB_SOURCE_E;
其中,在編碼器中,編碼幀存(參考幀和重構幀)分配支持兩種方式:PrivateVB池和UserVB池方式
PrivateVB:創建編碼通道時有VENC創建PrivateVB池作為該通道的參考幀和重構幀buffer, 這種模式下不需要用戶進行相關操作,只需要修改hi35xx_h164e.ko模塊參數 enH264eVBSource的VB類型為:VB_SOURCE_PRIVATE,由內存完成幀存分配
使用privateVB的好處就是,各個通道之間是獨立的,互不影響,單獨銷毀某個通道上的圖像對其他通道無影響,使用靈活方便。
UserVB: 創建編碼通道的時候不創建編碼幀vb池,而是需要用戶調用HI_MPI_VB_CreatePool手動創建,再調用HI_MPI_VENC_AttachVbPool把某個編碼通道綁定到固定的vb池中。修改hi35xx_h164e.ko模塊參數 enH264eVBSource的VB類型為:VB_SOURCE_USER。
UserVB的好處就是手動把n個通道綁定到VB池中,這樣對於多個相同分辨率的編碼通道,使用UserVB方式可以減少內存小號。
ModuleVB池:創建解碼通道時不分配解碼幀的buffer,而是由用戶調用HI_MPI_VB_CreateVBPool接口創建專屬於解碼模塊的ModuleVB池,該VB池只允許VDEC獲取VB塊。
解碼模塊同樣有UserVB和PrivateVB。解碼模塊這三種解碼幀存類型的分配可以通過接口HI_MPI_VDEC_SetModParam的參數恩enVdecVBSource來設置.
MMZ內存使用
使用MMZ有2個地方需要注意:地址(虛擬地址vs物理地址)和緩存(可緩存vs不可緩存)
地址(虛擬地址vs物理地址)
海思內部模塊基本上都是直接操作物理地址,海思提供了虛擬地址和物理地址之間互相映射的API,為我們在用戶態下操作物理內存提供了方式。實際使用時還需要注意以下事項:
- 物理地址:實際拿到的海思地址,在海思中只有一些模塊能夠直接訪問物理地址(CPU不能訪問),一般用於硬件加速、不同進程間地址交換;
- 虛擬地址:在本程序的地址頁表上的地址,就如同OS MEM一樣使用即可,CPU可以直接訪問,也就是說在進程內可以直接讀寫該地址。如果要在不同進程間交換,需要考慮使用共享內存等機制。
緩存(可緩存vs不可緩存)
這里的“緩存”是指,MMZ的虛擬地址會被CPU的寄存器緩存。
- 可緩存:MMZ虛擬地址會被CPU的寄存器同步保存一份,以做緩存命中,因此可緩存的MMZ會極大提高程序的讀寫性能;但是一定記住在外部模塊需要讀寫該MMZ之前要調用flush接口做同步。調用HI_MPI_SYS_MmzAlloc_Cached申請可cache的MMZ虛擬地址
- 不可緩存:不會被CPU的寄存器保存,也就是每次CPU讀寫該MMZ時都必然是和內存做讀寫,可以想見性能必然不高;但是這樣的好處是編程人員不需要考慮一致性問題,不需要做flush。調用HI_MPI_SYS_MmzAlloc申請不可cache的MMZ虛擬地址
還有一點必須記住,程序必須及時調用HI_MPI_SYS_MmzFree
釋放掉不用的MMZ,海思系統並不會幫助回收程序申請的MMZ內存。
VI模塊
VI模塊划分了4個部分:DEV-->PIPE-->PHY_CHN|EXT_CHN
圖7 VI模塊結構
各個芯片的設備數量
芯片 | DEV | PIPE | PHY_CHN | EXT_CHN |
Hi3559AV100ES | 6 | 6 | 2 | 8 |
Hi3559AV100 | 8 | 8 | 1 | 8 |
Hi3519AV100 | 5 | 6 | 2 | 8 |
輸入設備DEV負責對時序進行解析。PIPE綁定在DEV后方,包含了ISP的相關處理功能,主要是對圖像數據進行流水線處理,輸出YUV圖像個通道。PIPE主要包含了PIPE_FE和PIPE_BE,PIPE_FE主要負責從DEV接收BAYER格式的圖像數據,PIPE_BE主要負責執行圖像處理ISP,執行完ISP后輸出YUV圖像。PHY_CHN物理通道負責將處理后的數據輸出到DDR,通道包含了剪裁,縮減等功能(不同型號不同)。
DEV和MIPI的綁定關系以及PIPE和DEV的綁定關系詳細描述可以參考開發手冊,開發手冊里有詳細規定,這里不過多展開描述。
這里強調一下,DEV設備和MIPI設備綁定后不可動態更改,Hi3559和3519的DEV和MIPI的綁定關系是固定的,基本是一一對應的關系。DEV和時序輸入接口(MIPI,SLVS,BT.1120等)的綁定有約束關系,該約束關系在文檔中有描述,具體要根據硬件實際管腳連接來確定使用了哪一個DEV。
PIPE可以和任意的DEV綁定,一個DEV可以綁定多個PIPE(用於WDR模式),線性模式下一個DEV綁定一個PIPE。每一個PIPE對應着一個或2個的PHY_CHN(物理通道),物理通道具有裁剪功能,且輸出圖像格式為YUV,基本可以認為PHY_CHN和PIPE是一體的。
可通過cat /proc/umap/vi查看vi的相關屬性配置
圖 8 DEV和Bind PIPE屬性
圖 9 物理通道屬性
圖 10 VI設備里的各個模塊的綁定關系
sensor的從模式
從模式sensor,我覺得是sensor的管腳連接到了SENSOR_HSx/SENSOR_VSx,x根據不同芯片有不同取值,3559A芯片x取值為0-3,從模式sensor需要使用vi的從模式模塊,且從模式模塊與vi的PIPE對應關系是固定的,要確定需要使用的PIPE(只有特定的PIPE才有數據),首先需要根據硬件圖確定sensor連接到哪個SENSOR_HSx/SENSOR_VSx,然后查閱文檔可以確定這個sensor對應的從模式模塊以及該從模式模塊對應的PIPEID,使用時創建並打開該PIPE,就可以從該PIPE中獲取到圖像數據。
VPSS模塊
VPSS-視頻處理子系統,可以完成一系列的視頻處理功能包括,FRC幀率控制,CROP剪裁,3DNR3D降噪,像素格式轉換,旋轉,馬賽克等。