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

发布于:2025-08-06 ⋅ 阅读:(98) ⋅ 点赞:(0)

目录

一、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; // 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

#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

#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;
}


网站公告

今日签到

点亮在社区的每一天
去签到