• 本文多处摘自互联网,仅供本人学习使用,出处标示于文章尾端。

#一、概述
    Layer-3 音频文件,MPEG(Moving Picture Experts Group) 在汉语中译为活动图像专家组,特指活动影音压缩标准,MPEG音频文件是MPEG1 标准中的声音部分,也叫MPEG 音频层,它根据压缩质量和编码复杂程度划分为三层,即Layer-1、Layer2、Layer3,且分别对应MP1、MP2、MP3 这三种声音文件,并根据不同的用途,使用不同层次的编码。 MPEG 音频编码的层次越高,编码器越复杂,压缩率也越高,MP1 和MP2 的压缩率分别为4:1 和6:1-8:1,而MP3 的压缩率则高达10:1-12:1,也就是说,一分钟CD 音质的音乐,未经压缩需要10MB的存储空间,而经过MP3 压缩编码后只有1MB 左右。不过MP3 对音频信号采用的是有损压缩方式,为了降低声音失真度,MP3采取了“感官编码技术”,即编码时先对音频文件进行频谱分析,然后用过滤器滤掉噪音电平,接着通过量化的方式将剩下的每一位打散排列,最后形成具有较高压缩比的MP3 文件,并使压缩后的文件在回放时能够达到比较接近原音源的声音效果。

#二、MP3 文件结构
    MP3 文件大体分为三部分:TAG_V2(ID3V2)音频数据TAG_V1(ID3V1)

a). ID3V2 在文件开始的位置,包含了作者,作曲,专辑等信息,长度不固定,扩展了ID3V1 的信息量。

b). 一系列的音频数据的帧,在文件的中间位置,个数由文件大小和帧长决定;
每个帧的长度可能不固定,也可能固定,由位率bitrate决定
每个帧又分为帧头和数据实体两部分
帧头记录了mp3 的位率,采样率,版本等信息,每个帧之间相互独立 。

c). ID3V1在文件结尾的位置,包含了作者,作曲,专辑等信息,长度为128Byte。

##2.1、ID3V2
    ID3V2 到现在一共有4 个版本,但流行的播放软件一般只支持第3 版, 既ID3v2.3。

由于ID3V1 记录在MP3 文件的末尾,ID3V2就只好记录在MP3 文件的首部了(如果有一天发布ID3V3,真不知道该记录在哪里)。也正是由于这个原因,对ID3V2 的操作比ID3V1 要慢。而且ID3V2 结构比ID3V1 的结构要复杂得多,但比前者全面且可以伸缩和扩展。

下面就介绍一下ID3V2.3:
每个ID3V2.3 的标签都一个标签头和若干个标签帧或一个扩展标签头组成。关于曲目的信息如标题、作者等都存放在不同的标签帧中,扩展标签头和标签帧并不是必要的,但每个标签至少要有一个标签帧。标签头和标签帧一起顺序存放在MP3 文件的首部。

###2.1.1、标签头
    在文件的首部顺序记录10 个字节的ID3V2.3 的头部。数据结构如下:

typedef struct Zs_head_lable
{char Header[3]; // 必须为字符串"ID3",否则认为标签不存在 对应16进制:49 44 33char ver;   // 版本号ID3V2.3 就记录0x03char Revision;// 副版本号此版本记录为0x00char Flag;  // 存放标志的字节,这个版本只定义了3bitchar Size[4];   // 标签帧的大小,不包括标签头的10个字节
}head_lable;

图2.1.1

红色框部分即为ID3V2.3的头部:

前3个字节就是 ID30x03(第3版) 49 44 33

第4个表示版本号 03

第5个字节:副版本号,为00

第6个字节是标志字节 为00
标志字节一般为0,按位定义如下:
abc00000
a – 表示是否使用Unsynchronisation(这个单词不知道是什么意思,字典里也没有找到,一般不设置)
b – 表示是否有扩展头部,一般没有(至少Winamp 没有记录),所以一般也不设置
c – 表示是否为测试标签(99.99%的标签都不是测试用的啦,所以一般也不设置)

第7-10个字节表示标签帧大小
一共四个字节,但每个字节只用7位,最高位不使用恒为0。所以格式如下
0xxxxxxx 0xxxxxxx 0xxxxxxx 0xxxxxxx

计算大小时要将0 去掉,得到一个28 位的二进制数,就是标签大小,计算公式如下:

int label_frame_size;
label_frame_size=((Size[0]&0x7F)<<21)+ ((Size[1]&0x7F)<<14))+ ((Size[2]&0x7F)<<7)+ (Size[3]&0x7F);

第7到10字节:表示ID3标签的大小,这里为

label_frame_size=((0x00&0x7F)<<21)+((0x00&0x7F)<<14)+((0x07&0x7F)<<7) +(0x76 &0x7F)
= 0x3F6=1014;

这里的 0x3F6帧大小,并不包含标签头的10个字节,只表示标签帧内容的大小 加上标签头是10个字节,音频数据就是从1024后面的字节开始算。

###2.1.2、标签帧
    接上面的例子,接下里4086个字节都是标签帧的内容。
每个标签帧都有一个10 个字节的帧头和至少一个字节的不固定长度的内容组成。它们也是顺序存放在文件中,和标签头和其他的标签帧也没有特殊的字符分隔。得到一个完整的帧的内容只有从帧头中的到内容大小后才能读出,读取时要注意大小,不要将其他帧的内容或帧头读入。

帧头的定义如下:

typedef struct Zs_lable_frame_head
{char ID[4]; //用四个字符标识一个帧,说明其内容,稍后有常用的标识对照表char Size[4]; //帧内容的大小,不包括帧头,不得小于1char Flags[2]; //存放标志,只定义了6 位
}lable_frame_head,*plable_frame_head;

图2.1.2

蓝色部分是一个歌曲的标签帧的有效内容

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

前4个字节为帧标识,这里是54 59 45 52 (TYER) 是年代

####2)大小
这个可没有标签头的算法那么麻烦,每个字节的8 位全用,格式如下
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
算法如下:

int FrameSize;
FrameSize= (Size[0]<<24) +(Size[1]<<16)+ (Size[2]<<8)+ Size[3];

这里为

FrameSize =(0x00<<24) +( 0x00<<16) + (0x00<<8) + 0x05 = 5;

注意:这里的帧大小,并不包含帧头的10个字节,只表示帧内容的大小

####3)标志
只定义了6 位,另外的10 位为0,但大部分的情况下16 位都为0 就可以了。格式如下:
abc00000ijk00000

a – 标签保护标志,设置时认为此帧作废

b – 文件保护标志,设置时认为此帧作废

c – 只读标志,设置时认为此帧不能修改(但我没有找到一个软件理会这个标志)

i – 压缩标志,设置时一个字节存放两个BCD 码表示数字

j – 加密标志(没有见过哪个MP3 文件的标签用了加密)

k – 组标志,设置时说明此帧和其他的某帧是一组

值得一提的是winamp 在保存和读取帧内容的时候会在内容前面加个”\0”,并把这个字节计算在帧内容的大小中。
第9到10字节为标签帧的标记,如上所述,这里为00

第一个帧内容是歌曲年代,标题的5个字节的内容为:
0x00 0x32 0x30 0x31 0x35
‘\0’ ‘2’ ‘0’ ‘1’ ‘5’
上图中的内容依次读出为:
TYER:2015
TALB:Purpose
COMM:eng
TIT2:LoveYourself
TPE1:JustinBieber

##2.2、音频数据帧

一个MP3数据帧分为5个部分:帧头、CRC校验值、通道信息、主数据、附加数据。

###2.2.1、MP3帧头字节说明
每个帧都有一个帧头Header,长度是4Byte(32bit),帧头后面可能有两个字节的CRC 校验值,这两个字节的是否存在决定于Header 信息的第16bit,为0 则帧头后面无校验,为1 则有校验,校验值长度为2 个字节,紧跟在Header 后面,接着就是帧的实体数据了.
图2.2.1

红色部分的4个字节即是帧头

**表2.1.1 MP3帧头字节说明**表

名称 位长 说明
同步信息 11 所有位均为1,第1字节恒为FF>
版本 2 00-MPEG 2.5 01-未定义 10-MPEG 2 11-MPEG 1
2 00-未定义 01-Layer 3 10-Layer 2 11-Layer 1
CRC校验 1 0-校验 1-不校验
比特率 4 单位是kbps,例如采用MPEG-1 Layer 3,128kbps是,值为1001
具体参数对应比特率表
采样率 2 采样频率,对于MPEG-1: 00-44.1kHz 01-48kHz 10-32kHz 11-未定义
对于MPEG-2: 00-22.05kHz 01-24kHz 10-16kHz 11-未定义
对于MPEG-2.5: 00-11.025kHz 01-12kHz 10-8kHz 11-未定义
帧长调节 1 用来调整文件头长度,0-无需调整,1-调整,具体调整计算方法见下文
保留字 1 没有使用
声道模式 2 表示声道, 00-立体声Stereo 01-Joint Stereo 10-双声道 11-单声道
扩充模式 2 当声道模式为01是才使用
Value   强度立体声    MS立体声
00             off             off
01             on              off
10             off              on
11              on             on
版权 1 文件是否合法,0-不合法 1-合法
原版标志 1 是否原版, 0-非原版 1-原版
强调方式 2 用于声音经降噪压缩后再补偿的分类,很少用到,今后也可能不会用。
00-未定义 01-50/15ms 10-保留 11-CCITT J.17

**表2.1.2 MP3数据帧比特率表**

bits V1,L1 V1,L2 V1,L3 V2,L1 V2,L2 V2,L3
0000 free free free free free free
0001 32 32 32 32(32) 32(8) 8(8)
0010 64 48 40 64(48) 48(16) 16(16)
0011 96 54 48 96(56) 56(24) 24(24)
0100 128 64 56 128(64) 64(32) 32 (32)
0101 160 80 64 160(80) 80(40) 64 (40)
0110 192 96 80 192(96) 96(48) 80 (48)
0111 224 112 96 224(112) 112(56) 56 (56)
1000 256 128 112 256(128) 128(64) 64 (64)
1001 288 160 128 288(144) 160(80) 128 (80)
1010 320 192 160 320(160) 192(96) 160 (96)
1011 352 224 192 352(176) 224(112) 112 (112
1100 384 256 224 384(192) 256(128) 128 (128)
1101 416 320 256 416(224) 320(144) 256 (144)
1110 448 384 320 448(256) 384(160) 320 (160)
1111 bad bad bad bad bad bad

V1 - MPEG 1 V2 - MPEG 2 and MPEG 2.5 L1 - Layer 1 L2 - Layer 2 L3 - Layer 3 "free" 表示位率可变 "bad" 表示不允许值 规律说明:根据上表的分析,所有的Mp3文件的数据帧开始的两个字节必需是“FF FA”或者 “FF FB”。

####a) 例子数据分析
第1帧数据:帧头为 FF FA 91 6C
1111 1111 111 11 01 0 1001 00 0 1 01 10 1 1 00

前11位:同步信息

第12到13位:版本,其值为11 ->MPEG 1

第14到15位:层,其值为01->Layer 3

第16位:CRC检验标识,其值为0 ->校验

第17到20位:位率,其值为1001,从前面可知本帧为V1,L3类型, ->128K

第21到22位:采样率,其值为00,从前面知本帧为 MPEG 1-> 44.1K

第23位:帧长调节,其值为0 ->无需调整

第24位:保留字,未使用

第25到26位:声道模式,其值为01->-Joint Stereo

第27到28位:扩充模式,当声道模式为01(联合立体声)时才使用,此处是10, 使用MS立体声

第29位:版权,其值为1->有版权

第30位:原版标志,其值为1->是原版文件

第31到32位:强调方式,其值为00->未定义

####b)、 帧头信息存储结构体
自定义以下结构体,用来存储帧头数据:

typedef struct frameHeader
{unsigned int sync1:11;                      //同步信息1unsigned int version:2;                    //版本unsigned int layer:2;                      //层unsigned int crc_check:1;                  //CRC校验unsigned int bit_rate_index:4;             //比特率索引unsigned int sample_rate_index:2;          //采样率索引unsigned int padding:1;                    //帧长调节位unsigned int reserved:1;                   //保留字unsigned int channel_mode:2;               //声道模式unsigned int mode_extension:2;             //扩展模式,仅用于联合立体声unsigned int copyright:1;                  //版权标志unsigned int original:1;                   //原版标志unsigned int emphasis:2;                   //强调方式
}FHEADER, *LPHEADER;

发现直接读取4个字节的数据到这个结构体内,发现数据不对,
读的过程是按8字节对齐的,比如sync1会先读取8个字节到低位,剩下的3个bit成了其他数据的低位。
还是进行数据分析,然后填充到结构体内。

###2.2.2、CRC校验
    如果帧头的校验位为0,则帧头后就有一个16位的CRC值,这个值是big-endian的值,把这个值和该帧通过计算得出的CRC值进行比较就可以得知该帧是否有效。
例子中是校验值为0,需要进行校验。CRC校验值即是 帧头的后2个字节:06 9B
CRC校验本文不做详细介绍。

###2.2.3、 MP3帧长的计算
MP3帧长取决于位率和频率,计算公式为:

Size=((采样个数 * (1 / 采样率))* 帧的比特率)/8 + 帧的填充大小

a),帧的填充大小就是第23位的帧长调节,不是0就是1。

**b),**采样个数:MPEG的不同规范(MPEG-1/2/3),以及同一规范中不同的 Layer(Layer I/II/III),每一帧所对应的采样数,都是固定的,其具体的值参见下表:

表 2.2.2 MPEG帧的采样数索引表(单位:个/帧)

MPEG 1 MPEG 2(LSF) MPEG 2.5(LSF)
Layer 1 384 384 384
Layer 2 1152 1152 1152
Layer 3 1152 576 576

对于Mp3格式,MPEG 1 Layer3 采样个数是固定的1152,
Size = ((1152 * (1 / 采样率))* 帧的比特率)/8 + 帧的填充大小
= 144*帧的比特率/采样率 + 帧的填充大小
例:
如2.2.1中的数据,比特率为128K,采样率为44.1K,填充0,则其帧长度为:
(144 * 128K)/44.1K +0= 417 (字节)
回去看 图2.2.1
从当前数据的 “FF FA” 到下一个数据帧开始的"FF FA"之间,刚好是417个数据
包含了帧头的4个字节和2个CRC校验字节

###2.2.4、Side Info(通道信息)
    在帧头后边是Side Info(姑且称之为通道信息)。对标准的立体声MP3文件来说其长度为32字节。通道信息后面是Scale factor(增益因子)信息。当解码器在读到上述信息后,就可以进行解码了。 图2.2.1中是紧接着校验位的后32字节的数据。
帧边信息解码的主要目的在于找出解这帧的各个参数,包括主数据开始位置,尺度因子长度等。帧边信息如图2.2.4-1所示。

图2.2.4-1 side info ![这里写图片描述](https://img-blog.csdn.net/20171205190010497?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhlbmdsaWUxMTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 其中,main_data_begin(主数据开始)是一个偏移值,指出主数据是在同步字之前多少个字节开始。需要注意的是,1.帧头不一定是一帧的开始,帧头CRC校验字和帧边信息在帧数据中是滑动的。2.这个数值忽略帧头和帧边信息的存在,如果main_data_begin = 0, 则主数据从帧边信息的下一个字节开始,示意图如图2.2.4-2. 图2.2.4-2 MP3位流数据组织图 ![这里写图片描述](https://img-blog.csdn.net/20171206104103255?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhlbmdsaWUxMTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)

块类型(block_type)分为三种类型:

block_type = 0长块

block_type = 1开始块

block_type = 3结束块

block_type = 2短块

在编码过程中进行IMDCT变换时,针对不同信号为同时得到较好的时域和频域分辨率定义了两种不同的块长:长块的块长为18个样本,短块的块长为6个样本。这使得长块对于平稳的声音信号可以得到更高的频率分辨率,而短块对跳变信号可以得到更高的时域分辨率。由于在短块模式下,3个短块代替1个长块,而短块的大小恰好是一个长块的1/3,所以IMDCT的样本数不受块长的影响。对于给定的一帧声音信号,IMDCT可以全部使用长块或全部使用短块,也可以长短块混合使用。因为低频区的频域分辨率对音质有重大影响,所以在混合块模式下,IMDCT对最低频的2个子带使用长块,而对其余的30个子带使用短块。这样,既能保证低频区的频域分辨率,又不会牺牲高频区的时域分辨率。长块和短块之间的切换有一个过程,一般用一个带特殊长转短(即,起始块block_type = 1)或短转长(即终止块,block_type = 3)数据窗口的长块来完成这个长短块之间的切换。因此长块也就是包括正常窗,起始块和终止块数据窗口的数据块;短块也包含18个数据,但是是由6个数据独立加窗后在经过连接计算得到的。

libmad 使用以下结构体来存储side info

struct sideinfo {unsigned int main_data_begin;unsigned int private_bits;unsigned char scfsi[2];struct granule {struct channel {/* from side info */unsigned short part2_3_length;unsigned short big_values;unsigned short global_gain;unsigned short scalefac_compress;unsigned char flags;unsigned char block_type;unsigned char table_select[3];unsigned char subblock_gain[3];unsigned char region0_count;unsigned char region1_count;/* from main_data */unsigned char scalefac[39]; /* scalefac_l and/or scalefac_s */} ch[2];} gr[2];
};

###2.2.5、主数据(main data)
main_data中有两粒度组,没个粒度组分为两个声道,取数据存储结构如图2.2.5。

图2.2.5 ![这里写图片描述](https://img-blog.csdn.net/20171205164031847?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhlbmdsaWUxMTA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) **b)**对于mp3来说,现在有两种编码方式:

一种是CBR,也就是固定位率,固定位率的帧的大小在整个文件中都是是固定的,只要知道文件总长度,和从第一帧帧头读出的信息,就都可以通过计算得出这个mp3文件的信息,比如总的帧数,总的播放时间等等,要定位到某一帧或某个时间点也很方便,这种编码方式不需要文件头,第一帧开始就是音频数据。

另一种是VBR,就是可变位率,VBR是XING公司推出的算法,所以在MP3的FRAME里有“Xing”这个关键字(也有用”Info”来标识的,现在很多流行的小软件也可以进行VBR压缩,它们是否遵守这个约定,那就不得而知了),它存放在MP3文件中的第一个有效帧的数据区里,它标识了这个MP3文件是VBR的。同时第一个帧里存放了MP3文件的帧的总个数,这就很容易获得了播放总时间,同时还有100个字节存放了播放总时间的100个时间分段的帧索引,假设4分钟的MP3歌曲,240S,分成100段,每两个相邻INDEX的时间差就是2.4S,所以通过这个INDEX,只要前后处理少数的FRAME,就能快速找出我们需要快进的帧头。其实这第一帧就相当于文件头了。不过现在有些编码器在编码CBR文件时也像VBR那样将信息记入第一帧,比如著名的lame,它使用”Info”来做CBR的标记。
        第三种是 Info 帧
        info帧,结构和Xing帧是相同的,从一些网上的资料显示:这种类型的帧有点怪,在CBR文件中的第一个数据帧可以是Info帧,在VBR文件中的第一个数据帧也有可能是Info帧,但是我个人更倾向于认为第一个数据帧为Info帧的文件是CBR文件,比如Kugoo软件制作的铃声的第一帧都是Info帧,而且是CBR文件。

这里列出VBR的第一帧存储文件信息的头的格式。有两种格式,一种是常见的XINGHeader(头部包含字符‘Xing’),另一种是VBRIHeader(头部包含字符‘VBRI’)鉴于VBRIHeader不常见,下面只说XINGHeader:

表2.2.4 VBR Xing文件第一帧结构

字节 说明
1-4 标准声音帧头(Mp3时,为“FF FA xx xx”或者“FF FB xx xx”)
xx 校验位,如果有校验位,后面的数据后移两位
5-40 存放VBR文件标识“Xing”(58 69 6E 67),此标识具体位置视采用的MPEG标准和声道模式而定。标识的前后字节没有使用。
37-40 MPEG-1和非单声道(常见)
注意:Mp3的就是这种情况,第5至36的数据存储的是前面提到过的32字节的边信息,无效边信息时是32字节的“00”
22-25 MPEG-1和单声道
22-25 MPEG-2和非单声道
14-17 MPEG-2和单声道
41-44 标志,说明是否存储了帧数、文件长度、目录表和VBR规模信息,如果存储了,则01 02 04 08。注意:如果四种信息都存储了则这4个字节为“00 00 00 0F”,即F的二进制是“1111”,相应地,如果存储了帧数、文件长度、目录表,则这4个字节为“00 00 00 0E”
45-48 帧数(包括第一帧)
49-52 文件长度
53-152 目录表,用来按时间进行字节定位
153-156 VBR规模,用于位率变动音频质量指示,最差 0,最好 100,大端[可选]

在VBR格式的第一帧中,XING Header包括帧头一共最多只需要156个字节就够了,当然也可以在XING Header后面存储编码器的信息,比如lame在其后就是存储其版本,这需要给第一帧留足够的空间才行。
本文中的例子不是VBR,因此不做分析。

c)如何区分CBR和VBR

###2.2.6、播放时间计算
         区分了文件类型就可以计算Mp3文件的播放时长了。

####a) .CBR文件的时长计算(duration)
        每帧的持续时间
        每帧的持续时间可以通过计算获得,下面给出计算公式
        每帧持续时间(毫秒) = 每帧采样数 / 采样频率 * 1000
        标准的MP3其每帧时间为:
1152 / 44.1K * 1000 = 26.12 (约等于26ms)

对于计算CBR 的MP3的播放时间,其是Constant Bitrate,固定的比特率,每一帧的比特率也都是固定的同样的大小,所以,相对来说,很容易想得到,用文件大小,直接除于比特率,就可以得到文件的播放时间了,即就用如下公式可以计算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文件的播放时间。

####b).VBR文件的时长计算(duration)

#####1 平均比特率法
这个方法,就是和CBR 同样的思路,对于 VBR 的MP3来说,假如也像 CBR 的MP3一样,也有个类似的每一帧都是固定的某个值的比特率,那么计算整个 VBR的播放时间,也就可以用上面CBR 一样的公式去计算了。 由此,就有了平均比特率的概念,即,将所有帧的比特率的值相加,得到一个总的比特率的值,然后除于总的帧数,就得到了一个平均比特率,这样,使得理论上,此 VBR 相当于一个比特率为该平均比特率的CBR 了。
不过,可以看出,需要计算平均比特率之前,要先得到每一帧的比特率的值,以及总的帧的数目,然后才可以计算平均比特率的值。而为了得到每一帧的比特率的值,就要将整个 VBR MP3文件都遍历一遍,以此找到所有的帧,并解析每一个帧的帧头,得到比特率索引值,然后查表得到比特率的值。如此做的话,效率显然很低。因为此处只是为了计算整个 VBR MP3的播放时间,却要遍历整个文件,还要解析每一帧的帧头。

#####2 .总帧数法

总帧数法,即利用总的帧的数目,来计算 VBR 的播放时间。
此方法的前提,也是MP3文件的规范(以下两点非常重要):
(1)MP3,即 MPEG-1,Layer III,不论是 CBR,还是 VBR,每一帧的采样个数都是固定的 1152个。即每一帧,都是固定的 1152个采样。
(2)CBR和 VBR中的固定和可变,都是指的是比特率 Bitrate,而不是采样率 Sample Rate。对于同一 MP3文件,不论 CBR还是 VBR,采样率都是固定的。

了解了这两个前提后,就可以看出,对于 VBR 来说,虽然每一帧的比特率不同,但是每一帧的时间都是固定的,因为:

每一帧的时间= 该帧的采样个数 * 该帧的采样率 = 1152 * 采样率

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

VBR Duration
= 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”标志或“VBRi”标志的头中,会记录帧的总个数,这样就可以轻易地得到总的帧数和采样率了。不过如果帧头没有记录总帧数信息的话,还得遍历整个文件计算总帧数。

##2.3、ID3v1
    ID3V1标准并不周全,存放的信息少,无法存放歌词,无法录入专辑封面、图片等。ID3V2是一个相当完备的标准,但给编写软件带来困难,虽然赞成此格式的人很多,在软件中绝大多数MP3仍在使用ID3V1标准。ID3v1标签包含艺术家,标题,唱片集,发布年代和流派。另外还有额外的注释空间。位于音频文件的最后固定为128字节。可以读取该文件的最后这128字节获得标签。

ID3V1结构如下:

AAABBBBB BBBBBBBB BBBBBBBB BBBBBBBB
BCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCD
DDDDDDDD DDDDDDDD DDDDDDDD DDDDDEEE
EFFFFFFF FFFFFFFF FFFFFFFF FFFFFGHI

**表3.1 ID3 V1.0文件尾说明**

字节 长度 (字节) 说 明
1-3(A) 3 存放“TAG”字符,表示ID3 V1.0标准,紧接其后的是歌曲信息。
4-33(B) 30 歌名
34-63(C) 30 作者
64-93(D) 30 专辑名
94-97(E) 4 年份
98-125(F) 28 附注
126(G) 1 保留位
127(H) 1 音轨号
127(I) 1 MP3音乐类别,共147种

ID3V1 的各项信息都是顺序存放,没有任何标识将其分开,比如标题信息不足30 个字节,则使用”\0”填充,数据结构定义如下:

typedef struct tagID3V1
{char Header[3];     //标签头必须是”TAG”否则认为没有标签char Title[30];     //标题char Artist[30];    //作者char Album[30];     //专集char Year[4];       //出品年代char Comment[28];   //备注char reserve;       //保留char track;         //音轨char Genre;         //类型
}ID3V1, *pID3V1;

##**注:流派使用原码表示说明见附录二**

##附录一:帧标识的含义
4). Declared ID3v2 frames

Thefollowing frames are declared in this draft.

AENCAudio encryption

APICAttached picture

COMMComments

COMRCommercial

ENCREncryption method registration

EQUAEqualization

ETCOEvent timing codes

GEOBGeneral encapsulated object

GRIDGroup identification registration

IPLSInvolved people list

LINKLinked information

MCDIMusic CD identifier

MLLT MPEGlocation lookup table

OWNEOwnership

PRIVPrivate

PCNT Playcounter

POPMPopularimeter

POSSPosition synchronisation

RBUFRecommended buffer size

RVADRelative volume adjustment

RVRBReverb

SYLTSynchronized lyric/text

SYTCSynchronized tempo codes

TALBAlbum/Movie/Show title

TBPM BPM(beats per minute)

TCOMComposer

TCONContent type

TCOPCopyright message

TDAT Date

TDLYPlaylist delay

TENCEncoded by

TEXTLyricist/Text writer

TFLT Filetype

TIME Time

TIT1Content group deion

TIT2Title/songname/content deion

TIT3Subtitle/Deion refinement

TKEYInitial key

TLANLanguage(s)

TLENLength

TMEDMedia type

TOALOriginal album/movie/show title

TOFNOriginal filename

TOLYOriginal lyricist(s)/text writer(s)

TOPEOriginal artist(s)/performer(s)

TORYOriginal release year

TOWN Fileowner/licensee

TPE1 Leadperformer(s)/Soloist(s)

TPE2Band/orchestra/accompaniment

TPE3Conductor/performer refinement

TPE4Interpreted, remixed, or otherwise modified by

TPOS Partof a set

TPUBPublisher

TRCKTrack number/Position in set

TRDARecording dates

TRSNInternet radio station name

TRSOInternet radio station owner

TSIZ Size

TSRC ISRC(international standard recording code)

TSSESoftware/Hardware and settings used for encoding

TYER Year

TXXX Userdefined text information

UFIDUnique file identifier

USERTerms of use

USLTUnsychronized lyric/text tranion

WCOMCommercial information

WCOPCopyright/Legal information

WOAFOfficial audio file webpage

WOAROfficial artist/performer webpage

WOASOfficial audio source webpage

WORSOfficial internet radio station homepage

WPAYPayment

WPUBPublishers official webpage

WXXX Userdefined URL link

##附录二:流派使用原码表
/* Standard genres */
0=”Blues”;
1=”ClassicRock”;
2=”Country”;
3=”Dance”;
4=”Disco”;
5=”Funk”;
6=”Grunge”;
7=”Hip-Hop”;
8=”Jazz”;
9=”Metal”;
10=”NewAge”;
11=”Oldies”;
12=”Other”;
13=”Pop”;
14=”R&B”;
15=”Rap”;
16=”Reggae”;
17=”Rock”;
18=”Techno”;
19=”Industrial”;
20=”Alternative”;
21=”Ska”;
22=”Deathl”;
23=”Pranks”;
24=”Soundtrack”;
25=”Euro-Techno”;
26=”Ambient”;
27=”Trip-Hop”;
28=”Vocal”;
29=”Jazz+Funk”;
30=”Fusion”;
31=”Trance”;
32=”Classical”;
33=”Instrumental”;
34=”Acid”;
35=”House”;
36=”Game”;
37=”SoundClip”;
38=”Gospel”;
39=”Noise”;
40=”AlternRock”;
41=”Bass”;
42=”Soul”;
43=”Punk”;
44=”Space”;
45=”Meditative”;
46=”InstrumentalPop”;
47=”InstrumentalRock”;
48=”Ethnic”;
49=”Gothic”;
50=”Darkwave”;
51=”Techno-Industrial”;
52=”Electronic”;
53=”Pop-Folk”;
54=”Eurodance”;
55=”Dream”;
56=”SouthernRock”;
57=”Comedy”;
58=”Cult”;
59=”Gangsta”;
60=”Top40”;
61=”ChristianRap”;
62=”Pop/Funk”;
63=”Jungle”;
64=”NativeAmerican”;
65=”Cabaret”;
66=”NewWave”;
67=”Psychadelic”;
68=”Rave”;
69=”Showtunes”;
70=”Trailer”;
71=”Lo-Fi”;
72=”Tribal”;
73=”AcidPunk”;
74=”AcidJazz”;
75=”Polka”;
76=”Retro”;
77=”Musical”;
78=”Rock&Roll”;
79=”HardRock”;

Winamp扩充了这个表

80=”Folk”;
81=”Folk-Rock”;
82=”NationalFolk”;
83=”Swing”;
84=”FastFusion”;
85=”Bebob”;
86=”Latin”;
87=”Revival”;
88=”Celtic”;
89=”Bluegrass”;
90=”Avantgarde”;
91=”GothicRock”;
92=”ProgessiveRock”;
93=”PsychedelicRock”;
94=”SymphonicRock”;
95=”SlowRock”;
96=”BigBand”;
97=”Chorus”;
98=”EasyListening”;
99=”Acoustic”;
100=”Humour”;
101=”Speech”;
102=”Chanson”;
103=”Opera”;
104=”ChamberMusic”;
105=”Sonata”;
106=”Symphony”;
107=”BootyBass”;
108=”Primus”;
109=”PornGroove”;
110=”Satire”;
111=”SlowJam”;
112=”Club”;
113=”Tango”;
114=”Samba”;
115=”Folklore”;
116=”Ballad”;
117=”PowerBallad”;
118=”RhythmicSoul”;
119=”Freestyle”;
120=”Duet”;
121=”PunkRock”;
122=”DrumSolo”;
123=”Acapella”;
124=”Euro-House”;
125=”DanceHall”;

其他扩充

126=”Goa”;
127=”Drum&Bass”;
128=”Club-House”;
129=”Hardcore”;
130=”Terror”;
131=”Indie”;
132=”BritPop”;
133=”Negerpunk”;
134=”PolskPunk”;
135=”Beat”;
136=”ChristianGangstaRap”;
137=”Heavyl”;
138=”Blackl”;
139=”Crossover”;
140=”ContemporaryChristian”;
141=”ChristianRock”;
142=”Merengue”;
143=”Salsa”;
144=”Trashl”;
145=”Anime”;
146=”JPop”;
147=”Synthpop”;

其他任何的数值都认为是“unknown”

##注:本文参考自:
http://blog.csdn.net/fulinwsuafcie/article/details/8972346 作者:fulinwsuafcie
http://blog.csdn.net/xsjm206/article/details/6719970 作者: xsjm206
如有侵权请联系删除。

MP3解码流程(一)-----音频文件结构解析相关推荐

  1. 基于libmad库的MP3解码简析

    基于libmad库的MP3解码简析  MAD (libmad)是一个开源的高精度 MPEG 音频解码库,支持 MPEG-1(Layer I, Layer II 和 LayerIII(也就是 MP3). ...

  2. JPEG文件格式及其解码流程

    jpeg是1992年发布的图片编码标准,20多年过去了,它在如今图片压缩领域仍然占据着重要地位.本文主要针对标准ISO/IEC 10918-1 分析jpeg文件结构以及解码流程. 1.文件结构 1.1 ...

  3. MP3文件结构及编解码流程

    http://blog.csdn.net/wlsfling/article/details/5875959 AGENDA * MP3简介      * MP3文件结构         --Tag_v2 ...

  4. Java Mp3转化WAV/PCM音频数据,解码详细解析,提取每一帧数据集合/比特流/播放,一行代码!

    导言 大家好!我是原子君 1.因为Java本身只支持,wav,缺少mp3的解码器,所以Java自带的无法对mp3进行处理,这种MPEG-*音频有损压缩标准编码,更不要说使用Java的音频格式和音频流就 ...

  5. MP3文件结构解析(超详细)

    1. MP3文件结构解析 1.1. 概述 1.1.1. 音频相关术语 ID3: 一般位于一个mp3文件的开头或末尾的若干字节内,记录该mp3文件的歌手.标题.专辑名称.年代.风格等信息,ID3分位两个 ...

  6. 深入浅出:FFmpeg 音频解码与处理AVFrame全解析

    深入浅出:FFmpeg 音频解码与处理全解析 一.FFmpeg 简介 1.1 FFmpeg 的历史与发展 1.2 FFmpeg 的主要组成部分 二.音频编解码基础 (Basics of Audio E ...

  7. MP3文件格式与编码原理解码流程详解

    1 文件格式 MP3文件格式四部分,按顺序排列如下: ID3V2  包含了作者,作曲,专辑等信息,长度不固定,扩展了ID3V1的信息量 Frame  音频帧序列 APEV2  包含了作者,作曲,专辑等 ...

  8. MP3文件格式及编解码流程

    一.MP3简介: MP3全称MPEG 1 audio layer 3,其中MPEG(Moving Picture Experts Group)标准包括视频和音频 标准,其中音频标准已制定出 MPEG- ...

  9. 【Android RTMP】音频数据采集编码 ( AAC 音频格式解析 | FLV 音频数据标签解析 | AAC 音频数据标签头 | 音频解码配置信息 )

    文章目录 安卓直播推流专栏博客总结 一. AAC 音频格式解析 二. FLV 音频数据标签解析 1. 分析 FLV 格式中的 AAC 音频格式数据 2. AAC 音频特殊配置 3. AAC 音频数据标 ...

  10. ijkplayer源码分析 音频解码流程

    前言 本系列如下: 整体概述 视频渲染流程 音频播放流程 read线程流程 音频解码流程 视频解码流程 视频向音频同步 start流程和buffering缓冲策略 本文是流程分析的第四篇,分析ijkP ...

最新文章

  1. 贪心算法简单实践 -- 分糖果、钱币找零、最多区间覆盖、哈夫曼编解码
  2. 形式参数内存在哪java_深入浅出Java中JVM内存管理
  3. 在内核中添加系统调用
  4. 成功解决ValueError: Unable to add relationship because child variable ‘ID‘ in ‘cats_df‘ is also its inde
  5. Scss、elementUI引入、transition动画 - 学习笔记
  6. campaign read in WebUI - Fiori is correct!
  7. 在MapPath的Path参数中不允许字符'..',解决方法。
  8. ElasticSearch创建、修改、获取、删除、索引Indice mapping和Index Template案例
  9. vue里写三元判断绑定class和style
  10. git暂存工作区stash
  11. linux 的 swapper 进程不能sleep,深入理解perf报告中的swapper进程
  12. c语言中变量后减号大于号,大于等于运算符.ppt
  13. 7.数电复刻 之 门电路
  14. Linux系统密码忘记教程
  15. GitHub iOS开源项目
  16. php过气了吗,她怎么就过气了?
  17. win10自动修复无法修复你的电脑的解决方法(操作+原理理解)
  18. 每天自学3~4小时java,一年后能到什么程度
  19. 使用opencv的viz模块显示3d点云
  20. Windows时钟同步(时间同步)问题

热门文章

  1. Uncaught Error: Rendered fewer hooks than expected. This may be caused by an accidental early return
  2. PyQt5编程-鼠标事件
  3. 教育教学中,为什么需要培养学生的创新思维?
  4. MySQL 报错:ERROR 1137 (HY000): Can't reopen table: 'tempId'
  5. 携程网络防火墙自动化运维
  6. SayAsYouWish:Fine-grained Control of Image Caption Generation with Abstract Scene Graphs ---- 论文阅读笔记
  7. 倒排索引、正排索引,以及ElasticSearch对倒排索引的优化方法
  8. oracle认证考试_通过获得Oracle助理认证来提升您的职业-PrepAway进行的1Z0-052考试复习
  9. 笔记1-P2P后台管理系统
  10. in unnamed module of loader ‘app‘