当前位置: 首页 > news >正文

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

目录

一、RV1126 增加 USB 音视频设备

二、RkMedia 音频 API

2.1 PCM 音频输入

        系统初始化

        AI 通道配置

        AI 通道使能

        开启数据流

        获取数据

        保存数据

2.2 编码音频编码输入

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

USB 音频

Device Drivers --->

        <*> Sound card support --->

                <*> Advanced Linux Sound Architecture --->

                        [*] USB sound devices --->

                                <*> USB Audio/MIDI driver

保存退出

        make ARCH=arm savedefconfig

        cp defconfig arch/arm/configs/rv1126_defconfig

        编译固件然后烧录

使用

查看声音输出设备

        aplay -l

        当前 USB 声卡为 card1

        所以执行的指令为:

        aplay -D plughw:1,0 /sdcard/1.wav

查看声音输入设备

arecord -l

查看视频输入设备

v4l2-ctl --list-devices

官方音频测试例程

        SDK/buildroot/output/rockchip_rv1126_rv1109/build/rkmedia/examples

                rkmedia_audio_test.c

像编译自己写的程序一样编译即可

编译内核红色的警告

这个是正常的,是 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

        播放 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 的参数保持一致

RK_MPI_SYS_Init();RK_MPI_AO_SetChnAttr(0, &ao_attr);RK_MPI_AO_EnableChn(0);//计算延时时间RK_U32 u32Timeval = u32FrameCnt * 1000000 / u32SampleRate; // usMB_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

代码

mp2_aenc

#include "main.h"
#include <time.h>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编码格式给1ai_pstAttr.u32NbSamples = nbsmp;     //对于MP2编码格式给1152,对于G711A编码格式给1024ai_pstAttr.u32SampleRate = srate;    //PCM格式,不要太低,G711A编码格式给8000RK_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 <time.h>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编码格式给1ai_pstAttr.u32NbSamples = nbsmp;     //对于MP2编码格式给1152,对于G711A编码格式给1024ai_pstAttr.u32SampleRate = srate;    //PCM格式,不要太低,G711A编码格式给8000RK_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绑定AENC1MPP_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

#include "main.h"
#include <time.h>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编码格式给1ai_pstAttr.u32NbSamples = nbsmp;     //对于MP2编码格式给1152,对于G711A编码格式给1024ai_pstAttr.u32SampleRate = srate;    //PCM格式,不要太低,G711A编码格式给8000RK_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

#include "main.h"
#include <time.h>RK_U32 ai_chn = 2;      //mp2给2, 于G711A编码格式给1
RK_U32 nbsmp = 1152;    //对于MP2编码格式给1152,对于G711A编码格式给1024
RK_U32 srate = 48000;   //PCM格式,不要太低,G711A编码格式给8000FILE *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 BufferMEDIA_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;
}
http://www.xdnf.cn/news/1245709.html

相关文章:

  • Windows 远程管理 (WinRM)问题详解包括c#与python例子
  • C++ 变量初始化方式总结 | 拷贝初始化 | 列表初始化 | 值初始化
  • YooAsset源码阅读-Downloader篇
  • 本地使用uv管理的python项目怎么部署到服务器?
  • 攻击实验(ARP欺骗、MAC攻击、报文洪水攻击、DNS欺骗)
  • Laravel The requested URL /hellowzy was not found on this server. 404 问题的解决
  • 2025年渗透测试面试题总结-01(题目+回答)
  • 《Node.js与 Elasticsearch的全文搜索架构解析》
  • 如何用分布式架构视角理解宇宙稳定性?从精细调参到微服务的类比思考
  • 【C++】模板深入进阶
  • 检索召回率优化探究四:基于LangChain0.3集成Milvu2.5向量数据库构建的智能问答系统
  • Sklearn 机器学习 数据聚类 层次聚类的两个重要属性
  • 编码器模型和解码器模型解析
  • GPT-5的诞生之痛:AI帝国的现实危机
  • LLM开发——语言模型会根据你的提问方式来改变答案
  • arp攻击(ettercap 版本0.8.3.1)
  • Physics Simulation - UE中Projectile相关事项
  • tensorRT配合triton部署模型
  • HTML 如何转 Markdown
  • 【Redis】string常用命令
  • 417页PDF | 2025年“人工智能+”行业标杆案例荟萃
  • 三款好用的PDF阅读器
  • 深入理解 Android SO 导出符号:机制与安全优化
  • Python高级编程与实践:Python高级数据结构与编程技巧
  • 后量子时代已至?中国量子加密技术突破与网络安全新基建
  • 前端1.0
  • AIDL学习
  • 云计算一阶段Ⅱ——11. Linux 防火墙管理
  • 国产大模型平替方案:Spring Boot通义千问API集成指南
  • 【实时Linux实战系列】实时视频监控系统的开发