diff --git a/Code/Data/Paths.cs b/Code/Data/Paths.cs index 8218730..febc205 100644 --- a/Code/Data/Paths.cs +++ b/Code/Data/Paths.cs @@ -9,6 +9,7 @@ namespace Flowframes.IO public const string framesDir = "frames"; public const string interpDir = "interp"; public const string chunksDir = "vchunks"; + public const string resumeDir = "resumedata"; public const string scenesDir = "scenes"; public const string alphaSuffix = "-a"; diff --git a/Code/Data/ResumeState.cs b/Code/Data/ResumeState.cs new file mode 100644 index 0000000..1f3e8b2 --- /dev/null +++ b/Code/Data/ResumeState.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Flowframes.Data +{ + public struct ResumeState + { + bool autoEncode; + int lastInterpolatedInputFrame; + + public ResumeState (bool autoEncArg, int lastInterpInFrameArg) + { + autoEncode = autoEncArg; + lastInterpolatedInputFrame = lastInterpInFrameArg; + } + + public override string ToString () + { + string s = $"AUTOENC|{autoEncode}"; + + if (!autoEncode) + { + s += $"\nLASTINPUTFRAME|{lastInterpolatedInputFrame}"; + } + + return s; + } + } +} diff --git a/Code/Flowframes.csproj b/Code/Flowframes.csproj index 4866c33..aa7fcc7 100644 --- a/Code/Flowframes.csproj +++ b/Code/Flowframes.csproj @@ -205,6 +205,7 @@ + Form @@ -241,6 +242,7 @@ + diff --git a/Code/IO/IOUtils.cs b/Code/IO/IOUtils.cs index 6d29303..35c8654 100644 --- a/Code/IO/IOUtils.cs +++ b/Code/IO/IOUtils.cs @@ -280,11 +280,16 @@ namespace Flowframes.IO return oldNewNamesMap; } - public static void ReverseRenaming(Dictionary oldNewMap, bool clearDict) + public static async Task ReverseRenaming(Dictionary oldNewMap, bool clearDict) { if (oldNewMap == null || oldNewMap.Count < 1) return; + int counter = 0; foreach (KeyValuePair pair in oldNewMap) + { TryMove(pair.Value, pair.Key); + if (counter % 1000 == 0) + await Task.Delay(1); + } if (clearDict) oldNewMap.Clear(); } diff --git a/Code/Main/AutoEncode.cs b/Code/Main/AutoEncode.cs index 2f6fc2d..6ed420a 100644 --- a/Code/Main/AutoEncode.cs +++ b/Code/Main/AutoEncode.cs @@ -117,7 +117,7 @@ namespace Flowframes.Main if (Interpolate.canceled) return; - IOUtils.ReverseRenaming(AiProcess.filenameMap, true); // Get timestamps back + await IOUtils.ReverseRenaming(AiProcess.filenameMap, true); // Get timestamps back await CreateVideo.ChunksToVideos(Interpolate.current.tempFolder, videoChunksFolder, Interpolate.current.outFilename); } catch (Exception e) diff --git a/Code/Main/Interpolate.cs b/Code/Main/Interpolate.cs index 00a7470..ed306db 100644 --- a/Code/Main/Interpolate.cs +++ b/Code/Main/Interpolate.cs @@ -25,11 +25,8 @@ namespace Flowframes public static int currentInputFrameCount; public static bool currentlyUsingAutoEnc; - public static InterpSettings current; - public static bool canceled = false; - static Stopwatch sw = new Stopwatch(); public static async Task Start() @@ -54,7 +51,7 @@ namespace Flowframes Program.mainForm.SetProgress(100); if(!currentlyUsingAutoEnc) await CreateVideo.Export(current.interpFolder, current.outFilename, current.outMode, false); - IOUtils.ReverseRenaming(AiProcess.filenameMap, true); // Get timestamps back + await IOUtils.ReverseRenaming(AiProcess.filenameMap, true); // Get timestamps back await Cleanup(); Program.mainForm.SetWorking(false); Logger.Log("Total processing time: " + FormatUtils.Time(sw.Elapsed)); diff --git a/Code/Main/InterpolateSteps.cs b/Code/Main/InterpolateSteps.cs index 921233e..65c6b72 100644 --- a/Code/Main/InterpolateSteps.cs +++ b/Code/Main/InterpolateSteps.cs @@ -98,7 +98,7 @@ namespace Flowframes.Main currentInputFrameCount = await InterpolateUtils.GetInputFrameCountAsync(current.inPath); - IOUtils.ReverseRenaming(AiProcess.filenameMap, true); // Get timestamps back + await IOUtils.ReverseRenaming(AiProcess.filenameMap, true); // Get timestamps back // TODO: Check if this works lol, remove if it does //if (Config.GetBool("sbsAllowAutoEnc")) diff --git a/Code/Main/InterpolateUtils.cs b/Code/Main/InterpolateUtils.cs index 552b874..c2a9b66 100644 --- a/Code/Main/InterpolateUtils.cs +++ b/Code/Main/InterpolateUtils.cs @@ -98,7 +98,8 @@ namespace Flowframes.Main public static void UpdateInterpProgress(int frames, int target, string latestFramePath = "") { if (i.canceled) return; - + ResumeUtils.currentOutFrames = frames; + ResumeUtils.Save(); frames = frames.Clamp(0, target); int percent = (int)Math.Round(((float)frames / target) * 100f); Program.mainForm.SetProgress(percent); diff --git a/Code/Main/ResumeUtils.cs b/Code/Main/ResumeUtils.cs new file mode 100644 index 0000000..0c5172b --- /dev/null +++ b/Code/Main/ResumeUtils.cs @@ -0,0 +1,83 @@ +using Flowframes.Data; +using Flowframes.IO; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Flowframes.Main +{ + + class ResumeUtils + { + public static float timeBetweenSaves = 10; + public static int minFrames = 100; + public static int safetyDelayFrames = 100; + public static string resumeFileName = "resume.ini"; + public static string filenameMapFileName = "frameFilenames.ini"; + + public static int currentOutFrames; + public static Stopwatch timeSinceLastSave = new Stopwatch(); + + public static void Save () + { + if (timeSinceLastSave.IsRunning && timeSinceLastSave.ElapsedMilliseconds < (timeBetweenSaves * 1000f).RoundToInt()) return; + timeSinceLastSave.Restart(); + Directory.CreateDirectory(Path.Combine(Interpolate.current.tempFolder, Paths.resumeDir)); + SaveState(); + } + + public static async Task SaveState () + { + int frames = GetSafeInterpolatedInputFramesAmount(); + if (frames < 1) return; + ResumeState state = new ResumeState(Interpolate.currentlyUsingAutoEnc, frames); + string stateFilePath = Path.Combine(Interpolate.current.tempFolder, Paths.resumeDir, resumeFileName); + File.WriteAllText(stateFilePath, state.ToString()); + await SaveFilenameMap(); + } + + public static int GetSafeInterpolatedInputFramesAmount() + { + return (int)Math.Round((float)currentOutFrames / Interpolate.current.interpFactor) - safetyDelayFrames; + } + + static async Task SaveFilenameMap () + { + string filePath = Path.Combine(Interpolate.current.tempFolder, Paths.resumeDir, filenameMapFileName); + + if (File.Exists(filePath) && IOUtils.GetFilesize(filePath) > 0) + return; + + string fileContent = ""; + int counter = 0; + + foreach (KeyValuePair entry in AiProcess.filenameMap) + { + if (counter % 500 == 0) await Task.Delay(1); + fileContent += $"{entry.Key}|{entry.Value}\n"; + } + + File.WriteAllText(filePath, fileContent); + } + + static void LoadFilenameMap() + { + Dictionary dict = new Dictionary(); + string filePath = Path.Combine(Interpolate.current.tempFolder, Paths.resumeDir, filenameMapFileName); + string[] dictLines = File.ReadAllLines(filePath); + + foreach (string line in dictLines) + { + if (line.Length < 5) continue; + string[] keyValuePair = line.Split('|'); + dict.Add(keyValuePair[0].Trim(), keyValuePair[1].Trim()); + } + + AiProcess.filenameMap = dict; + } + } +}