2003年08月12日
川俣晶の縁側ソフトウェア技術雑記 total 7339 count

Windows MediaエンコーダをC#から呼び出すプログラミングのドタバタ記録

Written By: 川俣 晶連絡先

 今日は、VAIOのGipaPocket(外部キャビネット)のMPEGファイルをWindows Media形式に自動変換する変換するプログラムなんていうのを作ってしまいました。もちろん、エンコーダはマイクロソフトが提供するものを使っていますから、それを呼び出す側のプログラムを書いたということでしかありませんが。その顛末を書きましょう。

 そもそも、なぜ動画ファイルなどに手を出すことになったのか。

 その発端は、と~のちゃんが使っているVAIOで録画したデータの保管問題にありました。と~のちゃんは、地上波VHFで放送されるアニメをウォッチする立場で、相当数のアニメを録画しています。そのすべてを見ることはできず、一通り、ほとんどすべてを保存しています。と書くと、とんでもない量のメディアが積まれている状況が想像されるかもしれませんが、実際にはそれほどではありません。録画したデータは、VideoCD互換のMPEG1のファイルでしかなく、さほどデータ量は大きくありません。もちろん、画質もよくありませんが、このあたりが妥協のしどころです。

 しかし、その妥協したVideoCD互換のMPEG1のファイルですら、結構な負担になって来ました。昨日の時点で、データ保存用の外付け250GB IEEE-1394/USBドライブの残りが僅かになってきて、新しいHDDを買うか、それとも保存を止めるか、ということを真剣に考える事態になったのです。250GBのHDDなら、さほどスペースも取らずにかなりの量の番組を保存できますが、ともかく値段が高いのです。現在のと~のちゃんのペースなら、年間4台の250GBドライブを必要としますが、さすがにこれは常識的に出せない価格になります。

 「じゃあ、もう保存しておくのはやめようか」「うん」という感じで、一時は保存取りやめという方向に傾いたのですが。

 そこでふと気づきました。

 今となっては、MPEG1はけして効率の良い圧縮フォーマットではありません。

 他にももっと良いものがいろいろあります。

 手始めとして、すぐに試せそうなWindows Mediaで実験してみることにしました。ちょっと検索すると、Windows Media エンコーダというソフトがあることが分かったので、さっそくマイクロソフトのサイトから落としてインストール。そして、と~のちゃんの録画データから適当なMPEG1ファイルをエンコーダに掛けてみました。設定は、かなり低いグレードに設定してみました。(中品質ビデオVBR75+中品質オーディオVBR50)

 その結果……。

 最初の感想は「遅い!」ということでした。30分の番組に50分ぐらい掛かっていました。

 次に、驚いたことは、「小さい!」ということでした。なんと、約1/5というコンパクトなサイズになりました。

 更に、意外にも画質があまり落ちてないことに驚きました。確かに、画質音質の低下は見られます。しかし、何が放送されていたか確認する程度なら、これで十分です。

 この画質で、ファイルサイズが1/5!

 そのことに思わず燃えてしまいました。

 こんなことが実現可能なのに使わないのは、あまりにもったいなさすぎる!

 というわけで、さっそく自動的に多数のVAIOのMPEGファイルをエンコードするシステムが組めないか、調査を始めました。最初は、コマンドラインでエンコードが開始できれば、バッチが組めるかな、という程度の気持ちでした。しかし、Windows Media エンコーダのコマンドラインインターフェースは、WSHのVBSで実現されていることが分かって考えが変わりました。コマンドラインといっても、要するに、VBS経由でCOMを叩いているだけです。なら、C#でCOMを叩いても同じだろう、と思ってしまったのです。

 MSDN Libraryなどにも資料が豊富にあるので(英語ですが)、詳しいことはここでは書きません。Visual Studio 2003で、Windows Media エンコーダのCOMオブジェクトを参照してラッパを作成させて、それを経由して使うだけでOKです。サンプルソースもけっこうあります。今や、こういうメディアものを扱うプログラミングでも、C#でまったくOKな時代なのですね。

 これにより、VAIOが生成する4つのファイル(拡張子、mpg, sdb, ssc, scx)のうちmpgをwmvに、sdbを必要な情報だけ抜き出してXML文書に、残りの2つはただ単に削除して消滅させることが、指定ディレクトリ下の多数のファイルに対して一気に実現可能になりました。(ちなみに、sdbからXML文書にするクラスはすでに書いたものがありました)

 この間の最大の問題は、mpgファイルの削除がなぜかプログラム終了まで遅延されてしまうという現象でした。より小さなファイルを生成しつつ古い大きなファイルを削除して進行するシナリオを実現したかったので、削除タイミングが遅くなるのは問題でした。ぎりぎりの容量のHDDで実行した場合、削除が遅れれば、収まるはずのファイルが収まらない可能性が出てきてしまうのです。

 しかし、削除が遅延されるという動作は謎でした。エンコード終了後にFile.Deleteを呼んで問題なく動いているのに、実際に削除されるタイミングは遅延されてしまうのです。おそらく、エンコーダが完全にファイルを使い終わって閉じていないため、削除が遅延されているのだという推理を立てて、エンコード終了後にいろいろなコードを入れてみました。とりあえず、以下のようなものを入れてみました。

 Encoder.Flush();

 Encoder.Stop();

 Encoder.Reset();

 System.GC.Collect();

 その結果、意図通りにすぐにmpgファイルが消えてくれるようになりました。System.GC.Collect();は呼ばなくてもOKのようなので、これはコメントアウトしてありますが、残りは一応残してあります。時間がなかったので、この中のどれが本当に必要だったのかまでは絞り込めていません。

 さて、プログラムは完成しました。

 さっそく試してみようかと思ったのですが、そこではたと思いました。

 エンコードするのに、再生時間の約2倍の時間が掛かります。30分の番組は約330MBの容量があります。すると、1GBあたり、約1時間半の番組に相当し、エンコードに約3時間を要する計算になります。画像で満杯の250GBのHDDを処理するとすると、250*3時間=750時間。これを24で割って日数に換算すると、約31日です。

 うっかり実行開始させると、31日間止めることができないとは、あまりに過酷すぎます。特に、この猛暑の季節に、24時間ノンストップで31日間動かし続けるのは、非常識すぎるとすら言えます。そもそもパソコンは他の用途にも使うものですし。エンコードだけに使うわけには行かないのです。

 というわけで、新たな障害が生まれたところで、続編へ続きます。(はたして続編はあるでしょうか?)

続編はありました。

続編はこちら: https://mag.autumn.org/Content.aspx?id=20030813231658