Mp3的数据格式解析可以分为以下步骤
一、了解Mp3是如何组成?
MP3的格式基本上标准的就是ID3V2.x + Frame +ID3v1.x
其中x表示数字,也就是ID3大版本下的小版本。
但是也是不完全是这种组成,我遇到过的也是有Frame + ID3V1.x,这种虽然是非标准的格式,市面上的播放器还是可以解析的。
1.1 ID3V2.x里面都有什么东西?
ID3V2.x又是由标签头+标签帧组成
1.1.1 标签头
在文件的首部顺序记录10个字节的ID3V2.3的头部。数据结构如下:
char Header【3】; /必须为"ID3"否则认为标签不存在/
char Ver; /版本号ID3V2.3就记录3/
char Revision; /副版本号此版本记录为0/
char Flag; /存放标志的字节,这个版本只定义了三位,稍后详细解说/
char Size【4】; /标签大小,包括标签头的10个字节和所有的标签帧的大小/
1.标志字节
标志字节一般为0,定义为: abc00000
a – 表示是否使用Unsynchronisation(这个单词不知道是什么意思,字典里也没有找到,一般不设置)
b – 表示是否有扩展头部,一般没有(至少Winamp没有记录),所以一般也不设置
c – 表示是否为测试标签(99.99%的标签都不是测试用的啦,所以一般也不设置)
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)
莫名自己转上去了,后面尝试修复,size1。。。。表示数组的位置
1.1.2 标签帧
每个标签帧都有一个10个字节的帧头和至少一个字节的不固定长度的内容组成。它们也是顺序存放在文件中,和标签头和其他的标签帧也没有特殊的字符分隔。得到一个完整的帧的内容只有从帧头中的到内容大小后才能读出,读取时要注意大小,不要将其他帧的内容或帧头读入。
帧头的定义如下:
char FrameID【4】; 用四个字符标识一个帧,说明其内容,稍后有常用的标识对照表
char Size【4】; 帧内容的大小,不包括帧头,不得小于1*/
char Flags【2】; 存放标志,只定义了6位,稍后详细解说*/
1.帧标识
用四个字符标识一个帧,说明一个帧的内容含义,常用的对照如下:
TIT2=标题 表示内容为这首歌的标题,下同
APIC=attached picture(专辑封面)
TPE1=作者
TOPE=艺术家
TALB=专集
TRCK=音轨 格式:N/M 其中N为专集中的第N首,M为专集中共M首,N和M为ASCII码表示的数字
TYER=年代 是用ASCII码表示的数字
TCON=类型 直接用字符串表示
COMM=备注 格式:“eng"0备注内容”,其中eng表示备注所使用的自然语言
2.大小
这个可没有标签头的算法那么麻烦,每个字节的8位全用,格式如下
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
算法如下:
int FSize;
FSize = Size[0]*0x100000000 + Size[1]*0x10000 + Size[2]*0x100 + Size[3];
3.标志
只定义了6位,另外的10位为0,但大部分的情况下16位都为0就可以了。格式如下:
abc00000 ijk00000
a – 标签保护标志,设置时认为此帧作废
b – 文件保护标志,设置时认为此帧作废
c – 只读标志,设置时认为此帧不能修改(但我没有找到一个软件理会这个标志)
i – 压缩标志,设置时一个字节存放两个BCD码表示数字
j – 加密标志(没有见过哪个MP3文件的标签用了加密)
k – 组标志,设置时说明此帧和其他的某帧是一组
值得一提的是winamp在保存和读取帧内容的时候会在内容前面加个’"0’,并把这个字节计算在帧内容的大小中。
1.2 Frame
1. 2.1 帧头格式
下面是一个头内容图示,使用字符 A 到 M 表示不同的区域。在表格中你可以看到每一区域
的详细内容。
AAAAAAAA AAABBCCD EEEEFFGH IIJJKLMM
每个区域的含义在官网都有说 ID3官网: http://www.id3.org/
表单实在太长了,占用精华模板,自己去看看
总体来说,你可以在framehead中获取到各种信息,参照以下的结构体
typedef struct frameHeader
{
unsigned int sync1:8; //同步信息 1
unsigned int error_protection:1; //CRC 校验
unsigned int layer:2; //层
unsigned int version:2; //版本
unsigned int sync2:3; //同步信息 2
unsigned int extension:1; //版权
unsigned int padding:1; //填充空白字
unsigned int sample_rate_index:2; //采样率索引
unsigned int bit_rate_index:4; //位率索引
unsigned int emphasis:2; //强调方式
unsigned int original:1; //原始媒体
unsigned int copyright:1; //版权标志
unsigned int mode_extension:2; //扩展模式,仅用于联合立体声
unsigned int channel_mode:2; //声道模式
}FHEADER, *pFHEADER;
1.2.2 如何计算帧长度
我们首先区分两个术语:帧大小和帧长度。帧大小即每帧采样数表示一帧中采样的个数,这是恒定值。其值入下表所示
帧长度是压缩时每一帧的长度,包括帧头。它将填充的空位也计算在内。LayerI 的一个空位长 4 字节,LayerII 和 LayerIII 的空位是 1 字节。当读取 MPEG 文件时必须计算该值以便找到相邻的帧。
注意:因为有填充和比特率变换,帧长度可能变化。
从头中读取比特率,采样频率和填充,
LyaerI 使用公式:
帧长度(字节) = (( 每帧采样数 / 8 * 比特率 ) / 采样频率 ) + 填充 * 4
LyerII 和 LyaerIII 使用公式:
帧长度(字节)= (( 每帧采样数 / 8 * 比特率 ) / 采样频率 ) + 填充
例:
LayerIII 比特率 128000,采样频率 44100,填充 0
=〉帧大小 417 字节
1.3 ID3V1
ID3V1比较简单,它是存放在MP3文件的末尾,用16进制的编辑器打开一个MP3文件,查看其末尾的128个顺序存放字节,数据结构定义如下:
char Header[03]; /标签头必须是"TAG"否则认为没有标签/
char Title[30]; /标题/
char Artist[30]; /作者/
char Album[30]; /专集/
char Year[04]; /出品年代/
char Comment[30]; /备注/
char Genre; /类型,流派/
二.codeing环节
自己给一些建议吧!
Step1 首先先找出是否存在ID3V2的标签(也就是“ID3”的tag)
Step2 若没有ID3V2的标签存在时,那就意味着刚开始就已经是属于frame
Step3 从framehead中得到各种信息,这样子就可以保留各种信息。同时需要什么信息,就可以去取。
如果说类的话,我个人的做法是将Mp3的类,其次再拆分ID3和frame的两个类。在构建Mp3时,可以选择性的将ID3和frame去构建。
同样可以拆分为Mp3面向业务。ID3V2+frame+ID3V1。
希望可以帮助到各位!