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

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

上一篇提到了几个重要的数据结构体,这节说这个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_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.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_vi
    if(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);//设置进去
    }
}
相关推荐
启雀AI3 小时前
AI 驱动的视频课程自动摘要与知识点提取:ASR + LLM 流水线工程实践
人工智能·阿里云·华为云·音视频·培训saas平台
FinelyYang5 小时前
基于 LiveKit 实现一对一视频通话:从信令到媒体进房的完整实践
音视频·媒体
程序员老陆12 小时前
M3U8(HLS 索引协议)深度详解:它不存一帧画面,却指挥了整个互联网视频
音视频·hls·m3u8
雪的季节12 小时前
音视频(51-52)
音视频
hz5678913 小时前
视频会议终端品牌如何选择?主流产品特点与选型标准
安全·音视频·实时音视频·信息与通信
程序员老陆13 小时前
说一说FFmpeg6在Linux平台的编译
linux·运维·服务器·ffmpeg
用户5181860056615 小时前
FFmpeg 剪辑:为什么 `-c copy` 往往做不到帧准确剪切
ffmpeg
NutShell Wang15 小时前
国产全模态开源潮:从语言模型到视频模型,中国开源生态再升级
人工智能·语言模型·开源·大模型·音视频·多模态·vibe coding
福大大架构师每日一题16 小时前
mediamtx v1.19.3正式发布:认证安全、WebRTC跨域、MoQ稳定性、RTSP与HLS全面升级
安全·ffmpeg·webrtc
民乐团扒谱机17 小时前
【读论文】复调音乐信号的主旋律提取:方法、应用与挑战
开发语言·人工智能·算法·音视频·音乐