MP3音频解码详细过程(二)

最近做了无人机的音频解码,二周内从无任何音频基础到输出PCM数据码流到无人机上可以实现播报功能,其中遇到了许多莫名的坑,谨以此篇记录心得。也算交个作业。

架构设计思路:由usart 实时传输mp3音频码流,STM32F446 将音频流丢给软件音频解码器,解码器输出PCM码流到i2s的 dma双 缓存区。dma将pcm码流搬运给i2s外设。i2s将数据丢给tas5720 一款dac功放,即可实现实时音频播报。

MP3 文件是有帧(frame)构成的,frame 是文件最小组成单位。MP3 格式音乐文件普遍存在我们生活中,实际上MP3 本身是一种音频编码方式,全称为Moving Picture Experts Group Audio Layer III(MPEG Audio Layer 3)。Mp3 实际上是MPEG1 的Layer-3 层。为了降低失真度,MP3 采用感官编码技术,先对音频文件进行频谱分析,然后过滤掉噪音电平,然后通过量化方式,把剩下的每一位打散排列,形成MP3 文件。

一、MP3文件结构

MP3 由帧构成,每个帧包括FrameHeader 帧头,FrameData 帧数据,MP3 文件一般分为三部分:ID3V2,Frame,ID3V1,ID3V2,ID3V1 也属于帧,叫标签帧。Frame 部分叫数据帧。在一个MP3 文件内不一定有标签帧,但一定有数据帧。

  1. ID3V2:包含作者,作曲,专辑等信息,长度不固定,扩展了ID3V1 的信息量。
  2. Frame:一系列的帧,个数由文件大小和帧长决定;每个Frame 的长度可能不相等,也可能相等,由位率bitrate决定;每个Frame 又分为帧头和数据实体两部分,帧头记录了mp3 的位率,采样率,版本等信息,每个帧之间相互独立。
  3. ID3V1:包含了作者,作曲,专辑等信息,长度为128B。

二、 MP3 文件种类

根据位率是否相同,分成两类:位率相等叫CBR,constant bitrate,位率不等,叫VBR,variable bitrate. VBR 有两种规范:Xing,VBRI。

三、标签帧

3.1 ID3V2 标签: 都有一个标签头和若干个标签帧,存放于MP3 文件首部。
在这里插入图片描述
3.1.1 标签头 label header
在文件的首部顺序记录 10 个字节的 ID3V2.3 的头部。数据结构如下:
char Header[3];
必须为"ID3"否则认为标签不存在,如上图"49 44 33",文本为“ID3”*

char Ver;
/版本号 ID3V2.3 就记录 3,如上图地址03 处记录为"03",/

char Revision;
/副版本号此版本记录为 0/

char Flag;
/存放标志的字节,这个版本只定义了三位,稍后详细解说,这里为00/

char Size[4];
/*标签大小,包括标签头的 10 个字节和所有的标签帧的大小,这里为+10=个字节,计算方法见下文

1).Flag 标志字节
标志字节一般为 0,定义如下: abc00000
a-表示是否使用 Unsynchronisation
b-表示是否有扩展头部,一般没有(至少Winamp 没有记录),所以一般也不设置
c-表示是否为测试标签(99.99%的标签都不是测试用的啦,所以一般也不设置)

2).标签大小
一共四个字节,读取顺序为big-endia(低地址向高地址读取)但每个字节只用 7 位,最高位不使用恒为 0。所以格式如下 0xxxxxxx 0xxxxxxx 0xxxxxxx 0xxxxxxx。计算大小时要将 0 去掉,得到一个 28 位的二进制数,就是标签大小(不懂为什么要这样做,应该是MP3 规范定义好的)。计算公式如下:

*Size = (Size[0]&0x7F)*0x200000+(Size[1]&0x7F)*0x4000+(Size[2]&0x7F)0x80 +(Size[3]&0x7F)
= (Size[0]&0x7F)2165+(Size[1]&0x7F)*4*163 +(Size[2]&0x7F)816 +(Size[3]&0x7F)

而整个帧的大小需要加上帧头的10 个字节,即total_Size=Size+10
上述例子的标签大小字段为“00 00 21 34”,所以Size=0x10b4,整个帧的大小为0x10BE 个字节,所以在0X10BE这个地址处将开始新的帧。

3.1.2、标签帧label frame

每个标签帧都有一个 10 个字节的帧头frame header 和至少一个字节的不固定长度的内容组成。也是顺序存放在文件中,和标签头和其他的标签帧也没有特殊的字符分隔。得到一个完整的帧的内容只有从帧头中获取内容尺寸后才能读出,读取时要注意大小,不要将其他帧的内容或帧头读入。

帧头的定义如下:
char FrameID[4];
/用四个字符标识一个帧,说明其内容,稍后有常用的标识对照表,参见附录/

char Size[4];
/*帧内容的大小,不包括帧头,不得小于1,

char Flags[2];
/存放标志,只定义了 6 位,解说在后/

1).帧标识:用四个字符标识一个帧,说明一个帧的内容含义,常用的对照如下,具体可以参照后文附录4(帧标
识的含义):
TIT2=标题 表示内容为这首歌的标题,下同
TPE1=作者
TALB=专集
TRCK=音轨 格式:N/M 其中 N 为专集中的第 N 首,M 为专集中共 M 首,N 和 M 为 ASCII 码表示的数字
TYER=年代 是用 ASCII 码表示的数字
TCON=类型 直接用字符串表示
COMM=备注 格式:“eng\0 备注内容”,其中 eng 表示备注所使用的自然语言

2).大小: 这个可没有标签头的算法那么麻烦,每个字节的 8 位全用,格式如下
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
算法如下:
*Size = Size[0]*0x1000000 +Size[1]*0x10000 +Size[2]*0x100 +Size[3]= Size[0]*16^6 +Size[1]*16^4 +Size[2]16^2 +Size[3]

而整个帧的大小需要加上帧头的10 个字节,即total_Size=Size+10。

3).标志: 只定义了 6 位,另外的 10 位为 0,但大部分的情况下 16 位都为 0 就可以了。格式如下:
abc00000 ijk00000
a – 标签保护标志,设置时认为此帧作废
b – 文件保护标志,设置时认为此帧作废
c – 只读标志,设置时认为此帧不能修改(但我没有找到一个软件理会这个标志)
i – 压缩标志,设置时一个字节存放两个 BCD 码表示数字
j – 加密标志(没有见过哪个 MP3 文件的标签用了加密)
k – 组标志,设置时说明此帧和其他的某帧是一组
值得一提的是 winamp 在保存和读取帧内容的时候会在内容前面加个’\0’,并把这个字节计算在帧内容的大小中。

3.2. ID3V1 标签帧
ID3 V1.0 标准并不周全,存放的信息少,无法存放歌词,无法录入专辑封面、图片等。V2.0 是一个相当完备的
标准,但给编写软件带来困难,虽然赞成此格式的人很多,在软件中真正实现的却极少。绝大多数MP3 仍使用
ID3 V1.0 标准。此标准是将MP3 文件尾的最后128 个字节用来存放ID3 信息,这128 个字节使用说明见下表A。
表A ID3 V1.0 文件尾说明
字节 长度 (字节) 说 明
1-3 3 存放“TAG”字符,表示ID3 V1.0 标准,紧接其后的是歌曲信息。
4-33 30 歌名
34-63 30 作者
64-93 30 专辑名
94-97 4 年份
98-127 30 附注
128 1 MP3 音乐类别,共147 种。
在这里插入图片描述

表2 MP3 音乐类别:
0 ‘Blues’ 20 ‘Alternative’ 40 ‘AlternRock’ 60 ‘Top 40’
1 ‘Classic Rock’ 21 ‘Ska’ 41 ‘Bass’ 61 ‘Christian Rap’
2 ‘Country’ 22 ‘Death Metal’ 42 ‘Soul’ 62 ‘Pop/Funk’
3 ‘Dance’ 23 ‘Pranks’ 43 ‘Punk’ 63 ‘Jungle’
4 ‘Disco’ 24 ‘Soundtrack’ 44 ‘Space’ 64 ‘Native American’

5 ‘Funk’ 25 ‘Euro-Techno’ 45 ‘Meditative’ 65 ‘Cabaret’
6 ‘Grunge’ 26 ‘Ambient’ 46 ‘Instrumental Pop’ 66 ‘New Wave’
7 ‘Hip-Hop’ 27 ‘Trip-Hop’ 47 ‘Instrumental Rock’ 67 ‘Psychadelic’
8 ‘Jazz’ 28 ‘Vocal’ 48 ‘Ethnic’ 68 ‘Rave’
9 ‘Metal’ 29 ‘Jazz+Funk’ 49 ‘Gothic’ 69 ‘Showtunes’
10 ‘New Age’ 30 ‘Fusion’ 50 ‘Darkwave’ 70 ‘Trailer’
11 ‘Oldies’ 31 ‘Trance’ 51 ‘Techno-Industrial’ 71 ‘Lo-Fi’
12 ‘Other’ 32 ‘Classical’ 52 ‘Electronic’ 72 ‘Tribal’
13 ‘Pop’ 33 ‘Instrumental’ 53 ‘Pop-Folk’ 73 ‘Acid Punk’
14 ‘R&B’ 34 ‘Acid’ 54 ‘Eurodance’ 74 ‘Acid Jazz’
15 ‘Rap’ 35 ‘House’ 55 ‘Dream’ 75 ‘Polka’
16 ‘Reggae’ 36 ‘Game’ 56 ‘Southern Rock’ 76 ‘Retro’
17 ‘Rock’ 37 ‘Sound Clip’ 57 ‘Comedy’ 77 ‘Musical’
18 ‘Techno’ 38 ‘Gospel’ 58 ‘Cult’ 78 ‘Rock & Roll’
19 ‘Industrial’ 39 ‘Noise’ 59 ‘Gangsta’ 79 ‘Hard Rock’
80 Folk 81 Folk/Rock 82 National Folk 83 Swing
84 Fast-Fusion 85 Bebob 86 Latin 87 Revival
88 Celtic 89 Bluegrass 90 Advantgarde 91 Gothic Rock
92 Progressive Rock 93 Psychadelic Rock 94 Symphonic Rock 95 Slow Rock

96 Big Band 97 Chorus 98 Easy Listening 99 Acoustic
100 Humour 101 Speech 102 Chanson 103 Opera
104 Chamber Music 105 Sonata 106 Symphony 107 Booty Bass
108 Primus 109 Porn Groove 110 Satire 111 Slow Jam
112 Club 113 Tango 114 Samba 115 Folklore

四、数据帧:
帧头长4 字节,共32 位。帧头后面可能有两个字节的CRC 校验,这两个字节的是否存在决定于FRAMEHEADER 信息的第16bit, 为0 则帧头后面无校验,为1 则有校验,校验值长度为2 个字节,(后面是可变长度的附加信息,对于标准的MP3 文件来说,其长度是32 字节),紧接其后的是压缩的声音数据,当解码器读到此处时就进行解码了。
1. 帧头格式
帧头长4 字节,对于固定位率的MP3 文件,所有帧的帧头格式一样其数据结构如下:

typedef FrameHeader {
unsigned int sync: 11; //同步信息
unsigned int version: 2; //版本
unsigned int layer: 2; //层
unsigned int error protection: 1; // CRC 校验
unsigned int bitrate_index: 4; //位率
unsigned int sampling_freqy: 2; //采样频率
unsigned int padding: 1; //帧长调节
unsigned int private: 1; //保留字
unsigned int mode: 2; //声道模式
unsigned int mode extension: 2; //扩充模式
unsigned int copyright: 1; // 版权
unsigned int original: 1; //原版标志
unsigned int emphasis: 2; //强调模式
}HEADER, *LPHEADER;
帧头4 字节使用说明见表1。

4.1 计算帧长度
首先区分两个术语:帧大小和帧长度。帧大小即每帧采样数表示一帧中采样的个数,这是恒定值。其值如下表所示
在这里插入图片描述
帧长度是压缩时每一帧的长度,包括帧头。它将填充的空位也计算在内。Layer1 的一个空位长4 字节,Layer2和Layer3 的空位是1 字节。当读取MPEG 文件时必须计算该值以便找到相邻的帧。
注意:因为有填充和比特率变换,帧长度可能变化。 从头中读取比特率,采样频率和填充的值后可以进行计算:

Lyaer1 使用公式: 帧长度(字节)= ( 每帧采样个数(比特率/ 8 ) / 采样频率 ) + 填充 * 4*

Lyer2 和Lyaer3 使用公式:帧长度(字节)= (每帧采样个数 (比特率/ 8 ) / 采样频率 ) + 填充*

注释:比特率/ 8 就是每秒多少字节数,(比特率/ 8/采样频率)得出的是每赫兹采样几个字节,样本数*(比特率/ 8/采样频率),得到的是固定样本数下(比如1152 个)得到的字节数。例: Layer3 比特率 128000,采样频
率 44100,填充0,得出帧长度是 417 字节;规律说明:根据上表的分析,所有的Mp3 文件的数据帧开始的两个字节必需是“FF FA”或者 “FF FB”。

4.2 每帧的持续时间
每帧的持续时间可以通过计算获得,下面给出计算公式:
每帧持续时间(毫秒) = 每帧采样数 / 采样频率 * 1000
举例:44.1K 采样率时,每帧时间为:1152 / 44.1K * 1000 = 26.12 (约等于26ms)
如果是MPEG2 Layer3 采样率为16KHz 的话那一帧要持续36 毫秒,这个相差还是蛮大的,所以还是应该通过计算来获的。

4.3 MAIN_DATA 主数据
MAIN_DATA 部分长度是否变化取决于FrameHeader 的 位率是否变化,一首 MP3 歌曲,它有三个版本:
96Kbps(96 千比特位每秒)、128Kbps 和 192Kbps。Kbps(比特位速率),表明了音乐每秒的数据量,Kbps 值越高,
音质越好,文件也越大,MP3 标准规定, bitrate 不变的MP3 文件称作CBR,大多数 MP3 文件都是 CBR 的,而变
化的 bitrate 的MP3 文件称作VBR,每个Frame 的长度都可能是变化的。下面是 CBR 和 VBR 的不同点:
1)CBR:固定位率的帧长度是固定的(公式如上所述),只要知道文件总长度,和帧长即可由播放每帧需 26ms 计算
得出 mp3 播放的总时间,也可通过计数帧的个数控制快进、快退慢放等操作。注:有些时候,并不是所有的帧都是等长的,有的帧可能多一个或几个字节。

2)VBR:VBR 是Xing 公司推出的算法,所以在 MP3 的 FRAME 里会有“XING"这个关键字或者info,它存放在
MP3 文件中的第一个有效帧 里,它标识了这个 MP3 文件是可变位率的。同时第一个帧里存放了MP3 文件的总帧数,这就很容易获得了播放总时间,同时还有 100 个字节存放了播放总时间的 100 个时间分段的帧的INDEX,
假设 4 分钟的 MP3 歌曲,240S,分成 100 段,每两个相邻 INDEX 的时间差就是 2.4S,所以通过这个 INDEX,只要前后处理少数的帧,就能快速找出我们需要快进的帧头。

五、MP3 文件类型及其判断
MP3 文件类型是根据数据帧的类型来分的,文件类型如下表
在这里插入图片描述
5.1 如何判断一个MP3 文件的类型,属于CBR?VBR?XING?
5.2、文件播放的时长计算问题:区分了文件类型就可以计算Mp3 文件的播放时长了。
1.CBR 文件的时长计算(duration)
对于计算CBR 的MP3 的播放时间,每一帧的比特率都是固定的同样的大小,所以,相对来说,很容易想得到,用文件大小,直接除于比特率,就可以得到文件的播放时间了,即就用如下公式可以计算MP3 的播放时间:

CBR Duration = File Size(Byte) ×8 bit/Byte÷(Bitrate(K bit/s)× 1000 bit/Kbit )
CBR 播放时间 = 文件大小(字节)×8 比特/字节 ÷(比特率 千比特/秒 ×1000 比特/千比特) 【公式1】
其中:
文件大小
严格地说,应该是 MP3的文件总大小,减去 MP3的 Tag 的大小,即:文件大小 = 总的MP3文件大小 – MP3 的 Tag 大小;
其中,MP3 的 Tag,往往和 MP3 文件总大小相比,几乎可以忽略不计,
所以,一般也可以直接用总的MP3 为文件大小,直接来计算:文件大小 = 总的MP3 文件大小。

比特率:
可以通过解析MP3文件的第一帧的MPEG 的帧头,得到比特率的索引值,然后查比特率索引表,即可得到比特率是多少。所以,可以看出,对于 CBR 的文件,可以用上面的公式,获得MP3 文件大小后,再去解析第一帧的MPEG 帧头,得到比特率索引值,查表得到比特率的值,然后就算出整个CBR MP3 文件的播放时间。

2.VBR 文件的时长计算(duration)
2.1 平均比特率法

这个方法,就是和CBR 同样的思路,对于 VBR 的MP3 来说,假如也像 CBR 的MP3 一样,也有个类似的每一帧都是固定的某个值的比特率,那么计算整个 VBR 的播放时间,也就可以用上面CBR 一样的公式去计算了。

由此,就有了平均比特率的概念,即,将所有帧的比特率的值相加,得到一个总的比特率的值,然后除于总的帧数,就得到了一个平均比特率,这样,使得理论上,此 VBR 相当于一个比特率为该平均比特率的CBR 了。不过,可以看出,需要计算平均比特率之前,要先得到每一帧的比特率的值,以及总的帧的数目,然后才可以计算平均比特率的值。而为了得到每一帧的比特率的值,就要将整个VBR MP3 文件都遍历一遍,以此找到所有的帧,并解析每一个帧的帧头,得到比特率索引值,然后查表得到比特率的值。如此做的话,效率显然很低。因为此处只是为了计算整个VBR MP3 的播放时间,却要遍历整个文件,还要解析每一帧的帧头。

2.2 总帧数法
总帧数法,即利用总的帧的数目,来计算 VBR 的播放时间。 此方法的前提,也是MP3 文件的规范(以下两点
非常重要):

(1)MP3,即 MPEG-1,Layer3,不论是 CBR,还是 VBR,每一帧的采样个数都是固定的 1152 个。即每一帧,都是固定的 1152 个采样。
(2)CBR 和 VBR 中的固定和可变,都是指的是比特率Bitrate,而不是采样率 Sample Rate。对于同一MP3 文件,不论 CBR 还是 VBR,采样率都是固定的。

了解了这两个前提后,就可以看出,对于 VBR 来说,虽然每一帧的比特率不同,但是每一帧的时间都是固定的,
因为每一帧的时间= 该帧的采样个数 * (1/该帧的采样率) = 1152 * (1/采样率)=1152*采样周期其中:

采样个数
MPEG-1,Layer III,即MP3,不论是CBR 还是VBR,都是固定的 1152采样率:对于单个的 VBR 文件,都是统一的,固定的,常见的是 44100Hz。采样率可以通过解析第一帧的帧头得出采样率索引,然后查表得到采样率。既然知道了每一帧的时间都是固定的,那么很容易就想到,如果知道 VBR MP3 有一共多少帧,那么就可以用 总的帧数 × 每一帧的时间 = 总的时间长度了。公式如下:

*VBRDuration = Total_Frame_Number * Time_Per_Frame
= Total_Frame_Number (Sample_Number * Time_Per_Sample)
= Total_Frame_Number * (Sample_Number * (1 / Frame_Sample_Rate))

其中,因为是Mp3,所以Sample_Number=1152。所以,剩下的事情,就是去得到 VBR MP3 的总的帧数和采样率。 获取第一个数据帧,解析帧的帧头,得到采样率。在VBR 文件的“Xing”标志的头中,会记录帧的总个数,这样就可以轻易地得到总的帧数和采样率了。不过如果帧头没有记录总帧数信息的话,还得遍历整个文件计算总帧数。

链接为一款将任意音频格式的文件,自动转化成数组格式,可以用数组验证解码库,省去了文件系统的移植操作:
https://download.csdn.net/download/qq_35968965/13189180

  • 8
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
STM32 MP3解码是指使用STM32微控制器实现MP3音频文件的软解码MP3是一种流行的音频压缩格式,可以将音频文件压缩为较小的尺寸,同时保持较高的音质。为了在STM32上实现MP3解码,首先需要一个支持MP3解码的软件库。 在STM32上进行MP3解码,首先需要将MP3音频文件加载到STM32的存储器中,然后通过软件库对MP3文件进行解析。解析过程中,软件库会解码MP3文件的音频帧,并将解码后的音频数据通过STM32的音频接口输出。为了实现连续播放,解码过程需要以适当的速率进行,以保证解码音频数据在实时性要求下得到输出。 STM32 MP3解码可以通过使用现成的软件库来实现,如Helix MP3解码库。这种解码库已经经过优化,并被广泛应用于STM32等嵌入式平台。使用该库,开发者可以在STM32上实现高质量的MP3解码和播放功能。 要实现STM32 MP3解码,需要对MP3解码的算法和流程有一定的了解。开发者需要了解音频文件结构、帧解析、音频解码和输出等方面的知识。同时,还需要对STM32的存储器和音频接口进行适当的配置和编程。在实际开发过程中,还需要考虑处理器的性能和存储空间等资源限制,以保证解码的稳定性和性能。 总之,STM32 MP3解码是一种利用STM32微控制器实现MP3音频文件解码的技术。通过使用合适的软件库和适当的配置,开发者可以实现在STM32上高质量的MP3音频解码和播放功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王先森001

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值