首页 > 代码库 > MP3文件结构及解码概述

MP3文件结构及解码概述

MP3文件结构概述

Layer-3音频文件,MPEG(MovingPicture Experts Group)在汉语中译为活动图像专家组,特指活动影音压缩标准,MPEG音频文件是MPEG1标准中的声音部分,也叫MPEG音频层,它根据压缩质量和编码复杂程度划分为三层,即Layer-1Layer2Layer3,且分别对应MP1MP2MP3这三种声音文件,并根据不同的用途,使用不同层次的编码。MPEG音频编码的层次越高,编码器越复杂,压缩率也越高,MP1MP2的压缩率分别为4161-81,而MP3的压缩率则高达101-121

MP3文件大体分为三部分:TAG_V2(ID3V2),音频数据,TAG_V1(ID3V1),其中ID3V2ID3V1的补充,并不是所有的MP3都有ID3V2补充,即是不是所有的MP3文件都有ID3V2

ID3V2

        如果MP3文件存在ID3V2,则一定在文件的头部,ID3V2结构分为头部(header)和若干标签帧,其中头部长度为10字节,10个字节的结构如表1

0

1

2

3

4

5

6

7

8

9

内容为”ID3”

版本号

副版本号

存放标志的字节

ID3V2总大小(帧头和之后的若干标签帧总和)

1

因为345字节所代表的意义并不是MP3解码的重点,故此只解说前三字节和后四字节:

  1.  从表1可看出判断MP3文件是否存在ID3V2,只需要判断文件前三个字节是否是”ID3”

  2. ID3V2数据大小计算公司:

total_size = (Size[0]&0x7F)*0x200000+ (Size[1]&0x7F)*0x400 + (Size[2]&0x7F)*0x80 +(Size[3]&0x7F)

其中,size[0~3],分别是表1中的6~9字节。需要注意的是,这个公司计算的长度并不包括ID3V210个字节的头部。

ID3V2头部之后的若干标签帧每一帧结构分为标签ID4字节)、帧内容大小(4字节,不包括标签帧帧头)、存放标志位(2字节)、内容。其中标签ID的含义如下:

TEXT: 歌词作者    TENC: 编码        WXXX URL链接(URL)        TCOP: 版权(Copyright)   TOPE: 原艺术家

TCOM: 作曲家      TDAT: 日期        TPE3: 指挥者              TPE2: 乐队               TPE1: 艺术家相当于ID3v1Artist

TPE4: 翻译(记录员、修改员)          TYER: 即ID3v1Year      USLT: 歌词               TSIZ: 大小

TALB: 专辑相当于ID3v1Album         TIT1: 内容组描述          

TIT2: 标题相当于ID3v1Title       TIT3: 副标题

TCON: 流派(风格)相当于ID3v1Genre AENC: 音频加密技术        

TBPM: 每分钟节拍数COMM: 注释相当于ID3v1Comment   

TDLY: 播放列表返录                 TRCK: 音轨(曲号)相当于ID3v1Track

TFLT: 文件类型                     TIME: 时间       

TKEY: 最初关键字                   TLAN: 语言                

TLEN: 长度                        TMED: 媒体类型    

TOAL: 原唱片集                     TOFN: 原文件名            

TOLY: 原歌词作者                   TORY: 最初发行年份

TOWM: 文件所有者(许可证者)          TPOS: 作品集部分          

TPUB: 发行人                       TRDA: 录制日期

TRSN Intenet电台名称                 TRSO Intenet电台所有者   UFID: 唯一的文件标识符  

TSRC ISRC(国际的标准记录代码)     TSSE: 编码使用的软件(硬件设置)

读取MP3文件ID3V2信息的函数可如下:

//定义头部和标签帧

typedefstruct ID3v2Header{

   char Identify[3];         // ID3v2固定标志:ID3

   char Ver;              //主版本号,ID3v2就是3

   char Rever;            //副版本号,一般都为0

   char Flag;             //标志位,一般为0,字义为abc00000

   char Size[4];             //标签大小,一共四个字节,但每个字节只使用7位,最高位不使用恒为0,所以格式: 0xxxxxxx 0xxxxxxx 0xxxxxxx 0xxxxxxx

}ID3v2Header;

 

typedefstruct ID3v2Frame//标签帧,10个字节

{

   char FrameID[4];          //标志对照符,如TEXTTOPETDAT....

   char Size[4];             //帧体的大小,按照正常的8位存储的,FSize = Size[0]*0x100000000 + Size[1]*0x10000 + Size[2]*0x100 + Size[3];

   char Flag[2];             //存放标志

}ID3v2Frame;

 

//输出信息并返回ID3V2大小

int ReadID3v2(FILE *pf)

{

   ID3v2Headermp3header;

   ID3v2Frame mp3Frame;

   int FSize      = 0;

   char str[4096] = {0};

   char str2[5]   = {0};

   int ID3size;

   inthead_size = 0;

   inti;

   if(!pf)

       return -1;

   fseek(pf,0,SEEK_SET);

   fread(&mp3header,sizeof(mp3header),1,pf);

   if (mp3header.Identify[0]!=‘I‘ || mp3header.Identify[1]!=‘D‘ || mp3header.Identify[2]!=‘3‘ ){

       printf("此歌曲不支持ID3v2标准!\n");

       //文件复位

       rewind(pf);

       return -2;

   }

   printf("ID3v2标志:%.3s\n",mp3header.Identify);

   printf("ID3v2版本:%d\n",  mp3header.Ver);

   ID3size= (mp3header.Size[0]& 0x7F)<< 21|(mp3header.Size[1]& 0x7F)<< 14|(mp3header.Size[2] & 0x7F) << 7|(mp3header.Size[3] & 0x7F);

   printf("标签大小:%d\n***********\n",ID3size);

   for (i=0;i<ID3size;i=i+11+FSize){

       memset(&mp3Frame,0,sizeof(mp3Frame));

       memset(&str,0,sizeof(str));

       fseek(pf,10+i,SEEK_SET);               //移动到标签帧头

       fread(&mp3Frame,sizeof(mp3Frame),1,pf);

       //原则上是不用-1的,但是实际发现,总有一个字节的差距,为了计算方便-1,所以出现-1时标明此区块无内容

       FSize  = (int)(mp3Frame.Size[0]*0x100000000 + mp3Frame.Size[1]*0x10000+ mp3Frame.Size[2]*0x100 + mp3Frame.Size[3]-1);

       if (FSize>0)   {

           fseek(pf,10+11+i,SEEK_SET);//移动到内容区           

           fread(str,FSize,1,pf);

           GetStr(mp3Frame.FrameID,str2);

           printf("%s-%s:\t%s\n",str2,mp3Frame.FrameID,str);

           head_size+=11;

       }else{

           return ID3size+10;

       }

   }

   return ID3size+10;

}

 

//通过FrameID获取对应的中文名

void GetStr(char* oldstr,char* str)

{

   if (0==memcmp((LPCTSTR)"TIT2",oldstr,4))

   {

       memcpy(str,"标题",4);

   }elseif(0==memcmp((LPCTSTR)"TPE1",oldstr,4)){

       memcpy(str,"作者",4);

   }elseif(0==memcmp((LPCTSTR)"TALB",oldstr,4)){

       memcpy(str,"专辑",4);

   }elseif(0==memcmp((LPCTSTR)"TRCK",oldstr,4)){

       memcpy(str,"音轨",4);

   }elseif(0==memcmp((LPCTSTR)"TYER",oldstr,4)){

       memcpy(str,"年代",4);

   }elseif(0==memcmp((LPCTSTR)"COMM",oldstr,4)){

       memcpy(str,"备注",4);

   }elseif(0==memcmp((LPCTSTR)"TCON",oldstr,4)){

       memcpy(str,"类型",4);

   }else{

       memcpy(str,"未知",4);  //其他的不是很重要,所以省略了

   }

}

MP3文件数据结构及处理流程

MP3数据解码流程借用图1描述。

1

MP3文件的音频数据部分,是分为很多数据帧存放,每一帧数据播放的时间长度计算公式:

   每帧持续时间(毫秒) =每帧采样数 /采样频率 * 1000

假设每帧采样数为1152,采样频率为44.1K,则每帧数据播放的时间约为26ms

   没帧数据的结构包括帧头(header)、帧边信息(side)、主数据(main data)。

帧头(header

        数据帧帧头长度为4字节,结构如图2所示。

2

        由图可知,同步信息(synchronizationword11位皆为1,其他位信息如表

版本(ID

2bit

00-MPEG 2.5  01-未定义    10-MPEG 2    11-MPEG 1

层(layer

2bit

00-未定义     01-Layer 3    10-Layer 2     11-Layer 1

CRC校验

1bit

0-校验       1-不校验

位率索引

4bit

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

56

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" 表示不允许值

采样频率

2bit

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-未定义

是否填充

1bit

0-无需调整,1-调整

保留(reserved

1bit

 

声道模式

2bit

00-立体声Stereo   01-Joint Stereo   10-双声道       11-单声道

保留(reserved

2bit

 

版权标志

1bit

0-不合法  1-合法

原版标志

1bit

0-非原版  1-原版

强调方式

2bit

00-未定义    01-50/15ms    10-保留      11-CCITT J.17

2

数据帧大小计算公式:

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

对于Mp3格式:

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

其中:帧的填充大小便是23bit,不是0则为1

帧边信息(side

帧边信息解码的主要目的在于找出解这帧的各个参数,包括主数据开始位置,尺度因子长度等。帧边信息如图3所示。

3

其中main_data_begin(主数据开始)是一个偏移值,指出主数据是在同步字之前多少个字节开始。需要注意的是,1.帧头不一定是一帧的开始,帧头CRC校验字和帧边信息在帧数据中是滑动的。2.这个数值忽略帧头和帧边信息的存在,如果main_data_begin = 0, 则主数据从帧边信息的下一个字节开始,示意图如图4.

4

        块类型(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个数据独立加窗后在经过连接计算得到的。

主数据(main_data

        main_data中有两粒度组,没个粒度组分为两个声道,取数据存储结构如图5

5

其中,每个通道(chN_data)的结构图6.

6



MP3文件结构及解码概述