这里通过简单的一个播放器代码来学习如何在silverlight中使用多媒体。代码是参考的 http://www.cnblogs.com/webabcd/archive/2009/11/10/1344632.html 的例子进行稍加改造完成的。执行效果见下图:视频播放的是我家宝宝7个月的时候的视频。
代码如下:
Xaml 文件:
说明:这里使用了 Grid 来控制布局。
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="SilverlightStudy.MainPage" Loaded="UserControl_Loaded"> <Grid Height="500" Width="800"> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="45" /> <RowDefinition Height="90" /> Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition Width="200"/> Grid.ColumnDefinitions> <MediaElement x:Name="mediaElement" Grid.Row="0" Grid.ColumnSpan="4" Stretch="Fill" AutoPlay="False" Source="http://localhost:41454/SilverlightStudySite/MVI_0122.mp4" BufferingProgressChanged="mediaElement_BufferingProgressChanged" MediaEnded="mediaElement_MediaEnded" DownloadProgressChanged="mediaElement_DownloadProgressChanged" MediaOpened="mediaElement_MediaOpened" CurrentStateChanged="mediaElement_CurrentStateChanged" /> <Button x:Name="play" Content="播放" Margin="5" Grid.Row="1" Grid.Column="0" Click="play_Click" /> <Button x:Name="pause" Content="暂停" Margin="5" Grid.Row="1" Grid.Column="1" Click="pause_Click" /> <Button x:Name="stop" Content="停止" Margin="5" Grid.Row="1" Grid.Column="2" Click="stop_Click" /> <Button x:Name="mute" Content="静音" Margin="5" Grid.Row="1" Grid.Column="3" Click="mute_Click" /> <StackPanel Grid.Row="2" Grid.ColumnSpan="4"> <Slider x:Name="playSlider" Minimum="0" Maximum="1" Margin="5" ToolTipService.ToolTip="播放进度" ValueChanged="playSlider_ValueChanged" /> <Slider x:Name="volumeSlider" Minimum="0" Maximum="1" Margin="5" ToolTipService.ToolTip="音量大小" ValueChanged="volumeSlider_ValueChanged" /> <Slider x:Name="balanceSlider" Minimum="-1" Maximum="1" Margin="5" ToolTipService.ToolTip="音量平衡" ValueChanged="balanceSlider_ValueChanged" /> StackPanel> <StackPanel Grid.Column="4" Grid.RowSpan="3"> <TextBlock x:Name="lblPlayTime" Margin="5" /> <TextBlock x:Name="lblVolume" Margin="5" /> <TextBlock x:Name="lblBalance" Margin="5" /> <TextBlock x:Name="lblDownloadProgress" Margin="5" /> <TextBlock x:Name="lblBufferingProgress" Margin="5" /> <TextBlock x:Name="lblDroppedFramesPerSecond" Margin="5" /> <TextBlock x:Name="lblState" Margin="5" /> <TextBlock x:Name="lblWidth" Margin="5" /> <TextBlock x:Name="lblHeight" Margin="5" /> <TextBlock x:Name="lblTotalTime" Margin="5" /> <TextBlock x:Name="lblBufferingTime" Margin="5" /> StackPanel> Grid> UserControl>
对应的CS 文件,即事件处理代码。这里用了定时器,定时显示媒体的一些状态信息。
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using System.Windows.Threading; namespace SilverlightStudy { public partial class MainPage : UserControl { public MainPage() { // Required to initialize variables InitializeComponent(); } ////// 需要播放的文件的长度 /// private TimeSpan _duration; ////// 定时器,定时显示播放状态信息 /// private DispatcherTimer _timer = new DispatcherTimer(); private void UserControl_Loaded(object sender, RoutedEventArgs e) { // 每 500 毫秒调用一次指定的方法 _timer.Interval = TimeSpan.FromMilliseconds(500); _timer.Tick += new EventHandler(_timer_Tick); _timer.Start(); } void _timer_Tick(object sender, EventArgs e) { // CurrentState - 播放状态 [System.Windows.Media.MediaElementState枚举] // Position - 媒体的位置(单位:秒) if (mediaElement.CurrentState == MediaElementState.Playing) { lblPlayTime.Text = string.Format( "{0}{1:00}:{2:00}:{3:00}", "播放进度:", mediaElement.Position.Hours, mediaElement.Position.Minutes, mediaElement.Position.Seconds); } // DroppedFramesPerSecond - 媒体每秒正在丢弃的帧数 lblDroppedFramesPerSecond.Text = string.Format( "每秒丢弃帧数:{0}", mediaElement.DroppedFramesPerSecond); } private void mediaElement_BufferingProgressChanged(object sender, RoutedEventArgs e) { // BufferingProgress - 缓冲进度(0 - 1 之间) lblBufferingProgress.Text = string.Format( "缓冲进度:{0:##%}", mediaElement.BufferingProgress); } private void mediaElement_MediaEnded(object sender, RoutedEventArgs e) { mediaElement.Stop(); } private void mediaElement_DownloadProgressChanged(object sender, RoutedEventArgs e) { // DownloadProgress - 下载进度(0 - 1 之间) lblDownloadProgress.Text = string.Format( "下载进度:{0:##%}", mediaElement.DownloadProgress); } private void mediaElement_MediaOpened(object sender, RoutedEventArgs e) { /* * NaturalVideoWidth - 媒体文件的宽 * NaturalVideoHeight - 媒体文件的高 * HasTimeSpan - 是否可取得媒体文件的时长 * NaturalDuration - 媒体文件的时长 * Volume - 音量大小(0 - 1 之间) * Balance - 音量平衡(-1 - 1 之间) * BufferingTime - 需要缓冲的时间的长度 */ lblWidth.Text = "媒体文件的宽:" + mediaElement.NaturalVideoWidth.ToString(); lblHeight.Text = "媒体文件的高:" + mediaElement.NaturalVideoHeight.ToString(); _duration = mediaElement.NaturalDuration.HasTimeSpan ? mediaElement.NaturalDuration.TimeSpan : TimeSpan.FromMilliseconds(0); lblTotalTime.Text = string.Format( "时长:{0:00}:{0:00}:{0:00}", _duration.Hours, _duration.Minutes, _duration.Seconds); // 音量 mediaElement.Volume = 0.8; volumeSlider.Value = 0.8; lblVolume.Text = "音量大小:80%"; // 音量平和 mediaElement.Balance = 0; balanceSlider.Value = 0; lblBalance.Text = "音量平衡:0%"; // 缓存大小 mediaElement.BufferingTime = TimeSpan.FromSeconds(30); lblBufferingTime.Text = "缓冲长度:30秒"; } private void mediaElement_CurrentStateChanged(object sender, RoutedEventArgs e) { /* * CurrentState - 播放状态 [System.Windows.Media.MediaElementState枚举] * MediaElementState.Closed - 无可用媒体 * MediaElementState.Opening - 尝试打开媒体(此时Play(),Pause(),Stop()命令会被排进队列,等到媒体被成功打开后再依次执行) * MediaElementState.Buffering - 缓冲中 * MediaElementState.Playing - 播放中 * MediaElementState.Paused - 被暂停(显示当前帧) * MediaElementState.Stopped - 被停止(显示第一帧) */ lblState.Text = string.Format("播放状态:{0}", mediaElement.CurrentState); } private void play_Click(object sender, RoutedEventArgs e) { // Play() - 播放媒体(在当前 Position 处播放) mediaElement.Play(); } private void stop_Click(object sender, RoutedEventArgs e) { // Stop() - 停止媒体的播放 mediaElement.Stop(); } private void pause_Click(object sender, RoutedEventArgs e) { // CanPause - 媒体是否可暂停 // Pause() - 暂停媒体的播放 if (mediaElement.CanPause) mediaElement.Pause(); } private void mute_Click(object sender, RoutedEventArgs e) { // IsMuted - 是否静音 if (mediaElement.IsMuted == true) { mute.Content = "静音"; mediaElement.IsMuted = false; } else { mute.Content = "有声"; mediaElement.IsMuted = true; } } private void playSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { // CanSeek - 是否可以通过设置 Position 来重新定位媒体 // Position - 媒体的位置(单位:秒) if (mediaElement.CanSeek) { mediaElement.Pause(); mediaElement.Position = TimeSpan.FromSeconds(_duration.TotalSeconds * playSlider.Value); mediaElement.Play(); } } private void volumeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { // Volume - 音量大小(0 - 1 之间) mediaElement.Volume = volumeSlider.Value; lblVolume.Text = string.Format( "音量大小:{0:##%}", volumeSlider.Value); } private void balanceSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { // Balance - 音量平衡(-1 - 1 之间) mediaElement.Balance = balanceSlider.Value; lblBalance.Text = string.Format( "音量平衡:{0:##%}", balanceSlider.Value); } } }
一些播放多媒体的知识点:
Silverlight 并非支持所有媒体格式和协议。
详细支持的媒体请参看: http://msdn.microsoft.com/zh-cn/library/cc189080(VS.95).aspx
播放媒体的关键是 MediaElement 控件:这是一个表示包含音频和/或视频的控件。
MediaElement 的几个媒体特定的属性:
AutoPlay:指定 MediaElement 是否应自动开始播放。默认值为 true。
IsMuted:指定 MediaElement 是否静音。true 值将使 MediaElement 静音。默认值为 false。
Stretch:指定如何拉伸视频以填充 MediaElement 对象。可能值为 None、Uniform、UniformToFill 和 Fill。默认值为 Fill。
Balance: 音量平横,立体声扬声器的音量比。Double 类型属性,扬声器的音量比的范围为 -1 到 1。 默认值为 0。 值为 -1 表示左侧扬声器达到 100% 音量,而值为 1 表示右侧扬声器达到 100% 音量。0 表示在左右扬声器之间平均分布音量。
Volume: 音量大小。Double 类型属性,在 0 与 1 之间的线性标尺上所表示的媒体音量。 默认值为 0.5。
音量可能难以量化,因为每个媒体文件对于其录制或察觉到的音频级别都具有不同的基线。此外,真实的音量(以分贝标度表示)本质上是对数值。您可能希望用 Volume 属性来表示音频混频器滑块控件的位置,0 表示最低音量,而 1 表示最高音量。
Position : 自媒体开始播放之后经历的时间量。默认值是 TimeSpan 值"00:00:00"。可以设置的最大值是 MediaElement 对象的 NaturalDuration(媒体的自然持续时间)。
如果可以设置 Position,但该值被设置为某一负值或高于该媒体的 NaturalDuration 的值,则该属性值将相应设置为 00:00:00 或 NaturalDuration。
通常不应在 XAML 中设置此值,因为不能保证在加载媒体源之前可以定位该媒体。在引发 MediaOpened 后,检查 CanSeek 的值。如果该值为 true,则可以定位该媒体,并且可以设置 Position。
MediaElement 的事件说明:
MediaOpened: 当媒体流已被验证和打开且已读取文件头时发生。如果 AutoPlay 属性设置为 false,则当发生 MediaOpened 事件时,将暂停媒体。另外要注意: Position 属性在发生 MediaOpened 事件之前为 null。虽然 Position 是可设置的。但在引发 MediaOpened 事件之前,不应尝试设置 Position。包括不应在 XAML 中设置初始 Position 值。
MediaEnded : 当 MediaElement 对象不再播放音频或视频时发生。 如果媒体文件包含多个流,则在最后一个流结束后将发生 MediaEnded 事件。 如果以交互方式控制媒体播放,则不会发生 MediaEnded 事件。即上述演示代码中, mediaElement.Stop(); 不会触发 MediaEnded 事件。
CurrentStateChanged : 当 CurrentState 属性的值更改时发生。
尽管在 CurrentState 失效时会发生该事件,但这并不一定意味着 CurrentState 属性具有新值。例如,CurrentState 属性可能会从 Playing 切换为 Buffering 并很快又切换回 Playing,以致只引发了单个 CurrentStateChanged 事件,在这种情况下,该属性将并不表现为具有变化的值。此外,您的应用程序不应采用事件发生的顺序,尤其是针对"缓冲"之类的瞬态。在事件报告中可能会跳过某一瞬态,因为该瞬态发生得太快了。
DownloadProgressChanged : 在 DownloadProgress (MediaElement) 属性更改后发生。
对于渐进式下载,会发生 DownloadProgressChanged 事件(通常会发生多次)。只要下载的内容总量按照 0.05 或更高的量(作为 1.0 的系数,1.0 指示完成)增加或达到 1.0, 事件就会发生。
这里的 0.05, 是指 DownloadProgress 属性的值, DownloadProgress 属性是一个 Double 类型的属性,指示位于远程服务器上的内容的已下载内容的总量。此值介于 0 到 1 之间。乘以 100 可得到百分比。此属性为只读。默认值为 0。
BufferingProgressChanged : 当 BufferingProgress 属性更改时发生。
通常在下载过程中,BufferingProgressChanged 事件会发生多次。当 BufferingProgress 值按照 0.05 或更大的量增加(与上一次引发事件时相比)时,以及当该值达到 1.0 时,将发生该事件。
这里的 0.05, 是指 BufferingProgress 属性的值, BufferingProgress 属性是一个 Double 类型的属性,指示当前缓冲进度的值。此值介于 0 到 1 之间。乘以 100 可得到百分比。此属性为只读。默认值为 0。
参考资料:
稳扎稳打Silverlight(18) - 2.0视频之详解MediaElement, 开发一个简易版的全功能播放器
http://www.cnblogs.com/webabcd/archive/2009/11/10/1344632.html
音频和视频概述
http://msdn.microsoft.com/zh-cn/library/cc189078(VS.95).aspx