mirror of
https://github.com/QL-Win/QuickLook.git
synced 2026-05-09 02:07:50 +08:00
@@ -28,10 +28,12 @@ using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Animation;
|
||||
@@ -45,6 +47,9 @@ namespace QuickLook.Plugin.VideoViewer;
|
||||
|
||||
public partial class ViewerPanel : UserControl, IDisposable, INotifyPropertyChanged
|
||||
{
|
||||
private DispatcherTimer timer;
|
||||
private bool IsSeeked;
|
||||
|
||||
private readonly ContextObject _context;
|
||||
private BitmapSource _coverArt;
|
||||
private DispatcherTimer _lyricTimer;
|
||||
@@ -55,6 +60,7 @@ public partial class ViewerPanel : UserControl, IDisposable, INotifyPropertyChan
|
||||
private bool _isPlaying;
|
||||
private bool _wasPlaying;
|
||||
private bool _shouldLoop;
|
||||
private readonly bool isArm64 = RuntimeInformation.ProcessArchitecture == Architecture.Arm64;
|
||||
|
||||
public ViewerPanel(ContextObject context)
|
||||
{
|
||||
@@ -66,25 +72,41 @@ public partial class ViewerPanel : UserControl, IDisposable, INotifyPropertyChan
|
||||
|
||||
_context = context;
|
||||
|
||||
mediaElement.MediaUriPlayer.LAVFilterDirectory =
|
||||
IntPtr.Size == 8 ? @"LAVFilters-x64\" : @"LAVFilters-x86\";
|
||||
|
||||
//ShowViedoControlContainer(null, null);
|
||||
viewerPanel.PreviewMouseMove += ShowViedoControlContainer;
|
||||
|
||||
mediaElement.MediaUriPlayer.PlayerStateChanged += PlayerStateChanged;
|
||||
mediaElement.MediaOpened += MediaOpened;
|
||||
mediaElement.MediaEnded += MediaEnded;
|
||||
mediaElement.MediaFailed += MediaFailed;
|
||||
|
||||
if (isArm64)
|
||||
{
|
||||
InitializeArm64();
|
||||
} else
|
||||
{
|
||||
InitializeDefault();
|
||||
}
|
||||
|
||||
ShouldLoop = SettingHelper.Get("ShouldLoop", false, "QuickLook.Plugin.VideoViewer");
|
||||
|
||||
buttonPlayPause.Click += TogglePlayPause;
|
||||
buttonLoop.Click += ToggleShouldLoop;
|
||||
buttonTime.Click += (_, _) => buttonTime.Tag = (string)buttonTime.Tag == "Time" ? "Length" : "Time";
|
||||
buttonMute.Click += (_, _) => volumeSliderLayer.Visibility = Visibility.Visible;
|
||||
volumeSliderLayer.MouseDown += (_, _) => volumeSliderLayer.Visibility = Visibility.Collapsed;
|
||||
|
||||
|
||||
PreviewMouseWheel += (_, e) => ChangeVolume(e.Delta / 120d * 0.04d);
|
||||
}
|
||||
|
||||
private void InitializeDefault()
|
||||
{
|
||||
sliderProgress.Visibility = Visibility.Visible;
|
||||
buttonTime.Visibility = Visibility.Visible;
|
||||
|
||||
mediaElement.MediaUriPlayer.LAVFilterDirectory = (IntPtr.Size == 8 ? @"LAVFilters-x64\" : @"LAVFilters-x86\");
|
||||
mediaElement.MediaUriPlayer.PlayerStateChanged += PlayerStateChanged;
|
||||
mediaElement.MediaOpened += MediaOpened;
|
||||
mediaElement.MediaEnded += MediaEnded;
|
||||
mediaElement.MediaFailed += MediaFailed;
|
||||
|
||||
buttonTime.Click += (_, _) => buttonTime.Tag = (string)buttonTime.Tag == "Time" ? "Length" : "Time";
|
||||
sliderProgress.PreviewMouseDown += (_, e) =>
|
||||
{
|
||||
_wasPlaying = mediaElement.IsPlaying;
|
||||
@@ -94,8 +116,66 @@ public partial class ViewerPanel : UserControl, IDisposable, INotifyPropertyChan
|
||||
{
|
||||
if (_wasPlaying) mediaElement.Play();
|
||||
};
|
||||
}
|
||||
|
||||
PreviewMouseWheel += (_, e) => ChangeVolume(e.Delta / 120d * 0.04d);
|
||||
private void InitializeArm64()
|
||||
{
|
||||
sliderProgressWPF.Visibility = Visibility.Visible;
|
||||
buttonTimeWPF.Visibility = Visibility.Visible;
|
||||
|
||||
mediaElementWPF.MediaOpened += MediaOpened;
|
||||
mediaElementWPF.MediaEnded += MediaEnded;
|
||||
|
||||
buttonTimeWPF.Click += (_, _) => buttonTimeWPF.Tag = (string)buttonTimeWPF.Tag == "Time" ? "Length" : "Time";
|
||||
|
||||
|
||||
timer = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromSeconds(1)
|
||||
};
|
||||
timer.Tick += Seek_Timer;
|
||||
timer.Start();
|
||||
|
||||
buttonTimeWPF.Click += (_, _) => buttonTime.Tag = (string)buttonTime.Tag == "Time" ? "Length" : "Time";
|
||||
|
||||
sliderProgressWPF.PreviewMouseDown += (_, e) =>
|
||||
{
|
||||
_wasPlaying = IsPlaying;
|
||||
mediaElementWPF.Pause();
|
||||
};
|
||||
sliderProgressWPF.PreviewMouseUp += (_, _) =>
|
||||
{
|
||||
if (_wasPlaying) mediaElementWPF.Play();
|
||||
};
|
||||
|
||||
IsSeeked = false;
|
||||
}
|
||||
|
||||
private void Seek_Timer(object sender, EventArgs e)
|
||||
{
|
||||
if ((mediaElementWPF.Source != null) && (mediaElementWPF.NaturalDuration.HasTimeSpan) && (!IsSeeked))
|
||||
{
|
||||
sliderProgressWPF.Minimum = 0;
|
||||
sliderProgressWPF.Maximum = mediaElementWPF.NaturalDuration.TimeSpan.TotalSeconds;
|
||||
sliderProgressWPF.Value = mediaElementWPF.Position.TotalSeconds;
|
||||
|
||||
}
|
||||
}
|
||||
private void Seek_Drag_Started(object sender, DragStartedEventArgs e)
|
||||
{
|
||||
IsSeeked = true;
|
||||
}
|
||||
private void Seek_Drag_Completed(object sender, DragCompletedEventArgs e)
|
||||
{
|
||||
IsSeeked = false;
|
||||
mediaElementWPF.Position = TimeSpan.FromSeconds(sliderProgressWPF.Value);
|
||||
}
|
||||
private void Seek_Value_Changed(object sender, RoutedPropertyChangedEventArgs<double> e)
|
||||
{
|
||||
if ((string)buttonTimeWPF.Tag == "Time")
|
||||
textProgress.Text = TimeSpan.FromSeconds(sliderProgressWPF.Value).ToString(@"hh\:mm\:ss");
|
||||
else
|
||||
textProgress.Text = TimeSpan.FromSeconds(sliderProgressWPF.Maximum).ToString(@"hh\:mm\:ss");
|
||||
}
|
||||
|
||||
private partial void LoadAndInsertGlassLayer();
|
||||
@@ -130,6 +210,12 @@ public partial class ViewerPanel : UserControl, IDisposable, INotifyPropertyChan
|
||||
if (value == _shouldLoop) return;
|
||||
_shouldLoop = value;
|
||||
OnPropertyChanged();
|
||||
if (!IsPlaying)
|
||||
{
|
||||
IsPlaying = true;
|
||||
|
||||
if (isArm64) mediaElementWPF.Play(); else mediaElement.Play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,15 +239,18 @@ public partial class ViewerPanel : UserControl, IDisposable, INotifyPropertyChan
|
||||
|
||||
try
|
||||
{
|
||||
if (timer!=null)
|
||||
timer.Stop();
|
||||
mediaElement?.Close();
|
||||
mediaElementWPF?.Close();
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
mediaElement?.MediaUriPlayer.Dispose();
|
||||
mediaElement = null;
|
||||
mediaElementWPF = null;
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
} catch (Exception e)
|
||||
{
|
||||
Debug.WriteLine(e);
|
||||
}
|
||||
@@ -185,10 +274,21 @@ public partial class ViewerPanel : UserControl, IDisposable, INotifyPropertyChan
|
||||
|
||||
private void MediaOpened(object o, RoutedEventArgs args)
|
||||
{
|
||||
if (mediaElement == null)
|
||||
return;
|
||||
if (isArm64)
|
||||
{
|
||||
if (mediaElementWPF == null)
|
||||
return;
|
||||
|
||||
HasVideo = mediaElement.HasVideo;
|
||||
HasVideo = mediaElementWPF.HasVideo;
|
||||
|
||||
} else
|
||||
{
|
||||
if (mediaElement == null)
|
||||
return;
|
||||
|
||||
HasVideo = mediaElement.HasVideo;
|
||||
|
||||
}
|
||||
|
||||
_context.IsBusy = false;
|
||||
}
|
||||
@@ -209,21 +309,42 @@ public partial class ViewerPanel : UserControl, IDisposable, INotifyPropertyChan
|
||||
|
||||
private void MediaEnded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (mediaElement == null)
|
||||
return;
|
||||
|
||||
mediaElement.MediaPosition = 0L;
|
||||
if (ShouldLoop)
|
||||
if (isArm64)
|
||||
{
|
||||
IsPlaying = true;
|
||||
if (mediaElementWPF == null)
|
||||
return;
|
||||
|
||||
mediaElement.Play();
|
||||
}
|
||||
else
|
||||
mediaElementWPF.Position = new TimeSpan(0L);
|
||||
if (ShouldLoop)
|
||||
{
|
||||
IsPlaying = true;
|
||||
|
||||
mediaElementWPF.Play();
|
||||
} else
|
||||
{
|
||||
IsPlaying = false;
|
||||
|
||||
mediaElementWPF.Pause();
|
||||
}
|
||||
|
||||
} else
|
||||
{
|
||||
IsPlaying = false;
|
||||
if (mediaElement == null)
|
||||
return;
|
||||
|
||||
mediaElement.MediaPosition = 0L;
|
||||
if (ShouldLoop)
|
||||
{
|
||||
IsPlaying = true;
|
||||
|
||||
mediaElement.Play();
|
||||
} else
|
||||
{
|
||||
IsPlaying = false;
|
||||
|
||||
mediaElement.Pause();
|
||||
}
|
||||
|
||||
mediaElement.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,8 +406,7 @@ public partial class ViewerPanel : UserControl, IDisposable, INotifyPropertyChan
|
||||
var coverData = info.Get(StreamKind.General, 0, "Cover_Data");
|
||||
var coverBytes = CoverDataExtractor.Extract(coverData);
|
||||
CoverArt = CoverDataExtractor.Extract(coverBytes);
|
||||
}
|
||||
catch (Exception e)
|
||||
} catch (Exception e)
|
||||
{
|
||||
Debug.WriteLine(e);
|
||||
metaTitle.Text = Path.GetFileName(path);
|
||||
@@ -341,10 +461,9 @@ public partial class ViewerPanel : UserControl, IDisposable, INotifyPropertyChan
|
||||
{
|
||||
if (_lyricLines != null && _lyricLines.Length != 0)
|
||||
{
|
||||
var lyric = LrcHelper.GetNearestLrc(_lyricLines, new TimeSpan(mediaElement.MediaPosition));
|
||||
var lyric = LrcHelper.GetNearestLrc(_lyricLines, new TimeSpan(isArm64 ? mediaElementWPF.Position.Ticks : mediaElement.MediaPosition));
|
||||
metaLyric.Text = lyric?.LrcText?.Trim();
|
||||
}
|
||||
else
|
||||
} else
|
||||
{
|
||||
metaLyric.Text = null;
|
||||
metaLyric.Visibility = Visibility.Collapsed;
|
||||
@@ -353,8 +472,7 @@ public partial class ViewerPanel : UserControl, IDisposable, INotifyPropertyChan
|
||||
_lyricTimer.Start();
|
||||
|
||||
metaLyric.Visibility = Visibility.Visible;
|
||||
}
|
||||
else
|
||||
} else
|
||||
{
|
||||
metaLyric.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
@@ -362,10 +480,10 @@ public partial class ViewerPanel : UserControl, IDisposable, INotifyPropertyChan
|
||||
|
||||
public double LinearVolume
|
||||
{
|
||||
get => mediaElement.Volume;
|
||||
get => (isArm64 ? mediaElementWPF.Volume : mediaElement.Volume);
|
||||
set
|
||||
{
|
||||
mediaElement.Volume = value;
|
||||
if (isArm64) mediaElementWPF.Volume = value; else mediaElement.Volume = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
@@ -377,17 +495,53 @@ public partial class ViewerPanel : UserControl, IDisposable, INotifyPropertyChan
|
||||
|
||||
private void TogglePlayPause(object sender, EventArgs e)
|
||||
{
|
||||
if (mediaElement.IsPlaying)
|
||||
mediaElement.Pause();
|
||||
else
|
||||
mediaElement.Play();
|
||||
if (isArm64)
|
||||
{
|
||||
if (IsPlaying)
|
||||
{
|
||||
IsPlaying = false;
|
||||
mediaElementWPF.Pause();
|
||||
} else
|
||||
{
|
||||
IsPlaying = true;
|
||||
mediaElementWPF.Play();
|
||||
}
|
||||
} else
|
||||
{
|
||||
if (mediaElement.IsPlaying)
|
||||
mediaElement.Pause();
|
||||
else
|
||||
mediaElement.Play();
|
||||
}
|
||||
}
|
||||
|
||||
private void ToggleShouldLoop(object sender, EventArgs e)
|
||||
{
|
||||
ShouldLoop = !ShouldLoop;
|
||||
}
|
||||
public void LoadAndPlayWPF(string path, MediaInfoLib info)
|
||||
{
|
||||
// Detect whether it is other playback formats
|
||||
if (!HasVideo)
|
||||
{
|
||||
string audioCodec = info?.Get(StreamKind.Audio, 0, "Format");
|
||||
|
||||
if (audioCodec?.Equals("MIDI", StringComparison.OrdinalIgnoreCase) ?? false)
|
||||
{
|
||||
_midiPlayer = new MidiPlayer(this, _context);
|
||||
_midiPlayer.LoadAndPlay(path);
|
||||
return; // Midi player will handle the playback at all
|
||||
}
|
||||
}
|
||||
|
||||
UpdateMeta(path, info);
|
||||
|
||||
mediaElementWPF.Source = new Uri(path);
|
||||
// old plugin use an int-typed "Volume" config key ranged from 0 to 100. Let's use a new one here.
|
||||
LinearVolume = SettingHelper.Get("VolumeDouble", 1d, "QuickLook.Plugin.VideoViewer");
|
||||
|
||||
mediaElementWPF.Play();
|
||||
}
|
||||
public void LoadAndPlay(string path, MediaInfoLib info)
|
||||
{
|
||||
// Detect whether it is other playback formats
|
||||
|
||||
Reference in New Issue
Block a user