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

embedded/2025/1/18 2:12:06/

        在RV1126+FFMPEG推流项目(3)VI模块视频编码流程-CSDN博客,说了vi的编码流程,这篇说VENC的初始化(硬件编码)。

        上一篇提到了几个重要的数据结构体,这节说这个RV1126_VENC_CONFIG。继续认识一下。

/*** @brief RV1126_VENC_CONFIG 结构体定义* * 该结构体用于配置RV1126视频编码(VENC)的相关参数。* 包含视频编码通道的ID和属性配置。*/typedef struct
{unsigned int id;   //< 视频编码通道ID,用于标识不同的视频编码通道VENC_CHN_ATTR_S attr; //< 视频编码通道属性,包含通道的具体配置信息
} RV1126_VENC_CONFIG;

        之前提到RV1126_VENC_CONFIG 是自封装的一个数据结构,里面最重要的成员就是VENC_CHN_ATTR_S 数据结构。  

typedef struct rkVENC_CHN_ATTR_S {VENC_ATTR_S stVencAttr;    // 编码器基础属性结构体 VENC_RC_ATTR_S stRcAttr;   // 编码码率控制属性结构体 VENC_GOP_ATTR_S stGopAttr; // 编码器GOP属性结构体 
} VENC_CHN_ATTR_S;

        可以看到VENC_CHN_ATTR_S数据结构里面又套着三个数据结构体。下面通过编码来学习一下。


        VENC_ATTR_S(定义编码器属性结构体):来源于rk1126开发手册,看一下成员

        第一个参数编码器的类型,把视频和音频的都放在了这个枚举里面,要哪个就选择那个。

编码:

 //初始化Vemc编码模块RV1126_VENC_CONFIG rv_venc;memset(&rv_venc, 0, sizeof(rv_venc)); //先把空间初始化rv_venc.id = 0;//视频编码器属性rv_venc.attr. stVencAttr.enType = RK_CODEC_TYPE_H264; // 编码协议 设置成h264,需要265就写成265的rv_venc.attr.stVencAttr.imageType = IMAGE_TYPE_NV12;  // 图形格式 和rv_vi.attr.enPixFmt保持一样rv_venc.attr.stVencAttr.u32VirHeight =  1080; //图片高度和分辨率 vi的u32Height一样rv_venc.attr.stVencAttr.u32VirWidth = 1920; //图片高度和分辨率 vi的u32Width一样rv_venc.attr.stVencAttr.u32PicHeight = 1080;//图片高度和分辨率 vi的u32Height一样rv_venc.attr.stVencAttr.u32PicWidth = 1920;图片高度和分辨率 vi的u32Width一样rv_venc.attr.stVencAttr.u32Profile = 77; //  //后面调节画面质量更详细所说,传输的编码质量,66基本能看,77还不错,100最好,更具业务而定

 


         VENC_RC_ATTR_S(定义编码通道码率控制器属性):

 

      这里有一个非常重要的问题,你要是选着了264的编码器,就像选择264的码率控制器,H264CBR和 H264VBR和H264AVBR都可以,就是不能用265的,如果要用265码率控制器就要用265的编码器。

编码: 

 

//初始化所有的rkmedia
int init_rkmedia_module_function()
{int ret;rkmedia_function_init(); //初始化rkmedia功能RV1126_VI_CONFIG rv_vi;memset(&rv_vi, 0, sizeof(rv_vi));//配置rv_virv_vi.id = 0; //视频通道IDrv_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.u32Height = 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); //初始化rv_viif(ret != 0){printf("vi初始化失败\n");}else{printf("vi 初始化成功\n");/*** 设置容器的目的是为了后面开发,可以轻易拿到 vi的id,直接从容器里面拿*/RV1126_VI_CONTAINER vi_container; //创建出容器vi_container.id = 0; //所有vi_id的索引vi_container.vi_id = rv_vi.id; //id,储存到里面去set_vi_container(0, & vi_container); //把vi_id设置到容器里面}//配置Vemc编码模块RV1126_VENC_CONFIG rv_venc;memset(&rv_venc, 0, sizeof(rv_venc)); //先把空间初始化rv_venc.id = 0; //一般都是从0开始的通道号//视频编码器属性rv_venc.attr. stVencAttr.enType = RK_CODEC_TYPE_H264; // 编码协议 设置成h264,需要265就写成265的rv_venc.attr.stVencAttr.imageType = IMAGE_TYPE_NV12;  // 图形格式 和rv_vi.attr.enPixFmt保持一样rv_venc.attr.stVencAttr.u32VirHeight =  1080; //图片高度和分辨率 vi的u32Height一样rv_venc.attr.stVencAttr.u32VirWidth = 1920; //图片高度和分辨率 vi的u32Width一样rv_venc.attr.stVencAttr.u32PicHeight = 1080;//图片高度和分辨率 vi的u32Height一样rv_venc.attr.stVencAttr.u32PicWidth = 1920;图片高度和分辨率 vi的u32Width一样rv_venc.attr.stVencAttr.u32Profile = 66; //  //后面调节画面质量更详细所说,传输的编码质量,66基本能看,77还不错,100最好,更具业务而定/*** 视频码率控制属性有一个细节,选择264的编码器,就要选择264的率控制* 不可以选择264的编码器,就要选择265的率控制*/rv_venc.attr.stRcAttr.enRcMode =  VENC_RC_MODE_H264CBR; //编码器码率控制模式rv_venc.attr.stRcAttr.stH264Cbr.u32Gop = 30;//目前是30,每30帧插入一个帧GOPSIZE:关键帧间隔,目前我随意的,根据情况,值大需要的解码时间就,值小就要更更多的带宽rv_venc.attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;//源帧率分子rv_venc.attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 25;   // 源帧率分母rv_venc.attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 1; // 目标帧率分子rv_venc.attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 25;// 目标帧率分母rv_venc.attr.stRcAttr.stH264Cbr.u32BitRate = 1920 * 1080 * 3;//码率 每一个像素都是3中颜色组成//gop属性器stGopAttr查了很多资料,可以不配置ret = rkmedia_venc_init(&rv_venc); //初始化Vemc编码模块if(ret != 0){printf("venc,配置失败\n");}else{//成功了,//把可以轻易拿到 enc的id,保存到容器里面,直接从容器里面拿RV1126_VENC_CONTAINER venc_container;venc_container.id = 0;//所有venc_id的索引venc_container.venc_id = rv_venc.id;set_venc_container(0, &venc_container);//设置进去}
}


http://www.ppmy.cn/embedded/154819.html

相关文章

ElasticSearch-Nested 类型与 Object 类型的区别

在 Elasticsearch 中&#xff0c;nested 类型和 object 类型都用于处理嵌套的 JSON 数据&#xff0c;但它们在存储和查询方面有着显著的区别。本文将详细解释这两种类型的区别&#xff0c;并提供具体的示例。 一、基本概念 1. object 类型 定义&#xff1a;object 类型是 Elas…

论文阅读:Structure-Driven Representation Learning for Deep Clustering

Xiang Wang, Liping Jing, Huafeng Liu, and Jian Yu. 2023. Structure-Driven Representation Learning for Deep Clustering. ACM Trans. Knowl. Discov. Data 18, 1, Article 31 (January 2024), 25 pages. https://doi.org/10.1145/3623400 论文地址&#xff1a;Structure…

css 原子化

CSS 原子化&#xff08;Atomic CSS&#xff09;是一种设计思路&#xff0c;旨在通过定义小而简洁的类来实现高效的样式应用&#xff0c;每个类负责一个单独的样式属性。这样&#xff0c;通过组合多个原子类&#xff0c;可以快速、灵活地为元素应用样式&#xff0c;而不需要编写…

Spring Boot中的自动配置原理是什么

Spring Boot 自动配置原理 Spring Boot 的自动配置机制基于 条件化配置&#xff0c;通过 EnableAutoConfiguration 注解来启用。自动配置的核心原理是 基于类路径和环境条件来推断所需要的配置&#xff0c;Spring Boot 会根据项目中引入的依赖和当前环境来自动装配相关的配置项…

如何用 AI 打造孩子的专属学习助手?

目录 一、创建智能体 二、填写提示词 三、验证效果 四、发布到豆包 如何用 AI 打造孩子的专属学习助手&#xff1f; 如何用 AI 打造孩子的专属学习助手&#xff1f; 今天给大家分享个超实用滴干货&#xff0c;能让家里的娃在学习路上如虎添翼&#xff01;  前几天&#…

基于微信小程序的汽车销售系统的设计与实现springboot+论文源码调试讲解

第4章 系统设计 一个成功设计的系统在内容上必定是丰富的&#xff0c;在系统外观或系统功能上必定是对用户友好的。所以为了提升系统的价值&#xff0c;吸引更多的访问者访问系统&#xff0c;以及让来访用户可以花费更多时间停留在系统上&#xff0c;则表明该系统设计得比较专…

OSI七层协议——分层网络协议

OSI七层协议&#xff0c;顾名思义&#xff0c;分为七层&#xff0c;实际上七层是不存在的&#xff0c;是人为的进行划分,让人更好的理解 七层协议包括&#xff0c;物理层(我),数据链路层(据),网络层(网),传输层(传输),会话层(会),表示层(表),应用层(用)(记忆口诀->我会用表…

基于物联网表计的综合能源管理方案

为加快推进国家“双碳”战略和新型能源体系建设&#xff0c;努力实现负荷准确控制和用户精细化管理&#xff0c;按照“政府主导、电网组织、政企协同、用户实施”的指导原则&#xff0c;多地成立市/县级电力负荷管理中心&#xff0c;包括浙江宁波、慈溪、辽宁大连、湖南株洲、娄…