第九章: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 值可以分别设的置。


猜你喜欢

转载自blog.csdn.net/tainjau/article/details/80304528