第九章:mmp功能模塊

1、簡介

    海思提供的媒體處理軟件平臺(Media Process Platform,簡稱 MPP)
                        

VDEC用來解碼的,比如磁盤裏面有一個
VDA對視頻內容簡單的偵測
VPSS處理
VO是用於直接顯示的。

2、什麼是視頻緩衝池

(1)視頻的本質是多幀圖片,圖片的本質是RGB或rawRGB數據,要佔用一段連續內存

(2)視頻的裁剪、縮放、修正處理等各種操作,本質上就是對內存中的數據進行運算

(3)視頻緩存池(VB, video buffer)就是一段很大,又被合理劃分和管理的內存,用來做視頻數據的暫存和運算場地

(4)公共視頻緩存池的公共2字,可以理解爲全局變量,也就是各個模塊都能訪問的一段內存

(5)看似視頻緩存塊在各個模塊之間流轉,實際上並沒有內存複製,而是指針在傳遞

(6)視頻緩存池的內存由MPP來維護,我們在系統啓動時就把整個SDRAM分成了2部分:系統部分(由linux kernel來維護管理)和mpp部分(由mpp系統來維護管理)

(7)緩存池需要幾個,每個中包含幾個緩存塊,每個緩存塊多大,都是可以由用戶程序設置好參數,然後調用MPP的相應API來向MPP申請分配的。

                                

       海思3518e裏面有多個緩衝池,一個緩衝池裏面又有很多緩衝塊,大小相同地址相連,緩衝池的數量由內存大小決定(應該是自行劃定的吧,還未求證)這些都是由mpp維護的。

       視頻處理流程大致如下,先從緩衝池取出一個緩衝塊,然後放入VI中,將一幀數據填充進bm,之後傳入vpss進行處理,然後將處理完是數據放入新的緩衝塊中,最後將剛剛使用過的Bmijk緩衝塊釋放回去。

3、相關的數據結構和API

(1)VB_CONF_S:用於參數設置的,設置緩衝池有幾個,緩衝塊的數量大小等。

typedef struct hiVB_CONF_S
{
    HI_U32 u32MaxPoolCnt;   //設置申請最多緩衝池的數量,範圍是0- 16/* max count of pools, (0,VB_MAX_POOLS]  */    
    struct hiVB_CPOOL_S
    {
        HI_U32 u32BlkSize;		//緩衝塊大小
        HI_U32 u32BlkCnt;		//緩衝塊數量
        HI_CHAR acMmzName[MAX_MMZ_NAME_LEN];	//緩衝池的名字,用於調試階段可以看到名字
    }astCommPool[VB_MAX_COMM_POOLS];//最大上限16個公共緩衝池
} VB_CONF_S;

(2)HI_MPI_VB_SetConf:API,用於將緩衝池信息設置到mpp系統中
(3)HI_MPI_VB_Init     :API,執行設置緩衝池的操作。

【舉例】

HI_S32 s32ret;
VB_CONF_S stVbConf;
memset(&stVbConf,0,sizeof(VB_CONF_S));
stVbConf.u32MaxPoolCnt = 128;	//設置緩衝池數量最大上限
stVbConf.astCommPool[0].u32BlkSize = 768*576*2;	//設置第一個緩衝塊大小
stVbConf.astCommPool[0].u32BlkCnt = 20;			//設置第一個緩衝塊數量
stVbConf.astCommPool[1].u32BlkSize = 384*288*2;	//設置第二個緩衝塊大小
stVbConf.astCommPool[1].u32BlkCnt = 40;			//設置第二個緩衝塊數量
s32ret = HI_MPI_VB_SetConf(&stVbConf);			//將緩衝池信息設置到mpp系統中
if (HI_SUCCESS != s32ret)	
{
printf("set vb err:0x%x\n", s32ret);
return s32ret;
}
s32ret = HI_MPI_VB_Init();						//初始化
if (HI_SUCCESS != s32ret)
{
printf("init vb err:0x%x\n", s32ret);
return s32ret;
} 

       SAMPLE_VENC_1080P_CLASSIC();函數主要工作流程。

       程序主要是爲了錄像,指揮攝像頭採集圖像,然後將圖像編碼最後輸出碼流。

       第一部分:初始化sys部分的變量,sys也就是mpp中的變量填充,列如VB結構體裏面的數據

       第二部分:初始化mpp系統

       第三部分:啓動VI部分(設備和通道),然後採集圖像(和攝像頭相關部分)

       第四部分:啓動VPSS,然後將vi處理完的數據傳給vpss(使用bind函數將vi和vpss綁定在一起)

       第五部分:啓動編碼,這部分由mpp內部完成,僅調用相關API即可。

       第六部分:僅僅只是將流數據保存成文件。

3.1、第一部分詳解

       首先清空VB_CONF_S結構體,爲了後續填充變量做準備。
       然後調用SAMPLE_COMM_VI_GetSizeBySensor(PIC_SIZE_E *penSize)這個函數,傳入enSize數組,在這個函數裏面可以看到
       SAMPLE_VI_MODE_E enMode = SENSOR_TYPE;,其中SENSOR_TYPE是在外部makefile中定義的,通過SENSOR_TYPE來確定enSize的內容,enSize是用於存放將來編碼之後傳輸出來的碼流。
        s32ChnNum是設置輸出多少個碼流。
       其中碼流輸出的圖像是一致的,但是分辨率大小是不一樣的,其中一路是主碼流,其他的則是從主碼流中裁剪縮放而來的。

       一個緩衝池對應一個碼流。

SAMPLE_COMM_SYS_CalcPicVbBlkSize(VIDEO_NORM_E enNorm, PIC_SIZE_E enPicSize, PIXEL_FORMAT_E enPixFmt, HI_U32 u32AlignWidth)
這個函數是用於計算出一個緩衝塊需要多大空間。
VIDEO_NORM_E enNorm:傳入視頻格式,PAL制和NTSC制 
PIC_SIZE_E enPicSize:圖像尺寸
PIXEL_FORMAT_E enPixFmt:像素格式
HI_U32 u32AlignWidth:需要對齊排布的大小
其中這個函數的塊大小=圖像大小(根據長寬高和像素格式求得)+頭信息。
u32VbSize = (CEILING_2_POWER(stSize.u32Width, u32AlignWidth) * \
            CEILING_2_POWER(stSize.u32Height,u32AlignWidth) * \
           ((PIXEL_FORMAT_YUV_SEMIPLANAR_422 == enPixFmt)?2:1.5));
#define CEILING_2_POWER(x,a)     ( ((x) + ((a) - 1) ) & ( ~((a) - 1) ) )//x往a上除,直到能被整除

第二部分

       SAMPLE_COMM_SYS_Init(&stVbConf);

第三部分詳解

       學習方法:繪製調用關係圖譜

       (1)簡單瀏覽VI部分的調用層次,發現很複雜

       (2)有些函數是sample寫的,有些是調用MPP的,數據結構也是2種都有

       SAMPLE_xxx就是sample內部自己實現的

       HI_MPI_xxx就是調用mmp

       (3)學習重點1:全局把控熟悉整個過程全景視圖。

       (4)學習重點2:掌握細節數據結構元素含義,和遇到的概念。

       (5)學習重點3:知道某些關鍵操作在哪裏定義,哪裏設置,將來需要改的時候能找到地方 。
main
	SAMPLE_VENC_1080P_CLASSIC
		SAMPLE_COMM_VI_GetSizeBySensor(step1)
		SAMPLE_COMM_SYS_CalcPicVbBlkSize	
			SAMPLE_COMM_SYS_GetPicSize
		SAMPLE_COMM_SYS_Init(step2)
			HI_MPI_SYS_Exit();	
			HI_MPI_VB_Exit();
			HI_MPI_VB_SetConf
			HI_MPI_VB_Init
			HI_MPI_SYS_SetConf
			HI_MPI_SYS_Init
		SAMPLE_COMM_VI_StartVi(step3)----------------------->
    stViConfig.enViMode   = SENSOR_TYPE;	//sensor的類型
    stViConfig.enRotate   = ROTATE_NONE;	//輸出圖像是否旋轉(0、90、180°等)
    stViConfig.enNorm     = VIDEO_ENCODING_MODE_AUTO;//圖像制式(PAL、NTSC)
    stViConfig.enViChnSet = VI_CHN_SET_NORMAL;		//圖像加工(鏡像、翻轉等)
    stViConfig.enWDRMode  = WDR_MODE_NONE;		//WDR寬動態
			IsSensorInput
			SAMPLE_COMM_VI_StartIspAndVi
				SAMPLE_COMM_VI_StartMIPI(1)//對sensor做必要的初始化
//mipi是sensor和主芯片hi3518e之間的一種接口
//常用的接口有MIPI、LVDS、DC
					SAMPLE_COMM_VI_SetMipiAttr
						fd = open("/dev/hi_mipi", O_RDWR);
						ioctl(fd, HI_MIPI_SET_DEV_ATTR, pstcomboDevAttr)
				SAMPLE_COMM_ISP_Init(2)//isp就是image signal process,圖像信號處理
                   //HI3518E內部的ISP硬件單元是隸屬於VI模塊的
					sensor_register_callback		//在sensor驅動中,在/component/isp/sensor
					HI_MPI_AE_Register		//註冊3A單元:自動曝光
					HI_MPI_AWB_Register		//註冊3A調試:自動白平衡
					HI_MPI_AF_Register		//註冊3A調試:自動對焦
					HI_MPI_ISP_MemInit		//分配內存單元
					HI_MPI_ISP_SetWDRMode	//寬動態
					HI_MPI_ISP_SetPubAttr		--------------------->
   根據sensor的類型進行設置,填充stPubAttr結構體。
   以AR0130爲例
    stPubAttr.enBayer               = BAYER_GRBG;	//參考sensor手冊得知,像素排列順序
    stPubAttr.f32FrameRate          = 30;		//幀率
    stPubAttr.stWndRect.s32X        = 0;		//圖像區域的起始點X
    stPubAttr.stWndRect.s32Y        = 0;		//圖像區域的起始點Y
    stPubAttr.stWndRect.u32Width    = 1280;	//圖像長
    stPubAttr.stWndRect.u32Height   = 720;	//圖像寬
					HI_MPI_ISP_Init	//初始化isp模塊
				SAMPLE_COMM_ISP_Run(3)//創建線程運行isp
					pthread_create(&gs_IspPid, &attr, (void* (*)(void*))Test_ISP_Run, NULL)
						Test_ISP_Run
							HI_MPI_ISP_Run
				SAMPLE_COMM_VI_StartDev(4)
					HI_MPI_VI_SetDevAttr		//在step3中設置的參數,一路傳到這才被寫入硬件單元
					HI_MPI_ISP_GetWDRMode	//在上一步isp中設置了SetWDRMode,這一步獲取設置信息
					HI_MPI_VI_SetWDRAttr
					HI_MPI_VI_EnableDev		//啓動硬件單元
				SAMPLE_COMM_VI_StartChn(5)	//設置主通道
					HI_MPI_VI_SetChnAttr		//
					HI_MPI_VI_SetRotate
					HI_MPI_VI_EnableChn					
		SAMPLE_COMM_SYS_GetPicSize(step4)//得到處理圖像的長和高
		SAMPLE_COMM_VPSS_StartGroup		//開啓Group
   HI_MPI_VPSS_CreateGrp	//先創建一個Group
   HI_MPI_VPSS_GetNRParam//獲取NR的參數(降噪相關的)
   HI_MPI_VPSS_SetNRParam//在寫入進去(如果要做降噪相關的處理就需要在這之前對參數進行修改)
   HI_MPI_VPSS_StartGrp	//最後再啓動
		SAMPLE_COMM_VI_BindVpss	//將Vpss創建出來的Group和Vi的channel綁定在一起。
   HI_MPI_SYS_Bind	//調用海思驅動。
		SAMPLE_COMM_VPSS_EnableChn------------------------->
 	    VpssChn = 0;		//通道號
	    stVpssChnMode.enChnMode      = VPSS_CHN_MODE_USER;	//設置通道模式爲用戶模式
	    stVpssChnMode.bDouble        = HI_FALSE;				//現場幀率模式傳輸(不瞭解)
	    stVpssChnMode.enPixelFormat  = PIXEL_FORMAT_YUV_SEMIPLANAR_420;
	    stVpssChnMode.u32Width       = stSize.u32Width;			//該通道輸出圖像的長
	    stVpssChnMode.u32Height      = stSize.u32Height;			//該通道輸出圖像的寬
	    stVpssChnMode.enCompressMode = COMPRESS_MODE_SEG;//內部壓縮圖像的模式
		SAMPLE_COMM_VENC_Start(step5)//
		SAMPLE_COMM_VENC_BindVpss//綁定Vpss和Venc的channel綁定在一起。
		SAMPLE_COMM_VENC_StartGetStream(step6)//
   SAMPLE_COMM_VENC_GetVencStreamProc
   	    HI_MPI_VENC_GetChnAttr
     SAMPLE_COMM_VENC_GetFilePostfix
     HI_MPI_VENC_GetFd
     HI_MPI_VENC_Query	//返回狀態信息
     HI_MPI_VENC_GetStream
     SAMPLE_COMM_VENC_SaveStream//保存流文件
SAMPLE_COMM_VENC_SaveH264
     HI_MPI_VENC_ReleaseStream	//
		SAMPLE_COMM_VENC_StopGetStream(step7)

4、vpss基礎知識

       全稱:Video Process Sub-System

       支持對一幅輸入圖像進行統一預處理,如去噪、去隔行等,然後再對各通道分別進行縮放、銳化等處理,最後輸出多種不同分辨率的圖像。

概念:

       GROUP:VPSS 對用戶提供組(GROUP)的概念,各 GROUP 分時複用 VPSS 硬件。每個 VPSS GROUP 包含多個通道,通道數目視方案實現有所不同。

       CHANNEL:VPSS 組的通道。通道分爲 2 種:物理通道和擴展通道。VPSS 硬件提供多個物理通道,每個通道具有縮放、裁剪等功能。擴展通道具備縮放功能,它通過綁定物理通道,將物理通道輸出作爲自己的輸入,把圖像縮放成用戶設置的目標分辨率輸出。擴展通道藉助物理通道的輸出來進行處理。

       FRC:幀率控制,分爲 2 種:group 幀率控制和 chn 幀率控制。例如可變幀率的錄製。

       Crop:裁剪,分爲 3 種:group 的裁剪和物理通道的裁剪以及擴展通道的裁剪。

       −  Group 的裁剪,VPSS 對輸入圖像進行裁剪。
       −  物理通道的裁剪,VPSS 對各個物理通道的輸出圖像進行裁剪。

       −  擴展通道的裁剪,VPSS 調用 VGS 對擴展通道的輸出圖像進行裁剪。

       DEI:De-interlace,去隔行。將交錯的隔行視頻源還原成逐行視頻源。

       NR:去噪。通過參數配置,把圖像中的高斯噪聲去除,使得圖像變得平滑,有助於降低編碼碼率。

       Scale:縮放,對圖像進行縮小放大。

       LDC:Lens Distortion Correction,鏡頭畸變校正,一些低端鏡頭容易產生圖像畸變,需要根據畸變程度對其圖像進行校正。

       Cover:視頻遮擋區域,對 VPSS 的輸出圖像填充純色塊。

      Overlay:視頻疊加區域,在 GROUP 上進行位圖的加載和背景色更新,支持 ARGB4444、ARGB1555、ARGB8888 三種格式的位圖。

       Border:邊框,VPSS 在輸出圖像上加邊框。

       備份節點:原始圖像的備份節點。每個 GROUP 都有一個備份節點,用於備份即將提交硬件處理的那幀原始圖像。VPSS 在以下情況會將緩存隊列隊頭節點的圖像放入備份節點:

       −  當隊頭節點的圖像要經過 VPSS 硬件處理時,VPSS 會將其放入備份節點,並替換掉原有圖像。

       −  當後端綁定的接收模塊要求 VPSS 將隊頭圖像放入備份節點時,VPSS 也會替換備份節點中的圖像,即使該圖像不經過硬件處理。

       低延時:在 VI—VPSS 的在線方案中,編碼器性能足夠的情況下,VPSS 支持按照,以行爲單位,邊採集邊發送的方式,將圖像發送給編碼模塊進行編碼,用來減少 VPSS處理完整幀圖像再發送給編碼模塊過程中,數據的延時時間。這樣的方式即爲低延時方案。

5、VI/VPSS 離/在線模式

       VI/VPSS 離線模式是指 VI 進行時序解析後將圖像數據寫出到 DDR,VPSS 從DDR 中載入 VI 採集的數據進行圖像處理,是傳統Hi3518/Hi3520D 等芯片的VI/VPSS 的協作模式。

       VI/VPSS 在線模式是指 VI 進行時序解析後直接在芯片內部將數據傳遞到 VPSS,中間無 DDR 寫出的過程(少了一次到兩次的內存複製)。在線模式可以省一定的帶寬和內存,降低端到端的延時。需要注意的是,在線模式時,因爲 VI 不寫出數據到 DDR,無法進行CoverEx、OverlayEx、Rotate、LDC 等操作,需要在 VPSS 各通道寫出後再進行Rotate/LDC 等處理,而且有些功能只在離線下能支持,比如 DIS。

                                

       通過調用HI_MPI_SYS_Bind函數可以將可與 VI 和 VO/VENC/IVE 等模塊進行綁定,其中前者爲 VPSS 的輸入源(VO),後者爲 VPSS 的接收者。每個 GROUP 僅可與一個輸入源綁定。GROUP 的物理通道有兩種工作模式:AUTO 和 USER,兩種模式間可動態切換。默認的工作模式爲 AUTO,此模式下各通道僅可與一個接收者綁定。USER 模式主要用於對同一通道圖像進行多路編碼的場景。

       注:Hi3516A/Hi3518EV200/Hi3519V100 僅支持 USER 工作模式。

       VENC 模塊,即視頻編碼模塊。本模塊支持多路實時編碼,且每路編碼獨立,編碼協議和編碼 profile(圖像不同的清晰度標準) 可以不同。本模塊支持視頻編碼同時,調度 Region 模塊對編碼圖像內容進行疊加(OSD)和遮擋。

                                    

       BP基本的,清晰度不怎麼樣,但編碼速度快。

       MP:主流的,性能平衡。

       HP:高清的,清晰度最好的。

                                    

       視頻編碼的流程:典型的編碼流程包括了輸入圖像的接收、圖像內容的遮擋和覆蓋、圖像的編碼、以及碼流的輸出等過程。

                                        

       碼率控制器:碼率控制器實現對編碼碼率進行控制。

       從信息學的角度分析,圖像的壓縮比越低,壓縮圖像的質量越高;圖像壓縮比例越高,壓縮圖像的質量越低。對於場景變化的真實場景,圖像質量穩定,編碼碼率會波動;編碼碼率穩定,圖像質量會波動(例如運動視頻,如果壓縮度過高,就會破壞視頻質量)。以 H.264 編碼爲例,通常圖像 Qp 越低,圖像的質量越好,碼率越高;圖像 Qp (h.264編碼中的一個概念)越高,圖像質量越差,碼率越低。

       碼率控制器分別提供了對 H.264\H.265\MJPEG 協議編碼通道 CBR、VBR、FIXQP 等三種碼率控制模式,對圖像質量和碼率進行調節。

       CBR(Constant Bit Rate)固定比特率。即在碼率統計時間內保證編碼碼率平穩。碼率穩定主要由兩個量來評估,這兩個量都可以由用戶在創建編碼通道時指定。

       VBR(Variable Bit Rate)可變比特率,即允許在碼率統計時間內編碼碼率波動,從而保證編碼圖像質量平穩。以 H.264 編碼爲例,VENC 模塊提供用戶可設置 MaxQp,MinQp,MaxBitrate 和 ChangePos。MaxQp,MinQp 用於控制圖像的質量範圍,MaxBitrate 用於鉗位碼率統計時間內的最大編碼碼率,ChangePos 用於控制開始調整Qp 的碼率基準線。

       Fix Qp 固定 Qp 值。在碼率統計時間內,編碼圖像所有宏塊 Qp 值相同,採用用戶設定的圖像 Qp 值,I 幀和 P 幀的 QP 值可以分別設的置。


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