using Microsoft.WindowsAPICodePack.Shell; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Windows.Threading; namespace VideoPlayer { public enum VideoState { play, stop, pause } /// /// WenVideoPlayer.xaml 的互動邏輯 /// public partial class VideoPlayer : UserControl { public event EventHandler OnVideoComplete; public event EventHandler OnVideoStateChanged; /// 取得有總共有多少影片正在撥放 /// 撥放中的數量 public static int playingCount { get { int count = 0; foreach (VideoPlayer player in playerCreated) { if (player.IsPlaying) count++; } return count; } } public static void ReleaseAll() { VideoPlayer[] listClone = new VideoPlayer[playerCreated.Count]; playerCreated.CopyTo(listClone); foreach (VideoPlayer player in listClone) { player.ReleaseResource(); } } /// 阻擋對Player觸控的事件 public bool manipulationLocked = false; private static List playerCreated = new List(); private MediaElement mediaSource; private bool stopRequest = false; private bool progressSliderChanging = false; private DispatcherTimer toolbarHideTimer = new DispatcherTimer(); private const int timerInterval = 3000; //隱藏工具時間 private string _videoPath; private MediaTimeline mt; private bool mediaLoadComplete = false; private VideoState beginBehavier; private double videoRatio = 0; private Size videoSize = new Size(); private VideoState currentVideoState; private double videoLength; public double VideoLength { get { return videoLength; } } public bool IsPlaying { get { return !(mediaSource.Clock.IsPaused || mediaSource.Clock.CurrentState == ClockState.Stopped); } } public Size VideoSize { get { return videoSize; } } public string VideoPath { get { return _videoPath; } } public void Stop() { stop_TouchDown(null, null); } public void Play() { uxPlayButton_TouchUp(null, null); } public void Pause() { pause_TouchDown(null, null); } public void IncereaseVolume(double volume = 1) { setVolume(uxVolumeSlider.Value + volume); } public void DecressVolume(double volume = 1) { setVolume(uxVolumeSlider.Value - volume); } public void SetVolume(double volume = 1) { setVolume(volume); } public void UpdateScale(double scale) { double ratio = 1; ((ScaleTransform)uxControlPanel.RenderTransform).ScaleY = 1 / (scale); uxControlPanel.ColumnDefinitions[1].Width = new GridLength(30 / (scale * ratio), GridUnitType.Pixel); uxControlPanel.ColumnDefinitions[3].Width = new GridLength(30 / (scale * ratio), GridUnitType.Pixel); uxControlPanel.ColumnDefinitions[7].Width = new GridLength(30 / (scale * ratio), GridUnitType.Pixel); uxControlPanel.ColumnDefinitions[0].Width = new GridLength(15 / (scale * ratio), GridUnitType.Pixel); uxControlPanel.ColumnDefinitions[2].Width = new GridLength(15 / (scale * ratio), GridUnitType.Pixel); uxControlPanel.ColumnDefinitions[4].Width = new GridLength(15 / (scale * ratio), GridUnitType.Pixel); uxControlPanel.ColumnDefinitions[6].Width = new GridLength(15 / (scale * ratio), GridUnitType.Pixel); uxControlPanel.ColumnDefinitions[8].Width = new GridLength(15 / (scale * ratio), GridUnitType.Pixel); ((ScaleTransform)uxPlayButton.RenderTransform).ScaleX = 1 / scale; ((ScaleTransform)uxPlayButton.RenderTransform).ScaleY = 1 / scale; } public void ReleaseResource() { mediaSource.Clock.Completed -= Video_Completed; mediaSource.MediaOpened -= MediaSource_MediaOpened; mediaSource.Clock.CurrentTimeInvalidated -= media_CurrentTimeInvalidated; mediaSource.Clock.Controller.Stop(); mt.Source = null; mediaSource.Clock = null; mediaSource.Source = null; mediaSource = null; playerCreated.Remove(this); Console.WriteLine("WenVideoPlayer_ReleaseResource"); } public FrameworkElement DetatchController() { if (uxControlPanel.Parent is Panel parentPanel) parentPanel.Children.Remove(uxControlPanel); uxControlPanel.IsVisibleChanged += (s, e) => { if (uxControlPanel.Visibility == Visibility.Visible) { toolbarHideTimer.Stop(); toolbarHideTimer.Start(); } }; return uxControlPanel; } public VideoPlayer(Uri videoPath, VideoState beginBehavier = VideoState.play) { InitializeComponent(); currentVideoState = beginBehavier; //Stylus.SetIsPressAndHoldEnabled(this, false); //this.IsManipulationEnabled = true; _videoPath = videoPath.OriginalString; this.beginBehavier = beginBehavier; this.Unloaded += WenVideoPlayer_Unloaded; //this.MouseLeave += WenVideoPlayer_MouseLeave; //create preview image ShellFile shellFile = ShellFile.FromFilePath(_videoPath); ((Image)uxCoverImageParent.Children[0]).Source = shellFile.Thumbnail.ExtraLargeBitmapSource; //((Image)uxCoverImageParent.Children[0]).Stretch = Stretch.None; //this.Height = Convert.ToDouble(shellFile.Properties.System.Video.FrameHeight.Value); //this.Width = Convert.ToDouble(shellFile.Properties.System.Video.FrameWidth.Value); videoSize.Width = Convert.ToDouble(shellFile.Properties.System.Video.FrameWidth.Value); videoSize.Height = Convert.ToDouble(shellFile.Properties.System.Video.FrameHeight.Value); double nanoseconds = -1; Double.TryParse(shellFile.Properties.System.Media.Duration.Value.ToString(), out nanoseconds); videoLength = nanoseconds == -1 ? -1 : nanoseconds / 10000000; this.Loaded += VideoPlayer_Loaded; //add video player mediaSource = new MediaElement(); //mediaSource.Height = Convert.ToDouble(shellFile.Properties.System.Video.FrameHeight.Value); //mediaSource.Width = Convert.ToDouble(shellFile.Properties.System.Video.FrameWidth.Value); //mediaSource.Stretch = Stretch.Uniform; mt = new MediaTimeline(videoPath); mediaSource.Clock = mt.CreateClock(); mediaSource.Clock.CurrentTimeInvalidated += media_CurrentTimeInvalidated; mediaSource.Clock.Completed += Video_Completed; mediaSource.LoadedBehavior = MediaState.Stop; mediaSource.MediaOpened += MediaSource_MediaOpened; mediaSource.VerticalAlignment = VerticalAlignment.Bottom; RenderOptions.SetBitmapScalingMode(mediaSource, BitmapScalingMode.HighQuality); //mediaSource.Margin = new Thickness(0, -10, 0, -10); toolbarHideTimer.Interval = TimeSpan.FromMilliseconds(timerInterval); toolbarHideTimer.Tick += AutoHideControlTimer_Tick; uxVideoPanel.Children.Add(mediaSource); this.UpdateLayout(); playerCreated.Add(this); } private void VideoPlayer_Loaded(object sender, RoutedEventArgs e) { //video Height / Width info can get from this.Width & this.Height //videoRatio = (double)videoSize.Width / videoSize.Height; //double thisRatio = this.ActualWidth / this.ActualHeight; //if (videoRatio > thisRatio) //{ // this.Height = this.ActualWidth / videoRatio; //} //else //{ // this.Width = this.ActualHeight * videoRatio; //} uxVideoPanel.Height = this.Height; uxVideoPanel.Width = this.ActualWidth; //workaround mediaSource.Height = this.Height + 6; mediaSource.Width = this.ActualWidth + 6; } private void WenVideoPlayer_MouseLeave(object sender, RoutedEventArgs e) { return; mediaSource.Clock.Controller.Pause(); uxControlPanel.Visibility = Visibility.Collapsed; uxVolumeGrid.Visibility = Visibility.Collapsed; uxPlayButtonParent.Visibility = Visibility.Visible; } private void WenVideoPlayer_Unloaded(object sender, RoutedEventArgs e) { if (mediaSource != null) { //mediaSource.Clock.Completed -= Video_Completed; //mediaSource.MediaOpened -= MediaSource_MediaOpened; //mediaSource.Clock.CurrentTimeInvalidated -= media_CurrentTimeInvalidated; mediaSource.Clock.Controller.Stop(); mt.Source = null; //mediaSource.Clock = null; mediaSource.Source = null; //mediaSource = null; playerCreated.Remove(this); } } private void AutoHideControlTimer_Tick(object sender, EventArgs e) { uxControlPanel.Visibility = Visibility.Collapsed; uxVolumeGrid.Visibility = Visibility.Collapsed; toolbarHideTimer.Stop(); } private void Video_Completed(object sender, EventArgs e) { mediaSource.Clock.Controller.Stop(); uxControlPanel.Visibility = Visibility.Collapsed; uxVolumeGrid.Visibility = Visibility.Collapsed; if (toolbarHideTimer.IsEnabled) { toolbarHideTimer.Stop(); } uxPlayButtonParent.Visibility = Visibility.Visible; OnVideoComplete?.Invoke(this, new EventArgs()); } private void MediaSource_MediaOpened(object sender, RoutedEventArgs e) { mediaLoadComplete = true; mediaSource.Volume = uxVolumeSlider.Value / 10; //0.5; //uxVolumeSlider.Value = 5; //mt.Source.UserInfo.Count(); if (beginBehavier == VideoState.play) { Play(); } else if (beginBehavier == VideoState.stop) { mediaSource.Clock.Controller.Stop(); Stop(); } uxCoverImageParent.Visibility = Visibility.Collapsed; uxPlayButtonParent.Visibility = Visibility.Collapsed; //WenVideoPlayerIsPlaying += 1; } private void media_CurrentTimeInvalidated(object sender, EventArgs e) { if (stopRequest == true) { mediaSource.Clock.Controller.Stop(); stopRequest = false; } if (mediaSource.NaturalDuration.HasTimeSpan && mediaSource.Clock.CurrentTime != null && progressSliderChanging != true) { uxProgressSlider.Value = 10 * mediaSource.Clock.CurrentTime.Value.TotalMilliseconds / mediaSource.NaturalDuration.TimeSpan.TotalMilliseconds; } } private void uxVideoPanel_TouchDown(object sender, TouchEventArgs e) { //if (uxControlPanel.Visibility == Visibility.Collapsed) //{ // uxControlPanel.Visibility = Visibility.Visible; // toolbarHideTimer.Start(); //} //else if (uxControlPanel.Visibility == Visibility.Visible) //{ // uxControlPanel.Visibility = Visibility.Collapsed; // uxVolumeGrid.Visibility = Visibility.Collapsed; // if (toolbarHideTimer.IsEnabled) // { // toolbarHideTimer.Stop(); // } // uxPlayButtonParent.Visibility = Visibility.Visible; // mediaSource.Clock.Controller.Pause(); //} uxControlPanel.Visibility = Visibility.Visible; toolbarHideTimer.Start(); } private void pause_TouchDown(object sender, TouchEventArgs e) { if (currentVideoState != VideoState.pause) { currentVideoState = VideoState.pause; mediaSource.Clock.Controller.Pause(); uxControlPanel.Visibility = Visibility.Collapsed; uxVolumeGrid.Visibility = Visibility.Collapsed; uxPlayButtonParent.Visibility = Visibility.Visible; OnVideoStateChanged?.Invoke(this, VideoState.pause); } } private void stop_TouchDown(object sender, TouchEventArgs e) { if (currentVideoState != VideoState.stop) { currentVideoState = VideoState.stop; if (mediaLoadComplete == true) { mediaSource.Clock.Controller.Stop(); uxControlPanel.Visibility = Visibility.Collapsed; uxVolumeGrid.Visibility = Visibility.Collapsed; if (toolbarHideTimer.IsEnabled) { toolbarHideTimer.Stop(); } uxPlayButtonParent.Visibility = Visibility.Visible; uxCoverImageParent.Visibility = Visibility.Visible; } else { beginBehavier = VideoState.stop; } OnVideoStateChanged?.Invoke(this, VideoState.stop); } } private void uxPlayButton_TouchUp(object sender, TouchEventArgs e) { if (currentVideoState != VideoState.play) { currentVideoState = VideoState.play; uxPlayButtonParent.Visibility = Visibility.Collapsed; uxControlPanel.Visibility = Visibility.Collapsed; uxVolumeGrid.Visibility = Visibility.Collapsed; if (toolbarHideTimer.IsEnabled) { toolbarHideTimer.Stop(); } if (mediaSource.Clock.CurrentState == ClockState.Stopped) { mediaSource.Clock.Controller.Pause(); mediaSource.Clock.Controller.Resume(); mediaSource.Clock.Controller.Begin(); } else if (mediaSource.Clock.CurrentState == ClockState.Filling) { uxCoverImageParent.Visibility = Visibility.Collapsed; return; } if (mediaLoadComplete == false) { mediaSource.Clock.Controller.Begin(); beginBehavier = VideoState.play; return; } if (mediaSource.Clock.IsPaused == true) { mediaSource.Clock.Controller.Resume(); } else { mediaSource.Clock.Controller.Begin(); } uxCoverImageParent.Visibility = Visibility.Collapsed; OnVideoStateChanged?.Invoke(this, VideoState.play); } } private void uxProgressSlider_TouchDown(object sender, TouchEventArgs e) { progressSliderChanging = true; mediaSource.Clock.Controller.Pause(); Point pt = e.GetTouchPoint((UIElement)sender).Position; uxProgressSlider.Value = uxProgressSlider.Maximum * (pt.X) / uxProgressSlider.ActualWidth; e.Handled = true; Console.WriteLine("uxProgressSlider_TouchDown"); } private void uxProgressSlider_TouchUp(object sender, TouchEventArgs e) { progressSliderChanging = false; mediaSource.Clock.Controller.Resume(); } private void uxProgressSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { if (progressSliderChanging == true) { mediaSource.Clock.Controller.SeekAlignedToLastTick(new TimeSpan((long)(mediaSource.NaturalDuration.TimeSpan.Ticks * uxProgressSlider.Value / 10)), new System.Windows.Media.Animation.TimeSeekOrigin()); } } private void uxProgressSlider_TouchMove(object sender, TouchEventArgs e) { progressSliderChanging = true; if (mediaSource.Clock.IsPaused == false) { mediaSource.Clock.Controller.Pause(); } Point pt = e.GetTouchPoint((UIElement)sender).Position; uxProgressSlider.Value = uxProgressSlider.Maximum * (pt.X) / uxProgressSlider.ActualWidth; e.Handled = true; } private void Global_TouchUp(object sender, TouchEventArgs e) { if (progressSliderChanging == true) { progressSliderChanging = false; mediaSource.Clock.Controller.Resume(); } if (e.Source is Grid && ((Grid)e.Source) == uxPlayButtonParent) { uxPlayButton_TouchUp(sender, e); } else if (toolbarHideTimer.IsEnabled == true) { toolbarHideTimer.Stop(); toolbarHideTimer.Start(); } } private void uxSound_TouchDown(object sender, TouchEventArgs e) { if (uxVolumeGrid.Visibility == Visibility.Collapsed) { uxVolumeGrid.Visibility = Visibility.Visible; ((Storyboard)FindResource("sbShowVolSlider")).Begin(); } else { Storyboard sbBuf = ((Storyboard)FindResource("sbHideVolSlider")); sbBuf.Completed += delegate (object s, EventArgs se) { uxVolumeGrid.Visibility = Visibility.Collapsed; }; sbBuf.Begin(); } } private void uxVolumeGrid_TouchDown(object sender, TouchEventArgs e) { e.Handled = true; } private void uxVolumeGrid_TouchMove(object sender, TouchEventArgs e) { e.Handled = true; } private void uxVolumeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { setVolume(e.NewValue); } private void setVolume(double volume) { if (uxVolumeSlider.Value != volume) { uxVolumeSlider.Value = volume; if (volume == 0) { uxNoSound.Visibility = Visibility.Visible; uxSound.Visibility = Visibility.Collapsed; } else if (uxNoSound.Visibility == Visibility.Visible) //and e.NewValue != 0 { uxNoSound.Visibility = Visibility.Collapsed; uxSound.Visibility = Visibility.Visible; } } if (mediaSource != null && mediaSource.IsLoaded) { mediaSource.Volume = volume / 10; } } private void ResetTimer(object sender, TouchEventArgs e) { if (toolbarHideTimer.IsEnabled == true) { toolbarHideTimer.Stop(); toolbarHideTimer.Start(); } } private void Grid_PreviewTouchUp(object sender, TouchEventArgs e) { if (manipulationLocked == true) { e.Handled = true; return; } } private void uxVolumeSlider_TouchDown(object sender, TouchEventArgs e) { Point pt = e.GetTouchPoint((UIElement)sender).Position; uxVolumeSlider.Value = uxVolumeSlider.Maximum * (uxVolumeSlider.ActualHeight - pt.Y) / uxVolumeSlider.ActualHeight; e.Handled = true; } private void uxVolumeSlider_TouchMove(object sender, TouchEventArgs e) { Point pt = e.GetTouchPoint((UIElement)sender).Position; uxVolumeSlider.Value = uxVolumeSlider.Maximum * (uxVolumeSlider.ActualHeight - pt.Y) / uxVolumeSlider.ActualHeight; //e.Handled = true; } } }