音视频开发-PCM 原理与 AI 模块实战

1. 引言

音视频开发是移动应用、嵌入式系统和多媒体平台的核心技术方向。无论是语音通话、音乐播放、语音识别还是智能音箱,都离不开音频数据的采集、处理与播放。而这一切的起点,就是音频原始数据 PCM(脉冲编码调制)。本文将从 PCM 原理出发,系统讲解音频数据的生成过程、核心参数与存储格式,并结合 AI 模块(语音识别、AI 降噪等)的实战应用,帮助读者建立从底层数据到上层智能处理的完整认知。

2. PCM 音频原始数据

2.1 PCM 数据的生成过程

PCM 全称是脉冲编码调制(Pulse Code Modulation),是未经过压缩的音频数据。它由模拟信号经过 采样、量化、编码 三大步骤转换而来:
#mermaid-svg-r2RRNApwZbZuF4Cc{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-r2RRNApwZbZuF4Cc .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-r2RRNApwZbZuF4Cc .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-r2RRNApwZbZuF4Cc .error-icon{fill:#552222;}#mermaid-svg-r2RRNApwZbZuF4Cc .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-r2RRNApwZbZuF4Cc .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-r2RRNApwZbZuF4Cc .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-r2RRNApwZbZuF4Cc .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-r2RRNApwZbZuF4Cc .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-r2RRNApwZbZuF4Cc .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-r2RRNApwZbZuF4Cc .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-r2RRNApwZbZuF4Cc .marker{fill:#333333;stroke:#333333;}#mermaid-svg-r2RRNApwZbZuF4Cc .marker.cross{stroke:#333333;}#mermaid-svg-r2RRNApwZbZuF4Cc svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-r2RRNApwZbZuF4Cc p{margin:0;}#mermaid-svg-r2RRNApwZbZuF4Cc .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-r2RRNApwZbZuF4Cc .cluster-label text{fill:#333;}#mermaid-svg-r2RRNApwZbZuF4Cc .cluster-label span{color:#333;}#mermaid-svg-r2RRNApwZbZuF4Cc .cluster-label span p{background-color:transparent;}#mermaid-svg-r2RRNApwZbZuF4Cc .label text,#mermaid-svg-r2RRNApwZbZuF4Cc span{fill:#333;color:#333;}#mermaid-svg-r2RRNApwZbZuF4Cc .node rect,#mermaid-svg-r2RRNApwZbZuF4Cc .node circle,#mermaid-svg-r2RRNApwZbZuF4Cc .node ellipse,#mermaid-svg-r2RRNApwZbZuF4Cc .node polygon,#mermaid-svg-r2RRNApwZbZuF4Cc .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-r2RRNApwZbZuF4Cc .rough-node .label text,#mermaid-svg-r2RRNApwZbZuF4Cc .node .label text,#mermaid-svg-r2RRNApwZbZuF4Cc .image-shape .label,#mermaid-svg-r2RRNApwZbZuF4Cc .icon-shape .label{text-anchor:middle;}#mermaid-svg-r2RRNApwZbZuF4Cc .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-r2RRNApwZbZuF4Cc .rough-node .label,#mermaid-svg-r2RRNApwZbZuF4Cc .node .label,#mermaid-svg-r2RRNApwZbZuF4Cc .image-shape .label,#mermaid-svg-r2RRNApwZbZuF4Cc .icon-shape .label{text-align:center;}#mermaid-svg-r2RRNApwZbZuF4Cc .node.clickable{cursor:pointer;}#mermaid-svg-r2RRNApwZbZuF4Cc .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-r2RRNApwZbZuF4Cc .arrowheadPath{fill:#333333;}#mermaid-svg-r2RRNApwZbZuF4Cc .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-r2RRNApwZbZuF4Cc .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-r2RRNApwZbZuF4Cc .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-r2RRNApwZbZuF4Cc .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-r2RRNApwZbZuF4Cc .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-r2RRNApwZbZuF4Cc .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-r2RRNApwZbZuF4Cc .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-r2RRNApwZbZuF4Cc .cluster text{fill:#333;}#mermaid-svg-r2RRNApwZbZuF4Cc .cluster span{color:#333;}#mermaid-svg-r2RRNApwZbZuF4Cc div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-r2RRNApwZbZuF4Cc .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-r2RRNApwZbZuF4Cc rect.text{fill:none;stroke-width:0;}#mermaid-svg-r2RRNApwZbZuF4Cc .icon-shape,#mermaid-svg-r2RRNApwZbZuF4Cc .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-r2RRNApwZbZuF4Cc .icon-shape p,#mermaid-svg-r2RRNApwZbZuF4Cc .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-r2RRNApwZbZuF4Cc .icon-shape .label rect,#mermaid-svg-r2RRNApwZbZuF4Cc .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-r2RRNApwZbZuF4Cc .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-r2RRNApwZbZuF4Cc .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-r2RRNApwZbZuF4Cc :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 模拟音频信号
采样
量化
编码
PCM 数字信号

采样:把一段连续的模拟信号转换成离散的数字信号。采样率指每秒钟采样的个数。根据奈奎斯特采样定理:当采样率大于等于连续信号最高频率的 2 倍时,采样信号就能无差别还原出原始信号。人类听觉频率范围是 20Hz~20kHz,因此采样率需达到 40kHz 以上才能保证数据完整性。

量化:在坐标轴上把每一个离散采样点进行数字化操作,即把每个采样点用竖线表示出来,方便后续数字化存储。

编码:把每一个量化后的采样点以二进制形式存储起来。把所有采样点的编码数据连续拼接,就是一段完整的 PCM 数据,例如:

text 复制代码
011011110111101......

因此,音频原始数字信号的生成链路可概括为:

text 复制代码
采样 -> 量化 -> 编码 = PCM 数据

2.2 PCM 核心参数

2.2.1 采样率

采样率指每秒钟采样的个数,即 1 秒内采集声音的频率。例如 48000Hz 表示一秒钟采集 48000 个采样点。采样率越高,音频质量越好。PCM 常用采样率如下:

  • 192000Hz(192kHz):蓝光、高清电影 DVD。
  • 96000Hz(96kHz):蓝光、高清电影 DVD。
  • 48000Hz(48kHz):数字电视、DVD,最常用。
  • 44100Hz(44.1kHz):CD 音质。
  • 22000Hz(22kHz):无线广播。
2.2.2 采样深度(位深)

采样深度表示每次采样的大小。例如采样深度为 16bit,则声音有 2 的 16 次方个振幅等级;32bit 则有 2 的 32 次方个振幅等级。振幅等级越多,声音质量越高。PCM 常见采样深度有 8bit、16bit、32bit 三种。

2.2.3 通道数

PCM 常见通道数有四种:

  • 单声道:只有一个声音通道,如电话、喇叭。
  • 双声道(立体声):两个独立声道,录制时声音分配到左右两个通道,听感更立体。
  • 四声道:前左、前右、后左、后右四个发声通道,听感如被声音包围。
  • 5.1 声道:广泛用于家庭影院,开发中较少使用。
2.2.4 PCM 比特率

比特率指每秒传输的比特数(bit),PCM 比特率计算公式为:

text 复制代码
比特率 = 采样率 × 采样深度 × 通道数

例如采样率 48000、采样深度 16bit、通道数 2,则比特率为:

text 复制代码
48000 × 16 × 2 = 1536000 bit/s
2.2.5 PCM 文件大小计算

假设一个 PCM 音频设备采样率 48000、采样精度 16bit、2 通道,采集 10 分钟数据,其大小为:

text 复制代码
48000 × 16 × 2 × 10 × 60 = 921600000 bit

将 bit 转换为字节:

text 复制代码
921600000 / 8 / 1024 / 1024 ≈ 109 MB

可见 PCM 数据体积较大,这也是实际工程中常需压缩编码(如 AAC、Opus)的原因。

2.3 PCM 存储格式

PCM 单双声道的存储布局不同,这里重点讲解双声道。双声道有两种存储方式:

  • 交错模式(Interleaved):先记录第一帧的左声道样本和右声道样本,再记录第二帧,依次交替。
  • 非交错模式(Non-Interleaved):先记录一个周期内所有帧的左声道样本,再记录所有右声道样本。
text 复制代码
交错模式:L R L R L R L R
非交错模式:L L L L L R R R R R

3. RV1126 AI 音频模块实战

cpp 复制代码
#include <assert.h>
#include <fcntl.h>
#include <getopt.h>
#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

#include "rkmedia_api.h"
#define AUDIO_PATH "default"
#define AI_CHN 0

//获取PCM数据的线程
void * get_ai_pcm_thread(void * args)
{
    pthread_detach(pthread_self());
    FILE * pcm_file = fopen("test_ai.pcm", "w+");
    MEDIA_BUFFER mb ;

    while (1)
    {
        //获取PCM数据的线程
        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_AI, AI_CHN, -1);
        if(!mb)
        {
            printf("RK_MPI_SYS_GetMediaBuffer Failed....\n");
            break;
        }
        
        printf("get_pcm_data success...\n");
        fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, pcm_file);
        RK_MPI_MB_ReleaseBuffer(mb);
    }
}


int main(int argc, char *argv[])
{
    int ret;
    AI_CHN_ATTR_S ai_chn_s;
    ai_chn_s.pcAudioNode = AUDIO_PATH; //音频路径,默认default
    ai_chn_s.u32SampleRate = 48000; //音频采样率
    ai_chn_s.u32Channels = 2;   //音频通道数
    ai_chn_s.u32NbSamples = 1024; //音频采样个数,这里固定1024
    ai_chn_s.enSampleFormat = RK_SAMPLE_FMT_S16;//将音频通道的采样格式设置为 16位有符号PCM
    ai_chn_s.enAiLayout = AI_LAYOUT_NORMAL;  //NORMAL
    ret = RK_MPI_AI_SetChnAttr(AI_CHN, &ai_chn_s);  //设置AI模块
    if(ret)
    {
        printf("Set Ai_Chn_Attr Failed....\n");
    }
    else
    {
        printf("Set Ai_Chn_Attr Success....\n");
    }

    ret = RK_MPI_AI_EnableChn(AI_CHN);  //使能AI模块
    if(ret)
    {
        printf("Enable Ai_Chn_Attr Failed....\n");
    }

    ret = RK_MPI_AI_StartStream(AI_CHN); //启动音频AI模块
    if(ret)
    {
        printf("RK_MPI_AI_StartStream Failed....\n");
    }

    pthread_t pid;
    pthread_create(&pid, NULL, get_ai_pcm_thread, NULL); 

    while (1)
    {
        sleep(2);
    }

    RK_MPI_AI_DisableChn(AI_CHN);


    return 0;
}
相关推荐
HySpark3 小时前
熙瑾·会悟 ASR 实战:Qwen-ASR 漏字导致转写不完整,如何从音频分段到二次校验解决?
音视频·熙瑾会悟
大鹅办公4 小时前
酷狗音乐怎么转换MP3格式?4种方法亲测对比+避坑指南(附FFmpeg命令行教程)
ffmpeg·音视频·音频格式
小妖同学学AI5 小时前
AI视频生成难在提示词?这个Claude插件让Seedance 2.0效率翻倍,附超全示例!
人工智能·开源·github·音视频
梦想的旅途27 小时前
企业微信视频消息:mp4当图片发送失败
音视频·企业微信
老衲の少女心7 小时前
【AI项目】从零构建 AI 视频生成系统:多模型编排的工程实践
人工智能·音视频
h×317 小时前
FPGA视频4分屏项目 - 系统架构详细讲解
fpga开发·音视频
聚美智数21 小时前
视频审核-智能实时审核-短视频审核API接口介绍
音视频
怪奇云呼军1 天前
知识库也会注入指令?闪电智能VoiceAgent 如何防住 Prompt Injection
人工智能·python·算法·云计算·音视频
EasyDSS1 天前
开会不用装App:私有化音视频系统EasyDSS即时视频会议,浏览器点开就能聊,AI帮你写纪要
人工智能·音视频