MVVM模式基於開源VLC解碼器WPF萬能視頻播放器

採用VLC解碼器,能播放市面上幾乎所有格式影片。


Models:SysInfo.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MvvmPlayer.Models
{
    public  class SysInfo
    {
        public  string Title { get; set; }   //標題

        public string MediaFile { get; set; }   //媒體文件

        public float MediaPosition { get; set; }    //播放進度

        public string MediaTime { get; set; }  //播放時間

        //public double MediaVolume { get; set; }     //音量

        //public bool IsMute { get; set; }  //是否靜音
    }
}

ViewModels:VideoPlayerViewModel

using GalaSoft.MvvmLight;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Vlc.DotNet.Core;
using Vlc.DotNet.Wpf;
using MvvmPlayer.Models;
using System.Windows.Media;
using System.Windows.Input;
using GalaSoft.MvvmLight.Command;
using Microsoft.Win32;
using Vlc.DotNet.Core.Medias;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;

namespace MvvmPlayer.ViewModels
{
    public class VideoPlayerViewModel : ViewModelBase
    {

        #region 構造方法

        public VideoPlayerViewModel()
        {
            if (!VlcContext.IsInitialized)
                InitEncoder();
            _sysInfo = new SysInfo();
            myVideo = new VlcControl();          
	    this.Title = "作者:騰飛大俠 郵箱:[email protected]";
            this.MediaTime = "作者:騰飛大俠 郵箱:[email protected]";
this.PlayerWindowStyle = WindowStyle.ThreeDBorderWindow; this.PlayerWindowState = WindowState.Normal; this.GridVideoScaleY = 1; this.MyVideo.TimeChanged += myVideo_TimeChanged; //定義視頻播放時間改變事件 this.MyVideo.PositionChanged += myVideo_PositionChanged; //定義播放位置改變事件 } #endregion #region 初始化事件 // 播放控件拖放事件 void gridVideo_Drop(object sender, DragEventArgs e) { //獲取拖拽的文件 string fileName = ((System.Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0).ToString(); this.MyVideo.Stop(); this.MyVideo.Media = new PathMedia(fileName); System.Threading.Thread.Sleep(1); this.MyVideo.Play(); } //播放控件拖放事件 void gridVideo_DragEnter(object sender, DragEventArgs e) { //僅支持文件的拖放 if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effects = DragDropEffects.Link; else e.Effects = DragDropEffects.None; } // 窗口關閉事件 private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { VlcContext.CloseAll(); //關閉解碼器環境 } // 播放位置改變事件 private void myVideo_PositionChanged(VlcControl sender, VlcEventArgs<float> e) { if (myPositionChanging) //如果正在拖動進度條,則暫時不改變進度條的值 return; this.MediaPosition = e.Data; //改變進度條的值 } #region 進度條處理事件 // 進度條拖動事件 private bool myPositionChanging; private void sliderPosition_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) { myPositionChanging = true; //位置改變設置爲true this.MediaPosition = (float)sliderPosition.Value; //媒體進度值等於進度條的值 this.MyVideo.PositionChanged -= myVideo_PositionChanged; //刪除播放位置改變事件 } // 完成拖播放進度條 private void sliderPosition_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e) { this.MyVideo.Position = (float)sliderPosition.Value; //設置播放進度,等於進度條的值 this.MyVideo.PositionChanged += myVideo_PositionChanged; //添加播放位置改變事件 myPositionChanging = false; } // 進度條值改變 void sliderPosition_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { this.MediaPosition = (float)e.NewValue; //設置播放位置 } #endregion // 鼠標移動時,顯示播放進度條 DispatcherTimer timer1 = null; void gridVideo_MouseMove(object sender, MouseEventArgs e) { if (timer1 == null) { timer1 = new DispatcherTimer(); } if (this.PlayerWindowState == WindowState.Maximized) //判斷窗口是否爲最大化 { SliderPositionVisibility = Visibility.Visible; //顯示播放進度條 Mouse.OverrideCursor = null; //恢復鼠標顯示 timer1.Interval = TimeSpan.FromSeconds(4); //鼠標4秒不動,自動隱藏 timer1.Tick += (s, e1) => { SliderPositionVisibility = Visibility.Hidden; //隱藏播放進度條 Mouse.OverrideCursor = Cursors.None; //隱藏鼠標 timer1.IsEnabled=false; //禁用計時器 }; timer1.IsEnabled=true; } else if(this.playerWindowState==WindowState.Normal) { timer1.IsEnabled=false; SliderPositionVisibility = Visibility.Visible; //顯示進度條 Mouse.OverrideCursor = null; //恢復鼠標顯示 } } // 播放時間改變 private void myVideo_TimeChanged(VlcControl sender, VlcEventArgs<TimeSpan> e) { var duration = this.MyVideo.Media == null ? TimeSpan.Zero : this.MyVideo.Media.Duration; var time = TimeSpan.FromMilliseconds(duration.TotalMilliseconds * this.MediaPosition); //顯示播放時間 this.MediaTime = string.Format("時間:" + "{0:00}:{1:00}:{2:00}/{3:00}:{4:00}:{5:00}", time.Hours, time.Minutes, time.Seconds, duration.Hours, duration.Minutes, duration.Seconds ); //設置媒體時間屬性 } //private void Media_ParsedChanged(MediaBase sender, VlcEventArgs<int> e) //{ // this.MediaTime = string.Format( // "時間:{0:00}:{1:00}:{2:00}", // this.MyVideo.Media.Duration.Hours, // this.MyVideo.Media.Duration.Minutes, // this.MyVideo.Media.Duration.Seconds // ); // this.MediaVolume = myVideo.AudioProperties.Volume; //} #endregion #region 初始化屬性 private double gridVideoScaleY; public double GridVideoScaleY //視頻翻轉 { get { return gridVideoScaleY; } set { gridVideoScaleY = value; RaisePropertyChanged("GridVideoScaleY"); } } private bool playerTopmost; public bool PlayerTopmost //窗口置頂 { get { return playerTopmost; } set { playerTopmost = value; RaisePropertyChanged("PlayerTopmost"); } } private WindowStyle playerWindowStyle; public WindowStyle PlayerWindowStyle //窗口樣式 { get { return playerWindowStyle; } set { playerWindowStyle = value; RaisePropertyChanged("PlayerWindowStyle"); } } private Visibility sliderPositionVisibility; public Visibility SliderPositionVisibility //進度條狀態 { get { return sliderPositionVisibility; } set { sliderPositionVisibility = value; RaisePropertyChanged("SliderPositionVisibility"); } } private Visibility ctrolPanelVisibility; public Visibility CtrolPanelVisibility //控制面板狀態 { get { return ctrolPanelVisibility; } set { ctrolPanelVisibility = value; RaisePropertyChanged("CtrolPanelVisibility"); } } private WindowState playerWindowState; public WindowState PlayerWindowState //器窗口狀態 { get { return playerWindowState; } set { if (playerWindowState != value) { playerWindowState = value; RaisePropertyChanged("PlayerWindowState"); } } } private VlcControl myVideo; public VlcControl MyVideo //定義VlcControl控件 { get { return myVideo; } } private SysInfo _sysInfo; public SysInfo SysInfo //系統信息 { get { return _sysInfo; } set { _sysInfo = value; } } public string Title //標題 { get { return SysInfo.Title; } set { SysInfo.Title = value; RaisePropertyChanged("Title"); } } public string MediaFile //媒體文件 { get { return SysInfo.MediaFile; } set { SysInfo.MediaFile = value; RaisePropertyChanged("MediaFile"); } } public float MediaPosition //播放位置 { get { return SysInfo.MediaPosition; } set { if (SysInfo.MediaPosition != value) { SysInfo.MediaPosition = value; RaisePropertyChanged("MediaPosition"); } } } public int MediaVolume //音量 { get { return MyVideo.AudioProperties.Volume; } set { if (MyVideo.AudioProperties.Volume != value) { MyVideo.AudioProperties.Volume = value; RaisePropertyChanged("MediaVolume"); } } } public string MediaTime //播放時間 { get { return SysInfo.MediaTime; } set { SysInfo.MediaTime = value; RaisePropertyChanged("MediaTime"); } } #endregion #region 初始化命令 public ICommand WindowCommand //窗體命令 { get { return new RelayCommand<RoutedEventArgs>((e) => { if (Application.Current.Properties["VideoPlayerArgName"] != null) //如果啓動的時候帶媒體參數 { string fname = Application.Current.Properties["VideoPlayerArgName"].ToString(); //ArbitraryArgName要與APP裏面設置的名字相同 this.MyVideo.Media = new PathMedia(fname); MyVideo.Play(); } Window videoPlayer=e.OriginalSource as Window; videoPlayer.Closing += Window_Closing; }); } } public ICommand TxtgridVideoScaleTransformCommand //視頻翻轉 { get { return new RelayCommand<MouseButtonEventArgs>((e) => { if (this.GridVideoScaleY == 1) { this.GridVideoScaleY = -1; } else if (this.GridVideoScaleY == -1) { this.GridVideoScaleY = 1; } }); } } Slider sliderPosition = null; public ICommand SliderPositionCommand //進度條初始化命令 { get { return new RelayCommand<RoutedEventArgs>((e) => { sliderPosition = e.OriginalSource as Slider; sliderPosition.PreviewMouseLeftButtonDown += sliderPosition_MouseLeftButtonDown; sliderPosition.PreviewMouseLeftButtonUp += sliderPosition_MouseLeftButtonUp; sliderPosition.ValueChanged += sliderPosition_ValueChanged; }); } } int i = 0; Grid gridVideo = null; public ICommand GridVideoCommand //播放控件命令 { get { return new RelayCommand<RoutedEventArgs>((e) => { gridVideo = e.OriginalSource as Grid; //獲取事件觸發源 gridVideo.MouseLeftButtonDown += gridVideo_MouseLeftButtonDown; gridVideo.DragEnter += gridVideo_DragEnter; gridVideo.Drop += gridVideo_Drop; }); } } /// <summary> /// 播放控件鼠標單擊事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void gridVideo_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { i++; DispatcherTimer timer = new DispatcherTimer(); timer.Interval = new TimeSpan(0, 0, 0, 0, 300); //雙擊間隔時間爲300毫秒 timer.Tick += (s, e1) => { timer.IsEnabled = false; i = 0; }; timer.IsEnabled = true; if (i % 2 == 0) { timer.IsEnabled = false; i = 0; if (this.PlayerWindowState != WindowState.Maximized) //雙擊全屏 { gridVideo.MouseMove += gridVideo_MouseMove; //鼠標移動事件 this.PlayerWindowStyle = WindowStyle.None; //設置窗口樣式 this.PlayerWindowState = WindowState.Maximized; //設置窗口大小 //如果想讓開始菜單顯示出來,跟上面正好相反 //this.WindowState = WindowState.Maximized; //this.WindowStyle = WindowStyle.None; this.CtrolPanelVisibility = Visibility.Collapsed; //隱藏控件 this.SliderPositionVisibility = Visibility.Collapsed; gridVideo.Margin = new Thickness(0, 0, 0, 0); //設置邊界 //gridVideo.Width = SystemParameters.WorkArea.Width; this.PlayerTopmost = true; //窗口置頂 } else if (this.playerWindowState == WindowState.Maximized) //全屏狀態下,雙擊恢復正常狀態 { timer1.IsEnabled = false; //禁用timer1,否則從全屏切換到正常狀態下,進度條會隱藏 gridVideo.MouseMove -= gridVideo_MouseMove; this.PlayerWindowState = WindowState.Normal; this.PlayerWindowStyle = WindowStyle.SingleBorderWindow; this.CtrolPanelVisibility = Visibility.Visible; this.SliderPositionVisibility = Visibility.Visible; gridVideo.Margin = new Thickness(0, 0, 0, 54); this.PlayerTopmost = false; Mouse.OverrideCursor = null; } } } public ICommand OpenMediaFile //打開 { get { return new RelayCommand(() => { this.MyVideo.Stop(); this.MediaPosition = 0; var ofd = new OpenFileDialog { FileName = "", Title = "打開媒體文件", Filter = "所有文件|*.*" }; //ofd.InitialDirectory = Environment.CurrentDirectory; ofd.RestoreDirectory = true; if (ofd.ShowDialog() != true || ofd.FileName == null) return; this.Title = System.IO.Path.GetFileName(ofd.FileName); this.MediaFile = ofd.FileName; this.MyVideo.Media = new PathMedia(this.MediaFile); //this.MyVideo.Media.ParsedChanged += Media_ParsedChanged; this.MyVideo.Play(); }); } } public ICommand PlayMedia //播放 { get { return new RelayCommand(() => { this.MyVideo.Play(); }); } } public ICommand PauseMedia //暫停 { get { return new RelayCommand(() => { this.MyVideo.Pause(); }); } } public ICommand StopMedia //停止 { get { return new RelayCommand(() => { this.MyVideo.Stop(); this.MediaPosition = 0; this.MediaTime = "作者:騰飛大俠 郵箱:[email protected]"; }); } } #endregion /// <summary> /// 初始化解碼器 /// </summary> private void InitEncoder() { #region 初始化 // 設置解碼器路徑 //VlcContext.LibVlcDllsPath = System.IO.Path.Combine(Environment.CurrentDirectory, "libs"); VlcContext.LibVlcDllsPath = @"D:\VLC"; // 設置解碼器插件路徑 //VlcContext.LibVlcPluginsPath = System.IO.Path.Combine(Environment.CurrentDirectory, @"libs\plugins"); VlcContext.LibVlcPluginsPath = @"D:\VLC\plugins"; // 忽略解碼器配置文件 VlcContext.StartupOptions.IgnoreConfig = true; // 是否記錄日誌文件 VlcContext.StartupOptions.LogOptions.LogInFile = false; // 顯示解碼器日誌控件臺 VlcContext.StartupOptions.LogOptions.ShowLoggerConsole = false; // 設置解碼器記錄日誌級別 VlcContext.StartupOptions.LogOptions.Verbosity = VlcLogVerbosities.Debug; // 顯示媒體文件名稱 VlcContext.StartupOptions.AddOption("--no-video-title-show"); // 最後一個畫面顯示播放或暫停 //VlcContext.StartupOptions.AddOption("--play-and-pause"); // 初始化解碼器 VlcContext.Initialize(); #endregion } }}

Views:VideoPlayer.xaml

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MvvmPlayer.ViewModels"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:Custom="http://www.galasoft.ch/mvvmlight"
        x:Class="MvvmPlayer.Views.VideoPlayer"
        Title="{Binding Title}" Height="600" Width="800" Icon="Application.ico" 
        Background="#FF47A2D6" WindowStyle="{Binding PlayerWindowStyle}"          
        Topmost="{Binding PlayerTopmost}"
        WindowState="{Binding PlayerWindowState}"
        WindowStartupLocation="CenterScreen">
    <Window.DataContext>
        <local:VideoPlayerViewModel/>
    </Window.DataContext>
    <!--動畫-->
	<!--<Window.Resources>
		<Storyboard x:Key="gridVideoStoryboard">
			<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="gridVideo">
				<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
				<EasingDoubleKeyFrame KeyTime="0:0:1" Value="-1"/>
				<EasingDoubleKeyFrame KeyTime="0:0:2" Value="-1"/>
				<EasingDoubleKeyFrame KeyTime="0:0:3" Value="1"/>
			</DoubleAnimationUsingKeyFrames>
		</Storyboard>
	</Window.Resources>
	<Window.Triggers>
		<EventTrigger RoutedEvent="UIElement.MouseRightButtonDown" SourceName="gridVideo">            
			<BeginStoryboard Storyboard="{StaticResource gridVideoStoryboard}" x:Name="bs1"/>
		</EventTrigger>
	</Window.Triggers>-->
    
	<Grid x:Name="VideoPanel" Background="#FF280AE8">

        <!--<Wpf:VlcControl x:Name="myVideo"/>-->
        <!--視頻播放控件-->
		<Grid x:Name="gridVideo"  Grid.Row="0" Margin="0,0,0,54" RenderTransformOrigin="0.5,0.5" AllowDrop="True" >
			<Grid.RenderTransform>
				<TransformGroup>
                    <!--視頻翻轉-->
                    <ScaleTransform x:Name="gridVideost" ScaleY="{Binding GridVideoScaleY}"/> 
					<!--<SkewTransform/>
					<RotateTransform/>
					<TranslateTransform/>-->
				</TransformGroup>
			</Grid.RenderTransform>			
			<Grid.Background>
				<VisualBrush>
					<VisualBrush.Visual>
						<Image Source="{Binding MyVideo.VideoSource}"/>
					</VisualBrush.Visual>
				</VisualBrush>
			</Grid.Background>
			<i:Interaction.Triggers>
                <i:EventTrigger EventName="Loaded" SourceName="gridVideo">
                    <Custom:EventToCommand Command="{Binding GridVideoCommand}" PassEventArgsToCommand="True" />
				</i:EventTrigger>
			</i:Interaction.Triggers>
		</Grid>
        <StackPanel x:Name="CtrolPanel" Visibility="{Binding CtrolPanelVisibility}" Height="36" Margin="0,0,0,1" VerticalAlignment="Bottom" Orientation="Horizontal">
			<StackPanel.Background>
				<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
					<GradientStop Color="#FF0E21E4" Offset="0"/>
					<GradientStop Color="White" Offset="0.474"/>
					<GradientStop Color="#FF0C1FEC" Offset="1"/>
				</LinearGradientBrush>
			</StackPanel.Background>
			<TextBlock Margin="8,5,0,0" Height="24.24" HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="13.333" Text="音量:"/>
			<Slider Width="50" x:Name="sliderVolume" Maximum="200" SmallChange="1" LargeChange="5" Margin="2,0,0,0" Height="24.24" HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="13.333" BorderThickness="0,3,0,0" Value="{Binding MediaVolume, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
            <TextBlock Text="視頻翻轉" Height="24.24" Margin="8,8,0,0" HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="13.333" x:Name="txtgridVideoScaleTransform" >
                <i:Interaction.Triggers>
				<i:EventTrigger EventName="MouseLeftButtonDown" SourceName="txtgridVideoScaleTransform">
                    <Custom:EventToCommand Command="{Binding TxtgridVideoScaleTransformCommand}" PassEventArgsToCommand="True" />
				</i:EventTrigger>
			</i:Interaction.Triggers>
            </TextBlock>
            <Button x:Name="btnOpen" Content="打開" HorizontalAlignment="Center" VerticalAlignment="Center" Width="75"  Height="24.24" FontSize="13.333" Margin="10,0,0,0" Command="{Binding OpenMediaFile}"/>
			<Button x:Name="btnPlay" Content="播放" HorizontalAlignment="Center" Margin="15,0,0,0" VerticalAlignment="Center" Width="75"  Height="24.24" FontSize="13.333" Command="{Binding PlayMedia}"/>
			<Button x:Name="btnPause" Content="暫停" HorizontalAlignment="Center" Margin="15,0,0,0" VerticalAlignment="Center" Width="75"  Height="24.24" FontSize="13.333"  Command="{Binding PauseMedia}"/>
			<Button x:Name="btnStop" Content="停止" HorizontalAlignment="Center" Margin="15,0,0,0" VerticalAlignment="Center" Width="75"   Height="24.24" FontSize="13.333" Command="{Binding StopMedia}"/>
			<TextBlock x:Name="tblTime" Height="24.24" Margin="8,8,0,0" TextWrapping="Wrap" VerticalAlignment="Center" FontSize="13.333" Text="{Binding MediaTime, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
		</StackPanel>
		<StackPanel x:Name="SliderPanel" Height="18" Margin="0,0,0,36" VerticalAlignment="Bottom">
            <Slider x:Name="sliderPosition" Visibility="{Binding SliderPositionVisibility}" VerticalAlignment="Center" Height="18" Background="{x:Null}"  Maximum="1" LargeChange="0.05" 
				SmallChange="0.01"
				Value="{Binding MediaPosition}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Loaded" SourceName="sliderPosition">
                        <Custom:EventToCommand Command="{Binding SliderPositionCommand}" PassEventArgsToCommand="True" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Slider>
                    
		</StackPanel>

	</Grid>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <Custom:EventToCommand Command="{Binding WindowCommand}" PassEventArgsToCommand="True" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Window>

App.xaml.cs:

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;

namespace MvvmPlayer
{
    /// <summary>
    /// App.xaml 的交互邏輯
    /// </summary>
    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            if (e.Args != null && e.Args.Count() > 0)   //如果參數不爲空,且參數個數大於0
            {
                this.Properties["VideoPlayerArgName"] = e.Args[0];
            }  
            Views.VideoPlayer view = new Views.VideoPlayer();
            view.Show();
            base.OnStartup(e);
        }
    }
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章