一.本章节介绍:

本章节主要是介绍视觉项目的VI视频输入模块的讲解,VI视频模块是所有摄像头数据的入口。VI模块的配置在源文件rkmedia_module_function.cpp里面。

二.VI模块的思维导图:

上面思维导图主要是描述VI模块设置的大致流程,首先对RV1126_VI_CONFIG结构体进行参数设置,然后调用rkmedia_vi_init对VI模块进行设置和使能,设置完成后再把VI的模块ID放到VI数组里面(vi_containers)。

三.VI模块代码的截图

下图就是整个VI模块配置的具体参数,这里使用设置的结构体是RV1126_VI_CONFIG。RV1126_VI_CONFIG里面主要包含了VI_CHN_ATTR_S结构体进行设置。

typedef struct
{
    unsigned int id;
    VI_CHN_ATTR_S attr;
} RV1126_VI_CONFIG;
rkmedia_function_init();

    RV1126_VI_CONFIG rkmedia_vi_config;
    memset(&rkmedia_vi_config, 0, sizeof(rkmedia_vi_config));
    rkmedia_vi_config.id = 0;
    rkmedia_vi_config.attr.pcVideoNode = CMOS_DEVICE_NAME;   // VIDEO视频节点路径,
    rkmedia_vi_config.attr.u32BufCnt = 3;                    // VI捕获视频缓冲区计数,默认是3
    rkmedia_vi_config.attr.u32Width = 1920;                  // 视频输入的宽度,一般和CMOS摄像头或者外设的宽度一致
    rkmedia_vi_config.attr.u32Height = 1080;                 // 视频输入的高度,一般和CMOS摄像头或者外设的高度一致
    rkmedia_vi_config.attr.enPixFmt = IMAGE_TYPE_NV12;       // 视频输入的图像格式,默认是NV12(IMAGE_TYPE_NV12)
    rkmedia_vi_config.attr.enBufType = VI_CHN_BUF_TYPE_MMAP; // VI捕捉视频的类型
    rkmedia_vi_config.attr.enWorkMode = VI_WORK_MODE_NORMAL; // VI的工作模式,默认是NORMAL(VI_WORK_MODE_NORMAL)
    int ret = rkmedia_vi_init(&rkmedia_vi_config);           // 初始化VI工作
    if (ret != 0)
    {
        printf("vi init error\n");
    }
    else
    {
        printf("vi init success\n");
        RV1126_VI_CONTAINTER vi_container;
        vi_container.id = 0;
        vi_container.vi_id = rkmedia_vi_config.id;
        set_vi_container(0, &vi_container); // 设置VI容器
    }

id:VI模块的id号,用于初始化和使能VI模块

pcVideoNode: 摄像头的视频节点,这里默认是rkispp_scale0

u32BufCnt:缓冲区计数,默认是3

u32Width:VI模块分辨率宽度1920

u32Height:VI模块分辨率高度1080

enPixFmt:图像格式默认是NV12,这里填的是IMAGE_TYPE_NV12

enBufType:VI模块捕捉视频的类型,这里默认填写MMAP

enWorkMode:VI工作模式,这里写的是VI_WORK_MODE_NORMAL

填写完上述的配置参数后,就会调用rkmedia_vi_init这个自己封装的函数,这个函数主要是实现VI模块的初始化和使能的具体操作,具体看下图

int rkmedia_vi_init(RV1126_VI_CONFIG *rv1126_vi_config)
{
    int ret;
    VI_CHN_ATTR_S vi_attr = rv1126_vi_config->attr;
    unsigned int id = rv1126_vi_config->id;
    //vi_attr.pcVideoNode = CMOS_DEVICE_NAME;//
    //初始化VI模块
    ret = RK_MPI_VI_SetChnAttr(CAMERA_ID, id, &vi_attr);
    //使能VI模块
    ret |= RK_MPI_VI_EnableChn(CAMERA_ID, id);
    if (ret != 0)
    {
        printf("create vi failed.....\n", ret);
        return -1;
    }
    return 0;
}

rkmedia_vi_init这个自定义函数里面,关键是对VI进行初始化和使能,它分别调用了RK_MPI_VI_SetChnAttr的API对VI模块的属性进行初始化,然后再调用RK_MPI_VI_EnableChn对其使能。

设置完VI模块后,就要把VI模块的ID号设置到容器里面,调用自己封装的函数是set_vi_container

if (ret != 0)
    {
        printf("vi init error\n");
    }
    else
    {
        printf("vi init success\n");
        RV1126_VI_CONTAINTER vi_container;
        vi_container.id = 0;
        vi_container.vi_id = rkmedia_vi_config.id;
        set_vi_container(0, &vi_container); // 设置VI容器
    }

 set_vi_container(0, &vi_container)的具体实现:

int set_vi_container(unsigned int index, RV1126_VI_CONTAINTER *vi_container)
{
    pthread_mutex_lock(&all_containers_mutex);
    all_containers.vi_containers[index] = *vi_container;
    pthread_mutex_unlock(&all_containers_mutex);

    return 0;
}

在这个自定义的函数里面,最主要是把VI的ID号存放在VI模块数组里面(vi_containers),具体结构如下代码:

typedef struct
{
    unsigned int container_id;
    RV1126_VI_CONTAINTER vi_containers[ALL_CONTAINER_NUM];
    RV1126_AI_CONTAINTER ai_containers[ALL_CONTAINER_NUM];

    RV1126_VENC_CONTAINER venc_containers[ALL_CONTAINER_NUM];
    RV1126_AENC_CONTAINER aenc_containers[ALL_CONTAINER_NUM];

}RV1126_ALL_CONTAINER;

RV1126_ALL_CONTAINER结构体里面包含了四个模块的数组存储分别是VI模块(vi_contaianers)、AI模块(ai_containers)、VENC模块(venc_containers)、AENC模块(aenc_containers)。这四个模块容器就是分别存储,四个模块的ID号,让其能够更加方便的管理起来。

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐