Layer-3音频文件,MPEG(MovingPicture 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。
MP3文件大体分为三部分:TAG_V2(ID3V2),音频数据,TAG_V1(ID3V1),其中ID3V2是ID3V1的补充,并不是所有的MP3都有ID3V2补充,即是不是所有的MP3文件都有ID3V2。
如果MP3文件存在ID3V2,则一定在文件的头部,ID3V2结构分为头部(header)和若干标签帧,其中头部长度为10字节,10个字节的结构如表1:
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
内容为”ID3” |
版本号 |
副版本号 |
存放标志的字节 |
ID3V2总大小(帧头和之后的若干标签帧总和) |
表1
因为3、4、5字节所代表的意义并不是MP3解码的重点,故此只解说前三字节和后四字节:
从表1可看出判断MP3文件是否存在ID3V2,只需要判断文件前三个字节是否是”ID3”;
ID3V2数据大小计算公司:
total_size = (Size[0]&0x7F)*0x200000+ (Size[1]&0x7F)*0x400 + (Size[2]&0x7F)*0x80 +(Size[3]&0x7F) |
其中,size[0~3],分别是表1中的6~9字节。需要注意的是,这个公司计算的长度并不包括ID3V2的10个字节的头部。
ID3V2头部之后的若干标签帧每一帧结构分为标签ID(4字节)、帧内容大小(4字节,不包括标签帧帧头)、存放标志位(2字节)、内容。其中标签ID的含义如下:
TEXT: 歌词作者 TENC: 编码 WXXX: URL链接(URL) TCOP: 版权(Copyright) TOPE: 原艺术家 TCOM: 作曲家 TDAT: 日期 TPE3: 指挥者 TPE2: 乐队 TPE1: 艺术家相当于ID3v1的Artist TPE4: 翻译(记录员、修改员) TYER: 即ID3v1的Year USLT: 歌词 TSIZ: 大小 TALB: 专辑相当于ID3v1的Album TIT1: 内容组描述 TIT2: 标题相当于ID3v1的Title TIT3: 副标题 TCON: 流派(风格)相当于ID3v1的Genre AENC: 音频加密技术 TBPM: 每分钟节拍数COMM: 注释相当于ID3v1的Comment TDLY: 播放列表返录 TRCK: 音轨(曲号)相当于ID3v1的Track 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]; // 标志对照符,如TEXT,TOPE,TDAT.... 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 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数据解码流程借用图1描述。
图1
MP3文件的音频数据部分,是分为很多数据帧存放,每一帧数据播放的时间长度计算公式:
每帧持续时间(毫秒) =每帧采样数 /采样频率 * 1000 假设每帧采样数为1152,采样频率为44.1K,则每帧数据播放的时间约为26ms。 |
没帧数据的结构包括帧头(header)、帧边信息(side)、主数据(main data)。
数据帧帧头长度为4字节,结构如图2所示。
图2
由图可知,同步信息(synchronizationword)11位皆为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 |
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。 |
帧边信息解码的主要目的在于找出解这帧的各个参数,包括主数据开始位置,尺度因子长度等。帧边信息如图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中有两粒度组,没个粒度组分为两个声道,取数据存储结构如图5。
图5
其中,每个通道(chN_data)的结构图6.
图6