gstreamer 读取 mp3 标记时中文乱码的补丁
Rhythmbox 的用户可能会发现,自己硬盘上的 mp3 有很大一部分其中中文的 tag 被显示为乱码。当然仍然有一小部分是正常的。 对这个问题进行分析后我们发现,问题出在 gstreamer,以及它调用的库 libid3tag 上。
在分析 rhythmbox 显示中文 mp3 标记乱码的问题后,我们意识到这是一个 gstreamer 的问题。gstreamer 向 rhythmbox 提供了与乐曲格式无关的、Unicode 编码的标准化格式的标记信息。
gstreamer-plugins 中的一个插件,mad,负责 mp3 的解码工作。当发现该 mp3 中含有 id3v2 格式的标记信息时,它将调用一个名叫 libid3tag 的库去解析其中的内容。
在最初的 id3 标记信息规范中,没有对存储的字符串的编码作出规定。因此就像绝大多数情况那样,mp3 制作者使用各种形式的“地区编码”,比如 GB2312、Big-5 等,来存储该 mp3 的曲名、歌手等信息,并存储在 iso-8859 字段中。
当 id3v2 规范发布,并规定其中的字符串编码必须是 iso-8859 或者 unicode 时,已经太晚了,满世界的 mp3 都已经在 iso-8859 字段中填写了各类本地编码字符串。换句话说,所谓的 iso-8859 根本就不是它的字面意义,它只是表达说这是一个非 unicode 的字符串而已。
不幸的是 libid3tag 的作者显然并不生活在非西文地区。它忠实地执行了 id3v2 规范的内容:将 iso-8859 字段中的文字精确地按照 iso-8859->unicode 的方式进行转换,并向 gstreamer 提交 unicode 字符串。这样,存储在 iso-8859 字段中的一个中文字符就被编码成了2个 Unicode 字符。对其进行显示的结果,就是乱码。
在此似乎也无法苛责 libid3tag,毕竟它是根据规范而为。因此我选择了对 gstreamer-mad 打补丁,使其正确地按照当前系统所处的 locale,对存储在 iso-8859 字段中的字符串进行 unicode 转换。这样,当你的 locale 为中文时,就能通过 rhythmbox 正确看到中文 mp3 歌曲中的标记信息。
--
When studying the issue "Rhythmbox unable to show Chinese mp3 tags correctly", we learned that it's gstreamer who provided those badly encoded tag strings.
Gstreamer-mad, A plugin of gstreamer, is the decoder of mp3. When meet id3v2 tags, it calls libid3tag to parse them.
The ID3 specification defines two encoding: iso-8859 and unicode. Before this spec published, iso-8859 is the only charset supported by id3 tag. When people need tags in their own, non-latin language, they need a way to embed those non-ASCII characters into the iso-8859 field. They used an extension of ASCII, called "locale depending encoding", to store these characters, while still compatible with ASCII. This solution is cheap, because no modification of data structure or code is needed. It gets so widely used that becomes a Nation Standard in some countries.
Unfortunately, the author of libid3tag do not know about this. It believes all strings stored in iso-8859 field are pure iso-8859-1, and converts them into unicode before submit to gstreamer, and then the malformed string gets passed to rhythmbox, causes wrong displaying.
This locale depending encoding of id3 tags are supported by almost all music players on Windows platform, including WinAmp, RealOne and WMP. In China, all tagged mp3s are in this way by far, and won't change in a vision future. This is not a perfect solution and shouldn't be promoted, I agree, but we still need to be compatible with it.
So I patched gstreamer-mad a little, to recover the wrong strings read from libid3tag, according to the current locale settings, before submitting to the application. The patch is following.

