2008年3月21日金曜日

iTunes対応のUTF-16LE ID3v2タグを付加する

PerlスクリプトからMP3ファイルにID3タグを付けようとしてハマる。


MP3::Tag を使い iTunes で読めるようなID3タグを付けたかったのだが、何パターンか試したもののうまくいかなかった。原因がわからないので iTunes が生成した ID3 タグを MP3::Tag の出力結果と比べ、同じような結果が得られるようなコードを書いたのだがそれでもなお、うまくいかない。


寝たり他ごとしたりしつつ 12 時間ぐらいたってしまったが、解決しないので、 ID3v2 フォーマットの仕様書を見てみた。


ID3 tag version 2.4.0 - Main Frames の 4. ID3v2 frame overview には、以下の通り記述がある。


   Frames that allow different types of text encoding contains a text
   encoding description byte. Possible encodings:

     $00   ISO-8859-1 [ISO-8859-1]. Terminated with $00.
     $01   UTF-16 [UTF-16] encoded Unicode [UNICODE] with BOM. All
           strings in the same frame SHALL have the same byteorder.
           Terminated with $00 00.
     $02   UTF-16BE [UTF-16] encoded Unicode [UNICODE] without BOM.
           Terminated with $00 00.
     $03   UTF-8 [UTF-8] encoded Unicode [UNICODE]. Terminated with $00.

   Strings dependent on encoding are represented in frame descriptions
   as , or  if newlines are allowed. Any empty strings of
   type $01 which are NULL-terminated may have the Unicode BOM followed
   by a Unicode NULL ($FF FE 00 00 or $FE FF 00 00).


つまり iTunes 互換の UTF-16 Little Endian でエンコードする場合は


  • BOM (リトルエンディアンの場合は 0xFF 0xFE) ではじまり、 0x00 0x00 で終わること


  • encoding description byte が 1 であること


上記 2 点を満たす必要があるようだ。これを MP3::Tag で素直に書くと


use MP3::Tag;
use Encode qw/encode/;
(省略)
$id3v2->add_frame("TPE1",
1, #encoding description byte
sprintf("\xFF\xFE%s\x00\x00", encode('UTF-16LE', '初音ミク'));


という感じになるのだが、手元のマシンにインストールされていた sarge の MP3::Tag 0.40 だと ID3v2.pm に以下の Encoding=0 を強制するコードがあって encoding=1 を受け入れてくれない。まったく余計なことしてくれる。


MP3/Tag/ID3v2.pm
    450         if ($fs->{name} eq "_encoding") {
    451             $encoding = shift @data unless $defenc;
    452             warn "Encoding of text not supported yet\n" if $encoding;
    453             $encoding = 0; # other values are not used yet, so let's not
         write them in a tag
    454             $datastring .= chr($encoding);
    455             next;
    456         }


仕方ないので 453 行目をコメントアウトしてしまい、とりあえず目的は達成できるようになった。だるー。さっさとソースや仕様にあたれってことですかね...


0 件のコメント:

コメントを投稿