diff --git a/Code/Data/AI.cs b/Code/Data/AI.cs index af6f78b..80bea42 100644 --- a/Code/Data/AI.cs +++ b/Code/Data/AI.cs @@ -19,8 +19,7 @@ namespace Flowframes.Data public AI(string aiNameArg, string friendlyNameArg, string descArg, FlowPackage pkgArg, bool supportsAnyExpArg) { aiName = aiNameArg; - aiNameShort = aiNameArg.Split(' ')[0]; - aiNameShort = aiNameArg.Split('_')[0]; + aiNameShort = aiNameArg.Split(' ')[0].Split('_')[0]; friendlyName = friendlyNameArg; description = descArg; pkg = pkgArg; diff --git a/Code/Data/InterpSettings.cs b/Code/Data/InterpSettings.cs index c6d044f..b7e29a9 100644 --- a/Code/Data/InterpSettings.cs +++ b/Code/Data/InterpSettings.cs @@ -19,7 +19,7 @@ namespace Flowframes public AI ai; public float inFps; public float outFps; - public int interpFactor; + public float interpFactor; public Interpolate.OutMode outMode; public string model; @@ -68,6 +68,35 @@ namespace Flowframes scaledResolution = new Size(0, 0); } + /* + public InterpSettings (string serializedData) + { + Dictionary entries = new Dictionary(); + + foreach(string line in serializedData.SplitIntoLines()) + { + if (line.Length < 3) continue; + string[] keyValuePair = line.Split('|'); + entries.Add(keyValuePair[0], keyValuePair[1]); + } + + foreach (KeyValuePair entry in entries) + { + switch (entry.Key) + { + case "INPATH": inPath = entry.Value; break; + case "OUTPATH": outPath = entry.Value; break; + case "AI": ai = Networks.GetAi(entry.Value); break; + case "INFPS": inFps = float.Parse(entry.Value); break; + case "OUTFPS": outFps = float.Parse(entry.Value); break; + case "INTERPFACTOR": interpFactor = float.Parse(entry.Value); break; + case "OUTMODE": outMode = (Interpolate.OutMode)Enum.Parse(typeof(Interpolate.OutMode), entry.Value); break; + case "MODEL": model = entry.Value; break; + } + } + } + */ + public void UpdatePaths (string inPathArg, string outPathArg) { inPath = inPathArg; @@ -100,15 +129,15 @@ namespace Flowframes } } - public int GetTargetFrameCount(string overrideInputDir = "", int overrideFactor = -1) + public int GetTargetFrameCount(string overrideInputDir = "", float overrideFactor = -1) { if (framesFolder == null || !Directory.Exists(framesFolder)) return 0; string framesDir = (!string.IsNullOrWhiteSpace(overrideInputDir)) ? overrideInputDir : framesFolder; int frames = IOUtils.GetAmountOfFiles(framesDir, false, "*.png"); - int factor = (overrideFactor > 0) ? overrideFactor : interpFactor; - int targetFrameCount = (frames * factor) - (interpFactor - 1); + float factor = (overrideFactor > 0) ? overrideFactor : interpFactor; + int targetFrameCount = ((frames * factor) - (interpFactor - 1)).RoundToInt(); return targetFrameCount; } @@ -127,5 +156,22 @@ namespace Flowframes alpha = false; } } + + public string Serialize () + { + string s = $"INPATH|{inPath}\n"; + s += $"OUTPATH|{outPath}\n"; + s += $"AI|{ai.aiName}\n"; + s += $"INFPS|{inFps.ToStringDot()}\n"; + s += $"OUTFPS|{outFps.ToStringDot()}\n"; + s += $"INTERPFACTOR|{interpFactor}\n"; + s += $"OUTMODE|{outMode}\n"; + s += $"MODEL|{model}\n"; + s += $"INPUTRES|{inputResolution}\n"; + s += $"OUTPUTRES|{scaledResolution}\n"; + s += $"ALPHA|{alpha}\n"; + + return s; + } } } diff --git a/Code/Data/Networks.cs b/Code/Data/Networks.cs index 5b2233e..7f0b72a 100644 --- a/Code/Data/Networks.cs +++ b/Code/Data/Networks.cs @@ -19,5 +19,16 @@ namespace Flowframes.Data networks.Add(rifeNcnn); networks.Add(dainNcnn); } + + public static AI GetAi (string aiName) + { + foreach(AI ai in networks) + { + if (ai.aiName == aiName) + return ai; + } + + return networks[0]; + } } } \ No newline at end of file diff --git a/Code/Data/ResumeState.cs b/Code/Data/ResumeState.cs index 1f3e8b2..3868c40 100644 --- a/Code/Data/ResumeState.cs +++ b/Code/Data/ResumeState.cs @@ -19,11 +19,11 @@ namespace Flowframes.Data public override string ToString () { - string s = $"AUTOENC|{autoEncode}"; + string s = $"AUTOENC|{autoEncode}\n"; if (!autoEncode) { - s += $"\nLASTINPUTFRAME|{lastInterpolatedInputFrame}"; + s += $"LASTINPUTFRAME|{lastInterpolatedInputFrame}"; } return s; diff --git a/Code/Form1.cs b/Code/Form1.cs index e51ccbc..ddea2e4 100644 --- a/Code/Form1.cs +++ b/Code/Form1.cs @@ -338,6 +338,10 @@ namespace Flowframes SetTab("interpolation"); Logger.Log("Selected video/directory: " + Path.GetFileName(files[0])); inputTbox.Text = files[0]; + + if (IOUtils.GetAmountOfFiles(Path.Combine(files[0], Paths.resumeDir), true) > 0) + ResumeUtils.LoadTempFolder(files[0]); + MainUiFunctions.InitInput(outputTbox, inputTbox, fpsInTbox); } } diff --git a/Code/IO/IOUtils.cs b/Code/IO/IOUtils.cs index 35c8654..a996cbd 100644 --- a/Code/IO/IOUtils.cs +++ b/Code/IO/IOUtils.cs @@ -421,9 +421,9 @@ namespace Flowframes.IO return GetExportSuffix(Interpolate.current.interpFactor, Interpolate.current.ai, Interpolate.current.model); } - public static string GetExportSuffix(int factor, AI ai, string mdl) + public static string GetExportSuffix(float factor, AI ai, string mdl) { - string suffix = $"-{factor}x-{ai.aiNameShort.ToUpper()}"; + string suffix = $"-{factor.ToStringDot()}x-{ai.aiNameShort.ToUpper()}"; if (Config.GetBool("modelSuffix")) suffix += $"-{mdl}"; return suffix; diff --git a/Code/Main/AutoEncode.cs b/Code/Main/AutoEncode.cs index 442b5f2..6eb197d 100644 --- a/Code/Main/AutoEncode.cs +++ b/Code/Main/AutoEncode.cs @@ -28,7 +28,7 @@ namespace Flowframes.Main public static void UpdateChunkAndBufferSizes () { - chunkSize = GetChunkSize(IOUtils.GetAmountOfFiles(Interpolate.current.framesFolder, false, "*.png") * Interpolate.current.interpFactor); + chunkSize = GetChunkSize((IOUtils.GetAmountOfFiles(Interpolate.current.framesFolder, false, "*.png") * Interpolate.current.interpFactor).RoundToInt()); bool isNcnn = Interpolate.current.ai.aiName.ToUpper().Contains("NCNN"); safetyBufferFrames = isNcnn ? Config.GetInt("autoEncSafeBufferNcnn", 90) : Config.GetInt("autoEncSafeBufferCuda", 30); // Use bigger safety buffer for NCNN } diff --git a/Code/Main/CreateVideo.cs b/Code/Main/CreateVideo.cs index 5def87a..81806ac 100644 --- a/Code/Main/CreateVideo.cs +++ b/Code/Main/CreateVideo.cs @@ -189,7 +189,7 @@ namespace Flowframes.Main int times = -1; int minLength = Config.GetInt("minOutVidLength"); int minFrameCount = (minLength * i.current.outFps).RoundToInt(); - int outFrames = i.currentInputFrameCount * i.current.interpFactor; + int outFrames = (i.currentInputFrameCount * i.current.interpFactor).RoundToInt(); if (outFrames / i.current.outFps < minLength) times = (int)Math.Ceiling((double)minFrameCount / (double)outFrames); times--; // Not counting the 1st play (0 loops) diff --git a/Code/Main/FrameOrder.cs b/Code/Main/FrameOrder.cs index 7a199e3..532fbad 100644 --- a/Code/Main/FrameOrder.cs +++ b/Code/Main/FrameOrder.cs @@ -17,7 +17,7 @@ namespace Flowframes.Main public enum Mode { CFR, VFR } public static int timebase = 10000; - public static async Task CreateFrameOrderFile(string framesPath, bool loopEnabled, int times) + public static async Task CreateFrameOrderFile(string framesPath, bool loopEnabled, float times) { Logger.Log("Generating frame order information..."); try @@ -45,7 +45,7 @@ namespace Flowframes.Main } } - public static async Task CreateEncFile (string framesPath, bool loopEnabled, int interpFactor, bool notFirstRun) + public static async Task CreateEncFile (string framesPath, bool loopEnabled, float interpFactor, bool notFirstRun) { if (Interpolate.canceled) return; Logger.Log($"Generating frame order information for {interpFactor}x...", false, true); @@ -55,7 +55,7 @@ namespace Flowframes.Main string ext = InterpolateUtils.GetOutExt(); FileInfo[] frameFiles = new DirectoryInfo(framesPath).GetFiles($"*.png"); - string vfrFile = Path.Combine(framesPath.GetParentDir(), $"vfr-{interpFactor}x.ini"); + string vfrFile = Path.Combine(framesPath.GetParentDir(), $"vfr-{interpFactor.ToStringDot()}x.ini"); string fileContent = ""; string dupesFile = Path.Combine(framesPath.GetParentDir(), $"dupes.ini"); LoadDupesFile(dupesFile); @@ -74,7 +74,7 @@ namespace Flowframes.Main { if (Interpolate.canceled) return; - int interpFramesAmount = interpFactor; + int interpFramesAmount = (int)interpFactor; // TODO: This code won't work with fractional factors string inputFilenameNoExt = Path.GetFileNameWithoutExtension(frameFiles[i].Name); int dupesAmount = dupesDict.ContainsKey(inputFilenameNoExt) ? dupesDict[inputFilenameNoExt] : 0; diff --git a/Code/Main/Interpolate.cs b/Code/Main/Interpolate.cs index 66e4afd..1c5e879 100644 --- a/Code/Main/Interpolate.cs +++ b/Code/Main/Interpolate.cs @@ -173,7 +173,7 @@ namespace Flowframes tasks.Add(AiProcess.RunRifeCuda(current.framesFolder, current.interpFactor, current.model)); if (ai.aiName == Networks.rifeNcnn.aiName) - tasks.Add(AiProcess.RunRifeNcnn(current.framesFolder, outpath, current.interpFactor, current.model)); + tasks.Add(AiProcess.RunRifeNcnn(current.framesFolder, outpath, (int)current.interpFactor, current.model)); if (ai.aiName == Networks.dainNcnn.aiName) tasks.Add(AiProcess.RunDainNcnn(current.framesFolder, outpath, current.interpFactor, current.model, Config.GetInt("dainNcnnTilesize", 512))); @@ -199,7 +199,7 @@ namespace Flowframes Program.mainForm.SetProgress(0); if (Config.GetInt("processingMode") == 0 && !Config.GetBool("keepTempFolder")) { - if(IOUtils.GetAmountOfFiles(current.interpFolder, false) > ResumeUtils.minFrames) + if(IOUtils.GetAmountOfFiles(Path.Combine(current.tempFolder, Paths.resumeDir), true) > 0) { DialogResult dialogResult = MessageBox.Show($"Delete the temp folder (Yes) or keep it for resuming later (No)?", "Delete temporary files?", MessageBoxButtons.YesNo); if (dialogResult == DialogResult.Yes) diff --git a/Code/Main/InterpolateUtils.cs b/Code/Main/InterpolateUtils.cs index ebec362..b7c7215 100644 --- a/Code/Main/InterpolateUtils.cs +++ b/Code/Main/InterpolateUtils.cs @@ -61,7 +61,7 @@ namespace Flowframes.Main public static int targetFrames; public static string currentOutdir; - public static int currentFactor; + public static float currentFactor; public static bool progressPaused = false; public static bool progCheckRunning = false; public static async void GetProgressByFrameAmount(string outdir, int target) @@ -215,7 +215,7 @@ namespace Flowframes.Main return Path.Combine(basePath, Path.GetFileNameWithoutExtension(inPath).StripBadChars().Remove(" ").Trunc(30, false) + "-temp"); } - public static bool InputIsValid(string inDir, string outDir, float fpsOut, int interp, Interpolate.OutMode outMode) + public static bool InputIsValid(string inDir, string outDir, float fpsOut, float factor, Interpolate.OutMode outMode) { bool passes = true; @@ -231,7 +231,7 @@ namespace Flowframes.Main ShowMessage("Output path is not valid!"); passes = false; } - if (passes && interp != 2 && interp != 4 && interp != 8) + if (passes && /*factor != 2 && factor != 4 && factor != 8*/ factor > 16) { ShowMessage("Interpolation factor is not valid!"); passes = false; diff --git a/Code/Main/ResumeUtils.cs b/Code/Main/ResumeUtils.cs index 273668f..6114bb4 100644 --- a/Code/Main/ResumeUtils.cs +++ b/Code/Main/ResumeUtils.cs @@ -15,39 +15,39 @@ namespace Flowframes.Main { 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 safetyDelayFrames = 50; + public static string resumeFilename = "resume.ini"; + public static string interpSettingsFilename = "interpSettings.ini"; + public static string filenameMapFilename = "frameFilenames.ini"; public static int currentOutFrames; public static Stopwatch timeSinceLastSave = new Stopwatch(); public static void Save () { + Logger.Log("Save()", true); if (timeSinceLastSave.IsRunning && timeSinceLastSave.ElapsedMilliseconds < (timeBetweenSaves * 1000f).RoundToInt()) return; + Logger.Log("Stopwatch is running and elapsed time is long enough to save again", true); + int frames = (int)Math.Round((float)currentOutFrames / Interpolate.current.interpFactor) - safetyDelayFrames; + Logger.Log($"frames minus safetyDelayFrames = {frames}", true); + if (frames < 1) return; timeSinceLastSave.Restart(); Directory.CreateDirectory(Path.Combine(Interpolate.current.tempFolder, Paths.resumeDir)); - SaveState(); + SaveState(frames); + SaveInterpSettings(); + SaveFilenameMap(); } - public static async Task SaveState () + static void SaveState (int frames) { - 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; + string filePath = Path.Combine(Interpolate.current.tempFolder, Paths.resumeDir, resumeFilename); + File.WriteAllText(filePath, state.ToString()); } static async Task SaveFilenameMap () { - string filePath = Path.Combine(Interpolate.current.tempFolder, Paths.resumeDir, filenameMapFileName); + string filePath = Path.Combine(Interpolate.current.tempFolder, Paths.resumeDir, filenameMapFilename); if (File.Exists(filePath) && IOUtils.GetFilesize(filePath) > 0) return; @@ -65,10 +65,21 @@ namespace Flowframes.Main File.WriteAllText(filePath, fileContent); } + static void SaveInterpSettings () + { + string filePath = Path.Combine(Interpolate.current.tempFolder, Paths.resumeDir, interpSettingsFilename); + File.WriteAllText(filePath, Interpolate.current.Serialize()); + } + + public static void LoadTempFolder (string tempFolderPath) + { + string resumeFolderPath = Path.Combine(tempFolderPath, Paths.resumeDir); + } + static void LoadFilenameMap() { Dictionary dict = new Dictionary(); - string filePath = Path.Combine(Interpolate.current.tempFolder, Paths.resumeDir, filenameMapFileName); + string filePath = Path.Combine(Interpolate.current.tempFolder, Paths.resumeDir, filenameMapFilename); string[] dictLines = File.ReadAllLines(filePath); foreach (string line in dictLines) diff --git a/Code/OS/AiProcess.cs b/Code/OS/AiProcess.cs index a0f6d1b..80f4bc1 100644 --- a/Code/OS/AiProcess.cs +++ b/Code/OS/AiProcess.cs @@ -38,10 +38,10 @@ namespace Flowframes hasShownError = false; } - static void SetProgressCheck(string interpPath, int factor) + static void SetProgressCheck(string interpPath, float factor) { int frames = IOUtils.GetAmountOfFiles(lastInPath, false, "*.png"); - int target = (frames * factor) - (factor - 1); + int target = ((frames * factor) - (factor - 1)).RoundToInt(); InterpolateUtils.progressPaused = false; InterpolateUtils.currentFactor = factor; @@ -89,7 +89,7 @@ namespace Flowframes } } - public static async Task RunRifeCuda(string framesPath, int interpFactor, string mdl) + public static async Task RunRifeCuda(string framesPath, float interpFactor, string mdl) { string rifeDir = Path.Combine(Paths.GetPkgPath(), Path.GetFileNameWithoutExtension(Packages.rifeCuda.fileName)); string script = "rife.py"; @@ -112,7 +112,7 @@ namespace Flowframes await AiFinished("RIFE"); } - public static async Task RunRifeCudaProcess (string inPath, string outDir, string script, int interpFactor, string mdl) + public static async Task RunRifeCudaProcess (string inPath, string outDir, string script, float interpFactor, string mdl) { bool parallel = false; string uhdStr = await InterpolateUtils.UseUHD() ? "--UHD" : ""; @@ -222,7 +222,7 @@ namespace Flowframes while (!rifeNcnn.HasExited) await Task.Delay(1); } - public static async Task RunDainNcnn(string framesPath, string outPath, int factor, string mdl, int tilesize) + public static async Task RunDainNcnn(string framesPath, string outPath, float factor, string mdl, int tilesize) { await RunDainNcnnProcess(framesPath, outPath, factor, mdl, tilesize); @@ -236,14 +236,14 @@ namespace Flowframes await AiFinished("DAIN"); } - public static async Task RunDainNcnnProcess (string framesPath, string outPath, int factor, string mdl, int tilesize) + public static async Task RunDainNcnnProcess (string framesPath, string outPath, float factor, string mdl, int tilesize) { string dainDir = Path.Combine(Paths.GetPkgPath(), Path.GetFileNameWithoutExtension(Packages.dainNcnn.fileName)); Directory.CreateDirectory(outPath); Process dain = OSUtils.NewProcess(!OSUtils.ShowHiddenCmd()); AiStarted(dain, 1500); SetProgressCheck(outPath, factor); - int targetFrames = (IOUtils.GetAmountOfFiles(lastInPath, false, "*.png") * factor) - (factor - 1); + int targetFrames = ((IOUtils.GetAmountOfFiles(lastInPath, false, "*.png") * factor).RoundToInt()) - (factor.RoundToInt() - 1); // TODO: Won't work with fractional factors string args = $" -v -i {framesPath.Wrap()} -o {outPath.Wrap()} -n {targetFrames} -m {mdl.ToLower()}" + $" -t {GetNcnnTilesize(tilesize)} -g {Config.Get("ncnnGpus")} -f {GetNcnnPattern()} -j 2:1:2"; diff --git a/Code/UI/MainUiFunctions.cs b/Code/UI/MainUiFunctions.cs index 0be0c5d..31ba25f 100644 --- a/Code/UI/MainUiFunctions.cs +++ b/Code/UI/MainUiFunctions.cs @@ -27,8 +27,8 @@ namespace Flowframes.UI outputTbox.Text = inputTbox.Text.Trim().GetParentDir(); string path = inputTbox.Text.Trim(); Program.lastInputPath = path; - Program.lastInputPathIsSsd = OSUtils.DriveIsSSD(path); + if (!Program.lastInputPathIsSsd) Logger.Log("Your file seems to be on an HDD or USB device. It is recommended to interpolate videos on an SSD drive for best performance."); @@ -37,11 +37,10 @@ namespace Flowframes.UI string fpsStr = "Not Found"; float fps = IOUtils.GetFpsFolderOrVideo(path); + fpsInTbox.Text = fps.ToString(); + if (fps > 0) - { fpsStr = fps.ToString(); - fpsInTbox.Text = fpsStr; - } if (IOUtils.IsPathDirectory(path)) Logger.Log($"Video FPS (Loaded from fps.ini): {fpsStr} - Total Number Of Frames: {frameCount}", false, true);