目录
[一、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

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

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