从本章开始我们将要学习嵌入式音视频的学习了 ,使用的瑞芯微的开发板
个人主页:@ChenPi
推荐专栏1: 《C++_@ChenPi的博客-CSDN博客》✨✨✨
推荐专栏2: 《Linux C应用编程(概念类)_@ChenPi的博客-CSDN博客》✨✨✨
推荐专栏3:《嵌入式音视频_@ChenPi的博客-CSDN博客》
本篇简介 :本章主要讲解VI VENC模块和AI AENC模块的初始化及具体函数详解
构造一个项目,我们需要先将大概的框架给理解清楚,这样对写代码提供很多帮助
首先,我们看一下主函数
我们的主函数我们就写成这样,把功能和任务都分模块写,这样看代码和移植到方便一些
我们可以看到主函数接收参数的
我们要接收三个参数
- 参数1为可执行文件名
- 参数2为复合流格式
- 参数3为将要推流到的流媒体的地址
第三个红框就是初始化一些参数了
我们重点最后一个红框
这里面的内容是项目跑起来的关键
//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模块的绑定操作进行了一个封装
//初始化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;
}
需要注意的几个点
- 需要理解VENC_CHN_ATTR_S这个结构体,这个结构体中还包括了三个结构体,每个结构体功能不一样
- 需要按要求选择编码等级,不然选择了最高的编码等级但网络不好容易黑屏
- 编码器的选择需要看仔细
- 目标帧和原始帧最好选择和摄像头硬件匹配的,不然会有音频被加速的感觉。我的硬件25合适
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
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的参数对应上,声道数,采样率等等