歌名不在音频里

播放器列表里那行「晴天 – 周杰伦 – 叶惠美」,一个字节都不在 MP3 的音频帧里。MP3 的主体是一串 MPEG 音频帧,帧里只有压缩后的声音;歌名、歌手、专辑、封面这些元数据,住在文件最前面的 ID3v2 标签里——一段先于音频数据、自己管自己长度的结构化字节块。理解了这一点,很多日常怪象就有了答案:为什么有的 MP3 歌名是乱码、为什么编辑标签后音频质量不会变、为什么「删掉标签」文件还能正常播。

ID3 有两个并存的世代。v1 是 1996 年的极简方案:固定 128 字节钉死在文件末尾,标题/歌手/专辑各 30 字节、年份 4 字节、注释 30 字节、流派 1 字节——字段不够长就截断,中文一个字占 2 字节只剩 15 个字,封面更是无处安放。v2 是彻底重设计:标签搬到文件头部、长度可变、按「帧」组织,一帧一个字段,想加多少加多少。今天的文件常常两个都有:头部 v2,尾部 v1,播放器优先读 v2。

十字节头部与 synchsafe 整数

v2 标签以十字节头部开场:ASCII 的 “ID3”、主版本、副版本、标志字节、四字节的标签总长。真正有意思的是那个长度字段——它不是普通 32 位大端整数,而是 synchsafe 编码:每个字节只敢用低 7 位,四个字节拼出 28 位。

为什么自断一臂?因为 MP3 是流式格式,解码器随时可能在任意位置搜索音频帧同步字(0xFF 后跟高三位为 1 的字节)。如果一个尺寸字段恰好出现 FF E? 这样的字节组合,流式解析器就会把标签数据误认成音频帧,从头错到尾。synchsafe 强制每个字节的最高位为 0,从源头上杜绝标签内部出现假同步字。代价是长度上限从 4 GB 缩水到 256 MB——对一段歌名来说绰绰有余。同样是「为流式扫描让路」的设计,v2.4 里连帧长度也改成了 synchsafe,而 v2.3 的帧长仍是普通 32 位大端——同一份规范两代口径,解析器必须按版本分别对待。

头部标志字节的最高位是 unsynchronisation(反同步):写入方把标签数据里每个 FF 后面紧跟 111xxxxx 的位置插入一个 00,读取方再按 FF 00 → FF 还原。这是 synchsafe 之外的第二重保险,v2.3 作用于整个标签体(解析时必须先整段还原再逐帧遍历,顺序不能反),v2.4 细化到逐帧声明。站点的解析实现把这层做全了:v2.3 标签级反同步一次、v2.4 帧级按标志位逐帧处理,解析结果显示「已做反同步解码」的角标,就是这条路走过来的痕迹。

帧:四字符 ID 定乾坤

头部之后就是一串帧。每帧十字节帧头:四字符 ID、四字节长度、两字节标志;帧头之后是本帧数据。ID 的首字母即类型:T 开头是文本帧——TIT2 标题、TPE1 歌手、TALB 专辑、TRCK 音轨、TCON 流派、TCOM 作曲;COMM 是注释;APIC 是封面。v2.2 的上古结构是 6 字节帧头配 3 字符 ID(TT2、TP1……),如今只在老文件里偶尔撞见。

文本帧的第一个字节是编码声明,四种取值背后是一部乱码史:

1
2
3
4
0 = ISO-8859-1   单字节拉丁字母,中文按它读必乱码
1 = UTF-16 带 BOM  双字节,BOM 声明大小端
2 = UTF-16BE     双字节大端,无 BOM
3 = UTF-8        v2.4 才写入规范的迟到者

当年大量中文 MP3 用 GBK 编码写歌名、却把编码字节标成 0(ISO-8859-1),播放器忠实地按拉丁字母表解读,出来就是「å¨åæ¯é」这类天书——这是中文用户对 MP3 乱码最深的记忆。规范层面 v2.3 只认 0 和 1,UTF-8 是 v2.4 才转正的;但现实世界里主流播放器、手机、车机普遍兼容「v2.3 + UTF-8」,所以新写入的标签默认用 UTF-8,只有喂给很老的设备出现乱码时才回退 UTF-16。多值场景也有约定:一个文本帧里用 \0 分隔多个值,解析时合并展示——四位歌手挤在一个 TPE1 里是常态。

APIC 封面帧的结构是「文本帧 + 二进制负载」的混血:编码字节、MIME 类型字符串、图片类型(3 = 前封面)、描述字符串(各按编码有自己的终止符:单字节编码 00 结尾,UTF-16 要 00 00),剩下的全是图片字节。终止符宽度随编码变化这一点最坑,UTF-16 的描述字符串里夹一个 00 00 早停、或该停不停,封面就错位成噪声。

保存的哲学:只动头部,音频一个字节不碰

🔧 MP3标签编辑 按 v2.3/v2.4 规范逐帧解析以上全部结构——synchsafe、反同步、四种编码、压缩/加密帧的识别与跳过——保存时按 v2.3 规范重建标签:帧长普通 32 位大端、标签总长 synchsafe,文本默认 UTF-8。重建只发生在文件头部:替换标签字节块,音频数据从第一帧起原字节保留,末尾若存在 ID3v1 也原样不动。这就是「改标签无损」的字节级含义——不是听感无损,是音频字节逐一相同。

同样「容器装元数据」的思路在其他格式里也能认出来:MP4 把元数据放进 moov.udta box(参见《MP4 box 结构解剖》),EXIF 住在 JPEG 的 APP1 段。格式在变,思想没变。

改完标签想连封面带信息一起核对一遍,或者把转出来的音频做后期剪辑,这些工具连同降噪、拼接、响度分析,都收在音频创作工具箱专题里,全程本地处理,素材不出浏览器。