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;
}
相关推荐
comedate5 小时前
Windows / Linux GPU 虚拟内存布局差异与 CUDA 越界访问行为
linux·windows·mmu·cuda 越界访问
h×36 小时前
FPGA视频4分屏项目 - 系统架构详细讲解
fpga开发·音视频
暴力求解7 小时前
Linux网络---传输层协议TCP(二)
linux·服务器·开发语言·网络·tcp/ip
ltl8 小时前
序列化格式深度对比:Protobuf、FlatBuffers、Cap’n Proto
linux
lengjingzju8 小时前
编译与调试完全指南—第17章 总结
linux
ltl8 小时前
容器网络性能真相:veth vs macvlan vs eBPF 数据面
linux
我不会插花弄玉9 小时前
9.进程间通信(上)【由浅入深-Linux】
linux·共享内存·进程通信
莫浅子10 小时前
day01-USB架构与枚举
c++·单片机·嵌入式驱动
CSDN1211010 小时前
麒麟 V10 安装 Node-RED、IEC 104 协议插件及界面汉化
linux·编辑器·vim
恒锐丰科技韩生10 小时前
SS8844T|8.2‑40V 四通道独立半桥驱动 ETSSOP28 带散热焊盘 工业自动化机器人专用
嵌入式硬件·硬件工程