Pad/crop system for improved model support, VS improvements

This commit is contained in:
N00MKRAD
2024-11-12 22:13:59 +01:00
parent 9bd1736fec
commit 6b44346138
14 changed files with 247 additions and 127 deletions

View File

@@ -1,11 +1,7 @@
using Flowframes.IO;
using Flowframes.MiscUtils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Flowframes.Data
{
@@ -26,7 +22,7 @@ namespace Flowframes.Data
public string LogFilename { get { return PkgDir + "-log"; } }
public AiInfo () { }
public AiInfo() { }
public AiInfo(AiBackend backend, string aiName, string longName, InterpFactorSupport factorSupport = InterpFactorSupport.Fixed, int[] supportedFactors = null)
{
@@ -37,7 +33,7 @@ namespace Flowframes.Data
FactorSupport = factorSupport;
}
public string GetVerboseInfo ()
public string GetVerboseInfo()
{
return $"Name:\n{NameShort}\n\n" +
$"Full Name:\n{NameLong}\n\n" +
@@ -48,12 +44,12 @@ namespace Flowframes.Data
$"Package Directory/Size:\n{PkgDir} ({FormatUtils.Bytes(IoUtils.GetDirSize(Path.Combine(Paths.GetPkgPath(), PkgDir), true))})";
}
private string GetImplemString (AiBackend backend)
private string GetImplemString(AiBackend backend)
{
if (backend == AiBackend.Pytorch)
return $"CUDA/Pytorch Implementation";
if(backend == AiBackend.Ncnn)
if (backend == AiBackend.Ncnn)
return $"Vulkan/NCNN{(Piped ? "/VapourSynth" : "")} Implementation";
if (backend == AiBackend.Tensorflow)
@@ -76,7 +72,7 @@ namespace Flowframes.Data
return "Custom";
}
private string GetHwAccelString (AiBackend backend)
private string GetHwAccelString(AiBackend backend)
{
if (Backend == AiBackend.Pytorch)
return $"GPU (Nvidia CUDA)";
@@ -87,7 +83,7 @@ namespace Flowframes.Data
return "Unknown";
}
private string GetFactorsString (InterpFactorSupport factorSupport)
private string GetFactorsString(InterpFactorSupport factorSupport)
{
if (factorSupport == InterpFactorSupport.Fixed)
return $"{string.Join(", ", SupportedFactors.Select(x => $"{x}x"))}";
@@ -103,5 +99,33 @@ namespace Flowframes.Data
return "Unknown";
}
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
return false;
var other = (AiInfo)obj;
return Backend == other.Backend && NameInternal == other.NameInternal;
}
// Combine hash codes of properties (using a simple hash approach for .NET Framework)
public override int GetHashCode()
{
int hash = 17;
hash = hash * 23 + Backend.GetHashCode();
hash = hash * 23 + (NameInternal?.GetHashCode() ?? 0);
return hash;
}
public static bool operator ==(AiInfo left, AiInfo right)
{
if (left is null)
return ReferenceEquals(right, null);
else
return left.Equals(right);
}
public static bool operator !=(AiInfo left, AiInfo right) => !(left == right);
}
}

View File

@@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Flowframes.Data
namespace Flowframes.Data
{
public class OutputSettings
{

View File

@@ -3,13 +3,13 @@ using Flowframes.Data;
using Flowframes.IO;
using Flowframes.Main;
using Flowframes.MiscUtils;
using Flowframes.Ui;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Diagnostics;
namespace Flowframes
{
@@ -33,10 +33,49 @@ namespace Flowframes
public string interpFolder;
public bool inputIsFrames;
private Size _inputResolution;
public Size InputResolution { get { RefreshInputRes(); return _inputResolution; } }
public Size ScaledResolution { get { return InterpolateUtils.GetOutputResolution(InputResolution, false); } }
public Size ScaledPaddedResolution { get { return InterpolateUtils.GetOutputResolution(InputResolution, true); } }
private Size _inputResolution = new Size();
public Size InputResolution
{
get
{
if (_inputResolution.IsEmpty)
_inputResolution = GetMediaResolutionCached.GetSizeAsync(inPath).Result;
return _inputResolution;
}
}
private Size _outputResolution = new Size();
public Size OutputResolution
{
get
{
if (_outputResolution.IsEmpty)
_outputResolution = InterpolateUtils.GetInterpolationResolution(FfmpegCommands.ModuloMode.ForEncoding, InputResolution);
return _outputResolution;
}
}
private Size _scaledResolution = new Size();
public Size ScaledResolution
{
get
{
if (_scaledResolution.IsEmpty)
_scaledResolution = InterpolateUtils.GetInterpolationResolution(FfmpegCommands.ModuloMode.Disabled, InputResolution);
return _scaledResolution;
}
}
private Size _interpResolution = new Size();
public Size InterpResolution
{
get
{
if (_interpResolution.IsEmpty)
_interpResolution = InterpolateUtils.GetInterpolationResolution(FfmpegCommands.ModuloMode.ForInterpolation, InputResolution);
return _interpResolution;
}
}
public bool alpha;
public bool stepByStep;
@@ -169,12 +208,6 @@ namespace Flowframes
inputIsFrames = IoUtils.IsPathDirectory(inPath);
}
async Task RefreshInputRes ()
{
if (_inputResolution.IsEmpty)
_inputResolution = await GetMediaResolutionCached.GetSizeAsync(inPath);
}
public void RefreshAlpha ()
{
try
@@ -239,7 +272,7 @@ namespace Flowframes
s += $"OUTMODE|{outSettings.Format}\n";
s += $"MODEL|{model.Name}\n";
s += $"INPUTRES|{InputResolution.Width}x{InputResolution.Height}\n";
s += $"OUTPUTRES|{ScaledResolution.Width}x{ScaledResolution.Height}\n";
s += $"OUTPUTRES|{OutputResolution.Width}x{OutputResolution.Height}\n";
s += $"ALPHA|{alpha}\n";
s += $"STEPBYSTEP|{stepByStep}\n";
s += $"FRAMESEXT|{framesExt}\n";

View File

@@ -74,8 +74,8 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\RelGui</OutputPath>
<OutputType>WinExe</OutputType>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<Optimize>false</Optimize>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>

View File

@@ -601,7 +601,7 @@ namespace Flowframes.IO
Fraction maxFps = max.Contains("/") ? new Fraction(max) : new Fraction(max.GetFloat());
float fps = fpsLimit ? maxFps.Float : curr.outFps.Float;
Size outRes = await InterpolateUtils.GetOutputResolution(curr.inPath, true);
Size outRes = curr.OutputResolution; // TODO: Replace with EncodeResolution once implemented?
string pattern = Config.Get(Config.Key.exportNamePattern);
string inName = Interpolate.currentSettings.inputIsFrames ? Path.GetFileName(curr.inPath) : Path.GetFileNameWithoutExtension(curr.inPath);
bool encodeBoth = Config.GetInt(Config.Key.maxFpsMode) == 0;

View File

@@ -19,8 +19,8 @@ namespace Flowframes.Main
{
class Export
{
private static string MaxFps = Config.Get(Config.Key.maxFps);
private static Fraction MaxFpsFrac = new Fraction(MaxFps);
private static string MaxFps => Config.Get(Config.Key.maxFps);
private static Fraction MaxFpsFrac => new Fraction(MaxFps);
public static async Task ExportFrames(string path, string outFolder, OutputSettings exportSettings, bool stepByStep)
{
@@ -75,7 +75,7 @@ namespace Flowframes.Main
public static async Task<string> GetPipedFfmpegCmd(bool ffplay = false)
{
InterpSettings s = I.currentSettings;
string encArgs = FfmpegUtils.GetEncArgs(s.outSettings, (s.ScaledResolution.IsEmpty ? s.InputResolution : s.ScaledResolution), s.outFps.Float, true).FirstOrDefault();
string encArgs = FfmpegUtils.GetEncArgs(s.outSettings, (s.OutputResolution.IsEmpty ? s.InputResolution : s.OutputResolution), s.outFps.Float, true).FirstOrDefault();
bool fpsLimit = MaxFpsFrac.Float > 0f && s.outFps.Float > MaxFpsFrac.Float;
bool gifInput = I.currentMediaFile.Format.Upper() == "GIF"; // If input is GIF, we don't need to check the color space etc
VidExtraData extraData = gifInput ? new VidExtraData() : await FfmpegCommands.GetVidExtraInfo(s.inPath);

View File

@@ -128,7 +128,7 @@ namespace Flowframes
if (!currentSettings.inputIsFrames) // Extract if input is video, import if image sequence
await ExtractFrames(currentSettings.inPath, currentSettings.framesFolder, currentSettings.alpha);
else
await FfmpegExtract.ImportImagesCheckCompat(currentSettings.inPath, currentSettings.framesFolder, currentSettings.alpha, currentSettings.ScaledResolution, true, currentSettings.framesExt);
await FfmpegExtract.ImportImagesCheckCompat(currentSettings.inPath, currentSettings.framesFolder, currentSettings.alpha, currentSettings.OutputResolution, true, currentSettings.framesExt);
}
public static async Task ExtractFrames(string inPath, string outPath, bool alpha)
@@ -137,7 +137,7 @@ namespace Flowframes
Program.mainForm.SetStatus("Extracting frames from video...");
currentSettings.RefreshExtensions(InterpSettings.FrameType.Import);
bool mpdecimate = Config.GetInt(Config.Key.dedupMode) == 2;
Size res = await Utils.GetOutputResolution(inPath, true, true);
Size res = await Utils.GetOutputResolution(FfmpegCommands.ModuloMode.ForEncoding, inPath, print: true);
await FfmpegExtract.VideoToFrames(inPath, outPath, alpha, currentSettings.inFpsDetected, mpdecimate, false, res, currentSettings.framesExt);
if (mpdecimate)

View File

@@ -12,6 +12,7 @@ using System.Linq;
using System.Threading.Tasks;
using I = Flowframes.Interpolate;
using Padding = Flowframes.Data.Padding;
using Flowframes.MiscUtils;
namespace Flowframes.Main
{
@@ -252,42 +253,42 @@ namespace Flowframes.Main
public static bool IsVideoValid(string videoPath)
{
if (videoPath == null || !IoUtils.IsFileValid(videoPath))
return false;
return true;
return videoPath != null && IoUtils.IsFileValid(videoPath);
}
public static async Task<Size> GetOutputResolution(string inputPath, bool pad, bool print = false)
public static async Task<Size> GetOutputResolution(FfmpegCommands.ModuloMode moduloMode, string inputPath, bool print = false)
{
Size resolution = await GetMediaResolutionCached.GetSizeAsync(inputPath);
return GetOutputResolution(resolution, pad, print);
return GetInterpolationResolution(moduloMode, resolution, print);
}
public static Size GetOutputResolution(Size inputRes, bool pad, bool print = false)
public static Size GetInterpolationResolution(FfmpegCommands.ModuloMode moduloMode, Size inputRes, bool onlyRoundUp = true, bool print = false)
{
Size res = new Size(inputRes.Width, inputRes.Height);
int maxHeight = Config.GetInt(Config.Key.maxVidHeight);
int mod = pad ? FfmpegCommands.GetModulo() : 1;
int modulo = FfmpegCommands.GetModulo(moduloMode);
float factor = res.Height > maxHeight ? (float)maxHeight / res.Height : 1f; // Calculate downscale factor if bigger than max, otherwise just use 1x
Logger.Log($"Un-rounded downscaled size: {(res.Width * factor).ToString("0.###")}x{(res.Height * factor).ToString("0.###")}", true);
int width = RoundDivisibleBy((res.Width * factor).RoundToInt(), mod);
int height = RoundDivisibleBy((res.Height * factor).RoundToInt(), mod);
int width = RoundDivisibleBy((res.Width * factor).RoundToInt(), modulo, onlyRoundUp);
int height = RoundDivisibleBy((res.Height * factor).RoundToInt(), modulo, onlyRoundUp);
res = new Size(width, height);
if (print && factor < 1f)
Logger.Log($"Video is bigger than the maximum - Downscaling to {width}x{height}.");
if (res != inputRes)
Logger.Log($"Scaled {inputRes.Width}x{inputRes.Height} to {res.Width}x{res.Height}", true);
Logger.Log($"Scaled input res {inputRes.Width}x{inputRes.Height} to {res.Width}x{res.Height} ({moduloMode})", true);
return res;
}
public static int RoundDivisibleBy(int number, int divisibleBy) // Round to a number that's divisible by 2 (for h264 etc)
public static int RoundDivisibleBy(float number, int divisibleBy, bool onlyRoundUp = false)
{
int a = (number / divisibleBy) * divisibleBy; // Smaller multiple
int b = a + divisibleBy; // Larger multiple
return (number - a > b - number) ? b : a; // Return of closest of two
int numberInt = number.RoundToInt();
if (divisibleBy == 0)
return numberInt;
return onlyRoundUp
? (int)Math.Ceiling((double)number / divisibleBy) * divisibleBy
: (int)Math.Round((double)number / divisibleBy) * divisibleBy;
}
public static bool CanUseAutoEnc(bool stepByStep, InterpSettings current)
@@ -334,9 +335,9 @@ namespace Flowframes.Main
return true;
}
public static async Task<bool> UseUhd()
public static bool UseUhd()
{
return UseUhd(await GetOutputResolution(I.currentSettings.inPath, false));
return UseUhd(I.currentSettings.OutputResolution);
}
public static bool UseUhd(Size outputRes)
@@ -358,7 +359,7 @@ namespace Flowframes.Main
if (sceneFramesToDelete.Contains(scnFrame))
continue;
int sourceIndexForScnFrame = sourceFrames.IndexOf(scnFrame); // Get source index of scene frame
int sourceIndexForScnFrame = sourceFrames.IndexOf(scnFrame); // Get source index of scene frame
if ((sourceIndexForScnFrame + 1) == sourceFrames.Count)
continue;
string followingFrame = sourceFrames[sourceIndexForScnFrame + 1]; // Get filename/timestamp of the next source frame

View File

@@ -1,7 +1,6 @@
using Flowframes.Media;
using Flowframes.Data;
using Flowframes.IO;
using Flowframes.MiscUtils;
using System;
using System.Collections.Generic;
using System.Drawing;
@@ -9,7 +8,6 @@ using System.IO;
using System.Linq;
using System.Threading.Tasks;
using static Flowframes.AvProcess;
using System.Drawing.Imaging;
namespace Flowframes
{
@@ -34,21 +32,38 @@ namespace Flowframes
return wrap ? mpd.Wrap() : mpd;
}
public static int GetModulo()
{
if (Interpolate.currentSettings.ai.NameInternal == Implementations.flavrCuda.NameInternal)
return 8;
public enum ModuloMode { Disabled, ForInterpolation, ForEncoding }
return Interpolate.currentSettings.outSettings.Encoder.GetInfo().Modulo;
public static int GetModulo(ModuloMode mode)
{
if (mode == ModuloMode.ForEncoding)
{
return Interpolate.currentSettings.outSettings.Encoder.GetInfo().Modulo;
}
else if (mode == ModuloMode.ForInterpolation)
{
bool RifeNeedsPadding(string ver) => ver.Split('.').Last().GetInt() >= 25; // e.g. "RIFE 4.25" needs padding
if (Interpolate.currentSettings.model.Name.Contains("RIFE") && RifeNeedsPadding(Interpolate.currentSettings.model.Name))
return 64;
if (Interpolate.currentSettings.ai == Implementations.flavrCuda)
return 8;
}
return 1;
}
public static string GetPadFilter()
public static string GetPadFilter(int width = -1, int height = -1)
{
int mod = GetModulo();
int mod = GetModulo(ModuloMode.ForEncoding);
if (mod < 2)
return "";
if (width > 0 && width % mod == 0 && height > 0 && height % mod == 0)
return "";
return $"pad=width=ceil(iw/{mod})*{mod}:height=ceil(ih/{mod})*{mod}:color=black@0";
}
@@ -154,14 +169,14 @@ namespace Flowframes
}
}
public static void CheckVfr (string inputFile, MediaFile mediaFile, List<string> outputLinesPackets = null)
public static void CheckVfr(string inputFile, MediaFile mediaFile, List<string> outputLinesPackets = null)
{
if (mediaFile.InputTimestamps.Any())
return;
Logger.Log($"Checking frame timing...", true, false, "ffmpeg");
if(outputLinesPackets == null)
if (outputLinesPackets == null)
{
string argsPackets = $"ffprobe -v error -select_streams v:0 -show_packets -show_entries packet=pts_time -read_intervals \"%+120\" -of csv=p=0 {inputFile.Wrap()}";
outputLinesPackets = NUtilsTemp.OsUtils.RunCommand($"cd /D {GetAvDir().Wrap()} && {argsPackets}").SplitIntoLines().Where(l => l.IsNotEmpty()).ToList();

View File

@@ -20,7 +20,7 @@ namespace Flowframes.Media
IoUtils.RenameExistingFileOrDir(outPath);
Directory.CreateDirectory(outPath.GetParentDir());
string[] encArgs = Utils.GetEncArgs(settings, (Interpolate.currentSettings.ScaledResolution.IsEmpty ? Interpolate.currentSettings.InputResolution : Interpolate.currentSettings.ScaledResolution), Interpolate.currentSettings.outFps.Float);
string[] encArgs = Utils.GetEncArgs(settings, (Interpolate.currentSettings.OutputResolution.IsEmpty ? Interpolate.currentSettings.InputResolution : Interpolate.currentSettings.OutputResolution), Interpolate.currentSettings.outFps.Float);
string inArg = $"-f concat -i {Path.GetFileName(framesFile)}";
string linksDir = Path.Combine(framesFile + Paths.symlinksSuffix);
@@ -102,12 +102,7 @@ namespace Flowframes.Media
filters.Add($"zscale=transfer=linear,format={settings.PixelFormat.ToString().Lower()}".Wrap());
}
// Only if encoder is not GIF and width and height are not divisible by 2
if (settings.Encoder != Enums.Encoding.Encoder.Gif && (mf.VideoStreams[0].Resolution.Width % 2 != 0 || mf.VideoStreams[0].Resolution.Height % 2 != 0))
{
filters.Add(GetPadFilter());
}
filters.Add(GetPadFilter(Interpolate.currentSettings.ScaledResolution.Width, Interpolate.currentSettings.ScaledResolution.Height));
filters = filters.Where(f => f.IsNotEmpty()).ToList();
return filters.Count > 0 ?

View File

@@ -204,14 +204,16 @@ namespace Flowframes.Media
return false;
}
int div = GetModulo();
bool allDivBy2 = randomSamples.All(i => (i.Width % div == 0) && (i.Height % div == 0));
Logger.Log($"---> TODO: Modulo check for images? Or just check later and apply padding before interpolation if needed...", hidden: true);
if (!allDivBy2)
{
Logger.Log($"Sequence not compatible: Not all image dimensions are divisible by {div}.", true);
return false;
}
// int div = GetModulo();
// bool allDivBy2 = randomSamples.All(i => (i.Width % div == 0) && (i.Height % div == 0));
//
// if (!allDivBy2)
// {
// Logger.Log($"Sequence not compatible: Not all image dimensions are divisible by {div}.", true);
// return false;
// }
bool allSmallEnough = randomSamples.All(i => (i.Height <= maxHeight));

View File

@@ -211,5 +211,16 @@ namespace Flowframes.MiscUtils
string t = showTildeForApprox && !isPrecise ? "~" : "";
return $"{f} ({t}{decimalStr})";
}
public static string GetCallStack(int maxLevels = 10)
{
var trace = new System.Diagnostics.StackTrace().GetFrames()
.Skip(1) // Skip the current method
.Select(f => f.GetMethod().Name)
.Take(maxLevels)
.ToList();
return string.Join(", ", trace);
}
}
}

View File

@@ -104,7 +104,12 @@ namespace Flowframes.Os
if (!Interpolate.currentSettings.ai.Piped)
InterpolationProgress.UpdateInterpProgress(interpFramesCount, InterpolationProgress.targetFrames);
string logStr = $"Done running {aiName} - Interpolation took {FormatUtils.Time(processTime.Elapsed)}. Output FPS: {InterpolationProgress.LastFps.ToString("0.0")}";
string logStr = $"Done running {aiName} - Interpolation took {FormatUtils.Time(processTime.Elapsed)}.";
if(InterpolationProgress.LastFps > 0.0001)
{
logStr += $" Output FPS: {InterpolationProgress.LastFps.ToString("0.0")}";
}
if (Interpolate.currentlyUsingAutoEnc && AutoEncode.HasWorkToDo())
{
@@ -198,7 +203,7 @@ namespace Flowframes.Os
{
string outPath = Path.Combine(inPath.GetParentDir(), outDir);
Directory.CreateDirectory(outPath);
string uhdStr = await InterpolateUtils.UseUhd() ? "--UHD" : "";
string uhdStr = InterpolateUtils.UseUhd() ? "--UHD" : "";
string wthreads = $"--wthreads {2 * (int)interpFactor}";
string rbuffer = $"--rbuffer {Config.GetInt(Config.Key.rifeCudaBufferSize, 200)}";
//string scale = $"--scale {Config.GetFloat("rifeCudaScale", 1.0f).ToStringDot()}";
@@ -210,7 +215,7 @@ namespace Flowframes.Os
SetProgressCheck(Path.Combine(Interpolate.currentSettings.tempFolder, outDir), interpFactor);
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($"Running RIFE (CUDA){(InterpolateUtils.UseUhd() ? " (UHD Mode)" : "")}...", false);
Logger.Log("cmd.exe " + rifePy.StartInfo.Arguments, true);
if (!OsUtils.ShowHiddenCmd())
@@ -297,7 +302,7 @@ namespace Flowframes.Os
try
{
Logger.Log($"Running RIFE (NCNN){(await InterpolateUtils.UseUhd() ? " (UHD Mode)" : "")}...", false);
Logger.Log($"Running RIFE (NCNN){(InterpolateUtils.UseUhd() ? " (UHD Mode)" : "")}...", false);
await RunRifeNcnnProcess(framesPath, factor, outPath, mdl);
await NcnnUtils.DeleteNcnnDupes(outPath, factor);
@@ -321,7 +326,7 @@ namespace Flowframes.Os
int targetFrames = ((IoUtils.GetAmountOfFiles(lastInPath, false, "*.*") * factor).RoundToInt()); // TODO: Maybe won't work with fractional factors ??
string frames = mdl.Contains("v4") ? $"-n {targetFrames}" : "";
string uhdStr = await InterpolateUtils.UseUhd() ? "-u" : "";
string uhdStr = 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 " +
@@ -355,10 +360,8 @@ namespace Flowframes.Os
try
{
Size scaledSize = await InterpolateUtils.GetOutputResolution(Interpolate.currentSettings.inPath, false, false);
Logger.Log($"Running RIFE (NCNN-VS){(InterpolateUtils.UseUhd(scaledSize) ? " (UHD Mode)" : "")}...", false);
await RunRifeNcnnVsProcess(framesPath, factor, outPath, mdl, scaledSize, rt);
Logger.Log($"Running RIFE (NCNN-VS){(InterpolateUtils.UseUhd(Interpolate.currentSettings.OutputResolution) ? " (UHD Mode)" : "")}...", false);
await RunRifeNcnnVsProcess(framesPath, factor, outPath, mdl, Interpolate.currentSettings.OutputResolution, rt);
}
catch (Exception e)
{
@@ -406,7 +409,7 @@ namespace Flowframes.Os
AiStarted(rifeNcnnVs, 1000, inPath);
}
rifeNcnnVs.StartInfo.Arguments = $"{OsUtils.GetCmdArg()} cd /D {pkgDir.Wrap()} & vspipe {VapourSynthUtils.CreateScript(vsSettings).Wrap()} -c y4m - | {pipedTargetArgs}";
rifeNcnnVs.StartInfo.Arguments = $"{OsUtils.GetCmdArg()} cd /D {pkgDir.Wrap()} & vspipe {VapourSynthUtils.CreateScript(vsSettings).Wrap()} {VapourSynthUtils.GetVsPipeArgs(vsSettings)} -c y4m - | {pipedTargetArgs}";
Logger.Log("cmd.exe " + rifeNcnnVs.StartInfo.Arguments, true);
@@ -554,7 +557,7 @@ namespace Flowframes.Os
try
{
Logger.Log($"Running IFRNet (NCNN){(await InterpolateUtils.UseUhd() ? " (UHD Mode)" : "")}...", false);
Logger.Log($"Running IFRNet (NCNN){(InterpolateUtils.UseUhd() ? " (UHD Mode)" : "")}...", false);
await RunIfrnetNcnnProcess(framesPath, factor, outPath, mdl);
await NcnnUtils.DeleteNcnnDupes(outPath, factor);
@@ -576,7 +579,7 @@ namespace Flowframes.Os
SetProgressCheck(outPath, factor);
//int targetFrames = ((IoUtils.GetAmountOfFiles(lastInPath, false, "*.*") * factor).RoundToInt()); // TODO: Maybe won't work with fractional factors ??
//string frames = mdl.Contains("v4") ? $"-n {targetFrames}" : "";
string uhdStr = ""; // await InterpolateUtils.UseUhd() ? "-u" : "";
string uhdStr = ""; // InterpolateUtils.UseUhd() ? "-u" : "";
string ttaStr = ""; // Config.GetBool(Config.Key.rifeNcnnUseTta, false) ? "-x" : "";
ifrnetNcnn.StartInfo.Arguments = $"{OsUtils.GetCmdArg()} cd /D {Path.Combine(Paths.GetPkgPath(), Implementations.ifrnetNcnn.PkgDir).Wrap()} & ifrnet-ncnn-vulkan.exe " +

View File

@@ -22,21 +22,35 @@ namespace Flowframes.Os
public bool Uhd { get; set; } = false;
public float SceneDetectSensitivity { get; set; } = 0.15f;
public int GpuId { get; set; } = 0;
public int GpuThreads { get; set; } = 3;
public int GpuThreads { get; set; } = 2;
public bool Tta { get; set; } = false;
public bool Loop { get; set; } = false;
public bool MatchDuration { get; set; } = false;
public bool Dedupe { get; set; } = false;
public bool Realtime { get; set; } = false;
public bool Osd { get; set; } = true;
public int PadX { get; set; } = 0;
public int PadY { get; set; } = 0;
}
public static string CreateScript(VsSettings s)
public const string VarInputPath = "inputPath";
public const string VarTempDirPath = "tempDirPath";
public const string VarLwiPath = "cacheLwiPath";
public static string GetVsPipeArgs(VsSettings s)
{
return $"--arg {VarInputPath}={s.InterpSettings.inPath.Wrap()} --arg {VarTempDirPath}={s.InterpSettings.tempFolder.Wrap()}";
}
public static string CreateScript(VsSettings s, bool alwaysPreferFactorOverFps = true)
{
Logger.Log($"Creating RIFE VS script. Model: {s.ModelDir}, Factor: {s.Factor}, Res: {s.Res.Width}x{s.Res.Height}, UHD: {s.Uhd}, SC Sens: {s.SceneDetectSensitivity}, " +
$"GPU ID: {s.GpuId}, GPU Threads: {s.GpuThreads}, TTA: {s.Tta}, Loop: {s.Loop}, Match Duration: {s.MatchDuration}, Dedupe: {s.Dedupe}, RT: {s.Realtime}{(s.Osd ? $", OSD: {s.Osd}" : "")}", true);
string inputPath = s.InterpSettings.inPath;
s.PadX = s.InterpSettings.InterpResolution.Width - s.InterpSettings.ScaledResolution.Width;
s.PadY = s.InterpSettings.InterpResolution.Height - s.InterpSettings.ScaledResolution.Height;
int txtScale = (s.InterpSettings.ScaledResolution.Width / 1000f).RoundToInt().Clamp(1, 4);
string mdlPath = Path.Combine(Paths.GetPkgPath(), Implementations.rifeNcnnVs.PkgDir, s.ModelDir).Replace(@"\", "/").Wrap();
bool sc = s.SceneDetectSensitivity >= 0.01f;
@@ -53,14 +67,21 @@ namespace Flowframes.Os
int targetFrameCountMatchDuration = (frameCount * s.Factor).RoundToInt(); // Target frame count to match original duration (and for loops)
int targetFrameCountTrue = targetFrameCountMatchDuration - endDupeCount; // Target frame count without dupes at the end (only in-between frames added)
List<string> l = new List<string> { "import sys", "import os", "import json", "import time", "import functools", "import vapoursynth as vs", "core = vs.core", "" }; // Imports
l.Add($"inputPath = r'{inputPath}'");
List<string> imports = new List<string> { "sys", "os", "json", "time", "functools", "vapoursynth as vs" }; // Imports
var l = new List<string>() { "# Generated by Flowframes. Will be overwritten on the next run!", "" };
l.AddRange(imports.Select(i => $"import {i}"));
l.Add("core = vs.core");
l.Add($"");
l.Add($"inputPath = globals()[{VarInputPath.Wrap()}]");
l.Add($"tempDirPath = globals()[{VarTempDirPath.Wrap()}]");
l.Add($"");
bool loadFrames = s.InterpSettings.inputIsFrames;
if (loadFrames)
{
l.Add($"# Load frames");
FileInfo[] frames = IoUtils.GetFileInfosSorted(s.InterpSettings.framesFolder, false, "*.*");
string ext = frames.FirstOrDefault().Extension;
string first = Path.GetFileNameWithoutExtension(frames.FirstOrDefault().FullName);
@@ -69,29 +90,42 @@ namespace Flowframes.Os
}
else
{
l.Add("indexFilePath = f'{inputPath}.cache.lwi'");
l.Add($"if os.path.isdir(r'{s.InterpSettings.tempFolder}'):");
l.Add($" indexFilePath = r'{Path.Combine(s.InterpSettings.tempFolder, "cache.lwi")}'");
l.Add($"# Load video");
l.Add("indexFilePath = os.path.join(tempDirPath, 'index.lwi') if os.path.isdir(tempDirPath) else f'{inputPath}.index.lwi'");
l.Add($"clip = core.lsmas.LWLibavSource(inputPath, cachefile=indexFilePath)"); // Load video with lsmash
l.Add(Debugger.IsAttached ? "clip = core.text.FrameNum(clip, alignment=7)" : "");
l.Add(GetDedupeLines(s));
}
if (trim)
l.Add($"clip = clip.std.Trim({srcTrimStartFrame}, {srcTrimEndFrame}) # Trim");
l.Add($"");
l.Add($"srcFrames = len(clip)");
l.Add(Debugger.IsAttached ? $"clip = core.text.FrameNum(clip, alignment=7, scale={txtScale}) # Input frame counter" : "");
l.Add(GetDedupeLines(s));
l.Add($"");
if (trim)
{
l.Add($"# Trim");
l.Add($"clip = clip.std.Trim({srcTrimStartFrame}, {srcTrimEndFrame}) # Trim");
l.Add($"");
}
if (s.Loop && !s.InterpSettings.inputIsFrames)
{
l.Add($"# Loop: Copy first frame to end of clip");
l.Add($"firstFrame = clip[0]"); // Grab first frame
l.Add($"clip = clip + firstFrame"); // Add to end (for seamless loop interpolation)
l.Add($"");
}
l.Add($"firstFrameProps = clip.get_frame(0).props");
l.Add(GetScaleLines(s, loadFrames));
l.Add($"");
if (sc)
l.Add($"clip = core.misc.SCDetect(clip=clip, threshold={s.SceneDetectSensitivity.ToStringDot()})"); // Scene detection
{
l.Add($"# Scene detection");
l.Add($"clip = core.misc.SCDetect(clip=clip, threshold={s.SceneDetectSensitivity.ToString("0.0#####")})"); // Scene detection
l.Add($"");
}
Fraction outFps = s.InterpSettings.inFps * s.Factor;
@@ -100,16 +134,21 @@ namespace Flowframes.Os
outFps = Interpolate.currentMediaFile.VideoStreams.First().FpsInfo.SpecifiedFps * s.Factor;
}
Fraction factorFrac = new Fraction(s.Factor);
string interpStr = Interpolate.currentMediaFile.IsVfr ? $"factor_num={factorFrac.Numerator}, factor_den={factorFrac.Denominator}" : $"fps_num={outFps.Numerator}, fps_den={outFps.Denominator}";
l.Add($"preInterpFrames = len(clip)");
Fraction factor = new Fraction(s.Factor);
string interpStr = alwaysPreferFactorOverFps || Interpolate.currentMediaFile.IsVfr ? $"factor_num={factor.Numerator}, factor_den={factor.Denominator}" : $"fps_num={outFps.Numerator}, fps_den={outFps.Denominator}";
l.Add($"clip = core.rife.RIFE(clip, {interpStr}, model_path={mdlPath}, gpu_id={s.GpuId}, gpu_thread={s.GpuThreads}, tta={s.Tta}, uhd={s.Uhd}, sc={sc})"); // Interpolate
if (s.Dedupe && !s.Realtime)
{
l.Add(GetRedupeLines(s));
l.Add($"");
}
Console.WriteLine($"In Format: {Interpolate.currentMediaFile.Format.Upper()}");
bool use470bg = loadFrames && !new[] { "GIF", "EXR" }.Contains(Interpolate.currentMediaFile.Format.Upper());
l.Add($"clip = vs.core.resize.Bicubic(clip, format=vs.YUV444P16, matrix_s={(use470bg ? "'470bg'" : "cMatrix")})"); // Convert RGB to YUV. Always use 470bg if input is YUV frames
l.Add($"clip = core.std.Crop(clip, right={s.PadX}, bottom={s.PadY})");
if (!s.Dedupe) // Ignore trimming code when using deduping that that already handles trimming in the frame order file
{
@@ -130,13 +169,14 @@ namespace Flowframes.Os
if (s.Realtime && s.Osd)
l.Add(GetOsdLines());
l.Add(Debugger.IsAttached ? "clip = core.text.Text(clip, str(len(clip)), alignment=4)" : "");
l.Add(Debugger.IsAttached ? "clip = core.text.FrameNum(clip, alignment=1)" : "");
l.Add(Debugger.IsAttached ? $"clip = core.text.FrameNum(clip, alignment=9, scale={txtScale}) # Output frame counter" : "");
l.Add(Debugger.IsAttached ? $"clip = core.text.Text(clip, f\"Frames: {{srcFrames}}/{{preInterpFrames}} -> {{len(clip)}} [{factor.GetString()}x]\", alignment=8, scale={txtScale})" : "");
l.Add(Debugger.IsAttached ? $"clip = core.text.Text(clip, f\"targetMatchDuration: {targetFrameCountMatchDuration} - targetTrue: {targetFrameCountTrue} - endDupeCount: {endDupeCount}\", alignment=2, scale={txtScale})" : "");
l.Add($"clip.set_output()"); // Set output
l.Add("");
l.Add($"if os.path.isfile(r'{inputPath}.cache.lwi'):");
l.Add($" os.remove(r'{inputPath}.cache.lwi')");
l.Add("if os.path.isfile(r'{inputPath}.index.lwi'):");
l.Add(" os.remove(r'{inputPath}.index.lwi')");
string pkgPath = Path.Combine(Paths.GetPkgPath(), Implementations.rifeNcnnVs.PkgDir);
string vpyPath = Path.Combine(pkgPath, "rife.vpy");
@@ -150,16 +190,19 @@ namespace Flowframes.Os
{
InterpSettings interp = settings.InterpSettings;
bool resize = !interp.ScaledResolution.IsEmpty && interp.ScaledResolution != interp.InputResolution;
string s = "";
s += $"\n";
s += $"cMatrix = '709'\n";
s += $"\n";
s += $"# Scaled Res: {interp.ScaledResolution.Width}x{interp.ScaledResolution.Height} - Interpolation Res: {interp.InterpResolution.Width}x{interp.InterpResolution.Height} - Output Res: {interp.OutputResolution.Width}x{interp.OutputResolution.Height}\n";
s += $"\n";
if (!loadFrames)
{
s += "try:\n";
s += " m = clip.get_frame(0).props._Matrix\n";
s += " m = firstFrameProps._Matrix\n";
s += " if m == 0: cMatrix = 'rgb'\n";
s += " elif m == 4: cMatrix = 'fcc'\n";
s += " elif m == 5: cMatrix = '470bg'\n";
@@ -174,12 +217,7 @@ namespace Flowframes.Os
s += $"except:\n";
s += $" cMatrix = '709'\n";
s += $"\n";
s += $"colRange = 'limited'\n";
s += $"\n";
s += $"try:\n";
s += $" if clip.get_frame(0).props._ColorRange == 0: colRange = 'full'\n";
s += $"except:\n";
s += $" colRange = 'limited'\n";
s += $"colRange = 'full' if firstFrameProps.get('_ColorRange') == 0 else 'limited'\n";
s += $"\n";
}
@@ -190,6 +228,13 @@ namespace Flowframes.Os
s += $" clip = core.resize.Bicubic(clip=clip, format=vs.RGBS{(resize ? $", width={interp.ScaledResolution.Width}, height={interp.ScaledResolution.Height}" : "")})\n";
s += $"\n";
if (settings.PadX > 0 || settings.PadY > 0)
{
s += "# Padding to achieve a compatible resolution\n";
s += $"clip = core.std.AddBorders(clip, right={settings.PadX}, bottom={settings.PadY})\n";
s += $"\n";
}
return s;
}
@@ -211,8 +256,7 @@ namespace Flowframes.Os
s += " reorderedClip = reorderedClip + clip[i]\n";
s += "\n";
s += "clip = reorderedClip.std.Trim(1, reorderedClip.num_frames - 1) # Dedupe trim\n";
s += Debugger.IsAttached ? "clip = core.text.FrameNum(clip, alignment=4)\n" : "";
s += "\n";
//s += Debugger.IsAttached ? "clip = core.text.FrameNum(clip, alignment=9)\n" : "";
return s;
}
@@ -231,8 +275,7 @@ namespace Flowframes.Os
s += " reorderedClip = reorderedClip + clip[i]\n";
s += "\n";
s += "clip = reorderedClip.std.Trim(1, reorderedClip.num_frames - 1) # Redupe trim\n";
s += Debugger.IsAttached ? "clip = core.text.FrameNum(clip, alignment=1)\n" : "";
s += "\n";
//s += Debugger.IsAttached ? "clip = core.text.FrameNum(clip, alignment=1)\n" : "";
return s;
}
@@ -270,7 +313,6 @@ namespace Flowframes.Os
s += $" return clip \n";
s += $" \n";
s += $"clip = core.std.FrameEval(clip, functools.partial(onFrame, clip=clip)) \n";
s += $" \n";
return s;
}