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; } ```

相关推荐
hahaha60163 小时前
模拟电路中什么时候适合使用电流传递信号,什么时候合适使用电压传递信号
stm32·单片机·嵌入式硬件
iphone1083 小时前
企业内部机密视频安全保护|如何防止企业内部机密视频泄露?
安全·音视频·视频加密·加密技术·视频安全·企业机密·机密视频
小小少年1234 小时前
基于蓝牙的stm32智能火灾烟雾报警系统设计
stm32·单片机·嵌入式硬件
UNbuff4 小时前
Linux gzip 命令使用说明
linux
幸运狗头6 小时前
Linux学习-基于TCP实现群聊
linux·学习·tcp/ip·群聊
渡己(Sorin)6 小时前
Ubuntu有限网口无法使用解决方法
linux·运维·ubuntu
不懂机器人6 小时前
linux网络编程-----TCP服务端并发模型(epoll)
linux·网络·tcp/ip·算法
qq_297075676 小时前
网络安全测试(一)Kali Linux
linux·运维·服务器
点灯小铭6 小时前
基于51单片机红外避障车辆高速汽车测速仪表设计
单片机·嵌入式硬件·汽车·毕业设计·51单片机·课程设计
音视频牛哥8 小时前
机器人视频感知架构深度解析:7条技术法则,打造低延迟实时感知与交互
人工智能·计算机视觉·机器人·音视频·大牛直播sdk·机器视觉·rtmp rtsp播放器