海思3519 VIO Sample例程讲解

article/2025/9/17 2:37:28

海思VIO Sample例程讲解

海思SDK解压出来后,Sample包含各个功能模块的历程,本篇讲解VIO Sample历程。
进入VIO模块可以看到,VIO的main函数文件,先从main函数执行程序。
在这里插入图片描述
进入文件后首先看下VIO实现的功能,可以看到VIO示例的功能还是挺多的,并且支持HDMI与BT1120这两种输出接口,在SAMPLE_VIO_VoInterface_Usage函数,可以看到,下面一个一个功能进行说明。

1、Sample_vio_main函数

/******************************************************************************
* function : show usage
***************************************************************************/
HI_VOID SAMPLE_VIO_VoInterface_Usage(HI_VOID)
{printf("intf:\n");printf("\t 0) vo HDMI output.\n");printf("\t 1) vo BT1120 output, default.\n");
}void SAMPLE_VIO_Usage(char *sPrgNm)
{printf("Usage : %s <index> <intf>\n", sPrgNm);printf("index:\n");printf("\t 0)VI(Online) - VPSS(Online) - VO.\n");printf("\t 1)VI(Offline)- VPSS(Offline) - VO. LDC+DIS+SPREAD.\n");printf("\t 2)VI(Offline)- VPSS(Online) - VO.  Double pipe.\n");printf("\t 3)VI(Online)- VPSS(Offline) - VO.  Double chn.\n");printf("\t 4)Resolute Ratio Switch.\n");printf("\t 5)GDC - VPSS LowDelay.\n");printf("\t 6)Double WDR Pipe.\n");printf("\t 7)FPN Calibrate & Correction.\n");printf("\t 8)WDR Switch.\n");printf("\t 9)90/180/270 Rotate.\n");printf("\t 10)Mipi Demux Yuv.\n");printf("\t 11)UserPic.\n");printf("intf:\n");printf("\t 0) vo HDMI output, default.\n");printf("\t 1) vo BT1120 output.\n");return;
}

首先判断传给执行程序传入的参数个数是否正确,不正确则打印使用说明。

/******************************************************************************
* function    : main()
* Description : main
***************************************************************************/
#ifdef __HuaweiLite__
int app_main(int argc, char *argv[])
#else
int main(int argc, char *argv[])
#endif
{HI_S32 s32Ret = HI_FAILURE;HI_S32 s32Index;HI_U32 u32VoIntfType = 0;if (argc < 2){SAMPLE_VIO_Usage(argv[0]);return HI_FAILURE;}

设置相应信号处理函数,SIGINT由Interrupt Key产生,通常是CTRL+C或者Delete,发送给所有ForeGround Group的进程。SIGTERM请求终止进程,Kill命令缺省发送。

#ifdef __HuaweiLite__
#elsesignal(SIGINT, SAMPLE_VIO_HandleSig);signal(SIGTERM, SAMPLE_VIO_HandleSig);
#endifif ((argc > 2) && (1 == atoi(argv[2]))){u32VoIntfType = 1;}SAMPLE_VIO_MsgInit();

当捕获到异常信号后触发的自定义函数如下,主要是对信号的重新定义以及系统退出资源的释放。

void SAMPLE_VIO_HandleSig(HI_S32 signo)
{signal(SIGINT, SIG_IGN);signal(SIGTERM, SIG_IGN);if (SIGINT == signo || SIGTERM == signo){SAMPLE_COMM_VENC_StopGetStream();SAMPLE_COMM_All_ISP_Stop();SAMPLE_COMM_VO_HdmiStop();SAMPLE_COMM_SYS_Exit();printf("\033[0;31mprogram termination abnormally!\033[0;39m\n");}exit(-1);
}

SAMPLE_VIO_MsgInit()与SAMPLE_VIO_MsgExit()分别为程序初始化与退出的桩函数,用户可以进行添加内容。

HI_VOID SAMPLE_VIO_MsgInit(HI_VOID)
{
}HI_VOID SAMPLE_VIO_MsgExit(HI_VOID)
{
}

接着就是选择相应的功能,下面依次解析相关功能。

 s32Index = atoi(argv[1]);switch (s32Index){case 0:s32Ret = SAMPLE_VIO_ViOnlineVpssOnlineRoute(u32VoIntfType);break;case 1:s32Ret = SAMPLE_VIO_ViOnlineVpssOfflineRoute(u32VoIntfType);break;case 2:s32Ret = SAMPLE_VIO_ViDoublePipeRoute(u32VoIntfType);break;case 3:s32Ret = SAMPLE_VIO_ViDoubleChnRoute(u32VoIntfType);break;case 4:s32Ret = SAMPLE_VIO_ViResoSwitch(u32VoIntfType);break;case 5:s32Ret = SAMPLE_VIO_ViVpssLowDelay(u32VoIntfType);break;case 6:s32Ret = SAMPLE_VIO_ViDoubleWdrPipe(u32VoIntfType);break;case 7:s32Ret = SAMPLE_VIO_ViFPN(u32VoIntfType);break;case 8:s32Ret = SAMPLE_VIO_ViWdrSwitch(u32VoIntfType);break;case 9:s32Ret = SAMPLE_VIO_ViRotate(u32VoIntfType);break;case 10:s32Ret = SAMPLE_VIO_ViDeMuxYuv(u32VoIntfType);break;case 11:s32Ret = SAMPLE_VIO_ViSetUsrPic(u32VoIntfType);break;default:SAMPLE_PRT("the index %d is invaild!\n",s32Index);SAMPLE_VIO_Usage(argv[0]);SAMPLE_VIO_MsgExit();return HI_FAILURE;}

2、SAMPLE_VIO_ViOnlineVpssOnlineRoute

在解析源码前你可能需要阅读一下《HiMPP V4.0 媒体处理软件开发参考》文档,大部分的内容文档中都已经描述的很清楚,当然涉及到一些专业术语就要我们自己去查了。

前面一些都是关于VI、VPSS、VO以及VENC的配置,具体参数的信息可以在《HiMPP V4.0 媒体处理软件开发参考》查阅,这里是VI配置为单个Sensor,VI的配置为设备号0,使用PIPE与通道0,然后配置视频动态范围、线性模式、像素格式为YUV NV21、视频格式、不压缩等等,采用H265编码器对VPSS输出的视频流进行编码保存。

HI_S32 SAMPLE_VIO_ViOnlineVpssOnlineRoute(HI_U32 u32VoIntfType)
{HI_S32             s32Ret;HI_S32             s32ViCnt       = 1;//VI配置为单个sensorVI_DEV             ViDev          = 0;//VI配置为设备号0VI_PIPE            ViPipe         = 0;//VI配置为物理PIPE号0VI_CHN             ViChn          = 0;//VI配置通道号0HI_S32             s32WorkSnsId   = 0;SAMPLE_VI_CONFIG_S stViConfig;SIZE_S             stSize;VB_CONFIG_S        stVbConf;          //视频缓存池属性PIC_SIZE_E         enPicSize;HI_U32             u32BlkSize;VO_CHN             VoChn          = 0;//VO配置视频输出通道号0SAMPLE_VO_CONFIG_S stVoConfig;WDR_MODE_E         enWDRMode      = WDR_MODE_NONE;//WDR 工作模式,分为帧模式、行模式、非WDRDYNAMIC_RANGE_E    enDynamicRange = DYNAMIC_RANGE_SDR8;//动态范围,8bit数据的标准动态范围PIXEL_FORMAT_E     enPixFormat    = PIXEL_FORMAT_YVU_SEMIPLANAR_420;//像素格式VIDEO_FORMAT_E     enVideoFormat  = VIDEO_FORMAT_LINEAR;//视频格式,现行存储COMPRESS_MODE_E    enCompressMode = COMPRESS_MODE_NONE;//视频压缩数据格式,非压缩VPSS_GRP           VpssGrp        = 0; //VPSS GROUP 号0VPSS_GRP_ATTR_S    stVpssGrpAttr;VPSS_CHN           VpssChn        = VPSS_CHN0; //VPSS 通道号HI_BOOL            abChnEnable[VPSS_MAX_PHY_CHN_NUM] = {0};VPSS_CHN_ATTR_S    astVpssChnAttr[VPSS_MAX_PHY_CHN_NUM]; //VPSS物理通道属性VENC_CHN           VencChn[1]  = {0};   //编码通道号PAYLOAD_TYPE_E     enType      = PT_H265;//音视频净荷类型,解码通道类型为PT_256SAMPLE_RC_E        enRcMode    = SAMPLE_RC_CBR;HI_U32             u32Profile  = 0;VENC_GOP_ATTR_S    stGopAttr;     //编码器GOP属性/*config vi*/SAMPLE_COMM_VI_GetSensorInfo(&stViConfig);

因为很多sample需要调用同样的配置,所以海思将一些通用的接口都放在SAMPLE_COMM_XXX接口中,这里Sensor配置是使用I2C接口,可以在下面的注释部分有说明,Hi3519AV100的VI设备最多支持5个,不同的芯片型号支持的不一样,可以具体阅读《HiMPP V4.0 媒体处理软件开发参考》。

HI_VOID SAMPLE_COMM_VI_GetSensorInfo(SAMPLE_VI_CONFIG_S* pstViConfig)
{HI_S32 i;for (i = 0; i < VI_MAX_DEV_NUM; i++){pstViConfig->astViInfo[i].stSnsInfo.s32SnsId = i;pstViConfig->astViInfo[i].stSnsInfo.s32BusId = i;pstViConfig->astViInfo[i].stSnsInfo.MipiDev  = i;hi_memset(&pstViConfig->astViInfo[i].stSnapInfo, sizeof(SAMPLE_SNAP_INFO_S), 0, sizeof(SAMPLE_SNAP_INFO_S));pstViConfig->astViInfo[i].stPipeInfo.bMultiPipe = HI_FALSE;pstViConfig->astViInfo[i].stPipeInfo.bVcNumCfged = HI_FALSE;}/*single sensor using I2C,  s32BusId must be set to 1single sensor using spi,  s32BusId must be set to 0if add sensor using spi into SAMPLE_SNS_TYPE_E, please add code branch with sensor type*/pstViConfig->astViInfo[0].stSnsInfo.s32BusId = 1;pstViConfig->astViInfo[0].stSnsInfo.enSnsType = SENSOR0_TYPE;pstViConfig->astViInfo[1].stSnsInfo.enSnsType = SENSOR1_TYPE;pstViConfig->astViInfo[2].stSnsInfo.enSnsType = SENSOR2_TYPE;pstViConfig->astViInfo[3].stSnsInfo.enSnsType = SENSOR3_TYPE;pstViConfig->astViInfo[4].stSnsInfo.enSnsType = SENSOR4_TYPE;
}
typedef struct hiSAMPLE_VI_CONFIG_S
{SAMPLE_VI_INFO_S    astViInfo[VI_MAX_DEV_NUM];HI_S32              as32WorkingViId[VI_MAX_DEV_NUM];HI_S32              s32WorkingViNum;
} SAMPLE_VI_CONFIG_S;
typedef struct hiSAMPLE_VI_INFO_S
{SAMPLE_SENSOR_INFO_S    stSnsInfo;SAMPLE_DEV_INFO_S       stDevInfo;SAMPLE_PIPE_INFO_S      stPipeInfo;SAMPLE_CHN_INFO_S       stChnInfo;SAMPLE_SNAP_INFO_S      stSnapInfo;
} SAMPLE_VI_INFO_S;
typedef struct hiSAMPLE_SENSOR_INFO_S
{SAMPLE_SNS_TYPE_E   enSnsType;HI_S32              s32SnsId;HI_S32              s32BusId;combo_dev_t           MipiDev;
} SAMPLE_SENSOR_INFO_S;
typedef enum hiSAMPLE_SNS_TYPE_E
{SONY_IMX290_MIPI_2M_30FPS_12BIT,SONY_IMX290_MIPI_2M_30FPS_12BIT_WDR2TO1,SONY_IMX290_SLAVE_MIPI_2M_60FPS_10BIT,SONY_IMX334_MIPI_8M_30FPS_12BIT,SONY_IMX334_MIPI_8M_30FPS_12BIT_WDR2TO1,SONY_IMX377_MIPI_8M_30FPS_10BIT,NVP6324_MIPI_2M_30FPS_8BIT,SAMPLE_SNS_TYPE_BUTT,
} SAMPLE_SNS_TYPE_E;

可以看到结构体是一层套着一层,还是比较复杂的。
因为VPSS的工作模式设置为在线模式,可以简单的认为VPSS在线模式由VI_PROC将数据流直接发送给VPSS进行处理。

 /*config vi*/SAMPLE_COMM_VI_GetSensorInfo(&stViConfig);stViConfig.s32WorkingViNum                                   = s32ViCnt;stViConfig.as32WorkingViId[0]                                = 0;stViConfig.astViInfo[s32WorkSnsId].stSnsInfo.MipiDev         = ViDev;stViConfig.astViInfo[s32WorkSnsId].stDevInfo.ViDev           = ViDev;stViConfig.astViInfo[s32WorkSnsId].stDevInfo.enWDRMode       = enWDRMode;stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.enMastPipeMode = VI_ONLINE_VPSS_ONLINE;//VI PIPE 和 VPSS 组的工作模式stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.aPipe[0]       = ViPipe;stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.aPipe[1]       = -1;stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.aPipe[2]       = -1;stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.aPipe[3]       = -1;stViConfig.astViInfo[s32WorkSnsId].stChnInfo.ViChn           = ViChn;stViConfig.astViInfo[s32WorkSnsId].stChnInfo.enPixFormat     = enPixFormat;stViConfig.astViInfo[s32WorkSnsId].stChnInfo.enDynamicRange  = enDynamicRange;stViConfig.astViInfo[s32WorkSnsId].stChnInfo.enVideoFormat   = enVideoFormat;stViConfig.astViInfo[s32WorkSnsId].stChnInfo.enCompressMode  = enCompressMode;

根据不同Sensor类型的图片大小分配缓存,这里配置VI写出RAW的缓存块为4块,YUV缓存块10块,可以在下面的最后几行赋值看到10和4,数据结构u32BlkCnt可以在MIPP媒体软件开发参考里面查到

   /*get picture size*/s32Ret = SAMPLE_COMM_VI_GetSizeBySensor(stViConfig.astViInfo[s32WorkSnsId].stSnsInfo.enSnsType, &enPicSize);if (HI_SUCCESS != s32Ret){SAMPLE_PRT("get picture size by sensor failed!\n");return s32Ret;}s32Ret = SAMPLE_COMM_SYS_GetPicSize(enPicSize, &stSize);if (HI_SUCCESS != s32Ret){SAMPLE_PRT("get picture size failed!\n");return s32Ret;}/*config vb*/hi_memset(&stVbConf, sizeof(VB_CONFIG_S), 0, sizeof(VB_CONFIG_S));stVbConf.u32MaxPoolCnt              = 2;u32BlkSize = COMMON_GetPicBufferSize(stSize.u32Width, stSize.u32Height, SAMPLE_PIXEL_FORMAT, DATA_BITWIDTH_8, COMPRESS_MODE_SEG, DEFAULT_ALIGN);stVbConf.astCommPool[0].u64BlkSize  = u32BlkSize;stVbConf.astCommPool[0].u32BlkCnt   = 10;u32BlkSize = VI_GetRawBufferSize(stSize.u32Width, stSize.u32Height, PIXEL_FORMAT_RGB_BAYER_16BPP, COMPRESS_MODE_NONE, DEFAULT_ALIGN);stVbConf.astCommPool[1].u64BlkSize  = u32BlkSize;stVbConf.astCommPool[1].u32BlkCnt   = 4;

在启动各个模块之前必须需要MPP系统进行初始化。

s32Ret = SAMPLE_COMM_SYS_Init(&stVbConf);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("system init failed with %d!\n", s32Ret);return s32Ret;
}

为了防止其它进程已经使用MPP需要对其进行去初始化,然后根据之前VB的配置进行设置对系统进行初始化。

/******************************************************************************
* function : vb init & MPI system init
******************************************************************************/
HI_S32 SAMPLE_COMM_SYS_Init(VB_CONFIG_S* pstVbConfig)
{HI_S32 s32Ret = HI_FAILURE;HI_MPI_SYS_Exit();HI_MPI_VB_Exit();if (NULL == pstVbConfig){SAMPLE_PRT("input parameter is null, it is invaild!\n");return HI_FAILURE;}s32Ret = HI_MPI_VB_SetConfig(pstVbConfig);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;}s32Ret = HI_MPI_SYS_Init();if (HI_SUCCESS != s32Ret){SAMPLE_PRT("HI_MPI_SYS_Init failed!\n");HI_MPI_VB_Exit();return HI_FAILURE;}return HI_SUCCESS;
}

启动VI模块需要先启动MIPI,接口根据hi_mipi驱动进行控制,根据VI的配置进行VI模块的参数设置以及创建,还需要启动ISP,ISP这块又涉及到许多内容,包括调试图像、可以使用自定义3A库开发等等。

   /*start vi*/s32Ret = SAMPLE_COMM_VI_StartVi(&stViConfig);if (HI_SUCCESS != s32Ret){SAMPLE_PRT("start vi failed.s32Ret:0x%x !\n", s32Ret);goto EXIT;}

SAMPLE_COMM_VI_StartVi函数,ISP内容见最后几行代码。

HI_S32 SAMPLE_COMM_VI_StartVi(SAMPLE_VI_CONFIG_S* pstViConfig)
{HI_S32 s32Ret = HI_SUCCESS;if (!pstViConfig){SAMPLE_PRT("%s: null ptr\n", __FUNCTION__);return HI_FAILURE;}s32Ret = SAMPLE_COMM_VI_StartMIPI(pstViConfig);if (s32Ret != HI_SUCCESS){SAMPLE_PRT("SAMPLE_COMM_VI_StartMIPI failed!\n");return HI_FAILURE;}s32Ret = SAMPLE_COMM_VI_SetParam(pstViConfig);if (s32Ret != HI_SUCCESS){SAMPLE_PRT("SAMPLE_COMM_VI_SetParam failed!\n");return HI_FAILURE;}s32Ret = SAMPLE_COMM_VI_CreateVi(pstViConfig);if (s32Ret != HI_SUCCESS){SAMPLE_PRT("SAMPLE_COMM_VI_CreateVi failed!\n");return HI_FAILURE;}s32Ret = SAMPLE_COMM_VI_CreateIsp(pstViConfig);if (s32Ret != HI_SUCCESS){SAMPLE_COMM_VI_DestroyVi(pstViConfig);SAMPLE_PRT("SAMPLE_COMM_VI_CreateIsp failed!\n");return HI_FAILURE;}return s32Ret;
}

根据VPSS的配置创建group并启动,设置并使能VPSS,这里因为配置为VI与VPSS在线模式所以不需要进行VI与VPSS的绑定。

/*config vpss*/
hi_memset(&stVpssGrpAttr, sizeof(VPSS_GRP_ATTR_S), 0, sizeof(VPSS_GRP_ATTR_S));
stVpssGrpAttr.stFrameRate.s32SrcFrameRate    = -1;
stVpssGrpAttr.stFrameRate.s32DstFrameRate    = -1;
stVpssGrpAttr.enDynamicRange                 = DYNAMIC_RANGE_SDR8;
stVpssGrpAttr.enPixelFormat                  = enPixFormat;
stVpssGrpAttr.u32MaxW                        = stSize.u32Width;
stVpssGrpAttr.u32MaxH                        = stSize.u32Height;
stVpssGrpAttr.bNrEn                          = HI_TRUE;
stVpssGrpAttr.stNrAttr.enCompressMode        = COMPRESS_MODE_FRAME;
stVpssGrpAttr.stNrAttr.enNrMotionMode        = NR_MOTION_MODE_NORMAL;astVpssChnAttr[VpssChn].u32Width                    = stSize.u32Width;
astVpssChnAttr[VpssChn].u32Height                   = stSize.u32Height;
astVpssChnAttr[VpssChn].enChnMode                   = VPSS_CHN_MODE_USER;
astVpssChnAttr[VpssChn].enCompressMode              = enCompressMode;
astVpssChnAttr[VpssChn].enDynamicRange              = enDynamicRange;
astVpssChnAttr[VpssChn].enVideoFormat               = enVideoFormat;
astVpssChnAttr[VpssChn].enPixelFormat               = enPixFormat;
astVpssChnAttr[VpssChn].stFrameRate.s32SrcFrameRate = 30;
astVpssChnAttr[VpssChn].stFrameRate.s32DstFrameRate = 30;
astVpssChnAttr[VpssChn].u32Depth                    = 0;
astVpssChnAttr[VpssChn].bMirror                     = HI_FALSE;
astVpssChnAttr[VpssChn].bFlip                       = HI_FALSE;
astVpssChnAttr[VpssChn].stAspectRatio.enMode        = ASPECT_RATIO_NONE;/*start vpss*/abChnEnable[0] = HI_TRUE;s32Ret = SAMPLE_COMM_VPSS_Start(VpssGrp, abChnEnable, &stVpssGrpAttr, astVpssChnAttr);if (HI_SUCCESS != s32Ret){SAMPLE_PRT("start vpss group failed. s32Ret: 0x%x !\n", s32Ret);goto EXIT1;}

配置编码器并启动,这里接口可以根据配置切换为不同编码器,并绑定VPSS与VENC,自动将VPSS处理完的数据发送到VENC中进行编码。

/*config venc */
stGopAttr.enGopMode  = VENC_GOPMODE_SMARTP;
stGopAttr.stSmartP.s32BgQpDelta  = 7;
stGopAttr.stSmartP.s32ViQpDelta  = 2;
stGopAttr.stSmartP.u32BgInterval = 1200;
s32Ret = SAMPLE_COMM_VENC_Start(VencChn[0], enType, enPicSize, enRcMode, u32Profile, &stGopAttr);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("start venc failed. s32Ret: 0x%x !\n", s32Ret);goto EXIT2;
}s32Ret = SAMPLE_COMM_VPSS_Bind_VENC(VpssGrp, VpssChn, VencChn[0]);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("Venc bind Vpss failed. s32Ret: 0x%x !n", s32Ret);goto EXIT3;
}

最后配置VO并启动。

/*config vo*/
SAMPLE_COMM_VO_GetDefConfig(&stVoConfig);
stVoConfig.enDstDynamicRange = enDynamicRange;
if (1 == u32VoIntfType)
{stVoConfig.enVoIntfType = VO_INTF_BT1120;
}
else
{stVoConfig.enVoIntfType = VO_INTF_HDMI;
}
stVoConfig.enPicSize = enPicSize;/*start vo*/
s32Ret = SAMPLE_COMM_VO_StartVO(&stVoConfig);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("start vo failed. s32Ret: 0x%x !\n", s32Ret);goto EXIT4;
}

可以修改VO的输出接口时序为你需要的分辨率。

/*
* Name : SAMPLE_COMM_VO_GetDefConfig
* Desc : An instance of SAMPLE_VO_CONFIG_S, which allows you to use vo immediately.
*/
HI_S32 SAMPLE_COMM_VO_GetDefConfig(SAMPLE_VO_CONFIG_S *pstVoConfig)
{RECT_S  stDefDispRect  = {0, 0, 1920, 1080};SIZE_S  stDefImageSize = {1920, 1080};if(NULL == pstVoConfig){SAMPLE_PRT("Error:argument can not be NULL\n");return HI_FAILURE;}pstVoConfig->VoDev             = SAMPLE_VO_DEV_UHD;
#ifdef HI_FPGApstVoConfig->enVoIntfType = VO_INTF_BT1120;
#elsepstVoConfig->enVoIntfType = VO_INTF_HDMI;
#endifpstVoConfig->enIntfSync        = VO_OUTPUT_1080P30;pstVoConfig->u32BgColor        = COLOR_RGB_BLUE;pstVoConfig->enPixFormat       = PIXEL_FORMAT_YVU_SEMIPLANAR_420;pstVoConfig->stDispRect        = stDefDispRect;pstVoConfig->stImageSize       = stDefImageSize;pstVoConfig->enVoPartMode      = VO_PART_MODE_SINGLE;pstVoConfig->u32DisBufLen      = 3;pstVoConfig->enDstDynamicRange = DYNAMIC_RANGE_SDR8;pstVoConfig->enVoMode          = VO_MODE_1MUX;return HI_SUCCESS;
}

SAMPLE_COMM_VO_StartVO函数中最后需要启动相应的输出接口,HDMI由系统接口实现,MipiTx海思有提供相应的驱动hi_mipi_tx。
小注:另一篇Hi3516的文章,在SAMPLE_COMM_VO_StartVO还是里面配置输出时序。

/******************************
* Start hdmi device.
* Note : do this after vo device started.
********************************/
if(VO_INTF_HDMI == enVoIntfType)
{SAMPLE_COMM_VO_HdmiStartByDyRg(enIntfSync, enDstDyRg);
}/******************************
* Start mipi_tx device.
* Note : do this after vo device started.
********************************/
if(VO_INTF_MIPI == enVoIntfType)
{SAMPLE_COMM_VO_StartMipiTx(enIntfSync);
}return HI_SUCCESS;

绑定VPSS与VO自动将VPSS处理完的数据进行输出。

/*vpss bind vo*/
s32Ret = SAMPLE_COMM_VPSS_Bind_VO(VpssGrp, VpssChn, stVoConfig.VoDev, VoChn);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("vo bind vpss failed. s32Ret: 0x%x !\n", s32Ret);goto EXIT5;
}

创建线程,通过Venc的fd判断是否有数据流编码完成进行保存到文件中。下面的两段代码是在解释线程和fd的

s32Ret = SAMPLE_COMM_VENC_StartGetStream(VencChn, sizeof(VencChn)/sizeof(VENC_CHN));
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("Get venc stream failed!\n");goto EXIT6;
}PAUSE();

线程创建pthread_create,线程函数pthread_create的SAMPLE_COMM_VENC_GetVencStreamProc里面有关于fd和保存文件的函数,暂时还没有搞懂怎么用。

/******************************************************************************
* funciton : start get venc stream process thread
******************************************************************************/
HI_S32 SAMPLE_COMM_VENC_StartGetStream(VENC_CHN VeChn[],HI_S32 s32Cnt)
{HI_U32 i;gs_stPara.bThreadStart = HI_TRUE;gs_stPara.s32Cnt = s32Cnt;for(i=0; i<s32Cnt; i++){gs_stPara.VeChn[i] = VeChn[i];}return pthread_create(&gs_VencPid, 0, SAMPLE_COMM_VENC_GetVencStreamProc, (HI_VOID*)&gs_stPara);
}

SAMPLE_COMM_VENC_GetVencStreamProc函数,其中step 1: check & prepare save-file & venc-fd

/******************************************************************************
* funciton : get stream from each channels and save them
******************************************************************************/
HI_VOID* SAMPLE_COMM_VENC_GetVencStreamProc(HI_VOID* p)
{HI_S32 i;HI_S32 s32ChnTotal;VENC_CHN_ATTR_S stVencChnAttr;SAMPLE_VENC_GETSTREAM_PARA_S* pstPara;HI_S32 maxfd = 0;struct timeval TimeoutVal;fd_set read_fds;HI_U32 u32PictureCnt[VENC_MAX_CHN_NUM]={0};HI_S32 VencFd[VENC_MAX_CHN_NUM];HI_CHAR aszFileName[VENC_MAX_CHN_NUM][64];FILE* pFile[VENC_MAX_CHN_NUM];char szFilePostfix[10];VENC_CHN_STATUS_S stStat;VENC_STREAM_S stStream;HI_S32 s32Ret;VENC_CHN VencChn;PAYLOAD_TYPE_E enPayLoadType[VENC_MAX_CHN_NUM];VENC_STREAM_BUF_INFO_S stStreamBufInfo[VENC_MAX_CHN_NUM];prctl(PR_SET_NAME, "GetVencStream", 0,0,0);pstPara = (SAMPLE_VENC_GETSTREAM_PARA_S*)p;s32ChnTotal = pstPara->s32Cnt;/******************************************step 1:  check & prepare save-file & venc-fd******************************************/if (s32ChnTotal >= VENC_MAX_CHN_NUM){SAMPLE_PRT("input count invaild\n");return NULL;}for (i = 0; i < s32ChnTotal; i++){/* decide the stream file name, and open file to save stream */VencChn = pstPara->VeChn[i];s32Ret = HI_MPI_VENC_GetChnAttr(VencChn, &stVencChnAttr);if (s32Ret != HI_SUCCESS){SAMPLE_PRT("HI_MPI_VENC_GetChnAttr chn[%d] failed with %#x!\n", \VencChn, s32Ret);return NULL;}enPayLoadType[i] = stVencChnAttr.stVencAttr.enType;s32Ret = SAMPLE_COMM_VENC_GetFilePostfix(enPayLoadType[i], szFilePostfix);if (s32Ret != HI_SUCCESS){SAMPLE_PRT("SAMPLE_COMM_VENC_GetFilePostfix [%d] failed with %#x!\n", \stVencChnAttr.stVencAttr.enType, s32Ret);return NULL;}if(PT_JPEG != enPayLoadType[i]){snprintf(aszFileName[i],32, "stream_chn%d%s", i, szFilePostfix);pFile[i] = fopen(aszFileName[i], "wb");if (!pFile[i]){SAMPLE_PRT("open file[%s] failed!\n",aszFileName[i]);return NULL;}}/* Set Venc Fd. */VencFd[i] = HI_MPI_VENC_GetFd(i);if (VencFd[i] < 0){SAMPLE_PRT("HI_MPI_VENC_GetFd failed with %#x!\n",VencFd[i]);return NULL;}if (maxfd <= VencFd[i]){maxfd = VencFd[i];}

不同异常进行资源释放的处理。

   SAMPLE_COMM_VENC_StopGetStream();EXIT6:SAMPLE_COMM_VPSS_UnBind_VO(VpssGrp, VpssChn, stVoConfig.VoDev, VoChn);
EXIT5:SAMPLE_COMM_VO_StopVO(&stVoConfig);
EXIT4:SAMPLE_COMM_VPSS_UnBind_VENC(VpssGrp, VpssChn, VencChn[0]);
EXIT3:SAMPLE_COMM_VENC_Stop(VencChn[0]);
EXIT2:SAMPLE_COMM_VPSS_Stop(VpssGrp, abChnEnable);
EXIT1:SAMPLE_COMM_VI_StopVi(&stViConfig);
EXIT:SAMPLE_COMM_SYS_Exit();return s32Ret;
}

3、SAMPLE_VIO_ViOnlineVpssOfflineRoute

该函数实现VI在线VPSS离线功能,基本配置实现与上述相同,只有几处不同的地方。

需要配置模式为VI在线VPSS离线

/*config vi*/
SAMPLE_COMM_VI_GetSensorInfo(&stViConfig);stViConfig.s32WorkingViNum                                   = s32ViCnt;
stViConfig.as32WorkingViId[0]                                = 0;
stViConfig.astViInfo[s32WorkSnsId].stSnsInfo.MipiDev         = ViDev;
stViConfig.astViInfo[s32WorkSnsId].stDevInfo.ViDev           = ViDev;
stViConfig.astViInfo[s32WorkSnsId].stDevInfo.enWDRMode       = enWDRMode;
stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.enMastPipeMode = VI_OFFLINE_VPSS_OFFLINE;
stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.aPipe[0]       = ViPipe;
stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.aPipe[1]       = -1;
stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.aPipe[2]       = -1;
stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.aPipe[3]       = -1;
stViConfig.astViInfo[s32WorkSnsId].stChnInfo.ViChn           = ViChn;
stViConfig.astViInfo[s32WorkSnsId].stChnInfo.enPixFormat     = enPixFormat;
stViConfig.astViInfo[s32WorkSnsId].stChnInfo.enDynamicRange  = enDynamicRange;
stViConfig.astViInfo[s32WorkSnsId].stChnInfo.enVideoFormat   = enVideoFormat;
stViConfig.astViInfo[s32WorkSnsId].stChnInfo.enCompressMode  = enCompressMode;

需要绑定VI与VPSS实现将VI捕获的内容自动发送到VPSS中处理。

/*start vpss*/
abChnEnable[0] = HI_TRUE;
s32Ret = SAMPLE_COMM_VPSS_Start(VpssGrp, abChnEnable, &stVpssGrpAttr, astVpssChnAttr);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("start vpss group failed. s32Ret: 0x%x !\n", s32Ret);goto EXIT1;
}/*vi bind vpss*/
s32Ret = SAMPLE_COMM_VI_Bind_VPSS(ViPipe, ViChn, VpssGrp);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("vi bind vpss failed. s32Ret: 0x%x !\n", s32Ret);goto EXIT2;
}

VPSS绑定VO,

    /*vpss bind vo*/s32Ret = SAMPLE_COMM_VPSS_Bind_VO(VpssGrp, VpssChn, stVoConfig.VoDev, VoChn);if (HI_SUCCESS != s32Ret){SAMPLE_PRT("vo bind vpss failed. s32Ret: 0x%x !\n", s32Ret);goto EXIT6;}

按回车设置VI镜头畸变校正。

    s32Ret = SAMPLE_COMM_VENC_StartGetStream(VencChn, sizeof(VencChn)/sizeof(VENC_CHN));if (HI_SUCCESS != s32Ret){SAMPLE_PRT("Get venc stream failed!\n");goto EXIT7;}printf("Press Enter key to Enable LDC!\n");getchar();stLDCAttr.bEnable = HI_TRUE;stLDCAttr.stAttr.bAspect = 0;stLDCAttr.stAttr.s32XRatio = 100;stLDCAttr.stAttr.s32YRatio = 100;stLDCAttr.stAttr.s32XYRatio = 100;stLDCAttr.stAttr.s32CenterXOffset = 0;stLDCAttr.stAttr.s32CenterYOffset = 0;stLDCAttr.stAttr.s32DistortionRatio = 500;s32Ret = HI_MPI_VI_SetChnLDCAttr(ViPipe, ViChn, &stLDCAttr);if (HI_SUCCESS != s32Ret){SAMPLE_PRT("HI_MPI_VI_SetChnLDCAttr failed witfh %d\n", s32Ret);goto EXIT8;}

按回车启动防抖动设置。

printf("Press Enter key to Enable DIS!\n");
getchar();stDISConfig.enMode              = DIS_MODE_6_DOF_GME;
stDISConfig.enMotionLevel       = DIS_MOTION_LEVEL_NORMAL;
stDISConfig.u32CropRatio        = 80;
stDISConfig.u32BufNum           = 5;
stDISConfig.enPdtType           = DIS_PDT_TYPE_IPC;
stDISConfig.u32GyroOutputRange  = 0;
stDISConfig.u32FrameRate        = 30;
stDISConfig.bScale              = HI_TRUE;
stDISConfig.bCameraSteady       = HI_FALSE;s32Ret = HI_MPI_VI_SetChnDISConfig(ViPipe, ViChn, &stDISConfig);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("HI_MPI_VI_SetChnDISConfig failed.s32Ret:0x%x !\n", s32Ret);goto EXIT5;
}stDISAttr.bEnable               = HI_TRUE;
stDISAttr.u32MovingSubjectLevel = 0;
stDISAttr.s32RollingShutterCoef = 0;
stDISAttr.u32ViewAngle          = 1000;
stDISAttr.bStillCrop            = HI_FALSE;
stDISAttr.u32HorizontalLimit    = 512;
stDISAttr.u32VerticalLimit      = 512;s32Ret = HI_MPI_VI_SetChnDISAttr(ViPipe, ViChn, &stDISAttr);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("HI_MPI_VI_SetChnDISAttr failed.s32Ret:0x%x !\n", s32Ret);goto EXIT5;
}

按回车开启VI通道展宽功能,展宽图像操作是为了使用户便于观察记录信息显示的细节情况而设立的,其功能与压缩图像相反,默认是最宽状态。

printf("Press Enter key to Enable Spread!\n");
getchar();stSpreadAttr.bEnable        = HI_TRUE;
stSpreadAttr.u32SpreadCoef  = 16;
stSpreadAttr.stDestSize.u32Width = 3840;
stSpreadAttr.stDestSize.u32Height = 2160;s32Ret = HI_MPI_VI_SetChnSpreadAttr(ViPipe, ViChn, &stSpreadAttr);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("HI_MPI_VI_SetChnSpreadAttr failed witfh %d\n", s32Ret);goto EXIT5;
}PAUSE();

4、SAMPLE_VIO_ViDoublePipeRoute

改函数配置2个PIPE,并且配置2个VPSS。

HI_S32 SAMPLE_VIO_ViDoublePipeRoute(HI_U32 u32VoIntfType)
{HI_S32             s32Ret;HI_S32             s32ViCnt       = 1;VI_DEV             ViDev          = 0;VI_PIPE            ViPipe[2]      = {0, 1};VI_CHN             ViChn          = 0;HI_S32             s32WorkSnsId   = 0;SAMPLE_VI_CONFIG_S stViConfig;SIZE_S             stSize;VB_CONFIG_S        stVbConf;PIC_SIZE_E         enPicSize;HI_U32             u32BlkSize;VO_CHN             VoChn          = 0;SAMPLE_VO_CONFIG_S stVoConfig;WDR_MODE_E         enWDRMode      = WDR_MODE_NONE;DYNAMIC_RANGE_E    enDynamicRange = DYNAMIC_RANGE_SDR8;PIXEL_FORMAT_E     enPixFormat    = PIXEL_FORMAT_YVU_SEMIPLANAR_420;VIDEO_FORMAT_E     enVideoFormat  = VIDEO_FORMAT_LINEAR;COMPRESS_MODE_E    enCompressMode = COMPRESS_MODE_NONE;VPSS_GRP           VpssGrp[2]     = {0, 1};VPSS_GRP_ATTR_S    stVpssGrpAttr;VPSS_CHN           VpssChn        = VPSS_CHN0;HI_BOOL            abChnEnable[VPSS_MAX_PHY_CHN_NUM] = {0};VPSS_CHN_ATTR_S    astVpssChnAttr[VPSS_MAX_PHY_CHN_NUM];VENC_CHN           VencChn[1]  = {0};PAYLOAD_TYPE_E     enType      = PT_H265;SAMPLE_RC_E        enRcMode    = SAMPLE_RC_CBR;HI_U32             u32Profile  = 0;VENC_GOP_ATTR_S    stGopAttr;

由于第0个PIPE配置为VI离线VPSS在线所以其他PIPE也必须配置为VI离线VPSS在线,在SAMPLE_COMM_VI_SetParam函数中可以看到该逻辑。

 /*config vi*/SAMPLE_COMM_VI_GetSensorInfo(&stViConfig);stViConfig.s32WorkingViNum                                   = s32ViCnt;stViConfig.as32WorkingViId[0]                                = 0;stViConfig.astViInfo[s32WorkSnsId].stSnsInfo.MipiDev         = ViDev;stViConfig.astViInfo[s32WorkSnsId].stDevInfo.ViDev           = ViDev;stViConfig.astViInfo[s32WorkSnsId].stDevInfo.enWDRMode       = enWDRMode;stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.enMastPipeMode = VI_OFFLINE_VPSS_ONLINE;stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.aPipe[0]       = ViPipe[0];stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.aPipe[1]       = ViPipe[1];stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.aPipe[2]       = -1;stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.aPipe[3]       = -1;stViConfig.astViInfo[s32WorkSnsId].stChnInfo.ViChn           = ViChn;stViConfig.astViInfo[s32WorkSnsId].stChnInfo.enPixFormat     = enPixFormat;stViConfig.astViInfo[s32WorkSnsId].stChnInfo.enDynamicRange  = enDynamicRange;stViConfig.astViInfo[s32WorkSnsId].stChnInfo.enVideoFormat   = enVideoFormat;stViConfig.astViInfo[s32WorkSnsId].stChnInfo.enCompressMode  = enCompressMode;stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.bMultiPipe     = HI_TRUE;

因为VPSS是在线模式所以不用绑定VI与VPSS,并且将VPSSGRP1绑定到编码器,VPSSGRP0绑定到VO输出

/*start vpss*/
abChnEnable[0] = HI_TRUE;
s32Ret = SAMPLE_COMM_VPSS_Start(VpssGrp[0], abChnEnable, &stVpssGrpAttr, astVpssChnAttr);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("start vpss group failed. s32Ret: 0x%x !\n", s32Ret);goto EXIT1;
}s32Ret = SAMPLE_COMM_VPSS_Start(VpssGrp[1], abChnEnable, &stVpssGrpAttr, astVpssChnAttr);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("start vpss group failed. s32Ret: 0x%x !\n", s32Ret);goto EXIT2;
}/*config venc */
stGopAttr.enGopMode  = VENC_GOPMODE_SMARTP;
stGopAttr.stSmartP.s32BgQpDelta  = 7;
stGopAttr.stSmartP.s32ViQpDelta  = 2;
stGopAttr.stSmartP.u32BgInterval = 1200;
s32Ret = SAMPLE_COMM_VENC_Start(VencChn[0], enType, enPicSize, enRcMode, u32Profile, &stGopAttr);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("start venc failed. s32Ret: 0x%x !\n", s32Ret);goto EXIT3;
}s32Ret = SAMPLE_COMM_VPSS_Bind_VENC(VpssGrp[1], VpssChn, VencChn[0]);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("Venc bind Vpss failed. s32Ret: 0x%x !n", s32Ret);goto EXIT4;
}
/*vpss bind vo*/
s32Ret = SAMPLE_COMM_VPSS_Bind_VO(VpssGrp[0], VpssChn, stVoConfig.VoDev, VoChn);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("vo bind vpss failed. s32Ret: 0x%x !\n", s32Ret);goto EXIT6;
}s32Ret = SAMPLE_COMM_VENC_StartGetStream(VencChn, sizeof(VencChn)/sizeof(VENC_CHN));
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("Get venc stream failed!\n");goto EXIT7;
}PAUSE();

5、SAMPLE_VIO_ViDoubleChnRoute

该函数配置双通道。

HI_S32 SAMPLE_VIO_ViDoubleChnRoute(HI_U32 u32VoIntfType)
{HI_S32             s32Ret;HI_S32             s32ViCnt       = 1;VI_DEV             ViDev          = 0;VI_PIPE            ViPipe         = 0;VI_CHN             ViChn[2]       = {0, 1};HI_S32             s32WorkSnsId   = 0;SAMPLE_VI_CONFIG_S stViConfig;VI_CHN_ATTR_S      stChnAttr;VI_EARLY_INTERRUPT_S stEarlyInterrupt;

将VPSS设置为离线模式,并且将VI通道0与VPSS绑定。

/*config vi*/
SAMPLE_COMM_VI_GetSensorInfo(&stViConfig);stViConfig.s32WorkingViNum                                   = s32ViCnt;
stViConfig.as32WorkingViId[0]                                = 0;
stViConfig.astViInfo[s32WorkSnsId].stSnsInfo.MipiDev         = ViDev;
stViConfig.astViInfo[s32WorkSnsId].stDevInfo.ViDev           = ViDev;
stViConfig.astViInfo[s32WorkSnsId].stDevInfo.enWDRMode       = enWDRMode;
stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.enMastPipeMode = VI_ONLINE_VPSS_OFFLINE;
stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.aPipe[0]       = ViPipe;
stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.aPipe[1]       = -1;
stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.aPipe[2]       = -1;
stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.aPipe[3]       = -1;
stViConfig.astViInfo[s32WorkSnsId].stChnInfo.ViChn           = ViChn[0];
stViConfig.astViInfo[s32WorkSnsId].stChnInfo.enPixFormat     = enPixFormat;
stViConfig.astViInfo[s32WorkSnsId].stChnInfo.enDynamicRange  = enDynamicRange;
stViConfig.astViInfo[s32WorkSnsId].stChnInfo.enVideoFormat   = enVideoFormat;
stViConfig.astViInfo[s32WorkSnsId].stChnInfo.enCompressMode  = enCompressMode;
/*vi bind vpss*/
s32Ret = SAMPLE_COMM_VI_Bind_VPSS(ViPipe, ViChn[0], VpssGrp);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("vi bind vpss failed. s32Ret: 0x%x !\n", s32Ret);goto EXIT2;
}

VI通道1配置提前上报中断,并且将VI通道1与VO进行绑定直接输出图像

/*start vi chn1*/
s32Ret = HI_MPI_VI_GetChnAttr(ViPipe, ViChn[0], &stChnAttr);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("HI_MPI_VI_GetChnAttr failed. s32Ret: 0x%x !\n", s32Ret);goto EXIT3;
}stChnAttr.stSize.u32Width = stSize.u32Width / 2;
stChnAttr.stSize.u32Height = stSize.u32Height / 2;s32Ret = HI_MPI_VI_SetChnAttr(ViPipe, ViChn[1], &stChnAttr);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("HI_MPI_VI_GetChnAttr failed. s32Ret: 0x%x !\n", s32Ret);goto EXIT3;
}stEarlyInterrupt.bEnable = HI_TRUE;
stEarlyInterrupt.u32LineCnt = stChnAttr.stSize.u32Height / 2;
s32Ret = HI_MPI_VI_SetChnEarlyInterrupt(ViPipe, ViChn[1], &stEarlyInterrupt);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("HI_MPI_VI_SetChnEarlyInterrupt failed. s32Ret: 0x%x !\n", s32Ret);goto EXIT3;
}s32Ret = HI_MPI_VI_EnableChn(ViPipe, ViChn[1]);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("HI_MPI_VI_EnableChn failed. s32Ret: 0x%x !\n", s32Ret);goto EXIT3;
}
/*vpss bind vo*/
s32Ret = SAMPLE_COMM_VI_Bind_VO(ViPipe, ViChn[1], stVoConfig.VoDev, VoChn);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("vo bind vpss failed. s32Ret: 0x%x !\n", s32Ret);goto EXIT7;
}s32Ret = SAMPLE_COMM_VENC_StartGetStream(VencChn, sizeof(VencChn)/sizeof(VENC_CHN));
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("Get venc stream failed!\n");goto EXIT8;
}PAUSE();

6、SAMPLE_VIO_ViWdrSwitch

该函数只是在最后添加切换到2帧合成行WDR模式,需要设置两个PIPE。

printf("switch to wdr mode========\n");
getchar();SAMPLE_COMM_VPSS_Stop(VpssGrp, abChnEnable);
SAMPLE_COMM_VI_SwitchMode_StopVI(&stViConfig);if (SONY_IMX290_MIPI_2M_30FPS_12BIT == stViConfig.astViInfo[s32WorkSnsId].stSnsInfo.enSnsType)
{stViConfig.astViInfo[s32WorkSnsId].stSnsInfo.enSnsType = SONY_IMX290_MIPI_2M_30FPS_12BIT_WDR2TO1;
}
else if (SONY_IMX334_MIPI_8M_30FPS_12BIT == stViConfig.astViInfo[s32WorkSnsId].stSnsInfo.enSnsType)
{stViConfig.astViInfo[s32WorkSnsId].stSnsInfo.enSnsType = SONY_IMX334_MIPI_8M_30FPS_12BIT_WDR2TO1;
}stViConfig.astViInfo[s32WorkSnsId].stDevInfo.enWDRMode = WDR_MODE_2To1_LINE;
stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.aPipe[0]       = ViPipe;
stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.aPipe[1]       = 1;SAMPLE_COMM_VI_SwitchMode(&stViConfig);s32Ret = SAMPLE_COMM_VPSS_Start(VpssGrp, abChnEnable, &stVpssGrpAttr, astVpssChnAttr);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("start vpss group failed. s32Ret: 0x%x !\n", s32Ret);goto EXIT8;
}

再重新切换回线性模式,只需要一个PIPE。

printf("switch to linear mode========\n");
getchar();SAMPLE_COMM_VPSS_Stop(VpssGrp, abChnEnable);
SAMPLE_COMM_VI_SwitchMode_StopVI(&stViConfig);stViConfig.astViInfo[s32WorkSnsId].stSnsInfo.enSnsType = SENSOR0_TYPE;
stViConfig.astViInfo[s32WorkSnsId].stDevInfo.enWDRMode = WDR_MODE_NONE;
stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.aPipe[0]       = ViPipe;
stViConfig.astViInfo[s32WorkSnsId].stPipeInfo.aPipe[1]       = -1;SAMPLE_COMM_VI_SwitchMode(&stViConfig);
s32Ret = SAMPLE_COMM_VPSS_Start(VpssGrp, abChnEnable, &stVpssGrpAttr, astVpssChnAttr);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("start vpss group failed. s32Ret: 0x%x !\n", s32Ret);goto EXIT8;
}PAUSE();

7、SAMPLE_VIO_ViVpssLowDelay

该函数只是增加设置VI镜头畸变校正并按回车设置低延时,低延时指图像写出指定的行数到 DDR 后,VI上报一个中断,把图像发给后端模块处理,可以减少延时,且硬件会有机制保证图像是先写后读,不会出现读图像错误。

stLDCAttr.bEnable = HI_TRUE;
stLDCAttr.stAttr.bAspect = 0;
stLDCAttr.stAttr.s32XRatio = 100;
stLDCAttr.stAttr.s32YRatio = 100;
stLDCAttr.stAttr.s32XYRatio = 100;
stLDCAttr.stAttr.s32CenterXOffset = 0;
stLDCAttr.stAttr.s32CenterYOffset = 0;
stLDCAttr.stAttr.s32DistortionRatio = 500;
s32Ret = HI_MPI_VI_SetChnLDCAttr(ViPipe, ViChn, &stLDCAttr);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("HI_MPI_VI_SetChnLDCAttr failed witfh %d\n", s32Ret);goto EXIT8;
}printf("Press Enter key to Enable LowDelay!\n");
getchar();stLowDelayInfo.bEnable = HI_TRUE;
stLowDelayInfo.u32LineCnt = stSize.u32Height / 2;
HI_MPI_VI_SetChnLowDelayAttr(ViPipe, ViChn, &stLowDelayInfo);
if (HI_SUCCESS != s32Ret)
{SAMPLE_PRT("HI_MPI_VI_SetChnLowDelayAttr failed witfh %d\n", s32Ret);goto EXIT8;
}PAUSE();

8、小结:

剩下的几个功能大体流程都相识,只是增加调用了几个关于像低延时、旋转这样的接口使用示例,虽然海思的sample例程比较粗糙,但上手的话还是可以基于sample进行开发,思路还是在sample了解与《HiMPP V4.0 媒体处理软件开发参考》查找相关说明。

注:感谢博主工藤_新一的整理,本文参考解析sample例程学习官方API:解析VIO Sample例程,如有侵权,请及时联系小编,小编会及时删除的。


http://chatgpt.dhexx.cn/article/9b60Vjh7.shtml

相关文章

PL-VIO论文阅读

PL-VIO: Tightly-Coupled Monocular Visual–Inertial Odometry Using Point and Line Features Yijia He 1,2,* , Ji Zhao 3, Yue Guo 1,2, Wenhao He 1 and Kui Yuan 1 2018 摘要 To address the problem of estimating camera trajectory and to build a structural 3D m…

DM-VIO简析

今天主要是针对DMVIO/DM-VIO的简析&#xff0c;中文网上有的东西都太少了&#xff0c;只能靠看完论文和组员们一起改代码。Lukas组这个东西在中文网被称为有史以来最好的VIO&#xff0c;但是实际过程中我们还是发现了许多不完美的地方。。。(比如ZUPT更新改造中该有的问题仍然在…

VIOSLAM 综述

文章目录 1.VIO 松耦合/紧耦合。2. 相机和IMU的缺点及互补性3. VIO融合算法流程及其模块分解:4. VIO 算法核心:5. 实验结果与总结:6. 参考文献: 1.VIO 松耦合/紧耦合。 Visual-Inertial Odometry&#xff08;VIO&#xff09;即视觉惯性里程计&#xff0c;有时也叫视觉惯性系统…

VIO系统介绍

VIO&#xff08;visual-inertial odometry&#xff09;即视觉惯性里程计&#xff0c;有时也叫视觉惯性系统&#xff08;VINS&#xff0c;visual-inertial system&#xff09;&#xff0c;是融合相机和IMU数据实现SLAM的算法&#xff0c;根据融合框架的区别又分为紧耦合和松耦合…

vivado VIO (virtual input output)虚拟IO的使用

转自&#xff1a;https://blog.csdn.net/wordwarwordwar/article/details/77150930 一般情况下ILA和VIO都是用在chipscope上使用&#xff0c;VIO可以作为在chipscope时模拟IO。 譬如&#xff1a; 在使用chipscope时需要使用按键出发&#xff0c;但是没有设计按键或者板子不再身…

【Vivado那些事儿】-VIO原理及应用

虚拟输入输出&#xff08;Virtual Input Output,VIO)核是一个可定制的IP核&#xff0c;它可用于实时监视和驱动内部FPGA的信号&#xff0c;如图所示。 可以定制VIO的输入和输出端口的数量与宽度&#xff0c;用于和FPGA设计进行连接。由于VIO核与被监视和驱动的设计同步&#xf…

python logger.exception_Python logging设置和logger解析

一、logging模块讲解 1.函数:logging.basicConfig() 参数讲解: (1)level代表高于或者等于这个值时,那么我们才会记录这条日志 (2)filename代表日志会写在这个文件之中,如果没有这个字段则会显示在控制台上 (3)format代表我们的日志显示的格式自定义,如果字段为空,那么默认…

Logger 基本用法

Logger 基本用法 简介 Simple, pretty and powerful logger for android 为Android提供的&#xff0c;简单、强大而且格式美观的工具 本质就是封装系统提供的Log类&#xff0c;加上一些分割线易于查找不同的Log&#xff1b;logcat中显示的信息可配置。最初的样子如下图 包含…

【Logback】<logger>、<root>标签详解

文章目录 背景一、\<logger>使用1.1、使用示例1.1、属性配置说明 & 演示1.1.1、name1.1.2、level1.1.3、additivity1.1.3.1、效果演示&#xff1a;additivitytrue1.1.3.1、效果演示&#xff1a;additivity"false" 1.2 appender-ref 二、\<root>使用2…

python之logger

import logging import os.path import time def test_log():"""指定保存日志的文件路径&#xff0c;日志级别&#xff0c;以及调用文件将日志存入到指定的文件中:paramlogger:"""# 创建一个loggerlogger logging.getLogger()logger.setLevel(l…

Python中logger日志模块详解

1 logging模块简介 logging模块是Python内置的标准模块&#xff0c;主要用于输出运行日志&#xff0c;可以设置输出日志的等级、日志保存路径、日志文件回滚等&#xff1b;相比print&#xff0c;具备如下优点&#xff1a; 可以通过设置不同的日志等级&#xff0c;在release版…

logger:一款管理日志的Python神器

最近要新开一个项目&#xff0c;需要配个 logger 来管理日志&#xff0c;今天分享一下&#xff0c;喜欢记得点赞、关注、收藏。 【注】文末提供交流互助群 import logging ori_logger logging.getLogger(custom_logger) ori_logger.setLevel(logging.INFO) ori_logger.addHa…

Tensorboard + Logger 日志记录

在Pytorch 训练模型的时候&#xff0c;需要日志帮助开发者记录些重要信息和参数&#xff0c;以方便开发者更好的调节模型及参数&#xff0c;常见的日志非 Tensorboard不可&#xff0c;但是Pytorch 对 Tensorboard 的支持不是十分完美&#xff0c;在记录模型重要参数时 Tensorbo…

深入理解 rootLogger、logLogger、qtLogger

作者: 一去、二三里个人微信号: iwaleon微信公众号: 高效程序员 在使用 Log4Qt 时,你会发现有一系列的 logger - rootLogger()、logLogger()、qtLogger(),简直傻傻分不清楚! 为什么会有这么多 logger? 各 logger 之间有什么关系? 它们均适用于哪种场景? 参考文档对这部…

logger 报错

logger 报错&#xff1a;&#xff08;log4j 起不来&#xff0c;log message打不出来&#xff09; No appenders could be found for logger (com.vip.qa.android.base.DriverFactory). log4j:WARN Please initialize the log4j system properly. 原因&#xff1a; log4j.prop…

java的logger_java.util.logging.Logger 使用详解

概述: 第1部分 创建Logger对象 要使用J2SE的日志功能,首先要取得java.util.logging.Logger实例,这可以通过Logger类的两个静态getLogger()方法来取得: staticLogger getLogger(String name) 查找或创建一个logger。staticLogger getLogger(String name, String resourceBun…

Logger日志使用教程

Java util Logger的使用步骤 Java util Logger是java原生的日志生成工具&#xff0c;不需要另外引用类库&#xff0c;使用方便&#xff0c;学习简单&#xff0c;能够在小型应用中灵活使用。下面从实际应用角度&#xff0c;对Logger的使用步骤作出总结&#xff0c;以实现快速掌握…

Logger 日志管理

转载请注明出处&#xff1a; http://blog.csdn.net/like_program/article/details/52986553 1.Logger 是什么 在我们日常的开发中&#xff0c;肯定是少不了要和 Log 打交道&#xff0c;回想一下我们是怎么使用 Log 的&#xff1a;先定义一个静态常量 TAG&#xff0c;TAG 的值通…

【转】最详细的Log4J使用教程一、入门实例二、Log4J基本使用方法三、Spring中使用Log4J四、实战经验总结

原文地址&#xff1a;http://www.codeceo.com/article/log4j-usage.html 日志是应用软件中不可缺少的部分&#xff0c;Apache的开源项目log4j是一个功能强大的日志组件,提供方便的日志记录。在apache网站&#xff1a;jakarta.apache.org/log4j可以免费下载到Log4j最新版本的软…

Logger打印日志

1. 一个最基本的例子 使用Logging框架写Log基本上就三个步骤 引入loggerg类和logger工厂类声明logger记录日志 下面看一个例子 // 1. 引入slf4j接口的Logger和LoggerFactory import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class UserService { // 2. 声明…