ID3V2
相对于ID3V1,V2所附加到文件中的信息更多,除了一般关于音频的信息外,还能在文件中附加图片,在电脑和一些播放器上能看到的专辑封面,就是解码这部分信息得到的图片
ID3V2结构
ID3V2的四个版本中,直到V2.4才开始支持尾部,但是因为找到的采用2.4附加信息的音频文件很少,其中也没有连同尾部一起附加的,所以暂不做分析。值得一提的是,我在找的时候,发现不少2.3头带着v1尾的,这看着就像是v1的文件简单粗暴的加了个v2头。
len | value | 说明 | |
---|---|---|---|
文件头 | 10字节 | 0x49 44 33 0a bb cc xx xx xx xx | 前3字节是ID3,表示ID3V2,a表示2点几版本,bb是副版本号,整个完整的版本号是【2.a.bb】,x存的是size,但每个字节都只用了其中低7位 |
扩展文件头 | 10字节 | 这个不是必要的,文件头中指示了这部分是否存在 | |
标签头 | 10字节 | 包含了标签帧存的是什么内容及大小等信息 | |
标签内容 | N字节 | 官方给出的说明是这个部分包含1个字节的编码标识,0-3个字节的大小端识别,后面才是编码内容,但是有一些标签,不按这个套路,比如图片和comm |
文件头
首先来说说文件头的10个字节
offset | len | value | 说明 | |
---|---|---|---|---|
ID3标识 | 0x0 | 3 | 0x49 33 | 必须是这个值 |
ID3V2版本号 | 0x3 | 1 | 常见0x03 | |
副版本号 | 0x4 | 1 | 一般为 0x0 | |
标志字节 | 0x5 | 1 | 只定义了高3位,最高位表示非同步,次高位表示扩展头部是否存在,次次高位表示是否为测试。除了表示扩展头部的,其他的我都不知道是到底啥用的,咱也不敢问,一般都为0 |
数据结构:
typedef struct headlable
{
char FileIdentifier[3]; // 必须为字符串"ID3",否则认为标签不存在 对应16进制:49 44 33
char Version; // 版本号ID3V2.3 就记录0x03
char Revision; // 副版本号此版本记录为0x00
char Flag; // 存放标志的字节,这个版本只定义了3bit
char Size[4]; // 标签帧的大小,不包括标签头的10个字节
}HeadLab;
size的计算:
HeadLab *hdr;
int size;
//get hdr from file
size = 0;
size |= (hdr->Size[0]&0x7f) << 21;
size |= (hdr->Size[1]&0x7f) << 14;
size |= (hdr->Size[2]&0x7f) << 7;
size |= (hdr->Size[3]&0x7f) << 0;
扩展文件头
2.3和2.4的扩展文件头不同
2.3 | offset | len | value | 说明 |
---|---|---|---|---|
size | 0x0 | 4字节 | 0x XX XX XX XX | 使用了所有字节位 |
flag | 0x4 | 2字节 | ||
pading size | 0x6 | 4字节 | 0x XX XX XX XX | 为了添加更多的信息时,不改动后面数据的位置,头部信息中采用了填充 |
2.4的就不罗列了
标签帧结构
文件头之后紧接的如果没有扩展头,就是一段一段的标签帧,每一段标签的结构是这个样子的
标签帧头 | 标签内容 | 标签内容 | 标签内容 | |
---|---|---|---|---|
编码Index | 大小端Index | data | ||
大小 | 10字节 | 1字节 | 0-3字节 | N字节 |
标签帧头结构
标签帧头 | offset | len | value | 说明 |
---|---|---|---|---|
Frame ID | 0x0 | 4 | ||
Size | 0x4 | 4 | ||
Flags | 0x8 | 2 | 每个字节都定义了高四位中的低三位 |
编码及大小端
value | 编码标准 | 大小端识别字节 | 说明 |
---|---|---|---|
0x0 | ISO8859-1 | 不存在 | |
0x1 | utf-16 | 2字节 | FF FE 或者FE FF |
0x2 | utf-16be | 2字节 | FF FE 或者FE FF |
0x3 | utf-8 | 3字节 | EF BB BF |
会存在unicode或gkb转成 iso8859-1的方式存储,解码方法是 Unicode的话,每个字节补0x00 变成双字节
gkb编码成iso8859-1是按单字节的值采用分段编码
- 0x0-0x7f之间(含),值不变
- 0x80-0xbf之间(含),就加一个0xc2变成两个字节
- 0xc0-0xff,加一个0xc3,并且值减去0x40;
可以看出,除去编码所添加的0xc2和0xc3,编码中不会有超过0xc0的值,解码的时候,先判断这个值是否小于0x80,小于把这个字节提取出来,如果大于,先找编码添加值,c2就提取后一字节,c3就提取后一字节,并加0x40,其他值就表示出错