Metadata Editor をつくる
以前、C# で音楽再生というシリーズで作った音楽プレーヤーでは音楽再生に Bass.Net、WMA や MP3 のタグ情報取得は Windows Media Format Runtime を使用している。
Bass.Net にもタグ情報を読む機能は用意されており、こちらは Ogg Vorbis や FLAC などにも対応しているのだが読み込めるデータが限定されている。一方、Windows Media Format Runtime は豊富なタグ情報をサポートしているかわりに WMA と MP3 (正確には ASF と ID3 タグ) のみ対応。
そこで Bass.Net のように C# から利用できて様々なフォーマットと豊富なタグに対応したライブラリ、いわゆる Metadata Editor を自作してみることにした。少しずつ進めてゆき、折をみてこのブログに成果を公開してゆきたい。
設計方針
はじめに設計方針を立てておく。すべて達成できるかは分からないけれど意識しておきたいものをまとめる。
- なるべく C# のみで実装する
DllImport
やComImport
は避ける- ネイティブなライブラリでも、オープンソースなら C# に移植する
- クロスプラットフォームを目指す
- MonoDevelop でコンパイルできることを目標とする
- WPF などを使わなければ .NET Framework 3.5 程度をサポートしているとのこと
- 現時点で C# 3.0 までなら大丈夫
- 試してみたら System.Core.dll が参照できており、拡張メソッドもサポートされていた
- なるべく多くのタグ情報をサポートする
- フォーマットの用意するものはすべてサポートしたい
- 使用するタグを限定するかどうかは利用側が自由に決められる
- オープンソース
- LGPL で公開する
- 様々なライブラリを参考にすることを考えると LGPL が適切だと思われる
- 今のところはブログで公開してゆく予定
ライブラリ名は Parade.Metadata とする。System.Data.SQLite.dll にならって System.Data.Metadata というのも考えたが、SQLite ぐらい有名・有用なライブラリであっても、System 名前空間を使用することに批判があるので、あるていどユニークで音楽に近い用語をあてることにした。
ASF
手始めにサポートするフォーマットには ASF を選ぶことにした。私がメインで使用しているフォーマットが WMA であることがその理由。Microsoft はしばしばプロプライエタリであることを非難されるが ASF は早々に仕様とライブラリを公開している。開発者にとって非常に恵まれたフォーマットといえるのではないか。
はじめは Windows Media Format Runtime を利用しようと思った。しかし mp3infp という超有名なツールのソースを見たら、これを利用せずとも独自実装でゆけることが分かった。よってこれを参考にしながら実装することにした。独自実装であれば設計方針であげた「なるべく C# のみで実装する」も達成できる。
参考資料
ASF のタグ編集を実装するにあたり参考になりそうな資料をあげておく。
これは Microsoft による公式な ASF ファイルの仕様書である。英語だが内容は平易で読みやすい。とりあえずこれがなくてははじまらない。
Windows Media Format に関する、開発者用の情報ページ。その中でも頻繁に参照する場所をまとめてみた。
最後は mp3infp の公式ページである。Win32 工作部屋といえば WinAmp 日本語パッチが非常に有名でかつて私も利用していたのだが、このツールも有名。有り難いことにソースを公開している。ライセンスは LGPL。
ASF のタグ編集ではこのツールの実装を参考にする。
まずはダンプできるようにする
方針が決まり参考資料も揃ったのでさっそく実装とゆきたいところだが、途中まで実装してみて壁にあたった。ASF のタグ情報はすべて一定のルールに基づいて定義されていると思いこんでいたのだけどタグによって格納方式が異なるのだ。大半のタグは Extended Content Description Object という領域内に格納されている。しかし Title や Author などは Content Description Object、コーデック関連の情報は Codec List Object のように分散している。
Windows Media Format Runtime は WM/Artist
のようなタグ名とデータ型がわかれば、共通のメソッドで読み書きできるように設計されているのだが、同じようなことをおこなう場合は、自前で齟齬を吸収しなければならない。タグ名に対応するデータがどのように格納されるかについては前述の資料にも掲載されていないようで調査が必要。そこでまずは ASF のタグ情報をダンプするツールを作成することにした。
まず Parade.Metadata.dll に以下のようなクラスを定義。ASF ファイルのタグ情報を指定されたファイルにテキストとして出力できるようにする。
/// <summary>
/// ASF のタグ情報をダンプします。
/// </summary>
public class AsfTagDumper
{
/// <summary>
/// AST のタグ情報をダンプします。
/// </summary>
/// <param name="fileName">ASF ファイル。</param>
/// <param name="dumpFileName">ダンプ先となるテキストファイル</param>
public void Dump( string fileName, string dumpFileName )
{
using( var reader = new FileStream( fileName, FileMode.Open, FileAccess.Read, FileShare.Read ) )
{
using( var writer = new StreamWriter( dumpFileName, true, Encoding.Unicode ) )
{
this.Dump( reader, writer );
}
}
}
/// <summary>
/// AST のタグ情報をダンプします。
/// </summary>
/// <param name="reader">ASF のタグ情報を読み取るためのストリーム。</param>
/// <param name="writer">タグ情報を出力するためのストリーム。</param>
private void Dump( Stream reader, StreamWriter writer )
{
}
/// <summary>
/// Codec List Object の内容をダンプします。
/// </summary>
/// <param name="reader">ASF のタグ情報を読み取るためのストリーム。</param>
/// <param name="writer">タグ情報を出力するためのストリーム。</param>
private void DumpCodecListObject( Stream reader, StreamWriter writer )
{
}
/// <summary>
/// Content Description Object の内容をダンプします。
/// </summary>
/// <param name="reader">ASF のタグ情報を読み取るためのストリーム。</param>
/// <param name="writer">タグ情報を出力するためのストリーム。</param>
private void DumpContentDescriptionObject( Stream reader, StreamWriter writer )
{
}
/// <summary>
/// Extended Content Description Object の内容をダンプします。
/// </summary>
/// <param name="reader">ASF のタグ情報を読み取るためのストリーム。</param>
/// <param name="writer">タグ情報を出力するためのストリーム。</param>
private void DumpExtendedContentDescriptionObject( Stream reader, StreamWriter writer )
{
}
/// <summary>
/// File Properties Object の内容をダンプします。
/// </summary>
/// <param name="reader">ASF のタグ情報を読み取るためのストリーム。</param>
/// <param name="writer">タグ情報を出力するためのストリーム。</param>
private void DumpFilePropertiesObject( Stream reader, StreamWriter writer )
{
}
/// <summary>
/// Header Extension Object の内容をダンプします。
/// </summary>
/// <param name="reader">ASF のタグ情報を読み取るためのストリーム。</param>
/// <param name="writer">タグ情報を出力するためのストリーム。</param>
private void DumpHeaderExtensionObject( Stream reader, StreamWriter writer )
{
}
/// <summary>
/// Stream Properties Object の内容をダンプします。
/// </summary>
/// <param name="reader">ASF のタグ情報を読み取るためのストリーム。</param>
/// <param name="writer">タグ情報を出力するためのストリーム。</param>
private void DumpStreamPropertiesObject( Stream reader, StreamWriter writer )
{
}
}
Parade.Metadata.dll は以下のように使用する。
/// <summary>
/// プログラムのエントリポイントです。
/// </summary>
/// <param name="args">コマンドライン引数。</param>
static void Main( string[] args )
{
try
{
string dumpFileName;
{
var dir = Path.GetDirectoryName( Assembly.GetEntryAssembly().Location );
dumpFileName = dir + "\\dump.txt";
}
// 前回、出力されてたテキストがあれば削除する
if( File.Exists( dumpFileName ) && args.Length > 0 )
{
File.Delete( dumpFileName );
}
// 引数指定された ASF ファイルのタグ情報をまとめて出力
for( int i = 0; i < args.Length; ++i )
{
var dumper = new AsfTagDumper();
dumper.Dump( args[ i ], dumpFileName );
}
}
catch( Exception e )
{
Debug.WriteLine( e );
}
}
今回はここまで。このダンプ機能を利用してタグのデータ領域を調査しつつ、次回は Metadata Editor の作成に着手したい。
今回の成果物
今回の成果物を以下に公開する。
プロジェクトは Visual C# 2010 Express で作成。現時点の機能としては ASF ファイルのデータをダンプできる。ビルドすると Parade.Metadata.dll と TestApp.exe というコンソール アプリケーションが生成される。
コンソール アプリに ASF ファイル (WMA、WMV など) をドロップすると TSV (タブ文字区切り、文字コードは UTF-16LE) 形式のテキストとして ASF タグ情報が出力される。Excel を所有しているならテキストの内容をコピーしてシートへ貼り付けることにより見やすくなる。
Windows Vista などではサンプル ミュージックやサンプル ビデオとして WMA、WMV ファイルがプレインストールされている。動きをみるならばこれらを読み込ませてみるのが手っ取り早い。
Comments from WordPress
- Posaune 2010-07-04T13:34:00Z
おお!私も以前、AACのメタデータエディタを作ろうと思ってたんですが、タグフォーマットが独特でさっくり作れず、ちょっと挫折中です。
http://d.hatena.ne.jp/posaunehm/20091212/1260628232
C++での実装コードは公開されてるのでそれを読み解けばいけるはずなんですが(汗
- akabeko 2010-07-04T23:31:11Z
AAC は厄介ですね。正式なタグ仕様が非公開なので、誰かのハック頼りというところが困りものです。
ただ、このシリーズで作ろうとしている Metadata Editor では AAC もサポートしたいので、何とかものにしたいと思います。Posaune さんのブログ記事で紹介されている、MPEG-4 のタグをパースするツールは参考になりそうです。
情報提供、ありがとうございます。