• 海思3559 sample解析:vio


    前言

      拿到开发板,编完了平台sample,自然按捺不住要去简单学习测试了。打开最直观相对也比较简单的vio例程做个到手分析和流程梳理吧

    测试

      一开始自然是最磕磕绊绊的,连上HDMI线,串口登录后运行,屏幕乌漆嘛黑,尝试了几个参数后怀疑是不是线有问题或者哪里配置不对,就打开了snap例程,毕竟显示不了咱保存下来也是一样的看嘛
    在这里插入图片描述
      可惜还是没有半点反应,触发拍照超时,那就只能是sample之前的配置就有问题了呗
    完整的分析一下平台搭建后的流程

    Makefile

    makefile.param文件中首先需要将传感器型号选对,根绝自己所用传感器的型号进行选择(然后加载的时候好像不论加载参数选择哪个都不会报错,在viodemo里都会运行正常)
    在这里插入图片描述
      接下来开始分析vio的sample

    整体框架:

      vio中的main调用vio中的功能函数,再调用common中的功能函数,再调用mpp中的API,再调用HI3559E内部的硬件单元。

    main

      先从main函数开始看起:

    int main(int argc, char* argv[])
    #endif
    {
        HI_S32 s32Ret = HI_FAILURE;
        HI_S32 s32Index;
        VO_INTF_TYPE_E enVoIntfType = VO_INTF_HDMI;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

     if (argc < 2)
        {
            SAMPLE_VIO_Usage(argv[0]);
            return HI_FAILURE;
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

    #ifdef __HuaweiLite__
    #else
        signal(SIGINT, SAMPLE_VIO_HandleSig);
        signal(SIGTERM, SAMPLE_VIO_HandleSig);
    #endif
    
        if ((argc > 2) && (1 == atoi(argv[2])))
        {
            enVoIntfType = VO_INTF_BT1120;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

      然后开始选择工作模式

    switch (s32Index)
        {
            case 0:
                s32Ret = SAMPLE_VIO_8K30_PARALLEL(enVoIntfType);
                break;
    
            case 1:
                s32Ret = SAMPLE_VIO_2X4K60_TotalOnline(enVoIntfType);
                break;
    
            case 2:
                s32Ret = SAMPLE_VIO_4x4K30_WBC(enVoIntfType);
                break;
    
            case 3:
                s32Ret = SAMPLE_VIO_4K30_WDR_HDR10(enVoIntfType);
                break;
    
            case 4:
                s32Ret = SAMPLE_VIO_4K30_LDC_ROTATE(enVoIntfType);
                break;
    
            case 5:
                s32Ret = SAMPLE_VIO_4K30_FreeRotation(enVoIntfType);
                break;
    
            case 6:
                s32Ret = SAMPLE_VIO_4K30_LDC_SPREAD(enVoIntfType);
                break;
    
            default:
                SAMPLE_PRT("the index %d is invaild!\n",s32Index);
                SAMPLE_VIO_Usage(argv[0]);
                return HI_FAILURE;
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    SAMPLE_VIO_8K30_PARALLEL

      以第一种模式8k,30帧为例(摄像头应该没有8k),其他配置都是根据自己实际需求

    参数初始化

      每个参数的功能均配上了中文备注

    HI_S32                  s32Ret              = HI_SUCCESS;
        VI_DEV                  ViDev0              = 0;                                              //VI配置为设备号0
        VI_PIPE                 ViPipe0             = 0;                                              //VI配置为物理PIPE号0
        VI_CHN                  ViChn               = 0;                                              //VI配置通道号0
        HI_S32                  s32ViCnt            = 1;                                              //VI配置为单个sensor
        VPSS_GRP                VpssGrp0            = 0;                                              //VPSS GROUP 号0
        VPSS_CHN                VpssChn[4]          = {VPSS_CHN0, VPSS_CHN1, VPSS_CHN2, VPSS_CHN3};   //VPSS 通道号
        VPSS_GRP_ATTR_S         stVpssGrpAttr       = {0};
        VPSS_CHN_ATTR_S         stVpssChnAttr[VPSS_MAX_PHY_CHN_NUM];                                  //VPSS物理通道属性
        HI_BOOL                 abChnEnable[VPSS_MAX_PHY_CHN_NUM] = {0};
        VO_DEV                  VoDev               = SAMPLE_VO_DEV_DHD0;
        VO_CHN                  VoChn               = 0;                                              //VO配置视频输出通道号0
        VO_INTF_SYNC_E          g_enIntfSync        = VO_OUTPUT_3840x2160_30;
        HI_U32                  g_u32DisBufLen      = 3;
        PIC_SIZE_E              enPicSize           = PIC_3840x2160;
        WDR_MODE_E              enWDRMode           = WDR_MODE_NONE;                                  //WDR 工作模式,分为帧模式、行模式、非WDR
        DYNAMIC_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;                             //视频压缩数据格式,非压缩
        VI_VPSS_MODE_E          enMastPipeMode      = VI_PARALLEL_VPSS_PARALLEL;                      //定义 VI PIPE 和 VPSS 组的工作模式:VI 并行,VPSS 并行。
        SIZE_S                  stSize;
        HI_U32                  u32BlkSize;
        VB_CONFIG_S             stVbConf;                                                             //定义视频缓存池属性结构体
        SAMPLE_VI_CONFIG_S      stViConfig;
        SAMPLE_VO_CONFIG_S      stVoConfig;
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    第一步:获取所有传感器信息,

      这个例子中需要一个vi和一个mipi

    
        /************************************************
        step 1:  Get all sensors information, need one vi
            ,and need one mipi --
        *************************************************/
        SAMPLE_COMM_VI_GetSensorInfo(&stViConfig);
        stViConfig.s32WorkingViNum                           = s32ViCnt;
    
        stViConfig.as32WorkingViId[0]                        = 0;
        stViConfig.astViInfo[0].stSnsInfo.MipiDev            = SAMPLE_COMM_VI_GetComboDevBySensor(stViConfig.astViInfo[0].stSnsInfo.enSnsType, 0);
        stViConfig.astViInfo[0].stSnsInfo.s32BusId           = 0;
    
        stViConfig.astViInfo[0].stDevInfo.ViDev              = ViDev0;
        stViConfig.astViInfo[0].stDevInfo.enWDRMode          = enWDRMode;
    
        stViConfig.astViInfo[0].stPipeInfo.enMastPipeMode    = enMastPipeMode;                          //VI和VPSS均是并行模式
        stViConfig.astViInfo[0].stPipeInfo.aPipe[0]          = ViPipe0;
        stViConfig.astViInfo[0].stPipeInfo.aPipe[1]          = -1;
        stViConfig.astViInfo[0].stPipeInfo.aPipe[2]          = -1;
        stViConfig.astViInfo[0].stPipeInfo.aPipe[3]          = -1;
    
        stViConfig.astViInfo[0].stChnInfo.ViChn              = ViChn;
        stViConfig.astViInfo[0].stChnInfo.enPixFormat        = enPixFormat;
        stViConfig.astViInfo[0].stChnInfo.enDynamicRange     = enDynamicRange;
        stViConfig.astViInfo[0].stChnInfo.enVideoFormat      = enVideoFormat;
        stViConfig.astViInfo[0].stChnInfo.enCompressMode     = enCompressMode;
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    SAMPLE_COMM_VI_GetSensorInfo

      因为很多sample需要调用同样的配置,所以海思将一些通用的接口都放在SAMPLE_COMM_XXX接口中,这里Sensor配置在下面的注释部分有说明,Hi3559AV100的VI设备最多支持8个,不同的芯片型号支持的不一样,可以具体阅读《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;
    
            memset_s(&pstViConfig->astViInfo[i].stSnapInfo, sizeof(SAMPLE_SNAP_INFO_S), 0, sizeof(SAMPLE_SNAP_INFO_S));
        }
    
        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;
    
        pstViConfig->astViInfo[5].stSnsInfo.enSnsType = SENSOR5_TYPE;
    
        pstViConfig->astViInfo[6].stSnsInfo.enSnsType = SENSOR6_TYPE;
    
        pstViConfig->astViInfo[7].stSnsInfo.enSnsType = SENSOR7_TYPE;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

      入参结构体hiSAMPLE_VI_CONFIG_S

    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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    typedef enum hiSAMPLE_SNS_TYPE_E
    {
        SONY_IMX477_MIPI_12M_30FPS_12BIT,
        SONY_IMX477_MIPI_9M_50FPS_10BIT,
        SONY_IMX477_MIPI_9M_60FPS_10BIT,
        SONY_IMX477_MIPI_8M_60FPS_12BIT,
        SONY_IMX477_MIPI_8M_30FPS_12BIT,
        SONY_IMX290_MIPI_2M_30FPS_12BIT,
        SONY_IMX290_MIPI_2M_30FPS_12BIT_WDR3TO1,
        SONY_IMX334_SLAVE_MIPI_8M_30FPS_12BIT,
        SONY_IMX334_MIPI_8M_30FPS_12BIT,
        SONY_IMX334_MIPI_8M_30FPS_12BIT_WDR2TO1,
        SONY_IMX277_SLVS_8M_120FPS_10BIT,
        SONY_IMX277_SLVS_8M_30FPS_12BIT,
        SONY_IMX277_SLVS_8M_60FPS_12BIT,
        SONY_IMX277_SLVS_12M_30FPS_12BIT,
        SONY_IMX277_SLVS_2M_240FPS_12BIT,
        COMSIS_SHARP8K_SLVDS_8K_30FPS_12BIT,
        SAMPLE_SNS_TYPE_BUTT,
    } SAMPLE_SNS_TYPE_E;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

      再然后就会发现结构体一层套着一层,还是比较复杂的,只能根据具体情况具体做修改了

    工作模式的含义可以具体看下表

    模式VI_CAP 与 VI_PROCVI_PROC 与 VPSS
    在线模式VI_CAP 与 VI_PROC 之间在线数据流传输,此模式下 VI_CAP不会写出 RAW 数据到 DDR,而是直接把数据流送给VI_PROC。VI_PROC 与 VPSS 之间的在线数据流传输,在此模式下 VI_PROC不会写出 YUV 数据到 DDR,而是直接把数据流送给 VPSS
    离线模式VI_CAP 写出 RAW 数据到DDR,然后 VI_PROC 从 DDR读取 RAW 数据进行后处理。VI_PROC 写出 YUV 数据到DDR,然后 VPSS 从 DDR 读取YUV 数据进行后处理。
    并行模式当对接大数据量的时序,例如8K@30fps 时,需要 VI_CAP 与两个 VI_PROC 处于并行模式,VI_CAP 直接把一帧数据送给两个 VI_PROC 并行处理当对接大数据量的时序,例如8K@30fps 时,需要 VI_CAP 与两个 VI_PROC 处于并行模式,同时两个 VPSS 也分别与VI_PROC 处于并行模式,VI_CAP 直接把一帧数据送给两个 VI_PROC 并行处理,再给VPSS 并行处理。

    第二步 :获取输入大小

    /************************************************
        step 2:  Get  input size
        *************************************************/
        s32Ret = SAMPLE_COMM_VI_GetSizeBySensor(stViConfig.astViInfo[0].stSnsInfo.enSnsType, &enPicSize);
    
        if (HI_SUCCESS != s32Ret)
        {
            SAMPLE_PRT("SAMPLE_COMM_VI_GetSizeBySensor failed with %d!\n", s32Ret);
            return s32Ret;
        }
    
        s32Ret = SAMPLE_COMM_SYS_GetPicSize(enPicSize, &stSize);
    
        if (HI_SUCCESS != s32Ret)
        {
            SAMPLE_PRT("SAMPLE_COMM_SYS_GetPicSize failed with %d!\n", s32Ret);
            return s32Ret;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

      主要涉及两个重要函数

    HI_S32 SAMPLE_COMM_VI_GetSizeBySensor(SAMPLE_SNS_TYPE_E enMode, PIC_SIZE_E* penSize)
    
    • 1

      该函数主要switch了入参1enMode,从而对参数2penSize赋值

    HI_S32 SAMPLE_COMM_SYS_GetPicSize(PIC_SIZE_E enPicSize, SIZE_S* pstSize)
    
    • 1

      该函数则又根据赋值好的的enPicSize进行switch再对结构体pstSize的高和宽进行赋值

    第三步:初始化系统并对VB进行配置

     /************************************************
        step3:  Init SYS and common VB
        *************************************************/
        memset_s(&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_10, 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;
    
        s32Ret = SAMPLE_COMM_SYS_Init(&stVbConf);
    
        if (HI_SUCCESS != s32Ret)
        {
            SAMPLE_PRT("system init failed with %d!\n", s32Ret);
            goto EXIT;
        }
    
        s32Ret = SAMPLE_COMM_VI_SetParam(&stViConfig);
    
        if (HI_SUCCESS != s32Ret)
        {
            SAMPLE_PRT("SAMPLE_COMM_VI_SetParam failed with %d!\n", s32Ret);
            goto EXIT;
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

      这两步会根据不同Sensor类型的图片大小分配缓存,这里配置VI写出RAW的缓存块为4块,YUV缓存块10块,可以在下面的最后几行赋值看到10和4,数据结构u32BlkCnt可以在MIPP媒体软件开发参考里面查到(u16)。
      COMMON_GetPicBufferSize一般 linear 格式的 YUV 缓存池的大小计算函数
      VI_GetRawBufferSize是VI 写出的 Raw 数据缓存池大小的计算函数
    在这里插入图片描述
      在启动各个模块之前自然必须要对MPP系统进行初始化。
    在这里插入图片描述
      跳转进初始化函数,应该是为了防止其它进程已经使用MPP需要对其进行去初始化,然后根据之前VB的配置进行设置MPP 视频缓存池属性,初始化 MPP 视频缓存池,初始化 MPP 系统。分别对应了下面的三个函数

    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");
            return HI_FAILURE;
        }
    
        return HI_SUCCESS;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

      函数SAMPLE_COMM_VI_SetParam主要操作了内部函数用以获取 VI,VPSS 的工作模式。设置 VI,VPSS 工作模式

    第四步:启动vi

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

    /************************************************
        step 4: start VI
        *************************************************/
        s32Ret = SAMPLE_COMM_VI_StartVi(&stViConfig);
    
        if (HI_SUCCESS != s32Ret)
        {
            SAMPLE_PRT("SAMPLE_COMM_VI_StartVi failed with %d!\n", s32Ret);
            goto EXIT3;
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    第五步:启动vpss

    
        /************************************************
        step 5: start VPSS, need one grp
        *************************************************/
        stVpssGrpAttr.u32MaxW                        = stSize.u32Width;
        stVpssGrpAttr.u32MaxH                        = stSize.u32Height;
        stVpssGrpAttr.enPixelFormat                  = enPixFormat;
        stVpssGrpAttr.enDynamicRange                 = enDynamicRange;
        stVpssGrpAttr.stFrameRate.s32SrcFrameRate    = -1;
        stVpssGrpAttr.stFrameRate.s32DstFrameRate    = -1;
    
        abChnEnable[0]                               = HI_TRUE;
        stVpssChnAttr[0].u32Width                    = stSize.u32Width;
        stVpssChnAttr[0].u32Height                   = stSize.u32Height;
        stVpssChnAttr[0].enChnMode                   = VPSS_CHN_MODE_USER;
        stVpssChnAttr[0].enCompressMode              = enCompressMode;
        stVpssChnAttr[0].enDynamicRange              = enDynamicRange;
        stVpssChnAttr[0].enPixelFormat               = enPixFormat;
        stVpssChnAttr[0].enVideoFormat               = enVideoFormat;
        stVpssChnAttr[0].stFrameRate.s32SrcFrameRate = -1;
        stVpssChnAttr[0].stFrameRate.s32DstFrameRate = -1;
        stVpssChnAttr[0].u32Depth                    = 1;
        stVpssChnAttr[0].bMirror                     = HI_TRUE;                                                       //镜像使能
        stVpssChnAttr[0].bFlip                       = HI_TRUE;                                                        //翻转使能
        stVpssChnAttr[0].stAspectRatio.enMode        = ASPECT_RATIO_NONE;
    
        s32Ret = SAMPLE_COMM_VPSS_Start(VpssGrp0, abChnEnable, &stVpssGrpAttr, stVpssChnAttr);
    
        if (HI_SUCCESS != s32Ret)
        {
            SAMPLE_PRT("SAMPLE_COMM_VPSS_Start Grp0 failed with %d!\n", s32Ret);
            goto EXIT2;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

      SAMPLE_COMM_VPSS_Start内部主要调用四个函数,起到了创建vpss group, 配置通道属性, 启用通道 ,启用vpss group的作用

    /*****************************************************************************
    * function : start vpss grp.
    创建vpss group 配置通道属性 启用通道 启用vpss group
    *****************************************************************************/
    HI_S32 SAMPLE_COMM_VPSS_Start(VPSS_GRP VpssGrp, HI_BOOL* pabChnEnable, VPSS_GRP_ATTR_S* pstVpssGrpAttr, VPSS_CHN_ATTR_S* pastVpssChnAttr)
    {
        VPSS_CHN VpssChn;
        HI_S32 s32Ret;
        HI_S32 j;
    
        s32Ret = HI_MPI_VPSS_CreateGrp(VpssGrp, pstVpssGrpAttr);
    
        if (s32Ret != HI_SUCCESS)
        {
            SAMPLE_PRT("HI_MPI_VPSS_CreateGrp(grp:%d) failed with %#x!\n", VpssGrp, s32Ret);
            return HI_FAILURE;
        }
    
        for (j = 0; j < VPSS_MAX_PHY_CHN_NUM; j++)
        {
            if(HI_TRUE == pabChnEnable[j])
            {
                VpssChn = j;
                s32Ret = HI_MPI_VPSS_SetChnAttr(VpssGrp, VpssChn, &pastVpssChnAttr[VpssChn]);
    
                if (s32Ret != HI_SUCCESS)
                {
                    SAMPLE_PRT("HI_MPI_VPSS_SetChnAttr failed with %#x\n", s32Ret);
                    return HI_FAILURE;
                }
    
                s32Ret = HI_MPI_VPSS_EnableChn(VpssGrp, VpssChn);
    
                if (s32Ret != HI_SUCCESS)
                {
                    SAMPLE_PRT("HI_MPI_VPSS_EnableChn failed with %#x\n", s32Ret);
                    return HI_FAILURE;
                }
            }
        }
    
        s32Ret = HI_MPI_VPSS_StartGrp(VpssGrp);
    
        if (s32Ret != HI_SUCCESS)
        {
            SAMPLE_PRT("HI_MPI_VPSS_StartGrp failed with %#x\n", s32Ret);
            return HI_FAILURE;
        }
    
        return HI_SUCCESS;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    /* Group Settings
     *描述  :创建一个 VPSS GROUP
     *参数  :VpssGrp      VPSS GROUP 号。取值范围:[0, VPSS_MAX_GRP_NUM)。  输入
     *        pstGrpAttr   VPSS GROUP 属性指针。  输入
     *返回值:成功返回0,非0参考错误码
     *注意  :
     *        不支持重复创建。
     *        当 VPSS 工作在 VI_PARALLEL_VPSS_PARALLEL 模式时,只有 GROUP0 可以被创建。
     *        当 Hi3559AV100 VPSS 的 GROUP0 和 GROUP4 都工作VI_ONLINE_VPSS_ONLINE 模式时,只有 GROUP0 和 GROUP4 可以被创建。
     *        当Hi3519AV100/Hi3516CV500/Hi3516AV300/Hi3516DV300/Hi3556V200/Hi3559V200/Hi3516EV200 VPSS 的 GROUP0 工作 VI_ONLINE_VPSS_ONLINE 模式时,只有GROUP0 可以被创建。
     * 
     */
     HI_S32 HI_MPI_VPSS_CreateGrp(VPSS_GRP VpssGrp, const VPSS_GRP_ATTR_S *pstGrpAttr);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    /* Chn Settings 
     *描述  :设置 VPSS 通道属性。
     *参数  :VpssGrp  VPSS GROUP 号。取值范围:[0, VPSS_MAX_GRP_NUM)  输入
     *        VpssChn VPSS 通道号。取值范围:[0, VPSS_MAX_PHY_CHN_NUM) 输入
     *        pstGrpAttr VPSS 通道属性。                               输入 
     *返回值:成功返回0,失败参考错误码
     *注意  :GROUP 必须已创建。
              扩展通道不支持此接口。
              通道做任意角度旋转、LDC、Spread 处理或者其绑定的扩展通道开启了鱼眼校正时不支持通道尺寸动态改变。
              Hi3556V200/Hi3559V200 VPSS 输入图像宽度在(3360, 3840]范围内通道 0 不支持压缩输出。
    */
    HI_S32 HI_MPI_VPSS_SetChnAttr(VPSS_GRP VpssGrp, VPSS_CHN VpssChn, const VPSS_CHN_ATTR_S *pstChnAttr);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    /* 
     *描述  :启用 VPSS 通道。
     *参数  :VpssGrp      VPSS GROUP 号。取值范围:[0, VPSS_MAX_GRP_NUM)  输入
     *        VpssChn      VPSS 通道号。取值范围:[0, VPSS_MAX_CHN_NUM)    输入
     *返回值:成功返回0,失败参考错误码
     *注意  :多次使能返回成功。
              GROUP 必须已创建。
              Hi3516EV200 通道 0 低延时 buffer 卷绕开启时,若通道 0 写出 bufferSize 大于卷绕bufferSize,接口返回错误码 HI_ERR_VPSS_SIZE_NOT_ENOUGH。
              若支持扩展通道,扩展通道必须保证此通道绑定的源物理通道已经使能,否则返回失败错误码。
     */
    HI_S32 HI_MPI_VPSS_EnableChn(VPSS_GRP VpssGrp, VPSS_CHN VpssChn);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    /* 
     *描述  :启用 VPSS GROUP
     *参数  :VpssGrp      VPSS GROUP 号。取值范围:[0, VPSS_MAX_GRP_NUM) 输入
     *返回值:成功返回0,非0参考错误码
     *注意  :GROUP 必须已创建。
     *        重复调用该函数设置同一个组返回成功
     */
    HI_S32 HI_MPI_VPSS_StartGrp(VPSS_GRP VpssGrp);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    第六步:vi绑定vpss

      都是在线模式,就不需要绑定了

    /******************************************
        step 6:  VI bind VPSS, for total online, no need bind
        *************************************************/
    
    • 1
    • 2
    • 3

    第七步:启动vo

     /*step 7:  start V0
        *************************************************/
        SAMPLE_COMM_VO_GetDefConfig(&stVoConfig);
        stVoConfig.VoDev                                    = VoDev;
        stVoConfig.enVoIntfType                             = enVoIntfType;
        stVoConfig.enIntfSync                               = g_enIntfSync;
        stVoConfig.enPicSize                                = enPicSize;
        stVoConfig.u32DisBufLen                             = g_u32DisBufLen;
        stVoConfig.enDstDynamicRange                        = enDynamicRange;
        stVoConfig.enVoMode                                 = VO_MODE_1MUX;
    
        s32Ret = SAMPLE_COMM_VO_StartVO(&stVoConfig);
    
        if (HI_SUCCESS != s32Ret)
        {
            SAMPLE_PRT("SAMPLE_COMM_VO_StartVO failed with %d!\n", s32Ret);
            goto EXIT1;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

      SAMPLE_COMM_VO_GetDefConfig为vo的基本配置,允许立即使用vo
      SAMPLE_COMM_VO_StartVO主要含4个内部函数,分别有VO和VoDev的信息声明,设置并启动,如果改变的话设置显示矩形。打开VO通道的功能

    第八步:vi绑定vpss绑定vo

     /************************************************
        step 8:  VI bind VPSS bind VO
        *************************************************/
     s32Ret = SAMPLE_COMM_VI_Bind_VPSS(ViPipe0, ViChn, VpssGrp0);
        if (HI_SUCCESS != s32Ret)
        {
            SAMPLE_PRT("SAMPLE_COMM_VI_Bind_VPSS failed with %d!\n", s32Ret);
            goto EXIT1;
        }
    
        s32Ret = SAMPLE_COMM_VPSS_Bind_VO(VpssGrp0, VpssChn[0], stVoConfig.VoDev, VoChn);
    
        if (HI_SUCCESS != s32Ret)
        {
            SAMPLE_PRT("SAMPLE_COMM_VPSS_Bind_VO Grp0 failed with %d!\n", s32Ret);
            goto EXIT0;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

      SAMPLE_COMM_VI_Bind_VPSS包含数据源3个参数接收者3个参数,分别是vi和vpss,调用数据源到数据接收者绑定接口。
      SAMPLE_COMM_VPSS_Bind_VO包含数据源3个参数接收者3个参数,分别是vpss和vo,也是调用数据源到数据接收者绑定接口。
    都调用的同一个函数

    /* 
     *描述  :数据源到数据接收者绑定接口。
     *参数  :pstSrcChn 源通道指针。 输入
     *      :pstDestChn 目的通道指针。 输入
     *返回值:0成功,非0参考错误码
     *注意  :太多了参考手册吧p62
     */
    HI_S32 HI_MPI_SYS_Bind(const MPP_CHN_S *pstSrcChn, const MPP_CHN_S *pstDestChn);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

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

    PAUSE();
    
    //    SAMPLE_COMM_VPSS_UnBind_VO(VpssGrp1, VpssChn[0], stVoConfig.VoDev, VoChn[0]);
    //EXIT1:
        SAMPLE_COMM_VPSS_UnBind_VO(VpssGrp0, VpssChn[0], stVoConfig.VoDev, VoChn[0]);
    EXIT2:
        SAMPLE_COMM_VO_StopVO(&stVoConfig);
    EXIT3:
        SAMPLE_COMM_VPSS_Stop(VpssGrp1, abChnEnable);
    EXIT4:
        SAMPLE_COMM_VPSS_Stop(VpssGrp0, abChnEnable);
    EXIT5:
        SAMPLE_COMM_VI_StopVi(&stViConfig);
    EXIT:
        SAMPLE_COMM_SYS_Exit();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    显示可能存在的问题:

    1.显示器无法显示的问题

      解决办法:vio中关于分辨率部分修改为1080p60fps
    在这里插入图片描述
      sample里只更改参数的初始化这一行就可以了,如果自己需要手动修改
    在这里插入图片描述

      不建议更改common里面的函数,直接SAMPLE_COMM_VO_GetDefConfig配置后单独配置下面参数就可以

    2.显示器显示图像是倒立的

    在这里插入图片描述

      .bMirror参数为视频镜像,.bFlip参数为视频倒立 TRUE改为FALSE即可
      位于结构体

    typedef struct hiVPSS_CHN_ATTR_S {
        VPSS_CHN_MODE_E     enChnMode;          /* RW; Vpss channel's work mode. */
        /* RW; Range: Hi3559AV100 = [64, 16384] | Hi3519AV100 = [64, 8192] | Hi3516CV500 = [64, 8192] |
            Hi3516AV300 = [64, 8192] | Hi3516DV300 = [64, 8192] | Hi3556V200 = [64, 8192] | Hi3559V200 = [64, 8192] |
            Hi3516EV200 = [64, 4096]; Width of target image. */
        HI_U32              u32Width;
        /* RW; Range: Hi3559AV100 = [64, 16384] | Hi3519AV100 = [64, 8192] | Hi3516CV500 = [64, 8192] |
            Hi3516AV300 = [64, 8192] | Hi3516DV300 = [64, 8192] | Hi3556V200 = [64, 8192] | Hi3559V200 = [64, 8192] |
            Hi3516EV200 = [64, 4096]; Height of target image. */
        HI_U32              u32Height;
        VIDEO_FORMAT_E      enVideoFormat;      /* RW; Video format of target image. */
        PIXEL_FORMAT_E      enPixelFormat;      /* RW; Pixel format of target image. */
        DYNAMIC_RANGE_E     enDynamicRange;     /* RW; DynamicRange of target image. */
        COMPRESS_MODE_E     enCompressMode;     /* RW; Compression mode of the output. */
        FRAME_RATE_CTRL_S   stFrameRate;        /* Frame rate control info */
        HI_BOOL             bMirror;            /* RW; Mirror enable. */
        HI_BOOL             bFlip;              /* RW; Flip enable. */
        HI_U32              u32Depth;           /* RW; Range: [0, 8]; User get list depth. */
        ASPECT_RATIO_S      stAspectRatio;      /* Aspect Ratio info. */
    } VPSS_CHN_ATTR_S;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

      最后,万万没想到,不光配置有问题,线也有问题,也是醉啦,不过还好万里长征第一步迈出去啦!
    在这里插入图片描述

  • 相关阅读:
    python基础02——字符串
    从零编写STM32H7的MDK SPI FLASH下载算法
    状态压缩dp,91. 最短Hamilton路径
    containerd命令操作
    测试行业干了5年,从只会点点点到了现在的测试开发,总算是证明了自己
    java基础特别问题
    【Verilog教程】3.2 Verilog 时延
    手动下载新版的TCGA数据也是可以用TCGAbiolinks包整理的
    CesiumJS 2022^ 源码解读[0] - 文章目录与源码工程结构
    力扣-43题 字符串相乘(C++)- 大数相乘
  • 原文地址:https://blog.csdn.net/qq_42330920/article/details/124687984