P8 RV1126推流 —— 摄像头和咪头模块初始化

发布时间:2024年01月03日

前言?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

从本章开始我们将要学习嵌入式音视频的学习了 ,使用的瑞芯微的开发板

🎬 个人主页:@ChenPi

🐻推荐专栏1: 《C++_@ChenPi的博客-CSDN博客》????

🔥 推荐专栏2: 《Linux C应用编程(概念类)_@ChenPi的博客-CSDN博客》???

🛸推荐专栏3:《嵌入式音视频_@ChenPi的博客-CSDN博客
🌺本篇简介 ?:本章主要讲解VI VENC模块和AI AENC模块的初始化及具体函数详解

01 main函数

?

构造一个项目,我们需要先将大概的框架给理解清楚,这样对写代码提供很多帮助

首先,我们看一下主函数

?

我们的主函数我们就写成这样,把功能和任务都分模块写,这样看代码和移植到方便一些

我们可以看到主函数接收参数的

我们要接收三个参数

  • 参数1为可执行文件名
  • 参数2为复合流格式
  • 参数3为将要推流到的流媒体的地址

第三个红框就是初始化一些参数了

?我们重点最后一个红框

这里面的内容是项目跑起来的关键

02 模块参数初始化及模块配置

2.1 VI模块初始化

//1 VI设备参数初始化
int rkmedia_VI_Init()
{
    RV1126_VI_CONFIG vi_Config;    //VI模块配置信息结构体
    memset(&vi_Config, 0, sizeof(vi_Config));   
    vi_Config.id = 0;            
    vi_Config.attr.pcVideoNode = VI_4K_NodeName;       //设备节点
    vi_Config.attr.u32Height = 1080;                                         //视频输入的宽度,一般和CMOS摄像头或者外设的宽度一致
    vi_Config.attr.u32Width = 1920;                                         //视频输入的高度,一般和CMOS摄像头或者外设的高度一致
    vi_Config.attr.u32BufCnt = 3;                                               //缓冲区计数,一般默认为3
    vi_Config.attr.enWorkMode = VI_WORK_MODE_NORMAL;   //vi工作模式 VI_WORK_MODE_NORMAL正常模式 VI_WORK_MODE_LUMA_ONLY 亮度模式
    vi_Config.attr.enPixFmt = IMAGE_TYPE_NV12;                     //图像格式
    vi_Config.attr.enBufType = VI_CHN_BUF_TYPE_MMAP;  //vi关于视频的方式DMA和MMAP两种方式
    int ret = rkmedia_VI_Module_Init(&vi_Config);
    if(0 == ret)
    {
        RV1126_VI_CONTAINTER venc_container;     //保存通道号的结构体
        venc_container.index = 0;                                      //第几组编号
        venc_container.Vi_Channel_ID = vi_Config.id;   //通道号ID
        set_vi_container(0,&venc_container);        //将通道号保存进去
        puts("container creat succeeded"); 
    }else{
        puts("container creat failed");
    }
    return 0;
}

??

?首先我们来看一下VI模块的初始化

?RV1126_VI_CONFIG这个结构体实际上就是对VI_CHN_ATTR_S结构做了一个封装

?

?

多了一个变量ID,这个的作用是什么呢?这个是为了后期如果需要多路编码留下拓展空间

再看一下这行代码

int ret = rkmedia_VI_Module_Init(&vi_Config);

这个代码的实际是将VI和VENC模块的绑定操作进行了一个封装

??

2.2 VENC模块初始化

//初始化VENC模块
int rkmedia_VENC_Init()
{
    RV1126_VENC_CONFIG vencconfig;   //保存VENC模块配置信息结构体
    memset(&vencconfig, 0, sizeof(vencconfig));  
    vencconfig.id = 0;
    //1编码器基础属性结构体
    vencconfig.attr.stVencAttr.enType = RK_CODEC_TYPE_H264;   //编码器协议类型
    vencconfig.attr.stVencAttr.imageType = IMAGE_TYPE_NV12;     //输入图像类型
    vencconfig.attr.stVencAttr.u32PicWidth = 1920;                              //编码图像宽度    
    vencconfig.attr.stVencAttr.u32PicHeight = 1080;                             //编码图像高度
    vencconfig.attr.stVencAttr.u32VirWidth = 1920;                                //编码图像虚宽度,一般来说u32VirWidth和u32PicWidth是一致的
    vencconfig.attr.stVencAttr.u32VirHeight = 1080;                              //   
    vencconfig.attr.stVencAttr.u32Profile = 77;     //编码等级 有66 77 100 越高画质越好,但网络传输需要的带宽就越大
    //2编码码率控制属性结构体
    vencconfig.attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;  //编码器码率控制模式
    vencconfig.attr.stRcAttr.stH264Cbr.u32Gop = 30; // h264cbr 关键帧间隔
    vencconfig.attr.stRcAttr.stH264Cbr.u32BitRate = 1920*1080*3;      //编码码率
                /*原始帧和目标帧的分子分母*/
    vencconfig.attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum =25;    //目标帧
    vencconfig.attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;
    vencconfig.attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 25;    //原始帧
    vencconfig.attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;
    //3编码器GOP属性结构体
    int ret = rkmedia_VENC_Module_Init(&vencconfig);
    if(0 == ret)
    {
        RV1126_VENC_CONTAINER venc_container;
        venc_container.index = 0;
        venc_container.VENC_Channel_ID = vencconfig.id;
        set_venc_container(0, &venc_container);
    }else
    {

    }
    return 0;
}

?这个的做法和VI模块配置是相似的

?需要注意的几个点

  • 需要理解VENC_CHN_ATTR_S这个结构体,这个结构体中还包括了三个结构体,每个结构体功能不一样
  • 需要按要求选择编码等级,不然选择了最高的编码等级但网络不好容易黑屏
  • 编码器的选择需要看仔细
  • 目标帧和原始帧最好选择和摄像头硬件匹配的,不然会有音频被加速的感觉。我的硬件25合适

?

2.3 AI模块初始化

int rkmedia_AI_Init()
{
    RV1126_AI_CONFIG ai_Config;
    memset(&ai_Config, 0, sizeof(ai_Config));
    ai_Config.id = 0;
    ai_Config.attr.pcAudioNode = "default";                                      //音频节点路径
    ai_Config.attr.enSampleFormat = RK_SAMPLE_FMT_S16;   //采样格式
    ai_Config.attr.u32SampleRate = 48000;                                         //采样率
    ai_Config.attr.u32Channels = 2;                                                         //通道数
    ai_Config.attr.u32NbSamples = 1024;                                              //每帧采样数
    ai_Config.attr.enAiLayout = AI_LAYOUT_NORMAL;                   //音频布局 
    int ret = rkmedia_AI_Module_Init(&ai_Config);
    if(0 == ret)
    {
        RV1126_AI_CONTAINTER ai_container;
        ai_container.index = 0;
        ai_container.Ai_Channel_ID = ai_Config.id;
        set_ai_container(0,&ai_container);
    }else{
        puts("AI Init Failed");
    }
    return 0;
}

?

这个是音频的AI模块的初始化

注意点:

采样率:96000, 88200, 64000, 48000, 44100, 32000,采样率的选择很多,但一般48000就可以

通道数:单声道,双声道,四声道等等,一般2声道即可

采样个数:1024

2.4 AENC模块初始化

int rkmedia_AENC_Init()
{
    RV1126_AENC_CONFIG rkmedia_aenc_config; 
    rkmedia_aenc_config.id = 0;
    rkmedia_aenc_config.attr.enCodecType = RK_CODEC_TYPE_AAC; //AENC的编码类型
    rkmedia_aenc_config.attr.u32Bitrate = 153600;                                       //AENC的音频码率
    rkmedia_aenc_config.attr.u32Quality = 1;                                                    //AENC编码质量
    rkmedia_aenc_config.attr.stAencAAC.u32Channels = 2;                         //AENC编码通道
    rkmedia_aenc_config.attr.stAencAAC.u32SampleRate = 48000;           //AENC编码采样率
    int ret = rkmedia_AENC_Module_Init(&rkmedia_aenc_config);
    if(0 == ret)
    {
        RV1126_AENC_CONTAINER aenc_container;
        aenc_container.index = 0;
        aenc_container.AENC_Channel_ID = rkmedia_aenc_config.id;
        set_aenc_container(0, &aenc_container);
        puts("AENC Container Success!");
    }
    else
    {

    }
    return 0;
}

?注意:AENC的配置参数要和AI的参数对应上,声道数,采样率等等

?

文章来源:https://blog.csdn.net/weixin_73901182/article/details/135370567
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。