mirror of
https://github.com/n00mkrad/flowframes.git
synced 2025-12-25 12:49:26 +01:00
Basic support for RIFE-NCNN-VS
This commit is contained in:
@@ -7,29 +7,30 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Flowframes.Data
|
||||
{
|
||||
public struct AI
|
||||
public class AI
|
||||
{
|
||||
public enum Backend { Pytorch, Ncnn, Tensorflow, Other }
|
||||
public Backend backend;
|
||||
public string aiName;
|
||||
public string aiNameShort;
|
||||
public string friendlyName;
|
||||
public string description;
|
||||
public string pkgDir;
|
||||
public enum FactorSupport { Fixed, AnyPowerOfTwo, AnyInteger, AnyFloat }
|
||||
public FactorSupport factorSupport;
|
||||
public int[] supportedFactors;
|
||||
public enum AiBackend { Pytorch, Ncnn, Tensorflow, Other }
|
||||
public AiBackend Backend { get; set; } = AiBackend.Pytorch;
|
||||
public string AiName { get; set; } = "";
|
||||
public string AiNameShort { get; set; } = "";
|
||||
public string FriendlyName { get; set; } = "";
|
||||
public string Description { get; set; } = "";
|
||||
public string PkgDir { get; set; } = "";
|
||||
public enum InterpFactorSupport { Fixed, AnyPowerOfTwo, AnyInteger, AnyFloat }
|
||||
public InterpFactorSupport FactorSupport { get; set; } = InterpFactorSupport.Fixed;
|
||||
public int[] SupportedFactors { get; set; } = new int[0];
|
||||
public bool Piped { get; set; } = false;
|
||||
|
||||
public AI(Backend backend, string aiName, string friendlyName, string desc, string pkgDir, FactorSupport factorSupport = FactorSupport.Fixed, int[] factors = null)
|
||||
public AI(AiBackend backend, string aiName, string friendlyName, string desc, string pkgDir, InterpFactorSupport factorSupport = InterpFactorSupport.Fixed, int[] supportedFactors = null)
|
||||
{
|
||||
this.backend = backend;
|
||||
this.aiName = aiName;
|
||||
this.aiNameShort = aiName.Split(' ')[0].Split('_')[0];
|
||||
this.friendlyName = friendlyName;
|
||||
this.description = desc;
|
||||
this.pkgDir = pkgDir;
|
||||
this.supportedFactors = factors;
|
||||
this.factorSupport = factorSupport;
|
||||
Backend = backend;
|
||||
AiName = aiName;
|
||||
AiNameShort = aiName.Split(' ')[0].Split('_')[0];
|
||||
FriendlyName = friendlyName;
|
||||
Description = desc;
|
||||
PkgDir = pkgDir;
|
||||
SupportedFactors = supportedFactors;
|
||||
FactorSupport = factorSupport;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,28 +4,32 @@ namespace Flowframes.Data
|
||||
{
|
||||
class Implementations
|
||||
{
|
||||
public static AI rifeCuda = new AI(AI.Backend.Pytorch, "RIFE_CUDA", "RIFE",
|
||||
"CUDA/Pytorch Implementation of RIFE (Nvidia Only!)", "rife-cuda", AI.FactorSupport.AnyInteger, new int[] { 2, 3, 4, 5, 6, 7, 8, 9, 10 });
|
||||
public static AI rifeCuda = new AI(AI.AiBackend.Pytorch, "RIFE_CUDA", "RIFE",
|
||||
"CUDA/Pytorch Implementation of RIFE (Nvidia Only!)", "rife-cuda", AI.InterpFactorSupport.AnyInteger, new int[] { 2, 3, 4, 5, 6, 7, 8, 9, 10 });
|
||||
|
||||
public static AI rifeNcnn = new AI(AI.Backend.Ncnn, "RIFE_NCNN", "RIFE (NCNN)",
|
||||
"Vulkan/NCNN Implementation of RIFE", "rife-ncnn", AI.FactorSupport.AnyFloat, new int[] { 2, 3, 4, 5, 6, 7, 8, 9, 10 });
|
||||
public static AI rifeNcnn = new AI(AI.AiBackend.Ncnn, "RIFE_NCNN", "RIFE (NCNN)",
|
||||
"Vulkan/NCNN Implementation of RIFE", "rife-ncnn", AI.InterpFactorSupport.AnyFloat, new int[] { 2, 3, 4, 5, 6, 7, 8, 9, 10 });
|
||||
|
||||
public static AI flavrCuda = new AI(AI.Backend.Pytorch, "FLAVR_CUDA", "FLAVR",
|
||||
"Experimental Pytorch Implementation of FLAVR (Nvidia Only!)", "flavr-cuda", AI.FactorSupport.Fixed, new int[] { 2, 4, 8 });
|
||||
public static AI rifeNcnnVs = new AI(AI.AiBackend.Ncnn, "RIFE_NCNN_VS", "RIFE (NCNN/VS)",
|
||||
"Vulkan/NCNN Implementation of RIFE in VS", "rife-ncnn-vs", AI.InterpFactorSupport.AnyFloat, new int[] { 2, 3, 4, 5, 6, 7, 8, 9, 10 })
|
||||
{ Piped = true };
|
||||
|
||||
public static AI dainNcnn = new AI(AI.Backend.Ncnn, "DAIN_NCNN", "DAIN (NCNN)",
|
||||
"Vulkan/NCNN Implementation of DAIN", "dain-ncnn", AI.FactorSupport.AnyFloat, new int[] { 2, 3, 4, 5, 6, 7, 8 });
|
||||
public static AI flavrCuda = new AI(AI.AiBackend.Pytorch, "FLAVR_CUDA", "FLAVR",
|
||||
"Experimental Pytorch Implementation of FLAVR (Nvidia Only!)", "flavr-cuda", AI.InterpFactorSupport.Fixed, new int[] { 2, 4, 8 });
|
||||
|
||||
public static AI xvfiCuda = new AI(AI.Backend.Pytorch, "XVFI_CUDA", "XVFI",
|
||||
"CUDA/Pytorch Implementation of XVFI (Nvidia Only!)", "xvfi-cuda", AI.FactorSupport.AnyInteger, new int[] { 2, 3, 4, 5, 6, 7, 8, 9, 10 });
|
||||
public static AI dainNcnn = new AI(AI.AiBackend.Ncnn, "DAIN_NCNN", "DAIN (NCNN)",
|
||||
"Vulkan/NCNN Implementation of DAIN", "dain-ncnn", AI.InterpFactorSupport.AnyFloat, new int[] { 2, 3, 4, 5, 6, 7, 8 });
|
||||
|
||||
public static List<AI> networks = new List<AI> { rifeCuda, rifeNcnn, flavrCuda, dainNcnn, xvfiCuda };
|
||||
public static AI xvfiCuda = new AI(AI.AiBackend.Pytorch, "XVFI_CUDA", "XVFI",
|
||||
"CUDA/Pytorch Implementation of XVFI (Nvidia Only!)", "xvfi-cuda", AI.InterpFactorSupport.AnyInteger, new int[] { 2, 3, 4, 5, 6, 7, 8, 9, 10 });
|
||||
|
||||
public static List<AI> networks = new List<AI> { rifeCuda, rifeNcnn, rifeNcnnVs, flavrCuda, dainNcnn, xvfiCuda };
|
||||
|
||||
public static AI GetAi (string aiName)
|
||||
{
|
||||
foreach(AI ai in networks)
|
||||
{
|
||||
if (ai.aiName == aiName)
|
||||
if (ai.AiName == aiName)
|
||||
return ai;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace Flowframes
|
||||
{
|
||||
public string inPath;
|
||||
public string outPath;
|
||||
public string FullOutPath { get; set; } = "";
|
||||
public AI ai;
|
||||
public Fraction inFps;
|
||||
public Fraction inFpsDetected;
|
||||
@@ -233,7 +234,7 @@ namespace Flowframes
|
||||
{
|
||||
string s = $"INPATH|{inPath}\n";
|
||||
s += $"OUTPATH|{outPath}\n";
|
||||
s += $"AI|{ai.aiName}\n";
|
||||
s += $"AI|{ai.AiName}\n";
|
||||
s += $"INFPSDETECTED|{inFpsDetected}\n";
|
||||
s += $"INFPS|{inFps}\n";
|
||||
s += $"OUTFPS|{outFps}\n";
|
||||
|
||||
@@ -222,7 +222,7 @@ namespace Flowframes
|
||||
|
||||
public static string[] Split(this string str, string trimStr)
|
||||
{
|
||||
return str.Split(new string[] { trimStr }, StringSplitOptions.None);
|
||||
return str?.Split(new string[] { trimStr }, StringSplitOptions.None);
|
||||
}
|
||||
|
||||
public static bool MatchesWildcard(this string str, string wildcard)
|
||||
|
||||
@@ -441,6 +441,7 @@
|
||||
<Compile Include="Os\Python.cs" />
|
||||
<Compile Include="Os\StartupChecks.cs" />
|
||||
<Compile Include="Os\Updater.cs" />
|
||||
<Compile Include="Os\VapourSynthUtils.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="MiscUtils\FormatUtils.cs" />
|
||||
|
||||
4
Code/Form1.Designer.cs
generated
4
Code/Form1.Designer.cs
generated
@@ -1297,7 +1297,7 @@
|
||||
this.scnDetectValue.DecimalPlaces = 2;
|
||||
this.scnDetectValue.ForeColor = System.Drawing.Color.White;
|
||||
this.scnDetectValue.Increment = new decimal(new int[] {
|
||||
5,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
131072});
|
||||
@@ -1308,7 +1308,7 @@
|
||||
0,
|
||||
65536});
|
||||
this.scnDetectValue.Minimum = new decimal(new int[] {
|
||||
5,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
131072});
|
||||
|
||||
@@ -191,7 +191,7 @@ namespace Flowframes
|
||||
inputTbox.Text = entry.inPath;
|
||||
MainUiFunctions.SetOutPath(outputTbox, entry.outPath);
|
||||
interpFactorCombox.Text = entry.interpFactor.ToString();
|
||||
aiCombox.SelectedIndex = Implementations.networks.IndexOf(Implementations.networks.Where(x => x.aiName == entry.ai.aiName).FirstOrDefault());
|
||||
aiCombox.SelectedIndex = Implementations.networks.IndexOf(Implementations.networks.Where(x => x.AiName == entry.ai.AiName).FirstOrDefault());
|
||||
SetOutMode(entry.outMode);
|
||||
}
|
||||
|
||||
@@ -273,20 +273,20 @@ namespace Flowframes
|
||||
|
||||
foreach (AI ai in Implementations.networks)
|
||||
{
|
||||
if (ai.backend == AI.Backend.Pytorch && !pytorchAvailable)
|
||||
if (ai.Backend == AI.AiBackend.Pytorch && !pytorchAvailable)
|
||||
{
|
||||
Logger.Log($"AI implementation {ai.friendlyName} ({ai.backend}) has not been loaded because Pytorch was not found.", true);
|
||||
Logger.Log($"AI implementation {ai.FriendlyName} ({ai.Backend}) has not been loaded because Pytorch was not found.", true);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
aiCombox.Items.Add(ai.friendlyName + " - " + ai.description);
|
||||
aiCombox.Items.Add(ai.FriendlyName + " - " + ai.Description);
|
||||
}
|
||||
|
||||
string lastUsedAiName = Config.Get(Config.Key.lastUsedAiName);
|
||||
aiCombox.SelectedIndex = Implementations.networks.IndexOf(Implementations.networks.Where(x => x.aiName == lastUsedAiName).FirstOrDefault());
|
||||
aiCombox.SelectedIndex = Implementations.networks.IndexOf(Implementations.networks.Where(x => x.AiName == lastUsedAiName).FirstOrDefault());
|
||||
if (aiCombox.SelectedIndex < 0) aiCombox.SelectedIndex = 0;
|
||||
Config.Set(Config.Key.lastUsedAiName, GetAi().aiName);
|
||||
Config.Set(Config.Key.lastUsedAiName, GetAi().AiName);
|
||||
|
||||
ConfigParser.LoadComboxIndex(outModeCombox);
|
||||
}
|
||||
@@ -466,16 +466,16 @@ namespace Flowframes
|
||||
|
||||
interpFactorCombox.Items.Clear();
|
||||
|
||||
foreach (int factor in GetAi().supportedFactors)
|
||||
foreach (int factor in GetAi().SupportedFactors)
|
||||
interpFactorCombox.Items.Add($"x{factor}");
|
||||
|
||||
interpFactorCombox.SelectedIndex = 0;
|
||||
|
||||
if (initialized)
|
||||
Config.Set(Config.Key.lastUsedAiName, GetAi().aiName);
|
||||
Config.Set(Config.Key.lastUsedAiName, GetAi().AiName);
|
||||
|
||||
interpFactorCombox_SelectedIndexChanged(null, null);
|
||||
fpsOutTbox.ReadOnly = GetAi().factorSupport != AI.FactorSupport.AnyFloat;
|
||||
fpsOutTbox.ReadOnly = GetAi().FactorSupport != AI.InterpFactorSupport.AnyFloat;
|
||||
}
|
||||
|
||||
public void UpdateAiModelCombox()
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Flowframes.Forms
|
||||
InterpSettings entry = Program.batchQueue.ElementAt(i);
|
||||
string niceOutMode = entry.outMode.ToString().ToUpper().Remove("VID").Remove("IMG");
|
||||
string str = $"#{i+1}: {Path.GetFileName(entry.inPath).Trunc(40)} - {entry.inFps.GetFloat()} FPS => " +
|
||||
$"{entry.interpFactor}x {entry.ai.aiNameShort} ({entry.model.name}) => {niceOutMode}";
|
||||
$"{entry.interpFactor}x {entry.ai.AiNameShort} ({entry.model.name}) => {niceOutMode}";
|
||||
taskList.Items.Add(str);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -578,7 +578,7 @@ namespace Flowframes.IO
|
||||
filename = filename.Replace("[NAME]", inName);
|
||||
filename = filename.Replace("[FULLNAME]", Path.GetFileName(curr.inPath));
|
||||
filename = filename.Replace("[FACTOR]", curr.interpFactor.ToStringDot());
|
||||
filename = filename.Replace("[AI]", curr.ai.aiNameShort.ToUpper());
|
||||
filename = filename.Replace("[AI]", curr.ai.AiNameShort.ToUpper());
|
||||
filename = filename.Replace("[MODEL]", curr.model.name.Remove(" "));
|
||||
filename = filename.Replace("[FPS]", fps.ToStringDot());
|
||||
filename = filename.Replace("[ROUNDFPS]", fps.RoundToInt().ToString());
|
||||
|
||||
@@ -134,8 +134,8 @@ namespace Flowframes.IO
|
||||
|
||||
public static async Task DownloadModelFiles (AI ai, string modelDir, bool log = true)
|
||||
{
|
||||
string aiDir = ai.pkgDir;
|
||||
Logger.Log($"DownloadModelFiles(string ai = {ai.aiName}, string model = {modelDir}, bool log = {log})", true);
|
||||
string aiDir = ai.PkgDir;
|
||||
Logger.Log($"DownloadModelFiles(string ai = {ai.AiName}, string model = {modelDir}, bool log = {log})", true);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -198,7 +198,7 @@ namespace Flowframes.IO
|
||||
|
||||
foreach (AI ai in Implementations.networks)
|
||||
{
|
||||
string aiPkgFolder = Path.Combine(Paths.GetPkgPath(), ai.pkgDir);
|
||||
string aiPkgFolder = Path.Combine(Paths.GetPkgPath(), ai.PkgDir);
|
||||
ModelCollection aiModels = AiModels.GetModels(ai);
|
||||
|
||||
foreach(ModelCollection.ModelInfo model in aiModels.models)
|
||||
|
||||
@@ -14,12 +14,12 @@ namespace Flowframes.Main
|
||||
{
|
||||
public static ModelCollection GetModels (AI ai)
|
||||
{
|
||||
string pkgPath = Path.Combine(Paths.GetPkgPath(), ai.pkgDir);
|
||||
string pkgPath = Path.Combine(Paths.GetPkgPath(), ai.PkgDir);
|
||||
string modelsFile = Path.Combine(pkgPath, "models.json");
|
||||
|
||||
if (!File.Exists(modelsFile))
|
||||
{
|
||||
Logger.Log($"Error: File models.json is missing for {ai.aiName}, can't load AI models for this implementation!");
|
||||
Logger.Log($"Error: File models.json is missing for {ai.AiName}, can't load AI models for this implementation!");
|
||||
return new ModelCollection(ai);
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Flowframes.Main
|
||||
|
||||
public static List<string> GetCustomModels(AI ai)
|
||||
{
|
||||
string pkgPath = Path.Combine(Paths.GetPkgPath(), ai.pkgDir);
|
||||
string pkgPath = Path.Combine(Paths.GetPkgPath(), ai.PkgDir);
|
||||
List<string> custModels = new List<string>();
|
||||
|
||||
foreach (DirectoryInfo dir in new DirectoryInfo(pkgPath).GetDirectories())
|
||||
|
||||
@@ -36,10 +36,10 @@ namespace Flowframes.Main
|
||||
|
||||
safetyBufferFrames = 90;
|
||||
|
||||
if (Interpolate.current.ai.backend == AI.Backend.Ncnn)
|
||||
if (Interpolate.current.ai.Backend == AI.AiBackend.Ncnn)
|
||||
safetyBufferFrames = Config.GetInt(Config.Key.autoEncSafeBufferNcnn, 150);
|
||||
|
||||
if (Interpolate.current.ai.backend == AI.Backend.Pytorch)
|
||||
if (Interpolate.current.ai.Backend == AI.AiBackend.Pytorch)
|
||||
safetyBufferFrames = Config.GetInt(Config.Key.autoEncSafeBufferCuda, 90);
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace Flowframes.Main
|
||||
|
||||
string fname = Path.GetFileName(entry.inPath);
|
||||
if (IoUtils.IsPathDirectory(entry.inPath)) fname = Path.GetDirectoryName(entry.inPath);
|
||||
Logger.Log($"Queue: Processing {fname} ({entry.interpFactor}x {entry.ai.aiNameShort}).");
|
||||
Logger.Log($"Queue: Processing {fname} ({entry.interpFactor}x {entry.ai.AiNameShort}).");
|
||||
|
||||
Program.mainForm.LoadBatchEntry(entry); // Load entry into GUI
|
||||
Interpolate.current = entry;
|
||||
@@ -92,7 +92,7 @@ namespace Flowframes.Main
|
||||
|
||||
Program.batchQueue.Dequeue();
|
||||
Program.mainForm.SetWorking(false);
|
||||
Logger.Log($"Queue: Done processing {fname} ({entry.interpFactor}x {entry.ai.aiNameShort}).");
|
||||
Logger.Log($"Queue: Done processing {fname} ({entry.interpFactor}x {entry.ai.AiNameShort}).");
|
||||
}
|
||||
|
||||
static void SetBusy(bool state)
|
||||
@@ -120,7 +120,7 @@ namespace Flowframes.Main
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IoUtils.GetAmountOfFiles(Path.Combine(Paths.GetPkgPath(), entry.ai.pkgDir), true) < 1)
|
||||
if (IoUtils.GetAmountOfFiles(Path.Combine(Paths.GetPkgPath(), entry.ai.PkgDir), true) < 1)
|
||||
{
|
||||
Logger.Log("Queue: Can't process queue entry: Selected AI is not available.");
|
||||
return false;
|
||||
|
||||
@@ -189,6 +189,12 @@ namespace Flowframes.Main
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task MuxPipedVideo (string inputVideo, string outputPath)
|
||||
{
|
||||
await MuxOutputVideo(inputVideo, Path.Combine(outputPath, outputPath));
|
||||
await Loop(outputPath, await GetLoopTimes());
|
||||
}
|
||||
|
||||
public static async Task ChunksToVideo(string tempFolder, string chunksFolder, string baseOutPath, bool isBackup = false)
|
||||
{
|
||||
if (IoUtils.GetAmountOfFiles(chunksFolder, true, "*" + FfmpegUtils.GetExt(I.current.outMode)) < 1)
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Flowframes
|
||||
Program.mainForm.SetStatus("Starting...");
|
||||
sw.Restart();
|
||||
|
||||
if (!AutoEncodeResume.resumeNextRun)
|
||||
if (!AutoEncodeResume.resumeNextRun && !current.ai.Piped)
|
||||
{
|
||||
await GetFrames();
|
||||
if (canceled) return;
|
||||
@@ -57,13 +57,17 @@ namespace Flowframes
|
||||
if (canceled) return;
|
||||
bool skip = await AutoEncodeResume.PrepareResumedRun();
|
||||
if (skip || canceled) return;
|
||||
//Task.Run(() => Utils.DeleteInterpolatedInputFrames());
|
||||
await RunAi(current.interpFolder, current.ai);
|
||||
if (canceled) return;
|
||||
Program.mainForm.SetProgress(100);
|
||||
|
||||
if(!currentlyUsingAutoEnc)
|
||||
await Export.ExportFrames(current.interpFolder, current.outPath, current.outMode, false);
|
||||
if (!currentlyUsingAutoEnc)
|
||||
{
|
||||
if (current.ai.Piped)
|
||||
await Export.MuxPipedVideo(current.inPath, current.FullOutPath);
|
||||
else
|
||||
await Export.ExportFrames(current.interpFolder, current.outPath, current.outMode, false);
|
||||
}
|
||||
|
||||
if (!AutoEncodeResume.resumeNextRun && Config.GetBool(Config.Key.keepTempFolder))
|
||||
await Task.Run(async () => { await FrameRename.Unrename(); });
|
||||
@@ -71,7 +75,7 @@ namespace Flowframes
|
||||
await Done();
|
||||
}
|
||||
|
||||
public static async Task Done ()
|
||||
public static async Task Done()
|
||||
{
|
||||
await Cleanup();
|
||||
Program.mainForm.SetWorking(false);
|
||||
@@ -84,7 +88,7 @@ namespace Flowframes
|
||||
Program.mainForm.InterpolationDone();
|
||||
}
|
||||
|
||||
public static async Task<int> GetCurrentInputFrameCount ()
|
||||
public static async Task<int> GetCurrentInputFrameCount()
|
||||
{
|
||||
if (currentInputFrameCount < 2)
|
||||
currentInputFrameCount = await GetFrameCountCached.GetFrameCountAsync(current.inPath);
|
||||
@@ -92,7 +96,7 @@ namespace Flowframes
|
||||
return currentInputFrameCount;
|
||||
}
|
||||
|
||||
public static async Task GetFrames ()
|
||||
public static async Task GetFrames()
|
||||
{
|
||||
current.RefreshAlpha();
|
||||
current.RefreshExtensions(InterpSettings.FrameType.Import);
|
||||
@@ -125,17 +129,17 @@ namespace Flowframes
|
||||
float percentDeleted = ((float)framesDeleted / currentInputFrameCount) * 100f;
|
||||
string keptPercent = $"{(100f - percentDeleted).ToString("0.0")}%";
|
||||
|
||||
if(QuickSettingsTab.trimEnabled)
|
||||
if (QuickSettingsTab.trimEnabled)
|
||||
Logger.Log($"Deduplication: Kept {framesLeft} frames.");
|
||||
else
|
||||
Logger.Log($"Deduplication: Kept {framesLeft} ({keptPercent}) frames, deleted {framesDeleted} frames.");
|
||||
}
|
||||
|
||||
if(!Config.GetBool("allowConsecutiveSceneChanges", true))
|
||||
if (!Config.GetBool("allowConsecutiveSceneChanges", true))
|
||||
Utils.FixConsecutiveSceneFrames(Path.Combine(current.tempFolder, Paths.scenesDir), current.framesFolder);
|
||||
}
|
||||
|
||||
public static async Task PostProcessFrames (bool stepByStep)
|
||||
public static async Task PostProcessFrames(bool stepByStep)
|
||||
{
|
||||
if (canceled) return;
|
||||
|
||||
@@ -145,11 +149,11 @@ namespace Flowframes
|
||||
|
||||
if (!Directory.Exists(current.framesFolder) || currentInputFrameCount <= 0 || extractedFrames < 2)
|
||||
{
|
||||
if(extractedFrames == 1)
|
||||
if (extractedFrames == 1)
|
||||
Cancel("Only a single frame was extracted from your input file!\n\nPossibly your input is an image, not a video?");
|
||||
else
|
||||
Cancel($"Frame extraction failed!\nExtracted {extractedFrames} frames - current.framesFolder exists: {Directory.Exists(current.framesFolder)} - currentInputFrameCount = {currentInputFrameCount} - extractedFrames = {extractedFrames}.\n\nYour input file might be incompatible.");
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.GetInt(Config.Key.dedupMode) == 1)
|
||||
await Dedupe.Run(current.framesFolder);
|
||||
@@ -175,12 +179,15 @@ namespace Flowframes
|
||||
{
|
||||
if (canceled) return;
|
||||
|
||||
await Task.Run(async () => { await Dedupe.CreateDupesFile(current.framesFolder, currentInputFrameCount, current.framesExt); });
|
||||
await Task.Run(async () => { await FrameRename.Rename(); });
|
||||
await Task.Run(async () => { await FrameOrder.CreateFrameOrderFile(current.framesFolder, Config.GetBool(Config.Key.enableLoop), current.interpFactor); });
|
||||
if (!ai.Piped)
|
||||
{
|
||||
await Task.Run(async () => { await Dedupe.CreateDupesFile(current.framesFolder, currentInputFrameCount, current.framesExt); });
|
||||
await Task.Run(async () => { await FrameRename.Rename(); });
|
||||
await Task.Run(async () => { await FrameOrder.CreateFrameOrderFile(current.framesFolder, Config.GetBool(Config.Key.enableLoop), current.interpFactor); });
|
||||
}
|
||||
|
||||
Program.mainForm.SetStatus("Downloading models...");
|
||||
await ModelDownloader.DownloadModelFiles(ai, current.model.dir);
|
||||
//await ModelDownloader.DownloadModelFiles(ai, current.model.dir);
|
||||
if (canceled) return;
|
||||
|
||||
currentlyUsingAutoEnc = Utils.CanUseAutoEnc(stepByStep, current);
|
||||
@@ -189,19 +196,22 @@ namespace Flowframes
|
||||
|
||||
List<Task> tasks = new List<Task>();
|
||||
|
||||
if (ai.aiName == Implementations.rifeCuda.aiName)
|
||||
if (ai.AiName == Implementations.rifeCuda.AiName)
|
||||
tasks.Add(AiProcess.RunRifeCuda(current.framesFolder, current.interpFactor, current.model.dir));
|
||||
|
||||
if (ai.aiName == Implementations.rifeNcnn.aiName)
|
||||
if (ai.AiName == Implementations.rifeNcnn.AiName)
|
||||
tasks.Add(AiProcess.RunRifeNcnn(current.framesFolder, outpath, current.interpFactor, current.model.dir));
|
||||
|
||||
if (ai.aiName == Implementations.flavrCuda.aiName)
|
||||
if (ai.AiName == Implementations.rifeNcnnVs.AiName)
|
||||
tasks.Add(AiProcess.RunRifeNcnnVs(current.framesFolder, outpath, current.interpFactor, current.model.dir));
|
||||
|
||||
if (ai.AiName == Implementations.flavrCuda.AiName)
|
||||
tasks.Add(AiProcess.RunFlavrCuda(current.framesFolder, current.interpFactor, current.model.dir));
|
||||
|
||||
if (ai.aiName == Implementations.dainNcnn.aiName)
|
||||
if (ai.AiName == Implementations.dainNcnn.AiName)
|
||||
tasks.Add(AiProcess.RunDainNcnn(current.framesFolder, outpath, current.interpFactor, current.model.dir, Config.GetInt(Config.Key.dainNcnnTilesize, 512)));
|
||||
|
||||
if (ai.aiName == Implementations.xvfiCuda.aiName)
|
||||
if (ai.AiName == Implementations.xvfiCuda.AiName)
|
||||
tasks.Add(AiProcess.RunXvfiCuda(current.framesFolder, current.interpFactor, current.model.dir));
|
||||
|
||||
if (currentlyUsingAutoEnc)
|
||||
@@ -227,10 +237,10 @@ namespace Flowframes
|
||||
|
||||
if (!current.stepByStep && !Config.GetBool(Config.Key.keepTempFolder))
|
||||
{
|
||||
if(!BatchProcessing.busy && IoUtils.GetAmountOfFiles(Path.Combine(current.tempFolder, Paths.resumeDir), true) > 0)
|
||||
if (!BatchProcessing.busy && 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)
|
||||
Task.Run(async () => { await IoUtils.TryDeleteIfExistsAsync(current.tempFolder); });
|
||||
}
|
||||
@@ -261,7 +271,7 @@ namespace Flowframes
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Log("Cleanup Error: " + e.Message, true);
|
||||
if(retriesLeft > 0)
|
||||
if (retriesLeft > 0)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
await Cleanup(ignoreKeepSetting, retriesLeft - 1, true);
|
||||
|
||||
@@ -148,7 +148,7 @@ namespace Flowframes.Main
|
||||
|
||||
public static bool CheckAiAvailable(AI ai, ModelCollection.ModelInfo model)
|
||||
{
|
||||
if (IoUtils.GetAmountOfFiles(Path.Combine(Paths.GetPkgPath(), ai.pkgDir), true) < 1)
|
||||
if (IoUtils.GetAmountOfFiles(Path.Combine(Paths.GetPkgPath(), ai.PkgDir), true) < 1)
|
||||
{
|
||||
UiUtils.ShowMessageBox("The selected AI is not installed!", UiUtils.MessageType.Error);
|
||||
I.Cancel("Selected AI not available.", true);
|
||||
@@ -162,7 +162,7 @@ namespace Flowframes.Main
|
||||
return false;
|
||||
}
|
||||
|
||||
if (I.current.ai.aiName.ToUpper().Contains("CUDA") && NvApi.gpuList.Count < 1)
|
||||
if (I.current.ai.AiName.ToUpper().Contains("CUDA") && NvApi.gpuList.Count < 1)
|
||||
{
|
||||
UiUtils.ShowMessageBox("Warning: No Nvidia GPU was detected. CUDA might fall back to CPU!\n\nTry an NCNN implementation instead if you don't have an Nvidia GPU.", UiUtils.MessageType.Error);
|
||||
|
||||
@@ -286,6 +286,12 @@ namespace Flowframes.Main
|
||||
{
|
||||
AutoEncode.UpdateChunkAndBufferSizes();
|
||||
|
||||
if (current.ai.Piped)
|
||||
{
|
||||
Logger.Log($"Not Using AutoEnc: Using piped encoding.", true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Config.GetInt(Config.Key.cmdDebugMode) > 0)
|
||||
{
|
||||
Logger.Log($"Not Using AutoEnc: CMD window is shown (cmdDebugMode > 0)", true);
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Flowframes
|
||||
|
||||
public static int GetPadding ()
|
||||
{
|
||||
return (Interpolate.current.ai.aiName == Implementations.flavrCuda.aiName) ? 8 : 2; // FLAVR input needs to be divisible by 8
|
||||
return (Interpolate.current.ai.AiName == Implementations.flavrCuda.AiName) ? 8 : 2; // FLAVR input needs to be divisible by 8
|
||||
}
|
||||
|
||||
public static string GetPadFilter ()
|
||||
|
||||
@@ -50,6 +50,7 @@ namespace Flowframes.Media
|
||||
case Codec.ProRes: return "prores_ks";
|
||||
case Codec.AviRaw: return Config.Get(Config.Key.aviCodec);
|
||||
}
|
||||
|
||||
return "libx264";
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace Flowframes.MiscUtils
|
||||
return;
|
||||
|
||||
ModelCollection.ModelInfo modelInfo = modelCollection.models[i];
|
||||
form.SetStatus($"Downloading files for {modelInfo.ai.aiName.Replace("_", "-")}...");
|
||||
form.SetStatus($"Downloading files for {modelInfo.ai.AiName.Replace("_", "-")}...");
|
||||
await ModelDownloader.DownloadModelFiles(ai, modelInfo.dir, false);
|
||||
taskCounter++;
|
||||
UpdateProgressBar();
|
||||
|
||||
@@ -11,6 +11,8 @@ using Flowframes.MiscUtils;
|
||||
using System.Collections.Generic;
|
||||
using ImageMagick;
|
||||
using Paths = Flowframes.IO.Paths;
|
||||
using Flowframes.Media;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Flowframes.Os
|
||||
{
|
||||
@@ -63,6 +65,18 @@ namespace Flowframes.Os
|
||||
InterpolationProgress.GetProgressByFrameAmount(interpPath, target);
|
||||
}
|
||||
|
||||
static void SetProgressCheck(int sourceFrames, float factor, string logFile)
|
||||
{
|
||||
int target = ((sourceFrames * factor) - (factor - 1)).RoundToInt();
|
||||
InterpolationProgress.progressPaused = false;
|
||||
InterpolationProgress.currentFactor = factor;
|
||||
|
||||
if (InterpolationProgress.progCheckRunning)
|
||||
InterpolationProgress.targetFrames = target;
|
||||
else
|
||||
InterpolationProgress.GetProgressFromFfmpegLog(logFile, target);
|
||||
}
|
||||
|
||||
static async Task AiFinished(string aiName)
|
||||
{
|
||||
if (Interpolate.canceled) return;
|
||||
@@ -82,7 +96,7 @@ namespace Flowframes.Os
|
||||
Logger.Log(logStr);
|
||||
processTime.Stop();
|
||||
|
||||
if (interpFramesCount < 3)
|
||||
if (!Interpolate.current.ai.Piped && interpFramesCount < 3)
|
||||
{
|
||||
string[] logLines = File.ReadAllLines(Path.Combine(Paths.GetLogPath(), lastLogName + ".txt"));
|
||||
string log = string.Join("\n", logLines.Reverse().Take(10).Reverse().Select(x => x.Split("]: ").Last()).ToList());
|
||||
@@ -120,7 +134,7 @@ namespace Flowframes.Os
|
||||
|
||||
try
|
||||
{
|
||||
string rifeDir = Path.Combine(Paths.GetPkgPath(), Implementations.rifeCuda.pkgDir);
|
||||
string rifeDir = Path.Combine(Paths.GetPkgPath(), Implementations.rifeCuda.PkgDir);
|
||||
string script = "rife.py";
|
||||
|
||||
if (!File.Exists(Path.Combine(rifeDir, script)))
|
||||
@@ -164,7 +178,7 @@ namespace Flowframes.Os
|
||||
Process rifePy = OsUtils.NewProcess(!OsUtils.ShowHiddenCmd());
|
||||
AiStarted(rifePy, 3500);
|
||||
SetProgressCheck(Path.Combine(Interpolate.current.tempFolder, outDir), interpFactor);
|
||||
rifePy.StartInfo.Arguments = $"{OsUtils.GetCmdArg()} cd /D {Path.Combine(Paths.GetPkgPath(), Implementations.rifeCuda.pkgDir).Wrap()} & " +
|
||||
rifePy.StartInfo.Arguments = $"{OsUtils.GetCmdArg()} cd /D {Path.Combine(Paths.GetPkgPath(), Implementations.rifeCuda.PkgDir).Wrap()} & " +
|
||||
$"set CUDA_VISIBLE_DEVICES={Config.Get(Config.Key.torchGpus)} & {Python.GetPyCmd()} {script} {args}";
|
||||
Logger.Log($"Running RIFE (CUDA){(await InterpolateUtils.UseUhd() ? " (UHD Mode)" : "")}...", false);
|
||||
Logger.Log("cmd.exe " + rifePy.StartInfo.Arguments, true);
|
||||
@@ -193,7 +207,7 @@ namespace Flowframes.Os
|
||||
|
||||
try
|
||||
{
|
||||
string flavDir = Path.Combine(Paths.GetPkgPath(), Implementations.flavrCuda.pkgDir);
|
||||
string flavDir = Path.Combine(Paths.GetPkgPath(), Implementations.flavrCuda.PkgDir);
|
||||
string script = "flavr.py";
|
||||
|
||||
if (!File.Exists(Path.Combine(flavDir, script)))
|
||||
@@ -222,7 +236,7 @@ namespace Flowframes.Os
|
||||
Process flavrPy = OsUtils.NewProcess(!OsUtils.ShowHiddenCmd());
|
||||
AiStarted(flavrPy, 4000);
|
||||
SetProgressCheck(Path.Combine(Interpolate.current.tempFolder, outDir), interpFactor);
|
||||
flavrPy.StartInfo.Arguments = $"{OsUtils.GetCmdArg()} cd /D {Path.Combine(Paths.GetPkgPath(), Implementations.flavrCuda.pkgDir).Wrap()} & " +
|
||||
flavrPy.StartInfo.Arguments = $"{OsUtils.GetCmdArg()} cd /D {Path.Combine(Paths.GetPkgPath(), Implementations.flavrCuda.PkgDir).Wrap()} & " +
|
||||
$"set CUDA_VISIBLE_DEVICES={Config.Get(Config.Key.torchGpus)} & {Python.GetPyCmd()} {script} {args}";
|
||||
Logger.Log($"Running FLAVR (CUDA)...", false);
|
||||
Logger.Log("cmd.exe " + flavrPy.StartInfo.Arguments, true);
|
||||
@@ -268,6 +282,7 @@ namespace Flowframes.Os
|
||||
static async Task RunRifeNcnnProcess(string inPath, float factor, string outPath, string mdl)
|
||||
{
|
||||
Directory.CreateDirectory(outPath);
|
||||
string logFileName = "rife-ncnn-log";
|
||||
Process rifeNcnn = OsUtils.NewProcess(!OsUtils.ShowHiddenCmd());
|
||||
AiStarted(rifeNcnn, 1500, inPath);
|
||||
SetProgressCheck(outPath, factor);
|
||||
@@ -277,15 +292,15 @@ namespace Flowframes.Os
|
||||
string uhdStr = await InterpolateUtils.UseUhd() ? "-u" : "";
|
||||
string ttaStr = Config.GetBool(Config.Key.rifeNcnnUseTta, false) ? "-x" : "";
|
||||
|
||||
rifeNcnn.StartInfo.Arguments = $"{OsUtils.GetCmdArg()} cd /D {Path.Combine(Paths.GetPkgPath(), Implementations.rifeNcnn.pkgDir).Wrap()} & rife-ncnn-vulkan.exe " +
|
||||
rifeNcnn.StartInfo.Arguments = $"{OsUtils.GetCmdArg()} cd /D {Path.Combine(Paths.GetPkgPath(), Implementations.rifeNcnn.PkgDir).Wrap()} & rife-ncnn-vulkan.exe " +
|
||||
$" -v -i {inPath.Wrap()} -o {outPath.Wrap()} {frames} -m {mdl.ToLower()} {ttaStr} {uhdStr} -g {Config.Get(Config.Key.ncnnGpus)} -f {GetNcnnPattern()} -j {GetNcnnThreads()}";
|
||||
|
||||
Logger.Log("cmd.exe " + rifeNcnn.StartInfo.Arguments, true);
|
||||
|
||||
if (!OsUtils.ShowHiddenCmd())
|
||||
{
|
||||
rifeNcnn.OutputDataReceived += (sender, outLine) => { LogOutput("[O] " + outLine.Data, "rife-ncnn-log"); };
|
||||
rifeNcnn.ErrorDataReceived += (sender, outLine) => { LogOutput("[E] " + outLine.Data, "rife-ncnn-log", true); };
|
||||
rifeNcnn.OutputDataReceived += (sender, outLine) => { LogOutput("[O] " + outLine.Data, logFileName); };
|
||||
rifeNcnn.ErrorDataReceived += (sender, outLine) => { LogOutput("[E] " + outLine.Data, logFileName, true); };
|
||||
}
|
||||
|
||||
rifeNcnn.Start();
|
||||
@@ -299,6 +314,64 @@ namespace Flowframes.Os
|
||||
while (!rifeNcnn.HasExited) await Task.Delay(1);
|
||||
}
|
||||
|
||||
public static async Task RunRifeNcnnVs(string framesPath, string outPath, float factor, string mdl)
|
||||
{
|
||||
processTimeMulti.Restart();
|
||||
|
||||
try
|
||||
{
|
||||
bool uhd = await InterpolateUtils.UseUhd();
|
||||
Logger.Log($"Running RIFE (NCNN-VS){(uhd ? " (UHD Mode)" : "")}...", false);
|
||||
|
||||
await RunRifeNcnnVsProcess(framesPath, factor, outPath, mdl, uhd);
|
||||
//await DeleteNcnnDupes(outPath, factor);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Log("Error running RIFE-NCNN-VS: " + e.Message);
|
||||
Logger.Log("Stack Trace: " + e.StackTrace, true);
|
||||
}
|
||||
|
||||
await AiFinished("RIFE");
|
||||
}
|
||||
|
||||
static async Task RunRifeNcnnVsProcess(string inPath, float factor, string outPath, string mdl, bool uhd)
|
||||
{
|
||||
Directory.CreateDirectory(outPath);
|
||||
string logFileName = "rife-ncnn-vs-log";
|
||||
Process rifeNcnnVs = OsUtils.NewProcess(!OsUtils.ShowHiddenCmd());
|
||||
AiStarted(rifeNcnnVs, 1500, inPath);
|
||||
SetProgressCheck(Interpolate.currentInputFrameCount, factor, logFileName);
|
||||
|
||||
Interpolate.current.FullOutPath = Path.Combine(Interpolate.current.outPath, await IoUtils.GetCurrentExportFilename(false, true));
|
||||
string encArgs = FfmpegUtils.GetEncArgs(FfmpegUtils.GetCodec(Interpolate.current.outMode), (Interpolate.current.ScaledResolution.IsEmpty ? Interpolate.current.InputResolution : Interpolate.current.ScaledResolution), Interpolate.current.outFps.GetFloat()).FirstOrDefault();
|
||||
string ffmpegArgs = $"ffmpeg -y -i pipe: {encArgs} {Interpolate.current.FullOutPath.Wrap()}";
|
||||
|
||||
float scn = Config.GetBool(Config.Key.scnDetect) ? Config.GetFloat(Config.Key.scnDetectValue) : 0f;
|
||||
Size res = InterpolateUtils.GetOutputResolution(Interpolate.current.InputResolution, true, true);
|
||||
|
||||
rifeNcnnVs.StartInfo.Arguments = $"{OsUtils.GetCmdArg()} cd /D {Path.Combine(Paths.GetPkgPath(), Implementations.rifeNcnnVs.PkgDir).Wrap()} & " +
|
||||
$" vspipe {VapourSynthUtils.CreateScript(Interpolate.current, mdl, factor, res, uhd, scn).Wrap()} -c y4m - | {ffmpegArgs}";
|
||||
|
||||
Logger.Log("cmd.exe " + rifeNcnnVs.StartInfo.Arguments, true);
|
||||
|
||||
if (!OsUtils.ShowHiddenCmd())
|
||||
{
|
||||
rifeNcnnVs.OutputDataReceived += (sender, outLine) => { LogOutput("[O] " + outLine.Data, logFileName); };
|
||||
rifeNcnnVs.ErrorDataReceived += (sender, outLine) => { LogOutput("[E] " + outLine.Data, logFileName, true); };
|
||||
}
|
||||
|
||||
rifeNcnnVs.Start();
|
||||
|
||||
if (!OsUtils.ShowHiddenCmd())
|
||||
{
|
||||
rifeNcnnVs.BeginOutputReadLine();
|
||||
rifeNcnnVs.BeginErrorReadLine();
|
||||
}
|
||||
|
||||
while (!rifeNcnnVs.HasExited) await Task.Delay(1);
|
||||
}
|
||||
|
||||
public static async Task RunDainNcnn(string framesPath, string outPath, float factor, string mdl, int tilesize)
|
||||
{
|
||||
if (Interpolate.currentlyUsingAutoEnc) // Ensure AutoEnc is not paused
|
||||
@@ -320,7 +393,7 @@ namespace Flowframes.Os
|
||||
|
||||
public static async Task RunDainNcnnProcess(string framesPath, string outPath, float factor, string mdl, int tilesize)
|
||||
{
|
||||
string dainDir = Path.Combine(Paths.GetPkgPath(), Implementations.dainNcnn.pkgDir);
|
||||
string dainDir = Path.Combine(Paths.GetPkgPath(), Implementations.dainNcnn.PkgDir);
|
||||
Directory.CreateDirectory(outPath);
|
||||
Process dain = OsUtils.NewProcess(!OsUtils.ShowHiddenCmd());
|
||||
AiStarted(dain, 1500);
|
||||
@@ -359,7 +432,7 @@ namespace Flowframes.Os
|
||||
|
||||
try
|
||||
{
|
||||
string xvfiDir = Path.Combine(Paths.GetPkgPath(), Implementations.xvfiCuda.pkgDir);
|
||||
string xvfiDir = Path.Combine(Paths.GetPkgPath(), Implementations.xvfiCuda.PkgDir);
|
||||
string script = "main.py";
|
||||
|
||||
if (!File.Exists(Path.Combine(xvfiDir, script)))
|
||||
@@ -381,7 +454,7 @@ namespace Flowframes.Os
|
||||
|
||||
public static async Task RunXvfiCudaProcess(string inPath, string outDir, string script, float interpFactor, string mdlDir)
|
||||
{
|
||||
string pkgPath = Path.Combine(Paths.GetPkgPath(), Implementations.xvfiCuda.pkgDir);
|
||||
string pkgPath = Path.Combine(Paths.GetPkgPath(), Implementations.xvfiCuda.PkgDir);
|
||||
string basePath = inPath.GetParentDir();
|
||||
string outPath = Path.Combine(basePath, outDir);
|
||||
Directory.CreateDirectory(outPath);
|
||||
@@ -474,7 +547,7 @@ namespace Flowframes.Os
|
||||
if (!hasShownError && line.ToLower().Contains("error(s) in loading state_dict"))
|
||||
{
|
||||
hasShownError = true;
|
||||
string msg = (Interpolate.current.ai.aiName == Implementations.flavrCuda.aiName) ? "\n\nFor FLAVR, you need to select the correct model for each scale!" : "";
|
||||
string msg = (Interpolate.current.ai.AiName == Implementations.flavrCuda.AiName) ? "\n\nFor FLAVR, you need to select the correct model for each scale!" : "";
|
||||
UiUtils.ShowMessageBox($"Error loading the AI model!\n\n{line}{msg}", UiUtils.MessageType.Error);
|
||||
}
|
||||
|
||||
@@ -499,7 +572,7 @@ namespace Flowframes.Os
|
||||
if (!hasShownError && err && line.Contains("vkAllocateMemory failed"))
|
||||
{
|
||||
hasShownError = true;
|
||||
bool usingDain = (Interpolate.current.ai.aiName == Implementations.dainNcnn.aiName);
|
||||
bool usingDain = (Interpolate.current.ai.AiName == Implementations.dainNcnn.AiName);
|
||||
string msg = usingDain ? "\n\nTry reducing the tile size in the AI settings." : "\n\nTry a lower resolution (Settings -> Max Video Size).";
|
||||
UiUtils.ShowMessageBox($"Vulkan ran out of memory!\n\n{line}{msg}", UiUtils.MessageType.Error);
|
||||
}
|
||||
@@ -581,10 +654,5 @@ namespace Flowframes.Os
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static double Compare(string referenceImg, string compareImg)
|
||||
{
|
||||
return new MagickImage(referenceImg).Compare(new MagickImage(compareImg), ErrorMetric.PeakSignalToNoiseRatio);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,14 +157,14 @@ namespace Flowframes.Os
|
||||
try
|
||||
{
|
||||
var client = new WebClient();
|
||||
string aiName = ai.pkgDir;
|
||||
string aiName = ai.PkgDir;
|
||||
string url = $"https://raw.githubusercontent.com/n00mkrad/flowframes/main/Pkgs/{aiName}/models.txt";
|
||||
string movePath = Path.Combine(Paths.GetPkgPath(), aiName, "models.txt");
|
||||
string savePath = movePath + ".tmp";
|
||||
|
||||
if (!Directory.Exists(savePath.GetParentDir()))
|
||||
{
|
||||
Logger.Log($"Skipping {ai.pkgDir} models file download as '{savePath.GetParentDir()}' does not exist!", true);
|
||||
Logger.Log($"Skipping {ai.PkgDir} models file download as '{savePath.GetParentDir()}' does not exist!", true);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ namespace Flowframes.Os
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Log($"Failed to fetch models file for {ai.friendlyName}. Ignore this if you are not connected to the internet.");
|
||||
Logger.Log($"Failed to fetch models file for {ai.FriendlyName}. Ignore this if you are not connected to the internet.");
|
||||
Logger.Log($"{e.Message}\n{e.StackTrace}", true);
|
||||
}
|
||||
}
|
||||
|
||||
59
Code/Os/VapourSynthUtils.cs
Normal file
59
Code/Os/VapourSynthUtils.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using Flowframes.Data;
|
||||
using Flowframes.IO;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Flowframes.Os
|
||||
{
|
||||
class VapourSynthUtils
|
||||
{
|
||||
public static string CreateScript(InterpSettings set, string modelDir, float factor, Size res, bool uhd, float sceneDetectSens = 0.15f, int gpuId = 0, int gpuThreads = 3, bool tta = false)
|
||||
{
|
||||
string inputPath = set.inPath;
|
||||
bool resize = !set.ScaledResolution.IsEmpty && set.ScaledResolution != set.InputResolution;
|
||||
bool sc = sceneDetectSens >= 0.01f;
|
||||
|
||||
string text = ""
|
||||
+ $"import sys\n"
|
||||
+ $"import vapoursynth as vs\n"
|
||||
+ $"core = vs.core\n"
|
||||
+ $"clip = core.ffms2.Source(source=r'{inputPath}')\n"
|
||||
+ $"clip = core.resize.Bicubic(clip=clip, format=vs.RGBS, matrix_in_s=\"709\", range_s=\"limited\"{(resize ? $", width={set.ScaledResolution.Width}, height={set.ScaledResolution.Height}" : "")})\n"
|
||||
+ $"{(sc ? $"clip = core.misc.SCDetect(clip=clip,threshold={sceneDetectSens.ToStringDot()})" : "# Scene detection disabled")}\n"
|
||||
+ $"clip = core.rife.RIFE(clip, {GetModelNum(modelDir)}, {factor.ToStringDot()}, {gpuId}, {gpuThreads}, {tta}, {uhd}, {sc})\n"
|
||||
+ $"clip = vs.core.resize.Bicubic(clip, format=vs.YUV444P16, matrix_s=\"709\")\n"
|
||||
+ $"clip.set_output()\n";
|
||||
|
||||
string pkgPath = Path.Combine(Paths.GetPkgPath(), Implementations.rifeNcnnVs.PkgDir);
|
||||
string vpyPath = Path.Combine(pkgPath, "rife.vpy");
|
||||
|
||||
File.WriteAllText(vpyPath, text);
|
||||
|
||||
return vpyPath;
|
||||
}
|
||||
|
||||
private static int GetModelNum(string modelDir)
|
||||
{
|
||||
switch (modelDir)
|
||||
{
|
||||
case "rife": return 0;
|
||||
case "rife-HD": return 1;
|
||||
case "rife-UHD": return 2;
|
||||
case "rife-anime": return 3;
|
||||
case "rife-v2": return 4;
|
||||
case "rife-v2.3": return 5;
|
||||
case "rife-v2.4": return 6;
|
||||
case "rife-v3.0": return 7;
|
||||
case "rife-v3.1": return 8;
|
||||
case "rife-v4": return 9;
|
||||
}
|
||||
|
||||
return 9;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,17 +28,22 @@ namespace Flowframes.Ui
|
||||
public static PictureBox preview;
|
||||
public static BigPreviewForm bigPreviewForm;
|
||||
|
||||
public static async void GetProgressByFrameAmount(string outdir, int target)
|
||||
public static void Restart ()
|
||||
{
|
||||
progCheckRunning = true;
|
||||
deletedFramesCount = 0;
|
||||
lastFrame = 0;
|
||||
peakFpsOut = 0f;
|
||||
Program.mainForm.SetProgress(0);
|
||||
}
|
||||
|
||||
public static async void GetProgressByFrameAmount(string outdir, int target)
|
||||
{
|
||||
targetFrames = target;
|
||||
currentOutdir = outdir;
|
||||
Logger.Log($"Starting GetProgressByFrameAmount() loop for outdir '{currentOutdir}', target is {target} frames", true);
|
||||
bool firstProgUpd = true;
|
||||
Program.mainForm.SetProgress(0);
|
||||
deletedFramesCount = 0;
|
||||
lastFrame = 0;
|
||||
peakFpsOut = 0f;
|
||||
Restart();
|
||||
|
||||
while (Program.busy)
|
||||
{
|
||||
@@ -74,7 +79,7 @@ namespace Flowframes.Ui
|
||||
{
|
||||
try
|
||||
{
|
||||
string ncnnStr = I.current.ai.aiName.Contains("NCNN") ? " done" : "";
|
||||
string ncnnStr = I.current.ai.AiName.Contains("NCNN") ? " done" : "";
|
||||
Regex frameRegex = new Regex($@"(?<=.)\d*(?={I.current.interpExt}{ncnnStr})");
|
||||
if (!frameRegex.IsMatch(output)) return;
|
||||
lastFrame = Math.Max(int.Parse(frameRegex.Match(output).Value), lastFrame);
|
||||
@@ -85,6 +90,40 @@ namespace Flowframes.Ui
|
||||
}
|
||||
}
|
||||
|
||||
public static async void GetProgressFromFfmpegLog(string logFile, int target)
|
||||
{
|
||||
targetFrames = target;
|
||||
Logger.Log($"Starting GetProgressFromFfmpegLog() loop for log '{logFile}', target is {target} frames", true);
|
||||
Restart();
|
||||
|
||||
while (Program.busy)
|
||||
{
|
||||
if (!progressPaused && AiProcess.processTime.IsRunning)
|
||||
{
|
||||
string lastLogLine = Logger.GetSessionLogLastLines(logFile, 3).Where(x => x.Contains("frame=")).LastOrDefault();
|
||||
|
||||
int num = lastLogLine == null ? 0 : lastLogLine.Split("frame=")[1].Split("fps=")[0].GetInt();
|
||||
|
||||
if(num > 0)
|
||||
UpdateInterpProgress(num, targetFrames);
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
if (num >= targetFrames)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
await Task.Delay(100);
|
||||
}
|
||||
}
|
||||
|
||||
progCheckRunning = false;
|
||||
|
||||
if (I.canceled)
|
||||
Program.mainForm.SetProgress(0);
|
||||
}
|
||||
|
||||
public static int interpolatedInputFramesCount;
|
||||
public static float peakFpsOut;
|
||||
|
||||
|
||||
@@ -157,31 +157,31 @@ namespace Flowframes.Ui
|
||||
{
|
||||
AI ai = Program.mainForm.GetAi();
|
||||
|
||||
if (ai.aiName == Implementations.rifeNcnn.aiName && !Program.mainForm.GetModel(ai).dir.Contains("v4"))
|
||||
if (ai.AiName == Implementations.rifeNcnn.AiName && !Program.mainForm.GetModel(ai).dir.Contains("v4"))
|
||||
{
|
||||
if (factor != 2)
|
||||
Logger.Log($"{ai.friendlyName} models before 4.0 only support 2x interpolation!");
|
||||
Logger.Log($"{ai.FriendlyName} models before 4.0 only support 2x interpolation!");
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (ai.factorSupport == AI.FactorSupport.Fixed)
|
||||
if (ai.FactorSupport == AI.InterpFactorSupport.Fixed)
|
||||
{
|
||||
int closest = ai.supportedFactors.Min(i => (Math.Abs(factor.RoundToInt() - i), i)).i;
|
||||
int closest = ai.SupportedFactors.Min(i => (Math.Abs(factor.RoundToInt() - i), i)).i;
|
||||
return (float)closest;
|
||||
}
|
||||
|
||||
if(ai.factorSupport == AI.FactorSupport.AnyPowerOfTwo)
|
||||
if(ai.FactorSupport == AI.InterpFactorSupport.AnyPowerOfTwo)
|
||||
{
|
||||
return ToNearestPow2(factor.RoundToInt()).Clamp(2, 128);
|
||||
}
|
||||
|
||||
if(ai.factorSupport == AI.FactorSupport.AnyInteger)
|
||||
if(ai.FactorSupport == AI.InterpFactorSupport.AnyInteger)
|
||||
{
|
||||
return factor.RoundToInt().Clamp(2, 128);
|
||||
}
|
||||
|
||||
if(ai.factorSupport == AI.FactorSupport.AnyFloat)
|
||||
if(ai.FactorSupport == AI.InterpFactorSupport.AnyFloat)
|
||||
{
|
||||
return factor.Clamp(2, 128);
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace Flowframes.Ui
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Log($"Failed to load available AI models for {ai.aiName}! {e.Message}");
|
||||
Logger.Log($"Failed to load available AI models for {ai.AiName}! {e.Message}");
|
||||
Logger.Log($"Stack Trace: {e.StackTrace}", true);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user