Silverlight3 + Smooth Streaming による動画配信の Hello World! (in C#)

こんにちは。わび~です。

今日は Silverlight3 で Smooth Streaming の動画配信をするサンプルコード(C#)を紹介します。当ブログは質実剛健派ですので(?)できあいのものは使用せず、ゼロから作ります。ですので非常にシンプルな感じの出来栄えになりますことをご容赦くださいね。

準備する。

開発には以下の準備が必要です。

  1. Smooth Streaming のコンテンツを Expression Encoder 3 有償版で作る。*.ism, *.ismc, *.ismv です。
  2. IIS と IIS Media Services 3 をインストールする。 OS は Windows 7 などで OK です。
  3. Visual Studio 2008 SP1 と Silverlight 3 Tools (Silverlight 3 SDK 含む)をインストールする。
  4. Expression Encoder3 付属のテンプレートの SL3Standard の SmoothStreaming.xap を zip にリネームして展開し、PlugInMssCtrl.dll と SmoothStreaming.dll を取り出しておきます。32bit OS では C:\Program Files\Microsoft Expression\Encoder 3\Templates\en\SL3Standard\SmoothStremaing.xap にあります。

とにかく再生する。

Visual Studio で Silverlight プロジェクトを作成します。ここでは sltest1 としています。

MainPage.xaml に以下を貼り付けます。

 <UserControl x:Class="sltest1.MainPage"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
    <StackPanel Orientation="Vertical" Name="LayoutRoot">
        <MediaElement x:Name="m_player" Width="720" Height="480" Loaded="m_player_Loaded"></MediaElement>
        <TextBox x:Name="m_status" Width="800" Height="24"></TextBox>
    </StackPanel>
</UserControl>

MainPage.xaml.cs に以下を貼り付けます。ポイントは、ActiveStreamingSource を作成して Media Element に教えることと、URI に指定するのは *.ism ファイルであり、末尾に “/Manifest” を付ける点です。

 using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
using Microsoft.Expression.Encoder.AdaptiveStreaming;

namespace sltest1
{

    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }
        private void m_player_Loaded(object sender, RoutedEventArgs e)
        {
            string url = "media/tokyojazz.ism/Manifest";
            AdaptiveStreamingSource src = new AdaptiveStreamingSource();
            src.ManifestUrl = new Uri(url, UriKind.Relative);
            src.MediaElement = this.m_player;
            src.StartPlayback();
        }
    }
}

ClientBin フォルダに media というフォルダを作成し、その中にエンコードした Smooth Streaming 用コンテンツのファイル群 (*.ism, *.ismc, *.ismv) を置きます。

プロジェクトをビルドします。参照設定で PlugInMssCtrl.dll と SmoothStreaming.dll を追加するのを忘れないでください。

IISで sltest1.Web フォルダを仮想ディレクトリに追加し、そのページを IE からアクセスします。Hello World!!

 

再生中のビットレート情報を取得するイベントハンドラを作成する。

Smooth Streaming ですので、リアルタイムにビットレートが刻一刻と変わっていく様子が見えないと面白くありません。

それには以下のようなイベントハンドラを記述します。

         public void OnPlayBitrateChange(object sender, BitrateChangedEventArgs e)
        {
            if (e.StreamType == MediaStreamType.Video)
            {
                this.m_nowPlayingBitrate = (long)e.Bitrate;
            }
        }
        private void OnDownloadBitrateChange(object sender, BitrateChangedEventArgs e)
        {
            if (e.StreamType == MediaStreamType.Video)
            {
                this.m_nowDownloadingBitrate = (long)e.Bitrate;
            }
        }

このイベントハンドラを以下のように ActiveStreamingSource に登録しておきます。再生中のビットレートが変わったときに OnPlayBitrateChange() がコールされ、先行ダウンロード中のビットレートが変わったときに OnDownloadBitrateChange() がコールされます。

         private void m_player_Loaded(object sender, RoutedEventArgs e)
        {
            string url = "media/tokyojazz.ism/Manifest";

            AdaptiveStreamingSource src = new AdaptiveStreamingSource();
            src.ManifestUrl = new Uri(url, UriKind.Relative);
            src.MediaElement = this.m_player;
            src.StartPlayback();
            src.PlayBitrateChange += OnPlayBitrateChange;
            src.DownloadBitrateChange += OnDownloadBitrateChange;
        }

 

完成したコードはこれです。Mainpage.xaml は冒頭のもののままでOKです。一部かなりやっつけ仕事感がありますが、あくまでも Hello World ですので、どうかご勘弁を。

 using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
using Microsoft.Expression.Encoder.AdaptiveStreaming;

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

            this.m_dispatcher_timer = new DispatcherTimer();
            this.m_dispatcher_timer.Interval = new TimeSpan(0, 0, 0, 0, 200);
            this.m_dispatcher_timer.Tick += new EventHandler(this.dispatcher_timer_event_handler);
        }
        private void m_player_Loaded(object sender, RoutedEventArgs e)
        {
            string url = "media/tokyojazz.ism/Manifest";

            AdaptiveStreamingSource src = new AdaptiveStreamingSource();
            src.ManifestUrl = new Uri(url, UriKind.Relative);
            src.MediaElement = this.m_player;
            src.StartPlayback();
            src.PlayBitrateChange += OnPlayBitrateChange;
            src.DownloadBitrateChange += OnDownloadBitrateChange;
            this.m_dispatcher_timer.Start();

            update_status_info();
        }
        public void OnPlayBitrateChange(object sender, BitrateChangedEventArgs e)
        {
            if (e.StreamType == MediaStreamType.Video)
            {
                this.m_nowPlayingBitrate = (long)e.Bitrate;
            }
            update_status_info();
        }
        private void OnDownloadBitrateChange(object sender, BitrateChangedEventArgs e)
        {
            if (e.StreamType == MediaStreamType.Video)
            {
                this.m_nowDownloadingBitrate = (long)e.Bitrate;
            }
            update_status_info();
        }
        private void update_status_info()
        {
            TimeSpan ts_duration = this.m_player.NaturalDuration.TimeSpan;
            TimeSpan ts_position = this.m_player.Position;

            string duration = ts_duration.Hours.ToString("00")
                + ":" + ts_duration.Minutes.ToString("00")
                + ":" + ts_duration.Seconds.ToString("00");
            string position = ts_position.Hours.ToString("00")
                + ":" + ts_position.Minutes.ToString("00")
                + ":" + ts_position.Seconds.ToString("00");
            string status_m_player_play
                = this.m_player.CurrentState.ToString();
            string status_m_player_buffering
                = ((int)(this.m_player.BufferingProgress * 100)).ToString() + "% バッファリング完了";
            string status_m_player_download
                = ((int)(this.m_player.DownloadProgress * 100)).ToString() + "% ダウンロード完了";
            string status_m_player_fps
                = ((int)this.m_player.RenderedFramesPerSecond).ToString() + "fps 描画中";
            string status_m_player_fps_dropped
                = ((int)this.m_player.DroppedFramesPerSecond).ToString() + "fps 廃棄中";
            string status_m_player_bitrate_play
                = ((int)this.m_nowPlayingBitrate / 1000).ToString() + "Kbps 再生中";
            string status_m_player_bitrate_download
                = ((int)this.m_nowDownloadingBitrate / 1000).ToString() + "Kbps ダウンロード中";

            m_status.Text = position + "/" + duration + " " + status_m_player_play
                + " " + status_m_player_buffering + " " + status_m_player_download
                + " " + status_m_player_fps + " " + status_m_player_fps_dropped
                + " " + status_m_player_bitrate_play + " " + status_m_player_bitrate_download;
        }
        private long m_nowPlayingBitrate;
        private long m_nowDownloadingBitrate;
        private DispatcherTimer m_dispatcher_timer;
        private void dispatcher_timer_event_handler(Object sender, EventArgs e)
        {
            update_status_info();
        }
    }
}
 ぜひ試してみてくださいね。