一. 基本组成
MP3文件中的ID3v2 的基本组成如下:
可以看到,基本分为三部分:标签头,帧头,帧标识三部分。
二. 标签头
在文件的首部顺序记录 10 个字节的 ID3V2.3 的头部。数据结构如下:
typedef ID3_HEADER { uint8_t id3_identifier[3]; uint8_t id3_version; uint8_t id3_revision; uint8_t id3_flags; uint32_t id3_size; } ID3_HEADER_t;
各个字段的详细含义如下:
- id3_identifier[3]。
头部标识。占3个字节,由字符ID3组成,表示这是一个ID3v2的标签;
- id3_version。
主版本号。版本号 ID3V2.3 就记录 3
- id3_revision。
副版本号。这里记录为0
- id3_flags。
存放标志的字节。标志字节一般为 0,定义如下: abc00000,
a -- 表示是否使用 Unsynchronisation(这个单词不知道是什么意思,字典里也没有找到,一般不设置);
b -- 表示是否有扩展头部,一般没有(至少 Winamp 没有记录),所以一般也不设置
c -- 表示是否为测试标签(99.99%的标签都不是测试用的啦,所以一般也不设置)
- id3_size。
标签大小。代表的是后面所有标签帧的总大小。一共占四个字节, 但是按照ID3v2 标准(https://id3.org/id3v2.3.0#ID3v2_header)的要求,每个字节只用 7 位,最高位不使用,恒为 0。举个例子来说,
比如:如果后面标签帧的总大小是257,那么在写入时,就必须是:513
257 (%00000001 00000001) encoded as a 16 bit synchsafe integer is 513 (%00000010 00000001).
又比如:如果后面标签帧的总大小是255,那么在写入时,就必须是:383
255 (%11111111) encoded as a 16 bit synchsafe integer is 383 (%00000001 01111111).
另外,数值在写入时,必须以大端格式写入。
由于计算结果需要将每个字节的最高位0位丢弃,所以这里提供两个函数用于处理这个问题:
丢弃最高位:
int syncint_encode(int value) { int out, mask = 0x7F; while (mask ^ 0x7FFFFFFF) { out = value & ~mask; out <<= 1; out |= value & mask; mask = ((mask + 1) << 8) - 1; value = out; } return out; }
复原:
int syncint_decode(int value) { unsigned int a, b, c, d, result = 0x0; a = value & 0xFF; b = (value >> 8) & 0xFF; c = (value >> 16) & 0xFF; d = (value >> 24) & 0xFF; result = result | a; result = result | (b << 7); result = result | (c << 14); result = result | (d << 21); return result; }
三. 标签帧
每个标签帧都有一个 10 个字节的帧头和至少一个字节的不固定长度的内容组成。 它们也是顺序存放在文件中,和标签头和其他的标签帧也没有特殊的字符分隔。得到一个完整的帧的内容只有从帧头中的到内容大小后才能读出,读取时要注意大小,不要将其他帧的内容或帧头读入。
它的数据结构定义如下:
typedef ID3_FRAME { uint8_t frame_id[4]; uint32_t frame_size; uint16_t frame_flags; } ID3_FRAME_t;
各个字段的详细含义如下:
- frame_id[4]。用四个字符标识一个帧,描述其内容,常用的标识有:
TIT2 = 标题 表示内容为这首歌的标题,下同
TPE1 = 作者
TALB = 专集
TRCK = 音轨 格式:N/M 其中 N 为专集中的第 N 首,M 为专集中共 M 首,N 和 M 为 ASCII 码表示的数字
TYER = 年代 是用 ASCII 码表示的数字
TCON = 类型 直接用字符串表示
COMM = 备注 格式:"eng/0 备注内容",其中 eng 表示备注所使用的自然语言
更多的标识请参考:https://id3.org/id3v2.3.0#Declared_ID3v2_frames
- frame_size。代表帧内容的大小,这里要注意,写入时也必须为大端格式。
- frame_flags。 代表帧标记暂时不清楚有什么实际含义。
参考链接:
1. ID3 tag version 2.4.0 - Main Structure