HI3518E 中Sample Venc分析
一、系统参数初始化 根据通道数和sensor型号,定义缓冲池单幅图片的大小和整个缓冲池的大小 二、初始化mmp系统 三、打开vi捕捉设备和通道 四、打开vpss后绑定vi和vpss 设置vpssGrp属性后创建vpssGrp 启动vpssGrp 设置vichn和vpssGrp后进行绑定 五、开始编码流 打开编码通道 开始编码图片 绑定vpssGrp和vencchn 六、编码流处理 七、退出程序
- VI模块包含:
- sensor对接部分,常用sensor接口MIPI、LVDS、DC;
- ISP;
- VI dev(硬件单元采集图像)和channel(通道)
main函数
- 从main函数开始参数选择函数开始VI VPSS等待模块的操作。 主要是根据argv[]确定具体视频处理的具体码率、通道数等,见代码。
sample_venc.c文件函数
SAMPLE_VENC_720P_CLASSIC(HI_VOID)
- 一般选择进入 SAMPLE_VENC_1080P_CLASSIC
- step0:定义了视频编解码过程中使用的一些变量 setp1:init sys variable video buffer(系统变量的初始化 MPP定义系统缓存池) step2:mpp system init(MPP系统初始化) step3:start vi dev & chn to capture(开启VI,并捕获视频通道数据) step4:start vpss and vi bind vpss(开启VPSS,并绑定视频通道等)。 step5:start stream venc(开启venc流视频) step6:stream venc process – get stream, then save it to file (开启venc处理、获取视频流并保存在文件中) 然后getchar等待程序结束
/****************************************************************************** function : H.264@720p@30fps H.264@VGA@30fps H.264@QVGA@30fps *******************************************************************************/ step定义了一堆变量 #还有一些等着补充
HI_S32 SAMPLE_VENC_720P_CLASSIC(HI_VOID) {
PAYLOAD_TYPE_E enPayLoad[3]= {
PT_H264, PT_H264, PT_H264}; #存储三路视频的编码格式,这里只是默认填充,后面根据参数填充 PIC_SIZE_E enSize[3] = {
PIC_HD720, PIC_VGA, PIC_QVGA}; #存储视频大小,默认填充,具体大小后填充 VB_CONF_S stVbConf; #视频缓冲区管理块 SAMPLE_VI_CONFIG_S stViConfig; #VI结构体的模块配置 VPSS_GRP VpssGrp; VPSS_CHN VpssChn; VPSS_GRP_ATTR_S stVpssGrpAttr; VPSS_CHN_ATTR_S stVpssChnAttr; VPSS_CHN_MODE_S stVpssChnMode; VPSS_EXT_CHN_ATTR_S stVpssExtChnAttr; VENC_GRP VencGrp; VENC_CHN VencChn; SAMPLE_RC_E enRcMode= SAMPLE_RC_CBR; HI_S32 s32ChnNum = 3; HI_S32 s32Ret = HI_SUCCESS; HI_U32 u32BlkSize; SIZE_S stSize;
/****************************************** step 1: init sys variable (系统变量的初始化 MPP定义系统缓存池) ******************************************/
memset(&stVbConf,0,sizeof(VB_CONF_S)); #清空stVbConf视频缓存池控制块数据 switch(SENSOR_TYPE) //sensor型号
{
case SONY_IMX122_DC_1080P_30FPS:
case APTINA_MT9P006_DC_1080P_30FPS:
enSize[0] = PIC_HD1080;
break;
default:
break;
}
stVbConf.u32MaxPoolCnt = 128; //定义缓冲池最大个数
/*video buffer*/
/*************************video buffer************************/
// #根据enSize[ ]来选择填充stVbConf元素
u32BlkSize = SAMPLE_COMM_SYS_CalcPicVbBlkSize(gs_enNorm,\
enSize[0], SAMPLE_PIXEL_FORMAT, SAMPLE_SYS_ALIGN_WIDTH); //根据画面像素PIC_HD720和像素格式YUV420,加上头文件,统计一幅画面占的空间大小
stVbConf.astCommPool[0].u32BlkSize = u32BlkSize; //将一幅的大小填入缓冲池设置大小
stVbConf.astCommPool[0].u32BlkCnt = 10; //设置缓冲页的个数
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 = 6;
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 = 6;
/* hist buf*/
stVbConf.astCommPool[3].u32BlkSize = (196*4);
stVbConf.astCommPool[3].u32BlkCnt = 6;
/****************************************** step 2: mpp system init. (MPP系统初始化) ******************************************/ 将 stVbConf 传入 SAMPLE_COMM_SYS_Init ,根据 stVbConf 具体实际初始化缓存池
s32Ret = SAMPLE_COMM_SYS_Init(&stVbConf);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("system init failed with %d!\n", s32Ret);
goto END_VENC_720P_CLASSIC_0;
}
其中 SAMPLE_COMM_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(); #EXIT主要防止系统之前已经初始化过了....
HI_MPI_VB_Exit();
s32Ret = HI_MPI_VB_SetConf(pstVbConf); #下面这一系列函数都是海思以KO的形式提供的模块库
s32Ret = HI_MPI_VB_Init();
stSysConf.u32AlignWidth = SAMPLE_SYS_ALIGN_WIDTH;
s32Ret = HI_MPI_SYS_SetConf(&stSysConf);
s32Ret = HI_MPI_SYS_Init();
return HI_SUCCESS;
}
/****************************************** step 3: start vi dev & chn to capture (开启VI,并捕获视频通道数据) ******************************************/ 填充 stViConfig 结构体,将 stViConfig 传入 SAMPLE_COMM_VI_StartVi 开启VI模块
stViConfig.enViMode = SENSOR_TYPE; //#sensor模块的类型 stViConfig.enRotate = ROTATE_NONE; //#图像旋转是否 stViConfig.enNorm = VIDEO_ENCODING_MODE_AUTO; //视频自动编解码 stViConfig.enViChnSet = VI_CHN_SET_NORMAL; //镜像和轴转动 #VI通道自动设置 s32Ret = SAMPLE_COMM_VI_StartVi(&stViConfig); // #根据以上具体设置初始化
传感器模块 if (HI_SUCCESS != s32Ret) { SAMPLE_PRT("start vi failed!\n"); goto END_VENC_720P_CLASSIC_1; }
SAMPLE_COMM_VI_StartVi(&stViConfig)函数展开
HI_S32 SAMPLE_COMM_VI_StartVi(SAMPLE_VI_CONFIG_S* pstViConfig)
{
HI_S32 s32Ret = HI_SUCCESS;
SAMPLE_VI_MODE_E enViMode;
VIDEO_NORM_E enNorm;
if(!pstViConfig)
{
SAMPLE_PRT("%s: null ptr\n", __FUNCTION__);
return HI_FAILURE;
}
enViMode = pstViConfig->enViMode;
enNorm = pstViConfig->enNorm;
if(!IsSensorInput(enViMode))
{
s32Ret = SAMPLE_COMM_VI_StartBT656(enViMode, enNorm);
}
else
{
s32Ret = SAMPLE_COMM_VI_StartIsp(pstViConfig);
}
return s32Ret;
}
SAMPLE_COMM_VI_StartIsp(pstViConfig)函数展开
HI_S32 SAMPLE_COMM_VI_StartIsp(SAMPLE_VI_CONFIG_S* pstViConfig)
//此处省略参数定义
//此处省略参数幅值
/****************************************** step 1: configure sensor. note: you can jump over this step, if you do not use Hi3518 interal isp. ******************************************/
s32Ret = SAMPLE_COMM_ISP_SensorInit();
//此处省略if条件判断
/****************************************** step 2: configure & run isp thread note: you can jump over this step, if you do not use Hi3518 interal isp. ******************************************/
s32Ret = SAMPLE_COMM_ISP_Run();
//此处省略if条件判断
/****************************************************** step 3 : config & start vicap dev ******************************************************/
//此处省略if条件判断
/****************************************************** * Step 4: config & start vicap chn (max 1) ******************************************************/
//此处省略for循环
s32Ret = SAMPLE_COMM_VI_StartChn(ViChn, &stCapRect, &stTargetSize, pstViConfig);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_COMM_ISP_Stop();
return HI_FAILURE;
}
}
return s32Ret;
/****************************************** step 4: start vpss and vi bind vpss (开启VPSS,并绑定视频通道等) ******************************************/
s32Ret = SAMPLE_COMM_SYS_GetPicSize(gs_enNorm, enSize[0], &stSize);//#根据 gs_enNorm 、enSize[0] 的值来填充 stSize 结构体
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("SAMPLE_COMM_SYS_GetPicSize failed!\n");
goto END_VENC_720P_CLASSIC_1;
}
//#填充 stVpssGrpAttr 结构体
VpssGrp = 0;
stVpssGrpAttr.u32MaxW = stSize.u32Width; //设置vpssgrpattr属性
stVpssGrpAttr.u32MaxH = stSize.u32Height;
stVpssGrpAttr.bDrEn = HI_FALSE;
stVpssGrpAttr.bDbEn = HI_FALSE;
stVpssGrpAttr.bIeEn = HI_TRUE;
stVpssGrpAttr.bNrEn = HI_TRUE;
stVpssGrpAttr.bHistEn = HI_TRUE;
stVpssGrpAttr.enDieMode = VPSS_DIE_MODE_AUTO;
stVpssGrpAttr.enPixFmt = SAMPLE_PIXEL_FORMAT;
s32Ret = SAMPLE_COMM_VPSS_StartGroup(VpssGrp, &stVpssGrpAttr); //#开启VPSS GRP
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("Start Vpss failed!\n");
goto END_VENC_720P_CLASSIC_2;
}
SAMPLE_COMM_VPSS_StartGroup(VpssGrp, &stVpssGrpAttr)函数展开
HI_MPI_VPSS_CreateGrp(VpssGrp, pstVpssGrpAttr);//创建vpssgroup HI_MPI_VPSS_GetNRParam(VpssGrp, &unNrParam);//获取NRParam参数 HI_MPI_VPSS_SetNRParam(VpssGrp, &unNrParam);//设置NRaram参数 HI_MPI_VPSS_StartGrp(VpssGrp);//启动vpssgrp
s32Ret = SAMPLE_COMM_VI_BindVpss(stViConfig.enViMode); //绑定VI和vpss
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("Vi bind Vpss failed!\n");
goto END_VENC_720P_CLASSIC_3;
}
SAMPLE_COMM_VI_BindVpss(stViConfig.enViMode)函数展开
s32Ret = SAMPLE_COMM_VI_Mode2Param(enViMode, &stViParam);//设置dev和chn的数量和间隔 s32Ret = HI_MPI_SYS_Bind(&stSrcChn, &stDestChn);//将设置好的src和des进行绑定
VpssChn = 0;
memset(&stVpssChnAttr, 0, sizeof(stVpssChnAttr));
stVpssChnAttr.bFrameEn = HI_FALSE;
stVpssChnAttr.bSpEn = HI_TRUE;
s32Ret = SAMPLE_COMM_VPSS_EnableChn(VpssGrp, VpssChn, &stVpssChnAttr, HI_NULL, HI_NULL);//分别填充好vpsschnmod和vpsschnattr后启动vpsschn
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("Enable vpss chn failed!\n");
goto END_VENC_720P_CLASSIC_4;
}
SAMPLE_COMM_VPSS_EnableChn();函数展开
s32Ret = HI_MPI_VPSS_SetChnAttr(VpssGrp, VpssChn, pstVpssChnAttr);//将填充的chnattr进行设置 s32Ret = HI_MPI_VPSS_SetChnMode(VpssGrp, VpssChn, pstVpssChnMode);//将填充的chnmod进行设置 s32Ret = HI_MPI_VPSS_EnableChn(VpssGrp, VpssChn);//设置完成启动vpsschn
//下面两个跟第一个在同一个group下,只需要填充spsschnmod和vpsschnattr后启动vpsschn即可
VpssChn = 1;
stVpssChnMode.enChnMode = VPSS_CHN_MODE_USER; //#填充VPSS通道模式
stVpssChnMode.bDouble = HI_FALSE;
stVpssChnMode.enPixelFormat = SAMPLE_PIXEL_FORMAT;
stVpssChnMode.u32Width = 640;
stVpssChnMode.u32Height = 480;
s32Ret = SAMPLE_COMM_VPSS_EnableChn(VpssGrp, VpssChn, &stVpssChnAttr, &stVpssChnMode, HI_NULL);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("Enable vpss chn failed!\n");
goto END_VENC_720P_CLASSIC_4;
}
VpssChn = 3;
stVpssExtChnAttr.s32BindChn = 1;
stVpssExtChnAttr.s32SrcFrameRate = 30;
stVpssExtChnAttr.s32DstFrameRate = 30;
stVpssExtChnAttr.enPixelFormat = SAMPLE_PIXEL_FORMAT;
stVpssExtChnAttr.u32Width = 320;
stVpssExtChnAttr.u32Height = 240;
s32Ret = SAMPLE_COMM_VPSS_EnableChn(VpssGrp, VpssChn, HI_NULL, HI_NULL, &stVpssExtChnAttr);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("Enable vpss chn failed!\n");
goto END_VENC_720P_CLASSIC_4;
}
/****************************************** step 5: start stream venc (开启venc流视频) ******************************************/
/*** HD720P **/
VpssGrp = 0;
VpssChn = 0;
VencGrp = 0;
VencChn = 0;
s32Ret = SAMPLE_COMM_VENC_Start(VencGrp, VencChn, enPayLoad[0],\
gs_enNorm, enSize[0], enRcMode); //#开启venc视频流
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("Start Venc failed!\n");
goto END_VENC_720P_CLASSIC_5;
}
s32Ret = SAMPLE_COMM_VENC_BindVpss(VencGrp, VpssGrp, VpssChn);//绑定vpsschn和vencchn
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("Start Venc failed!\n");
goto END_VENC_720P_CLASSIC_5;
}
/*** vga **/
//功能代码省略
/*** vga **/
//功能代码省略
/****************************************** step 6: stream venc process – get stream, then save it to file. (开启venc处理,获取视频流,并保存到文件中) ******************************************/
s32Ret = SAMPLE_COMM_VENC_StartGetStream(s32ChnNum);//#获取venc视频流,函数源码其实是开启了一个线程来获取视频并保存视频流
//省略功能代码
/****************************************** step 7: exit process ******************************************/
SAMPLE_COMM_VENC_StopGetStream(); //#键盘按下两次退出程序后释放相关资源,包括关闭线程等操作,然后继续退出程序
//省略功能代码
VI部分
频输入( VI)模块实现的功能:通过 ITU-R BT656/601/1120 接口或 Digital Camera接口、 MIPI Rx(含 MIPI 接口、 LVDS 接口和 HISPI 接口)接收视频数据。当工作在离线模式时,将接收到的数据存入到指定的内存区域;当工作在在线模式时, VI 会将数据直接送给 VPSS。在此过程中, VI 可以对接收到的原始视频图像数据进行裁剪( Crop)等处理,并实现一路原始视频图像输入,输出一路视频图像功能。
- 主要包括1.与sensor接口对应的部分、2.ISP部分、3.VI dev和channel 部分
/****************************************** step 3: start vi dev & chn to capture ******************************************/
stViConfig.enViMode = SENSOR_TYPE;
stViConfig.enRotate = ROTATE_NONE;
stViConfig.enNorm = VIDEO_ENCODING_MODE_AUTO;
stViConfig.enViChnSet = VI_CHN_SET_NORMAL;
stViConfig.enWDRMode = WDR_MODE_NONE;
s32Ret = SAMPLE_COMM_VI_StartVi(&stViConfig);
SAMPLE_COMM_VI_StartVi 函数中由逻辑可得 走的是s32Ret = SAMPLE_COMM_VI_StartIspAndVi(pstViConfig);
HI_S32 SAMPLE_COMM_VI_StartVi(SAMPLE_VI_CONFIG_S* pstViConfig)
{
HI_S32 s32Ret = HI_SUCCESS;
SAMPLE_VI_MODE_E enViMode;
if(!pstViConfig) {
SAMPLE_PRT("%s: null ptr\n", __FUNCTION__);
return HI_FAILURE;
}
enViMode = pstViConfig->enViMode;
if(!IsSensorInput(enViMode)) {
s32Ret = SAMPLE_COMM_VI_StartBT656(pstViConfig);
}
else{
s32Ret = SAMPLE_COMM_VI_StartIspAndVi(pstViConfig);
}
return s32Ret;
}
SAMPLE_COMM_VI_StartIspAndVi函数中封装了很多细节,Hi3518_SDK_V1.0.8.1没有该函数
HI_S32 SAMPLE_COMM_VI_StartIspAndVi(SAMPLE_VI_CONFIG_S* pstViConfig)
{
HI_S32 i, s32Ret = HI_SUCCESS;
VI_DEV ViDev;
VI_CHN ViChn;
HI_U32 u32DevNum = 1;
HI_U32 u32ChnNum = 1;
SIZE_S stTargetSize;
RECT_S stCapRect;
SAMPLE_VI_MODE_E enViMode;
#变量定义、参数检查
if(!pstViConfig)
{
SAMPLE_PRT("%s: null ptr\n", __FUNCTION__);
return HI_FAILURE;
}
enViMode = pstViConfig->enViMode;
/****************************************** step 1: mipi configure mipi设置与sensor接口相关的部分 ******************************************/
s32Ret = SAMPLE_COMM_VI_StartMIPI(pstViConfig); # init mipi
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("%s: MIPI init failed!\n", __FUNCTION__);
return HI_FAILURE;
}
/****************************************** step 2: configure sensor and ISP (include WDR mode).跳过 note: you can jump over this step, if you do not use Hi3516A interal isp. ******************************************/
s32Ret = SAMPLE_COMM_ISP_Init(pstViConfig->enWDRMode); #其中包括了很多细节如3A初始化,ISP具体初始化等
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("%s: Sensor init failed!\n", __FUNCTION__);
return HI_FAILURE;
}
/****************************************** step 3: run isp thread 跳过 note: you can jump over this step, if you do not use Hi3516A interal isp. ******************************************/
s32Ret = SAMPLE_COMM_ISP_Run(); #主要是开了一个线程来跑Test_ISP_Run
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("%s: ISP init failed!\n", __FUNCTION__);
/* disable videv */
return HI_FAILURE;
}
/****************************************************** step 4 : config & start vicap dev #配置并开启vi 捕获设备 u32DevNum = 1 ******************************************************/
for (i = 0; i < u32DevNum; i++)
{
ViDev = i;
s32Ret = SAMPLE_COMM_VI_StartDev(ViDev, enViMode); #开启设备,可以理解为3518e中带一个镜头就是一个设备
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("%s: start vi dev[%d] failed!\n", __FUNCTION__, i);
return HI_FAILURE;
}
}
/****************************************************** * Step 5: config & start vicap chn (max 1) ******************************************************/
for (i = 0; i < u32ChnNum; i++)
{
ViChn = i;
stCapRect.s32X = 0;
stCapRect.s32Y = 0;
switch (enViMode)
{
case APTINA_9M034_DC_720P_30FPS:
case APTINA_AR0130_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:
stCapRect.u32Width = 1280;
stCapRect.u32Height = 720;
break;
case SONY_IMX222_DC_1080P_30FPS:
case APTINA_AR0230_HISPI_1080P_30FPS:
case PANASONIC_MN34222_MIPI_1080P_30FPS:
case OMNIVISION_OV2718_MIPI_1080P_25FPS:
stCapRect.u32Width = 1920;
stCapRect.u32Height = 1080;
break;
default:
stCapRect.u32Width = 1920;
stCapRect.u32Height = 1080;
break;
}
stTargetSize.u32Width = stCapRect.u32Width;
stTargetSize.u32Height = stCapRect.u32Height;
s32Ret = SAMPLE_COMM_VI_StartChn(ViChn, &stCapRect, &stTargetSize, pstViConfig); #star vi chn 开启vi CHN,有很多个虚拟channel
if (HI_SUCCESS != s32Ret)
{
SAMPLE_COMM_ISP_Stop();
return HI_FAILURE;
}
}
return s32Ret;
}
VPSS部分
VPSS( Video Process Sub-System)支持对一幅输入图像进行统一预处理,如去噪、去隔行等,然后再对各通道分别进行缩放、锐化等处理,最后输出多种不同分辨率的图像。 VPSS 单元支持的具体图像处理功能包括 FRC( Frame Rate Control)、 Crop、 NR( Noise Reduce)、 LDC( Lens Distortion Correction)、 Rotate、 Cover/Overlay、 Scale、Mirror/Flip、 FishEye 等。
/****************************************** step 4: start vpss and vi bind vpss ******************************************/ s32Ret = SAMPLE_COMM_SYS_GetPicSize(gs_enNorm, enSize[0], &stSize); #根据 enSize[0] 来填充 stSize 结构体 if (HI_SUCCESS != s32Ret) { SAMPLE_PRT("SAMPLE_COMM_SYS_GetPicSize failed!\n"); goto END_VENC_1080P_CLASSIC_1; } if(s32ChnNum >= 1) { VpssGrp = 0; #仅仅在第一个通道的时候初始化 VpssGrp 的相关一些属性 stVpssGrpAttr.u32MaxW = stSize.u32Width; stVpssGrpAttr.u32MaxH = stSize.u32Height; stVpssGrpAttr.bIeEn = HI_FALSE; stVpssGrpAttr.bNrEn = HI_TRUE; stVpssGrpAttr.bHistEn = HI_FALSE; stVpssGrpAttr.bDciEn = HI_FALSE; stVpssGrpAttr.enDieMode = VPSS_DIE_MODE_NODIE; stVpssGrpAttr.enPixFmt = PIXEL_FORMAT_YUV_SEMIPLANAR_420; s32Ret = SAMPLE_COMM_VPSS_StartGroup(VpssGrp, &stVpssGrpAttr); #也仅仅在第一个通道的时候写入VpssGrp 的 stVpssGrpAttr if (HI_SUCCESS != s32Ret) { SAMPLE_PRT("Start Vpss failed!\n"); goto END_VENC_1080P_CLASSIC_2; } s32Ret = SAMPLE_COMM_VI_BindVpss(stViConfig.enViMode); #也仅仅在第一个通道的时候绑定VI与VPSS if (HI_SUCCESS != s32Ret) {
搜索
最近热搜
历史搜索 清除历史记录