diff --git a/Code/Extensions/ProcessExtensions.cs b/Code/Extensions/ProcessExtensions.cs index d7676c9f..2704112d 100644 --- a/Code/Extensions/ProcessExtensions.cs +++ b/Code/Extensions/ProcessExtensions.cs @@ -1,11 +1,8 @@ using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Linq; using System.Runtime.InteropServices; -using System.Text; +using System.Threading; using System.Threading.Tasks; -using Win32Interop; namespace Flowframes.Extensions { @@ -57,5 +54,46 @@ public static void Resume(this Process process) ResumeThread(pOpenThread); } } + + public static async Task WaitForExitAsync(this Process process, CancellationToken cancellationToken = default) + { + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + + void Process_Exited(object sender, EventArgs e) + { + tcs.TrySetResult(process.ExitCode); + } + + try + { + process.EnableRaisingEvents = true; + } + catch (InvalidOperationException) when (process.HasExited) + { + // This is expected when trying to enable events after the process has already exited. + // Simply ignore this case. + // Allow the exception to bubble in all other cases. + } + + using (cancellationToken.Register(() => tcs.TrySetCanceled())) + { + process.Exited += Process_Exited; + + try + { + + if (process.HasExited) + { + tcs.TrySetResult(process.ExitCode); + } + + return await tcs.Task.ConfigureAwait(false); + } + finally + { + process.Exited -= Process_Exited; + } + } + } } } diff --git a/Code/IO/Logger.cs b/Code/IO/Logger.cs index 9078d4c6..87feae1a 100644 --- a/Code/IO/Logger.cs +++ b/Code/IO/Logger.cs @@ -18,7 +18,7 @@ class Logger public const string defaultLogName = "sessionlog"; public static long id; - private static Dictionary sessionLogs = new Dictionary(); + private static Dictionary> sessionLogs = new Dictionary>(); private static string _lastUi = ""; public static string LastUiLine { get { return _lastUi; } } private static string _lastLog = ""; @@ -116,7 +116,12 @@ public static void LogToFile(string logStr, bool noLineBreak, string filename) try { string appendStr = noLineBreak ? $" {logStr}" : $"{Environment.NewLine}[{id.ToString().PadLeft(8, '0')}] [{time}]: {logStr}"; - sessionLogs[filename] = (sessionLogs.ContainsKey(filename) ? sessionLogs[filename] : "") + appendStr; + //sessionLogs[filename] = (sessionLogs.ContainsKey(filename) ? sessionLogs[filename] : "") + appendStr; + List sessionLog = (sessionLogs.ContainsKey(filename) ? sessionLogs[filename] : new List()); + sessionLog.Add(appendStr); + if (sessionLog.Count > 10) + sessionLog.RemoveAt(0); + sessionLogs[filename] = sessionLog; File.AppendAllText(file, appendStr); id++; } @@ -126,7 +131,7 @@ public static void LogToFile(string logStr, bool noLineBreak, string filename) } } - public static string GetSessionLog(string filename) + public static List GetSessionLog(string filename) { if (!filename.Contains(".txt")) filename = Path.ChangeExtension(filename, "txt"); @@ -134,14 +139,15 @@ public static string GetSessionLog(string filename) if (sessionLogs.ContainsKey(filename)) return sessionLogs[filename]; else - return ""; + return new List(); } public static List GetSessionLogLastLines(string filename, int linesCount = 5) { - string log = GetSessionLog(filename); - string[] lines = log.SplitIntoLines(); - return lines.Reverse().Take(linesCount).Reverse().ToList(); + List log = GetSessionLog(filename); + //string[] lines = log.SplitIntoLines(); + //return lines.Reverse().Take(linesCount).Reverse().ToList(); + return log.Count > linesCount ? log.GetRange(0, linesCount) : log; } public static void LogIfLastLineDoesNotContainMsg(string s, bool hidden = false, bool replaceLastLine = false, string filename = "") diff --git a/Code/Main/AutoEncode.cs b/Code/Main/AutoEncode.cs index 72874a6a..1d5520fa 100644 --- a/Code/Main/AutoEncode.cs +++ b/Code/Main/AutoEncode.cs @@ -1,16 +1,15 @@ -using Flowframes.Media; -using Flowframes.Data; +using Flowframes.Data; using Flowframes.IO; +using Flowframes.Media; using Flowframes.MiscUtils; +using Flowframes.Os; +using Flowframes.Ui; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; -using System.Text; using System.Threading.Tasks; -using Flowframes.Ui; -using Flowframes.Os; namespace Flowframes.Main { @@ -67,7 +66,7 @@ public static async Task MainLoop(string interpFramesPath) Logger.Log($"[AE] Starting AutoEncode MainLoop - Chunk Size: {chunkSize} Frames - Safety Buffer: {safetyBufferFrames} Frames", true); int chunkNo = AutoEncodeResume.encodedChunks + 1; string encFile = Path.Combine(interpFramesPath.GetParentDir(), Paths.GetFrameOrderFilename(Interpolate.currentSettings.interpFactor)); - interpFramesLines = IoUtils.ReadLines(encFile).Select(x => x.Split('/').Last().Remove("'").Split('#').First()).ToArray(); // Array with frame filenames + interpFramesLines = IoUtils.ReadLines(encFile).Where(x => x.StartsWith("file ")).Select(x => x.Split('/').Last().Remove("'").Split('#').First()).ToArray(); // Array with frame filenames while (!Interpolate.canceled && GetInterpFramesAmount() < 2) await Task.Delay(1000); @@ -78,7 +77,7 @@ public static async Task MainLoop(string interpFramesPath) { if (Interpolate.canceled) return; - if (paused) + if (paused || InterpolationProgress.lastFrame == 0) { await Task.Delay(200); continue; @@ -229,12 +228,16 @@ public static bool HasWorkToDo () static int GetChunkSize(int targetFramesAmount) { - if (targetFramesAmount > 100000) return 4800; + /*if (targetFramesAmount > 100000) return 4800; if (targetFramesAmount > 50000) return 2400; if (targetFramesAmount > 20000) return 1200; if (targetFramesAmount > 5000) return 600; if (targetFramesAmount > 1000) return 300; - return 150; + return 150;*/ + int round = (int)Math.Floor(targetFramesAmount / 2400f); + if (round == 0) + round = 1; + return Math.Min(round * 600, 6000); } static int GetInterpFramesAmount() diff --git a/Code/Main/Export.cs b/Code/Main/Export.cs index 75fa0927..bcfa902d 100644 --- a/Code/Main/Export.cs +++ b/Code/Main/Export.cs @@ -1,20 +1,19 @@ -using Flowframes.IO; +using Flowframes.Data; +using Flowframes.IO; using Flowframes.Magick; +using Flowframes.Media; +using Flowframes.MiscUtils; +using Flowframes.Os; +using Flowframes.Ui; +using Newtonsoft.Json; using System; +using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Threading.Tasks; -using System.Windows.Forms; -using Padding = Flowframes.Data.Padding; using I = Flowframes.Interpolate; -using System.Diagnostics; -using Flowframes.Data; -using Flowframes.Media; -using Flowframes.MiscUtils; -using Flowframes.Os; -using System.Collections.Generic; -using Newtonsoft.Json; -using Flowframes.Ui; +using Padding = Flowframes.Data.Padding; namespace Flowframes.Main { @@ -284,7 +283,7 @@ public static async Task EncodeChunk(string outPath, string interpDir, int chunk { string framesFileFull = Path.Combine(I.currentSettings.tempFolder, Paths.GetFrameOrderFilename(I.currentSettings.interpFactor)); string concatFile = Path.Combine(I.currentSettings.tempFolder, Paths.GetFrameOrderFilenameChunk(firstFrameNum, firstFrameNum + framesAmount)); - File.WriteAllLines(concatFile, IoUtils.ReadLines(framesFileFull).Skip(firstFrameNum).Take(framesAmount)); + File.WriteAllLines(concatFile, IoUtils.ReadLines(framesFileFull).Skip(firstFrameNum*2).Take(framesAmount*2)); List inputFrames = JsonConvert.DeserializeObject>(File.ReadAllText(framesFileFull + ".inputframes.json")).Skip(firstFrameNum).Take(framesAmount).ToList(); @@ -367,7 +366,7 @@ public static async Task MuxOutputVideo(string inputPath, string outVideo, bool { if (!File.Exists(outVideo)) { - I.Cancel($"No video was encoded!\n\nFFmpeg Output:\n{AvProcess.lastOutputFfmpeg}"); + I.Cancel($"No video was encoded!\n\nFFmpeg Output:\n{await OsUtils.GetOutputAsync(AvProcess.lastAvProcess)}"); return; } diff --git a/Code/Main/FrameOrder.cs b/Code/Main/FrameOrder.cs index e7e3564e..f84473f9 100644 --- a/Code/Main/FrameOrder.cs +++ b/Code/Main/FrameOrder.cs @@ -1,8 +1,6 @@ using Flowframes.Data; using Flowframes.IO; using Flowframes.MiscUtils; -using Flowframes.Os; -using Flowframes.Properties; using Newtonsoft.Json; using System; using System.Collections.Generic; @@ -15,13 +13,12 @@ namespace Flowframes.Main { class FrameOrder { - private static Stopwatch benchmark = new Stopwatch(); - private static FileInfo[] frameFiles; - private static FileInfo[] frameFilesWithoutLast; - private static List sceneFrames = new List(); - private static Dictionary frameFileContents = new Dictionary(); - private static List inputFilenames = new List(); - private static int lastOutFileCount; + static Stopwatch benchmark = new Stopwatch(); + static FileInfo[] frameFiles; + static List sceneFrames = new List(); + static Dictionary frameFileContents = new Dictionary(); + static List inputFilenames = new List(); + static int lastOutFileCount; public static async Task CreateFrameOrderFile(string tempFolder, bool loopEnabled, float interpFactor) { @@ -154,8 +151,6 @@ public static async Task CreateFramesFileImgSeq(string tempFolder, bool loop, fl string framesDir = Path.Combine(tempFolder, Paths.framesDir); frameFiles = new DirectoryInfo(framesDir).GetFiles("*" + Interpolate.currentSettings.framesExt); - frameFilesWithoutLast = frameFiles; - Array.Resize(ref frameFilesWithoutLast, frameFilesWithoutLast.Length - 1); string framesFile = Path.Combine(tempFolder, Paths.GetFrameOrderFilename(interpFactor)); string fileContent = ""; string dupesFile = Path.Combine(tempFolder, "dupes.json"); @@ -178,7 +173,7 @@ public static async Task CreateFramesFileImgSeq(string tempFolder, bool loop, fl if (interpFactor == (int)interpFactor) // Use old multi-threaded code if factor is not fractional { - for (int i = 0; i < frameFilesWithoutLast.Length; i += linesPerTask) + for (int i = 0; i < frameFiles.Length; i += linesPerTask) { tasks.Add(GenerateFrameLines(num, i, linesPerTask, (int)interpFactor, sceneDetection, debug)); num++; @@ -198,10 +193,13 @@ public static async Task CreateFramesFileImgSeq(string tempFolder, bool loop, fl if (Config.GetBool(Config.Key.fixOutputDuration)) // Match input duration by padding duping last frame until interp frames == (inputframes * factor) { - int neededFrames = (frameFiles.Length * interpFactor).RoundToInt() - fileContent.SplitIntoLines().Where(x => x.StartsWith("'file ")).Count(); + int neededFrames = (frameFiles.Length * interpFactor).RoundToInt() - fileContent.SplitIntoLines().Where(x => x.StartsWith("file ")).Count(); for (int i = 0; i < neededFrames; i++) - fileContent += fileContent.SplitIntoLines().Where(x => x.StartsWith("'file ")).Last(); + { + fileContent += fileContent.SplitIntoLines().Where(x => x.StartsWith("file ")).Last() + "\n"; + fileContent += fileContent.SplitIntoLines().Where(x => x.StartsWith("duration ")).Last() + "\n"; + } } if (loop) @@ -341,13 +339,15 @@ static async Task GenerateFrameLines(int number, int startIndex, int count, int for (int i = startIndex; i < (startIndex + count); i++) { if (Interpolate.canceled) return; - if (i >= frameFilesWithoutLast.Length) break; + if (i >= frameFiles.Length) break; - string frameName = GetNameNoExt(frameFilesWithoutLast[i].Name); + string frameName = GetNameNoExt(frameFiles[i].Name); string frameNameImport = GetNameNoExt(FrameRename.importFilenames[i]); int dupesAmount = dupesDict.ContainsKey(frameNameImport) ? dupesDict[frameNameImport].Count : 0; - bool discardThisFrame = (sceneDetection && i < frameFilesWithoutLast.Length && sceneFrames.Contains(GetNameNoExt(FrameRename.importFilenames[i + 1]))); // i+2 is in scene detection folder, means i+1 is ugly interp frame + bool discardThisFrame = (sceneDetection && (i + 1) < FrameRename.importFilenames.Length && sceneFrames.Contains(GetNameNoExt(FrameRename.importFilenames[i + 1]))); // i+2 is in scene detection folder, means i+1 is ugly interp frame + if (i == frameFiles.Length - 1) + interpFramesAmount = 1; for (int frm = 0; frm < interpFramesAmount; frm++) // Generate frames file lines { if (discardThisFrame) // If frame is scene cut frame @@ -386,7 +386,7 @@ static async Task GenerateFrameLines(int number, int startIndex, int count, int fileContent = WriteFrameWithDupes(dupesAmount, fileContent, totalFileCount, ext, debug, $"[In: {frameName}] [{((frm == 0) ? " Source " : $"Interp {frm}")}]"); } - inputFilenames.Add(frameFilesWithoutLast[i].Name); + inputFilenames.Add(frameFiles[i].Name); } } @@ -398,8 +398,12 @@ static async Task GenerateFrameLines(int number, int startIndex, int count, int static string WriteFrameWithDupes(int dupesAmount, string fileContent, int frameNum, string ext, bool debug, string debugNote = "", string forcedNote = "") { + string duration = $"duration {1f / Interpolate.currentSettings.outFps.GetFloat()}"; for (int writtenDupes = -1; writtenDupes < dupesAmount; writtenDupes++) // Write duplicates + { fileContent += $"file '{Paths.interpDir}/{frameNum.ToString().PadLeft(Padding.interpFrames, '0')}{ext}' # {(debug ? ($"Dupe {(writtenDupes + 1).ToString("000")} {debugNote}").Replace("Dupe 000", " ") : "")}{forcedNote}\n"; + fileContent += $"{duration}\n"; + } return fileContent; } diff --git a/Code/Main/Interpolate.cs b/Code/Main/Interpolate.cs index f209ceba..f8ac74a2 100644 --- a/Code/Main/Interpolate.cs +++ b/Code/Main/Interpolate.cs @@ -122,7 +122,7 @@ public static async Task GetFrames() if (Config.GetBool(Config.Key.scnDetect) && !currentSettings.ai.Piped) { Program.mainForm.SetStatus("Extracting scenes from video..."); - await FfmpegExtract.ExtractSceneChanges(currentSettings.inPath, Path.Combine(currentSettings.tempFolder, Paths.scenesDir), currentSettings.inFpsDetected, currentSettings.inputIsFrames, currentSettings.framesExt); + await FfmpegExtract.ExtractSceneChanges(currentSettings.inPath, Path.Combine(currentSettings.tempFolder, Paths.scenesDir), currentSettings.inFps, currentSettings.inputIsFrames, currentSettings.framesExt); } if (!currentSettings.inputIsFrames) // Extract if input is video, import if image sequence @@ -138,7 +138,7 @@ public static async Task ExtractFrames(string inPath, string outPath, bool alpha currentSettings.RefreshExtensions(InterpSettings.FrameType.Import); bool mpdecimate = Config.GetInt(Config.Key.dedupMode) == 2; Size res = await Utils.GetOutputResolution(inPath, true, true); - await FfmpegExtract.VideoToFrames(inPath, outPath, alpha, currentSettings.inFpsDetected, mpdecimate, false, res, currentSettings.framesExt); + await FfmpegExtract.VideoToFrames(inPath, outPath, alpha, currentSettings.inFps, mpdecimate, false, res, currentSettings.framesExt); if (mpdecimate) { diff --git a/Code/Media/AvProcess.cs b/Code/Media/AvProcess.cs index 8e6dbd34..fac2e3a0 100644 --- a/Code/Media/AvProcess.cs +++ b/Code/Media/AvProcess.cs @@ -1,33 +1,22 @@ -using Flowframes.IO; +using Flowframes.Extensions; +using Flowframes.IO; +using Flowframes.Media; +using Flowframes.MiscUtils; using Flowframes.Os; using System; -using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; -using System.Text; -using System.Text.RegularExpressions; using System.Threading.Tasks; -using Flowframes.MiscUtils; -using Microsoft.VisualBasic; -using Flowframes.Media; -using System.Windows.Input; namespace Flowframes { class AvProcess { public static Process lastAvProcess; - public static Stopwatch timeSinceLastOutput = new Stopwatch(); - - public static string lastOutputFfmpeg; - public enum LogMode { Visible, OnlyLastLine, Hidden } - static LogMode currentLogMode; - static bool showProgressBar; static readonly string defLogLevel = "warning"; - public static void Kill() { if (lastAvProcess == null) return; @@ -93,7 +82,7 @@ public static async Task RunFfmpeg(string args, string workingDir, LogMo ffmpeg.BeginErrorReadLine(); } - while (!ffmpeg.HasExited) await Task.Delay(10); + await ffmpeg.WaitForExitAsync(); while (reliableOutput && timeSinceLastOutput.ElapsedMs < 200) await Task.Delay(50); if (progressBar) @@ -176,7 +165,7 @@ public static async Task RunFfprobe(FfprobeSettings settings, bool async ffprobe.BeginErrorReadLine(); } - while (!ffprobe.HasExited) await Task.Delay(10); + await ffprobe.WaitForExitAsync(); while (timeSinceLastOutput.ElapsedMs < 200) await Task.Delay(50); return processOutput; diff --git a/Code/Media/FfmpegUtils.cs b/Code/Media/FfmpegUtils.cs index 04f19f37..d6e3b11d 100644 --- a/Code/Media/FfmpegUtils.cs +++ b/Code/Media/FfmpegUtils.cs @@ -21,7 +21,6 @@ namespace Flowframes.Media class FfmpegUtils { private readonly static FfprobeMode showStreams = FfprobeMode.ShowStreams; - private readonly static FfprobeMode showFormat = FfprobeMode.ShowFormat; public static List CompatibleHwEncoders = new List(); public static bool NvencSupportsBFrames = false; diff --git a/Code/MiscUtils/FrameRename.cs b/Code/MiscUtils/FrameRename.cs index b6c2ddd9..c7b361f2 100644 --- a/Code/MiscUtils/FrameRename.cs +++ b/Code/MiscUtils/FrameRename.cs @@ -1,12 +1,9 @@ -using System; -using System.Collections.Generic; +using Flowframes.Data; +using Flowframes.IO; using System.Diagnostics; using System.IO; using System.Linq; -using System.Text; using System.Threading.Tasks; -using Flowframes.Data; -using Flowframes.IO; namespace Flowframes.MiscUtils { @@ -24,6 +21,8 @@ public static async Task Rename() public static async Task Unrename() { + if (!framesAreRenamed) return; + Stopwatch sw = new Stopwatch(); sw.Restart(); diff --git a/Code/Os/AiProcess.cs b/Code/Os/AiProcess.cs index e6fb68d0..533c467a 100644 --- a/Code/Os/AiProcess.cs +++ b/Code/Os/AiProcess.cs @@ -1,19 +1,17 @@ -using Flowframes.IO; +using Flowframes.Data; +using Flowframes.Extensions; +using Flowframes.IO; +using Flowframes.Main; +using Flowframes.MiscUtils; +using Flowframes.Ui; +using Flowframes.Utilities; using System; using System.Diagnostics; +using System.Drawing; using System.IO; using System.Linq; using System.Threading.Tasks; -using Flowframes.Ui; -using Flowframes.Main; -using Flowframes.Data; -using Flowframes.MiscUtils; -using System.Collections.Generic; -using ImageMagick; using Paths = Flowframes.IO.Paths; -using Flowframes.Media; -using System.Drawing; -using Flowframes.Utilities; namespace Flowframes.Os { @@ -314,7 +312,6 @@ public static async Task RunRifeNcnn(string framesPath, string outPath, float fa static async Task RunRifeNcnnProcess(string inPath, float factor, string outPath, string mdl) { Directory.CreateDirectory(outPath); - string logFileName = "rife-ncnn-log"; Process rifeNcnn = OsUtils.NewProcess(!OsUtils.ShowHiddenCmd()); AiStarted(rifeNcnn, 1500, inPath); SetProgressCheck(outPath, factor); @@ -336,6 +333,7 @@ static async Task RunRifeNcnnProcess(string inPath, float factor, string outPath } rifeNcnn.Start(); + rifeNcnn.PriorityClass = ProcessPriorityClass.BelowNormal; if (!OsUtils.ShowHiddenCmd()) { @@ -343,7 +341,7 @@ static async Task RunRifeNcnnProcess(string inPath, float factor, string outPath rifeNcnn.BeginErrorReadLine(); } - while (!rifeNcnn.HasExited) await Task.Delay(1); + await rifeNcnn.WaitForExitAsync(); } public static async Task RunRifeNcnnVs(string framesPath, string outPath, float factor, string mdl, bool rt = false) diff --git a/Code/Ui/UiUtils.cs b/Code/Ui/UiUtils.cs index f4cc6d54..258a8bea 100644 --- a/Code/Ui/UiUtils.cs +++ b/Code/Ui/UiUtils.cs @@ -92,9 +92,9 @@ public static DialogResult ShowMessageBox(string text, MessageType type = Messag return new DialogResult(); } - MessageBoxIcon icon = MessageBoxIcon.Information; - if (type == MessageType.Warning) icon = MessageBoxIcon.Warning; - else if (type == MessageType.Error) icon = MessageBoxIcon.Error; +// MessageBoxIcon icon = MessageBoxIcon.Information; +// if (type == MessageType.Warning) icon = MessageBoxIcon.Warning; +// else if (type == MessageType.Error) icon = MessageBoxIcon.Error; MessageForm form = new MessageForm(text, type.ToString()); form.ShowDialog();