mirror of
https://github.com/n00mkrad/flowframes.git
synced 2025-12-15 16:07:45 +01:00
mpdecimate improvements, fix custom out path, lwi caching, alpha tests (wip)
This commit is contained in:
@@ -35,7 +35,7 @@
|
||||
|
||||
public class Interpolation
|
||||
{
|
||||
public enum MpDecimateSens { Normal, High, VeryHigh, Extreme }
|
||||
public enum MpDecimateSens { Low, Normal, High, VeryHigh, Extreme }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,7 +105,7 @@ namespace Flowframes
|
||||
return;
|
||||
|
||||
inPath = inputPath;
|
||||
outPath = (Config.GetInt("outFolderLoc") == 0) ? inputPath.GetParentDir() : Config.Get("custOutDir").Trim();
|
||||
// outPath = (Config.GetInt("outFolderLoc") == 0) ? inputPath.GetParentDir() : Config.Get("custOutDir").Trim();
|
||||
tempFolder = InterpolateUtils.GetTempFolderLoc(inPath, outPath);
|
||||
framesFolder = Path.Combine(tempFolder, Paths.framesDir);
|
||||
interpFolder = Path.Combine(tempFolder, Paths.interpDir);
|
||||
|
||||
@@ -86,7 +86,14 @@ namespace Flowframes.IO
|
||||
return path;
|
||||
}
|
||||
|
||||
public static string GetSessionDataPath()
|
||||
public static string GetCachePath()
|
||||
{
|
||||
string path = Path.Combine(GetDataPath(), "cache");
|
||||
Directory.CreateDirectory(path);
|
||||
return path;
|
||||
}
|
||||
|
||||
public static string GetSessionDataPath()
|
||||
{
|
||||
string path = Path.Combine(GetSessionsPath(), sessionTimestamp);
|
||||
Directory.CreateDirectory(path);
|
||||
|
||||
16
CodeLegacy/Data/PseudoHash.cs
Normal file
16
CodeLegacy/Data/PseudoHash.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Flowframes.Data
|
||||
{
|
||||
internal class PseudoHash
|
||||
{
|
||||
public static string GetHash(string path, bool b64 = true)
|
||||
{
|
||||
var file = new FileInfo(path);
|
||||
string hash = $"{file.Name}{file.Length}{file.LastWriteTime.ToString("yyyyMMddHHmmss")}";
|
||||
return b64 ? Convert.ToBase64String(Encoding.UTF8.GetBytes(hash)).TrimEnd('=') : hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -382,6 +382,7 @@
|
||||
<Compile Include="Data\FpsInfo.cs" />
|
||||
<Compile Include="Data\MediaFile.cs" />
|
||||
<Compile Include="Data\ModelCollection.cs" />
|
||||
<Compile Include="Data\PseudoHash.cs" />
|
||||
<Compile Include="Data\Servers.cs" />
|
||||
<Compile Include="Data\Streams\AttachmentStream.cs" />
|
||||
<Compile Include="Data\Streams\AudioStream.cs" />
|
||||
|
||||
@@ -115,8 +115,8 @@ namespace Flowframes.Forms
|
||||
ConfigParser.SaveGuiElement(onlyShowRelevantSettings);
|
||||
ConfigParser.SaveComboxIndex(processingMode);
|
||||
ConfigParser.SaveGuiElement(maxVidHeight, ConfigParser.StringMode.Int);
|
||||
ConfigParser.SaveComboxIndex(tempFolderLoc);
|
||||
ConfigParser.SaveComboxIndex(outFolderLoc);
|
||||
ConfigParser.SaveComboxIndex(tempFolderLoc); ConfigParser.SaveGuiElement(tempDirCustom);
|
||||
ConfigParser.SaveComboxIndex(outFolderLoc); ConfigParser.SaveGuiElement(custOutDir);
|
||||
ConfigParser.SaveGuiElement(keepTempFolder);
|
||||
ConfigParser.SaveGuiElement(exportNamePattern);
|
||||
ConfigParser.SaveGuiElement(exportNamePatternLoop);
|
||||
|
||||
@@ -275,6 +275,7 @@ namespace Flowframes.IO
|
||||
// Debug / Other / Experimental
|
||||
if (key == Key.ffEncPreset) return WriteDefault(key, "fast");
|
||||
if (key == Key.sbsRunPreviousStepIfNeeded) return WriteDefault(key, true);
|
||||
if (keyStr == "mpdecimateMode") return WriteDefault(keyStr, "1");
|
||||
if (type == Type.Int || type == Type.Float) return WriteDefault(key, "0"); // Write default int/float (0)
|
||||
if (type == Type.Bool) return WriteDefault(key, false); // Write default bool (False)
|
||||
return WriteDefault(key, "");
|
||||
|
||||
@@ -309,9 +309,9 @@ namespace Flowframes.Magick
|
||||
Logger.Log($"Dedupe: Factor is 1, will not redupe; overriding factor to {frameCount}/{inputFrames.Count} = {Interpolate.currentSettings.interpFactor.ToString("0.######")}", true);
|
||||
}
|
||||
|
||||
if (keepPercentage > 95f)
|
||||
if (keepPercentage > 85f)
|
||||
{
|
||||
Logger.Log("Deduplication: Less than 5% duplicate frames detected; disabling for this video.");
|
||||
Logger.Log("Deduplication: Less than 15% duplicate frames detected; disabling for this video.");
|
||||
Interpolate.currentSettings.dedupe = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,16 +72,32 @@ namespace Flowframes.Main
|
||||
}
|
||||
|
||||
private const bool _useNutPipe = true;
|
||||
public enum AlphaMode { None, AlphaOut, AlphaIn }
|
||||
|
||||
public static async Task<string> GetPipedFfmpegCmd(bool ffplay = false)
|
||||
public static async Task<string> GetPipedFfmpegCmd(bool ffplay = false, AlphaMode alpha = AlphaMode.None)
|
||||
{
|
||||
InterpSettings s = I.currentSettings;
|
||||
string encArgs = FfmpegUtils.GetEncArgs(s.outSettings, (s.OutputResolution.IsEmpty ? s.InputResolution : s.OutputResolution), s.outFps.Float, true).FirstOrDefault();
|
||||
var alphaOutSettings = new OutputSettings { Encoder = Enums.Encoding.Encoder.X264, PixelFormat = Enums.Encoding.PixelFormat.Yuv444P, CustomQuality = "20" };
|
||||
var outSettings = alpha == AlphaMode.AlphaOut ? alphaOutSettings : s.outSettings;
|
||||
var outRes = s.OutputResolution.IsEmpty ? s.InputResolution : s.OutputResolution;
|
||||
string encArgs = FfmpegUtils.GetEncArgs(outSettings, outRes, s.outFps.Float, true).First();
|
||||
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);
|
||||
string extraArgsIn = await FfmpegEncode.GetFfmpegExportArgsIn(I.currentMediaFile.IsVfr ? s.outFpsResampled : s.outFps, s.outItsScale, extraData.Rotation);
|
||||
string extraArgsOut = await FfmpegEncode.GetFfmpegExportArgsOut(fpsLimit ? MaxFpsFrac : new Fraction(), extraData, s.outSettings);
|
||||
string extraArgsOut;
|
||||
string alphaPassFile = Path.Combine(s.tempFolder, "alpha.mkv");
|
||||
Fraction fps = fpsLimit ? MaxFpsFrac : new Fraction();
|
||||
|
||||
if (alpha == AlphaMode.AlphaOut)
|
||||
{
|
||||
extraArgsOut = await FfmpegEncode.GetFfmpegExportArgsOut(fps, new VidExtraData(), alphaOutSettings);
|
||||
return $"{extraArgsIn} -i - {extraArgsOut} {encArgs} {alphaPassFile.Wrap()}";
|
||||
}
|
||||
else
|
||||
{
|
||||
extraArgsOut = await FfmpegEncode.GetFfmpegExportArgsOut(fps, extraData, s.outSettings, alphaPassFile: alpha == AlphaMode.AlphaIn ? alphaPassFile : "");
|
||||
}
|
||||
|
||||
// For EXR, force bt709 input flags. Not sure if this really does anything
|
||||
if (s.outSettings.Encoder == Enums.Encoding.Encoder.Exr)
|
||||
@@ -95,7 +111,7 @@ namespace Flowframes.Main
|
||||
string format = _useNutPipe ? "nut" : "yuv4mpegpipe";
|
||||
|
||||
return
|
||||
$"{extraArgsIn} -i pipe: {encArgs} {extraArgsOut} -f {format} - | ffplay - " +
|
||||
$"{extraArgsIn} -i - {encArgs} {""} -f {format} - | ffplay - " +
|
||||
$"-autoexit -seek_interval {VapourSynthUtils.GetSeekSeconds(Program.mainForm.currInDuration)} " +
|
||||
$"-window_title \"Flowframes Realtime Interpolation ({s.inFps.GetString()} FPS x{s.interpFactor} = {s.outFps.GetString()} FPS) ({s.model.Name})\" ";
|
||||
}
|
||||
@@ -111,7 +127,13 @@ namespace Flowframes.Main
|
||||
s.FullOutPath += $"/%{Padding.interpFrames}d.{s.outSettings.Encoder.GetInfo().OverideExtension}";
|
||||
}
|
||||
|
||||
return $"{extraArgsIn} -i pipe: {extraArgsOut} {encArgs} {s.FullOutPath.Wrap()}";
|
||||
// Merge alpha
|
||||
if (alpha == AlphaMode.AlphaIn)
|
||||
{
|
||||
return $"{extraArgsIn} -i - {extraArgsOut} {encArgs} {s.FullOutPath.Wrap()}";
|
||||
}
|
||||
|
||||
return $"{extraArgsIn} -i - {extraArgsOut} {encArgs} {s.FullOutPath.Wrap()}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,7 +422,7 @@ namespace Flowframes.Main
|
||||
return;
|
||||
}
|
||||
|
||||
if(I.currentMediaFile.IsVfr && I.currentMediaFile.OutputFrameIndexes != null && I.currentMediaFile.OutputFrameIndexes.Count > 0)
|
||||
if (I.currentMediaFile.IsVfr && I.currentMediaFile.OutputFrameIndexes != null && I.currentMediaFile.OutputFrameIndexes.Count > 0)
|
||||
{
|
||||
Logger.Log($"{nameof(MuxTimestamps)}: CFR conversion due to FPS limit was applied (picked {I.currentMediaFile.OutputFrameIndexes.Count} frames for {I.currentSettings.outFpsResampled} FPS); won't mux timestamps.", hidden: true);
|
||||
return;
|
||||
|
||||
@@ -16,20 +16,30 @@ namespace Flowframes
|
||||
public static string hdrFilter = @"-vf zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p";
|
||||
public static string pngCompr = "-compression_level 3";
|
||||
|
||||
public static Dictionary<Enums.Interpolation.MpDecimateSens, int> MpDecSensLookup = new Dictionary<Enums.Interpolation.MpDecimateSens, int>
|
||||
/// <summary> Lookup table for mpdecimate sensitivity preset values (lo/hi/frac). </summary>
|
||||
public static Dictionary<Enums.Interpolation.MpDecimateSens, (int, int, float)> MpDecSensLookup = new Dictionary<Enums.Interpolation.MpDecimateSens,(int, int, float)>
|
||||
{
|
||||
{ Enums.Interpolation.MpDecimateSens.Normal, 4 },
|
||||
{ Enums.Interpolation.MpDecimateSens.High, 20 },
|
||||
{ Enums.Interpolation.MpDecimateSens.VeryHigh, 32 },
|
||||
{ Enums.Interpolation.MpDecimateSens.Extreme, 40 }
|
||||
{ Enums.Interpolation.MpDecimateSens.Low, (3, 10, 0.33f) },
|
||||
{ Enums.Interpolation.MpDecimateSens.Normal, (4, 12, 0.50f) },
|
||||
{ Enums.Interpolation.MpDecimateSens.High, (20, 18, 0.65f) },
|
||||
{ Enums.Interpolation.MpDecimateSens.VeryHigh, (32, 24, 0.75f) },
|
||||
{ Enums.Interpolation.MpDecimateSens.Extreme, (40, 30, 0.90f) },
|
||||
};
|
||||
|
||||
public static string GetMpdecimate(bool wrap = true)
|
||||
/// <summary>
|
||||
/// Construct mpdecimate filter with prefiltering: <paramref name="scaleSize"/> limits resolution, <paramref name="cropSize"/> center-crops the frame using a factor,
|
||||
/// <paramref name="lumaOnly"/> only processes luma channel.<br/><paramref name="wrap"/> wraps the filter in double quotes.
|
||||
/// </summary>
|
||||
public static string GetMpdecimate(bool wrap = true, int scaleSize = 640, float cropSize = 0.8f, bool lumaOnly = true)
|
||||
{
|
||||
int mpdValIndex = Config.GetInt(Config.Key.mpdecimateMode);
|
||||
int mpdVal = MpDecSensLookup[(Enums.Interpolation.MpDecimateSens)mpdValIndex];
|
||||
string mpd = $"mpdecimate=hi=64*12:lo=64*{mpdVal}:frac=1.0";
|
||||
return wrap ? mpd.Wrap() : mpd;
|
||||
(int lo, int hi, float frac) = MpDecSensLookup[(Enums.Interpolation.MpDecimateSens)mpdValIndex];
|
||||
string format = lumaOnly ? $"format=yuv420p,extractplanes=y" : "";
|
||||
string scale = scaleSize > 64 ? $"scale='min({scaleSize},iw)':min'({scaleSize},ih)':force_original_aspect_ratio=decrease:force_divisible_by=2" : "";
|
||||
string crop = cropSize > 0.1f && cropSize < 0.99f ? $"crop=iw*{cropSize}:ih*{cropSize}" : "";
|
||||
string mpdec = $"mpdecimate=hi=64*{hi}:lo=64*{lo}:frac={frac.ToString("0.0#")}";
|
||||
string filters = string.Join(",", new string[] { format, crop, scale, mpdec }.Where(s => s.IsNotEmpty())); // Only take non-empty filter strings
|
||||
return wrap ? filters.Wrap() : filters;
|
||||
}
|
||||
|
||||
public enum ModuloMode { Disabled, ForInterpolation, ForEncoding }
|
||||
|
||||
@@ -49,12 +49,12 @@ namespace Flowframes.Media
|
||||
var args = new List<string>();
|
||||
fps = fps / new Fraction(itsScale);
|
||||
|
||||
if(fps > 0.1f)
|
||||
if (fps > 0.1f)
|
||||
{
|
||||
args.Add($"-r {fps}");
|
||||
}
|
||||
|
||||
if(rotation != 0)
|
||||
|
||||
if (rotation != 0)
|
||||
{
|
||||
args.Add($"-display_rotation {rotation}");
|
||||
}
|
||||
@@ -62,24 +62,13 @@ namespace Flowframes.Media
|
||||
return string.Join(" ", args);
|
||||
}
|
||||
|
||||
public static async Task<string> GetFfmpegExportArgsOut(Fraction resampleFps, VidExtraData extraData, OutputSettings settings, bool isChunk = false)
|
||||
public static async Task<string> GetFfmpegExportArgsOut(Fraction resampleFps, VidExtraData extraData, OutputSettings settings, bool isChunk = false, string alphaPassFile = "")
|
||||
{
|
||||
var beforeArgs = new List<string>();
|
||||
var filters = new List<string>();
|
||||
var extraArgs = new List<string> { Config.Get(Config.Key.ffEncArgs) };
|
||||
var mf = Interpolate.currentMediaFile;
|
||||
|
||||
if (resampleFps.Float >= 0.1f)
|
||||
{
|
||||
if (Interpolate.currentMediaFile.IsVfr && !Interpolate.currentSettings.dedupe)
|
||||
{
|
||||
Logger.Log($"Won't add fps filter as VFR handling already outputs at desired frame rate ({resampleFps.Float} FPS)", true);
|
||||
}
|
||||
else
|
||||
{
|
||||
filters.Add($"fps={resampleFps}");
|
||||
}
|
||||
}
|
||||
int inputs = 1;
|
||||
|
||||
if (Config.GetBool(Config.Key.keepColorSpace) && extraData.HasAllColorValues())
|
||||
{
|
||||
@@ -93,24 +82,42 @@ namespace Flowframes.Media
|
||||
if (!isChunk && settings.Format == Enums.Output.Format.Mp4 || settings.Format == Enums.Output.Format.Mov)
|
||||
extraArgs.Add($"-movflags +faststart");
|
||||
|
||||
if (resampleFps.Float >= 0.1f)
|
||||
{
|
||||
if (Interpolate.currentMediaFile.IsVfr && !Interpolate.currentSettings.dedupe)
|
||||
{
|
||||
Logger.Log($"Won't add fps filter as VFR handling already outputs at desired frame rate ({resampleFps.Float} FPS)", true);
|
||||
}
|
||||
else
|
||||
{
|
||||
filters.Add($"fps={resampleFps}");
|
||||
}
|
||||
}
|
||||
|
||||
if (alphaPassFile.IsNotEmpty())
|
||||
{
|
||||
beforeArgs.Add($"-i {alphaPassFile.Wrap()}");
|
||||
filters.Add($"[{inputs}:v]alphamerge");
|
||||
inputs++;
|
||||
}
|
||||
|
||||
if (settings.Format == Enums.Output.Format.Gif)
|
||||
{
|
||||
string dither = Config.Get(Config.Key.gifDitherType).Split(' ').First();
|
||||
string palettePath = Path.Combine(Paths.GetSessionDataPath(), "palette.png");
|
||||
string paletteFilter = $"[1:v]paletteuse=dither={dither}";
|
||||
|
||||
int colors = OutputUtils.GetGifColors(ParseUtils.GetEnum<Enums.Encoding.Quality.GifColors>(settings.Quality, true, Strings.VideoQuality));
|
||||
string palettePath = Path.Combine(Paths.GetSessionDataPath(), "palette.png");
|
||||
await FfmpegExtract.GeneratePalette(mf.ImportPath, palettePath, colors);
|
||||
|
||||
if (File.Exists(palettePath))
|
||||
{
|
||||
beforeArgs.Add($"-i {palettePath.Wrap()}");
|
||||
filters.Add(paletteFilter);
|
||||
inputs++;
|
||||
filters.Add($"[{inputs - 1}:v]paletteuse=dither={dither}");
|
||||
}
|
||||
}
|
||||
else if (settings.Encoder == Enums.Encoding.Encoder.Exr)
|
||||
{
|
||||
if(mf.Format.Upper() != "EXR")
|
||||
if (mf.Format.Upper() != "EXR")
|
||||
filters.Add($"zscale=transfer=linear,format={settings.PixelFormat.ToString().Lower()}".Wrap());
|
||||
}
|
||||
|
||||
|
||||
@@ -71,13 +71,11 @@ namespace Flowframes.MiscUtils
|
||||
}
|
||||
|
||||
// Otherwise return "numerator/denominator"
|
||||
Logger.Log($"Approximated fraction for {value}: {bestNum}/{bestDen} (={((float)bestNum / bestDen).ToString("0.0#######")})", true);
|
||||
// Logger.Log($"Approximated fraction for {value}: {bestNum}/{bestDen} (={((float)bestNum / bestDen).ToString("0.0#######")})", true);
|
||||
return (bestNum, bestDen);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the greatest common divisor (Euclid's algorithm).
|
||||
/// </summary>
|
||||
/// <summary> Computes the greatest common divisor (Euclid's algorithm). </summary>
|
||||
private static int GCD(int a, int b)
|
||||
{
|
||||
a = Math.Abs(a);
|
||||
|
||||
@@ -375,7 +375,6 @@ namespace Flowframes.Os
|
||||
IoUtils.CreateDir(outPath);
|
||||
Process rifeNcnnVs = OsUtils.NewProcess(!OsUtils.ShowHiddenCmd());
|
||||
string avDir = Path.Combine(Paths.GetPkgPath(), Paths.audioVideoDir);
|
||||
string pipedTargetArgs = $"{Path.Combine(avDir, "ffmpeg").Wrap()} -loglevel warning -stats -y {await Export.GetPipedFfmpegCmd(rt)}";
|
||||
string pkgDir = Path.Combine(Paths.GetPkgPath(), Implementations.rifeNcnnVs.PkgDir);
|
||||
int gpuId = NcnnGpuIds.Split(',')[0].GetInt();
|
||||
|
||||
@@ -408,26 +407,26 @@ namespace Flowframes.Os
|
||||
AiStarted(rifeNcnnVs, 1000, inPath);
|
||||
}
|
||||
|
||||
string scriptPath = Path.Combine(Paths.GetPkgPath(), Implementations.rifeNcnnVs.PkgDir, "rife.py");
|
||||
string vsPipeArgs = $"{scriptPath} {VapourSynthUtils.GetVsPipeArgs(vsSettings)} -c y4m -";
|
||||
rifeNcnnVs.StartInfo.Arguments = $"{OsUtils.GetCmdArg()} cd /D {pkgDir.Wrap()} & vspipe {vsPipeArgs} | {pipedTargetArgs}";
|
||||
IoUtils.TryDeleteIfExists(Path.Combine(Interpolate.currentSettings.tempFolder, "alpha.mkv"));
|
||||
string vspipe = $"vspipe rife.py {VapourSynthUtils.GetVsPipeArgs(vsSettings)}";
|
||||
string ffmpeg = $"{Path.Combine(avDir, "ffmpeg").Wrap()} -loglevel warning -stats -y";
|
||||
string baseArgs = $"{OsUtils.GetCmdArg()} cd /D {pkgDir.Wrap()}";
|
||||
|
||||
if(vsSettings.Alpha)
|
||||
{
|
||||
rifeNcnnVs.StartInfo.Arguments = $"{baseArgs} && {vspipe} --arg alpha=\"True\" -c y4m - | {ffmpeg} {await Export.GetPipedFfmpegCmd(alpha: Export.AlphaMode.AlphaOut)} && {vspipe} -c y4m - | {ffmpeg} {await Export.GetPipedFfmpegCmd(alpha: Export.AlphaMode.AlphaIn)}";
|
||||
}
|
||||
else
|
||||
{
|
||||
rifeNcnnVs.StartInfo.Arguments = $"{baseArgs} && {vspipe} -c y4m - | {ffmpeg} {await Export.GetPipedFfmpegCmd(rt)}";
|
||||
}
|
||||
|
||||
Logger.Log($"cmd.exe {rifeNcnnVs.StartInfo.Arguments}", true);
|
||||
|
||||
if (!OsUtils.ShowHiddenCmd())
|
||||
{
|
||||
rifeNcnnVs.OutputDataReceived += (sender, outLine) => { LogOutput("[O] " + outLine.Data, Implementations.rifeNcnnVs); };
|
||||
rifeNcnnVs.ErrorDataReceived += (sender, outLine) => { LogOutput("[E] " + outLine.Data, Implementations.rifeNcnnVs, true); };
|
||||
}
|
||||
|
||||
rifeNcnnVs.OutputDataReceived += (sender, outLine) => { LogOutput("[O] " + outLine.Data, Implementations.rifeNcnnVs); };
|
||||
rifeNcnnVs.ErrorDataReceived += (sender, outLine) => { LogOutput("[E] " + outLine.Data, Implementations.rifeNcnnVs, true); };
|
||||
rifeNcnnVs.Start();
|
||||
|
||||
if (!OsUtils.ShowHiddenCmd())
|
||||
{
|
||||
rifeNcnnVs.BeginOutputReadLine();
|
||||
rifeNcnnVs.BeginErrorReadLine();
|
||||
}
|
||||
|
||||
rifeNcnnVs.BeginOutputReadLine();
|
||||
rifeNcnnVs.BeginErrorReadLine();
|
||||
while (!rifeNcnnVs.HasExited) await Task.Delay(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace Flowframes.Os
|
||||
public InterpSettings InterpSettings { get; set; }
|
||||
public string ModelDir { get; set; } = "";
|
||||
public float Factor { get; set; } = 2.0f;
|
||||
public bool Alpha { get; set; } = false;
|
||||
public Size Res { get; set; } = new Size();
|
||||
public bool Uhd { get; set; } = false;
|
||||
public float SceneDetectSensitivity { get; set; } = 0.15f;
|
||||
@@ -37,17 +38,17 @@ namespace Flowframes.Os
|
||||
{
|
||||
Logger.Log($"Preparing RIFE VS args. 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);
|
||||
bool debug = Program.Debug && !(System.Windows.Input.Keyboard.Modifiers == System.Windows.Input.ModifierKeys.Shift);
|
||||
|
||||
var args = new List<(string, object)>()
|
||||
{
|
||||
("input", s.InterpSettings.inPath), // Input path
|
||||
("tmpDir", s.InterpSettings.tempFolder), // Temp dir path
|
||||
("cache", Path.Combine(Paths.GetCachePath(), PseudoHash.GetHash(s.InterpSettings.inPath) + ".lwi")), // File PseudoHash to allow caching
|
||||
("inFps", s.InterpSettings.inFps), // Input FPS
|
||||
("outFps", !s.InterpSettings.inputIsFrames ? Interpolate.currentMediaFile.VideoStreams.First().FpsInfo.SpecifiedFps * s.Factor : s.InterpSettings.inFps * s.Factor), // Output FPS
|
||||
("outFpsRes", s.InterpSettings.outFpsResampled),
|
||||
("resIn", s.InterpSettings.InputResolution.ToStringShort()),
|
||||
("resSc", s.InterpSettings.ScaledResolution.ToStringShort()),
|
||||
("resOut", s.InterpSettings.OutputResolution.ToStringShort()),
|
||||
("pad", $"{s.InterpSettings.InterpResolution.Width - s.InterpSettings.ScaledResolution.Width}x{s.InterpSettings.InterpResolution.Height - s.InterpSettings.ScaledResolution.Height}"), // Padding
|
||||
("frames", s.InterpSettings.inputIsFrames), // Input is frames?
|
||||
("dedupe", s.InterpSettings.dedupe), // Dedupe?
|
||||
@@ -56,16 +57,15 @@ namespace Flowframes.Os
|
||||
("sc", s.SceneDetectSensitivity), // Scene change detection sensitivity
|
||||
("loop", s.Loop), // Loop?
|
||||
("factor", new Fraction(s.Factor)),
|
||||
("mdlPath", Path.Combine(Paths.GetPkgPath(), Implementations.rifeNcnnVs.PkgDir, s.ModelDir).Replace(@"\", "/")), // Model path
|
||||
("gpuThreads", s.GpuThreads), // GPU threads
|
||||
("mdl", s.ModelDir), // Path.Combine(Paths.GetPkgPath(), Implementations.rifeNcnnVs.PkgDir, s.ModelDir).Replace(@"\", "/")), // Model path
|
||||
("gpuThrds", s.GpuThreads), // GPU threads
|
||||
("uhd", s.Uhd), // UHD?
|
||||
("tta", s.Tta), // TTA?
|
||||
("gpu", s.GpuId), // GPU ID
|
||||
("rt", s.Realtime), // Realtime?
|
||||
("osd", s.Osd), // OSD?
|
||||
("debugFrNums", Program.Debug), // Show debug overlay with frame nums?
|
||||
("debugVars", Program.Debug), // Show debug overlay with variables?
|
||||
("txtScale", (s.InterpSettings.ScaledResolution.Width / 1000f).RoundToInt().Clamp(1, 4)), // Text scale
|
||||
("osd", debug), // OSD?
|
||||
("debugFrNums", debug), // Show debug overlay with frame nums?
|
||||
("debugVars", debug), // Show debug overlay with variables?
|
||||
};
|
||||
|
||||
long frameCount = Interpolate.currentMediaFile.FrameCount;
|
||||
@@ -100,6 +100,7 @@ namespace Flowframes.Os
|
||||
args.Add(("cMatrix", use470bg ? "470bg" : ""));
|
||||
args.Add(("targetMatch", targetFrameCountMatchDuration));
|
||||
|
||||
args = args.Where(a => a.Item2.ToString() != "False" && a.Item2.ToString() != "").ToList();
|
||||
return string.Join(" ", args.Select(a => $"--arg {a.Item1}={a.Item2.ToString().Wrap()}"));
|
||||
}
|
||||
|
||||
|
||||
@@ -141,6 +141,14 @@ namespace Flowframes
|
||||
{
|
||||
IoUtils.TryDeleteIfExists(installerTempDir);
|
||||
}
|
||||
|
||||
foreach (var cacheFile in IoUtils.GetFileInfosSorted(Paths.GetCachePath(), true))
|
||||
{
|
||||
if ((DateTime.Now - cacheFile.LastWriteTime).TotalDays > 3d)
|
||||
{
|
||||
IoUtils.TryDeleteIfExists(cacheFile.FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -10,6 +10,7 @@ core = vs.core
|
||||
# Vars from command line (via VSPipe)
|
||||
input_path = globals()["input"]
|
||||
temp_dir_path = globals()["tmpDir"]
|
||||
cache_file = globals()["cache"]
|
||||
fps_in = globals()["inFps"]
|
||||
fps_out = globals()["outFps"]
|
||||
fps_out_resampled = globals()["outFpsRes"]
|
||||
@@ -30,6 +31,12 @@ show_vars = globals()["debugVars"] == 'True'
|
||||
txt_scale = globals()["txtScale"]
|
||||
trim = globals()["trim"]
|
||||
override_c_matrix = globals()["cMatrix"]
|
||||
alpha = globals()["alpha"] == 'True'
|
||||
|
||||
if alpha:
|
||||
show_frame_nums = False
|
||||
show_vars = False
|
||||
perf_osd = False
|
||||
|
||||
# Construct & parse additional variables
|
||||
frames_dir = os.path.join(temp_dir_path, 'frames')
|
||||
@@ -52,8 +59,10 @@ if frames:
|
||||
clip = core.imwri.Read(rf"{pattern}", firstnum=int(first)) # Load the image sequence with imwri
|
||||
clip = core.std.AssumeFPS(clip, fpsnum=infps_num, fpsden=infps_den) # Set the frame rate for the image sequence
|
||||
else:
|
||||
index_file_path = os.path.join(temp_dir_path, 'index.lwi') if os.path.isdir(temp_dir_path) else f'{input_path}.index.lwi'
|
||||
clip = core.lsmas.LWLibavSource(input_path, cachefile=index_file_path) # Load video with lsmash
|
||||
clip = core.lsmas.LWLibavSource(input_path, cachefile=cache_file) # Load video with lsmash
|
||||
if alpha:
|
||||
clip = core.std.PropToClip(clip, prop='_Alpha') # Process only alpha channel
|
||||
|
||||
|
||||
src_frames = len(clip) # Amount of source frames
|
||||
|
||||
@@ -107,6 +116,10 @@ resize = res_scaled and res_scaled != "0x0" and res_scaled != res_input
|
||||
res_w = res_scaled_x if resize else res_in_x
|
||||
res_h = res_scaled_y if resize else res_in_y
|
||||
|
||||
# Scene change detection
|
||||
if sc_sens > 0.01:
|
||||
clip = core.misc.SCDetect(clip=clip, threshold=sc_sens)
|
||||
|
||||
# Convert to RGBS from YUV or RGB
|
||||
colors = "YUV" if clip.format.color_family == vs.YUV else "RGB"
|
||||
if colors == "YUV":
|
||||
@@ -121,10 +134,6 @@ info_str += f"Loop: {loop}\nScn Detect: {sc_sens}\nMatch Dur: {match_duration}\n
|
||||
if pad_x > 0 or pad_y > 0:
|
||||
clip = core.std.AddBorders(clip, right=pad_x, bottom=pad_y)
|
||||
|
||||
# Scene change detection
|
||||
if sc_sens > 0.01:
|
||||
clip = core.misc.SCDetect(clip=clip, threshold=sc_sens)
|
||||
|
||||
pre_interp_frames = len(clip)
|
||||
frames_processed_total = 0
|
||||
|
||||
@@ -153,17 +162,21 @@ r_fac_num, r_fac_den = map(int, factor.split('/'))
|
||||
clip = core.rife.RIFE(clip, factor_num=r_fac_num, factor_den=r_fac_den, model_path=r_mdlpath, gpu_id=(None if r_gpu < 0 else r_gpu), gpu_thread=r_threads, tta=r_tta, uhd=r_uhd, sc=sc_sens > 0.01)
|
||||
|
||||
# Reduplication
|
||||
if dedupe and allow_redupe and not realtime:
|
||||
def reorder_clip(clip, frames_vs_json_path):
|
||||
reordered_clip = clip[0]
|
||||
with open(frames_vs_json_path) as json_file:
|
||||
with open(frames_vs_json_path, 'r') as json_file:
|
||||
frame_list = json.load(json_file)
|
||||
for i in frame_list:
|
||||
if i < clip.num_frames:
|
||||
reordered_clip = reordered_clip + clip[i]
|
||||
clip = reordered_clip.std.Trim(1, reordered_clip.num_frames - 1) # Redupe trim
|
||||
# Redupe trim and return the result
|
||||
return reordered_clip.std.Trim(1, reordered_clip.num_frames - 1) # Redupe trim
|
||||
|
||||
if dedupe and allow_redupe and not realtime:
|
||||
clip = reorder_clip(clip, frames_vs_json_path)
|
||||
|
||||
# Set output format & color matrix
|
||||
clip = vs.core.resize.Bicubic(clip, format=vs.YUV444P16, matrix_s=c_matrix)
|
||||
clip = vs.core.resize.Bicubic(clip, format=vs.YUV444P16, matrix_s=c_matrix) if not alpha else vs.core.resize.Bicubic(clip, format=vs.GRAY8, matrix_s=c_matrix)
|
||||
|
||||
# Undo compatibility padding by cropping the same area
|
||||
if pad_x > 0 or pad_y > 0:
|
||||
@@ -231,7 +244,4 @@ if os.path.isfile(vfr_json_path):
|
||||
if realtime and loop:
|
||||
clip = clip.std.Loop(0)
|
||||
|
||||
clip.set_output()
|
||||
|
||||
if os.path.isfile(index_file_path):
|
||||
os.remove(index_file_path)
|
||||
clip.set_output()
|
||||
Reference in New Issue
Block a user