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