RV1126+FFMPEG推流项目(3)VI模块视频编码流程

视频编码的流程:

本章节讲的是RV1126视频编码的流程,在整个项目之中视频编码功能是核心之一。视频编码流程主要分三步:V I 的初始化V ENC的初始化( 硬件编码****)**** 、绑定V I VENC 节点开启V ENC ****线程进行视频编码的采集,****注意一下这里的编码是硬件编码,不是使用ffmpeg软件编码

rv1126有一份开发手册,很多东西都是在里面找到了。

视频采集流程:

重要的结构体:

第一步要 rkmedia_function_init();该函数主要负责初始化rkmedia系统,确保系统准备就绪,可以执行后续的操作,它调用RK_MPI_SYS_Init()函数来进行实际的初始化工作

复制代码
//初始化所有rkmedia的模块
int init_rkmedia_module_function()
{
    rkmedia_function_init(); //初始化rkmedia功能
}

继续往下说之前,先来了认识几个重要的数据结构。RV1126_VI_CONFIG、RV1126_AI_CONFIG、RV1126_VENC_CONFIG、RV1126_AENC_CONFIG 这是个结构体都是自己封装的,对rv1126的一下api封装了一下都在rkmedia_config_public.h文件里面**。
RV1126_VI_CONFIG:**

复制代码
/**
 * @brief RV1126_VI_CONFIG 结构体定义
 * 
 * 该结构体用于配置RV1126视频输入(VI)的相关参数。
 * 包含视频通道的ID和属性配置。
 */

typedef struct
{
    unsigned int id;   ///< 视频通道ID,用于标识不同的视频输入通道
    VI_CHN_ATTR_S attr; ///< 视频通道属性,包含通道的具体配置信息
} RV1126_VI_CONFIG;

VI_CHN_ATTR_S:在rk1126的开发文档里面


RV1126_AI_CONFIG:

复制代码
/**
 * @brief RV1126_AI_CONFIG 结构体定义
 * 
 * 该结构体用于配置RV1126音频输入(AI)的相关参数。
 * 包含音频通道的ID和属性配置。
 */

typedef struct
{
    unsigned int id;   ///< 音频通道ID,用于标识不同的音频输入通道
    AI_CHN_ATTR_S attr; ///< 音频通道属性,包含通道的具体配置信息
} RV1126_AI_CONFIG;

AI_CHN_ATTR_S:在rk1126的开发文档里面


RV1126_VENC_CONFIG:

复制代码
/**
 * @brief RV1126_VENC_CONFIG 结构体定义
 * 
 * 该结构体用于配置RV1126视频编码(VENC)的相关参数。
 * 包含视频编码通道的ID和属性配置。
 */

typedef struct
{
    unsigned int id;   ///< 视频编码通道ID,用于标识不同的视频编码通道
    VENC_CHN_ATTR_S attr; ///< 视频编码通道属性,包含通道的具体配置信息
} RV1126_VENC_CONFIG;

VENC_CHN_ATTR_S: 在rk1126的开发文档里面


RV1126_AENC_CONFIG:

复制代码
/**
 * @brief RV1126_AENC_CONFIG 结构体定义
 * 
 * 该结构体用于配置RV1126音频编码(AENC)的相关参数。
 * 包含音频编码通道的ID和属性配置。
 */

typedef struct
{
    unsigned int id;   ///< 音频编码通道ID,用于标识不同的音频编码通道
    AENC_CHN_ATTR_S attr; ///< 音频编码通道属性,包含通道的具体配置信息
} RV1126_AENC_CONFIG;

AENC_CHN_ATTR_S:

开始编码:

在rkmedia_module_function.cpp(功能模块),还有一部分其他的源码,比如下面容器的一部分代码放在 rkmedia_container.cpp (容器管理模块),主要功能是保存 VIAI 初始化的设备节点,供多线程使用。这里就不上传了,不然就会很乱了,感兴趣的可以问我拿整个源码。

复制代码
int init_rkmedia_module_function()
{
    int ret;

    rkmedia_function_init(); //初始化rkmedia功能

    RV1126_VI_CONFIG rv_vi;
    memset(&rv_vi, 0, sizeof(rv_vi));

    //初始化rv_vi
    rv_vi.id = 0; //视频通道ID
    rv_vi.attr.pcVideoNode = COMS_DEVICE_NAME; //video视频节点路径
    /*
        VI捕获视频缓冲区计数,默认是3
        比如说vi和摄像头直接基础没有缓存区,vi模块如果数度跟不上会造成数据的丢失
        所以加上缓存区的,就可以减轻vi模块的压力,也是类似与一个生产着和消费着模型,主要是摄像头每时每刻都在采集数据不会停的
        所以加上缓存去,就可以大大保存数据的完整性。至于为啥3,这是工程师的经验
    */
    rv_vi.attr.u32BufCnt = 3; 
    rv_vi.attr.u32Width = 1920;//视频输入的宽度,一般和CMOS摄像头或者外设的宽度一致
    rv_vi.attr.u32Width = 1080;视频输入的高度,一般和CMOS摄像头或者外设的高度一致
    rv_vi.attr.enPixFmt = IMAGE_TYPE_NV12; // 图形格式 和vi_chn_attr.enPixFmt保持一样
    
    /**
     *  VI_CHN_BUF_TYPE_MMAP和VI_CHN_BUF_TYPE_DMA
     *  VI_CHN_BUF_TYPE_DMA:vi模块直接和内存打交道,优点:速度快,缺点:如果硬件差的,可能会造成发热,频繁操作加快硬件损坏
     * I_CHN_BUF_TYPE_MMAP:中间有一个虚拟内存,vi和内存不直接接触,优点:硬件使用时间会长,缺点:有一点点延迟,但是不影响
     */
    rv_vi.attr.enBufType = VI_CHN_BUF_TYPE_MMAP; //视频输入的图像格式,默认是NV12(IMAGE_TYPE_NV12)
    rv_vi.attr.enWorkMode = VI_WORK_MODE_NORMAL; //VI的工作模式,默认是NORMAL(VI_WORK_MODE_NORMAL)
    ret = rkmedia_vi_init(&rv_vi);
    if(ret != 0)
    {
        printf("vi初始化失败\n");
    }
    else
    {
        printf("vi 初始化成功\n");
        /**
         * 设置容器的目的是为了后面开发,可以轻易拿到 vi的id,直接从容器里面拿
         */
        RV1126_VI_CONTAINER vi_container; //创建出容器
        vi_container.id = 0;
        vi_container.vi_id = rv_vi.id;
        set_vi_container(0, & vi_container); //把vi_id设置到容器里面
        
    }



}
相关推荐
路溪非溪4 小时前
各种音频产品及场景总结
音视频
丢丢丢丢丢丢~4 小时前
apache2的默认html修改
linux·运维·服务器
wusam4 小时前
Linux系统管理与编程20:Apache
linux·运维·服务器·apache·shell编程
我不想当小卡拉米4 小时前
【Linux】操作系统入门:冯诺依曼体系结构
linux·开发语言·网络·c++
ChironW5 小时前
Ubuntu 24.04 LTS系统上配置国内时间同步
linux·运维·服务器·ubuntu
苏生要努力6 小时前
第九届御网杯网络安全大赛初赛WP
linux·python·网络安全
若风的雨6 小时前
【DeepSeek】判断两个 PCIe 设备是否属于**同一个 PCIe 子树
linux
科技小E6 小时前
WebRTC技术EasyRTC嵌入式音视频通信SDK打造远程实时视频通话监控巡检解决方案
人工智能·音视频
江畔独步6 小时前
vim中的查找
linux·编辑器·vim
源码方舟7 小时前
【基于ALS模型的教育视频推荐系统(Java实现)】
java·python·算法·音视频