Linux驱动25 --- RkMedia音频API使用&&增加 USB 音视频设备

目录

[一、RV1126 增加 USB 音视频设备](#一、RV1126 增加 USB 音视频设备)

[二、RkMedia 音频 API](#二、RkMedia 音频 API)

[2.1 PCM 音频输入](#2.1 PCM 音频输入)

系统初始化

[AI 通道配置](#AI 通道配置)

[AI 通道使能](#AI 通道使能)

开启数据流

获取数据

保存数据

[2.2 编码音频编码输入](#2.2 编码音频编码输入)

[2.3 PCM 音频输出](#2.3 PCM 音频输出)


一、RV1126 增加 USB 音视频设备

配置过程

第一步:来到 SDK 内核路径下

source envsetup.sh --- 选择:rockchip_rv1126_rv1109_spi_nand 选项

./build.sh lunch --- 选择:BoardConfig-38x38-spi-nand.mk 选项

cd kernel

make ARCH=arm rv1126_defconfig

make ARCH=arm menuconfig

USB 摄像头支持

Device Drivers --->

<*> Multimedia support --->

\*\] Media USB Adapters ---\> \<\*\> USB Video Class (UVC) \[\*\] UVC input events device support ![](https://i-blog.csdnimg.cn/direct/318e689248a7409b9b396c44b28371f7.png) USB 音频 Device Drivers ---\> \<\*\> Sound card support ---\> \<\*\> Advanced Linux Sound Architecture ---\> \[\*\] USB sound devices ---\> \<\*\> USB Audio/MIDI driver ![](https://i-blog.csdnimg.cn/direct/e1fa263cbadf4cd1813c7b649319addc.png) 保存退出 make ARCH=arm savedefconfig cp defconfig arch/arm/configs/rv1126_defconfig 编译固件然后烧录 使用 **查看声音输出设备** aplay -l ![](https://i-blog.csdnimg.cn/direct/9068663957304511b37f345345871449.png) 当前 USB 声卡为 card1 所以执行的指令为: aplay -D plughw:1,0 /sdcard/1.wav **查看声音输入设备** arecord -l ![](https://i-blog.csdnimg.cn/direct/ee2a8af033ea4a9d80c4e28913b88050.png) 查看视频输入设备 v4l2-ctl --list-devices ![](https://i-blog.csdnimg.cn/direct/32ce0397352744d09e0f4bb8577ca225.png) **官方音频测试例程** SDK/buildroot/output/rockchip_rv1126_rv1109/build/rkmedia/examples rkmedia_audio_test.c 像编译自己写的程序一样编译即可 **编译内核红色的警告** ![](https://i-blog.csdnimg.cn/direct/ceb81ef3c8994615948ab1b9f8a234cb.png) 这个是正常的,是 SDK 提醒不要随便改电源配置 ## 二、RkMedia 音频 API **核心:音频** ### 2.1 PCM 音频输入 #### 系统初始化 RK_MPI_SYS_Init(); #### AI 通道配置 RK_MPI_AI_SetChnAttr(0, \&ai_attr); #### AI 通道使能 RK_MPI_AI_EnableChn(0); #### 开启数据流 RK_MPI_AI_StartStream(0); #### 获取数据 #### 保存数据 arecord -L ![](https://i-blog.csdnimg.cn/direct/f5937c3dcb454a56be3b260276bc7c0f.png) 播放 PCM 的指令 aplay -f S16_LE -r 48000 -c 2 9203.pcm ### 2.2 编码音频编码输入 MP2 用于和 H264 视频共同合成一个 mp4 文件 G711A 用于音频推流--- rkmedia 不支持推太大的数据流 编码后的文件是无法播放的 后续 MP2 在合成的音视频中可以播放 G711A 可以推流之后在 VLC 播放 **RV1126板子可以做的音频解码** **可以做 G711A 的解码** 编码和 PCM 多的内容在 创建一个编码通道 做一个绑定 ### 2.3 PCM 音频输出 主要使用的是 AO 通道 AI --- 音频输入设置的参数 为了保存数据 AO --- 音频输出设置的参数 为了准确无误的获取参数 AO 的参数要和 AI 的参数保持一致 ```cpp RK_MPI_SYS_Init(); RK_MPI_AO_SetChnAttr(0, &ao_attr); RK_MPI_AO_EnableChn(0); //计算延时时间 RK_U32 u32Timeval = u32FrameCnt * 1000000 / u32SampleRate; // us MB_AUDIO_INFO_S stSampleInfo = { ao_attr.u32Channels, ao_attr.u32SampleRate, ao_attr.u32NbSamples, ao_attr.enSampleFormat }; mb = RK_MPI_MB_CreateAudioBufferExt(&stSampleInfo, RK_FALSE, 0); fread(RK_MPI_MB_GetPtr(mb), 1, RK_MPI_MB_GetSize(mb), file); RK_MPI_SYS_SendMediaBuffer(RK_ID_AO, 0, mb); usleep(u32Timeval); RK_MPI_MB_ReleaseBuffer(mb); mb = NULL; ``` aplay -L ![](https://i-blog.csdnimg.cn/direct/925dd4c1bece4f9dac0dff7bd2873e2b.png) 代码 mp2_aenc #include "main.h" #include RK_U32 ai_chn = 2; //于G711A编码格式给1 RK_U32 nbsmp = 1152; //对于MP2编码格式给1152,对于G711A编码格式给1024 RK_U32 srate = 48000; //PCM格式,不要太低,G711A编码格式给8000 int end_flag = 0; FILE *file; // 输出回调函数 void myoutcbfunc(MEDIA_BUFFER mb) { if(end_flag) { RK_MPI_MB_ReleaseBuffer(mb); return; } fwrite(RK_MPI_MB_GetPtr(mb), 1, RK_MPI_MB_GetSize(mb), file); RK_MPI_MB_ReleaseBuffer(mb); } int main(void) {//PCM音频输入 file = fopen("./9203.mp2", "w"); //1.系统初始化 RK_MPI_SYS_Init(); //2.AI通道配置 AI_CHN_ATTR_S ai_pstAttr = {0}; ai_pstAttr.enAiLayout = AI_LAYOUT_NORMAL; ai_pstAttr.enSampleFormat = RK_SAMPLE_FMT_S16; ai_pstAttr.pcAudioNode = "default:CARD=Device"; ai_pstAttr.u32Channels = ai_chn; //于G711A编码格式给1 ai_pstAttr.u32NbSamples = nbsmp; //对于MP2编码格式给1152,对于G711A编码格式给1024 ai_pstAttr.u32SampleRate = srate; //PCM格式,不要太低,G711A编码格式给8000 RK_MPI_AI_SetChnAttr(0, &ai_pstAttr); //AI通道使能 RK_MPI_AI_EnableChn(0); //开启数据流 RK_MPI_AI_StartStream(0); //获取数据 MPP_CHN_S ai_pstChn = {0}; ai_pstChn.enModId = RK_ID_AI;//视频输入通道 ai_pstChn.s32ChnId = 0;//VI通道 ai_pstChn.s32DevId = 0; RK_MPI_SYS_RegisterOutCb(&ai_pstChn, myoutcbfunc); int count = 10; while(1) { sleep(1); if(!count) { end_flag = 1; break; } printf("剩余 %d 秒结束\n", count); count--; } fclose(file); RK_MPI_AI_DisableChn(0); //保存数据 return 0; } g711a_aenc #include "main.h" #include RK_U32 ai_chn = 1; //mp2给2, 于G711A编码格式给1 RK_U32 nbsmp = 1024; //对于MP2编码格式给1152,对于G711A编码格式给1024 RK_U32 srate = 8000; //PCM格式,不要太低,G711A编码格式给8000 int end_flag = 0; FILE *file; // 输出回调函数 void myoutcbfunc(MEDIA_BUFFER mb) { if(end_flag) { RK_MPI_MB_ReleaseBuffer(mb); return; } fwrite(RK_MPI_MB_GetPtr(mb), 1, RK_MPI_MB_GetSize(mb), file); RK_MPI_MB_ReleaseBuffer(mb); } int main(void) {//PCM音频输入 //file = fopen("./9203.mp2", "w"); file = fopen("./9203.g711a", "w"); //1.系统初始化 RK_MPI_SYS_Init(); //2.AI通道配置 AI_CHN_ATTR_S ai_pstAttr = {0}; ai_pstAttr.enAiLayout = AI_LAYOUT_NORMAL; ai_pstAttr.enSampleFormat = RK_SAMPLE_FMT_S16; ai_pstAttr.pcAudioNode = "default:CARD=Device"; ai_pstAttr.u32Channels = ai_chn; //于G711A编码格式给1 ai_pstAttr.u32NbSamples = nbsmp; //对于MP2编码格式给1152,对于G711A编码格式给1024 ai_pstAttr.u32SampleRate = srate; //PCM格式,不要太低,G711A编码格式给8000 RK_MPI_AI_SetChnAttr(0, &ai_pstAttr); //AI通道使能 RK_MPI_AI_EnableChn(0); //开启数据流 RK_MPI_AI_StartStream(0); AENC_CHN_ATTR_S aenc_pstAttr = {0}; // aenc_pstAttr.enCodecType = RK_CODEC_TYPE_MP2; // aenc_pstAttr.stAencMP2.u32Channels = ai_chn; // aenc_pstAttr.stAencMP2.u32SampleRate = srate; aenc_pstAttr.enCodecType = RK_CODEC_TYPE_G711A; aenc_pstAttr.stAencG711A.u32Channels = ai_chn; aenc_pstAttr.stAencG711A.u32NbSample = nbsmp; aenc_pstAttr.stAencG711A.u32SampleRate = srate; aenc_pstAttr.u32Bitrate = 64000; //严格来说,这个需要算 aenc_pstAttr.u32Quality = 1; RK_MPI_AENC_CreateChn(0, &aenc_pstAttr); //在此创建一个通道 --- 演示编码MP2编码(音视频合成)和G711A的编码(推流) --- AI0绑定AENC0,AI0绑定AENC1 MPP_CHN_S a_pstSrcChn = {0}; a_pstSrcChn.enModId = RK_ID_AI; a_pstSrcChn.s32ChnId = 0; a_pstSrcChn.s32DevId = 0; MPP_CHN_S a_pstDestChn = {0}; a_pstDestChn.enModId = RK_ID_AENC; //后续AENC的通道ID是需要改的 a_pstDestChn.s32ChnId = 0; a_pstDestChn.s32DevId = 0; RK_MPI_SYS_Bind(&a_pstSrcChn, &a_pstDestChn); RK_MPI_SYS_RegisterOutCb(&a_pstDestChn, myoutcbfunc); int count = 10; while(1) { sleep(1); if(!count) { end_flag = 1; break; } printf("剩余 %d 秒结束\n", count); count--; } fclose(file); RK_MPI_SYS_UnBind(&a_pstSrcChn, &a_pstDestChn); RK_MPI_AENC_DestroyChn(0); RK_MPI_AI_DisableChn(0); //保存数据 return 0; } ai_pcm ```cpp #include "main.h" #include RK_U32 ai_chn = 2; //于G711A编码格式给1 RK_U32 nbsmp = 1152; //对于MP2编码格式给1152,对于G711A编码格式给1024 RK_U32 srate = 48000; //PCM格式,不要太低,G711A编码格式给8000 int end_flag = 0; FILE *file; // 输出回调函数 void myoutcbfunc(MEDIA_BUFFER mb) { if(end_flag) { RK_MPI_MB_ReleaseBuffer(mb); return; } fwrite(RK_MPI_MB_GetPtr(mb), 1, RK_MPI_MB_GetSize(mb), file); RK_MPI_MB_ReleaseBuffer(mb); } int main(void) {//PCM音频输入 file = fopen("./9203.pcm", "w"); //1.系统初始化 RK_MPI_SYS_Init(); //2.AI通道配置 AI_CHN_ATTR_S ai_pstAttr = {0}; ai_pstAttr.enAiLayout = AI_LAYOUT_NORMAL; ai_pstAttr.enSampleFormat = RK_SAMPLE_FMT_S16; ai_pstAttr.pcAudioNode = "default:CARD=Device"; ai_pstAttr.u32Channels = ai_chn; //于G711A编码格式给1 ai_pstAttr.u32NbSamples = nbsmp; //对于MP2编码格式给1152,对于G711A编码格式给1024 ai_pstAttr.u32SampleRate = srate; //PCM格式,不要太低,G711A编码格式给8000 RK_MPI_AI_SetChnAttr(0, &ai_pstAttr); //AI通道使能 RK_MPI_AI_EnableChn(0); //开启数据流 RK_MPI_AI_StartStream(0); //获取数据 MPP_CHN_S ai_pstChn = {0}; ai_pstChn.enModId = RK_ID_AI;//视频输入通道 ai_pstChn.s32ChnId = 0;//VI通道 ai_pstChn.s32DevId = 0; RK_MPI_SYS_RegisterOutCb(&ai_pstChn, myoutcbfunc); int count = 10; while(1) { sleep(1); if(!count) { end_flag = 1; break; } printf("剩余 %d 秒结束\n", count); count--; } fclose(file); RK_MPI_AI_DisableChn(0); //保存数据 return 0; } ``` ao_pcm ```cpp #include "main.h" #include RK_U32 ai_chn = 2; //mp2给2, 于G711A编码格式给1 RK_U32 nbsmp = 1152; //对于MP2编码格式给1152,对于G711A编码格式给1024 RK_U32 srate = 48000; //PCM格式,不要太低,G711A编码格式给8000 FILE *file; int main(void) { file = fopen("./9203.pcm", "r"); RK_MPI_SYS_Init(); //1.设置AO通道属性 AO_CHN_ATTR_S ao_pstAttr = {0}; ao_pstAttr.enSampleFormat = RK_SAMPLE_FMT_S16; ao_pstAttr.pcAudioNode = "default:CARD=rockchipi2s0sou"; ao_pstAttr.u32Channels = ai_chn; ao_pstAttr.u32NbSamples = nbsmp; ao_pstAttr.u32SampleRate = srate; RK_MPI_AO_SetChnAttr(0, &ao_pstAttr); //2.设置AO通道 RK_MPI_AO_EnableChn(0); //3.计算延时时间 RK_U32 u32Timeval = nbsmp * 1000000 / srate; // us //4.填充核心结构体 MB_AUDIO_INFO_S stSampleInfo = { ao_pstAttr.u32Channels, ao_pstAttr.u32SampleRate, ao_pstAttr.u32NbSamples, ao_pstAttr.enSampleFormat }; //5.创建Media Buffer MEDIA_BUFFER mb = NULL; int ret = 0; //结束标志 while(1) { mb = RK_MPI_MB_CreateAudioBufferExt(&stSampleInfo, RK_FALSE, 0); //6.读取一帧数据 ret = fread(RK_MPI_MB_GetPtr(mb), 1, RK_MPI_MB_GetSize(mb), file); if(ret <= 0) { break; } //7.发送给AO通道 RK_MPI_SYS_SendMediaBuffer(RK_ID_AO, 0, mb); //8.延时 usleep(u32Timeval); RK_MPI_MB_ReleaseBuffer(mb); mb = NULL; } RK_MPI_MB_ReleaseBuffer(mb); mb = NULL; fclose(file); RK_MPI_AENC_DestroyChn(0); //保存数据 return 0; } ```

相关推荐
小嵌同学23 分钟前
Meson:开源的自动化构建系统
linux·运维·开源·自动化·meson
果子⌂1 小时前
Zabbix 企业级高级应用
linux·运维·nginx·zabbix
jinlong06031 小时前
GB28181监控平台LiveGBS如何配置GB28181对接海康、大华解码器上墙,将GB28181平台是视频给硬件解码器解码上墙
音视频
Antonio9151 小时前
【音视频】WebRTC 一对一通话-信令服
c++·websocket·音视频·webrtc
码小文2 小时前
Altium Designer 22使用笔记(4)---添加封装、ERC检查、PDF文档与BOM生成
笔记·嵌入式硬件·硬件工程·学习方法·硬件经验
IPFLY代理专家2 小时前
Linux设置动态IP的三种方法:图文+命令行实操详解
linux·前端框架
Antonio9152 小时前
【音视频】WebRTC 一对一通话-Web端
前端·音视频·webrtc
DogDaoDao2 小时前
WebRTC音视频编码模块深度解析:从编解码器到自适应码率控制(2025技术实践)
音视频·webrtc·实时音视频·视频编解码·h264·vp9·svc编码
猫猫的小茶馆2 小时前
【STM32】HAL库中的实现(四):RTC (实时时钟)
stm32·单片机·嵌入式硬件·mcu·51单片机·实时音视频·pcb工艺