本篇博文主要介绍如何构建一个简单的媒体播放器。
《快速构建Windows 8风格应用20-MediaElement》博文中提到了如何使用MediaElement对象进行播放视频的简单功能,但是在实际应用中需要更复杂的功能,例如:控制视频播放的控件、全屏模式、进度条等等其他功能。
本篇博文中示例使用应用程序中包含的媒体文件,当然我们也可以通过网络或者本地[使用 ]进行加载某一媒体文件。
首先我们创建一个MediaElement控件并添加到
- <ContentControl x:Name="videoContainer" KeyUp="VideoContainer_KeyUp" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Height="400" Grid.Row="0" >
- <MediaElement Name="videoMediaElement" Source="Video/Azure_Tmobile_500k.wmv"
- MediaOpened="videoElement_MediaOpened"
- MediaEnded="videoMediaElement_MediaEnded"
- MediaFailed="videoMediaElement_MediaFailed"
- CurrentStateChanged="videoMediaElement_CurrentStateChanged"
- PosterSource="Media/1.png"
- AutoPlay="False" />
- </ContentControl>
MediaElement控件的Source属性指向要播放的音频或视频文件。,该属性可以设置为应用中的某一文件的URI或网络上的文件的 URI。当然我们也可以使用
最后设置PosterSource属性值,PosterSource是一个图像,它在媒体加载前为MediaElement控件提供视觉展示。
1)未设置有效的源,例如:未设置Source、Source设置为Null、或源无效;
一般控制MediaElement播放包括播放,停止和暂停等功能。
4)快退:将MediaElement控件的DefaultPlaybackRate属性的值设置为 -2.0,我们可以调整此值,以提高或降低快退的速率。然后,处理程序调用
5)播放:如果MediaElement控件的DefaultPlaybackRate属性值不是 1.0,则将DefaultPlaybackRate 设置为 1.0。然后,处理程序调用
7)音量增加、音量降低:如果IsMuted为true,则取消音量静音,然后处理程序按 0.1 增加或降低
< StackPanel Orientation ="Horizontal"> < Button Name ="btnPlay" Click ="btnPlay_Click" Style ="{StaticResource transportStyle}" Content ="Play" /> < Button Name ="btnPause" Click ="btnPause_Click" Style ="{StaticResource transportStyle}" Content ="Pause" /> < Button Name ="btnStop" Click ="btnStop_Click" Style ="{StaticResource transportStyle}" Content ="Stop" /> < Button Name ="btnReverse" Click ="btnReverse_Click" Style ="{StaticResource transportStyle}" Content ="Rewind" /> < Button Name ="btnForward" Click ="btnForward_Click" Style ="{StaticResource transportStyle}" Content ="Forward" /> < Button Name ="btnMute" Click ="btnMute_Click" Style ="{StaticResource transportStyle}" Content ="Mute" /> < Button Name ="btnFullScreenToggle" Click ="btnFullScreenToggle_Click" Style ="{StaticResource transportStyle}" Content ="Full" /> < ComboBox Name ="cbAudioTracks" SelectionChanged ="cbAudioTracks_SelectionChanged" < Button Name ="btnVolumeUp" Click ="btnVolumeUp_Click" Style ="{StaticResource transportStyle}" Content ="-" /> < Button Name ="btnVolumeDown" Click ="btnVolumeDown_Click" Style ="{StaticResource transportStyle}" Content ="+" /> < TextBlock Name ="txtVolume" FontSize ="14" Text ="{Binding Volume, ElementName=videoMediaElement}" VerticalAlignment ="Center" HorizontalAlignment ="Right" /> private void btnPlay_Click(
object sender, RoutedEventArgs e)
if (videoMediaElement.DefaultPlaybackRate != 1)
videoMediaElement.DefaultPlaybackRate = 1.0;
videoMediaElement.Play();
private void btnPause_Click(
object sender, RoutedEventArgs e)
videoMediaElement.Pause();
private void btnStop_Click(
object sender, RoutedEventArgs e)
videoMediaElement.Stop();
private void btnForward_Click(
object sender, RoutedEventArgs e)
videoMediaElement.DefaultPlaybackRate = 2.0;
videoMediaElement.Play();
private void btnReverse_Click(
object sender, RoutedEventArgs e)
videoMediaElement.DefaultPlaybackRate = -2;
videoMediaElement.Play();;
private void btnVolumeDown_Click(
object sender, RoutedEventArgs e)
if (videoMediaElement.IsMuted)
videoMediaElement.IsMuted =
false;
if (videoMediaElement.Volume < 1)
videoMediaElement.Volume += .1;
private void btnMute_Click(
object sender, RoutedEventArgs e)
videoMediaElement.IsMuted = !videoMediaElement.IsMuted;
private void btnVolumeUp_Click(
object sender, RoutedEventArgs e)
if (videoMediaElement.IsMuted)
videoMediaElement.IsMuted =
false;
if (videoMediaElement.Volume > 0)
videoMediaElement.Volume -= .1;
启用全屏视频播放功能,需要将MediaElement的Width和Height设置为当前窗口的Windows.Bounds(使用的是Window.Current.Bounds.Width和 Window.Current.Bounds.Height)。
2)将MediaElement的Width和Height设置为显示的最大范围,这会让MediaElement控件的高度和宽度与窗口的对应尺寸一致。但是需要首先保存当前Height和Width,方便在应用退出全屏模式时将控件恢复为正确的大小。然后,可以将ContentControl和MediaElement的尺寸设置为当前窗口的
1)侦听键盘事件以检测用户希望何时退出全屏模式,通常我们使用Esc 键通来退出全屏模式。在ContentControl控件中添加
3)将ContentControl和MediaElement的Width和Height恢复为其原来的尺寸;
private bool _isFullscreenToggle =
false;
get {
return _isFullscreenToggle; }
set { _isFullscreenToggle =
value; }
private Size _previousVideoContainerSize =
new Size();
private void FullscreenToggle()
this.IsFullscreen = !
this.IsFullscreen;
TransportControlsPanel.Visibility = Visibility.Collapsed;
_previousVideoContainerSize.Width = videoContainer.ActualWidth;
_previousVideoContainerSize.Height = videoContainer.ActualHeight;
videoContainer.Width = Window.Current.Bounds.Width;
videoContainer.Height = Window.Current.Bounds.Height;
videoMediaElement.Width = Window.Current.Bounds.Width;
videoMediaElement.Height = Window.Current.Bounds.Height;
TransportControlsPanel.Visibility = Visibility.Visible;
videoContainer.Width = _previousVideoContainerSize.Width;
videoContainer.Height = _previousVideoContainerSize.Height;
videoMediaElement.Width = _previousVideoContainerSize.Width;
videoMediaElement.Height = _previousVideoContainerSize.Height;
private void btnFullScreenToggle_Click(
object sender, RoutedEventArgs e)
private void VideoContainer_KeyUp(
object sender, KeyRoutedEventArgs e)
if (IsFullscreen && e.Key == Windows.System.VirtualKey.Escape)
通常我们使用Slider控件来显示或更改视频位置,大致思路为设置Slider控件并使用
< Slider Name ="timelineSlider" Margin ="10,0" Width ="200"/> 如果我们想采用更高的精度可以使用设置为250 毫秒的最低频率调节这些数字。
private double SliderFrequency(TimeSpan timevalue)
double stepfrequency = -1;
double absvalue = (
int)Math.Round(
timevalue.TotalSeconds, MidpointRounding.AwayFromZero);
stepfrequency = (
int)(Math.Round(absvalue / 100));
if (timevalue.TotalMinutes >= 10 && timevalue.TotalMinutes < 30)
else if (timevalue.TotalMinutes >= 30 && timevalue.TotalMinutes < 60)
else if (timevalue.TotalHours >= 1)
if (stepfrequency == 0) stepfrequency += 1;
stepfrequency = absvalue / 100;
1)MediaElement当前状态为暂停或停止时;
3)进度条不可见时,例如:全屏模式下。这里需要注意的是进度条在推出全屏模式后重新开始计时;
下面C#代码是如何创建和设置DispatcherTimer:
private DispatcherTimer _timer;
private void SetupTimer()
_timer =
new DispatcherTimer();
_timer.Interval = TimeSpan.FromSeconds(timelineSlider.StepFrequency);
private void _timer_Tick(
object sender,
object e)
timelineSlider.Value = videoMediaElement.Position.TotalSeconds;
private void StartTimer()
_timer.Tick += _timer_Tick;
_timer.Tick -= _timer_Tick;
private void MainPage_Loaded(
object sender, RoutedEventArgs e)
timelineSlider.ValueChanged += timelineSlider_ValueChanged;
PointerEventHandler pointerpressedhandler =
new PointerEventHandler(slider_PointerEntered);
timelineSlider.AddHandler(Control.PointerPressedEvent, pointerpressedhandler,
true);
PointerEventHandler pointerreleasedhandler =
new PointerEventHandler(slider_PointerCaptureLost);
timelineSlider.AddHandler(Control.PointerCaptureLostEvent, pointerreleasedhandler,
true);
void videoElement_MediaOpened(
object sender, RoutedEventArgs e)
double absvalue = (
int)Math.Round(
videoMediaElement.NaturalDuration.TimeSpan.TotalSeconds,
MidpointRounding.AwayFromZero);
timelineSlider.Maximum = absvalue;
timelineSlider.StepFrequency =
SliderFrequency(videoMediaElement.NaturalDuration.TimeSpan);
// Helper method to populate the combobox with audio tracks. PopulateAudioTracks(videoMediaElement, cbAudioTracks);
private bool _sliderpressed =
false;
void slider_PointerEntered(
object sender, PointerRoutedEventArgs e)
void slider_PointerCaptureLost(
object sender, PointerRoutedEventArgs e)
videoMediaElement.Position = TimeSpan.FromSeconds(timelineSlider.Value);
void timelineSlider_ValueChanged(
object sender, Windows.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventArgs e)
videoMediaElement.Position = TimeSpan.FromSeconds(e.NewValue);
void videoMediaElement_CurrentStateChanged(
object sender, RoutedEventArgs e)
if (videoMediaElement.CurrentState == MediaElementState.Playing)
if (videoMediaElement.CurrentState == MediaElementState.Paused)
if (videoMediaElement.CurrentState == MediaElementState.Stopped)
timelineSlider.Value = 0;
void videoMediaElement_MediaEnded(
object sender, RoutedEventArgs e)
timelineSlider.Value = 0.0;
private void videoMediaElement_MediaFailed(
object sender, ExceptionRoutedEventArgs e)
// get HRESULT from event args string hr = GetHresultFromErrorMessage(e);
// Handle media failed event appropriately private string GetHresultFromErrorMessage(ExceptionRoutedEventArgs e)
String hr = String.Empty;
String token =
"HRESULT - ";
const int hrLength = 10;
// eg "0xFFFFFFFF" int tokenPos = e.ErrorMessage.IndexOf(token, StringComparison.Ordinal);
hr = e.ErrorMessage.Substring(tokenPos + token.Length, hrLength);
到此为止一个简单的媒体播放器就基本完成了!运行效果图如下:
注意:本博文介绍的媒体播放器在实际应用开发中,对于开发者是远远不够理想的,我们需要在此基础上进一步去优化。
音频和视频播放是非常耗费资源的操作。有关媒体应用性能的详细信息,可参阅
XAML 框架可以在只呈现视频时优化呈现的视频,这种情况类似于全屏播放的情况。 此方法使用较少的电源,并且产生高于同时显示其他元素情况下的频率。若要优化媒体播放,请将
XAML 框架尽可能长地延迟加载 DLL 和创建大型对象。
解码视频主要使用内存和 GPU,因此应选择与要在其上显示的设备的分辨率接近的视频格式。例如,解码高清 (1080) 视频,然后将其缩小至相当小的尺寸进行显示会占有不必要的资源。许多应用不会将相同的视频解码为不同的分辨率,但如果可用,请使用接近显示设备的分辨率的解码。
4)请勿动态显示 MediaElement 对象。
动画和媒体播放都会耗费大量系统资源。 在合适的上下文中使用动画可以创建完美动人的效果。 但是,出于性能方面考虑,请避免在使用 C++、C# 或 Visual Basic 的 Metro 风格应用中动态显示
本文转自 王祖康 51CTO博客,原文链接:http://blog.51cto.com/wzk89/1033384 ,如需转载请自行联系原作者