海思3559 sample解析:vio

本文涉及的产品
阿里云百炼推荐规格 ADB PostgreSQL,4核16GB 100GB 1个月
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 拿到开发板,编完了平台sample,自然按捺不住要去简单学习测试了。打开最直观相对也比较简单的vio例程做个到手分析和流程梳理吧

前言

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

测试

 一开始自然是最磕磕绊绊的,连上HDMI线,串口登录后运行,屏幕乌漆嘛黑,尝试了几个参数后怀疑是不是线有问题或者哪里配置不对,就打开了snap例程,毕竟显示不了咱保存下来也是一样的看嘛

Tedu.ko for Hi1559AW10e...OKI rE.ko for H13S59AW100...OK! ond Tenc-ko for H1155900...CK oud h2646.ho for Ha3559AY10O...OK!
h265e.ko for H13559AV1000...区I oud ipige.ko for Ha7559AY10O...0K! osd jpeod.ko ....ok! load hi vfmw,ko ..... ond rdec.no ....ok
load ive,ko for Hi3559AV10...KI ipcmasipcms
hpia detecting thread running! faesssoe reey threed oon
lead mnie.ko for H13550A100...OKI oud cup.ko for Ha3559AVI0...0I
lond dou pect.ko for H1559w100...oki ond dou match,ke for H13559AV100...oxi oud hi piris.ko ok!!
Loed seneor spi.ko for H13550A10e...0K I mort judio
load hi mapi draver successful! loud mipi tx driver succeusful!
nt/out/Tinun/cilti core/ke s ed ../../../../
out/  siaple/ too.s/  
nt/out/linusysulti.core/ko s ed ../../../../suple/
gudaey yub online calibratiov Latees mode swtcy lsc_onlin calin vdec! Unc_p? tratfie capture
ommony  PCIV/ vdec hateros  
d1s/  phete/  vene? 
dpu iceng.sutar 
ishrye/ Snap/ vi6/  
Tpu/  Svp/  
16
nt/out/tinux/ulti core/ke cd ../../../../sumple/snap/ ant/sample/unap f./sanple shup jsept i ./ssmple snap cindee. inder:
0ldouble pipe offline, nereal snap.
ant/anple/unkp 3./mp.e thup o
SAPLE C0HVI SetHipiAtLrT2016: ==.......... Hipiter 0, SetMipiAttr erbOfHode: t KX47T AKOK ACH 1PRIT DOFPS IN1T SUCCURS!
SAHpLE CoH9 155 ThreTd1 323: I5p Dey 0 umina i SuMpLE comH ise Thread]-323: Isp Dev 5 muming t
SAMPLEcoHvostartchn1-544: u32Width:1920 u32meicht:1000, u125quare:1.....upress sny key to trioger..s
SAMPLE COHH VENC SnapProcess]-1283: snap time out!  Hx--1024  
SAMPLE SHAP DoubleP:ptoffLing: sanp process failed

 可惜还是没有半点反应,触发拍照超时,那就只能是sample之前的配置就有问题了呗

完整的分析一下平台搭建后的流程

Makefile

makefile.param文件中首先需要将传感器型号选对,根绝自己所用传感器的型号进行选择(然后加载的时候好像不论加载参数选择哪个都不会报错,在viodemo里都会运行正常)

8
################# select sensor tvpe for  VOUr  sample ###############################  
9
####  SONY IMX477 MIPI 8M 30FPS 12BIT ################# 
0
####  SONY IMX477 MIPI 8M 60FPS 12BIT ################# 
7
####  SONY IMX477 MIPI 12M 30FPS 12BIT  ################# 
####  SONY IMX477 MIPI 9M 50FPS 10BIT ################# 
3 ####  SONY IMX477 MIPI 9M 60FPS 10BIT ################# 
14  ####  SONY IMX290 MIPI 2M 30FPS 12BIT ################# 
15  ####  SONY IMX290 MIPI 2M 30FPS 12BIT WDR3T01 ################# 
16  ####  SONY IMX334 SLAVE MIPI 8M 30FPS 12BIT ################# 
>
####  SONY IMX334 MIPI 8M 30FPS 12BIT ################# 
####  SONY IMX334 MIPI 8M 30FPS 12BIT WDR2T01 ############甘#### 
Z8
19  ####  SONY IMX277 SLVS 8M 120FPS 10BIT  ################# 
20  ####  SONY IMX277 SLVS 8M 30FPS 12BIT ################# 
21  ####  SONY IMX277 SLVS 8M 60FPS 12BIT ################# 
22  ####  SONY IMX277 SLVS 12M 30FPS 12BIT  ################# 
23  ####  SONY IMX277 SLVS 2M 240FPS 12BIT  ################# 
24  ####  COMSIS SHARP8K SLVDS 8K 30FPS 12BIT ################# 
25
26  SENSORO TYPE ?= SONY IMX334 MIPI 8M 30FPS 12BIT 
27  SENSOR1 TYPE ?= SONY IMX334 MIPI 8M 30FPS 12BIT 
28  # SENSORO TYPE ?= SONY IMX477 MIPI 8M 30FPS 12BIT 
00  # SENSOR1 TYPE.?_ SONY TMX477 MTPT 8M BOEPS 12BTT Hx--1024

 接下来开始分析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;

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

if (argc < 2)
    {
        SAMPLE_VIO_Usage(argv[0]);
        return HI_FAILURE;
    }

 设置相应信号处理函数,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;
}
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;
    }

 然后开始选择工作模式

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;

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

 这个例子中需要一个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;

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;
}

 入参结构体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;
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_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;

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

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

模式 VI_CAP 与 VI_PROC VI_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;
    }

 主要涉及两个重要函数

HI_S32 SAMPLE_COMM_VI_GetSizeBySensor(SAMPLE_SNS_TYPE_E enMode, PIC_SIZE_E* penSize)

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

HI_S32 SAMPLE_COMM_SYS_GetPicSize(PIC_SIZE_E enPicSize, SIZE_S* pstSize)

 该函数则又根据赋值好的的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;
    }

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

 COMMON_GetPicBufferSize一般 linear 格式的 YUV 缓存池的大小计算函数

 VI_GetRawBufferSize是VI 写出的 Raw 数据缓存池大小的计算函数

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;
2
/************************************************ step3: Init sys and common vB
*************************************************/
memsets(&stVbConf, sizeof(VB CONFIG S), 0, sizeof(VB CONFIG S));
stVbConf.u32MaxPoolCnt  = 2;  
u32B1kSize =COMMON GetPicBufferSize(stsize.u32Width,stsize.u32Height,SAMPLEPIXEL FORMAT,DATA BITWIDTH 10, COMPRESS MODE_NONE, DEFAULT A
stVbConf.astCommPool[0].u64BlkSize  =u32Blksize:  
stVbConf.astCommPool[0].u32BlkCnt = 10; 
u32B1kSize =VIGetRawBufferSize(stSize.u32Width,stsize.u32Height,PIXEL FORMAT RGB BAYER_16BPP, COMPRESS MODE NONE, DEFAULT ALIGN); stVbConf.astCommPool[11.u64BlkSize = u32BlkSize:
stVbConf.astCommPool[1].u32BlkCnt = 4;  Hx--1024  
!

 在启动各个模块之前自然必须要对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;
}

 函数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;
    }

第五步:启动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;
    }

 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;
}
/* 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);
/* 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);
/* 
 *描述  :启用 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);
/* 
 *描述  :启用 VPSS GROUP
 *参数  :VpssGrp      VPSS GROUP 号。取值范围:[0, VPSS_MAX_GRP_NUM) 输入
 *返回值:成功返回0,非0参考错误码
 *注意  :GROUP 必须已创建。
 *        重复调用该函数设置同一个组返回成功
 */
HI_S32 HI_MPI_VPSS_StartGrp(VPSS_GRP VpssGrp);

第六步:vi绑定vpss

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

/******************************************
    step 6:  VI bind VPSS, for total online, no need bind
    *************************************************/

第七步:启动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;
    }

 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;
    }

 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);

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

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.显示器无法显示的问题

 解决办法:vio中关于分辨率部分修改为1080p60fps

105 HI_S32 SAMPLE_VIO_8K30_PARALLEL(VO_INTF_TYPE_E enVoIntfType)  
106
107 HI S32  s32Ret  = HI_SUCCESS; 
108 VI DEV  ViDev0  = 0;  //VI配置为设备号0 
109 VI PIPE ViPipe0 = 0;  //VI配置为物理PIPE号0 
110 VI_CHN  ViChn = 0;  //VI配置通道号0  
111 HI S32  s32ViCnt  = 1;  //VI配置为单个sensor 
112 VPSS GRP  VpssGrp0  = 0;  //VPSS GROUP 号0 
113 VPSS_CHN  VpssChn[4]  {VPSS CHNO, VPSS CHN1, VPSS CHN2, VPSS CHN3}; //VPSS 通道号  
114 VPSS_GRP_ATTR_S stVpssGrpAttr = {0};  
115 VPSS_CHN ATTR_S stVpssChnAttr[VPSS MAX PHY CHN NUM];  //VPSS物理通道属性  
116 HI BOOL abChnEnable[VPSS_MAX_PHY_CHN_NUM] = {0};  
117 VO DEV  VoDev = SAMPLE_VO_DEV_DHDO; 
118 VO CHN  VoChn = 0;  //VO配置视频输出通道号0  
119 VO INTF SYNC E  g_enIntfSync  = VO_OUTPUT_1080P60;  
120 HI U32  g_u32DisBufLen  = 3;  
121 PIC_SIZE_E  enPicSize = PIC_3840x2160;  
122 WDR MODE E  enWDRMode = WDR MODE NONE;  //WDR 工作模式,分为帧模式、行模式、非WDR 
123 DYNAMIC RANGE E enDynamicRange  = DYNAMIC RANGE SDR8; //动态范围,8bit数据的标准动态范围  
124 PIXEL FORMAT E  enPixFormat = PIXEL_FORMAT_YVU_SEMIPLANAR_420;  //像素格式  
125 VIDEO FORMAT E  enVideoFormat = VIDEO FORMAT LINEAR;  //视频格式,现行存储 
126 COMPRESS MODE E enCompressMode  = COMPRESS MODE NONE; //视频压缩数据格式,非压缩  
127 VI VPSS MODE E  enMastPipeMode  = VI OFFLINE VPSS OFFLINE;  //定义 VI PIPE 和 VPSS 组的工作模式:VI 并行,v  
128 SIZE_S  stsize; 
129 HI U32  u32Blksize; 
130 VB CONFIG S stvbConf; //定义视频缓存池属性结构体  
131 SAMPLE VI CONFIG S  stViConfig; 
132 132 SAMPLE VO CONFIG S  stVoConfig; Hx--1024

 sample里只更改参数的初始化这一行就可以了,如果自己需要手动修改

260 step  start vo  
261 ************************************************* 
262 SAMPLE COMM_VO GetDefConfig(&stVoConfig); 
263 stVoConfig.VoDev  = VoDev;  
264 stVoConfig.enVoIntfType =enVoIntfType;  
265 stVoConfig.enIntfSync g_enIntfSync; 
266 stVoConfig.enPicSize  =enPicSize; 
267 stVoConfig.u32DisBufLen =g_u32DisBufLen;  
268 stVoConfig.enDstDynamicRange  =enDynamicRange;  
269 stVoConfig.enVoMode =VO_MODE_1MUX;  
270
271 s32Ret = SAMPLE COMM VO StartVO(&stVoConfig); 
272
273 if (HI SUCCESS != s32Ret) 
274 (char [40])"SAMPLE COMM vo Startvo failed with %d!\n' 
275 SAMPLE PRT("SAMPLE COMM vo Startvo failed with %d!\n", s32Ret); 
276 goto EXIT1; 
277 Hx--1024

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

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

/************************************************ 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 COMMVPSS Start(VpssGrp0,abChnEnable,&stVpssGrpAttr,stVpssChnAttr);  Hx--1024

.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;

f0727bbc4d79489d8f1101c892297e0e.png  最后,万万没想到,不光配置有问题,线也有问题,也是醉啦,不过还好万里长征第一步迈出去啦!7ea01f1b83ef4375a2c4d0bdb76debd8.png

相关文章
|
传感器 编解码 缓存
海思3559 sample解析:venc
海思3559 sample解析:venc
1097 0
海思3559 sample解析:venc
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
71 2
|
2月前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
76 0
|
2月前
|
算法 Java 容器
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
62 0
|
2月前
|
存储 Java C++
Collection-PriorityQueue源码解析
Collection-PriorityQueue源码解析
66 0
|
2月前
|
安全 Java 程序员
Collection-Stack&Queue源码解析
Collection-Stack&Queue源码解析
86 0
|
18天前
|
PyTorch Shell API
Ascend Extension for PyTorch的源码解析
本文介绍了Ascend对PyTorch代码的适配过程,包括源码下载、编译步骤及常见问题,详细解析了torch-npu编译后的文件结构和三种实现昇腾NPU算子调用的方式:通过torch的register方式、定义算子方式和API重定向映射方式。这对于开发者理解和使用Ascend平台上的PyTorch具有重要指导意义。
|
22天前
|
缓存 监控 Java
Java线程池提交任务流程底层源码与源码解析
【11月更文挑战第30天】嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的方式,带你一步步深入线程池的奥秘,从概述到功能点,再到背景和业务点,最后到底层原理和示例,让你对线程池有一个全新的认识。
50 12
|
1月前
|
存储 安全 Linux
Golang的GMP调度模型与源码解析
【11月更文挑战第11天】GMP 调度模型是 Go 语言运行时系统的核心部分,用于高效管理和调度大量协程(goroutine)。它通过少量的操作系统线程(M)和逻辑处理器(P)来调度大量的轻量级协程(G),从而实现高性能的并发处理。GMP 模型通过本地队列和全局队列来减少锁竞争,提高调度效率。在 Go 源码中,`runtime.h` 文件定义了关键数据结构,`schedule()` 和 `findrunnable()` 函数实现了核心调度逻辑。通过深入研究 GMP 模型,可以更好地理解 Go 语言的并发机制。
|
1月前
|
消息中间件 缓存 安全
Future与FutureTask源码解析,接口阻塞问题及解决方案
【11月更文挑战第5天】在Java开发中,多线程编程是提高系统并发性能和资源利用率的重要手段。然而,多线程编程也带来了诸如线程安全、死锁、接口阻塞等一系列复杂问题。本文将深度剖析多线程优化技巧、Future与FutureTask的源码、接口阻塞问题及解决方案,并通过具体业务场景和Java代码示例进行实战演示。
54 3

推荐镜像

更多