一. 基本組成
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
3. ID3 Implementations (ID3v2 代碼實現)