zoukankan      html  css  js  c++  java
  • 闲来无事,倒腾了一个简单的silverlight视频播放器

    近二日闲来无事,把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代码:
      1using System;
      2using System.Collections.Generic;
      3using System.Json;
      4using System.Windows;
      5using System.Windows.Controls;
      6using System.Windows.Input;
      7using System.Windows.Interop;
      8using System.Windows.Threading;
      9
     10namespace 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

    作者:菩提树下的杨过
    出处:http://yjmyzz.cnblogs.com
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    android-自定义View
    java
    记录-常用的开发技巧
    便签:
    zTree 树形控件 ajax动态加载数据
    jquery ajax 传数据到后台乱码的处理方法
    spring + quartz 定时
    SpringMVC + Spring + MyBatis 学习笔记:提交数据遭遇基础类型和日期类型报400错误解决方法
    复制新项目 ,tomcat部署时名字还是旧项目名
    jsp 通用获取所有表单值传后台
  • 原文地址:https://www.cnblogs.com/yjmyzz/p/1552682.html
Copyright © 2011-2022 走看看