概述
最近使用开发的过程中出现了一个小问题,顺便记录一下原因和方法--字节文件
一、概述
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。
ID3V2 | 包括了作者,作曲,专辑等信息,长度不固定,扩展了ID3V1的信息量。 |
Frame . . . Frame | 一系列的帧,个数由文件巨细和帧长决议 每一个FRAME的长度可能不固定,也可能固定,由位率bitrate决议 每一个FRAME又分为帧头和数据实体两部分 帧头记录了mp3的位率,采样率,版本等信息,每一个帧之间互相独立。 |
ID3V1 | 包括了作者,作曲,专辑等信息,长度为128BYTE。 |
表格2.1
1、ID3V2
ID3V2 到现在一共有4 个版本,但风行的播放软件一般只支撑第3 版, 既ID3v2.3。
由于ID3V1 记录在MP3 文件的末端,ID3V2就只好记录在MP3 文件的首部了(如果有一天发布ID3V3,真不晓得该记录在哪里)。也恰是由于这个原因,对ID3V2 的操作比ID3V1 要慢。而且ID3V2 结构比ID3V1 的结构要庞杂很多,但比前者全面且可以伸缩和扩展。
上面就分析一下ID3V2.3:
每一个ID3V2.3 的标签都一个标签头和若干个标签帧或一个扩展标签头组成。关于曲目的信息如标题、作者等都存放在不同的标签帧中,扩展标签头和标签帧并非必要的,但每一个标签最少要有一个标签帧。标签头和标签帧一起次序存放在MP3 文件的首部。
1、标签头
在文件的首部次序记录10 个字节的ID3V2.3 的头部。数据结构如下:
char Header[3]; /*必须为"ID3"否则以为标签不存在*/
char Ver; /*版本号ID3V2.3 就记录3*/
char Revision; /*副版本号此版本记录为0*/
char Flag; /*存放标记的字节,这个版本只定义了三位,稍后具体解说*/
char Size[4]; /*标签巨细,包括标签头的10 个字节和所有的标签帧的巨细*/
图2.1
蓝色部分即为ID3V2.3的头部:前4个字节就是 ID30x03(第3版)
第5个字节:副版本号,为0
注:文中关于mp3文件数据截图均为“紫藤花.mp3”文件中的数据截图
1)标记字节
标记字节一般为0,定义如下:
abc00000
a -- 表示是不是使用Unsynchronisation(这个单词不晓得是什么意思,字典里也没有找到,一般不设置)
b -- 表示是不是有扩展头部,一般没有(最少Winamp 没有记录),所以一般也不设置
c -- 表示是不是为测试标签(99.99%的标签都不是测试用的啦,所以一般也不设置)
第6个字节:存放标记的字节,只定义了三位,这里值为0
2)标签巨细
一共四个字节,但每一个字节只用7位,最高位不使用恒为0。所以格式如下
0xxxxxxx 0xxxxxxx 0xxxxxxx 0xxxxxxx
盘算巨细时要将0 去掉,得到一个28 位的二进制数,就是标签巨细(不懂为什么要这样做),盘算公式如下:
int total_size;
total_size =
(Size[0]&0x7F)*0x200000+ (Size[1]&0x7F)*0x400 + (Size[2]&0x7F)*0x80 +(Size[3]&0x7F)
第7到10字节:表示ID3标签的巨细,这里为
total_size=(0x00&0x7F)*0x200000+(0x00&0x7F)*0x400+(0x2F&0x10)*0x80 +(0x76 &072)
= 0x872 =2162
注意:这里的帧巨细,并不包括帧头的10个字节,只表示帧内容的巨细
2、标签帧
每一个标签帧都有一个10 个字节的帧头和最少一个字节的不固定长度的内容组成。它们也是次序存放在文件中,和标签头和其他的标签帧也没有特别的字符分开。得到一个完全的帧的内容只有从帧头中的到内容巨细后才能读出,读取时要注意巨细,不要将其他帧的内容或帧头读入。
帧头的定义如下:
char ID[4]; /*用四个字符标识一个帧,说明其内容,稍后有常用的标识对照表*/
char Size[4]; /*帧内容的巨细,不包括帧头,不得小于1*/
char Flags[2]; /*存放标记,只定义了6 位,稍后具体解说*/
图2.2
蓝色部分是一个歌曲标题的标签帧
1)帧标识
用四个字符标识一个帧,说明一个帧的内容含义,常用的对照如下:
TIT2=标题表示内容为这首歌的标题,下同
TPE1=作者
TALB=专集
TRCK=音轨格式:N/M 其中N 为专集中的第N 首,M为专集中共M 首,N和M 为ASCII 码表示的数字
TYER=年月是用ASCII 码表示的数字
TCON=类型直接用字符串表示
COMM=备注格式:"eng 备注内容",其中eng 表示备注所使用的自然语言
注:更多的帧标识说明见附录一。
前4个字节为帧标识,这里是54 49 5432(TIT2) 是标题的标签帧
2)巨细
这个可没有标签头的算法那么费事,每一个字节的8 位全用,格式如下
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
算法如下:
int FSize;
FSize = Size[0]*0x100000000 + Size[1]*0x10000+ Size[2]*0x100 + Size[3];
第5到8字节为标签帧的巨细,这里为
FSize = 0x00*0x100000000+ 0x00*0x10000 + 0x00*0x100 + 0x24 = 0x24 = 36
注意:这里的帧巨细,并不包括帧头的10个字节,只表示帧内容的巨细
3)标记
只定义了6 位,另外的10 位为0,但大部分的情况下16 位都为0 就可以了。格式如下:
abc00000ijk00000
a -- 标签掩护标记,设置时以为此帧作废
b -- 文件掩护标记,设置时以为此帧作废
c -- 只读标记,设置时以为此帧不能修改(但我没有找到一个软件理会这个标记)
i -- 压缩标记,设置时一个字节存放两个BCD 码表示数字
j -- 加密标记(没有见过哪个MP3 文件的标签用了加密)
k -- 组标记,设置时说明此帧和其他的某帧是一组
值得一提的是winamp 在保存和读取帧内容的时候会在内容前面加个''