mirror of
https://github.com/QL-Win/QuickLook.git
synced 2025-09-11 17:59:17 +00:00
move to new FFME control and probe media info
This commit is contained in:
@@ -75,4 +75,28 @@ namespace QuickLook.Plugin.VideoViewer
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public class TimeSpanToSecondsConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType,
|
||||
object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is TimeSpan) return ((TimeSpan) value).TotalSeconds;
|
||||
if (value is Duration)
|
||||
return ((Duration) value).HasTimeSpan ? ((Duration) value).TimeSpan.TotalSeconds : 0d;
|
||||
|
||||
return 0d;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType,
|
||||
object parameter, CultureInfo culture)
|
||||
{
|
||||
var result = TimeSpan.FromTicks((long) Math.Round(TimeSpan.TicksPerSecond * (double) value, 0));
|
||||
// Do the conversion from visibility to bool
|
||||
if (targetType == typeof(TimeSpan)) return result;
|
||||
if (targetType == typeof(Duration)) return new Duration(result);
|
||||
|
||||
return Activator.CreateInstance(targetType);
|
||||
}
|
||||
}
|
||||
}
|
102
QuickLook.Plugin/QuickLook.Plugin.VideoViewer/FFmpeg/FFprobe.cs
Normal file
102
QuickLook.Plugin/QuickLook.Plugin.VideoViewer/FFmpeg/FFprobe.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
// Copyright © 2017 Paddy Xu
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using System.Xml.XPath;
|
||||
|
||||
namespace QuickLook.Plugin.VideoViewer.FFmpeg
|
||||
{
|
||||
internal class FFprobe
|
||||
{
|
||||
private static readonly string _probePath =
|
||||
Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "FFmpeg\\",
|
||||
App.Is64Bit ? "x64\\" : "x86\\", "ffprobe.exe");
|
||||
|
||||
private XPathNavigator infoNavigator;
|
||||
|
||||
public FFprobe(string media)
|
||||
{
|
||||
Run(media);
|
||||
}
|
||||
|
||||
private bool Run(string media)
|
||||
{
|
||||
var result = string.Empty;
|
||||
|
||||
using (var p = new Process())
|
||||
{
|
||||
p.StartInfo.UseShellExecute = false;
|
||||
p.StartInfo.CreateNoWindow = true;
|
||||
p.StartInfo.RedirectStandardOutput = true;
|
||||
p.StartInfo.FileName = _probePath;
|
||||
p.StartInfo.Arguments = $"-v quiet -print_format xml -show_streams -show_format \"{media}\"";
|
||||
p.Start();
|
||||
p.WaitForExit();
|
||||
|
||||
result = p.StandardOutput.ReadToEnd();
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(result))
|
||||
return false;
|
||||
|
||||
ParseResult(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ParseResult(string result)
|
||||
{
|
||||
infoNavigator = new XPathDocument(new StringReader(result)).CreateNavigator();
|
||||
}
|
||||
|
||||
public bool CanDecode()
|
||||
{
|
||||
var info = infoNavigator.SelectSingleNode("/ffprobe/streams");
|
||||
|
||||
return info != null;
|
||||
}
|
||||
|
||||
public string GetFormatName()
|
||||
{
|
||||
var format = infoNavigator.SelectSingleNode("/ffprobe/format/@format_name")?.Value;
|
||||
|
||||
return format ?? string.Empty;
|
||||
}
|
||||
|
||||
public string GetFormatLongName()
|
||||
{
|
||||
var format = infoNavigator.SelectSingleNode("/ffprobe/format/@format_long_name")?.Value;
|
||||
|
||||
return format ?? string.Empty;
|
||||
}
|
||||
|
||||
public Size GetViewSize()
|
||||
{
|
||||
var width = infoNavigator.SelectSingleNode("/ffprobe/streams/stream[@codec_type='video'][1]/@coded_width")
|
||||
?.Value;
|
||||
var height = infoNavigator.SelectSingleNode("/ffprobe/streams/stream[@codec_type='video'][1]/@coded_height")
|
||||
?.Value;
|
||||
|
||||
if (width == null || height == null)
|
||||
return Size.Empty;
|
||||
|
||||
return new Size(double.Parse(width), double.Parse(height));
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
@@ -15,11 +15,12 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using Unosquare.FFmpegMediaElement;
|
||||
using QuickLook.Plugin.VideoViewer.FFmpeg;
|
||||
using Unosquare.FFME;
|
||||
|
||||
namespace QuickLook.Plugin.VideoViewer
|
||||
{
|
||||
@@ -32,7 +33,9 @@ namespace QuickLook.Plugin.VideoViewer
|
||||
|
||||
public void Init()
|
||||
{
|
||||
MediaElement.FFmpegPaths.RegisterFFmpeg();
|
||||
MediaElement.FFmpegDirectory =
|
||||
Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "\\FFmpeg\\",
|
||||
App.Is64Bit ? "x64\\" : "x86\\");
|
||||
}
|
||||
|
||||
public bool CanHandle(string path)
|
||||
@@ -54,10 +57,11 @@ namespace QuickLook.Plugin.VideoViewer
|
||||
|
||||
public void Prepare(string path, ContextObject context)
|
||||
{
|
||||
using (var element = new MediaElement {Source = new Uri(path)})
|
||||
{
|
||||
context.SetPreferredSizeFit(new Size(element.NaturalVideoWidth, element.NaturalVideoHeight), 0.6);
|
||||
}
|
||||
var def = new Size(1024, 768);
|
||||
|
||||
var real = new FFprobe(path).GetViewSize();
|
||||
|
||||
context.SetPreferredSizeFit(real == Size.Empty ? def : real, 0.6);
|
||||
}
|
||||
|
||||
public void View(string path, ContextObject context)
|
||||
|
@@ -53,6 +53,10 @@
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="ffme, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8ed0ff27966cae1f, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>ffme\ffme.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="FontAwesome.WPF, Version=4.7.0.37774, Culture=neutral, PublicKeyToken=0758b07a11a4f466, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\FontAwesome.WPF.4.7.0.9\lib\net40\FontAwesome.WPF.dll</HintPath>
|
||||
</Reference>
|
||||
@@ -61,10 +65,7 @@
|
||||
<Reference Include="System.Xaml">
|
||||
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="Unosquare.FFmpegMediaElement, Version=1.3.1.4, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>References\Unosquare.FFmpegMediaElement.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="WindowsBase" />
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
@@ -82,6 +83,7 @@
|
||||
<Link>Properties\GitVersion.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="Converters.cs" />
|
||||
<Compile Include="FFmpeg\FFprobe.cs" />
|
||||
<Compile Include="Plugin.cs" />
|
||||
<Compile Include="ViewerPanel.xaml.cs">
|
||||
<DependentUpon>ViewerPanel.xaml</DependentUpon>
|
||||
@@ -102,6 +104,9 @@
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="ffme\ffme.dll" />
|
||||
<Resource Include="ffme\ffme.xml" />
|
||||
<Content Include="ffme\ffmpeg.dll" />
|
||||
<Content Include="FFmpeg\x64\avcodec-57.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
@@ -117,6 +122,9 @@
|
||||
<Content Include="FFmpeg\x64\avutil-55.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="FFmpeg\x64\ffprobe.exe">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="FFmpeg\x64\swresample-2.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
@@ -138,6 +146,9 @@
|
||||
<Content Include="FFmpeg\x86\avutil-55.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="FFmpeg\x86\ffprobe.exe">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="FFmpeg\x86\swresample-2.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -5,15 +5,14 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||
xmlns:local="clr-namespace:QuickLook.Plugin.VideoViewer"
|
||||
xmlns:ffmpeg="clr-namespace:Unosquare.FFmpegMediaElement;assembly=Unosquare.FFmpegMediaElement"
|
||||
xmlns:ffmpeg="clr-namespace:Unosquare.FFME;assembly=ffme"
|
||||
mc:Ignorable="d"
|
||||
Background="#B2454545"
|
||||
d:DesignHeight="449.167" d:DesignWidth="767">
|
||||
<Grid>
|
||||
<Grid.Resources>
|
||||
<ResourceDictionary>
|
||||
<local:DoubleToTimeSpanConverter x:Key="DoubleToTimeSpanConverter" />
|
||||
<local:DecimalToTimeSpanConverter x:Key="DecimalToTimeSpanConverter" />
|
||||
<local:TimeSpanToSecondsConverter x:Key="TimeSpanToSecondsConverter" />
|
||||
<local:BooleanToVisibilityHiddenConverter x:Key="BooleanToVisibilityHiddenConverter" />
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="Styles.xaml" />
|
||||
@@ -63,9 +62,12 @@
|
||||
</Style>
|
||||
</Grid.Style>
|
||||
|
||||
<Slider x:Name="sliderProgress" Style="{StaticResource PositionSliderStyle}"
|
||||
Value="{Binding Position, ElementName=mediaElement}"
|
||||
Maximum="{Binding NaturalDuration, ElementName=mediaElement, Mode=OneWay}" Grid.Row="1" />
|
||||
<Slider Grid.Row="1" x:Name="sliderProgress" Style="{StaticResource PositionSliderStyle}"
|
||||
IsEnabled="{Binding IsOpen, ElementName=mediaElement}"
|
||||
SmallChange="{Binding FrameStepDuration, ElementName=mediaElement,Converter={StaticResource TimeSpanToSecondsConverter}}"
|
||||
LargeChange="{Binding FrameStepDuration, ElementName=mediaElement, Converter={StaticResource TimeSpanToSecondsConverter}}"
|
||||
Maximum="{Binding NaturalDuration, ElementName=mediaElement,Converter={StaticResource TimeSpanToSecondsConverter}}"
|
||||
Value="{Binding Position, ElementName=mediaElement, Converter={StaticResource TimeSpanToSecondsConverter}}" />
|
||||
|
||||
<Grid Grid.Row="2">
|
||||
<Grid.ColumnDefinitions>
|
||||
@@ -126,10 +128,10 @@
|
||||
<StackPanel Grid.Column="2" HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Orientation="Horizontal" Margin="0,0,20,0">
|
||||
<TextBlock FontSize="16" Foreground="#FFEFEFEF"
|
||||
Text="{Binding Position, ElementName=mediaElement,Converter={StaticResource DecimalToTimeSpanConverter}}" />
|
||||
Text="{Binding Position, StringFormat=hh\\:mm\\:ss, ElementName=mediaElement}" />
|
||||
<TextBlock FontSize="16" Text=" / " Foreground="#FFEFEFEF" />
|
||||
<TextBlock FontSize="16" Foreground="#FFEFEFEF"
|
||||
Text="{Binding NaturalDuration, StringFormat=hh:mm:ss, ElementName=mediaElement,Converter={StaticResource DoubleToTimeSpanConverter}}" />
|
||||
Text="{Binding NaturalDuration.TimeSpan, StringFormat=hh\\:mm\\:ss, ElementName=mediaElement}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
@@ -17,9 +17,9 @@
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using Unosquare.FFmpegMediaElement;
|
||||
|
||||
namespace QuickLook.Plugin.VideoViewer
|
||||
{
|
||||
@@ -47,32 +47,31 @@ namespace QuickLook.Plugin.VideoViewer
|
||||
buttonBackward.MouseLeftButtonUp += (sender, e) => SeekBackward();
|
||||
buttonForward.MouseLeftButtonUp += (sender, e) => SeekForward();
|
||||
|
||||
mediaElement.MediaErrored += ShowErrorNotification;
|
||||
mediaElement.MediaFailed += ShowErrorNotification;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
mediaElement?.Stop();
|
||||
mediaElement?.Dispose();
|
||||
mediaElement = null;
|
||||
}
|
||||
|
||||
private void SeekBackward()
|
||||
{
|
||||
var pos = Convert.ToDouble(mediaElement.Position);
|
||||
var len = mediaElement.NaturalDuration;
|
||||
var delta = TimeSpan.FromSeconds(15).TotalSeconds;
|
||||
var pos = mediaElement.Position;
|
||||
var delta = TimeSpan.FromSeconds(15);
|
||||
|
||||
mediaElement.Position = Convert.ToDecimal(pos - delta < 0 ? 0 : pos - delta);
|
||||
mediaElement.Position = pos < pos - delta ? TimeSpan.Zero : pos - delta;
|
||||
}
|
||||
|
||||
private void SeekForward()
|
||||
{
|
||||
var pos = Convert.ToDouble(mediaElement.Position);
|
||||
var len = mediaElement.NaturalDuration;
|
||||
var delta = TimeSpan.FromSeconds(15).TotalSeconds;
|
||||
var pos = mediaElement.Position;
|
||||
var len = mediaElement.NaturalDuration.TimeSpan;
|
||||
var delta = TimeSpan.FromSeconds(15);
|
||||
|
||||
mediaElement.Position = Convert.ToDecimal(pos + delta > len ? len : pos + delta);
|
||||
mediaElement.Position = pos + delta > len ? len : pos + delta;
|
||||
}
|
||||
|
||||
private void TogglePlayPause(object sender, MouseButtonEventArgs e)
|
||||
@@ -84,7 +83,7 @@ namespace QuickLook.Plugin.VideoViewer
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
private void ShowErrorNotification(object sender, MediaErrorRoutedEventArgs e)
|
||||
private void ShowErrorNotification(object sender, ExceptionRoutedEventArgs exceptionRoutedEventArgs)
|
||||
{
|
||||
_context.ShowNotification("", "An error occurred while loading the video.");
|
||||
mediaElement.Stop();
|
||||
@@ -98,8 +97,7 @@ namespace QuickLook.Plugin.VideoViewer
|
||||
public void LoadAndPlay(string path)
|
||||
{
|
||||
mediaElement.Source = new Uri(path);
|
||||
mediaElement.IsMuted = true;
|
||||
mediaElement.Play();
|
||||
mediaElement.MediaOpened += (sender, e) => mediaElement.IsMuted = true;
|
||||
}
|
||||
|
||||
~ViewerPanel()
|
||||
|
BIN
QuickLook.Plugin/QuickLook.Plugin.VideoViewer/ffme/ffme.dll
Normal file
BIN
QuickLook.Plugin/QuickLook.Plugin.VideoViewer/ffme/ffme.dll
Normal file
Binary file not shown.
6637
QuickLook.Plugin/QuickLook.Plugin.VideoViewer/ffme/ffme.xml
Normal file
6637
QuickLook.Plugin/QuickLook.Plugin.VideoViewer/ffme/ffme.xml
Normal file
File diff suppressed because it is too large
Load Diff
BIN
QuickLook.Plugin/QuickLook.Plugin.VideoViewer/ffme/ffmpeg.dll
Normal file
BIN
QuickLook.Plugin/QuickLook.Plugin.VideoViewer/ffme/ffmpeg.dll
Normal file
Binary file not shown.
Reference in New Issue
Block a user