我在“IIS 7 Smooth Streaming技术在Silverlight 3中的应用 ”一文中详细介绍了有关IIS 7、Smooth Streaming技术以及如何在Silverlight中使用MediaElement控件播放Smooth Streaming视频的内容,在继续本文之前,如果你对什么是Smooth Streaming还存在疑问,你可以先去看看我的那篇文章,也算作是一个入门吧。
在本文中,我将向大家介绍一个新控件——SmoothStreamingMediaElement,也被称之为SSME,它是IIS Smooth Streaming Player Development Kit工具包中的一个Silverlight控件,是在原MediaElement控件基础上的功能加强,主要增加了对Smooth Streaming视频源的直接支持以及一些相关事件。大家可以去微软的官方站点上下载该工具包,目前已经出到Beta2版了。
在上一文中我向大家介绍了如何利用现有的MediaElement控件来支持Smooth Streaming视频的播放,事实上这种方法具有很大的局限性,例如控制播放进度、添加视频播放时的tracing事件等等。SmoothStreamingMediaElement控件作为MediaElement控件的一个加强版本,正好弥补了这方面的不足,同时,该控件也支持普通视频文件的播放。你当然还记得Smooth Streaming官方站点上的那个Big Buck Bunny演示影片,或许你也想知道它是怎么实现的,不要着急,在接下来的一系列文章中将会花点篇幅来向大家介绍,今天我们主要看看如何使用SSME控件,因为Big Buck Bunny的核心控件就是SSME。
需要些什么
1. 既然是开发一个Silverlight工程,那么首先Visual Studio和Silverlight Tool kits是肯定需要的,这点我就不详细介绍了,相信大家的这个环境都是具备的,如果不具备,可以去微软官网上找相关的资源。
2. IIS Smooth Streaming Player Development Kit。目前的版本应该是Beta2版,下载后安装,你会发现Microsoft.Web.Media.SmoothStreaming.dll,这个正是我们所需要的。
3. 另外就是一些开发Silverlight所要具备的知识了,如果你从未开发过Silverlight程序并且对Silverlight一无所知,那么我建议你不要继续往下看了。
如何开始
现在我们应该就可以着手开始我们的工程了。首先在Visual Studio中创建一个Silverlight工程,如下图。
然后将Microsoft.Web.Media.SmoothStreaming.dll拷贝到你Silverlight工程的Bin\Debug\目录下(注意在Visual Studio中创建Silverlight项目时会同时创建一个用来进行测试的Web项目,不用将该文件复制到Web项目的Bin目录下),将该类库引用到Silverlight工程中。
然后我们需要将SSME控件添加到MainPage.xaml页面上,有两种方法,第一种方法是在Visual Studio的工具箱中单击右键-“选择项”,在弹出的对话框中选择“Silverlight组建”选项卡,然后点击“浏览”,找到Microsoft.Web.Media.SmoothStreaming.dll文件,确定并关闭对话框,这时控件SSME会出现在Visual Studio的工具箱中,你可以直接将该控件拖放到页面上。这和在Visual Studio中添加普通的ASP.NET自定义控件是一样的。
另一种方法是在页面中手动注册并引用控件。打开MainPage.xaml,在页面的头部添加下图所示的内容,Visual Studio的智能感知可以帮助你快速找到你要引用的命名空间。然后你在页面上就可以直接使用SSME命名空间下的控件了,其中就包含了SmoothStreamingMediaElement控件。熟悉下SSME控件的常用属性和事件
有必要先向大家介绍下SSME控件中一些常用的属性和事件,由于该控件没有包含在任何一个版本的Silverlight标准类库中,目前还只是一个测试版,所以微软官方提供的资料很少,在msdn上虽然能够见到它的身影,但是几乎没有任何示例和相关解释,读者可以查看一下它都包含哪些东西,http://msdn.microsoft.com/en-us/library/microsoft.web.media.smoothstreaming.smoothstreamingmediaelement_members.aspx。在这里我给出一些常用的属性和方法,如果你对MediaElement控件很熟悉,那么非常好,你可以毫不费力地过渡到SSME上,因为SSME几乎支持了MediaElement控件的全部属性和方法。
AutoPlay:与MediaElement不同,除非你显示指定AutoPlay的值为True,否则即使SSME已经成功打开的视频源也不会自动播放视频。
Source:播放普通视频文件时的地址。
SmoothStreamingSource:播放Smooth Streaming视频文件时的地址。
VideoPlaybackTrack.Bitrate:通过该值可以得到SSME当前播放影片的比特率,如果SSME当前播放的是Smooth Streaming格式的影片,那么比特率会随网络带宽动态发生变化。
VideoDownloadTrack.Bitrate:同样的,通过该值可以得到当前下载影片的比特率。
RenderedFramesPerSecond:通过该值可以得到当前播放影片的帧率(即每秒播放多少帧)。
PlaybackTrackChanged:当播放影片的比特率发生变化时触发。
DownloadTrackChanged:当下载影片的比特率发生变化时触发。
细心的读者是否已经发现,我们通过上面给出的这些属性和事件,加上Silverlight里的路径动画,是不是就可以构造一个类似于Big Buck Bunny的播放器呢?先别着急,我们还是先熟悉熟悉SSME吧,我打算在下一篇文章中再来介绍那个让人找摸不透的播放器呢。
继续完善我们的SSME播放器
接着进行我们的工程。知道如何在工程中加入SSME了,下面你可以试着将这段代码复制到你的MainPage.xaml页面中。
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:SSME="clr-namespace:Microsoft.Web.Media.SmoothStreaming;assembly=Microsoft.Web.Media.SmoothStreaming"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="0.90*"></RowDefinition>
<RowDefinition Height="0.05*"></RowDefinition>
<RowDefinition Height="0.05*"></RowDefinition>
</Grid.RowDefinitions>
<SSME:SmoothStreamingMediaElement AutoPlay="True" x:Name="SmoothPlayer" SmoothStreamingSource="http://localhost:77/Wildlife.ism/manifest" Grid.Row="0"/>
</Grid>
</UserControl>
注意SmoothStreamingSource的值应当指定为一个你事先已经准备好的Smooth Streaming视频源,如果这个视频源不在本地,你可能需要添加跨域访问的代码,有关如何创建Smooth Streaming视频源以及如何架设Smooth Streaming视频服务,请参考“IIS 7 Smooth Streaming技术在Silverlight 3中的应用”一文。
好了,按下F5,启动工程直接查看效果,你会发现浏览器中除了一块黑色外并没有播放你所指定的影片,怎么回事啊?难道视频地址给错了?首先请确保你所给出的地址可以通过浏览器直接访问,得出的结果应该类似于下面这样的画面:
如果不能通过浏览器直接访问,那你就要检查你的视频服务了,或许你需要通过Expression Encoder重新转换视频并发布到IIS 7上。如果可以通过浏览器直接访问,那么恭喜你,你所看到的黑色画面是正常的。还记得我在上一文中说过调试Smooth Streaming播放器时只能通过IIS 7,而不能直接通过Visual Studio或者Blend吗?所以你不得不在你机器的IIS 7上部署一个Web站点,然后将用来进行测试的Web工程中的所有文件复制到Web站点中,然后通过浏览器进行访问。
如果一切顺利的话,你应该可以在你的浏览器中看到影片了,仔细观察影片,你会看到一开始的时候画面是比较模糊的,但是SSME可以根据网络带宽动态调整画面质量,随着影片的播放,你会发现画面越来越清晰了。如果你仍然看不到影片,可能会有几个原因,首先还是视频服务的问题,你需要重新去确认视频服务是否可用并能正常访问;然后是权限的问题,你可以试着将浏览器地址中的localhost改为你的机器名,然后重新刷新浏览器,或者修改Silverlight工程中SSME的SmoothStreamingSource的地址,将其中的localhost改为你的机器名(如果你使用的是本地的视频源),如果视频源和Web站点都在同一台机器上,你应该同时使用localhost或是机器名。下面是在我本地看到的影片的播放效果:
添加播放控制部分
当然,一个像样的播放器是需要有播放控制面板的,我打算在我们的SSME播放器上添加一个播放进度条、音量控制、开始/暂停按钮、停止按钮。添加控件后的xaml代码如下:
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:SSME="clr-namespace:Microsoft.Web.Media.SmoothStreaming;assembly=Microsoft.Web.Media.SmoothStreaming"
mc:Ignorable="d" xmlns:dataInput="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.Input" x:Class="SmoothStreamingPlayer.MainPage"
d:DesignWidth="640" d:DesignHeight="480">
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="0.90*"/>
<RowDefinition Height="0.05*"/>
<RowDefinition Height="0.05*"/>
</Grid.RowDefinitions>
<SSME:SmoothStreamingMediaElement AutoPlay="True" x:Name="SmoothPlayer" Grid.Row="0"/>
<Slider x:Name="playSlider" Grid.Row="1" Cursor="Hand" Maximum="100"/>
<ToggleButton x:Name="playToogleButton" Grid.Row="2" HorizontalAlignment="Left" Margin="8,0,0,4" Width="33" Content="暂停" Height="20" Cursor="Hand"/>
<Slider Margin="115,4,0,8" Grid.Row="2" HorizontalAlignment="Left" Width="65" x:Name="volumeSlider" Cursor="Hand" Maximum="1" Value="{Binding Path=Volume, ElementName=SmoothPlayer, Mode=TwoWay}" />
<dataInput:Label HorizontalAlignment="Left" Margin="87,3,0,5" Width="29" Grid.Row="2" Content="音量"/>
<Button x:Name="stopButton" HorizontalAlignment="Left" Margin="45,0,0,4" Grid.Row="2" Content="停止" Width="33" Height="20" Cursor="Hand"/>
</Grid>
</UserControl>
SSME的SmoothStreamingSource改到后台去指定了,为的是方便在Blend中打开Silverlight工程,因为Blend会默认在页面打开的时候自动加载视频并生成缩略图,由于我们指定的播放地址不是普通地址,视频加载的时候Blend会报错,导致页面无法在Blend中打开。
UI界面已经完成了,尽管比较难看!说老实话,我也不是美工出身,对界面这方面也不是很在行。下面的工作就是让这些控件能够发挥作用,我将我的代码给出来,大家可以做个参考。
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Controls.Primitives;
namespace SmoothStreamingPlayer
{
public partial class MainPage : UserControl
{
private const string VIDEOSOURCE = "http://localhost:77/Wildlife.ism/manifest";
private TimeSpan _duration;
public MainPage()
{
InitializeComponent();
InitialPlayer();
}
//初始化属性和事件
private void InitialPlayer()
{
this.SmoothPlayer.SmoothStreamingSource = new Uri(VIDEOSOURCE);
//this.SmoothPlayer.Source = new Uri(VIDEOSOURCE);
this.playToogleButton.Click += new RoutedEventHandler(playToogleButton_Click);
this.stopButton.Click += new RoutedEventHandler(stopButton_Click);
this.playSlider.ValueChanged += new RoutedPropertyChangedEventHandler<double>(playSlider_ValueChanged);
this.SmoothPlayer.MediaOpened += new RoutedEventHandler(SmoothPlayer_MediaOpened);
this.SmoothPlayer.MediaEnded += new RoutedEventHandler(SmoothPlayer_MediaEnded);
this.SmoothPlayer.MarkerReached += new TimelineMarkerRoutedEventHandler(SmoothPlayer_MarkerReached);
}
//拖动播放进度条
void playSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
double time = _duration.TotalSeconds / playSlider.Maximum * playSlider.Value;
this.SmoothPlayer.Position = new TimeSpan(0, 0, (int)time);
}
//停止播放
void stopButton_Click(object sender, RoutedEventArgs e)
{
this.SmoothPlayer.Stop();
playSlider.Value = 0;
playToogleButton.IsChecked = true;
playToogleButton.Content = "播放";
}
//播放/暂停
void playToogleButton_Click(object sender, RoutedEventArgs e)
{
ToggleButton button = (ToggleButton)sender;
if (button.IsChecked == true && this.SmoothPlayer.CanPause)
{
this.SmoothPlayer.Pause();
this.playToogleButton.Content = "播放";
}
if (button.IsChecked == false)
{
this.SmoothPlayer.Play();
this.playToogleButton.Content = "暂停";
}
}
//控制播放进度条
void SmoothPlayer_MarkerReached(object sender, TimelineMarkerRoutedEventArgs e)
{
this.Dispatcher.BeginInvoke(delegate()
{
double time = e.Marker.Time.TotalSeconds;
double seconds = this.SmoothPlayer.NaturalDuration.TimeSpan.TotalSeconds;
if (seconds <= 0)
{
return;
}
double marker = (time * playSlider.Maximum / seconds);
playSlider.Value = marker;
});
}
//影片播放完后停止播放器并重置进度条
void SmoothPlayer_MediaEnded(object sender, RoutedEventArgs e)
{
this.SmoothPlayer.Stop();
playSlider.Value = 0;
playToogleButton.IsChecked = true;
playToogleButton.Content = "播放";
}
//影片打开后初始化进度条
void SmoothPlayer_MediaOpened(object sender, RoutedEventArgs e)
{
_duration = this.SmoothPlayer.NaturalDuration.HasTimeSpan ? this.SmoothPlayer.NaturalDuration.TimeSpan : TimeSpan.FromMilliseconds(0);
this.SmoothPlayer.Volume = 0.8;
playSlider.Minimum = 0;
playSlider.Maximum = 10;
for (int i = (int)playSlider.Minimum; i < (int)playSlider.Maximum; i++)
{
TimelineMarker marker = new TimelineMarker();
double time = _duration.TotalSeconds / playSlider.Maximum * i;
marker.Time = new TimeSpan(0, 0, (int)time);
marker.Text = string.Empty;
marker.Type = string.Empty;
this.SmoothPlayer.Markers.Add(marker);
}
}
}
}
其中播放进度条的控制使用了TimelineMarker,由于我要播放的影片是Win7自带的一个高清视频演示文件,播放时长比较短,所以我将Maximum的值设得比较小,你可以根据影片的长短来设定该值。另外,我在程序中将播放地址hard-code到代码里了,你完全可以通过页面上的InitParams参数将播放地址传进来,也或者你可以将播放参数写到playlist里作为xml传进来。
好了,一切搞定!现在你可以在浏览器中预览SSME播放器啦,下面是在我机器上看到的效果。
结语
使用SSME可以非常方便地支持Smooth Streaming视频的播放,Silverlight程序员几乎不用做任何额外的工作就可以让自己的Silverlight播放器支持Smooth Streaming视频流,同时,你可以在程序中做出判断以决定让SSME播放普通的视频还是Smooth Streaming视频。接下来的内容我将向大家介绍如何利用SSME并结合FrameRateGraph、BitrateGraph等控件实现一个完整的Big Buck Bunny播放器。