Mac::iPod::GNUpod の m4a ファイルサポート
Mac::iPod::GNUpod という Perl で iPod に曲を転送したり、取得したりする便利な module があるんだけど、こいつはどうも wav と mp3 にしか対応していないらしい。最近 AAC でばっかりエンコーディングしてるので m4a にも対応して欲しいところだ。
コードを見てみると対応予定なのかなんなのか、Mac::iPod::GNUpod::Utils::mp4_info というのはあるんだけど、何も書いてないし、呼び出されもしない。
m4a というか、MP4 を扱う Perl module は MP4::Info として CPAN に上がっているのでこいつを使って mp4_info を書いてみる。
--- Utils.pm.org Wed Apr 5 00:08:02 2006 +++ Utils.pm Wed Apr 5 00:12:34 2006 @@ -13,6 +13,7 @@ use Unicode::String; use File::Spec; use MP3::Info qw(:all); +use MP4::Info; use Audio::Wav; @ISA = qw/Exporter/; @@ -24,6 +25,7 @@ BEGIN { MP3::Info::use_winamp_genres(); MP3::Info::use_mp3_utf8(0); + MP4::Info::use_mp4_utf8(0); } # Reformat shx numbers @@ -111,11 +113,9 @@ elsif ($file =~ m/\.wav$/) { $h = wav_info($file); } -=rem Currently unimplemented - else if ($file =~ m/\.(mp4|m4a)$/) { + elsif ($file =~ m/\.(mp4|m4a)$/) { $h = mp4_info($file); } -=cut # Unrecognized file types else { @@ -218,6 +218,54 @@ # This will be filled out someday sub mp4_info { + my $file = shift; + + my $h = MP4::Info::get_mp4info($file); + return unless $h; #Not an mp3 + + #This is our default fallback: + #If we didn't find a title, we'll use the + #Filename.. why? because you are not able + #to play the file without a filename ;) + my $cf = (File::Spec->splitpath($file))[-1]; + + my %rh = (); + + $rh{bitrate} = $h->{BITRATE}; + $rh{filesize} = $h->{SIZE}; + $rh{srate} = int($h->{FREQUENCY}*1000); + $rh{time} = int($h->{SECS}*1000); + $rh{fdesc} = $h->{TOO}; + + $h = MP4::Info::get_mp4tag($file,1); #Get the IDv1 tag + my $hs = MP4::Info::get_mp4tag($file, 2, 2); #Get the IDv2 tag + # If any of these are array refs (multiple values), take last value + for (keys %$hs) { + if (ref($hs->{$_}) eq 'ARRAY') { + $hs->{$_} = $hs->{$_}->[-1]; + } + } + + #IDv2 is stronger than IDv1.. + #Try to parse things like 01/01 + no warnings 'uninitialized'; + no warnings 'numeric'; + my @songa = parseslashes($hs->{TRCK} || $h->{TRACKNUM}); + my @cda = parseslashes($hs->{TPOS}); + $rh{songs} = int($songa[1]); + $rh{songnum} = int($songa[0]); + $rh{cdnum} = int($cda[0]); + $rh{cds} = int($cda[1]); + $rh{year} = $hs->{TYER} || $h->{YEAR} || 0; + $rh{title} = $hs->{TIT2} || $h->{TITLE} || $cf || "Untitled"; + $rh{album} = $hs->{TALB} || $h->{ALBUM} || "Unknown Album"; + $rh{artist} = $hs->{TPE1} || $h->{ARTIST} || "Unknown Artist"; + $rh{genre} = $h->{GENRE} || ""; + $rh{comment} = $hs->{COMM} || $h->{COMMENT}|| ""; + $rh{composer} = $hs->{TCOM} || ""; + $rh{playcount}= int($hs->{PCNT}) || 0; + + return \%rh; }
コメントアウトされている箇所に else if とか罠が書いてあったりもしたけど、まあ問題なく書けた。
MP4::Info は MP3::Info と同じ method を提供してるのと、method が返す値もまあ似ているので、mp4_info は mp3_info をほとんどコピペでオッケーなので簡単なんだけどね。
使ってみたけど問題なく m4a ファイルを転送できた。(日本語まわりが若干自信ないけど)ふむ。どうしようかな。
追記
なにげにこのパッチを author に送ったら apply してくれるとのこと。どうもこの module を作ったときには MP4::Info がなかったとか何とか。みんな幸せになれることはいいことだな。
2006-04-28 追記
Mac::iPod::GNUpod-1.22 パッチ追加された!!!。