Skip to content

Commit

Permalink
Updated libraries, added better progress indication, added back/forwa…
Browse files Browse the repository at this point in the history
…rd skip, added drag-n-drop support
  • Loading branch information
valery-kirichenko committed Jun 19, 2021
1 parent 3b90262 commit ff31d53
Show file tree
Hide file tree
Showing 15 changed files with 147 additions and 44 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop" ToolsVersion="Current">
<PropertyGroup Label="Globals">
<Platforms>x64</Platforms>
<PackageVersion>1.1.0</PackageVersion>
<PackageVersion>1.2.0</PackageVersion>
<Company>Kirichenko Valery</Company>
<Product>ClipChopper</Product>
<AssemblyVersion>1.1.0</AssemblyVersion>
<AssemblyVersion>1.2.0</AssemblyVersion>
<AssemblyName>ClipChopper</AssemblyName>
<PackageId>ClipChopper</PackageId>
<Authors>Kirichenko Valery</Authors>
Expand Down Expand Up @@ -60,8 +60,9 @@
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="FFME.Windows" Version="4.2.330" />
<PackageReference Include="FFME.Windows" Version="4.4.350" />
<PackageReference Include="FFmpeg.AutoGen" Version="4.4.0" />
<PackageReference Include="NExifTool" Version="0.9.0" />
<PackageReference Include="Ookii.Dialogs.Wpf.NETCore" Version="2.0.0" />
<PackageReference Include="Ookii.Dialogs.Wpf" Version="3.1.0" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public static TimeSpan FindClosestKeyframeTime(string filePath, TimeSpan time)

string args = $"-threads {Environment.ProcessorCount} -select_streams v -skip_frame nokey " +
$"-show_frames -print_format csv " +
$"-show_entries frame=key_frame,pkt_dts_time \"{filePath}\"";
$"-show_entries frame=key_frame,pkt_pts_time \"{filePath}\"";

var startInfo = new ProcessStartInfo()
{
Expand Down
53 changes: 49 additions & 4 deletions ClipChopper/Applications/ClipChopper.DesktopApp/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
Title="Clip Chopper"
Height="870"
Width="1491"
WindowStartupLocation="CenterScreen">
WindowStartupLocation="CenterScreen"
AllowDrop="True"
Drop="MainWindow_OnDrop">
<!--1491x870 to get 720p video preview-->
<Window.Resources>
<local:TimeSpanToSecondsConverter x:Key="TimeSpanToSecondsConverter" />
Expand Down Expand Up @@ -124,7 +126,7 @@
</Rectangle>
</Viewbox>
</Button>
<Button Margin="5" Click="Pframe_Click" ToolTip="Previous frame">
<Button Margin="5" Click="SkipBack_Click" ToolTip="Skip Back">
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Rectangle Width="16" Height="16">
<Rectangle.Fill>
Expand All @@ -143,7 +145,7 @@
</Rectangle>
</Viewbox>
</Button>
<Button Margin="5" Click="Nframe_Click" ToolTip="Next frame">
<Button Margin="5" Click="SkipForward_Click" ToolTip="Skip Forward">
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Rectangle Width="16" Height="16">
<Rectangle.Fill>
Expand All @@ -162,6 +164,46 @@
</Rectangle>
</Viewbox>
</Button>
<Button Margin="5" Click="Pframe_Click" ToolTip="Previous Frame">
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Rectangle Width="16" Height="16">
<Rectangle.Fill>
<DrawingBrush>
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="#00FFFFFF" Geometry="F1M16,16L0,16 0,0 16,0z" />
<GeometryDrawing Brush="#FFF6F6F6" Geometry="F1M2.248,8.0723L11,13.8853 11,13.0003 14,13.0003 14,3.0003 11,3.0003 11,2.1343z" />
<GeometryDrawing Brush="#FF414141" Geometry="F1M10,12L3.794,8.063 10,4z" />
<GeometryDrawing Brush="#FF414141" Geometry="F1M12,12L13,12 13,4 12,4z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>
</Viewbox>
</Button>
<Button Margin="5" Click="Nframe_Click" ToolTip="Next Frame">
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Rectangle Width="16" Height="16">
<Rectangle.Fill>
<DrawingBrush>
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="#00FFFFFF" Geometry="F1M16,16L0,16 0,0 16,0z" />
<GeometryDrawing Brush="#FFF6F6F6" Geometry="F1M14.752,7.9492L6,2.1352 6,3.0002 3,3.0002 3,13.0002 6,13.0002 6,13.8872z" />
<GeometryDrawing Brush="#FF414141" Geometry="F1M7,4L12.958,7.958 7,12z" />
<GeometryDrawing Brush="#FF414141" Geometry="F1M4,12L5.001,12 5.001,4 4,4z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>
</Viewbox>
</Button>
<Button Margin="5"
Padding="10 0"
x:Name="Start"
Expand Down Expand Up @@ -198,7 +240,10 @@
DisplayMemberPath="Name"
x:Name="AudioTrackSlider"
VerticalContentAlignment="Center"
SelectionChanged="ComboBox_SelectionChanged"/>
SelectionChanged="ComboBox_SelectionChanged"
IsEnabled="False"/>

<TextBlock x:Name="Status" Margin="5" VerticalAlignment="Center"/>
</StackPanel>
</Grid>
</Grid>
Expand Down
127 changes: 92 additions & 35 deletions ClipChopper/Applications/ClipChopper.DesktopApp/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,14 @@ public sealed partial class MainWindow
private string? _loadedMedia;
private FragmentSelection? _fragment;
private int _selectedAudioStream;
public ObservableCollection<AudioTrack> AudioTracks { get; } = new ObservableCollection<AudioTrack>();
public ObservableCollection<AudioTrack> AudioTracks { get; } = new ObservableCollection<AudioTrack>(new List<AudioTrack>()
{
new AudioTrack
{
Name = "No Audio",
StreamIndex = 0
}
});

public MainWindow()
{
Expand All @@ -30,22 +37,36 @@ public MainWindow()
Media.MediaChanging += Media_MediaChanging;
}

private void Media_MediaOpened(object? sender, Unosquare.FFME.Common.MediaOpenedEventArgs e)
private async void Media_MediaOpened(object? sender, Unosquare.FFME.Common.MediaOpenedEventArgs e)
{
var tags = LoadTags();
var tags = await LoadTags();
AudioTracks.Clear();
var audioStreams = Media.MediaInfo.Streams
.Where(kvp => kvp.Value.CodecType == FFmpeg.AutoGen.AVMediaType.AVMEDIA_TYPE_AUDIO)
.Select(kvp => kvp.Value);
foreach (var stream in audioStreams)

if (!audioStreams.Any())
{
AudioTracks.Add(new AudioTrack
{
Name = $"Audio #{stream.StreamIndex} - " + tags
.Where(tag => tag.Name.Equals($"Track{stream.StreamId}Name")).Select(tag => tag.Value)
.DefaultIfEmpty("Untitled").First(),
StreamIndex = stream.StreamIndex
Name = "No Audio",
StreamIndex = 0
});
AudioTrackSlider.IsEnabled = false;
}
else
{
foreach (var stream in audioStreams)
{
AudioTracks.Add(new AudioTrack
{
Name = $"Audio #{stream.StreamIndex} - " + tags
.Where(tag => tag.Name.Equals($"Track{stream.StreamId}Name")).Select(tag => tag.Value)
.DefaultIfEmpty("Untitled").First(),
StreamIndex = stream.StreamIndex
});
}
AudioTrackSlider.IsEnabled = true;
}

AudioTrackSlider.SelectedIndex = 0;
Expand Down Expand Up @@ -93,7 +114,10 @@ private async void Play_Click(object sender, RoutedEventArgs e)

private void Pframe_Click(object sender, RoutedEventArgs e)
{
Media.StepBackward();
if (Media.Position - Media.PositionStep > Media.PlaybackStartTime)
{
Media.StepBackward();
}
}

private void Nframe_Click(object sender, RoutedEventArgs e)
Expand All @@ -108,28 +132,23 @@ private void Nframe_Click(object sender, RoutedEventArgs e)

private void SelectDirectory_Click(object sender, RoutedEventArgs e)
{
var dialog = new Ookii.Dialogs.Wpf.VistaFolderBrowserDialog();
var dialog = new VistaFolderBrowserDialog();
if (dialog.ShowDialog().GetValueOrDefault())
{
_selectedDirectory = dialog.SelectedPath;

// TODO: implement extensions filter, move this to new method.
IReadOnlyList<string> files = Directory.GetFiles(_selectedDirectory, "*.*")
.Where(s => s.EndsWith(".mp4", StringComparison.OrdinalIgnoreCase) ||
s.EndsWith(".mkv", StringComparison.OrdinalIgnoreCase))
.ToList();

DirectoryList.ItemsSource = Enumerable.Range(0, files.Count)
.Select(i => new DirectoryItem(files[i]))
.ToList();
LoadDirectory();
}
}

private void RefreshDirectory_Click(object sender, RoutedEventArgs e)
{
if (_selectedDirectory is null) return;
LoadDirectory();
}

// TODO: implement extensions filter, move this to new method.
private void LoadDirectory()
{
if (_selectedDirectory is null) return;
// TODO: implement extensions filter
List<string> files = Directory.GetFiles(_selectedDirectory, "*.*")
.Where(s => s.EndsWith(".mp4", StringComparison.OrdinalIgnoreCase) ||
s.EndsWith(".mkv", StringComparison.OrdinalIgnoreCase))
Expand Down Expand Up @@ -178,7 +197,7 @@ private void DirectoryList_Selected(object sender, SelectionChangedEventArgs arg
_loadedMedia = selectedFile.Path;
}

private void Save_Click(object sender, RoutedEventArgs eventArgs)
private async void Save_Click(object sender, RoutedEventArgs eventArgs)
{
if (_fragment is null) return;

Expand All @@ -189,7 +208,7 @@ private void Save_Click(object sender, RoutedEventArgs eventArgs)

Debug.WriteLine(Path.GetExtension(_loadedMedia).Substring(1, 3));

var dialog = new Ookii.Dialogs.Wpf.VistaSaveFileDialog()
var dialog = new VistaSaveFileDialog()
{
AddExtension = true,
Filter = "MP4 Files (*.mp4)|*.mp4|MKV Files (*.mkv)|*.mkv",
Expand All @@ -206,7 +225,8 @@ private void Save_Click(object sender, RoutedEventArgs eventArgs)
var outputFile = dialog.FileName;

var ffmpegPath = Path.Combine(Unosquare.FFME.Library.FFmpegDirectory, "ffmpeg.exe");
var startKeyframe = KeyframeProber.FindClosestKeyframeTime(inputFile, _fragment.Start);
Status.Text = "Looking for keyframes...";
var startKeyframe = await Task.Run(() => KeyframeProber.FindClosestKeyframeTime(inputFile, _fragment.Start));

string args = $"-y -ss {startKeyframe} -i \"{inputFile}\" -map_metadata 0 " +
$"-to \"{_fragment.Stop - startKeyframe}\" -c:v copy -c:a copy " +
Expand All @@ -222,15 +242,20 @@ private void Save_Click(object sender, RoutedEventArgs eventArgs)
Arguments = args
};

using (var ffmpeg = Process.Start(startInfo))
Status.Text = "Trimming...";
await Task.Run(() =>
{
Debug.Assert(ffmpeg != null, nameof(ffmpeg) + " != null");
ffmpeg.OutputDataReceived += (s, e) => { Debug.WriteLine(e.Data); };
ffmpeg.WaitForExit();
}

ShowMessage("Done");
using (var ffmpeg = Process.Start(startInfo))
{
Debug.Assert(ffmpeg != null, nameof(ffmpeg) + " != null");
ffmpeg.OutputDataReceived += (s, e) => { Debug.WriteLine(e.Data); };
ffmpeg.WaitForExit();
}
});
Status.Text = "Done";
RefreshDirectory_Click(sender, eventArgs);
await Task.Delay(2000);
Status.Text = "";
}

private void Volume_Change(object sender, RoutedPropertyChangedEventArgs<double> eventArgs)
Expand All @@ -256,7 +281,7 @@ private void ShowMessage(string message)
dialog.ShowDialog(this);
}

private List<NExifTool.Tag> LoadTags()
private async Task<List<NExifTool.Tag>> LoadTags()
{
var etOptions = new NExifTool.ExifToolOptions()
{
Expand All @@ -265,8 +290,8 @@ private void ShowMessage(string message)
var et = new NExifTool.ExifTool(etOptions);
Debug.WriteLine(etOptions.ExifToolPath);
Debug.WriteLine(_loadedMedia);
var task = Task.Run(async () => await et.GetTagsAsync(_loadedMedia));
return task.Result.ToList();
var result = await et.GetTagsAsync(_loadedMedia);
return result.ToList();
}

private void Media_MediaChanging(object? sender, Unosquare.FFME.Common.MediaOpeningEventArgs e)
Expand All @@ -287,5 +312,37 @@ private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs
_selectedAudioStream = ((AudioTrack)AudioTrackSlider.SelectedItem).StreamIndex;
Media.ChangeMedia();
}

private void MainWindow_OnDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
string path = ((string[]) e.Data.GetData(DataFormats.FileDrop))[0];
if (Directory.Exists(path))
{
_selectedDirectory = path;
} else if (File.Exists(path))
{
_selectedDirectory = Path.GetDirectoryName(path);
if (path.EndsWith(".mp4", StringComparison.OrdinalIgnoreCase) ||
path.EndsWith(".mkv", StringComparison.OrdinalIgnoreCase))
{
Media.Open(new Uri(path));
_loadedMedia = path;
}
}
LoadDirectory();
}
}

private void SkipBack_Click(object sender, RoutedEventArgs e)
{
Media.Position = Media.Position.Subtract(TimeSpan.FromSeconds(5));
}

private void SkipForward_Click(object sender, RoutedEventArgs e)
{
Media.Position = Media.Position.Add(TimeSpan.FromSeconds(5));
}
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified ClipChopper/Applications/ClipChopper.DesktopApp/ffmpeg/ffplay.exe
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 comments on commit ff31d53

Please sign in to comment.