闲来无事,倒腾了一个简单的silverlight视频播放器

简介: #silverlightControlHost { height:407px; width:480px; padding:3px; text-align:center; border:solid 1px #ccc; margin:10px; } 近二日闲来无事,把silverlight的官方文档瞅了瞅,倒腾了一个简单的视频播放器,顺便也测试了下能否播放传说中的h.
近二日闲来无事,把silverlight的官方文档瞅了瞅,倒腾了一个简单的视频播放器,顺便也测试了下能否播放传说中的h.264,最终效果如下:

 

http://images.24city.com/jimmy/player/default.html

布局思路:

Grid做为最外层容器,分上中下三行

第一行为视频播放窗口,同时单击视频时"暂停"遮罩层也放在这一行,只不过默认不显示而已
第二行为进度条显示区,为了方便布局,在这一行用StackPanel作子容器横向放置了二个控件(进度条和时间显示)
第三行为其它的控制按钮区,也是用StackPanel横向放置其它控件

实现的功能:

1.单击视频,暂停播放,再次单击则继续播放,原则就是利用鼠标单击事件控制Canvas的显示/隐藏以及调用MediaElement的Play(),Pause()方法
2.进度条与播放时间的同步,这里用到了Timer控件,每隔一定时间重新设置进度条的值
3.播放列表采用json字符串解析后绑定实现,同时选择列表的相关视频后,马上播放选择的视频
4.全屏功能
5.静音功能(其实还可以方便左右声道功能,只要不知道界面上怎么放,所以这一块功能没加上去)
6.缓冲以及加载进度的百分比进度显示
7.播放时,预先加载下一段视频(这一块好象效果不明显,主要是对silverlight的缓冲机制不清楚,期待大家共同探讨改进)

另:本示例中用的视频全部为mp4格式的h.264视频

其它不清楚的地方,基本上代码中都有注释


xaml代码:


 1 < UserControl  x:Class ="Test.MainPage"
 2     xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
 3     xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
 4     xmlns:d ="http://schemas.microsoft.com/expression/blend/2008"  xmlns:mc ="http://schemas.openxmlformats.org/markup-compatibility/2006"  
 5     mc:Ignorable ="d" >
 6      < Grid  x:Name ="LayoutRoot"  ShowGridLines ="False"    >
 7
 8          <!-- Grid布局:分成三行,第一行放视频窗口,第二行为进度条,第三行为其它控制按钮 -->
 9          < Grid.ColumnDefinitions >
10              < ColumnDefinition  Width ="*" ></ ColumnDefinition >            
11          </ Grid.ColumnDefinitions >
12
13          < Grid.RowDefinitions >
14              < RowDefinition  Height ="*" ></ RowDefinition >
15              < RowDefinition  Height ="22" ></ RowDefinition >
16              < RowDefinition  Height ="25" ></ RowDefinition >
17          </ Grid.RowDefinitions >
18
19
20          <!-- 视频播放控件 -->
21          < MediaElement  x:Name ="media"  Source =""  Grid.Row ="0"   Grid.Column ="0"  CurrentStateChanged ="Media_State_Changed"  MediaEnded ="media_MediaEnded"  Cursor ="Hand"  MouseLeftButtonDown ="media_MouseLeftButtonDown"  BufferingProgressChanged ="media_BufferingProgressChanged"  DownloadProgressChanged ="media_DownloadProgressChanged" ></ MediaElement >
22
23          <!-- 这里用一个Canvas来实现暂停时的遮盖效果 -->
24          < Canvas  Background ="#AAFAEBD7"   Grid.Row ="0"  Grid.Column ="0"   Cursor ="Hand"   x:Name ="canvas_Pause"  MouseLeftButtonDown ="Canvas_MouseLeftButtonDown"   >
25              < Ellipse  Height ="200"  Width ="200"  Stroke ="AliceBlue"  StrokeThickness ="10"  Canvas.Left ="140"  Canvas.Top ="80" ></ Ellipse >
26              < Path  Stretch ="Fill"  Stroke ="AliceBlue"  StrokeThickness ="10"  Height ="98"  Width ="10"  UseLayoutRounding ="False"  Canvas.Left ="203"  Canvas.Top ="131"  Data ="M208,136 L208,224" />
27              < Path  Stretch ="Fill"  Stroke ="AliceBlue"  StrokeThickness ="10"  Height ="98"  Width ="10"  UseLayoutRounding ="False"  Canvas.Left ="263"  Canvas.Top ="131"  Data ="M208,136 L208,224" />
28
29              < TextBlock  Canvas.Left ="104"  Canvas.Top ="296"  Foreground ="White"   > Made by 菩提树下的杨过(http://yjmyzz.cnblogs.com/) </ TextBlock >
30          </ Canvas >
31         
32          < MediaElement  x:Name ="mediaBuffer"  Width ="0"  Grid.Column ="0"  Grid.Row ="0"  BufferingTime ="0:0:10"  IsMuted ="True"  AutoPlay ="True"    ></ MediaElement >
33
34          <!-- 第二行用一个StackPanel横向放了二个子控件,用于显示进度条和当前播放时间 -->
35          < StackPanel  Grid.Column ="0"  Grid.Row ="1"  Orientation ="Horizontal"   HorizontalAlignment ="Center"   >
36              < Slider  Height ="20"  Width ="370"  x:Name ="sliderProgress"  ValueChanged ="sliderProgress_ValueChanged"  Cursor ="Hand"   ></ Slider >
37              < TextBlock  Text ="00:00:00/00:00:00"  Width ="110"  x:Name ="txtTime" />
38          </ StackPanel >
39
40          <!-- 第三行同样用StackPanel横向放置其它控制按钮 -->
41          < StackPanel  Grid.Column ="0"  Grid.Row ="2"  Orientation ="Horizontal"  HorizontalAlignment ="Center"   >
42              < Button  Click ="PlayMedia"   Content ="||"  Width ="25"  Height ="25"  x:Name ="btnPlay"  Cursor ="Hand"   />
43              < Button  Click ="StopMedia"   Content ="■"  Width ="25"  Height ="25"  x:Name ="btnStop"  Cursor ="Hand" />
44              < TextBlock  x:Name ="txtProgress"    FontSize ="12"  Width ="90"  Text ="缓冲中100%"  Height ="25"  TextAlignment ="Center"  Margin ="3,0"   Padding ="0,6,0,0"    ></ TextBlock >
45              < ComboBox  x:Name ="cboList"  SelectionChanged ="cboList_SelectionChanged"  Height ="25"  Width ="232" >
46             
47              </ ComboBox >
48              < Button  Content ="静"  Width ="25"  Height ="25"  Margin ="3,0"  x:Name ="btnVoice"  Click ="btnVoice_Click"  Cursor ="Hand" ></ Button >
49              < Slider  Height ="25"  Width ="50"  x:Name ="sliderVoice"  Maximum ="1"  Minimum ="0"  ValueChanged ="sliderVoice_ValueChanged"  Value ="0.5"  Cursor ="Hand"   ></ Slider >
50              < Button  Content ="全"  Width ="20"  Height ="25"  Cursor ="Hand"  x:Name ="btnFull"  Click ="btnFull_Click" ></ Button >
51          </ StackPanel >
52
53      </ Grid >
54 </ UserControl >
55

后端cs代码:
  1 using  System;
  2 using  System.Collections.Generic;
  3 using  System.Json;
  4 using  System.Windows;
  5 using  System.Windows.Controls;
  6 using  System.Windows.Input;
  7 using  System.Windows.Interop;
  8 using  System.Windows.Threading;
  9
 10 namespace  Test
 11 {
 12
 13
 14    public partial class MainPage : UserControl
 15    {
 16        private DispatcherTimer _timerPlay;
 17
 18        //实际应用中,以下字符串可通过wcf调用获得
 19        private string _medialist = "[{src:'http://task.24city.com/video/01.mp4',name:'苹果王手机第1段'},{src:'http://task.24city.com/video/02.mp4',name:'苹果王手机第2段'},{src:'http://task.24city.com/video/03.mp4',name:'苹果王手机第3段'},{src:'http://task.24city.com/video/04.mp4',name:'蔡依林-柠檬草的味道'},{src:'http://task.24city.com/video/05.mp4',name:'我也不知道是啥'},{src:'http://task.24city.com/video/06.mp4',name:'游戏宣传片段'}]";
 20
 21        List<MediaItem> _listMedia = null;
 22
 23        int _currentIndex = -1;//正在播放的元素索引
 24
 25
 26        public MainPage()
 27        {
 28            InitializeComponent();
 29
 30            //解析Json
 31            JsonValue _jsValue = JsonArray.Parse(_medialist);
 32
 33            if (_jsValue.Count > 0)
 34            {
 35                _listMedia = new List<MediaItem>(_jsValue.Count);
 36
 37                for (int i = 0; i < _jsValue.Count; i++)
 38                {
 39                    _listMedia.Add(new MediaItem() { src = _jsValue[i]["src"], name = _jsValue[i]["name"] });
 40                }

 41
 42                _currentIndex = 0;//默认从第一个开始播放
 43                media.Source = new Uri(_listMedia[_currentIndex].src);                
 44
 45                cboList.ItemsSource = _listMedia;
 46                cboList.DisplayMemberPath = "name";
 47                cboList.SelectedIndex = _currentIndex;
 48
 49
 50                this._timerPlay = new DispatcherTimer();
 51                this._timerPlay.Interval = new TimeSpan(0000100);
 52                this._timerPlay.Tick += new EventHandler(timer_Tick);
 53                this._timerPlay.Start();
 54            }

 55
 56
 57            App.Current.Host.Content.FullScreenChanged += new EventHandler(Content_FullScreenChanged);
 58
 59
 60        }

 61
 62        /// <summary>
 63        /// timer触发时,设置进度条与播放时间同步
 64        /// </summary>
 65        /// <param name="sender"></param>
 66        /// <param name="e"></param>

 67        void timer_Tick(object sender, EventArgs e)
 68        {
 69            this.sliderProgress.Maximum = this.media.NaturalDuration.TimeSpan.TotalSeconds;
 70
 71            this.sliderProgress.ValueChanged -= new RoutedPropertyChangedEventHandler<double>(sliderProgress_ValueChanged);
 72
 73            this.sliderProgress.Value = this.media.Position.TotalSeconds;
 74
 75            this.sliderProgress.ValueChanged += new RoutedPropertyChangedEventHandler<double>(sliderProgress_ValueChanged);
 76
 77            this.txtTime.Text = media.Position.Hours.ToString().PadLeft(2'0'+ ":" + media.Position.Minutes.ToString().PadLeft(2'0'+ ":" + media.Position.Seconds.ToString().PadLeft(2'0'+ "/" + media.NaturalDuration.TimeSpan.Hours.ToString().PadLeft(2'0'+ ":" + media.NaturalDuration.TimeSpan.Minutes.ToString().PadLeft(2'0'+ ":" + media.NaturalDuration.TimeSpan.Seconds.ToString().PadLeft(2'0');
 78        }

 79
 80        /// <summary>
 81        /// 显示播放状态
 82        /// </summary>
 83        /// <param name="sender"></param>
 84        /// <param name="e"></param>

 85        private void Media_State_Changed(object sender, EventArgs e)
 86        {
 87           
 88            if (_currentIndex >= 0)
 89            {
 90                MediaItem _currentMedia = _listMedia[_currentIndex];
 91
 92                switch (media.CurrentState)
 93                {
 94                    case System.Windows.Media.MediaElementState.AcquiringLicense:
 95                        txtProgress.Text = "加载许可证";
 96                       
 97                        break;
 98                    case System.Windows.Media.MediaElementState.Buffering:
 99                        txtProgress.Text = "缓冲中";                        
100                        break;
101                    case System.Windows.Media.MediaElementState.Closed:
102                        txtProgress.Text = "已关闭";
103                        break;
104                    case System.Windows.Media.MediaElementState.Individualizing:
105                        txtProgress.Text = "加载个性化设置";
106                        break;
107                    case System.Windows.Media.MediaElementState.Opening:
108                        txtProgress.Text = "加载中";
109                        break;
110                    case System.Windows.Media.MediaElementState.Paused:
111                        txtProgress.Text = "已暂停";
112                        break;
113                    case System.Windows.Media.MediaElementState.Playing:
114                        txtProgress.Text = "正在播放";  
115
116                        //预选缓冲下一段视频(不过在实际测试中,感觉这么干没啥明显效果,欢迎大家共同探讨如何提前缓冲下一段视频)
117                        if (_currentIndex + 1 > _listMedia.Count - 1)
118                        {
119                            mediaBuffer.Source = new Uri(_listMedia[0].src);
120                        }

121                        else 
122                        {
123                            mediaBuffer.Source = new Uri(_listMedia[_currentIndex + 1].src);
124                        }

125                     
126                        break;
127                    case System.Windows.Media.MediaElementState.Stopped:
128                        txtProgress.Text = "已停止";
129                        break;
130                    default:
131                        break;
132                }

133            }

134
135        }

136
137
138        /// <summary>
139        /// 停止播放
140        /// </summary>
141        /// <param name="sender"></param>
142        /// <param name="e"></param>

143        private void StopMedia(object sender, System.Windows.RoutedEventArgs e)
144        {
145            media.Stop();
146            btnPlay.Content = ">";
147
148        }

149
150       
151
152        /// <summary>
153        /// 播放/暂停
154        /// </summary>
155        /// <param name="sender"></param>
156        /// <param name="e"></param>

157        private void PlayMedia(object sender, System.Windows.RoutedEventArgs e)
158        {           
159
160            if (media.CurrentState == System.Windows.Media.MediaElementState.Paused || media.CurrentState == System.Windows.Media.MediaElementState.Stopped)
161            {
162                media.Play();
163                btnPlay.Content = "||";
164                canvas_Pause.Visibility = Visibility.Collapsed;
165                
166            }

167            else 
168            {
169                media.Pause();
170                btnPlay.Content = ">";
171                canvas_Pause.Visibility = Visibility.Visible;
172            }

173            
174        }

175
176        /// <summary>
177        /// 一段播放完毕后,自动跳到下一段
178        /// </summary>
179        /// <param name="sender"></param>
180        /// <param name="e"></param>

181        private void media_MediaEnded(object sender, System.Windows.RoutedEventArgs e)
182        {
183            _currentIndex++;
184
185            if (_currentIndex > _listMedia.Count - 1)
186            {
187                _currentIndex = 0;
188            }

189
190            media.Source = new Uri(_listMedia[_currentIndex].src);
191
192            cboList.SelectedIndex = _currentIndex;
193        }

194
195        /// <summary>
196        /// 下拉列表改变时,播放相关片段
197        /// </summary>
198        /// <param name="sender"></param>
199        /// <param name="e"></param>

200        private void cboList_SelectionChanged(object sender, SelectionChangedEventArgs e)
201        {
202            _currentIndex = cboList.SelectedIndex;
203            if (_currentIndex > _listMedia.Count - 1)
204            {
205                _currentIndex = 0;
206            }

207
208            media.Source = new Uri(_listMedia[_currentIndex].src);
209            canvas_Pause.Visibility = System.Windows.Visibility.Collapsed;
210            media.Position = new TimeSpan(0,0,0,0,0);
211            sliderProgress.Value = 0;
212        }

213
214        /// <summary>
215        /// 暂时Canvas点击后,隐藏Canvas,同时继续播放
216        /// </summary>
217        /// <param name="sender"></param>
218        /// <param name="e"></param>

219        private void Canvas_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
220        {
221            canvas_Pause.Visibility = System.Windows.Visibility.Collapsed;
222            media.Play();
223        }

224
225        /// <summary>
226        /// 视频画面单击时,暂时播放
227        /// </summary>
228        /// <param name="sender"></param>
229        /// <param name="e"></param>

230        private void media_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
231        {
232            canvas_Pause.Visibility = System.Windows.Visibility.Visible;
233            media.Pause();
234        }

235
236        /// <summary>
237        /// 进度条拖动时,跳到相关位置
238        /// </summary>
239        /// <param name="sender"></param>
240        /// <param name="e"></param>

241        private void sliderProgress_ValueChanged(object sender, System.Windows.RoutedPropertyChangedEventArgs<double> e)
242        {
243            this.media.Position = new TimeSpan((long)(e.NewValue * 1000 * 1000 * 10));
244        }

245
246
247        //private void media_BufferingProgressChanged(object sender, RoutedEventHandler e) 
248        //{
249        //    txtTime.Text = "缓冲中" + media.BufferingProgress.ToString("F0") + "%";
250        //}
251
252        /// <summary>
253        /// 静音按钮的实现
254        /// </summary>
255        /// <param name="sender"></param>
256        /// <param name="e"></param>

257        private void btnVoice_Click(object sender, RoutedEventArgs e)
258        {
259            if (media.IsMuted)
260            {
261                media.IsMuted = false;
262                this.btnVoice.Content = "";
263                sliderVoice.IsEnabled = true;
264            }

265            else 
266            {
267                media.IsMuted = true;
268                this.btnVoice.Content = "";
269                sliderVoice.IsEnabled = false;
270            }

271
272        }

273
274        /// <summary>
275        /// 调整音量大小
276        /// </summary>
277        /// <param name="sender"></param>
278        /// <param name="e"></param>

279        private void sliderVoice_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
280        {
281            if (sliderVoice == null)
282            {
283                return;
284            }

285            media.Volume = sliderVoice.Value;
286        }

287
288        private void btnFull_Click(object sender, RoutedEventArgs e)
289        {
290            Content contentObj = App.Current.Host.Content;
291            contentObj.IsFullScreen = !contentObj.IsFullScreen;
292
293           
294        }

295
296
297
298        private void Content_FullScreenChanged(object sender, EventArgs e) 
299        {
300            Content contentObj = App.Current.Host.Content;
301           
302            if (contentObj.IsFullScreen)
303            {
304                btnFull.Content = "退";
305            }

306            else
307            {
308                btnFull.Content = "";
309            }

310        }

311
312        /// <summary>
313        /// 显示缓冲进度
314        /// </summary>
315        /// <param name="sender"></param>
316        /// <param name="e"></param>

317        private void media_BufferingProgressChanged(object sender, RoutedEventArgs e)
318        {
319            this.txtProgress.Text = "缓冲中" + (media.BufferingProgress*100).ToString("F0"+ "%";
320            canvas_Pause.Visibility = Visibility.Visible;
321            if (media.BufferingProgress >= 1.0
322            {
323                canvas_Pause.Visibility = Visibility.Collapsed;
324                switch (media.CurrentState)
325                {
326                    case System.Windows.Media.MediaElementState.Buffering:
327                        txtProgress.Text = "缓冲中";
328                        break;
329                    case System.Windows.Media.MediaElementState.Closed:
330                        txtProgress.Text = "已关闭";
331                        break;
332                    case System.Windows.Media.MediaElementState.Paused:
333                        txtProgress.Text = "已暂停";
334                        break;
335                    case System.Windows.Media.MediaElementState.Playing:
336                        txtProgress.Text = "正在播放";
337                        break;
338                    case System.Windows.Media.MediaElementState.Stopped:
339                        txtProgress.Text = "已停止";
340                        break;
341                    default:
342                        txtProgress.Text = "就绪";
343                        break;
344                }

345            }

346        }

347
348        /// <summary>
349        /// 显示加载进度
350        /// </summary>
351        /// <param name="sender"></param>
352        /// <param name="e"></param>

353        private void media_DownloadProgressChanged(object sender, RoutedEventArgs e)
354        {
355            txtProgress.Text = "加载中" + (media.DownloadProgress * 100).ToString("F0"+ "%";
356            if (media.DownloadProgress >= 1
357            {
358                switch (media.CurrentState)
359                {                   
360                    case System.Windows.Media.MediaElementState.Buffering:
361                        txtProgress.Text = "缓冲中";
362                        break;
363                    case System.Windows.Media.MediaElementState.Closed:
364                        txtProgress.Text = "已关闭";
365                        break;                  
366                    case System.Windows.Media.MediaElementState.Paused:
367                        txtProgress.Text = "已暂停";
368                        break;
369                    case System.Windows.Media.MediaElementState.Playing:
370                        txtProgress.Text = "正在播放";
371                        break;
372                    case System.Windows.Media.MediaElementState.Stopped:
373                        txtProgress.Text = "已停止";
374                        break;
375                    default:
376                        txtProgress.Text = "就绪";
377                        break;
378                }

379            }

380        }

381
382      
383
384
385    }

386
387
388    /// <summary>
389    /// 媒体元素Item自定义类
390    /// </summary>

391    public class MediaItem
392    {
393        public string src setget; }
394        public string name setget; }
395    }

396}

397

目录
相关文章
|
缓存 Android开发
教你使用超简单的视频播放器JiaoZiVideoPlayer
教你使用超简单的视频播放器JiaoZiVideoPlayer
1380 0
教你使用超简单的视频播放器JiaoZiVideoPlayer
|
Android开发 Java 编解码
安卓音视频播放器
安卓音视频播放器 随着短视频的发展,短视频的需求越来越复杂,比如添加滤镜、特效、字幕、贴纸等越来越多的功能都将添加到短视频编辑的功能里面。 为了能够实时预览我们想要的效果,我们一般都需要自研播放器。
1597 0
|
C# 编解码 Windows
WPF播放视频
原文:WPF播放视频 在现在的项目中需要使用到播放视频的功能,本来打算使用VLC来做的。后来发现WPF 4.0之后新增了MediaElement类,可以实现视频播放。 ...
2086 0