From 4124065dff571e9ea821925c0bb1fa35e5266d7e Mon Sep 17 00:00:00 2001 From: the-database <25811902+the-database@users.noreply.github.com> Date: Thu, 5 Oct 2023 14:03:20 -0400 Subject: [PATCH] add backend selection with trt, dml, ncnn, capture console output to gui and error.log file --- .../ViewModels/MainWindowViewModel.cs | 235 ++++++++++++++---- AnimeJaNaiConverterGui/Views/MainWindow.axaml | 100 +++++--- .../Views/MainWindow.axaml.cs | 27 +- 3 files changed, 278 insertions(+), 84 deletions(-) diff --git a/AnimeJaNaiConverterGui/ViewModels/MainWindowViewModel.cs b/AnimeJaNaiConverterGui/ViewModels/MainWindowViewModel.cs index ce7a182..8760332 100644 --- a/AnimeJaNaiConverterGui/ViewModels/MainWindowViewModel.cs +++ b/AnimeJaNaiConverterGui/ViewModels/MainWindowViewModel.cs @@ -10,6 +10,7 @@ using System.Reactive; using System.Runtime.Serialization; using System.Text; +using System.Threading.Tasks; namespace AnimeJaNaiConverterGui.ViewModels { @@ -18,8 +19,6 @@ public class MainWindowViewModel : ViewModelBase { public MainWindowViewModel() { - //AddModel(); - this.WhenAnyValue(x => x.InputFilePath, x => x.OutputFilePath, x => x.InputFolderPath, x => x.OutputFolderPath, x => x.SelectedTabIndex).Subscribe(x => @@ -42,6 +41,41 @@ public int SelectedTabIndex } } + private string _validationText; + public string ValidationText + { + get => _validationText; + set + { + this.RaiseAndSetIfChanged(ref _validationText, value); + } + } + + private string _consoleText; + public string ConsoleText + { + get => _consoleText; + set + { + this.RaiseAndSetIfChanged(ref _consoleText, value); + } + } + + private bool _overwriteExistingVideos; + [DataMember] + public bool OverwriteExistingVideos + { + get => _overwriteExistingVideos; + set + { + + this.RaiseAndSetIfChanged(ref _overwriteExistingVideos, value); + + } + } + + private string _overwriteCommand => OverwriteExistingVideos ? "-y" : ""; + private static readonly string _ffmpegX265 = "libx265 -crf 16 -preset slow -x265-params \"sao=0:bframes=8:psy-rd=1.5:psy-rdoq=2:aq-mode=3:ref=6\""; private static readonly string _ffmpegX264 = "libx264 -crf 13 -preset slow"; private static readonly string _ffmpegHevcNvenc = "hevc_nvenc -preset p7 -profile:v main10 -b:v 50M"; @@ -68,6 +102,39 @@ public string FfmpegVideoSettings } } + private bool _tensorRtSelected = true; + [DataMember] + public bool TensorRtSelected + { + get => _tensorRtSelected; + set + { + this.RaiseAndSetIfChanged(ref _tensorRtSelected, value); + } + } + + private bool _directMlSelected = false; + [DataMember] + public bool DirectMlSelected + { + get => _directMlSelected; + set + { + this.RaiseAndSetIfChanged(ref _directMlSelected, value); + } + } + + private bool _ncnnSelected = false; + [DataMember] + public bool NcnnSelected + { + get => _ncnnSelected; + set + { + this.RaiseAndSetIfChanged(ref _ncnnSelected, value); + } + } + private string _inputFilePath = string.Empty; [DataMember] public string InputFilePath @@ -180,24 +247,57 @@ public void SetFfmpegLossless() FfmpegVideoSettings = _ffmpegLossless; } + public void SetTensorRtSelected() + { + TensorRtSelected = true; + DirectMlSelected = false; + NcnnSelected = false; + } + + public void SetDirectMlSelected() + { + DirectMlSelected = true; + TensorRtSelected = false; + NcnnSelected = false; + } + + public void SetNcnnSelected() + { + NcnnSelected = true; + TensorRtSelected = false; + DirectMlSelected = false; + } + public void Validate() { + var valid = true; + var validationText = new List(); if (SelectedTabIndex == 0) { - var fileModeIsValid = File.Exists(InputFilePath) && !string.IsNullOrWhiteSpace(OutputFilePath); - if (!fileModeIsValid) + if (!File.Exists(InputFilePath)) + { + valid = false; + validationText.Add("Input Video is required."); + } + + if (string.IsNullOrWhiteSpace(OutputFilePath)) { - Valid = false; - return; + valid = false; + validationText.Add("Output Video is required."); } } else { - var folderModeIsValid = Directory.Exists(InputFolderPath) && !string.IsNullOrWhiteSpace(OutputFolderPath); - if (!folderModeIsValid) + if (!Directory.Exists(InputFolderPath)) { - Valid = false; - return; + valid = false; + validationText.Add("Input Folder is required."); + } + + if (string.IsNullOrWhiteSpace(OutputFolderPath)) + { + valid = false; + validationText.Add("Output Folder is required."); } } @@ -205,20 +305,23 @@ public void Validate() { if (!File.Exists(upscaleModel.OnnxModelPath)) { - Valid = false; - return; + valid = false; + validationText.Add("ONNX Model Path is required."); } } - Valid = true; + Valid = valid; + ValidationText = string.Join("\n", validationText); } public void SetupAnimeJaNaiConfSlot1() { var confPath = Path.GetFullPath(@".\mpv-upscale-2x_animejanai\portable_config\shaders\animejanai_v2.conf"); + var backend = DirectMlSelected ? "DirectML" : NcnnSelected ? "NCNN" : "TensorRT"; HashSet filesNeedingEngine = new(); - var configText = new StringBuilder(@"[global] + var configText = new StringBuilder($@"[global] logging=yes +backend={backend} [slot_1] "); @@ -242,28 +345,35 @@ public void SetupAnimeJaNaiConfSlot1() File.WriteAllText(confPath, configText.ToString()); } - public void CheckEngines(string inputFilePath) + public async Task CheckEngines(string inputFilePath) { + if (!TensorRtSelected) + { + return; + } + for (var i = 0; i < UpscaleSettings.Count; i++) { var enginePath = @$".\mpv-upscale-2x_animejanai\vapoursynth64\plugins\models\animejanai\{Path.GetFileNameWithoutExtension(UpscaleSettings[i].OnnxModelPath)}.engine"; if (!File.Exists(enginePath)) { - GenerateEngine(inputFilePath); + await GenerateEngine(inputFilePath); } } } - public void RunUpscale() + public async Task RunUpscale() { + ConsoleText = ""; + Valid = false; SetupAnimeJaNaiConfSlot1(); if (SelectedTabIndex == 0) { - CheckEngines(InputFilePath); - RunUpscaleSingle(InputFilePath, OutputFilePath); + await CheckEngines(InputFilePath); + await RunUpscaleSingle(InputFilePath, OutputFilePath); } else { @@ -272,49 +382,72 @@ public void RunUpscale() foreach (var file in files) { - CheckEngines(file); + await CheckEngines(file); var outputFilePath = Path.Combine(OutputFolderPath, Path.GetFileName(file)); - RunUpscaleSingle(file, outputFilePath); + await RunUpscaleSingle(file, outputFilePath); } } - return; + Valid = true; + } + + public async Task RunUpscaleSingle(string inputFilePath, string outputFilePath) + { + var cmd = $@"..\..\VSPipe.exe -c y4m --arg ""slot=1"" --arg ""video_path={inputFilePath}"" ./animejanai_v2_encode.vpy - | ffmpeg {_overwriteCommand} -i pipe: -i ""{inputFilePath}"" -map 0:v -c:v {FfmpegVideoSettings} -map 1:t? -map 1:a? -map 1:s? -c:t copy -c:a copy -c:s copy ""{outputFilePath}"""; + ConsoleText += $@"Upscaling with command: {cmd}"; + await RunCommand($@" /C {cmd}"); } - public void RunUpscaleSingle(string inputFilePath, string outputFilePath) + public async Task GenerateEngine(string inputFilePath) { - // Create a new process to run the CMD command - using (var process = new Process()) - { - process.StartInfo.FileName = "cmd.exe"; - process.StartInfo.Arguments = $@" /C ..\..\VSPipe.exe -c y4m --arg ""slot=1"" --arg ""video_path={inputFilePath}"" ./animejanai_v2_encode.vpy - | ffmpeg -i pipe: -i ""{inputFilePath}"" -map 0:v -c:v {FfmpegVideoSettings} -map 1:t? -map 1:a? -map 1:s? -c:t copy -c:a copy -c:s copy ""{outputFilePath}"""; - process.StartInfo.RedirectStandardOutput = false; - process.StartInfo.UseShellExecute = false; - process.StartInfo.CreateNoWindow = false; - process.StartInfo.WorkingDirectory = Path.GetFullPath(@".\mpv-upscale-2x_animejanai\portable_config\shaders"); - - process.Start(); - ChildProcessTracker.AddProcess(process); - process.WaitForExit(); - } + var cmd = $@"..\..\VSPipe.exe -c y4m --arg ""slot=1"" --arg ""video_path={inputFilePath}"" --start 0 --end 1 ./animejanai_v2_encode.vpy -p ."; + ConsoleText += $"Generating TensorRT engine with command: {cmd}"; + await RunCommand($@" /C {cmd}"); } - public void GenerateEngine(string inputFilePath) + public async Task RunCommand(string command) { - // Create a new process to run the CMD command - using (var process = new Process()) + await Task.Run(async () => { - process.StartInfo.FileName = "cmd.exe"; - process.StartInfo.Arguments = $@" /C ..\..\VSPipe.exe -c y4m --arg ""slot=1"" --arg ""video_path={inputFilePath}"" --start 0 --end 1 ./animejanai_v2_encode.vpy -p ."; - process.StartInfo.RedirectStandardOutput = false; - process.StartInfo.UseShellExecute = false; - process.StartInfo.CreateNoWindow = false; - process.StartInfo.WorkingDirectory = Path.GetFullPath(@".\mpv-upscale-2x_animejanai\portable_config\shaders"); - - process.Start(); - ChildProcessTracker.AddProcess(process); - process.WaitForExit(); - } + // Create a new process to run the CMD command + using (var process = new Process()) + { + process.StartInfo.FileName = "cmd.exe"; + process.StartInfo.Arguments = command; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.WorkingDirectory = Path.GetFullPath(@".\mpv-upscale-2x_animejanai\portable_config\shaders"); + + // Create a StreamWriter to write the output to a log file + using (var outputFile = new StreamWriter("error.log", append: true)) + { + process.ErrorDataReceived += (sender, e) => + { + if (!string.IsNullOrEmpty(e.Data)) + { + outputFile.WriteLine(e.Data); // Write the output to the log file + ConsoleText += e.Data + "\n"; + } + }; + + process.OutputDataReceived += (sender, e) => + { + if (!string.IsNullOrEmpty(e.Data)) + { + outputFile.WriteLine(e.Data); // Write the output to the log file + ConsoleText += e.Data + "\n"; + } + }; + + process.Start(); + process.BeginErrorReadLine(); // Start asynchronous reading of the output + await process.WaitForExitAsync(); + } + ChildProcessTracker.AddProcess(process); + } + }); } } diff --git a/AnimeJaNaiConverterGui/Views/MainWindow.axaml b/AnimeJaNaiConverterGui/Views/MainWindow.axaml index ee27841..e19055c 100644 --- a/AnimeJaNaiConverterGui/Views/MainWindow.axaml +++ b/AnimeJaNaiConverterGui/Views/MainWindow.axaml @@ -17,70 +17,91 @@ + + + - + Input Video - + + + + + diff --git a/AnimeJaNaiConverterGui/Views/MainWindow.axaml.cs b/AnimeJaNaiConverterGui/Views/MainWindow.axaml.cs index d46b7d9..e9aad8e 100644 --- a/AnimeJaNaiConverterGui/Views/MainWindow.axaml.cs +++ b/AnimeJaNaiConverterGui/Views/MainWindow.axaml.cs @@ -1,13 +1,12 @@ using AnimeJaNaiConverterGui.ViewModels; +using Avalonia; using Avalonia.Controls; -using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Markup.Xaml; using Avalonia.Platform.Storage; using Avalonia.ReactiveUI; using ReactiveUI; using System; -using System.Collections.Generic; using System.IO; namespace AnimeJaNaiConverterGui.Views @@ -19,6 +18,30 @@ public MainWindow() //InitializeComponent(); AvaloniaXamlLoader.Load(this); this.WhenActivated(disposable => { }); + Resized += MainWindow_Resized; ; + } + + private void ConsoleTextBlock_PropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) + { + if (e.Property.Name == "Text") + { + var consoleScrollViewer = this.FindControl("ConsoleScrollViewer"); + if (consoleScrollViewer != null) + { + consoleScrollViewer.ScrollToEnd(); + } + } + } + + private void MainWindow_Resized(object? sender, WindowResizedEventArgs e) + { + // Set the ScrollViewer width based on the new parent window's width + var consoleScrollViewer = this.FindControl("ConsoleScrollViewer"); + if (consoleScrollViewer != null) + { + consoleScrollViewer.Width = Width - 40; // Adjust the width as needed + } + } private async void OpenInputFileButtonClick(object? sender, RoutedEventArgs e)