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;
}
}
}