May 2010

Volume 25 Number 05

再生中 - Silverlight Media Framework によるカスタム プレーヤーの構築

Ben Rush | May 2010

ストリーミング メディアが Web 上のいたるところで見受けられるようになっています。ニュース サイトからソーシャル ネットワークや隣に住む人まで、まるでだれもがオンラインのビデオ エクスペリエンスを利用していると思えるほどです。このように急速に普及してきたことから、ほとんどのサイトでは、高品質のビデオ (多くの場合は、高品質で "帯域幅に対応した" ビデオ) を、信頼できる使いやすい方法で利用者に見せたいと考えています。

オンラインでのメディア配信エクスペリエンスの重要な要素はプレーヤーそのものです。プレーヤーは利用者が操作するものなので、プレーヤーしだいでオンライン エクスペリエンスのあらゆる要素が変化します。これほどプレーヤーに注目が集まっていることを考えれば当然ですが、現在の Web ベースのメディア プレーヤーは数年前よりもはるかに実装が複雑になっています。このため、開発者には、プレーヤーを構築する基盤となる堅牢なフレームワークが必要です。

Silverlight Media Framework (SMF) は、2009 年の Microsoft Professional Developers Conference でマイクロソフトがリリースしたオープン ソース プロジェクトです。SMF は、拡張可能で非常にスケーラブルな Silverlight ビデオ フレームワークで、開発者やデザイナーが独自のプレーヤーを作成するために必要な安定した中核基盤を直接提供します。Silverlight Media Framework の中心をなすコードは、NBC のオリンピック中継や「Sunday Night Football」の Web ビデオ プロジェクトから得た教訓に基づいて強化されています。

この記事では、SMF の基本要素について説明し、SMF を独自のプレーヤー プロジェクトに統合する方法を紹介し、SMF によってカスタム プレーヤー エクスペリエンスを実現する簡単なプロジェクトについて解説します。また、SMF のログ機能、設定機能、およびイベント処理機能の使用方法も示します。最後に、現在のビデオ終了時に、続けて視聴するのにお勧めビデオを表示するプレーヤー アプリケーションを作成します。

SMF 入門

まず、SMF を Codeplex (smf.codeplex.com、英語) からダウンロードします。また、Smooth Streaming Player Development Kit (iis.net/expand/smoothplayer、英語) をダウンロードして、SMF を使用するプロジェクトで参照することも必要です。Smooth Streaming Player Development Kit は SMF に含まれているのではなく、完全に独立したクローズドソース コンポーネントです。ただし、SMF ではこのキットの中核となる一連の機能、特にビデオ プレーヤーそのものを利用しています。この記事の執筆時点では、Smooth Streaming Player Development Kit のバージョンはベータ 2 です。

SMF は多くの Microsoft .NET アセンブリから構成され (図 1 参照)、それぞれのアセンブリにフレームワーク全体のさまざまな機能が割り当てられています。

Silverlight Media Framework のアセンブリ

図 1 Silverlight Media Framework のアセンブリ

中核となるアセンブリは、Microsoft.SilverlightMediaFramework.dll です。このアセンブリは、フレームワークの他のアセンブリ全体から参照される多数のユーティリティ クラスやユーティリティ型から構成されています。SMF の機能を使用するときは、Microsoft.SilverlightMediaFramework.dll アセンブリも参照する必要があります。

Microsoft.SilverlightMediaFramework.Data 名前空間には、プレーヤー外のデータを利用したり、プレーヤー内のデータをカプセル化したりするためのヘルパー クラスが用意されています。データは、任意の形式の汎用的なデータだけでなく、プレーヤー独自の設定情報にもなり得ます。さらに、プレーヤーの設定を表す型や操作する型のための、Microsoft.SilverlightMediaFramework.Data.Settings という別の名前空間もあります。

設定に使用するデータとは別に、開発者が最もよく操作する Data 名前空間内の型は、ストリーム外の DataClient クラスです。このクラスを使用すると、データを外部ソースから取得できます。プレーヤー外のデータをダウンロードして使用する場合は、このアセンブリを参照します。

SMF プレーヤーには、堅牢な Microsoft.SilverlightMediaFramework.Logging フレームワークが付属しています。このフレームワークは、ログ インフラストラクチャに書き込むとイベントが発生する、コールバック方式のパラダイムを使用します。ログ システムに独自のコールバック メソッドを登録して、登録したコールバックが呼び出されるときに、Web サービスへの情報の送信やテキスト ボックスへの情報の表示など、追加の操作を実行します。SMF 組み込みのログ機能を使用する場合は、このアセンブリを使用します。

Microsoft.SilverlightMediaFramework.Player アセンブリは、プレーヤー自体を実装します。また、スクラブ用コントロール、ボリューム コントロール、タイムライン マーカーなど、プレーヤーで使用する多くのコントロールも提供します。既定の SMF プレーヤーは簡潔で、Silverlight プレーヤーを必要とするあらゆるプロジェクトの出発点として最適です。しかし、SMF 内で定義されているすべてのコントロールは、コントロール テンプレートの考え方を中心に据えているため、Expression Blend や Visual Studio などのツールを使用して各コントロールにテーマを適用できます。

SMF のビルドおよび参照

SMF のソース コードは 1 つの .zip ファイルとしてダウンロードでき、この .zip ファイル内に、ソリューション ファイル、各出力ライブラリのプロジェクト、およびプレーヤー自体を実行して検証するテスト プロジェクトが含まれています。

SMF は、Smooth Streaming Player Development Kit を使用しています。このキットを参照するには、まず、スムーズ ストリーミングのアセンブリ (Microsoft.Web.Media.SmoothStreaming.dll) を SMF プロジェクトの \Lib フォルダーに移動します。

次に、SMF ソリューションを Visual Studio で開いてビルドし、フレームワークの利用に必要なすべてのアセンブリを作成します。すべての機能が期待どおりに動作することを確認するには、F5 キーを押してデバッグを開始します。この操作により、ソリューションがビルドされ、Microsoft.SilverlightMediaFramework.Test.Web ターゲット プロジェクトが実行されて、「Big Buck Bunny」ビデオをストリーミングする既定の SMF プレーヤーが表示されます (図 2 参照)。既定のプレーヤーの完成度に注目してください。スクラブ用の配置要素として、再生、停止、および一時停止用のボタン、ボリューム コントロール、全画面表示用のコントロールなどが既に用意されています。

SMF プレーヤーと「Big Buck Bunny」ビデオ

図 2 SMF プレーヤーと「Big Buck Bunny」ビデオ

次は、独自の Silverlight プロジェクトを別に作成して、このプロジェクト内から SMF を利用します。Visual Studio で、[ファイル] メニューの [新規作成] をポイントし、[プロジェクト] をクリックします。次に、[Silverlight アプリケーション] をクリックします。ソリューションに「SMFPlayerTest」という名前を付け、[OK] をクリックします。モーダル ダイアログ ボックスが表示され、Silverlight アプリケーションを新しい Web サイトでホストするかどうかを確認するメッセージが表示されます。[OK] をクリックすると、SMFPlayerTest と SMFPlayerTest.Web という 2 つのプロジェクトで構成される基本的な Silverlight アプリケーション ソリューションが表示されます。

最後に、新規作成したプロジェクトから Smooth Streaming Player Development Kit と SMF のアセンブリを参照します。SMF の出力アセンブリと Smooth Streaming Player Development Kit を SMF ソリューションの Debug フォルダーからコピーして、新しいプロジェクトに貼り付けます (図 3 参照)。これで、SMF を最大限に活用するのに必要なすべてのアセンブリ参照が新しいソリューションに含まれるようになりました。

必要なアセンブリの参照

図 3 必要なアセンブリの参照

プレーヤーの表示

SMF の使用を開始するには、SMF プレーヤーの名前空間を MainPage.xaml ページ内に含めます。このようにすると、すべての参照が正しく解決されます。

xmlns:p="clr-namespace:Microsoft.SilverlightMediaFramework.Player;assembly=Microsoft.SilverlightMediaFramework.Player"

ここで、ページの LayoutRoot というグリッド コントロールに、プレーヤーの XAML を挿入します。

<Grid x:Name="LayoutRoot">
  <p:Player>
  </p:Player>
</Grid>

F5 キーを押すと、プロジェクトが起動し、SMF プレーヤーが表示されます。ただし、再生するビデオをプレーヤーに指定していないため、何も再生されません。再生するコンテンツのないプレーヤーが表示されるだけです。

SMF では、SmoothStreamingMediaElement (Smooth Streaming Player Development Kit に付属) を利用してビデオを再生します。SMF では、この SmoothStreamingMediaElement から、CoreSmoothStreamingMediaElement オブジェクトと呼ばれる独自のプレーヤーを継承します。プレーヤーでコンテンツをストリーミングする場合はこのオブジェクトが必要です。必ず、SmoothStreamingSource プロパティの値を有効なスムーズ ストリーミング メディアの URL に設定してください。

<Grid x:Name="LayoutRoot">
  <p:Player>
    <p:CoreSmoothStreamingMediaElement
      AutoPlay="True"
      SmoothStreamingSource="replace with address to content here"/>
  </p:Player>
</Grid>

先ほど説明したように、マイクロソフトでは「Big Buck Bunny」サンプル ビデオ ストリームを提供しており、開発者はこのビデオを使用して Silverlight プロジェクトをテストできます。このテスト ストリームを使用するには、CoreSmoothStreamingMediaElement の SmoothStreamingSource プロパティを次の URL に設定します。

http://video3.smoothhd.com.edgesuite.net/ondemand/Big%20Buck%20Bunny%20Adaptive.ism/Manifest

もう一度 F5 キーを押し、プロジェクトをビルドして実行します。前回と同じプレーヤーがブラウザーで実行されますが、今回はプレーヤーが完全に読み込まれるとすぐに「Big Buck Bunny」ビデオのストリーミングが開始されます。基本的な Silverlight プレーヤーを作成してコンテンツをストリームすることが目的なら、これで作業は完了です。

しかし、SMF では、ここまで説明してきた機能よりもさらに高度な機能が提供されています。次は、基本的なログ機能を追加しましょう。

プレーヤーでのログ記録

SMF のログはシンプルです。イベントがログ記録されるたびに、LogReceived イベントが発生します。このイベントのイベント ハンドラーを登録して、各ログ イベントが発生するたびにそのイベントの通知を受信します。通知で実行する処理は、開発者が自由に決定できます。プレーヤー内の新しいウィンドウに通知を表示することも、イベントをフィルター処理して、特定のイベントが発生するたびに Web サービスに通知することも、シナリオ上必要な任意の処理を実行することもできます。

LogReceived イベントは、Logger クラス (Microsoft.SilverlightMediaFramework.Logging.dll 内で定義) 自体で静的に定義されているため、プロジェクト内の任意の場所にログ イベントを登録できます。以下に、SMFPlayerTest プロジェクトの MainPage.xaml ファイル内でイベント ハンドラーを登録して定義する例を示します。

public partial class MainPage : UserControl {
  public MainPage() {
    InitializeComponent();

    Logger.LogReceived += 
      new EventHandler<SimpleEventArgs<Log>>(
      Logger_LogReceived);
  }

  void Logger_LogReceived(object sender, 
    Microsoft.SilverlightMediaFramework.SimpleEventArgs<Log> e) {
    throw new NotImplementedException();
  }
}

SMF では、組み込みのイベントが多数発生します。これらのイベントを確認するには、Logger_LogReceived メソッド内にブレークポイントを作成し、プレーヤーを再度デバッグ モードで実行します。すぐにブレークポイントにヒットするので、メソッドのパラメーターを 1 つずつステップ実行して、情報が渡されるようすを確認できます。

ログ イベントのデータは、Log という抽象クラスから型を継承する必要がある、特殊なメッセージング オブジェクト内にパッケージ化されます。この Log 抽象型には、Sender、Message、および TimeStamp という 3 つのプロパティがあります。Sender プロパティは、イベントが発生したオブジェクトを指します。Message プロパティは、ログ イベントのテキストを保持する System.String 型のオブジェクトです。TimeStamp プロパティには、ログ オブジェクトのインスタンスが最初に作成された日時が保持されるだけです。第 2 パラメーターとしてイベント ハンドラーに渡されている SimpleEventArgs<> オブジェクトでは、その Result プロパティを介して Log オブジェクトの参照が保持されます。

ログ イベントを発生させるには、Log 基本クラスから継承する型のインスタンスを作成し、この型を Logger 型の静的に定義された Log メソッドに渡すだけです。SMF では、既に Log 基本型から継承している DebugLog クラスが提供されます。しかし、DebugLog 型は特殊で、Silverlight プロジェクトで参照するライブラリを SMF のデバッグ ビルドで作成した場合は、DebugLog 型を SMF のログ フレームワークに渡すと、対応するログ イベントが発生します (この結果、開発者が作成したイベント ハンドラーが呼び出されます)。しかし、SMF のリリース ビルドでは、DebugLog クラスが渡される Log メソッドへの呼び出しがすべて無視されます。簡単に言えば、デバッグ ステートメントがある場合は、ログ イベント引数として DebugLog オブジェクトを渡し、デバッグ ビルドのみを使用します。それ以外の場合は、Log 抽象型を継承する独自の型を作成する必要があります。

以下に、DebugLog オブジェクトのインスタンスを作成して Logger 型の Log 静的メソッドに渡すことで、SMF イベント システムを通じてリッスン中であることを通知するイベントを発生させる例を示します (必ず Smooth Streaming Player Development Kit のファイルをデバッグ設定でビルドしておきます)。

public MainPage() {
  InitializeComponent();

  Logger.LogReceived += 
  new EventHandler<SimpleEventArgs<Log>>(
    Logger_LogReceived);

  Logger.Log(new DebugLog { 
    Message = "Listening!", Sender = this }); 
}

Player クラスからの継承

ログはプレーヤーの中心機能ですが、SMF の Player 型自体を継承して拡張しない限り、SMF の再生機能を使用できません。

このしくみを確認するため、Player 型から継承する SMFPlayer という新しいクラスを作成します。

新しい SMFPlayer クラスは次のようになります。

namespace SMFPlayerTest {
  public class SMFPlayer : Player {
    public override void OnApplyTemplate() {
      base.OnApplyTemplate();
    }
  }
}

すべての FrameworkElement 型 (SMF の Player 型など) には、ApplyTemplate イベントが発生するたびに呼び出される OnApplyTemplate メソッドがあります。多くの場合、このメソッドは FrameworkElement 型のインスタンスを作成する際の便利な出発点の役割を果たします。

ここでは、SMFPlayer クラス内で既定の OnApplyTemplate メソッドをオーバーライドします。既定の Player 型の代わりに新しい SMFPlayer 型が実行されることを確認するには、オーバーライド内にブレークポイントを設定します。プレーヤーを Visual Studio でデバッグすると、Silverlight で SMFPlayer を実行するときにこのブレークポイントに到達します。

今度は、新しいプレーヤー クラスを使用するように MainPage.xaml ファイルを更新します。まず、以下のように、既に参照済みの名前空間の一覧にプレーヤーの名前空間を含めます (先ほどプレーヤーの名前空間を含めたのと同じ方法です)。

xmlns:smf="clr-namespace:SMFPlayerTest"

この後は、以下のように、Player の代わりに SMFPlayer を使用するよう XAML 内の Player タグを更新するだけです。

<Grid x:Name="LayoutRoot">
  <smf:SMFPlayer>
    <p:CoreSmoothStreamingMediaElement
      AutoPlay="true"
      SmoothStreamingSource="http://..."/>
  </smf:SMFPlayer>
</Grid>

次に、先ほどと同様に、以下のように DebugLog クラスのインスタンスを作成し、このインスタンスを Log メソッドに渡します。このようにすると、前に登録したイベント ハンドラー向けのイベントが発生します。

public override void OnApplyTemplate() {
  Logger.Log(new DebugLog {
    Message = "Hello from OnApplyTemplate!",
    Sender = this
    });

  base.OnApplyTemplate();
}

イベント ハンドラーから特にこのイベントだけをリッスンするには、DebugLog オブジェクトの Message プロパティを直接フィルター処理します。この例では、次のように OnApplyTemplate というテキストを含むメッセージを検索します。

void Logger_LogReceived(
  object sender, SimpleEventArgs<Log> e) {
  if (e.Result.Message.Contains("OnApplyTemplate")) {
    return;
  }
}

設定データの使用

設定を操作する優れたフレームワークは、ほとんどの大規模ソフトウェア プロジェクトに不可欠です。SMF の設定を操作するコードは、Microsoft.SilverlightMediaFramework.Data.dll アセンブリに構築されています。このアセンブリを使用すると、汎用の外部データをダウンロードできます。SMF の設定層では、このインフラストラクチャを使用して、Web サーバー上でホストされている特殊な形式の XML 設定ファイルにアクセスしてダウンロードします。設定データを正常にダウンロードして読み取ったら、SMF の設定層では、読み取ったデータを SettingsBase オブジェクトにカプセル化します。その後、このオブジェクトのメソッドを使用して、設定の値を取得します。

SettingsBase クラスは、その名のとおり、より具体的な (厳密に型指定された方法で設定値にアクセスできる) クラスの基本クラスとして機能します。以下に、SettingsBase から継承するクラスの例を示します。このクラスには 2 つのプロパティがあります。1 つは、ビデオ プレーヤーのソース URL を取得するプロパティで、もう 1 つは、ビデオ プレーヤーが自動的に開始するか、ユーザーが再生ボタンを押すまで待機するかを示すブール値を取得するプロパティです。

namespace SMFPlayerTest {
  public class SMFPlayerTestSettings : SettingsBase {
    public Uri VideoPlayerSource {
      get { return new Uri(
        GetParameterValue("videoSource")); }
    }

    public bool? AutoStartVideo {
      get { return GetParameterBoolean(
        "autoStart"); }
    }
  }
}

プロパティ メソッドでは、SettingsBase クラスによって実装された関数を使用して、型に読み込まれている設定の名前と値のペアに関する、プロパティが基づいているコレクションを調べます (これには後で説明するメカニズムを使用します)。これにより、タイプ セーフで IntelliSense に対応した方法で設定情報を取得できます。

ここで、新しい XML ファイルを SMFPlayerTest.Web プロジェクト内に作成し、SMFPlayerSettings.xml という名前を付けて、このファイルの末尾に以下のコードを追加します。

<?xml version="1.0" encoding="utf-8" ?>
<settings>
  <Parameters>
    <Parameter 
      Name="videoSource" 
      Value="http://video3.smoothhd.com.edgesuite.net/ondemand/Big%20Buck%20Bunny%20Adaptive.ism/Manifest"/>
    <Parameter Name="autoStart" Value="True"/>
  </Parameters>
</settings>

次に、設定の XML を読み込む SettingsClient オブジェクトを作成します。SettingsClient オブジェクトは、設定ファイルを指す URI を受け取ります。

m_settingsGetter = new SettingsClient(
  new Uri("http://localhost:10205/SMFPlayerSettings.xml"));

設定データを取得する処理は非同期なので、次のように、コールバック メソッドを SettingsClient オブジェクトの RequestCompleted メソッドに代入する必要があります。

m_settingsGetter.RequestCompleted += 
  new EventHandler<SimpleEventArgs<SettingsBase>>
  (m_settingsGetter_RequestCompleted);

最後に、SettingsClient オブジェクトのパラメーターを受け取らない Fetch メソッドを呼び出します。データを取得すると、次のように settingsGetter_RequestCompleted イベント ハンドラーが呼び出され、SettingsBase オブジェクトがこのイベント ハンドラーに渡されます。

void m_settingsGetter_RequestCompleted(
  object sender, SimpleEventArgs<SettingsBase> e) {

  SettingsBase settingsBase = e.Result;
  return; 
}

settingsGetter_RequestCompleted メソッドに渡された SettingsBase オブジェクトは、SMFPlayerSettings.xml ファイルが基づいているフレームワークによって、解析された名前と値のペアと共に読み込まれます。このデータを SMFPlayerTestSettings オブジェクトに読み込むには、次のように Merge メソッドを呼び出すだけです。このメソッドでは、SettingsBase から派生したオブジェクトどうしの設定情報をマージします。

SettingsBase settingsBase = e.Result;
m_settings.Merge(settingsBase);

this.mediaElement.SmoothStreamingSource = 
  m_settings.VideoPlayerSource;
this.mediaElement.AutoPlay = 
  (bool)m_settings.AutoStartVideo; 

return;

プレーヤーの設定は OnApplyTemplate メソッドからダウンロードされているので、CoreSmoothStreamingMediaElement の AutoPlay プロパティと SmoothStreamingSource プロパティを XAML ページ内にハードコードする必要はなくなりました。プレーヤーの XAML に必要なのは次のコードだけです。

<Grid x:Name="LayoutRoot">
  <smf:SMFPlayer>
    <p:CoreSmoothStreamingMediaElement/>
  </smf:SMFPlayer>
</Grid>

プレーヤーを実行すると、すべての設定データが読み込まれ、コールバックによってプレーヤーのメディア要素に値が読み込まれて、これまでと同様にビデオのストリームが開始されます。

SMF プレーヤーの拡張

多くの人気ビデオ サイトでは、ビデオの再生が完了すると、同様のビデオやお勧めビデオの一覧が表示されます。SMF プレーヤーを非常に容易に拡張できることを示すために、同様のお勧めビデオ機能を SMFPlayerTest プロジェクトに組み込む手順を順番に説明しましょう。

まず、次のように MainPage.xaml ファイルの SMFPlayer 要素に x:Name 属性を追加します。

<Grid x:Name="LayoutRoot">
  <smf:SMFPlayer x:Name="myPlayer">
    <p:CoreSmoothStreamingMediaElement/>
  </smf:SMFPlayer>
</Grid>

この属性を追加すると、Visual Studio と Expression Blend の両方で SMFPlayer オブジェクトを名前で参照するのが容易になります。

続いて、ソリューション エクスプローラーで [MainPage.xaml] ファイルを右クリックし、[Expression Blend を開く] をクリックします。Expression Blend 3 が起動し、SMF プレーヤーのデザイン インターフェイスが表示されます。[オブジェクトとタイムライン] セクションでは、先ほど SMFPlayer に付けた名前に対応する myPlayer ノードがビジュアル オブジェクトのツリーに表示されています。目的は、SMFPlayer のテンプレートを作成し、このテンプレートにお勧めビデオを表す 3 つのボタンを追加することです。Expression Blend のテンプレートを使用すると、プレーヤー自体に組み込まれたコントロールの追加、編集、または削除を実行できます。

テンプレートを作成するには、[オブジェクトとタイムライン] ウィンドウの [myPlayer] を右クリックし、[テンプレートの編集] をポイントして、[コピーして編集] をクリックします。[Style リソースの作成] ダイアログ ボックスが表示されるので、[OK] をクリックします。3 つのボタンをビデオ プレーヤーの前面に挿入するには、追加するボタンごとに、[ツール] ウィンドウのボタン アイコンをダブルクリックします。プレーヤーのテンプレートを構成するコントロールのツリーに 3 つのボタンが表示されるようになります (図 4 参照)。

コントロールのツリーに追加されたボタン コントロール

図 4 コントロールのツリーに追加されたボタン コントロール

ツリーのボタンを 3 つとも選択し、これらのコントロールのプロパティ ウィンドウに移動して、水平方向と垂直方向の配置を中央揃えに設定します (図 5 参照)。この結果、ビデオ プレーヤーの中央にボタンが配置されます。

ボタン コントロールの配置の設定

図 5 ボタン コントロールの配置の設定

ボタンは、既定のサイズですべて重なって配置されます。各ボタンの幅を 400 に設定し、高さを 75に設定します。次に、余白を調整して、1 つ目のボタンはボタンの下端から 175 ピクセルの位置にオフセットにし、2 つ目のボタンはボタンの上端から 175 ピクセルの位置にオフセットにして、3 つ目のボタンは余白のオフセットを 0 ピクセルにします。最終的に、図 6 のようになります。

Expression Blend の中央に配置したボタン

図 6 Expression Blend の中央に配置したボタン

ボタンが適切にプレーヤーに配置されていることを確認するには、Expression Blend で開いているすべてのファイルを保存し、Visual Studio に戻ります。Visual Studio では、Expression Blend で変更したドキュメントを再度読み込むよう促すメッセージが表示される場合があります。メッセージが表示された場合は、[OK] をクリックします。Visual Studio で F5 キーを押して、SMF プレーヤーをデバッグ モードで再起動します。今回は、ビデオ画面の中央に 3 つのボタンが配置された状態でプレーヤーが表示されます (図 7 参照)。

SMF プレーヤーの中央に配置したボタン

図 7 SMF プレーヤーの中央に配置したボタン

イベント ハンドラーのフック

次は、イベント ハンドラーをボタンに関連付ける必要があります。コードからボタンを参照するには、ボタンに名前を割り当てる必要があります。そのためには、[プロパティ] タブの [名前] ボックスを使用します。作業を簡単にするために、Button1、Button2、および Button3 という名前をボタンに付けます。ボタンに名前を付けると、[オブジェクトとタイムライン] ウィンドウが更新され、ビジュアル ツリーのボタン アイコンの隣にボタン名が表示されます。

各ボタンの [プロパティ] タブには、表示コンポーネントのイベント ハンドラーを割り当てるのに使用する [イベント] ボタンがあります。ボタンの 1 つを選択し、[プロパティ] タブの [イベント] ボタンをクリックして、[Click] ボックスをダブルクリックすると、MainPage.xaml.cs ファイルにイベント ハンドラーが自動生成されます。この結果、各ボタンのプロパティ ウィンドウには、そのボタンの Click イベントに割り当てられたイベント ハンドラーが表示され (図 8 参照)、MainPage.xaml.cs ファイルには、各ボタンの Click イベントに割り当てられたイベント ハンドラーが挿入されます。

イベント ハンドラーの設定

図 8 イベント ハンドラーの設定

これで、プレーヤーをデバッグできるようになりました。画面でいずれかのボタンをクリックすると、Click イベントが発生します。このイベントは MainPage.xaml.cs ファイル内の自動生成メソッドによって処理されるようになります。

お勧めビデオ

これらのボタンを使用して、お勧めビデオ機能を有効にしましょう。次の XML は、お勧めビデオを表します。

<?xml version="1.0" encoding="utf-8" ?>
<Suggestions>
  <Suggestion DisplayName="A suggestion" Url=""/>
  <Suggestion DisplayName="Another suggestion" Url=""/>
  <Suggestion DisplayName="My final suggestion" Url=""/>
</Suggestions>

Url 属性の値には、ボタンのクリック時にプレーヤーに読み込むビデオを指定します。DisplayName 属性の値は、ボタンに表示するテキストです。このファイルを Suggestions.xml という名前で SMFPlayerTest.Web プロジェクトに保存します。

DataClient 型 (Microsoft.SilverlightMediaFramework.Data 名前空間内) は、XML ドキュメントをダウンロードしてそのコンテンツをタイプ セーフな方法で表すために使用します。XML ファイルから読み込まれた各 Suggestion 要素を厳密に型指定された方法で表すには、Silverlight プロジェクトに次のような SMFPlayerTestSuggestion というクラスを作成します。

namespace SMFPlayerTest {
  public class SMFPlayerTestSuggestion {
    public string DisplayName;
    public Uri Url; 
  }
}

SettingsBase クラスと同様に、DataClient クラスは、XML コンテンツのデータを厳密に型指定された方法 (この場合は、SMFPlayerTestSuggestion オブジェクトの配列) で表せるクラスを派生することを目的としています。

次のように、SMFPlayerTest プロジェクトにクラス ファイルをもう 1 つ作成し、SMFPlayerTestDataClient という名前を付けます。

namespace SMFPlayerTest {
  public class SMFPlayerTestDataClient : 
    DataClient<SMFPlayerTestSuggestion[]> {

    public SMFPlayerTestDataClient(Uri Url) : base(Url) { }

    protected override void OnRequestCompleted(
      object sender, SimpleEventArgs<string> e) {

      throw new NotImplementedException();
    }
  }
}

SMFPlayerTestDataClient クラスは DataClient クラスから継承し、テンプレート引数を SMFPlayerTestSuggestion 型の配列に設定します。DataClient 基本クラスでは、オンラインに移行して外部 XML ファイルをダウンロードするのに必要な、すべての非同期ネットワーク ロジックが提供されます。ただし、コンテンツがダウンロードされると、DataClient 基本クラスでは OnRequestCompleted が呼び出されます。このとき、XML データに関するすべての処理が続いて実行されると想定されます。つまり、コンテンツは DataClient 基本クラスによってダウンロードされますが、コンテンツに関する処理は実装者が担当します。

より完成度の高い OnRequestCompleted の実装を次に示します。

protected override void OnRequestCompleted(
  object sender, SimpleEventArgs<string> e) {

  XDocument doc = XDocument.Parse(e.Result);
  List<SMFPlayerTestSuggestion> suggestions = 
    new List<SMFPlayerTestSuggestion>();
  foreach (XElement element in doc.Descendants("Suggestion")) {
    suggestions.Add(new SMFPlayerTestSuggestion {
      DisplayName = element.Attribute("DisplayName").GetValue(),
      Url = element.Attribute("Url").GetValueAsUri()
    });
  }

  base.OnFetchCompleted(suggestions.ToArray()); 
}

作業を簡単にするために、この実装では、LINQ to XML を使用して XML の必要な要素と属性を解析しています。各 Suggestion ノードの DisplayName 属性と Url 属性の値を取得したら、SMFPlayerTestSuggestion オブジェクトを配置して値を割り当てます。

最後に、OnFetchCompleted イベントを呼び出します。SMFPlayerTestDataClient クラスの外部コンシューマーには、お勧めビデオのデータがダウンロードされたときに通知を受け取るように FetchCompleted イベントのイベント ハンドラーを登録しているものもあります。OnRequestCompleted では XML データをタイプ セーフな方法でパッケージ化しているため、各イベント ハンドラーで受け取るのは、扱いやすい SMFPlayerTestSuggestion オブジェクトの配列です。この配列には、DataClient 基本クラスでダウンロードした XML ドキュメントの Suggestion 要素ごとに、SMFPlayerTestSuggestion オブジェクトが 1 つずつ含まれています。

基になる DataClient クラスでは、Fetch というメソッドが提供されます。Fetch メソッドを呼び出すと、コンテンツの非同期読み込みが開始されます。ビデオの終了時にお勧めビデオのデータをダウンロードし始めるには、次の mediaElement_MediaEnded というイベント ハンドラーを MediaElement オブジェクトの MediaEnded イベントにアタッチします。

void mediaElement_MediaEnded(
  object sender, RoutedEventArgs e) {

  m_client = new SMFPlayerTestDataClient(
    new Uri("http://localhost:10205/Suggestions.xml"));
  m_client.FetchCompleted += 
    new EventHandler<SimpleEventArgs<
    SMFPlayerTestSuggestion[]>>(m_client_FetchCompleted);
  m_client.Fetch(); 
}

mediaElement_MediaEnded メソッドでは、SMFPlayerTestDataClient 型のインスタンスを作成し、別のイベント ハンドラーを FetchCompleted イベントに割り当て、Fetch メソッドを呼び出してダウンロード処理を開始します。先ほど OnRequestCompleted 内に実装した OnFetchCompleted が呼び出されることで、FetchCompleted ハンドラーが呼び出されます (OnRequestCompleted は、コンテンツのダウンロード完了時に DataClient 基本型によって呼び出されます)。

mediaElement_MediaEnded イベント ハンドラー内に登録されている suggestion_FetchCompleted イベント ハンドラーの実装では、次のように、Suggestion 要素のデータの厳密に型指定された配列を受け取って、各ボタンに Suggestion 要素を 1 つずつ割り当てます。

void m_client_FetchCompleted(
  object sender, SimpleEventArgs<
  SMFPlayerTestSuggestion[]> e) {
  for (int c = 1; c <= 3; c++) {
    Button btn = (Button)GetTemplateChild(
      "Button" + c.ToString());
    btn.Tag = e.Result[c - 1].Url;
    btn.Content = 
      e.Result[c - 1].DisplayName; 
  }
}

基になる FrameworkElement 型の GetTemplateChild メソッドでは、MainPage.xaml で定義されている各ボタンの参照を取得します。ボタンごとに、表示テキストが Content プロパティに割り当てられ、URI が Tag プロパティに割り当てられます。この結果、各ボタンに対する Click イベントのハンドラーで、次のように Tag プロパティから URI を取得し、この URI をプレーヤーの MediaElement オブジェクトに代入してストリームを再生できるようになります。

private void Button1_Click(
  object sender, System.Windows.RoutedEventArgs e) {

  Uri redirectUrl = (Uri)((Button)sender).Tag;
  myPlayer.MediaElement.SmoothStreamingSource = 
    redirectUrl; 
}

ボタンの表示

最後に、現在ストリーミング中のビデオが終了するまでボタンを非表示にし、ビデオが終了したらボタンを表示します。ユーザーがボタンをクリックしたら、ボタンを非表示に戻します。

Visual Studio でこのクラスを編集し、SMFPlayer クラスに次のような 2 つの TemplateVisualState 属性を追加します。

[TemplateVisualState(Name = "Hide", GroupName = "SuggestionStates")]
[TemplateVisualState(Name = "Show", GroupName = "SuggestionStates")]
public class SMFPlayer : Player

TemplateVisualState 属性は、オブジェクトに設定可能な表示状態を定義する、すばらしく強力な属性です。表示状態がアクティブになると、Silverlight では、クラスに含まれる表示要素のプロパティが指定どおりに (子のボタン コントロールを表示するかどうかなどについて) 更新されます。

現在の表示状態を設定するには、VisualStateManager クラス (Silverlight のネイティブ型) の GoToState 静的メソッドを使用します。TemplateVisualState グループの GroupName プロパティは類似した状態をまとめ、TemplateVisualState グループの Name プロパティは個別の状態を指定します。

Expression Blend に戻りましょう。myPlayer テンプレートで、アートボード上の myPlayer を直接クリックし、[テンプレートの編集] をポイントして [現在のテンプレートの編集] をクリックします。[状態] タブをクリックし、SuggestionStates までスクロールします (図 9 参照)。

SuggestionStates の表示状態

図 9 SuggestionStates の表示状態

属性によって作成される 2 つの SuggestionStates が、[Hide] と [Show] として表示されています。[Hide] をクリックすると、左側に赤い円が表示され、デザイナー内で行うすべてのプロパティの変更が Expression Blend で記録されていることが示されます。Expression Blend では、[Hide] を再度クリックするまでプロパティの変更を記録し続けます。クリックすると、記録を示す赤い円が表示されなくなります。

Expression Blend では Hide 表示状態がアクティブになって記録されるので、ボタンの状態を Collapsed に設定します。[オブジェクトとタイムライン] ウィンドウでボタンを 3 つとも選択し、[プロパティ] タブで Visibility プロパティの値に Collapsed を指定します。[Hide] ボタンを再度クリックして、Hide 表示状態の記録を停止します。次は、[Show] をクリックして、Show 表示状態の左側に赤い円を表示します。今度は、Visible を表示状態として明示的に記録します。そのためには、[Visibility] の右側にある [詳細プロパティ オプション] をクリックして、[現在値の記録] をクリックします。開いているすべてのファイルを保存し、もう一度 Visual Studio に戻ります。

Silverlight のネイティブ クラスである VisualStateManager クラスは、現在アクティブな表示状態を明示的に設定するためのものです。プレーヤーの OnApplyTemplate メソッドで、現在アクティブな表示状態を次のように Hide に設定します。

VisualStateManager.GoToState(this, "Hide", true);

ストリームが終了して Suggestion 要素のダウンロードが完了したら、suggestion_FetchCompleted イベント ハンドラーで、次のように現在の表示状態を Show に設定してボタンを表示します。

VisualStateManager.GoToState(this, "Show", true);

いずれかのボタンをクリックしたら (または、元のストリームがもう一度再生されたら) ボタンを非表示にするには、MediaElement の MediaOpened イベントに対する新しいイベント ハンドラーを作成し、表示状態を Hide に設定します。

最後に 1 回プレーヤーを起動してデバッグします。ビデオが終了するまでボタンが表示されず、終了するとボタンが表示されることがわかります。ボタンをクリックすると、そのボタンに対応する Suggestion の設定で指定された任意の URL にプレーヤーが移動されます。

Codeplex にある SMF のプロジェクト サイトでは、コード ベース、ドキュメント、ディスカッション、および問題追跡ページを利用できます。ぜひアクセスして皆さんの力をお貸しください。創造的な思考がプロジェクトに加わるほど、すべての人が優れた結果を享受できるようになります。

Ben Rush は、18 年の経験を持つベテランのソフトウェア開発者であり、Microsoft .NET Framework および関連する Microsoft テクノロジを専門にしています。趣味は、優れたコードとスピードを出してサイクリングすることです。