Finished vchunk-based saving/resuming, needs some more testing

This commit is contained in:
n00mkrad
2021-09-29 11:22:43 +02:00
parent dd03af2616
commit 6cb95a2374
6 changed files with 175 additions and 64 deletions

View File

@@ -40,6 +40,8 @@ namespace Flowframes
public string framesExt;
public string interpExt;
public InterpSettings() { }
public InterpSettings(string inPathArg, string outPathArg, AI aiArg, Fraction inFpsDetectedArg, Fraction inFpsArg, int interpFactorArg, float itsScale, Interpolate.OutMode outModeArg, ModelCollection.ModelInfo modelArg)
{
inPath = inPathArg;

View File

@@ -95,7 +95,7 @@ namespace Flowframes
void HandleArgs()
{
foreach(string arg in Program.args)
foreach (string arg in Program.args)
{
if (arg.StartsWith("out="))
outputTbox.Text = arg.Split('=').Last().Trim();
@@ -123,7 +123,7 @@ namespace Flowframes
}
void UnlockInterpFactorIfEnabled ()
void UnlockInterpFactorIfEnabled()
{
if (!Config.GetBool(Config.Key.allowCustomInterpFactor))
return;
@@ -131,7 +131,7 @@ namespace Flowframes
interpFactorCombox.DropDownStyle = ComboBoxStyle.DropDown;
}
void RemovePreviewIfDisabled ()
void RemovePreviewIfDisabled()
{
if (!Config.GetBool(Config.Key.disablePreview))
return;
@@ -144,7 +144,7 @@ namespace Flowframes
}
public HTTabControl GetMainTabControl() { return mainTabControl; }
public TextBox GetInputFpsTextbox () { return fpsInTbox; }
public TextBox GetInputFpsTextbox() { return fpsInTbox; }
public Button GetPauseBtn() { return pauseBtn; }
public bool IsInFocus() { return (ActiveForm == this); }
@@ -164,7 +164,7 @@ namespace Flowframes
public InterpSettings GetCurrentSettings()
{
SetTab("interpolate");
return new InterpSettings(inputTbox.Text.Trim(), outputTbox.Text.Trim(), GetAi(), currInFpsDetected, currInFps,
return new InterpSettings(inputTbox.Text.Trim(), outputTbox.Text.Trim(), GetAi(), currInFpsDetected, currInFps,
interpFactorCombox.GetInt(), outSpeedCombox.GetInt().Clamp(1, 64), GetOutMode(), GetModel(GetAi()));
}
@@ -196,7 +196,8 @@ namespace Flowframes
inputTbox.Text = entry.inPath;
outputTbox.Text = entry.outPath;
interpFactorCombox.Text = entry.interpFactor.ToString();
aiCombox.SelectedIndex = Implementations.networks.IndexOf(entry.ai);
//aiCombox.SelectedIndex = Implementations.networks.IndexOf(entry.ai);
aiCombox.SelectedIndex = Implementations.networks.IndexOf(Implementations.networks.Where(x => x.aiName == entry.ai.aiName).FirstOrDefault());
SetOutMode(entry.outMode);
}
@@ -206,7 +207,7 @@ namespace Flowframes
statusLabel.Text = str;
}
public string GetStatus ()
public string GetStatus()
{
return statusLabel.Text;
}
@@ -226,7 +227,7 @@ namespace Flowframes
public long currInDuration;
public long currInDurationCut;
public void UpdateInputInfo ()
public void UpdateInputInfo()
{
string str = $"Size: {(!currInRes.IsEmpty ? $"{currInRes.Width}x{currInRes.Height}" : "Unknown")} - ";
str += $"Rate: {(currInFpsDetected.GetFloat() > 0f ? $"{currInFpsDetected} ({currInFpsDetected.GetFloat()})" : "Unknown")} - ";
@@ -235,7 +236,7 @@ namespace Flowframes
inputInfo.Text = str;
}
public void InterpolationDone ()
public void InterpolationDone()
{
SetStatus("Done interpolating!");
@@ -243,7 +244,7 @@ namespace Flowframes
CompletionAction();
}
public void CompletionAction ()
public void CompletionAction()
{
if (Program.args.Contains("quit-when-done"))
Application.Exit();
@@ -261,7 +262,7 @@ namespace Flowframes
new TimeoutForm(completionAction.Text, OsUtils.Shutdown).ShowDialog();
}
public void ResetInputInfo ()
public void ResetInputInfo()
{
currInRes = new Size();
currInFpsDetected = new Fraction();
@@ -328,7 +329,7 @@ namespace Flowframes
{
return AiModels.GetModels(currentAi).models[aiModel.SelectedIndex];
}
catch
catch
{
return null;
}
@@ -350,7 +351,7 @@ namespace Flowframes
{
int targetIndex = 0;
for(int i = 0; i < outModeCombox.Items.Count; i++)
for (int i = 0; i < outModeCombox.Items.Count; i++)
{
string currentItem = outModeCombox.Items[i].ToString().ToLower();
if (mode == Interpolate.OutMode.VidMkv && currentItem.Contains("mkv")) targetIndex = i;
@@ -422,7 +423,7 @@ namespace Flowframes
string aiName = GetAi().aiName.Replace("_", "-");
}
public void ValidateFactor ()
public void ValidateFactor()
{
interpFactorCombox.Text = $"x{MainUiFunctions.ValidateInterpFactor(interpFactorCombox.GetInt())}";
}
@@ -460,14 +461,14 @@ namespace Flowframes
interpFactorCombox.Items.Add($"x{factor}");
interpFactorCombox.SelectedIndex = 0;
if(initialized)
if (initialized)
ConfigParser.SaveComboxIndex(aiCombox);
interpFactorCombox_SelectedIndexChanged(null, null);
}
public void UpdateAiModelCombox ()
public void UpdateAiModelCombox()
{
aiModel = UiUtils.LoadAiModelsIntoGui(aiModel, GetAi());
}
@@ -509,7 +510,7 @@ namespace Flowframes
bool start = Program.initialRun && Program.args.Contains("start");
if (files.Length > 1)
if (files.Length > 1)
{
queueBtn_Click(null, null);
if (BatchProcessing.currentBatchForm != null)
@@ -521,11 +522,11 @@ namespace Flowframes
Logger.Log("Selected video/directory: " + Path.GetFileName(files[0]), true);
inputTbox.Text = files[0];
bool resume = (IoUtils.GetAmountOfFiles(Path.Combine(files[0], Paths.resumeDir), true) > 0);
ResumeUtils.resumeNextRun = resume;
bool resume = (IoUtils.GetAmountOfFiles(Path.Combine(files[0], Paths.resumeDir), true, "*.json") > 0);
AutoEncodeResume.resumeNextRun = resume;
if (resume)
ResumeUtils.LoadTempFolder(files[0]);
AutoEncodeResume.LoadTempFolder(files[0]);
trimCombox.SelectedIndex = 0;
@@ -536,7 +537,7 @@ namespace Flowframes
private void cancelBtn_Click(object sender, EventArgs e)
{
DialogResult dialog = MessageBox.Show($"Are you sure you want to cancel the interpolation?", "Are you sure?", MessageBoxButtons.YesNo);
if (dialog == DialogResult.Yes)
{
SetTab("interpolation");
@@ -601,7 +602,7 @@ namespace Flowframes
public void UpdateStepByStepControls()
{
if(stepSelector.SelectedIndex < 0)
if (stepSelector.SelectedIndex < 0)
stepSelector.SelectedIndex = 0;
bool stepByStep = Config.GetInt(Config.Key.processingMode) == 1;
@@ -644,7 +645,7 @@ namespace Flowframes
#region Quick Settings
public void SaveQuickSettings (object sender, EventArgs e)
public void SaveQuickSettings(object sender, EventArgs e)
{
if (!quickSettingsInitialized) return;
@@ -661,7 +662,7 @@ namespace Flowframes
ConfigParser.SaveGuiElement(maxFps);
}
public void LoadQuickSettings (object sender = null, EventArgs e = null)
public void LoadQuickSettings(object sender = null, EventArgs e = null)
{
ConfigParser.LoadGuiElement(maxVidHeight);
ConfigParser.LoadComboxIndex(dedupMode);

View File

@@ -45,7 +45,9 @@ namespace Flowframes.Main
public static async Task MainLoop(string interpFramesPath)
{
AutoEncodeResume.Reset();
if(!AutoEncodeResume.resumeNextRun)
AutoEncodeResume.Reset();
debug = Config.GetBool("autoEncDebug", false);
try
@@ -63,7 +65,7 @@ namespace Flowframes.Main
unencodedFrameLines.Clear();
Logger.Log($"[AE] Starting AutoEncode MainLoop - Chunk Size: {chunkSize} Frames - Safety Buffer: {safetyBufferFrames} Frames", true);
int chunkNo = 1;
int chunkNo = AutoEncodeResume.encodedChunks + 1;
string encFile = Path.Combine(interpFramesPath.GetParentDir(), Paths.GetFrameOrderFilename(Interpolate.current.interpFactor));
interpFramesLines = IoUtils.ReadLines(encFile).Select(x => x.Split('/').Last().Remove("'").Split('#').First()).ToArray(); // Array with frame filenames

View File

@@ -20,6 +20,11 @@ namespace Flowframes.Main
public static int encodedChunks = 0;
public static int encodedFrames = 0;
public static bool resumeNextRun;
public static string interpSettingsFilename = "settings.json";
public static string chunksFilename = "chunks.json";
public static string inputFramesFilename = "input-frames.json";
public static void Reset ()
{
processedInputFrames = new List<string>();
@@ -31,14 +36,109 @@ namespace Flowframes.Main
{
string saveDir = Path.Combine(I.current.tempFolder, Paths.resumeDir);
Directory.CreateDirectory(saveDir);
string chunksJsonPath = Path.Combine(saveDir, "chunks.json");
string chunksJsonPath = Path.Combine(saveDir, chunksFilename);
Dictionary<string, string> saveData = new Dictionary<string, string>();
saveData.Add("encodedChunks", encodedChunks.ToString());
saveData.Add("encodedFrames", encodedFrames.ToString());
File.WriteAllText(chunksJsonPath, JsonConvert.SerializeObject(saveData, Formatting.Indented));
string inputFramesJsonPath = Path.Combine(saveDir, "input-frames.json");
string inputFramesJsonPath = Path.Combine(saveDir, inputFramesFilename);
File.WriteAllText(inputFramesJsonPath, JsonConvert.SerializeObject(processedInputFrames, Formatting.Indented));
string settingsJsonPath = Path.Combine(saveDir, interpSettingsFilename);
File.WriteAllText(settingsJsonPath, JsonConvert.SerializeObject(I.current, Formatting.Indented));
}
public static void LoadTempFolder(string tempFolderPath)
{
try
{
Logger.Log($"Resume: Loading temp folder");
string resumeFolderPath = Path.Combine(tempFolderPath, Paths.resumeDir);
string settingsJsonPath = Path.Combine(resumeFolderPath, interpSettingsFilename);
InterpSettings interpSettings = JsonConvert.DeserializeObject<InterpSettings>(File.ReadAllText(settingsJsonPath));
Program.mainForm.LoadBatchEntry(interpSettings);
Logger.Log($"Resume: Loaded temp folder");
}
catch(Exception e)
{
Logger.Log($"Failed to load resume data: {e.Message}\n{e.StackTrace}");
resumeNextRun = false;
}
}
public static async Task<bool> PrepareResumedRun() // Remove already interpolated frames, return true if interpolation should be skipped
{
if (!resumeNextRun) return false;
try
{
string chunkJsonPath = Path.Combine(I.current.tempFolder, Paths.resumeDir, chunksFilename);
string inFramesJsonPath = Path.Combine(I.current.tempFolder, Paths.resumeDir, inputFramesFilename);
dynamic chunksData = JsonConvert.DeserializeObject(File.ReadAllText(chunkJsonPath));
encodedChunks = chunksData.encodedChunks;
encodedFrames = chunksData.encodedFrames;
List<string> processedInputFrames = JsonConvert.DeserializeObject<List<string>>(File.ReadAllText(inFramesJsonPath));
int uniqueInputFrames = processedInputFrames.Distinct().Count();
Logger.Log($"Preparing resumed run - Already encoded {encodedFrames} frames in {encodedChunks} chunks, processed {uniqueInputFrames} input frames");
foreach (string inputFrameName in processedInputFrames)
{
string inputFrameFullPath = Path.Combine(I.current.tempFolder, Paths.framesDir, inputFrameName);
IoUtils.TryDeleteIfExists(inputFrameFullPath);
}
int inputFramesLeft = IoUtils.GetAmountOfFiles(Path.Combine(I.current.tempFolder, Paths.framesDir), false);
Logger.Log($"Deleted already processed input frames - {inputFramesLeft} left to interpolate");
if(inputFramesLeft < 2)
{
string videoChunksFolder = Path.Combine(I.current.tempFolder, Paths.chunksDir);
if(IoUtils.GetAmountOfFiles(videoChunksFolder, true, "*.*") > 0)
{
Logger.Log($"No more frames left to interpolate - Merging existing video chunks instead.");
await Export.ChunksToVideos(I.current.tempFolder, videoChunksFolder, I.current.outPath);
await I.Done();
}
else
{
I.Cancel("There are no more frames left to interpolate in this temp folder!");
}
return true;
}
return false;
}
catch (Exception e)
{
Logger.Log($"Failed to prepare resumed run: {e.Message}\n{e.StackTrace}");
I.Cancel("Failed to resume interpolation. Check the logs for details.");
resumeNextRun = false;
return true;
}
// string stateFilepath = Path.Combine(I.current.tempFolder, Paths.resumeDir, resumeFilename);
// ResumeState state = new ResumeState(File.ReadAllText(stateFilepath));
//
// string fileMapFilepath = Path.Combine(I.current.tempFolder, Paths.resumeDir, filenameMapFilename);
// List<string> inputFrameLines = File.ReadAllLines(fileMapFilepath).Where(l => l.Trim().Length > 3).ToList();
// List<string> inputFrames = inputFrameLines.Select(l => Path.Combine(I.current.framesFolder, l.Split('|')[1])).ToList();
//
// for (int i = 0; i < state.interpolatedInputFrames; i++)
// {
// IoUtils.TryDeleteIfExists(inputFrames[i]);
// if (i % 1000 == 0) await Task.Delay(1);
// }
//
// Directory.Move(I.current.interpFolder, I.current.interpFolder + Paths.prevSuffix); // Move existing interp frames
// Directory.CreateDirectory(I.current.interpFolder); // Re-create empty interp folder
}
}
}

View File

@@ -38,7 +38,7 @@ namespace Flowframes
Program.mainForm.SetWorking(true);
if (!Utils.InputIsValid(current.inPath, current.outPath, current.inFps, current.interpFactor, current.outMode)) return; // General input checks
if (!Utils.CheckAiAvailable(current.ai, current.model)) return; // Check if selected AI pkg is installed
if (!ResumeUtils.resumeNextRun && !Utils.CheckDeleteOldTempFolder()) return; // Try to delete temp folder if an old one exists
if (!AutoEncodeResume.resumeNextRun && !Utils.CheckDeleteOldTempFolder()) return; // Try to delete temp folder if an old one exists
if (!Utils.CheckPathValid(current.inPath)) return; // Check if input path/file is valid
if (!(await Utils.CheckEncoderValid())) return; // Check NVENC compat
Utils.ShowWarnings(current.interpFactor, current.ai);
@@ -46,7 +46,7 @@ namespace Flowframes
current.stepByStep = false;
Program.mainForm.SetStatus("Starting...");
if (!ResumeUtils.resumeNextRun)
if (!AutoEncodeResume.resumeNextRun)
{
await GetFrames();
if (canceled) return;
@@ -55,7 +55,8 @@ namespace Flowframes
}
if (canceled) return;
await ResumeUtils.PrepareResumedRun();
bool skip = await AutoEncodeResume.PrepareResumedRun();
if (skip || canceled) return;
//Task.Run(() => Utils.DeleteInterpolatedInputFrames());
await RunAi(current.interpFolder, current.ai);
if (canceled) return;
@@ -67,14 +68,19 @@ namespace Flowframes
if (Config.GetBool(Config.Key.keepTempFolder))
await Task.Run(async () => { await FrameRename.Unrename(); });
await Done();
}
public static async Task Done ()
{
await Cleanup();
Program.mainForm.SetWorking(false);
Logger.Log("Total processing time: " + FormatUtils.Time(sw.Elapsed));
sw.Stop();
if(!BatchProcessing.busy)
if (!BatchProcessing.busy)
OsUtils.ShowNotificationIfInBackground("Flowframes", $"Finished interpolation after {FormatUtils.Time(sw.Elapsed)}.");
Program.mainForm.InterpolationDone();
}

View File

@@ -16,7 +16,7 @@ namespace Flowframes.Main
class ResumeUtils
{
public static bool resumeNextRun;
// public static bool resumeNextRun;
public static float timeBetweenSaves = 10;
public static int minFrames = 100;
@@ -72,36 +72,36 @@ namespace Flowframes.Main
File.WriteAllText(filepath, I.current.Serialize());
}
public static void LoadTempFolder (string tempFolderPath)
{
string resumeFolderPath = Path.Combine(tempFolderPath, Paths.resumeDir);
string interpSettingsPath = Path.Combine(resumeFolderPath, interpSettingsFilename);
InterpSettings interpSettings = new InterpSettings(File.ReadAllText(interpSettingsPath));
Program.mainForm.LoadBatchEntry(interpSettings);
}
// public static void LoadTempFolder (string tempFolderPath)
// {
// string resumeFolderPath = Path.Combine(tempFolderPath, Paths.resumeDir);
// string interpSettingsPath = Path.Combine(resumeFolderPath, interpSettingsFilename);
// InterpSettings interpSettings = new InterpSettings(File.ReadAllText(interpSettingsPath));
// Program.mainForm.LoadBatchEntry(interpSettings);
// }
public static async Task PrepareResumedRun ()
{
if (!resumeNextRun) return;
string stateFilepath = Path.Combine(I.current.tempFolder, Paths.resumeDir, resumeFilename);
ResumeState state = new ResumeState(File.ReadAllText(stateFilepath));
string fileMapFilepath = Path.Combine(I.current.tempFolder, Paths.resumeDir, filenameMapFilename);
List<string> inputFrameLines = File.ReadAllLines(fileMapFilepath).Where(l => l.Trim().Length > 3).ToList();
List<string> inputFrames = inputFrameLines.Select(l => Path.Combine(I.current.framesFolder, l.Split('|')[1])).ToList();
for (int i = 0; i < state.interpolatedInputFrames; i++)
{
IoUtils.TryDeleteIfExists(inputFrames[i]);
if (i % 1000 == 0) await Task.Delay(1);
}
Directory.Move(I.current.interpFolder, I.current.interpFolder + Paths.prevSuffix); // Move existing interp frames
Directory.CreateDirectory(I.current.interpFolder); // Re-create empty interp folder
LoadFilenameMap();
}
// public static async Task PrepareResumedRun ()
// {
// if (!resumeNextRun) return;
//
// string stateFilepath = Path.Combine(I.current.tempFolder, Paths.resumeDir, resumeFilename);
// ResumeState state = new ResumeState(File.ReadAllText(stateFilepath));
//
// string fileMapFilepath = Path.Combine(I.current.tempFolder, Paths.resumeDir, filenameMapFilename);
// List<string> inputFrameLines = File.ReadAllLines(fileMapFilepath).Where(l => l.Trim().Length > 3).ToList();
// List<string> inputFrames = inputFrameLines.Select(l => Path.Combine(I.current.framesFolder, l.Split('|')[1])).ToList();
//
// for (int i = 0; i < state.interpolatedInputFrames; i++)
// {
// IoUtils.TryDeleteIfExists(inputFrames[i]);
// if (i % 1000 == 0) await Task.Delay(1);
// }
//
// Directory.Move(I.current.interpFolder, I.current.interpFolder + Paths.prevSuffix); // Move existing interp frames
// Directory.CreateDirectory(I.current.interpFolder); // Re-create empty interp folder
//
// LoadFilenameMap();
// }
static void LoadFilenameMap()
{