RV1126 NO.56:ROCKX+RV1126人脸识别推流项目之VI模块和VENC模块讲解

一.VI模块介绍:

本章节介绍基于RockX和RV1126的人脸识别推流项目中VI模块和VENC模块的初始化设置。该项目需要配置两个VI模块:一个用于RockX人脸检测和识别处理,另一个用于显示AI处理结果。相关实现代码位于rkmedia_module_function.cpp文件中。

二.VI模块的思维导图:

该思维导图概述了VI模块配置的基本流程。具体操作包括:首先创建两个RV1126_VI_CONFIG结构体,分别用于rockx人脸检测/识别功能以及AI处理结果的显示输出。完成参数配置后,通过调用rkmedia_vi_init函数对两个VI模块进行初始化和启用操作。最终,将这两个VI模块的ID号存储在vi_containers数组中。

三.VI模块设置代码

3.1. rockx的VI模块设置

cpp 复制代码
RV1126_VI_CONFIG rockx_rkmedia_vi_config;
    memset(&rockx_rkmedia_vi_config, 0, sizeof(rockx_rkmedia_vi_config));
    rockx_rkmedia_vi_config.id = 0;
    rockx_rkmedia_vi_config.attr.pcVideoNode = CMOS_DEVICE_NAME;   // VIDEO视频节点路径,
    rockx_rkmedia_vi_config.attr.u32BufCnt = 3;                    // VI捕获视频缓冲区计数,默认是3
    rockx_rkmedia_vi_config.attr.u32Width = 1920;                  // 视频输入的宽度,一般和CMOS摄像头或者外设的宽度一致
    rockx_rkmedia_vi_config.attr.u32Height = 1080;                 // 视频输入的高度,一般和CMOS摄像头或者外设的高度一致
    rockx_rkmedia_vi_config.attr.enPixFmt = IMAGE_TYPE_NV12;       // 视频输入的图像格式,默认是NV12(IMAGE_TYPE_NV12)
    rockx_rkmedia_vi_config.attr.enBufType = VI_CHN_BUF_TYPE_MMAP; // VI捕捉视频的类型
    rockx_rkmedia_vi_config.attr.enWorkMode = VI_WORK_MODE_NORMAL; // VI的工作模式,默认是NORMAL(VI_WORK_MODE_NORMAL)
    int ret = rkmedia_vi_init(&rockx_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 = rockx_rkmedia_vi_config.id;
        set_vi_container(0, &vi_container); // 设置VI容器
    }

参数说明:

  • id:VI模块的唯一标识符,用于模块初始化和使能
  • pcVideoNode:指定摄像头视频节点(默认:rkispp_scale0)
  • u32BufCnt:缓冲区数量配置(默认值:3)
  • u32Width:VI模块分辨率宽度(默认:1920像素)
  • u32Height:VI模块分辨率高度(默认:1080像素)
  • enPixFmt:图像格式设置(默认:IMAGE_TYPE_NV12)
  • enBufType:视频捕获类型(默认:MMAP)
  • enWorkMode:VI模块工作模式(默认:VI_WORK_MODE_NORMAL)

配置流程: 完成上述参数设置后,需调用**set_vi_container**函数将VI模块ID存入数组,存储位置为数组索引0。

3.2.显示AI结果的VI模块设置

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

这部分参数与上文基本一致,主要区别在于pcVideoNode参数。具体说明如下:

  1. 参数说明:

    • id:VI模块标识号,用于初始化和启用模块
    • pcVideoNode:视频节点名称(显示VI模块使用rkispp_scale1,而rockx VI模块使用rkispp_scale0)
    • u32BufCnt:缓冲区数量(默认值3)
    • u32Width:分辨率宽度(1920)
    • u32Height:分辨率高度(1080)
    • enPixFmt:图像格式(默认NV12,此处指定为IMAGE_TYPE_NV12)
    • enBufType:视频捕获类型(默认MMAP)
    • enWorkMode:工作模式(设置为VI_WORK_MODE_NORMAL)
  2. 配置完成后,需要通过set_vi_container将VI模块号存入数组,注意此处数组索引号为1。

3.3. 启动两个VI模块进行视频采集

cpp 复制代码
//同一个物理摄像头(CAMERA_ID)可以输出多路不同规格的视频流,而非多个独立摄像头。
    ret = RK_MPI_VI_StartStream(CAMERA_ID, 0);
    if(ret)
    {
        printf("RK_MPI_VI_StartStream_0 Failed....\n");
    }

    ret = RK_MPI_VI_StartStream(CAMERA_ID, 1);
    if(ret)
    {
        printf("RK_MPI_VI_StartStream_1 Failed....\n");
    }

完成两个VI模块的参数配置后,调用RK_MPI_VI_StartStream函数即可启动摄像头双视频模块的数据采集。

3.4. rkmedia_vi_init函数的实现:

cpp 复制代码
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模块的初始化和使能。具体通过以下两个步骤完成:

  1. 调用RK_MPI_VI_SetChnAttr接口初始化VI通道属性
  2. 调用RK_MPI_VI_EnableChn接口使能VI通道

3.5. set_vi_container函数的实现:

cpp 复制代码
typedef struct
{
    unsigned int id;
    unsigned int vi_id;

}RV1126_VI_CONTAINTER;



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

四.VENC模块介绍

一.VENC模块的思维导图

二.VENC模块设置的代码

4.1. venc参数的设置

cpp 复制代码
RV1126_VENC_CONFIG rkmedia_venc_config = {0};
    memset(&rkmedia_venc_config, 0, sizeof(rkmedia_venc_config));
    rkmedia_venc_config.id = 0;
    rkmedia_venc_config.attr.stVencAttr.enType = RK_CODEC_TYPE_H264;          // 编码器协议类型
    rkmedia_venc_config.attr.stVencAttr.imageType = IMAGE_TYPE_NV12;          // 输入图像类型
    rkmedia_venc_config.attr.stVencAttr.u32PicWidth = 1920;                   // 编码图像宽度
    rkmedia_venc_config.attr.stVencAttr.u32PicHeight = 1080;                  // 编码图像高度
    rkmedia_venc_config.attr.stVencAttr.u32VirWidth = 1920;                   // 编码图像虚宽度,一般来说u32VirWidth和u32PicWidth是一致的
    rkmedia_venc_config.attr.stVencAttr.u32VirHeight = 1080;                  // 编码图像虚高度,一般来说u32VirHeight和u32PicHeight是一致的
    rkmedia_venc_config.attr.stVencAttr.u32Profile = 66;                      // 编码等级H.264: 66: Baseline; 77:Main Profile; 100:High Profile; H.265: default:Main; Jpege/MJpege: default:Baseline(编码等级的作用主要是改变画面质量,66的画面质量最差利于网络传输,100的质量最好)

    rkmedia_venc_config.attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;        // 编码器码率控制模式
    rkmedia_venc_config.attr.stRcAttr.stH264Cbr.u32Gop = 25;                  // GOPSIZE:关键帧间隔
    rkmedia_venc_config.attr.stRcAttr.stH264Cbr.u32BitRate = 1920 * 1080 * 3; // 码率
    rkmedia_venc_config.attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;      // 目的帧率分子:填的是1固定
    rkmedia_venc_config.attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 25;     // 目的帧率分母:填的是25固定
    rkmedia_venc_config.attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;       // 源头帧率分子:填的是1固定
    rkmedia_venc_config.attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 25;      // 源头帧率分母:填的是25固定

以下是高分辨率VENC编码器的参数设置及其含义:

编码器基础属性配置

stVencAttr.enType:指定编码器协议类型,此处设置为H264编码器(RK_CODEC_TYPE_H264)

stVencAttr.imageType:编码器图像类型,需与输入图像类型一致(IMAGE_TYPE_NV12)

分辨率参数

stVencAttr.enType.u32PicWidth:编码图像宽度(1920)

stVencAttr.enType.u32PicHeight:编码图像高度(1080)

stVencAttr.enType.u32VirWidth:虚拟宽度(与u32PicWidth相同,1920)

stVencAttr.enType.u32VirHeight:虚拟高度(与u32PicHeight相同,1080)

编码等级

stVencAttr.enType.u32Profile:设置为66(Baseline模式),更适合视频传输

码率控制配置

stRcAttr.enRcMode:码率控制模式(H264 CBR模式,VENC_RC_MODE_H264CBR)

stRcAttr.stH264Cbr.u32Gop:GOP值(25)

stRcAttr.stH264Cbr.u32BitRate:码率设置(1920×1080×3≈700KB/s)

帧率参数

stRcAttr.stH264Cbr.u32SrcFrameRateDen:源帧率分母(25)

stRcAttr.stH264Cbr.u32SrcFrameRateNum:源帧率分子(1)

stRcAttr.stH264Cbr.u32DstFrameRateDen:目标帧率分母(25)

stRcAttr.stH264Cbr.u32DstFrameRateNum:目标帧率分子(1)

(注:通常源帧率和目标帧率保持相同数值)

完成上述参数配置后,调用封装函数rkmedia_venc_init进行VENC模块初始化。

4.2.rkmedia_venc_init的实现

cpp 复制代码
//VENC的初始化
int rkmedia_venc_init(RV1126_VENC_CONFIG *rv1126_venc_config)
{
    int ret;
    VENC_CHN_ATTR_S venc_chn_attr = rv1126_venc_config->attr;
    unsigned int venc_id = rv1126_venc_config->id;
    ret = RK_MPI_VENC_CreateChn(rv1126_venc_config->id, &venc_chn_attr);
    if (ret != 0)
    {
        printf("create rv1126_venc_module failed\n");
        return -1;
    }
    else
    {
        printf("create rv1126_venc_module success\n");
    }

    return 0;
}

该自定义函数主要对RK_MPI_VENC_CreateChn进行了简单封装,并接RV1126_VENC_CONFIG结构体指针作为参数。

4.3.set_venc_container函数的实现:

cpp 复制代码
typedef struct
{
    unsigned int id;
    unsigned int venc_id;

}RV1126_VENC_CONTAINER;



int set_venc_container(unsigned int index, RV1126_VENC_CONTAINER *venc_container)
{
    pthread_mutex_lock(&all_containers_mutex);
    all_containers.venc_containers[index] = *venc_container;
    pthread_mutex_unlock(&all_containers_mutex);
    return 0;
}

完成VENC模块配置后,需要将模块ID注册至VENC容器数组。其中,高分辨率VENC的默认ID为0,可通过调用封装函数set_venc_container 实现。该函数的核心功能是将VENC ID 存储至全局数组venc_containers中。

相关推荐
骄傲的心别枯萎2 小时前
RV1126 NO.55:ROCKX+RV1126人脸识别推流项目讲解
opencv·计算机视觉·音视频·rv1126
汉得数字平台2 小时前
汉得H-AI飞码——前端编码助手V1.1.2正式发布:融业务知识,提开发效能
前端·人工智能·智能编码
资源补给站2 小时前
论文15 | 深度学习对功能性超声图像进行血管分割案例分析
人工智能·深度学习
AALoveTouch2 小时前
n8n 2.0 中文汉化版一键部署教程 | 解除Execute Command限制
人工智能·自动化
ACP广源盛139246256732 小时前
GSV1015@ACP#1015/2015产品规格详解及产品应用分享
单片机·嵌入式硬件·音视频
لا معنى له2 小时前
学习笔记:Transformer
人工智能·笔记·深度学习·学习·机器学习·transformer
人工智能培训2 小时前
什么是基于大模型的智能体构建?
人工智能·深度学习·大模型·具身智能·智能体·智能体构建·大模型智能体
深度学习实战训练营2 小时前
SegFormer:使用Transformer进行语义分割,简单而高效的设计-k学长深度学习专栏
人工智能·深度学习·transformer
大、男人2 小时前
FastMCP高级特性之Composition
人工智能·fastmcp