Hi3518E官方录像例程源码流程分析(三)
文章目录
- 第二阶段,初始化第一阶段计算好的参数
- SAMPLE_COMM_SYS_Init
- 第三阶段,启动VI和chn捕获
- SAMPLE_COMM_VI_StartVi()
- SAMPLE_COMM_VI_StartBT656
- 小阶段1 SAMPLE_COMM_VI_StartMIPI_BT1120()
- 小阶段1 SAMPLE_COMM_VI_StartDev()
- HI_MPI_ISP_GetWDRMode
- HI_MPI_VI_SetWDRAttr
- HI_MPI_VI_EnableDev
- 小阶段二 配置和启动VI捕获通道
- SAMPLE_COMM_VI_StartChn()
- HI_MPI_VI_SetRotate
- HI_MPI_VI_EnableChn
源码地址 + 文档资料 – 提取码: chmr
本专栏分析的是mpp\venc\sample\sample_venc.c
第二阶段,初始化第一阶段计算好的参数
/******************************************step 2: mpp system init. ******************************************/s32Ret = SAMPLE_COMM_SYS_Init(&stVbConf);//VB_CONF_S stVbConf;if (HI_SUCCESS != s32Ret){SAMPLE_PRT("system init failed with %d!\n", s32Ret);goto END_VENC_1080P_CLASSIC_0;}
第二阶段的内容还是很简单的,就是把第一阶段计算好的参数都初始化进系统
SAMPLE_COMM_SYS_Init
先是函数SAMPLE_COMM_SYS_Init
里面的内容也很简单,调用到的函数都是海思官方提供的库函数,我们也没办法看到函数的内部实现,在我给的链接里也有官方的数据手册,里面也有写每个API都是干嘛的
MPP_SYS_CONF_S stSysConf = {0};HI_S32 s32Ret = HI_FAILURE;//In case there are things left behind before that have not been cleaned up.HI_MPI_SYS_Exit();//firstHI_MPI_VB_Exit(); //lastif (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 failed\n");return HI_FAILURE;}s32Ret = HI_MPI_SYS_Init();if (HI_SUCCESS != s32Ret){SAMPLE_PRT("HI_MPI_SYS_Init failed!\n");return HI_FAILURE;}
这里进来先是调用了两个清理函数
HI_MPI_SYS_Exit();//firstHI_MPI_VB_Exit(); //last
应该是用来防止之前留下的内容没被清理或释放
然后再需要注意一下的就是函数的调用顺序
先清理SYS空间,再是VB(缓存池)
后面的函数是用来设置第一阶段计算好的参数和缓存池,调用顺序是先设置VB,再是SYS
第二阶段的内容就这些,比较简单
第三阶段,启动VI和chn捕获
视频输入(VI)模块实现的功能:VI 可以对接收到的原始视频图像数据进行裁剪(Crop)等处理,并实现一路原始视频图像输入,输出一路视频图像功能。
虽然阶段三看着只有一个函数,但是里面的内容就多了
/******************************************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);if (HI_SUCCESS != s32Ret){SAMPLE_PRT("start vi failed!\n");goto END_VENC_1080P_CLASSIC_1;}
第三阶段前面先是设置了一些视频参数
stViConfig.enViMode = SENSOR_TYPE;这个是传感器类型,前面提到过的我用的传感器是AR0130
stViConfig.enRotate = ROTATE_NONE;这个参数决定了输出的视频是否需要旋转,如输出的视频是原视频旋转90度或180度这种
stViConfig.enNorm = VIDEO_ENCODING_MODE_AUTO;这个再上一章节也有提到,就是PAL和NTSC两种格式,这里选的是AUTO自动选择
stViConfig.enViChnSet = VI_CHN_SET_NORMAL;这个参数决定输出的视频是否翻转或镜像
stViConfig.enWDRMode = WDR_MODE_NONE;WDR(Wide Dynamic Range),宽动态
SAMPLE_COMM_VI_StartVi()
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;//Determine whether the image source is a sensorif(!IsSensorInput(enViMode)){s32Ret = SAMPLE_COMM_VI_StartBT656(pstViConfig);}else{ //sansor choices32Ret = SAMPLE_COMM_VI_StartIspAndVi(pstViConfig);}return s32Ret;
}
进来以后会先进入这个if判断
这里面就是判断是否支持之前定义过的视频格式
if(!IsSensorInput(enViMode)){........}IsSensorInput()
{switch(enViMode){case SAMPLE_VI_MODE_1_D1:case SAMPLE_VI_MODE_BT1120_1080P:case SAMPLE_VI_MODE_BT1120_720P:bRet = HI_FALSE;break;default:break;}
}
然后我们命中到这个函数
SAMPLE_COMM_VI_StartBT656
这里面的内容就多了
VI_DEV ViDev;VI_CHN ViChn;HI_U32 u32DevNum = 1;HI_U32 u32ChnNum = 1;
进来先是设备数和通道数初始化
小阶段1 SAMPLE_COMM_VI_StartMIPI_BT1120()
HI_S32 SAMPLE_COMM_VI_StartMIPI_BT1120(SAMPLE_VI_MODE_E enViMode)
{HI_S32 fd;combo_dev_attr_t *pstcomboDevAttr = NULL;fd = open("/dev/hi_mipi", O_RDWR);if (fd < 0){printf("warning: open hi_mipi dev failed\n");return -1;}if( (enViMode == SAMPLE_VI_MODE_BT1120_720P)||(enViMode == SAMPLE_VI_MODE_BT1120_1080P) ){pstcomboDevAttr = &MIPI_BT1120_ATTR;}else{}if (NULL == pstcomboDevAttr){printf("Func %s() Line[%d], unsupported enViMode: %d\n", __FUNCTION__, __LINE__, enViMode);close(fd);return HI_FAILURE; }if (ioctl(fd, HI_MIPI_SET_DEV_ATTR, pstcomboDevAttr)){printf("set mipi attr failed\n");close(fd);return HI_FAILURE;}close(fd);return HI_SUCCESS;
}
这里面就是打开vi驱动设备了
fd = open("/dev/hi_mipi", O_RDWR);
ioctl(fd, HI_MIPI_SET_DEV_ATTR, pstcomboDevAttr)
打开设备以后在根据设备数量启动设备
由手册可知Hi3518EV200只有一个vi设备
小阶段1 SAMPLE_COMM_VI_StartDev()
进来先是开辟内存空间?
根据我的传感器会定位到这个
case APTINA_AR0130_DC_720P_30FPS:memcpy(&stViDevAttr,&DEV_ATTR_9M034_DC_720P_BASE,sizeof(stViDevAttr));break;
然后就是把前面设置的参数真正写入硬件处理,调用到的也是海思官方提供的库函数
就是之前这些
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;
然后是海思官方的宽动态(WDR)设置
HI_MPI_ISP_GetWDRMode
HI_MPI_VI_SetWDRAttr
设备启动
HI_MPI_VI_EnableDev
小阶段二 配置和启动VI捕获通道
由手册得3518EV支持一个物理通道和两个扩展通道
视频物理通道负责将输入设备解析后得到的视频数据输出到 DDR。在真正将数据
输出到 DDR 之前,它可以实现裁剪等功能,
扩展通道是物理通道的扩展,主要实现缩放功能,其数据来源于物理通道。
Hi3516A/Hi3518EV200/Hi3519V100 最多支持 16 个扩展通道。
物理通道Chn0和扩展通道Chn1,Chn2
阶段二先是对各个通道输出的视频尺寸大小做了设置
switch (enViMode){case SAMPLE_VI_MODE_BT1120_720P: stCapRect.u32Width = 1280;stCapRect.u32Height = 720;break;case SAMPLE_VI_MODE_BT1120_1080P: stCapRect.u32Width = 1920;stCapRect.u32Height = 1080;break; default:stCapRect.u32Width = 1920;stCapRect.u32Height = 1080;break;}
然后进入这个函数
SAMPLE_COMM_VI_StartChn()
进来以后就是设置每个通道输出的视频的大小,是否旋转,是否镜像,是否翻转,是什么格式YUV420 \ 422
if(pstViConfig){enViChnSet = pstViConfig->enViChnSet;enRotate = pstViConfig->enRotate;}/* step 5: config & start vicap dev */memcpy(&stChnAttr.stCapRect, pstCapRect, sizeof(RECT_S));stChnAttr.enCapSel = VI_CAPSEL_BOTH;/* to show scale. this is a sample only, we want to show dist_size = D1 only */stChnAttr.stDestSize.u32Width = pstTarSize->u32Width;stChnAttr.stDestSize.u32Height = pstTarSize->u32Height;stChnAttr.enPixFormat = PIXEL_FORMAT_YUV_SEMIPLANAR_420; /* sp420 or sp422 */stChnAttr.bMirror = HI_FALSE;stChnAttr.bFlip = HI_FALSE;switch(enViChnSet){case VI_CHN_SET_MIRROR:stChnAttr.bMirror = HI_TRUE;break;case VI_CHN_SET_FLIP:stChnAttr.bFlip = HI_TRUE;break;case VI_CHN_SET_FLIP_MIRROR:stChnAttr.bMirror = HI_TRUE;stChnAttr.bFlip = HI_TRUE;break;default:break;}
默认的帧率控制
stChnAttr.s32SrcFrameRate = -1;stChnAttr.s32DstFrameRate = -1;
然后是海思的设置通道参数的库函数
HI_MPI_VI_SetRotate
打开通道