Fixed AutoEncode getting stuck when using scn+magickdedup

This commit is contained in:
N00MKRAD
2021-01-11 11:45:38 +01:00
parent 5aba6d3f4a
commit 8ea1848818
5 changed files with 107 additions and 78 deletions

View File

@@ -9,6 +9,7 @@ using ImageMagick;
using Flowframes.OS;
using Flowframes.Data;
using System.Drawing;
using Paths = Flowframes.IO.Paths;
namespace Flowframes.Magick
{
@@ -205,7 +206,7 @@ namespace Flowframes.Magick
return bufferSize;
}
public static async Task CreateDupesFileMpdecimate (string framesPath, int lastFrameNum)
public static async Task CreateDupesFile (string framesPath, int lastFrameNum)
{
string infoFile = Path.Combine(framesPath.GetParentDir(), $"dupes.ini");
string fileContent = "";
@@ -221,6 +222,9 @@ namespace Flowframes.Magick
int diff = frameNum2 - frameNum1;
int dupes = diff - 1;
//if (File.Exists(Path.Combine(framesPath.GetParentDir(), Paths.scenesDir, frameFiles[i].Name)))
// dupes = 0;
fileContent += $"{Path.GetFileNameWithoutExtension(frameFiles[i].Name)}:{dupes}\n";
}

View File

@@ -32,85 +32,98 @@ namespace Flowframes.Main
public static async Task MainLoop(string interpFramesPath)
{
UpdateChunkAndBufferSizes();
interpFramesFolder = interpFramesPath;
videoChunksFolder = Path.Combine(interpFramesPath.GetParentDir(), Paths.chunksDir);
if (Interpolate.currentlyUsingAutoEnc)
Directory.CreateDirectory(videoChunksFolder);
encodedFrameLines.Clear();
unencodedFrameLines.Clear();
Logger.Log($"Starting AutoEncode MainLoop - Chunk Size: {chunkSize} Frames - Safety Buffer: {safetyBufferFrames} Frames", true);
int videoIndex = 1;
string encFile = Path.Combine(interpFramesPath.GetParentDir(), $"vfr-{Interpolate.current.interpFactor}x.ini");
interpFramesLines = IOUtils.ReadLines(encFile).Select(x => x.Split('/').Last().Remove("'")).ToArray(); // Array with frame filenames
while (!Interpolate.canceled && GetInterpFramesAmount() < 2)
await Task.Delay(1000);
while (HasWorkToDo()) // Loop while proc is running and not all frames have been encoded
try
{
if (Interpolate.canceled) return;
UpdateChunkAndBufferSizes();
if (paused)
{
await Task.Delay(100);
continue;
}
//Logger.Log($"{unencodedFrameLines.Count} unencoded frame lines, {encodedFrameLines.Count} encoded frame lines", true, false, "ffmpeg");
interpFramesFolder = interpFramesPath;
videoChunksFolder = Path.Combine(interpFramesPath.GetParentDir(), Paths.chunksDir);
if (Interpolate.currentlyUsingAutoEnc)
Directory.CreateDirectory(videoChunksFolder);
encodedFrameLines.Clear();
unencodedFrameLines.Clear();
for(int vfrLine = 0; vfrLine < interpFramesLines.Length; vfrLine++)
Logger.Log($"Starting AutoEncode MainLoop - Chunk Size: {chunkSize} Frames - Safety Buffer: {safetyBufferFrames} Frames", true);
int videoIndex = 1;
string encFile = Path.Combine(interpFramesPath.GetParentDir(), $"vfr-{Interpolate.current.interpFactor}x.ini");
interpFramesLines = IOUtils.ReadLines(encFile).Select(x => x.Split('/').Last().Remove("'").Split('#').First()).ToArray(); // Array with frame filenames
while (!Interpolate.canceled && GetInterpFramesAmount() < 2)
{
if (File.Exists(Path.Combine(interpFramesPath, interpFramesLines[vfrLine])) && !encodedFrameLines.Contains(vfrLine))
unencodedFrameLines.Add(vfrLine);
// Logger.Log("autoenc waiting for 2s because GetInterpFramesAmount() < 2");
await Task.Delay(2000);
}
bool aiRunning = !AiProcess.currentAiProcess.HasExited;
if (unencodedFrameLines.Count >= (chunkSize + safetyBufferFrames) || !aiRunning) // Encode every n frames, or after process has exited
while (HasWorkToDo()) // Loop while proc is running and not all frames have been encoded
{
busy = true;
if (Interpolate.canceled) return;
List<int> frameLinesToEncode = aiRunning ? unencodedFrameLines.Take(chunkSize).ToList() : unencodedFrameLines; // Take all remaining frames if process is done
//Logger.Log($"{unencodedFrameLines.Count} unencoded frame lines, {IOUtils.GetAmountOfFiles(interpFramesFolder, false)} frames in interp folder", true, false, "ffmpeg");
string outpath = Path.Combine(videoChunksFolder, "chunks", $"{videoIndex.ToString().PadLeft(4, '0')}{FFmpegUtils.GetExt(Interpolate.current.outMode)}");
int firstFrameNum = frameLinesToEncode[0];
Logger.Log($"Encoding Chunk #{videoIndex} to '{outpath}' using {Path.GetFileName(interpFramesLines[frameLinesToEncode.First()])} through {Path.GetFileName(Path.GetFileName(interpFramesLines[frameLinesToEncode.Last()]))}", true, false, "ffmpeg");
await CreateVideo.EncodeChunk(outpath, Interpolate.current.outMode, firstFrameNum, frameLinesToEncode.Count);
if(Interpolate.canceled) return;
if (Config.GetInt("autoEncMode") == 2)
if (paused)
{
foreach (int frame in frameLinesToEncode)
{
if(!FrameIsStillNeeded(interpFramesLines[frame], frame)) // Make sure frames are no longer needed (e.g. for dupes) before deleting!
{
string framePath = Path.Combine(interpFramesPath, interpFramesLines[frame]);
File.WriteAllText(framePath, "THIS IS A DUMMY FILE - DO NOT DELETE ME"); // Overwrite to save space without breaking progress counter
}
}
Logger.Log("autoenc paused");
await Task.Delay(100);
continue;
}
encodedFrameLines.AddRange(frameLinesToEncode);
//Logger.Log($"Adding {frameLinesToEncode.Count} frameLinesToEncode to encodedFrameLines, new count is {encodedFrameLines.Count}");
unencodedFrameLines.Clear();
for (int vfrLine = 0; vfrLine < interpFramesLines.Length; vfrLine++)
{
if (File.Exists(Path.Combine(interpFramesPath, interpFramesLines[vfrLine])) && !encodedFrameLines.Contains(vfrLine))
unencodedFrameLines.Add(vfrLine);
}
Logger.Log("Done Encoding Chunk #" + videoIndex, true, false, "ffmpeg");
videoIndex++;
busy = false;
// Logger.Log($"{unencodedFrameLines.Count} unencoded frame lines, {encodedFrameLines.Count} encoded frame lines", false, false, "ffmpeg");
bool aiRunning = !AiProcess.currentAiProcess.HasExited;
if (unencodedFrameLines.Count > 0 && (unencodedFrameLines.Count >= (chunkSize + safetyBufferFrames) || !aiRunning)) // Encode every n frames, or after process has exited
{
busy = true;
Logger.Log("unencodedFrameLines: " + unencodedFrameLines.Count, true, false, "autoenc");
List<int> frameLinesToEncode = aiRunning ? unencodedFrameLines.Take(chunkSize).ToList() : unencodedFrameLines; // Take all remaining frames if process is done
Logger.Log("frameLinesToEncode: " + frameLinesToEncode.Count, true, false, "autoenc");
string outpath = Path.Combine(videoChunksFolder, "chunks", $"{videoIndex.ToString().PadLeft(4, '0')}{FFmpegUtils.GetExt(Interpolate.current.outMode)}");
int firstFrameNum = frameLinesToEncode[0];
Logger.Log($"Encoding Chunk #{videoIndex} to '{outpath}' using {Path.GetFileName(interpFramesLines[frameLinesToEncode.First()])} through {Path.GetFileName(Path.GetFileName(interpFramesLines[frameLinesToEncode.Last()]))}", true, false, "ffmpeg");
await CreateVideo.EncodeChunk(outpath, Interpolate.current.outMode, firstFrameNum, frameLinesToEncode.Count);
if (Interpolate.canceled) return;
if (Config.GetInt("autoEncMode") == 2)
{
foreach (int frame in frameLinesToEncode)
{
if (!FrameIsStillNeeded(interpFramesLines[frame], frame)) // Make sure frames are no longer needed (e.g. for dupes) before deleting!
{
string framePath = Path.Combine(interpFramesPath, interpFramesLines[frame]);
File.WriteAllText(framePath, "THIS IS A DUMMY FILE - DO NOT DELETE ME"); // Overwrite to save space without breaking progress counter
}
}
}
encodedFrameLines.AddRange(frameLinesToEncode);
//Logger.Log($"Adding {frameLinesToEncode.Count} frameLinesToEncode to encodedFrameLines, new count is {encodedFrameLines.Count}");
Logger.Log("Done Encoding Chunk #" + videoIndex, true, false, "ffmpeg");
videoIndex++;
busy = false;
}
await Task.Delay(50);
}
await Task.Delay(50);
if (Interpolate.canceled) return;
IOUtils.ReverseRenaming(AiProcess.filenameMap, true); // Get timestamps back
await CreateVideo.ChunksToVideos(Interpolate.current.tempFolder, videoChunksFolder, Interpolate.current.outFilename);
}
catch (Exception e)
{
Logger.Log($"AutoEnc Error: {e.Message}. Stack Trace:\n{e.StackTrace}");
Interpolate.Cancel("Auto-Encode encountered an error.");
}
if (Interpolate.canceled) return;
IOUtils.ReverseRenaming(AiProcess.filenameMap, true); // Get timestamps back
await CreateVideo.ChunksToVideos(Interpolate.current.tempFolder, videoChunksFolder, Interpolate.current.outFilename);
}
static bool FrameIsStillNeeded (string frameName, int frameIndex)
@@ -123,7 +136,7 @@ namespace Flowframes.Main
public static bool HasWorkToDo ()
{
if (Interpolate.canceled || interpFramesFolder == null) return false;
//Logger.Log($"HasWorkToDo - Process Running: {(AiProcess.currentAiProcess != null && !AiProcess.currentAiProcess.HasExited)} - encodedFrameLines.Count: {encodedFrameLines.Count} - interpFramesLines.Length: {interpFramesLines.Length}");
// Logger.Log($"HasWorkToDo - Process Running: {(AiProcess.currentAiProcess != null && !AiProcess.currentAiProcess.HasExited)} - encodedFrameLines.Count: {encodedFrameLines.Count} - interpFramesLines.Length: {interpFramesLines.Length}");
return ((AiProcess.currentAiProcess != null && !AiProcess.currentAiProcess.HasExited) || encodedFrameLines.Count < interpFramesLines.Length);
}

View File

@@ -217,7 +217,7 @@ namespace Flowframes.Main
if (debug) Logger.Log($"Writing frame {totalFileCount} [Discarding Next]", true);
//fileContent += $"file '{interpPath}/{totalFileCount.ToString().PadLeft(Padding.interpFrames, '0')}.{ext}'\n";
fileContent = WriteFrameWithDupes(dupesAmount, fileContent, totalFileCount, interpPath, ext, debug);
fileContent = WriteFrameWithDupes(dupesAmount, fileContent, totalFileCount, interpPath, ext, debug, $"[i={i}] [{frameFiles[i].Name}] scn: discarding next [{frameFiles[i+1].Name}]");
totalFileCount++;
if (debug) Logger.Log("Discarding interp frames with out num " + totalFileCount);
@@ -225,7 +225,7 @@ namespace Flowframes.Main
{
if (debug) Logger.Log($"Writing frame {totalFileCount} which is actually repeated frame {lastNum}");
//fileContent += $"file '{interpPath}/{lastNum.ToString().PadLeft(Padding.interpFrames, '0')}.{ext}'\n";
fileContent = WriteFrameWithDupes(dupesAmount, fileContent, lastNum, interpPath, ext, debug);
fileContent = WriteFrameWithDupes(dupesAmount, fileContent, lastNum, interpPath, ext, debug, $"[{inputFilenameNoExt}] scn: repeated last frame");
totalFileCount++;
}
@@ -233,7 +233,7 @@ namespace Flowframes.Main
}
else
{
fileContent = WriteFrameWithDupes(dupesAmount, fileContent, totalFileCount, interpPath, ext, debug);
fileContent = WriteFrameWithDupes(dupesAmount, fileContent, totalFileCount, interpPath, ext, debug, $"[{inputFilenameNoExt}]");
totalFileCount++;
}
}
@@ -242,10 +242,14 @@ namespace Flowframes.Main
await Task.Delay(1);
}
// Use average frame duration for last frame - TODO: Use real duration??
//string durationStrLast = ((totalDuration / (totalFileCount - 1)) / timebase).ToString("0.0000000", CultureInfo.InvariantCulture);
fileContent += $"file '{interpPath}/{totalFileCount.ToString().PadLeft(Padding.interpFrames, '0')}.{ext}'\n";
totalFileCount++;
if(debug) Logger.Log("target: " + ((frameFiles.Length * interpFactor) - (interpFactor - 1)), true);
if(debug) Logger.Log("totalFileCount: " + totalFileCount, true);
if (totalFileCount < (frameFiles.Length * interpFactor) - (interpFactor - 1))
{
fileContent += $"file '{interpPath}/{totalFileCount.ToString().PadLeft(Padding.interpFrames, '0')}.{ext}'\n";
totalFileCount++;
}
string finalFileContent = fileContent.Trim();
if(loop)
@@ -268,12 +272,12 @@ namespace Flowframes.Main
}
}
static string WriteFrameWithDupes (int dupesAmount, string fileContent, int frameNum, string interpPath, string ext, bool debug)
static string WriteFrameWithDupes (int dupesAmount, string fileContent, int frameNum, string interpPath, string ext, bool debug, string note = "")
{
for (int writtenDupes = -1; writtenDupes < dupesAmount; writtenDupes++) // Write duplicates
{
if (debug) Logger.Log($"Writing frame {frameNum} (writtenDupes {writtenDupes})", true, false);
fileContent += $"file '{interpPath}/{frameNum.ToString().PadLeft(Padding.interpFrames, '0')}.{ext}'\n";
fileContent += $"file '{interpPath}/{frameNum.ToString().PadLeft(Padding.interpFrames, '0')}.{ext}'{(debug ? ($"# Dupe {writtenDupes+1} {note}") : "" )}\n";
}
return fileContent;
}

View File

@@ -55,7 +55,7 @@ namespace Flowframes
await PostProcessFrames();
if (canceled) return;
int frames = IOUtils.GetAmountOfFiles(current.framesFolder, false, "*.png");
int targetFrameCount = frames * current.interpFactor;
int targetFrameCount = (frames * current.interpFactor) - (current.interpFactor - 1);
Utils.GetProgressByFrameAmount(current.interpFolder, targetFrameCount);
if (canceled) return;
Program.mainForm.SetStatus("Running AI...");
@@ -132,7 +132,7 @@ namespace Flowframes
Dedupe.ClearCache();
if (Config.GetInt("dedupMode") == 2 || Config.GetInt("dedupMode") == 1)
await Dedupe.CreateDupesFileMpdecimate(current.framesFolder, currentInputFrameCount);
await Dedupe.CreateDupesFile(current.framesFolder, currentInputFrameCount);
if (canceled) return;

View File

@@ -49,14 +49,22 @@ namespace Flowframes
logStr += " - Waiting for encoding to finish...";
Logger.Log(logStr);
processTime.Stop();
Stopwatch timeSinceFfmpegRan = new Stopwatch();
timeSinceFfmpegRan.Restart();
while (Interpolate.currentlyUsingAutoEnc && Program.busy)
{
if (AvProcess.lastProcess != null && !AvProcess.lastProcess.HasExited && AvProcess.lastTask == AvProcess.TaskType.Encode)
{
timeSinceFfmpegRan.Restart();
string lastLine = AvProcess.lastOutputFfmpeg.SplitIntoLines().Last();
Logger.Log(lastLine.Trim().TrimWhitespaces(), false, Logger.GetLastLine().Contains("frame"));
}
await Task.Delay(1000);
if (timeSinceFfmpegRan.ElapsedMilliseconds > 3000)
break;
// Logger.Log($"AiProcess loop - Program.busy = {Program.busy}");
await Task.Delay(500);
}
}