Managed DirectX (その 2 AudioVideoPlayback)
~ Cutting Edge DX 9 - 第 3 回目 ~
Hiroyuki Kawanishi (川西 裕幸)
マイクロソフト株式会社
テクニカル エバンジェリスト
March 19, 2003
目次
- AudioVideoPlayer サンプル
- Texture サンプル
今回は、C# から Managed DirectX を使ってビデオを再生する方法を、DirectX 9.0 SDK に入っているサンプルをベースに紹介します。Microsoft.DirectX.AudioVideoPlayback 名前空間にあるクラスは、C# アプリケーションから間単にビデオ再生が扱えることを目的としているので、DirectShow のような細かい操作はできませんし、VMR (Video Mixing Renderer) のような高機能なアクセラレーションも期待できません。しかし、Microsoft.DirectX.AudioVideoPlayback 名前空間の Video クラスを使えば、Play、Pause、Stop といったメソッドを呼び出すだけで、ビデオを再生・操作できます (もちろんビデオ ファイルにオーディオが入っていればオーディオも再生されます)。
また、Microsoft.DirectX.AudioVideoPlayback 名前空間の Video クラスは、テクスチャ サーフェイスにビデオをレンダリングする RenderToTexture メソッドを持っています。このメソッドを使えば、3D ジオメトリにビデオを (動画テクスチャとして) 表示できます。この使い方についても紹介します。
AudioVideoPlayer サンプル
Managed DirectX を使ったビデオの再生は、以下の手順で行います。もちろんその前に、Microsoft.DirectX.AudioVideoPlayback 名前空間の追加やフォームの作成など、C# お決まりの設定が必要です。
- Video クラスのインスタンスを作成する
- ビデオ ファイル (あるいは URL) を開く
- ビデオを表示する親ウィンドウを指定する
- Play メソッドを呼び出す
インスタンス作成時にファイルを指定すれば、1 と 2 を同時に行うこともできます。AudioVideoPlayer サンプルでは、AudioVideoPlayer.cs の OpenFile() でこの処理を行っています。
if (ourVideo == NULL)
{
// まずビデオ ファイルとしてこのファイルをオープンしてみる
ourVideo = new Video(ofdOpen.FileName);
ourVideo.Ending += new System.EventHandler(this.ClipEnded);
ourVideo.Owner = this;
// 再生開始
ourVideo.Play();
}
else
{
ourVideo.Open(ofdOpen.FileName, true);
}
ビデオ クリップが終了したときに頭から再生を繰り返すようにするために、Video クラスのインスタンスを作成した後で Ending イベントをイベントハンドラに追加しています。イベント発生時に呼び出される ClipEnded() では、クリップを頭出しするために Stop メソッドを呼び出してから、再度 Play メソッドを呼び出しています。
private void ClipEnded (object sender, System.EventArgs e)
{
// クリップが終了した、停止し再度再生を開始する
if (outVideo != null)
{
ourVideo.Stop();
ourVideo.Play();
}
...
}
AudioVideoPlayback 名前空間では、ビデオのサイズ変更やフルスクリーンへの切り替えなどのためのプロパティや、シークや一時停止 (ポーズ) 用のメソッドもサポートされています。詳しくは、DirectX 9.0 SDK のドキュメントを参照してください。
Texture サンプル
3D ジオメトリにテクスチャとしてビデオを再生するときは、3D レンダリングと同期を取る TextureRenderEventHandler デリゲートの呼び出しと、ビデオをレンダリングするターゲット デバイス (テクスチャ) の設定が必要です。Texture サンプルでは、texture.cs の RestoreDeviceObjects() でこの処理を行っています。
try
{
videoTexture = Video.FromFile(path);
videoTexture.Ending += new System.EventHandler (this.MovieOver);
videoTexture.TextureReadyToRender += new TextureRenderEventHandler (this.RenderIt);
// テクスチャへのレンダリング開始
videoTexture.RenderToTexture (device);
}
テクスチャ サーフェイスへのビデオのレンダリングと 3D レンダリングとが、同じサーフェイスに同時にアクセスしてはまずいので、TextureReadyToRender メソッドを使って TextureRenderEventHandler デリゲートにイベントを追加し、同期を取っています。3D レンダリングが可能になった時点 (一枚のイメージの書き込みが完了した時点) でイベントが発生し、イベントハンドラが RenderIt () を呼び出します。RenderIt () では、デバイスをロックし、3D レンダリングに使うテクスチャとして設定し、3D のレンダリングを呼び出します。この部分が通常のビデオ再生とは一番違うトリッキーな部分でしょう。
void RenderIt (object sender, TextureRenderEventArgs e)
{
Lock(this)
{
// テクスチャをセットしてレンダリングする
texture = e.Texture;
RenderTexture();
}
}
通常のビデオ再生と同じように、Stop、Pause、Play メソッドが使えます。このサンプルでも、クリップ終了時の頭出しと繰り返しを先のサンプルと同じように、Stop と Play メソッドを使って処理しています。
void MovieOver (object sender, EventArgs e)
{
videoTexture.Stop();
videoTexture.Play();
}
もちろん、テクスチャ サーフェイスをレンダーターゲットとしてデバイスに定義するなどの、3D ではおなじみのテクスチャ サーフェイスを作成する処理が必要です。このサンプルでは、通常のデバイス用の共通処理として C#\Common\D3DApp.cs の InitializeEnvironment() でこの処理が行われています。
AudioVideoPlayback 名前空間には、Audio クラスもサポートされており、バランスやボリュームのプロパティを持っていますが、このクラスは基本的には Video クラスと一緒に使うものとして (つまりビデオ内のオーディオの操作用として) 設計されています。オーディオの再生だけを目的とする場合には、ミキシングやさまざまなエフェクトが可能で低遅延の DirectSound 名前空間のクラスを使ったほうがよいでしょう。