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