デジタル メディア
WPF を使ってコントロールと 3D の表面にビデオを追加する
Lee Brimelow
この記事の内容 : :
- Windows Presentation Foundation のデジタル メディアの基礎
- MediaElement と MediaPlayer を使用する
- WPF コントロールに埋め込まれたビデオ
- ビデオを 3D の表面にマップする
|
この記事は次のテクノロジを使用しています:
.NET Framework 3.0
|

コンテンツ
Windows Presentation Foundation (WPF) を取り巻く騒ぎが Adobe Flash コミュニティ全体に広がり始めたとき、私の最初の反応は懐疑的なものでした。マイクロソフトは、私を含む多くの Flash 開発者最愛のプラットフォームをサポートする企業に難癖をつける競合テクノロジを導入したと考えたのです。その後、Windows® Presentation Foundation のデモを行うためにサンフランシスコの frog design のスタジオにテクニカル エバンジェリストを派遣したという電子メール メッセージをマイクロソフトから受け取ったので、Flash があらゆる点で最高のものである理由を全員に示す絶好のチャンスだと考えました。
Karsten Januszewski はプレゼンテーションの途中で、今では有名になった North Face デモ (
channel9.msdn.com/Showpost.aspx?postid=116327 (英語)) を披露しました。このデモでは、高品質の Windows Media
® Video (WMV) クリップにマップされた曲線の 3D メッシュ オブジェクトに 3D のカルーセルが描かれています。このデモは、サンフランシスコにあるインタラクティブ スタジオ Fluid と Microsoft Windows Presentation Foundation チームのメンバとの共同で作成されました。私は現実に直面して先入観を捨てることにしました。はっきり言うと、Flash などのプラットフォームでこの種のプレゼンテーションを実現するのは困難または不可能です。
このセッションから間もなく、私は自尊心を抑えて Microsoft
® .NET Framework 3.0 ランタイムをダウンロードしました。そして、Windows Presentation Foundation インタラクティブ デザイナとしての私のキャリアが始まりました。その時以来、Flash と Windows Presentation Foundation の 2 つのテクノロジの中で実際に競合する分野はそれほど多くはないということから、両者を対比して行う論争はまったくなくなりました。マイクロソフトが、グラフィック、ビデオ、アニメーション、オーディオなどを含む、クロスプラットフォーム Web ページの配信に関する最新のソリューションをリリースすると、再び論争が巻き起こるかもしれません。このリリース予定のソリューションはコードネームを "WPF/E" といい、"WPF/E" デベロッパー センター (
msdn2.microsoft.com/bb187358.aspx (英語)) からプレビューを入手できます。
ビデオを 3D の表面にマップする機能は、主に、インタラクティブ デザイナの注意を引きつけるために必要なアイ キャンディを提供していました。しかし、この機能はオーディオとビデオを Windows Presentation Foundation に統合した場合に可能になることのほんの一部にすぎません。この記事では、Windows Presentation Foundation のメディア統合を十分理解できるようにし、独自のアプリケーションにメディア ファイルを追加するために必要な知識を提供します。また、オプションで独自のアプリケーションが人目を引く外観を備えるようにするために必要な知識についても説明します。
技術概要
現在、Win32® アプリケーションにデジタル メディア ファイルを追加する場合に最も一般的に使われるのは、DirectShow® API を使用する方法と、Windows Media Player ActiveX® コントロールを埋め込む方法の 2 つです。DirectShow を使用すると開発者がメディア統合を完全に制御できますが、Windows Media Player ActiveX コントロールを単純に埋め込むよりもはるかに複雑になります。
Windows Presentation Foundation アプリケーションでメディアの表示や管理をきめ細かく制御する必要がある場合、DirectShow を使用することは依然として実行可能な選択肢の 1 つです。また、既存の Win32 アプリケーションを Windows Presentation Foundation と .NET Framework 3.0 に移植する際に、Windows Presentation Foundation アプリケーションに DirectShow を埋め込むこともできます。
Windows Media Player ActiveX コントロールを使用してメディアを再生することは Windows Presentation Foundation でも選択肢の 1 つですが、新しい MediaElement コントロールを使用する方がはるかに妥当です。一見すると両者は基本的に同じことを行えるように思えますが、後者は Windows Presentation Foundation に適切に統合されます。具体的には、アルファブレンディングでメディアを合成でき、3D の表面にレンダリングすることもできます。
オーディオとビデオが Windows Presentation Foundation に統合されることにより、選択可能な複数のオプションが開発者に提供されます。それぞれのオプションには複雑さとメディア ファイルの制御に関して固有のレベルがあります。使用するコントロールやクラスとは関係なく、背後で行われていることはほぼ同じです。一般的な考え方として、アプリケーションが Windows Presentation Foundation でメディア ファイルを再生するという場合は、ファイルを再生するために、バックグラウンドで Windows Media Player ランタイムを起動することになります。Windows Presentation Foundation が Windows Media Player を使用し、独自のメディア レンダリング エンジンを備えていないことにはいくつか利点と欠点があります。Windows Media Player に便乗することは、ActiveX コントロールを使用することに似た点があります。
Windows Media Player が Windows Presentation Foundation メディアの再生を担当するので、Windows Presentation Foundation と互換性のあるメディア形式を説明するのは簡単です。基本的には、既にインストールされている Windows Media Player を使ってエンド ユーザーが再生できるすべての形式が、Windows Presentation Foundation アプリケーションで使用できます。新たなメディアの種類に対するサポートを追加するためには、ユーザーは新たなビデオ コーデックをインストールする必要があります。
メディア ファイルを再生する場合、Windows Media Player ランタイムを起動する必要があるため、メディアを最初に再生するときに、バックグラウンドでランタイムが読み込まれる間遅延が生じることに注意してください。その結果、特に Windows Presentation Foundation でオーディオやビデオとアニメーションなどのイベントとの同期を取ろうとする場合、メディアを正確に制御することが困難になる可能性があります。この状況を回避する 1 つの方法は、メディア ファイルを事前に読み込み、使用準備が整うまで一時停止状態にしておくことです。もう 1 つの選択肢として、アニメーション エンジンのスリップを使用して、他のアニメーションを MediaElement に依存させることができます。そうすれば、少なくともすべてに均等に遅延が生じます。これは最適なワークフローではありません。そのため、Windows Presentation Foundation メディア チームは次のバージョンでの解決に向けて取り組んでいます。さいわい、オーディオを再生する場合には代替手段として System.Media.SoundPlayer クラスがあります。このクラスでは、Windows Media Player を必要としないで WAV ファイルを単純に再生できます。この記事の後半で、このクラスの使い方を見てみることにしましょう。
MediaElement コントロールを使用する
新しい MediaElement コントロールを使用すると、実に簡単にメディアを Windows Presentation Foundation アプリケーションに追加できます。このコントロールは、Windows Presentation Foundation の他のすべてのコントロールと同様に、XAML を使って、または C# や Visual Basic® を使用する分離コード ファイルを使って追加できます。MediaElement では、メディア ファイルの基本的な再生や制御が可能で、Independent モードまたは Clock モードのいずれかで実行できます。
Independent モードが既定のモードで、従来の Media Player に最も近い形式で機能します。
<MediaElement Source="myMedia.wmv" Width="320"
Height="240" LoadedBehavior="Manual" />
Source プロパティに、メディア ファイルの URI を設定します。メディア ファイルが読み込まれるときの動作は、LoadedBehavior プロパティによって決まります。このプロパティには、MediaState 列挙値の値を設定する必要があります。列挙値の値は、Close、Manual、Pause、Play、または Stop です。MediaElement コントロールの Play、Pause、または Stop の各メソッドを使用してメディアの再生を制御するためには、LoadedBehavior プロパティに Manual を設定する必要があります。
図 1 に、Independent モードで実行されている MediaElement コントロールを使用する簡単な Media Player の例を示します。図 2 には、このコントロールの実装に使用する XAML と C# コードを示します。

Figure 2 MediaElement コントロールを実装する
XAML
XAML
<Window x:Class="VideoProject.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="VideoProject" Height="800" Width="600">
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<MediaElement Name="myMedia" Source="myMedia.wmv"
LoadedBehavior="Manual" Width="320" Height="240" />
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<Button Content="Play" Margin="0,0,10,0"
Padding="5" Click="mediaPlay" />
<Button Content="Pause" Margin="0,0,10,0"
Padding="5" Click="mediaPause" />
<Button x:Name="muteButt" Content="Mute"
Padding="5" Click="mediaMute" />
</StackPanel>
</StackPanel>
</Grid>
</Window>
C#
C#
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace VideoProject
{
public partial class Window1 : System.Windows.Window
{
public Window1()
{
InitializeComponent();
myMedia.Volume = 100;
myMedia.Play();
}
void mediaPlay(Object sender, EventArgs e)
{
myMedia.Play();
}
void mediaPause(Object sender, EventArgs e)
{
myMedia.Pause();
}
void mediaMute(Object sender, EventArgs e)
{
if (myMedia.Volume == 100)
{
myMedia.Volume = 0;
muteButt.Content = "Listen";
}
else
{
myMedia.Volume = 100;
muteButt.Content = "Mute";
}
}
}
}
図 1 簡単な MediaElement コントロール
Clock モードで MediaElement コントロールを実行すると、堅牢な Windows Presentation Foundation アニメーション エンジンを使用してメディアの再生を制御できます。Clock モードを有効にするには、MediaTimeline の一部として MediaElement を対象に指定するか、MediaTimeline から MediaClock を明示的に作成し、それを MediaElement に割り当てます (ただし、後者の方法はお勧めしません)。これには少し混乱するかもしれませんが、基本的には MediaElement を Storyboard にアタッチし、Windows Presentation Foundation アニメーション エンジンを使用して、コントロールの位置をアニメーションで動かすことを意味しているだけです。その結果、アプリケーション内でメディアの再生と他のアプリケーションを同期させることができます。
以下に、Storyboard を使用して、Clock モードでメディアを再生するのに必要な XAML コードの例を示します。
<MediaElement Name="myMedia" Width="320" Height="240" />
<Grid.Triggers>
<EventTrigger RoutedEvent="Grid.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard Storyboard.TargetName="myMedia">
<MediaTimeline Source="myMedia.wmv"
BeginTime="00:00:00" Duration="00:05:00" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Grid.Triggers>
メディア ファイルの Source は、MediaElement ではなく、MediaTimeline で設定していることに注意してください。MediaTimeline では、Storyboard.TargetName 添付プロパティ経由で MediaElement コントロールを対象に指定します。Windows Presentation Foundation のアニメーション エンジンに馴染みがないと、Clock モードに困惑する可能性があるので、Windows Presentation Foundation の基本的なアニメーションに慣れてから、このモードを使用してください。
MediaElement を設定し、そのモードを構成したら、メディア再生のエクスペリエンスを強化するために、多くのプロパティを読み取ったり、書き込んだりすることができます。メディア ファイルの位置を取得または設定するには、Position プロパティに有効な TimeSpan オブジェクトを設定するだけです。BufferingProgress プロパティや DownloadProgress プロパティを読み取ることによって、バッファリングや再生の進行状況をユーザーに表示できます。オーディオ コントロールの場合は、Balance プロパティや Volume プロパティを設定することで、メディアのオーディオ トラックをカスタマイズまたは動作させることができます。では、これらの値を 2 つのスライダにデータバインドした場合を考えてください。そうすれば、ユーザーはメディアの音量を完全に制御できるようになります。
MediaElement は、多くの有益なイベントも発生します。メディアが開始されたか終了されたかを基にアプリケーションの他の部分をトリガする場合、MediaOpened イベントと MediaEnded イベントが便利です。バッファリング中にビデオが停止してしまうときにユーザーに状況を知らせるには、BufferingStarted イベントと BufferingEnded イベントを使用できます。これらのイベントを BufferingProgress プロパティと連携して使用すると、Windows Media Player でストリーミング ビデオを表示している場合と同様に、バッファリングのパーセンテージをユーザーに表示できます。
私の実体験に基づくと (Windows Presentation Foundation メディア チームとの対話の中でさらに強く感じましたが)、Clock モードが決定的に必要な場合を除いて、通常、Independent モードで MediaElement コントロールを使用することをお勧めします。標準のメディアを再生および制御する場合、Storyboard や MediaTimeline を扱う必要はありません。XAML を使用して MediaElement を追加する機能により、デザイナは他の作業をまったく行わずにメディアを実装できるようになるので、メディア統合では既定で MediaElement を選択してください。
MediaPlayer クラスを使用する
MediaElement コントロールが十分な機能を提供せず、作成中のアプリケーション向けに再生を十分制御できない場合、考慮すべき次の選択肢は System.Windows.Media 名前空間にある MediaPlayer クラスを使用することです。これは Windows Presentation Foundation のコントロール要素ではないので、MediaPlayer を実装する場合、C# または Visual Basic を使用する分離コードファイルで MediaPlayer を作成するのが唯一の方法です。以下に、C# を使用して MediaPlayer を実装する方法を示す簡単な例を紹介します。
MediaPlayer mp = new MediaPlayer();
Try {
mp.Open(new Uri("myMedia.wmv"));
}
catch(Exception ex) {
MessageBox.Show(ex.Message);
}
MediaPlayer クラスで使用できるプロパティとメソッドは、MediaElement コントロールのプロパティとメソッドとまったく同様です。これは偶然の一致ではありません。MediaElement は、基本的には MediaPlayer クラスの高度なラッパーです。MediaPlayer を使用する場合に主に注意する点は、MediaPlayer には直接的なビジュアル表現がなく、MediaPlayer をビジュアル ツリーに直接追加できないことです。ビデオを再生するには、表示面に MediaPlayer を描画後、その表示面をビジュアル ツリーに追加する必要があります。オーディオを再生する場合、明らかにビジュアル表現は不要なので、MediaPlayer が適切な選択肢になります。ビデオをそのまま再生する場合は、UIElement クラスから継承されており、アプリケーションのビジュアル ツリーに直接追加できる点から、MediaElement コントロールがはるかに優れた選択肢になります。
MediaElement コントロールとまったく同様に、MediaPlayer のインスタンスを Independent モードと Clock モードのいずれかで実行できます。コントロールの再生に関しては、基本的には MediaElement コントロールとまったく同様です。では、MediaPlayer にはどのような違いがあるのでしょう。1 つは LoadedBehavior プロパティと UnloadedBehavior プロパティを扱えないことです。これらは MediaElement コントロール固有のプロパティです。VideoDrawing クラスを使用して 3D の表面にメディアを描画することを計画している場合は、VideoDrawing の Player プロパティは値として MediaElement コントロールを受け取らないので、MediaPlayer を使用する必要があります (ご心配なく。この後すぐに、3D などの表面にビデオを描画する方法を示します)。
もう 1 つの利点 (状況によっては欠点にもなります) は、MediaPlayer は XAML を使って実装されないので、ビジュアル ツリーの一部にならないことです。メディア ファイルでビジュアル表現が必要でなければ、ビジュアル ツリーの一部にならないことが有益である場合があります。また、アプリケーションにメディア ファイルを読み込む方法にもやや違いがあります。MediaElement コントロールでは Source プロパティを設定しますが、MediaPlayer クラスを使用するときは、有効な Uri オブジェクトを渡して、Open メソッドを呼び出します。
したがって、アプリケーションで XAML を使用してメディア ファイルを実装する必要がない場合、またはアプリケーションに自動的なビジュアル表現が備わっている場合、オーバーヘッドが追加される恐れなしに、MediaElement コントロールのすべての機能を使えるため、おそらく Media Player が最適な選択肢になります。
WPF コントロールの内部にビデオを埋め込む
MediaElement コントロールは System.Windows.UIElement クラスから継承されているので、他の UIElement コントロールを配置できるところであればどこでも配置できます。一例として、MediaElement コントロールを Button コントロールの内部に入れ子にして、ビデオ ボタンを作成します。これは、以下の XAML コードを使用して実現できます。
<Button Name="myVideoButton" Click="playVideo"
Width="320" Height="240">
<MediaElement Name="myVid" Source="myMedia.wmv"
LoadedBehavior="Manual" Width="320"
Height="240" />
</Button>
このコードでは、Button コントロールの内部に MediaElement コントロールを埋め込み、LoadedBehavior プロパティを Manual に設定しています。Button の Click イベントでは、MediaElement に再生を指示するメソッド (ここでは示していません) を呼び出します。ほんの数行のコードで、インタラクティブ ビデオ サムネイルを作成しました。Windows Presentation Foundation では MediaElement コントロールがビジュアル ツリー内の他の任意の UI 要素とまったく同様に扱われる点から、あらゆる種類の創造的可能性が広がります。次のセクションで説明するように、MediaElement で再生されるビデオを他の Windows Presentation Foundation オブジェクト上に描画して、信じられないほど充実したユーザー エクスペリエンスを生み出すことができます。
ウエット フロア (Wet Floor) 技法
最近、鏡と反射の効果を使ったインターフェイスが広まっているのが目に付きます。間違いなく、Windows Presentation Foundation でこうした技法の提供を求められる日が来るでしょう。さいわい、これは容易に実現できます。Windows Presentation Foundation に用意された広範なブラシ システムを使用すると、あるコントロールを別のコントロール上に容易に描画できます。この例では、MediaElement コントロールで再生されているビデオを VisualBrush を使用して Rectangle 上に描画し、ビデオの完全な反射像を生み出しています。デザインの世界では、これをウエット フロア (Wet Floor) 効果と呼びます。
ウエット フロア効果を作り出す最も簡単な方法は、StackPanel コントロールの最初のスロットに MediaElement コントロールを配置することです。次に、その下にビデオと同じサイズで Rectangle を作成します。続いて、VisualBrush を使用して Rectangle を塗りつぶし、Rectangle の Visual プロパティを MediaElement コントロールにデータバインドします。最後に、映像を反転して鏡像を作成し、映像が徐々に消えるように OpacityMask を適用します。
図 3 に完成した効果を、図 4 に XAML コードを示します。従来の Win32 プログラミングでは、この種の表示操作は極めて困難でした。Windows Presentation Foundation の優れたデータバインド機能のおかげで、この種の操作がビデオの更新に同期して自動的に更新されるライブ映像になります。

Figure 4 ウエット フロア効果を生み出すために使用する XAML
<Grid x:Name="myGrid">
<StackPanel VerticalAlignment="Center">
<MediaElement Name="myVid" Source="myMedia.wmv"
LoadedBehavior="Play" Width="320" Height="240" />
<Rectangle Width="320" Height="240">
<Rectangle.Fill>
<VisualBrush Visual="{Binding ElementName=myVid}" />
</Rectangle.Fill>
<Rectangle.OpacityMask>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Color="#AA000000" Offset="1" />
<GradientStop Color="#00000000" Offset="0" />
</LinearGradientBrush>
</Rectangle.OpacityMask>
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleY="-1" />
<TranslateTransform Y="242" />
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
</StackPanel>
</Grid>
図 3 完成したウエット フロア
ビデオを 3D の表面にマップする
Windows Presentation Foundation に関して最大の騒ぎを引き起こしたと考えられる分野を 1 つ挙げるとすれば、ビデオ ファイルを 3D メッシュ オブジェクトにマップする機能になるでしょう。North Face デモでは、視覚的に驚くほど美しいユーザー インターフェイスを作り出すために、この機能がどれほど優れているかを示しました。多くの人々が、この効果は単なる宣伝にすぎないとか、リソースを使いすぎるとかいう記事にしていますが、私の感じでは、適度に行えば、普通のアプリケーションを、際立ったエクスペリエンスをユーザーにもたらすアプリケーションに変換できます。
パフォーマンスに関しては、当然、3D メッシュの表示やアニメーションに関連するオーバーヘッドが相当量生じます。これは、3D メッシュにマップされるビデオとしてフルモーション ビデオ表示を追加する場合の大量のオーバヘッドの話です。モカ フラペチーノを飲む場合とまったく同様に、ほどほどにするのが大切です。全般的には、3D メッシュの複雑性 (ポリゴン数) を必要最低限に抑えている限り、Windows Presentation Foundation の 3D パフォーマンスは優れていることがわかりました。Windows Presentation Foundation メディア チームは、今後のバージョンで 3D メディアの負荷を下げることに取り組んでいます。ただし、2D メディアよりも負荷が高くなるのは当然でしょう。
ビデオを 3D オブジェクトにマップする方法を見ていく前に、まず、Windows Presentation Foundation で 3D シーンを設定するのに何を行うかを復習しましょう。第一に、3D オブジェクトをシーンに配置する必要があります。.NET Framework 3.0 には 3D 基本クラスが含まれていません。ただし、マイクロソフトの社員が作成したと思われる Mesh3DObjects というクラスがあります。このクラスでは、広範な基本オブジェクトを作成できます (このクラスの詳細については、Karsten Januszewski によるチュートリアル (
msdn.microsoft.com/library/en-us/dnlong/html/avalon2d-3d.asp (英語) を参照してください)。
Windows Presentation Foundation には、3D シーンを作成するために必要な特定のセットの要素があります。まず、3D オブジェクトが必要です。このオブジェクトには、シーン内で表示可能にするための何らかの種類のマテリアルを備えている必要があります。マテリアルは、SolidColorBrush、LinearGradientBrush、ImageBrush、VisualBrush などのブラシを使用して作成します。ビデオを始めとするビジュアル要素を 3D の表面にマップするために VisualBrush を使用する方法はすぐにわかります。この技法は、基本的には前述のウエット フロア技法と同じです。
3D メッシュとマテリアルは GeometryModel3D 要素の内部にグループ化する必要があります。そうすることで、有効な Windows Presentation Foundation 3D オブジェクトが作成されます。3D シーンを目に見えるようにするためには、シーンに 1 つ以上のライトを追加する必要があります。カメラがなければ写真が撮れないのとまったく同様に、Windows Presentation Foundation の 3D シーンにはこの両方が必要です。最後に、シーンを完成するには、処理をシールするためにこれらすべてのアイテムを Viewport3D コントロールにラップする必要があります。
有効に機能する 3D シーンを適切に作成したら、ビデオなどのメディアを 3D メッシュにマッピングする作業を始めることができます。これは、VisualBrush を使用して、3D の表面にビデオを描画することで実現します。次のコードでは、VisualBrush を 3D オブジェクトの DiffuseMaterial に適用しています。
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<VisualBrush>
<VisualBrush.Visual>
<MediaElement Source="myMedia.wmv" />
</VisualBrush.Visual>
</VisualBrush>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
図 5 に、Windows Presentation Foundation の 3D の表面にマップされたビデオの 1 フレームを示します。
図 5 WPF 3D の表面にマップする
Windows Presentation Foundation の 3D の表面にビデオをマップするために使用できる別の方法があります。それは、System.Windows.Media 名前空間に含まれる VideoDrawing クラスで、まさにその名が示すとおりの機能を果たします。このクラスでは、MediaPlayer インスタンスからのビデオを DrawingBrush を使用して、任意のブラシ互換の表面に描画できます。これを行うには、DrawingBrush の Drawing プロパティに VideoDrawing クラスのインスタンスを設定する必要があります。この VideoDrawing のインスタンスでは、Player プロパティにビデオ ファイルを含む MediaPlayer インスタンスを設定することによって、ビデオをレンダリングできます。最後に、DrawingBrush を 3D オブジェクトの DiffuseMaterial の Brush プロパティに適用できます。次のコードは、C# を使用したサンプル実装を示します。
MediaPlayer mp = new MediaPlayer();
mp.Open(myValidMediaUri);
VideoDrawing vd = new VideoDrawing();
vd.Player = mp;
DrawingBrush db = new DrawingBrush();
db.Drawing = vd;
diffuseMat.Brush = db;
vd.Player.Play();
VisualBrush を使用する場合と VisualDrawing クラスを使用する場合の大きな違いの 1 つは、VisualDrawing クラスでは (C# または Visual Basic を使用する) 分離コード ファイルを作成および実装する必要がある点です。さらに、VideoDrawing クラスは MediaPlayer インスタンスとのみ連携して機能し、MediaElement コントロールとは連携しません。どちらの方法でもビデオを 3D に正しくマップするために、Windows Presentation Foundation が中間的な描画表示面を作成する必要があるので、パフォーマンスの点では大きな違いはありません。
ビデオ フレームからビットマップをレンダリングする
ビデオ アプリケーションは、その性質上、ビデオ ストリームからスクリーン ショットを取り、ビットマップにレンダリングする必要が生じることがあります。このような例は、市販の DVD 再生ソフトウェアにいくつか見受けられます。こうしたソフトウェアでは、ユーザーが再生中の任意の時点でカメラ アイコンをクリックすると、ビデオからスクリーン ショットを取得できます。他にも、一連のビデオ ファイルのすべてを実際に MediaElement コントロールに接続したくない場合は、この機能を使用してビデオ ファイルのサムネイルを作成できます。また、実行時のビデオ特殊効果を作成することも考えられます。ただし、この種の作業には、DirectShow API を使用する方がはるかに適しています。
Windows Presentation Foundation での大部分の作業と同様に、この種の作業を実現する方法も複数あります。ビデオ フレームのビットマップをレンダリングする場合も同じです。使用する方法とは関係なく、Windows Presentation Foundation で表示要素のビットマップをレンダリングする中核機能は、RenderTargetBitmap クラスで処理されます。このクラスは、Windows.Media.Imaging 名前空間に含まれています。この驚くべきクラスでは、Windows Presentation Foundation アプリケーションのビジュアル ツリー内のすべての項目からビットマップを作成できます。
このクラスを使用してビットマップをレンダリングするには、まず、新しく DrawingVisual オブジェクトを作成する必要があります。このオブジェクトは、RenderTargetBitmap.Render メソッドに渡されます。次に、DrawingVisual.Render メソッドに渡す DrawingContext オブジェクトを新しく作成します。この DrawingContext のインスタンスを使って、すべての種類のグラフィックを DrawingVisual オブジェクトに描画できます。ビデオのフレームを描画するには、DrawingContext.DrawVideo メソッドを呼び出します。このメソッドには、ビデオ ファイルを現在再生している MediaPlayer のインスタンスを渡します。また、ビデオ ファイルのキャプチャ領域を決める Rect 値も渡す必要があります。
この時点で、キャプチャしたビデオ フレームが DrawingVisual インスタンスに含まれることになり、そこから実際にビットマップをレンダリングできます。レンダリングする場合は、このインスタンスを RenderTargetBitmap.Render メソッドに渡す必要があるだけです。これで RenderTargetBitmap インスタンスにはビデオ フレームが含まれるようになりますが、このインスタンスを BitmapFrame.Create メソッドに渡すまではビットマップになりません。ビットマップ フレームを表示するには、Image コントロールの Source プロパティの値としてこのメソッド呼び出しを設定するだけです。次のコードは、こうしたフレームキャプチャ技法を C# で実装したものです。
RenderTargetBitmap rtb = new RenderTargetBitmap(320, 240, 1 / 200,
1 / 200, PixelFormats.Pbgra32);
DrawingVisual dv = new DrawingVisual();
DrawingContext dc = dv.RenderOpen();
dc.DrawVideo(myMediaPlayer, new Rect(0, 0, 320, 240));
dc.Close();
rtb.Render(dv);
Image im = new Image();
im.Source = BitmapFrame.Create(rtb);
対象のビットマップの形式は、RenderTargetBitmap コンストラクタに有効な PixelFormats 列挙値を渡して設定します。ビデオ フレームからビットマップをレンダリングする機能は、最初は限られた機能のように思えますが、この種の機能は実際には単なるスクリーン キャプチャ ツール以上の多くの使い道があります。
WPF のその他のオーディオ機能
Windows Presentation Foundation のメディア統合についてここまで説明してきたほとんどのことは、ビデオとオーディオの両方に当てはまります。ただし、Windows Presentation Foundation でオーディオの再生を扱う場合に使用できるクラスが他にもいくつかあります。前述のように、Windows Presentation Foundation で再生されるメディアは、実際には一連の Windows Media Player ランタイムによって駆動されます。そのため、ファイルを再生する前にこのランタイムを読み込んでおく必要があります。メディア ファイルとユーザー イベントやアニメーションとの同期を取る際には、これが大きな問題を引き起こすことがあります。ただし、この問題はタイムラインのスリップ動作で緩和できる場合があります。オーディオに関しては、こうした問題を回避できる別の手段がいくつかあります。
System.Media 名前空間に含まれる SoundPlayer クラスには、オーディオ WAV ファイルを読み込んで再生するための簡単なインターフェイスが用意されています。対象となる WAV ファイルは、外部ファイルであっても、ストリーミング ファイルであっても、埋め込みリソースであってもかまいません。この方式のオーディオ再生は、Windows Media Player に再生をまったく依存しないので、MediaElement コントロールを使ってオーディオ ファイルを再生するよりもオーバーヘッドがはるかに少なくなります。
WAV ファイルを SoundPlayer インスタンスに読み込むには、まず、SoundLocation プロパティに WAV ファイルの場所を設定してから、Load メソッドを呼び出して読み込み処理を開始する必要があります。ファイルが完全に読み込まれたら、SoundPlayer.Play メソッドを使用して再生できます。ファイルがすべてメモリに読み込まれないと、ファイルの再生は開始されません。
この簡易オーディオ再生は、SoundPlayerAction コントロールを使用して XAML でも使用できます。XAML では、EventTrigger 内部で WAV ファイルを再生できます。たとえば、ボタン ロールオーバーのインターフェイス音のようなものに、これが非常に役立ちます。これを使用するには、単純に、EventTrigger の EventTrigger.Actions ブロック内に配置します。以下に、マウス ボタンの MouseEnter イベントに応じて呼び出される SoundPlayerAction のコードを示します。
<EventTrigger RoutedEvent="Button.MouseEnter" SourceName="myButton">
<EventTrigger.Actions>
<SoundPlayerAction Source="media/overSound.wav"/>
</EventTrigger.Actions>
</EventTrigger>
まとめ
この記事では、Windows Presentation Foundation アプリケーションにオーディオとビデオを統合する際に使用できる方法について調査しました。Windows Presentation Foundation ではプロジェクトに必要なレベルの制御を行えない場合は、いつでも、メディア統合向けの DirectShow API の使用に戻ることができます。ただし、XAML を使ってオーディオとビデオを追加する機能によって、デザイナが簡単にメディア統合を処理できるようになるので、開発者はより複雑なコーディング作業に力を注ぐことができます。私は、かつてのように懐疑的ではなくなりました。Windows Presentation Foundation で利用できる驚くほど豊富なビジュアル機能により、メディア統合が単なる可能性ではなくなり、信じられないほど魅力的なものになります。
Lee Brimelow は、frog design 社の Senior Design Technologist で、Flash と WPF を専門とする受賞歴のあるインタラクティブ デザイナです。また、
www.thewpfblog.com (英語) で WPF テクノロジに関する人気のあるブログを運営しています。