Hi3518E官方录像例程源码流程分析(四)
文章目录
- Vpss的一些基本概念(来自资料里的官方文档)
- GROUP
- CHANNEL
- FRC
- 第四阶段 启动视频处理子系统vpss,并且绑定vi到vpss
- SAMPLE_COMM_SYS_GetPicSize
- if(s32ChnNum >= 1)
- SAMPLE_COMM_VPSS_StartGroup
- HI_MPI_VPSS_CreateGrp
- HI_MPI_VPSS_GetNRParam
- HI_MPI_VPSS_SetNRParam
- HI_MPI_VPSS_StartGrp
- SAMPLE_COMM_VI_BindVpss(),将当前组绑定到上一级VI的通道
- SAMPLE_COMM_VI_Mode2Param()
- 回到SAMPLE_COMM_VI_BindVpss
源码地址 + 文档资料 – 提取码: chmr
本专栏分析的是mpp\venc\sample\sample_venc.c
Vpss的一些基本概念(来自资料里的官方文档)
VPSS(Video Process Sub-System) 模块接收 VI 和解码模块发送过来的图像,支持对一幅输入图像进行统一预处理,如去噪、去隔行等,然后再对各通道分别进行缩放、锐化等处理,最后输出多种不同分辨率的图像。
GROUP
VPSS 对用户提供组(GROUP)的概念。最大可用数为 VPSS_MAX_GRP_NUM个,各芯片的最大组数目有所不同,各 GROUP 分时复用 VPSS 硬件。每个 VPSS GROUP 包含多个通道,通道数目视方案实现有所不同,具体描述请参见CHANNEL。
CHANNEL
VPSS 组的通道。通道分为 2 种:物理通道和扩展通道。VPSS 硬件提供多个物理通道,每个通道具有缩放、裁剪等功能。扩展通道具备缩放功能,它通过绑定物理通道,将物理通道输出作为自己的输入,把图像缩放成用户设置的目标分辨率输出。
FRC
- Group 帧率控制:用于控制各 group 对输入图像的接收,只应用在 VI—VPSS的离线方案中。
- Chn 帧率控制:用于控制各个物理通道图像的处理,应用在离线和在线方案中。
通过调用 SYS 模块的绑定接口,可与 VI 和 VO/VENC/IVE 等模块进行绑定,其中前者为 VPSS 的输入源,后者为 VPSS 的接收者。用户可通过提供的 MPI 接口对 GROUP进行管理。每个 GROUP 仅可与一个输入源绑定。
GROUP 的物理通道有两种工作模式:AUTO 和 USER,两种模式间可动态切换。默认的工作模式为 AUTO,此模式下各通道仅可与一个接收者绑定。若想使用 USER 模式,则需调用 MPI 接口进行设置,同时指定所需图像的大小和格式,此模式下各通道可与多个接收者绑定。需要特别注意的是,USER 模式主要用于对同一通道图像进行多路编码的场景,此模式下播放控制不生效,因此预览和回放场景下不建议使用 USER 模式。
第四阶段 启动视频处理子系统vpss,并且绑定vi到vpss
第四阶段看似很长,其实设置通道的三部分都是重复的步骤
if(s32ChnNum >= 1){....}
if(s32ChnNum >= 2){....}
if(s32ChnNum >= 3){....}
s32Ret = SAMPLE_COMM_SYS_GetPicSize(gs_enNorm, 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;//Grp number//Maximum sizestVpssGrpAttr.u32MaxW = stSize.u32Width;stVpssGrpAttr.u32MaxH = stSize.u32Height;//Some functions in the groupstVpssGrpAttr.bIeEn = HI_FALSE;stVpssGrpAttr.bNrEn = HI_TRUE;stVpssGrpAttr.bHistEn = HI_FALSE;stVpssGrpAttr.bDciEn = HI_FALSE;stVpssGrpAttr.enDieMode = VPSS_DIE_MODE_NODIE;//set convert from RAW_RGB to YUV420stVpssGrpAttr.enPixFmt = PIXEL_FORMAT_YUV_SEMIPLANAR_420;s32Ret = SAMPLE_COMM_VPSS_StartGroup(VpssGrp, &stVpssGrpAttr);if (HI_SUCCESS != s32Ret){SAMPLE_PRT("Start Vpss failed!\n");goto END_VENC_1080P_CLASSIC_2;}//Bind the current Group to the Channal of the previous level VIs32Ret = SAMPLE_COMM_VI_BindVpss(stViConfig.enViMode);if (HI_SUCCESS != s32Ret){SAMPLE_PRT("Vi bind Vpss failed!\n");goto END_VENC_1080P_CLASSIC_3;}//So far, the data in vi has arrived at Vpss.VpssChn = 0;//3518E can only work in MODE mode、mode:vpss channel's work modestVpssChnMode.enChnMode = VPSS_CHN_MODE_USER;stVpssChnMode.bDouble = HI_FALSE;stVpssChnMode.enPixelFormat = PIXEL_FORMAT_YUV_SEMIPLANAR_420;stVpssChnMode.u32Width = stSize.u32Width;stVpssChnMode.u32Height = stSize.u32Height;//Processing modules in large bytesstVpssChnMode.enCompressMode = COMPRESS_MODE_SEG;memset(&stVpssChnAttr, 0, sizeof(stVpssChnAttr));//Does not control frame ratestVpssChnAttr.s32SrcFrameRate = -1;stVpssChnAttr.s32DstFrameRate = -1;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_1080P_CLASSIC_4;}}//There are three chn, but they all belong to the same grp.if(s32ChnNum >= 2){//Reset the obtained image sizes32Ret = SAMPLE_COMM_SYS_GetPicSize(gs_enNorm, enSize[1], &stSize);if (HI_SUCCESS != s32Ret){SAMPLE_PRT("SAMPLE_COMM_SYS_GetPicSize failed!\n");goto END_VENC_1080P_CLASSIC_4;}VpssChn = 1;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;stVpssChnAttr.s32SrcFrameRate = -1;stVpssChnAttr.s32DstFrameRate = -1;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_1080P_CLASSIC_4;}}if(s32ChnNum >= 3){ s32Ret = SAMPLE_COMM_SYS_GetPicSize(gs_enNorm, enSize[2], &stSize);if (HI_SUCCESS != s32Ret){SAMPLE_PRT("SAMPLE_COMM_SYS_GetPicSize failed!\n");goto END_VENC_1080P_CLASSIC_4;}VpssChn = 2;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_NONE;stVpssChnAttr.s32SrcFrameRate = -1;stVpssChnAttr.s32DstFrameRate = -1;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_1080P_CLASSIC_4;}}
SAMPLE_COMM_SYS_GetPicSize
这个函数提到过很多次了,更新图像的像素大小
case PIC_HD720: /* 1280 * 720 */pstSize->u32Width = 1280;pstSize->u32Height = 720;
if(s32ChnNum >= 1)
stVpssGrpAttr.bIeEn = HI_FALSE;
stVpssGrpAttr.bNrEn = HI_TRUE;
stVpssGrpAttr.bHistEn = HI_FALSE;
stVpssGrpAttr.bDciEn = HI_FALSE;
stVpssGrpAttr.enDieMode = VPSS_DIE_MODE_NODIE;
首先进来是Vpss的一些参数
stVpssGrpAttr.bIeEn //图像增强
stVpssGrpAttr.bNrEn //去噪声
stVpssGrpAttr.bDciEn // 动态对比度调节
stVpssGrpAttr.enDieMode //隔行扫描
stVpssGrpAttr.enPixFmt //Raw_RGB -> YUV…
SAMPLE_COMM_VPSS_StartGroup
前面那些条件判断就不理他了
HI_MPI_VPSS_CreateGrp
创建一个 VPSS GROUP
HI_MPI_VPSS_GetNRParam
获取 vpss 3DNR 参数
HI_MPI_VPSS_SetNRParam
设置 vpss 3DNR 参数,将s32Ret更改为自定义降噪部分等
HI_MPI_VPSS_StartGrp
启用 VPSS GROUP
SAMPLE_COMM_VI_BindVpss(),将当前组绑定到上一级VI的通道
这里又涉及到Vpss的另一个概念
在线模式
由手册也可以看到3518E的每个通道地区在线模式和离线模式可能会有不一样的功能
我们这里是直接把VI绑定到Vpss,所以都是在线模式
SAMPLE_COMM_VI_Mode2Param()
设置设备和通道的数量以及每个设备id之间和通道id之间的差值间隔
pstViParam->s32ViDevCnt = 1;//There are currently several dev's.
pstViParam->s32ViDevInterval = 1;
pstViParam->s32ViChnCnt = 1;//There are several channals currently
pstViParam->s32ViChnInterval = 1;
回到SAMPLE_COMM_VI_BindVpss
上面设置了stViParam.s32ViChnCnt = 1,所以这个只会执行1次
VpssGrp = 0;for (j=0; j<stViParam.s32ViChnCnt; j++){ //Interval between each channal numberViChn = j * stViParam.s32ViChnInterval;//Source: chn0 of dev0 in unit vistSrcChn.enModId = HI_ID_VIU;//Internal unit number of ChipstSrcChn.s32DevId = 0;stSrcChn.s32ChnId = ViChn;//Purpose: chn0 of Grp0 in the vpss unitstDestChn.enModId = HI_ID_VPSS;stDestChn.s32DevId = VpssGrp;stDestChn.s32ChnId = 0;//online mode:Bind vi and vpsss32Ret = HI_MPI_SYS_Bind(&stSrcChn, &stDestChn);if (s32Ret != HI_SUCCESS){SAMPLE_PRT("failed with %#x!\n", s32Ret);return HI_FAILURE;}VpssGrp ++;}
先是这一句:ViChn = j * stViParam.s32ViChnInterval;
前面不是设置了通道id之间的差值吗,这里通过 j 乘 这个差值就能找到具体的通道
然后把vi的channel和Vpss Group里的channel绑定起来
//Source: chn0 of dev0 in unit vistSrcChn.enModId = HI_ID_VIU;//Internal unit number of ChipstSrcChn.s32DevId = 0;stSrcChn.s32ChnId = ViChn;//Purpose: chn0 of Grp0 in the vpss unitstDestChn.enModId = HI_ID_VPSS;stDestChn.s32DevId = VpssGrp;stDestChn.s32ChnId = 0;
HI_MPI_SYS_Bind()
到此为止,Vi模块里的数据就到达了Vpss模块