概述
以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。
前言
本文将详细介绍博文第二季3:sample_venc.c的整体分析中提及的“初始化MPP系统”。
MPP系统的初始化包括以下步骤:
-
配置VB:HI_MPI_VB_SetConf函数
-
初始化VB:HI_MPI_VB_Init函数
-
配置系统:HI_MPI_SYS_SetConf函数
-
初始化系统:HI_MPI_SYS_Init函数
上述函数均位于SAMPLE_COMM_SYS_Init函数中,该个函数之前的代码,都是在填充VB有关的变量。上述函数都是以库的形式提供,没有具体的源代码代码。
一、分析参数的含义
函数SAMPLE_VENC_1080P_CLASSIC开头定义了一些变量,我们先了解其含义。
/******************************************************************************
* function : H.264@1080p@30fps+H.264@VGA@30fps
******************************************************************************/
HI_S32 SAMPLE_VENC_1080P_CLASSIC(HI_VOID)
{
PAYLOAD_TYPE_E enPayLoad[3]= {PT_H264, PT_H264,PT_H264};//图像传输格式
PIC_SIZE_E enSize[3] = {PIC_HD1080, PIC_VGA,PIC_QVGA};//图像分辨率
HI_U32 u32Profile = 0;//baseline,main,high
VB_CONF_S stVbConf;//与VB配置有关
SAMPLE_VI_CONFIG_S stViConfig = {0};//与VI配置有关
VPSS_GRP VpssGrp;
VPSS_CHN VpssChn;
VPSS_GRP_ATTR_S stVpssGrpAttr;//VPSS组的属性
VPSS_CHN_ATTR_S stVpssChnAttr;//vpss信道的属性
VPSS_CHN_MODE_S stVpssChnMode;//vpss信道工作模式的属性
VENC_CHN VencChn;
SAMPLE_RC_E enRcMode= SAMPLE_RC_CBR;//码率控制
HI_S32 s32ChnNum=0;
HI_S32 s32Ret = HI_SUCCESS;
HI_U32 u32BlkSize;
SIZE_S stSize;//具体的图像分辨率
char c;
1、PAYLOAD_TYPE_E 枚举类型
这个枚举类型表示图像的传输格式。
/* We just coyp this value of payload type from RTP/RTSP definition */
typedef enum
{
PT_PCMU = 0,
PT_1016 = 1,
/*……*/
/* add by hisilicon */
PT_AMR = 1001,
PT_MJPEG = 1002,
PT_AMRWB = 1003,
PT_BUTT
} PAYLOAD_TYPE_E;
2、PIC_SIZE_E 枚举类型
这个枚举类型表示图像的分辨率。
typedef enum hiPIC_SIZE_E
{
PIC_QCIF = 0,
PIC_CIF,
PIC_2CIF,
PIC_HD1,
PIC_D1,
PIC_960H,
PIC_QVGA, /* 320 * 240 *///………………………………………………QVGA
PIC_VGA, /* 640 * 480 *///………………………………………………VGA
PIC_XGA, /* 1024 * 768 */
PIC_SXGA, /* 1400 * 1050 */
PIC_UXGA, /* 1600 * 1200 */
PIC_QXGA, /* 2048 * 1536 */
PIC_WVGA, /* 854 * 480 */
PIC_WSXGA, /* 1680 * 1050 */
PIC_WUXGA, /* 1920 * 1200 */
PIC_WQXGA, /* 2560 * 1600 */
PIC_HD720, /* 1280 * 720 *///……………………………………………HD720
PIC_HD1080, /* 1920 * 1080 *///…………………………………………HD1080
PIC_2304x1296, /* 3M:2304 * 1296 */
PIC_2592x1520, /* 4M:2592 * 1520 */
PIC_5M, /* 2592 * 1944 */
PIC_UHD4K, /* 3840 * 2160 */
PIC_12M, /* 4000 * 3000 */
PIC_BUTT
} PIC_SIZE_E;
3、VB_CONF_S 结构体
这个结构体用于描述“视频缓冲池”的配置。具体见第二季2:视频缓存池的简介_天糊土的博客。
typedef struct hiVB_CONF_S
{
HI_U32 u32MaxPoolCnt; /* 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];
} VB_CONF_S;
4、 SAMPLE_VI_CONFIG_S 结构体
这个结构体用于描述VI模块的配置。
typedef struct sample_vi_config_s
{
SAMPLE_VI_MODE_E enViMode;//sensor的种类
VIDEO_NORM_E enNorm;//视频信号制式 /*DC: VIDEO_ENCODING_MODE_AUTO */
ROTATE_E enRotate;//图像旋转
SAMPLE_VI_CHN_SET_E enViChnSet; //表示flip或者mirror
WDR_MODE_E enWDRMode;//宽动态有关
}SAMPLE_VI_CONFIG_S;
(1)其中sample_vi_mode_e用来描述摄像头传感器的种类,有着不同的分辨率和帧率。
typedef enum sample_vi_mode_e
{
APTINA_AR0130_DC_720P_30FPS = 0,
APTINA_9M034_DC_720P_30FPS,
APTINA_AR0230_HISPI_1080P_30FPS,
SONY_IMX222_DC_1080P_30FPS,
SONY_IMX222_DC_720P_30FPS,
PANASONIC_MN34222_MIPI_1080P_30FPS,
OMNIVISION_OV9712_DC_720P_30FPS,
OMNIVISION_OV9732_DC_720P_30FPS,
OMNIVISION_OV9750_MIPI_720P_30FPS,
OMNIVISION_OV9752_MIPI_720P_30FPS,
OMNIVISION_OV2718_MIPI_1080P_25FPS,
SAMPLE_VI_MODE_1_D1,
SAMPLE_VI_MODE_BT1120_720P,
SAMPLE_VI_MODE_BT1120_1080P,
}SAMPLE_VI_MODE_E;
(2)其中VIDEO_NORM_E用来表示视频信号制式,比如PAL、NTSC等,具体介绍见博文PAL与NTSC制式的详解。简单来讲,像是每秒显示多少帧,每帧总的像素数量,每个像素的显示时间、显示顺序都是包含在制式所要求的格式里面的。
typedef enum hiVIDEO_NORM_E
{
VIDEO_ENCODING_MODE_PAL = 0,
VIDEO_ENCODING_MODE_NTSC,
VIDEO_ENCODING_MODE_AUTO,
VIDEO_ENCODING_MODE_BUTT
} VIDEO_NORM_E;
(3)其中ROTATE_E表示将图像旋转多少度。
typedef enum hiROTATE_E
{
ROTATE_NONE = 0,
ROTATE_90 = 1,
ROTATE_180 = 2,
ROTATE_270 = 3,
ROTATE_BUTT
} ROTATE_E;
(4)其中SAMPLE_VI_CHN_SET_E表示将图像沿着水平轴翻转(flip),或者沿着纵轴翻转(mirror)。比如参见博客第4季6:图像sensor的寄存器操作所列出的图像。
typedef enum sample_vi_chn_set_e
{
VI_CHN_SET_NORMAL = 0, /* mirror, flip close */
VI_CHN_SET_MIRROR, /* open MIRROR */
VI_CHN_SET_FLIP, /* open filp */
VI_CHN_SET_FLIP_MIRROR /* mirror, flip */
}SAMPLE_VI_CHN_SET_E;
(5)其中WDR_MODE_E用来描述宽动态有关的内容。具体介绍见宽动态 (WDR)介绍和理解。
typedef enum hiWDR_MODE_E
{
WDR_MODE_NONE = 0,
WDR_MODE_BUILT_IN,
WDR_MODE_2To1_LINE,
WDR_MODE_2To1_FRAME,
WDR_MODE_2To1_FRAME_FULL_RATE,
WDR_MODE_3To1_LINE,
WDR_MODE_3To1_FRAME,
WDR_MODE_3To1_FRAME_FULL_RATE,
WDR_MODE_4To1_LINE,
WDR_MODE_4To1_FRAME,
WDR_MODE_4To1_FRAME_FULL_RATE,
WDR_MODE_BUTT,
} WDR_MODE_E;
5、VPSS_GRP_ATTR_S 结构体
这个结构体用来描述VPSS组的属性。
/*Define attributes of vpss GROUP*/
typedef struct hiVPSS_GRP_ATTR_S
{
/*statistic attributes*/
HI_U32 u32MaxW; /*MAX width of the group*/
HI_U32 u32MaxH; /*MAX height of the group*/
PIXEL_FORMAT_E enPixFmt; /*Pixel format*/
HI_BOOL bIeEn; /*Image enhance enable*/
HI_BOOL bDciEn; /*Dynamic contrast Improve enable*/
HI_BOOL bNrEn; /*Noise reduce enable*/
HI_BOOL bHistEn; /*Hist enable*/
VPSS_DIE_MODE_E enDieMode; /*De-interlace enable*/
}VPSS_GRP_ATTR_S;
6、VPSS_CHN_ATTR_S 结构体
这个结构体用来描述VPSS信道的属性。
/*Define attributes of vpss channel*/
typedef struct hiVPSS_CHN_ATTR_S
{
HI_BOOL bSpEn; /*Sharpen enable*/
HI_BOOL bBorderEn; /*Frame enable*/
HI_BOOL bMirror; /*mirror enable*/
HI_BOOL bFlip; /*flip enable*/
HI_S32 s32SrcFrameRate; /* source frame rate */
HI_S32 s32DstFrameRate; /* dest frame rate */
BORDER_S stBorder;
}VPSS_CHN_ATTR_S;
7、VPSS_CHN_MODE_S 结构体
这个结构体用来描述VPSS信道工作模式的属性。
/*Define attributes of vpss channel's work mode*/
typedef struct hiVPSS_CHN_MODE_S
{
VPSS_CHN_MODE_E enChnMode; /*Vpss channel's work mode*/
HI_U32 u32Width; /*Width of target image*/
HI_U32 u32Height; /*Height of target image*/
HI_BOOL bDouble; /*Field-frame transfer,only valid for VPSS_PRE0_CHN*/
PIXEL_FORMAT_E enPixelFormat;/*Pixel format of target image*/
COMPRESS_MODE_E enCompressMode; /*Compression mode of the output*/
}VPSS_CHN_MODE_S;
8、SAMPLE_RC_E 枚举类型
这个枚举类型用来描述码率控制的类型。
typedef enum sample_rc_e
{
SAMPLE_RC_CBR = 0,//固定比特率
SAMPLE_RC_VBR,//可变比特率
SAMPLE_RC_FIXQP//???
}SAMPLE_RC_E;
9、SIZE_S 结构体
这个结构体用来描述图像的分辨率(长宽像素),这里是具体的分辨率信息,有别于PIC_SIZE_E 这种指代形式的。
typedef struct hiSIZE_S
{
HI_U32 u32Width;
HI_U32 u32Height;
} SIZE_S;
二、分析MPP系统的初始化
MPP系统的初始化包括以下两个步骤,其函数调用关系如下。
step1:
SAMPLE_COMM_VI_GetSizeBySensor//根据sensor类型获取图像分辨率(枚举类型)
SAMPLE_COMM_SYS_CalcPicVbBlkSize//计算VB中缓冲块的大小
SAMPLE_COMM_SYS_GetPicSize//计算图像的真实分辨率(根据上面的枚举类型返回w与h)
CEILING_2_POWER//宏函数
VB_PIC_HEADER_SIZE//宏函数,计算出图像头的大小
step2:
SAMPLE_COMM_SYS_Init//初始化MPP系统
HI_MPI_SYS_Exit//去除MPP的初始化
HI_MPI_VB_Exit//去除VB的初始化
HI_MPI_VB_SetConf//设置VB属性
HI_MPI_VB_Init//初始化VB
HI_MPI_SYS_SetConf//设置系统属性
HI_MPI_SYS_Init//初始化系统
1、step1的分析
step1的代码与分析如下,主要是填充stVbConf这个变量。该变量表示公共缓冲池,一帧图像大小小于缓冲池里的一个缓冲块的容积。
/******************************************
step 1: init sys variable
******************************************/
memset(&stVbConf,0,sizeof(VB_CONF_S));
//该函数通过sensor的类型来获取图像的分辨率。
SAMPLE_COMM_VI_GetSizeBySensor(&enSize[0]); //函数返回时enSize[0]= PIC_HD720
if (PIC_HD1080 == enSize[0])
{
enSize[1] = PIC_VGA;
s32ChnNum = 2;
}
else if (PIC_HD720 == enSize[0])//这个成立
{
enSize[1] = PIC_VGA;
enSize[2] = PIC_QVGA;
s32ChnNum = 3;//三路码流内容一样,但分辨率不一样
//三路码流对应的图像分辨率为HD720、VGA、QVGA
}
else
{
printf("not support this sensorn");
return HI_FAILURE;
}
#ifdef hi3518ev201
s32ChnNum = 1;
#endif
printf("s32ChnNum = %dn",s32ChnNum);
stVbConf.u32MaxPoolCnt = 128;//定义缓冲池的最大数目是128个
//每个码流对应着一个公共缓冲池,每个缓冲池中有很多块。
//下面代码在计算,三个码流所对应的缓冲池中的块的大小。
/*video buffer*/
if(s32ChnNum >= 1)
{
u32BlkSize = SAMPLE_COMM_SYS_CalcPicVbBlkSize(gs_enNorm,
enSize[0], SAMPLE_PIXEL_FORMAT, SAMPLE_SYS_ALIGN_WIDTH);
stVbConf.astCommPool[0].u32BlkSize = u32BlkSize;
stVbConf.astCommPool[0].u32BlkCnt = g_u32BlkCnt;//值为4,即每个缓冲池有4个缓冲块
}
if(s32ChnNum >= 2)
{
u32BlkSize = SAMPLE_COMM_SYS_CalcPicVbBlkSize(gs_enNorm,
enSize[1], SAMPLE_PIXEL_FORMAT, SAMPLE_SYS_ALIGN_WIDTH);
stVbConf.astCommPool[1].u32BlkSize = u32BlkSize;
stVbConf.astCommPool[1].u32BlkCnt =g_u32BlkCnt;
}
if(s32ChnNum >= 3)
{
u32BlkSize = SAMPLE_COMM_SYS_CalcPicVbBlkSize(gs_enNorm,
enSize[2], SAMPLE_PIXEL_FORMAT, SAMPLE_SYS_ALIGN_WIDTH);
stVbConf.astCommPool[2].u32BlkSize = u32BlkSize;
stVbConf.astCommPool[2].u32BlkCnt = g_u32BlkCnt;
}
(1)SAMPLE_COMM_VI_GetSizeBySensor函数如下,其参数是输出型参数,通过判断传感器类型从而获取图像分辨率(只是一个枚举变量,对应着某个具体的分辨率),
/******************************************************************************
* funciton : Get enSize by diffrent sensor
******************************************************************************/
HI_S32 SAMPLE_COMM_VI_GetSizeBySensor(PIC_SIZE_E *penSize)
{
HI_S32 s32Ret = HI_SUCCESS;
SAMPLE_VI_MODE_E enMode = SENSOR_TYPE;//sensor的类型定义在Makefile.param文件中
if (!penSize)
{
return HI_FAILURE;
}
switch (enMode)
{
case APTINA_AR0130_DC_720P_30FPS:
case APTINA_9M034_DC_720P_30FPS:
case SONY_IMX222_DC_720P_30FPS:
case OMNIVISION_OV9712_DC_720P_30FPS:
case OMNIVISION_OV9732_DC_720P_30FPS:
case OMNIVISION_OV9750_MIPI_720P_30FPS:
case OMNIVISION_OV9752_MIPI_720P_30FPS:
*penSize = PIC_HD720;//上述sensor类型的分辨率都是这个
break;
case APTINA_AR0230_HISPI_1080P_30FPS:
case SONY_IMX222_DC_1080P_30FPS:
case PANASONIC_MN34222_MIPI_1080P_30FPS:
case OMNIVISION_OV2718_MIPI_1080P_25FPS:
*penSize = PIC_HD1080;
break;
default:
printf("not support this sensorn");
break;
}
(2)SAMPLE_COMM_SYS_CalcPicVbBlkSize函数如下,它计算缓冲池中每个块的大小。其中参数1是图像制式(上层函数传过来的是NTSC),参数2是图像分辨率(枚举变量),参数3是像素格式(上层函数传过来的是SAMPLE_PIXEL_FORMAT,即YUV_SEMIPLANAR_420),参数4是对齐宽度(上层函数传过来的是SAMPLE_SYS_ALIGN_WIDTH,即64)。
/******************************************************************************
* function : calculate VB Block size of picture.
******************************************************************************/
HI_U32 SAMPLE_COMM_SYS_CalcPicVbBlkSize(VIDEO_NORM_E enNorm, PIC_SIZE_E enPicSize, PIXEL_FORMAT_E enPixFmt, HI_U32 u32AlignWidth)
{
HI_S32 s32Ret = HI_FAILURE;
SIZE_S stSize;
HI_U32 u32VbSize;
HI_U32 u32HeaderSize;
s32Ret = SAMPLE_COMM_SYS_GetPicSize(enNorm, enPicSize, &stSize);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("get picture size[%d] failed!n", enPicSize);
return HI_FAILURE;
}
if (PIXEL_FORMAT_YUV_SEMIPLANAR_422 != enPixFmt && PIXEL_FORMAT_YUV_SEMIPLANAR_420 != enPixFmt)
{
SAMPLE_PRT("pixel format[%d] input failed!n", enPixFmt);
return HI_FAILURE;
}
if (16!=u32AlignWidth && 32!=u32AlignWidth && 64!=u32AlignWidth)
{
SAMPLE_PRT("system align width[%d] input failed!n",
u32AlignWidth);
return HI_FAILURE;
}
//SAMPLE_PRT("w:%d, u32AlignWidth:%dn", CEILING_2_POWER(stSize.u32Width,u32AlignWidth), u32AlignWidth);
u32VbSize = (CEILING_2_POWER(stSize.u32Width, u32AlignWidth) *
CEILING_2_POWER(stSize.u32Height,u32AlignWidth) *
((PIXEL_FORMAT_YUV_SEMIPLANAR_422 == enPixFmt)?2:1.5));
VB_PIC_HEADER_SIZE(stSize.u32Width, stSize.u32Height, enPixFmt, u32HeaderSize);
u32VbSize += u32HeaderSize;
return u32VbSize;
}
1)SAMPLE_COMM_SYS_GetPicSize函数代码如下,参数1是图像制式,参数2是图像分辨率(枚举变量),而参数3是输出型参数,它表示图像的真实分辨率,即一帧图像的大小(w*h)。
/******************************************************************************
* function : get picture size(w*h), according Norm and enPicSize
******************************************************************************/
HI_S32 SAMPLE_COMM_SYS_GetPicSize(VIDEO_NORM_E enNorm, PIC_SIZE_E enPicSize, SIZE_S *pstSize)
{
switch (enPicSize)
{
//省略部分代码
case PIC_2CIF:
pstSize->u32Width = 360;
pstSize->u32Height = (VIDEO_ENCODING_MODE_PAL==enNorm)?576:480;
break;
case PIC_QVGA: /* 320 * 240 */
pstSize->u32Width = 320;
pstSize->u32Height = 240;
break;
case PIC_VGA: /* 640 * 480 */
pstSize->u32Width = 640;
pstSize->u32Height = 480;
break;
//省略部分代码
case PIC_HD720: /* 1280 * 720 */
pstSize->u32Width = 1280;
pstSize->u32Height = 720;
break;
case PIC_HD1080: /* 1920 * 1080 */
pstSize->u32Width = 1920;
pstSize->u32Height = 1080;
break;
case PIC_5M: /* 2592 * 1944 */
pstSize->u32Width = 2592;
pstSize->u32Height = 1944;
break;
default:
return HI_FAILURE;
}
return HI_SUCCESS;
}
2)CEILING_2_POWER这个宏的定义如下,它计算出不小于x的、且是a整数倍的最小值。
#define CEILING_2_POWER(x,a) ( ((x) + ((a) - 1) ) & ( ~((a) - 1) ) )
参考博客:CEILING_2_POWER、对齐操作函数、视频帧内存size计算。
另外,(PIXEL_FORMAT_YUV_SEMIPLANAR_422 == enPixFmt)?2:1.5),是什么意思呢?
我们知道YUV422,对于2*2的4个像素点,有4个Y、2个U、2个V,一共8个字节,那么每个像素占用2个字节。而对于YUV420,对于2*2的4个像素点,有4个Y,1个U,1个V,一共6个字节,那么每个像素占1.5个字节。上面的三目运算符就是这个意思。
这里之所以只有YUV422和YUV420,是因为海思方案里只允许使用这两种色彩空间。rawRGB转化为RGB后,应该还是要转为YUV422或者420的(这里使用420)。
3)VB_PIC_HEADER_SIZE这个宏计算出图像头的大小。根据代码,一帧图像对应着缓冲池里的一个缓冲块,但缓冲块的容量肯定比一帧图像要大,因为之前的CEILING_2_POWER计算方式得到的就比一帧图像要大,而且这里还加上一个图像头。
2、step2的分析
step2的代码如下,主要是将step1中填充的stVbConf变量作为参数,调用SAMPLE_COMM_SYS_Init函数来初始化mpp系统。
/******************************************
step 2: mpp system init.
******************************************/
s32Ret = SAMPLE_COMM_SYS_Init(&stVbConf);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("system init failed with %d!n", s32Ret);
goto END_VENC_1080P_CLASSIC_0;
}
其中的SAMPLE_COMM_SYS_Init函数的调用图谱如下。注意到其所调用的函数都是以HI开头的,这些函数我们看不到具体的源码,不过要明白它们的用法与含义。
SAMPLE_COMM_SYS_Init
HI_MPI_VB_SetConf //配置VB
HI_MPI_VB_Init //初始化VB
HI_MPI_SYS_SetConf //配置系统
HI_MPI_SYS_Init //初始化系统
/******************************************************************************
* function : vb init & MPI system init
******************************************************************************/
HI_S32 SAMPLE_COMM_SYS_Init(VB_CONF_S *pstVbConf)
{
MPP_SYS_CONF_S stSysConf = {0};
HI_S32 s32Ret = HI_FAILURE;
HI_MPI_SYS_Exit();
HI_MPI_VB_Exit();
if (NULL == pstVbConf)
{
SAMPLE_PRT("input parameter is null, it is invaild!n");
return HI_FAILURE;
}
s32Ret = HI_MPI_VB_SetConf(pstVbConf);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("HI_MPI_VB_SetConf failed!n");
return HI_FAILURE;
}
s32Ret = HI_MPI_VB_Init();
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("HI_MPI_VB_Init failed!n");
return HI_FAILURE;
}
stSysConf.u32AlignWidth = SAMPLE_SYS_ALIGN_WIDTH;
s32Ret = HI_MPI_SYS_SetConf(&stSysConf);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("HI_MPI_SYS_SetConf failedn");
return HI_FAILURE;
}
s32Ret = HI_MPI_SYS_Init();
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("HI_MPI_SYS_Init failed!n");
return HI_FAILURE;
}
return HI_SUCCESS;
}
最后
以上就是虚心小霸王为你收集整理的第二季4:初始化MPP系统(step1&2)前言一、分析参数的含义二、分析MPP系统的初始化的全部内容,希望文章能够帮你解决第二季4:初始化MPP系统(step1&2)前言一、分析参数的含义二、分析MPP系统的初始化所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复