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

目录

[一、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 <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编码格式给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 <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编码格式给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 <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编码格式给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 <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编码格式给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;
}
相关推荐
Dillon Dong3 小时前
【风电控制】TI TMS320F28379D 双CPU架构解析与任务分布设计
嵌入式硬件·算法·变流器·风电控制
为思念酝酿的痛9 小时前
POSIX信号量
linux·运维·服务器·后端
南山有乔木78910 小时前
网易云音乐下载的ncm歌曲怎么转换MP3?本地播放可以这样整理
音视频
人还是要有梦想的10 小时前
linux下用搜狗输入法,中英文切换
linux·运维·服务器
bush410 小时前
嵌入式linux学习记录二
linux·运维·学习
9分钟带帽10 小时前
linux_通过NFS挂载远程服务器的硬盘
linux·服务器
weixin_4684668511 小时前
MoneyPrinterTurbo 短视频自动化生产实战指南
运维·人工智能·自动化·大模型·音视频·moneyprinter
三易串口屏11 小时前
实验20 自动灭火场景实验
嵌入式硬件·串口屏·三易串口屏·uart 通信
蒸蛋一级爱好者12 小时前
TFTP协议
单片机·嵌入式硬件
优信电子12 小时前
STM32/C51驱动 DHTC11 温湿度传感器
stm32·单片机·嵌入式硬件·c51·温湿度传感器·dhtc11·环境测量