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