WIP: StepByStep fixes to be able to re-use existing files, dynamically use AutoEnc

+ faster thumbnai (single frame) extraction using lower png compression
+ some null checks & cancel checks
This commit is contained in:
N00MKRAD
2020-12-01 16:54:12 +01:00
parent db070ca61a
commit 1b015f4eec
8 changed files with 93 additions and 50 deletions

View File

@@ -58,7 +58,7 @@ namespace Flowframes
public static async Task ExtractSingleFrame(string inputFile, string outputPath, int frameNum, bool hdr, bool delSrc)
{
string hdrStr = hdr ? hdrFilter : "";
string args = $"-i {inputFile.Wrap()} {hdrStr }-vf \"select=eq(n\\,{frameNum})\" -vframes 1 {outputPath.Wrap()}";
string args = $"-i {inputFile.Wrap()} {pngComprArg} {hdrStr }-vf \"select=eq(n\\,{frameNum})\" -vframes 1 {outputPath.Wrap()}";
await AvProcess.RunFfmpeg(args, AvProcess.LogMode.Hidden);
if (delSrc)
DeleteSource(inputFile);

View File

@@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
@@ -435,5 +436,17 @@ namespace Flowframes.IO
return false;
}
}
public static string GetFileMd5 (string filename)
{
using (var md5 = MD5.Create())
{
using (var stream = File.OpenRead(filename))
{
var hash = md5.ComputeHash(stream);
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
}
}
}
}
}

View File

@@ -12,8 +12,8 @@ namespace Flowframes.Main
{
static string interpFramesFolder;
static string videoChunksFolder;
static int chunkSize = 125; // Encode every n frames
static int safetyBufferFrames = 25;
public static int chunkSize = 125; // Encode every n frames
public static int safetyBufferFrames = 25;
public static List<string> encodedFrames = new List<string>();
public static List<string> unencodedFrames = new List<string>();
@@ -86,7 +86,7 @@ namespace Flowframes.Main
public static bool HasWorkToDo ()
{
if (Interpolate.canceled) return false;
if (Interpolate.canceled || interpFramesFolder == null) return false;
return ((AiProcess.currentAiProcess != null && !AiProcess.currentAiProcess.HasExited) || encodedFrames.Count < GetInterpFramesAmount());
}

View File

@@ -28,7 +28,8 @@ namespace Flowframes
public static float currentInFps;
public static float currentOutFps;
public static OutMode currentOutMode;
public static bool currentInputIsFrames;
public static bool currentlyUsingAutoEnc;
public static int lastInterpFactor;
public static string lastInputPath;
public static string nextOutPath;
@@ -59,10 +60,11 @@ namespace Flowframes
if(!Utils.CheckPathValid(inPath)) return; // Check if input path/file is valid
Utils.PathAsciiCheck(inPath, outDir);
lastAi = ai;
currentInputIsFrames = IOUtils.IsPathDirectory(inPath);
Program.mainForm.SetStatus("Starting...");
Program.mainForm.SetWorking(true);
await Task.Delay(10);
if (!IOUtils.IsPathDirectory(inPath)) // Input is video - extract frames first
if (!currentInputIsFrames) // Input is video - extract frames first
await ExtractFrames(inPath, currentFramesPath);
else
IOUtils.Copy(inPath, currentFramesPath);
@@ -81,7 +83,8 @@ namespace Flowframes
await RunAi(interpFramesDir, targetFrameCount, tilesize, ai);
if (canceled) return;
Program.mainForm.SetProgress(100);
//await CreateVideo.FramesToVideo(interpFramesDir, nextOutPath, outMode); // TODO: DISABLE NORMAL ENCODING IF PARALLEL ENC WAS USED
if(!currentlyUsingAutoEnc)
await CreateVideo.FramesToVideo(interpFramesDir, nextOutPath, outMode);
Cleanup(interpFramesDir);
Program.mainForm.SetWorking(false);
Logger.Log("Total processing time: " + FormatUtils.Time(sw.Elapsed));
@@ -145,7 +148,7 @@ namespace Flowframes
Cancel("Failed to extract frames from input video!");
}
string hasPreprocessedFile = Path.Combine(currentTempDir, ".preprocessed");
string hasPreprocessedFile = Path.Combine(currentTempDir, ".preprocessed"); // TODO: DUMP THIS WHOLE IDEA
if (File.Exists(hasPreprocessedFile)) return;
if (Config.GetInt("dedupMode") == 1)
@@ -175,6 +178,7 @@ namespace Flowframes
public static async Task RunAi(string outpath, int targetFrames, int tilesize, AI ai)
{
currentlyUsingAutoEnc = IOUtils.GetAmountOfFiles(currentFramesPath, false) >= (AutoEncode.chunkSize + AutoEncode.safetyBufferFrames) * 1.2f;
Directory.CreateDirectory(outpath);
List<Task> tasks = new List<Task>();
@@ -191,6 +195,7 @@ namespace Flowframes
if (ai.aiName == Networks.rifeNcnn.aiName)
tasks.Add(AiProcess.RunRifeNcnnMulti(currentFramesPath, outpath, tilesize, interpFactor));
if(currentlyUsingAutoEnc)
tasks.Add(AutoEncode.MainLoop(outpath));
await Task.WhenAll(tasks);
}

View File

@@ -60,6 +60,8 @@ namespace Flowframes.Main
if (string.IsNullOrWhiteSpace(currentFramesPath))
currentFramesPath = Path.Combine(currentTempDir, Paths.framesDir);
currentInterpFramesDir = Path.Combine(currentTempDir, Paths.interpDir);
}
public static async Task ExtractSceneChanges ()
@@ -106,14 +108,18 @@ namespace Flowframes.Main
public static async Task DoInterpolate ()
{
IOUtils.TryDeleteIfExists(currentInterpFramesDir);
foreach (string ini in Directory.GetFiles(currentTempDir, "*.ini", SearchOption.TopDirectoryOnly))
IOUtils.TryDeleteIfExists(ini);
await PostProcessFrames(true);
string interpFramesDir = Path.Combine(currentTempDir, Paths.interpDir);
if (!IOUtils.TryDeleteIfExists(interpFramesDir))
{
InterpolateUtils.ShowMessage("Failed to delete old \"interpolated-frames folder\" - Make sure none of the files are opened in another program!", "Error");
return;
}
// if (!IOUtils.TryDeleteIfExists(interpFramesDir))
// {
// InterpolateUtils.ShowMessage("Failed to delete old \"interpolated-frames folder\" - Make sure none of the files are opened in another program!", "Error");
// return;
// }
lastInterpFactor = interpFactor;
int frames = IOUtils.GetAmountOfFiles(currentFramesPath, false, "*.png");
int targetFrameCount = frames * lastInterpFactor;
@@ -127,7 +133,6 @@ namespace Flowframes.Main
public static async Task CreateOutputVid ()
{
currentInterpFramesDir = Path.Combine(currentTempDir, Paths.interpDir);
string outPath = Path.Combine(currentOutPath, Path.GetFileNameWithoutExtension(currentInPath) + IOUtils.GetAiSuffix(currentAi, lastInterpFactor) + InterpolateUtils.GetExt(currentOutMode));
await CreateVideo.FramesToVideo(currentInterpFramesDir, outPath, currentOutMode);
}

View File

@@ -47,7 +47,11 @@ namespace Flowframes.Main
string scnFramesPath = Path.Combine(framesPath.GetParentDir(), Paths.scenesDir);
string interpPath = Paths.interpDir; // framesPath.Replace(@"\", "/") + "-interpolated";
List<string> sceneFrames = Directory.GetFiles(scnFramesPath).Select(file => Path.GetFileName(file)).ToList();
List<string> sceneFrames = new List<string>();
Logger.Log($"Scn path {scnFramesPath} exists: {Directory.Exists(scnFramesPath)}");
if (Directory.Exists(scnFramesPath))
sceneFrames = Directory.GetFiles(scnFramesPath).Select(file => Path.GetFileName(file)).ToList();
Logger.Log($"Found {sceneFrames.Count} scn frames");
int lastFrameDuration = 1;

View File

@@ -25,6 +25,7 @@ namespace Flowframes
static void AiStarted (Process proc, int startupTimeMs, string defaultExt = "png")
{
SwapFilenames(false);
lastStartupTimeMs = startupTimeMs;
InterpolateUtils.lastExt = defaultExt;
if (Config.GetBool("jpegInterps")) InterpolateUtils.lastExt = "jpg";
@@ -37,12 +38,32 @@ namespace Flowframes
{
Program.mainForm.SetProgress(100);
string logStr = $"Done running {aiName} - Interpolation took {FormatUtils.Time(processTime.Elapsed)}";
if (AutoEncode.HasWorkToDo())
if (Interpolate.currentlyUsingAutoEnc && AutoEncode.HasWorkToDo())
logStr += " - Waiting for encoding to finish...";
Logger.Log(logStr);
processTime.Stop();
}
static Dictionary<string, string> filenameMap = new Dictionary<string, string>(); // TODO: Store on disk instead for crashes?
public static void SwapFilenames (bool restore) // Renames files with a counter or restores original timecode names via MD5/filename mapping
{
Stopwatch filenameSwapSw = new Stopwatch();
if (!restore) // Rename with counter and store original names
{
filenameSwapSw.Start();
filenameMap.Clear();
foreach (string file in Directory.GetFiles(Path.Combine(Interpolate.currentFramesPath)))
filenameMap.Add(Path.GetFileName(file), IOUtils.GetFileMd5(file));
Logger.Log($"Stored file/md5 pairs in {filenameSwapSw.ElapsedMilliseconds}ms");
}
else
{
filenameSwapSw.Start();
// add restore code!
Logger.Log($"Restored original file/md5 pairs in {filenameSwapSw.ElapsedMilliseconds}ms");
}
}
public static async Task RunDainNcnn(string framesPath, string outPath, int targetFrames, int tilesize)
{
string args = $" -v -i {framesPath.Wrap()} -o {outPath.Wrap()} -n {targetFrames} -t {tilesize} -g {Config.Get("ncnnGpus")}";
@@ -137,7 +158,7 @@ namespace Flowframes
public static async Task RunRifeCuda(string framesPath, int interpFactor)
{
string script = "interp-parallel.py";
if(Config.GetInt("rifeMode") == 0 || IOUtils.GetAmountOfFiles(framesPath, false) < 10)
if(Config.GetInt("rifeMode") == 0 || IOUtils.GetAmountOfFiles(framesPath, false) < 6)
script = "interp-basic.py";
string rifeDir = Path.Combine(Paths.GetPkgPath(), Path.GetFileNameWithoutExtension(Packages.rifeCuda.fileName));
@@ -163,33 +184,6 @@ namespace Flowframes
AiFinished("RIFE");
}
public static async Task RunRifeNcnn (string framesPath, string outPath, int interpFactor, int tilesize)
{
string args = $" -v -i {framesPath.Wrap()} -o {outPath.Wrap()} -t {tilesize} -g {Config.Get("ncnnGpus")} -f {InterpolateUtils.lastExt} -j 4:{Config.Get("ncnnThreads")}:4";
Process rifeNcnn = OSUtils.NewProcess(!OSUtils.ShowHiddenCmd());
AiStarted(rifeNcnn, 750);
rifeNcnn.StartInfo.Arguments = $"{OSUtils.GetCmdArg()} cd /D {PkgUtils.GetPkgFolder(Packages.rifeNcnn).Wrap()} & rife-ncnn-vulkan.exe {args}";
Logger.Log("Running RIFE...", false);
Logger.Log("cmd.exe " + rifeNcnn.StartInfo.Arguments, true);
if (!OSUtils.ShowHiddenCmd())
{
rifeNcnn.OutputDataReceived += (sender, outLine) => { LogOutput("[O] " + outLine.Data, "rife-ncnn-log.txt"); };
rifeNcnn.ErrorDataReceived += (sender, outLine) => { LogOutput("[E] " + outLine.Data, "rife-ncnn-log.txt"); };
}
rifeNcnn.Start();
if (!OSUtils.ShowHiddenCmd())
{
rifeNcnn.BeginOutputReadLine();
rifeNcnn.BeginErrorReadLine();
}
while (!rifeNcnn.HasExited) await Task.Delay(1);
if (Interpolate.canceled) return;
Magick.MagickDedupe.ZeroPadDir(outPath, InterpolateUtils.lastExt, 8);
AiFinished("RIFE");
}
public static async Task RunRifeNcnnMulti(string framesPath, string outPath, int tilesize, int times)
{
processTimeMulti.Restart();

View File

@@ -36,21 +36,43 @@ namespace Flowframes.UI
else
Logger.Log($"Video FPS: {fpsStr} - Total Number Of Frames: {FFmpegCommands.GetFrameCount(path)}");
await Task.Delay(10);
Size res = FFmpegCommands.GetSize(path);
Logger.Log($"Video Resolution: {res.Width}x{res.Height}");
await PrintResolution(path);
MagickDedupe.ClearCache();
await Task.Delay(10);
InterpolateUtils.SetPreviewImg(await GetThumbnail(path));
}
static async Task<Image> GetThumbnail (string videoPath)
static async Task PrintResolution (string path)
{
Size res = new Size();
if (!IOUtils.IsPathDirectory(path)) // If path is video
{
res = FFmpegCommands.GetSize(path);
}
else // Path is frame folder
{
Image thumb = await GetThumbnail(path);
res = new Size(thumb.Width, thumb.Height);
}
if (res.Width > 1 && res.Height > 1)
Logger.Log($"Input Resolution: {res.Width}x{res.Height}");
}
static async Task<Image> GetThumbnail (string path)
{
string imgOnDisk = Path.Combine(Paths.GetDataPath(), "thumb-temp.png");
try
{
await FFmpegCommands.ExtractSingleFrame(videoPath, imgOnDisk, 1, false, false);
if (!IOUtils.IsPathDirectory(path)) // If path is video - Extract first frame
{
await FFmpegCommands.ExtractSingleFrame(path, imgOnDisk, 1, false, false);
return IOUtils.GetImage(imgOnDisk);
}
else // Path is frame folder - Get first frame
{
return IOUtils.GetImage(Directory.GetFiles(path)[0]);
}
}
catch (Exception e)
{
Logger.Log("GetThumbnail Error: " + e.Message, true);