VFR option in GUI, logic fixes and sanity check improvs, disable dedupe if <5% dupes

This commit is contained in:
N00MKRAD
2024-12-03 00:40:24 +01:00
parent 2769b7dff7
commit 046cbaddb1
17 changed files with 127 additions and 62 deletions

View File

@@ -2,6 +2,7 @@
{
public class Enums
{
public enum VfrMode { Auto, All, None }
public enum Round { Near, Up, Down }
public class Output

View File

@@ -99,6 +99,9 @@ namespace Flowframes
private void SetPaths (string inputPath)
{
if (!File.Exists(inputPath) && !Directory.Exists(inputPath))
return;
inPath = inputPath;
outPath = (Config.GetInt("outFolderLoc") == 0) ? inputPath.GetParentDir() : Config.Get("custOutDir").Trim();
tempFolder = InterpolateUtils.GetTempFolderLoc(inPath, outPath);

View File

@@ -92,5 +92,12 @@ namespace Flowframes.Data
{ Enums.Encoding.Quality.JpegWebm.ImgLow.ToString(), "Low" },
{ Enums.Encoding.Quality.JpegWebm.ImgLowest.ToString(), "Lowest" },
};
public static Dictionary<string, string> VfrMode = new Dictionary<string, string>
{
{ Enums.VfrMode.Auto.ToString(), "Automatic" },
{ Enums.VfrMode.All.ToString(), "Treat all videos as VFR" },
{ Enums.VfrMode.None.ToString(), "Treat no videos as VFR" },
};
}
}

View File

@@ -285,11 +285,6 @@ namespace Flowframes
return filePath.IsConcatFile() ? $"{rateStr}-safe 0 -f concat " : "";
}
public static string GetFfmpegInputArg(this string filePath)
{
return $"{(filePath.IsConcatFile() ? filePath.GetConcStr() : "")} -i {filePath.Wrap()}";
}
public static string Get(this Dictionary<string, string> dict, string key, bool returnKeyInsteadOfEmptyString = false, bool ignoreCase = false)
{
if (key == null)

View File

@@ -141,6 +141,8 @@
this.cancelBtn = new System.Windows.Forms.Button();
this.menuStripQueue = new System.Windows.Forms.ContextMenuStrip(this.components);
this.addCurrentConfigurationToQueueToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.label5 = new System.Windows.Forms.Label();
this.vfrHandling = new System.Windows.Forms.ComboBox();
this.panel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pictureBox4)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBox3)).BeginInit();
@@ -1163,6 +1165,8 @@
// quickSettingsTab
//
this.quickSettingsTab.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(48)))), ((int)(((byte)(48)))), ((int)(((byte)(48)))));
this.quickSettingsTab.Controls.Add(this.vfrHandling);
this.quickSettingsTab.Controls.Add(this.label5);
this.quickSettingsTab.Controls.Add(this.panel2);
this.quickSettingsTab.Controls.Add(this.label20);
this.quickSettingsTab.Controls.Add(this.maxFps);
@@ -1667,6 +1671,29 @@
this.addCurrentConfigurationToQueueToolStripMenuItem.Text = "Add Current Configuration to Queue";
this.addCurrentConfigurationToQueueToolStripMenuItem.Click += new System.EventHandler(this.addCurrentConfigurationToQueueToolStripMenuItem_Click);
//
// label5
//
this.label5.AutoSize = true;
this.label5.ForeColor = System.Drawing.Color.White;
this.label5.Location = new System.Drawing.Point(6, 189);
this.label5.Margin = new System.Windows.Forms.Padding(10, 10, 10, 7);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(185, 15);
this.label5.TabIndex = 91;
this.label5.Text = "Detect Variable Frame Rate Videos";
//
// vfrHandling
//
this.vfrHandling.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
this.vfrHandling.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.vfrHandling.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.vfrHandling.ForeColor = System.Drawing.Color.White;
this.vfrHandling.FormattingEnabled = true;
this.vfrHandling.Location = new System.Drawing.Point(280, 187);
this.vfrHandling.Name = "vfrHandling";
this.vfrHandling.Size = new System.Drawing.Size(249, 23);
this.vfrHandling.TabIndex = 92;
//
// Form1
//
this.AllowDrop = true;
@@ -1855,6 +1882,8 @@
public System.Windows.Forms.TabPage quickSettingsTab;
public System.Windows.Forms.TabPage abtTab;
public System.Windows.Forms.TabPage welcomeTab;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.ComboBox vfrHandling;
}
}

View File

@@ -35,6 +35,8 @@ namespace Flowframes.Forms.Main
public bool ShowModelDownloader = false;
private Enums.VfrMode prevVfrMode = (Enums.VfrMode)(-1);
protected override CreateParams CreateParams
{
get
@@ -68,6 +70,7 @@ namespace Flowframes.Forms.Main
private async void Form1_Shown(object sender, EventArgs e)
{
Program.mainForm = this;
Refresh();
await Task.Delay(1);
@@ -77,12 +80,12 @@ namespace Flowframes.Forms.Main
// Main Tab
UiUtils.InitCombox(interpFactorCombox, 0);
UiUtils.InitCombox(outSpeedCombox, 0);
// Video Utils
UiUtils.InitCombox(trimCombox, 0);
// Quick Settings
UiUtils.InitCombox(trimCombox, 0);
mpdecimateMode.FillFromEnum<Enums.Interpolation.MpDecimateSens>(useKeyNames: true);
vfrHandling.FillFromEnum<Enums.VfrMode>(stringMap: Strings.VfrMode);
vfrHandling.SelectedIndexChanged += (s, ev) => VfrModeChange();
Program.mainForm = this;
Logger.textbox = logBox;
VulkanUtils.Init();
NvApi.Init();
@@ -101,17 +104,22 @@ namespace Flowframes.Forms.Main
completionAction.SelectedIndex = 0;
}
private void VfrModeChange()
{
var oldMode = (Enums.VfrMode)Config.GetInt(Config.Key.vfrHandling);
var newMode = ParseUtils.GetEnum<Enums.VfrMode>(vfrHandling.Text, stringMap: Strings.VfrMode);
if (newMode != oldMode)
{
SaveQuickSettings();
HandleInputFiles(new[] { inputTbox.Text });
}
}
private void InitOutputUi()
{
comboxOutputFormat.FillFromEnum<Enums.Output.Format>(Strings.OutputFormat, 0);
UpdateOutputUi();
if (Debugger.IsAttached)
{
Logger.Log($"Formats: {string.Join(", ", Enum.GetValues(typeof(Enums.Output.Format)).Cast<Enums.Output.Format>().Select(e => Strings.OutputFormat.Get(e.ToString())))}", true);
Logger.Log($"Encoders: {string.Join(", ", Enum.GetValues(typeof(Enums.Encoding.Encoder)).Cast<Enums.Encoding.Encoder>().Select(e => Strings.Encoder.Get(e.ToString())))}", true);
Logger.Log($"Pixel Formats: {string.Join(", ", Enum.GetValues(typeof(Enums.Encoding.PixelFormat)).Cast<Enums.Encoding.PixelFormat>().Select(e => Strings.PixelFormat.Get(e.ToString())))}", true);
}
}
public async void ResetOutputUi()
@@ -168,7 +176,7 @@ namespace Flowframes.Forms.Main
labelOutput.Text = $"Set {string.Join(", ", infoStrings)}";
}
async Task Checks()
private async Task Checks()
{
try
{
@@ -187,14 +195,14 @@ namespace Flowframes.Forms.Main
}
}
void HandleArgs()
private void HandleArgs()
{
// Input & interpolation settings
if (Cli.ValidFiles.Any())
{
Logger.Log($"[CLI] Loading file(s): {string.Join(", ", Cli.ValidFiles)}", true);
DragDropHandler(Cli.ValidFiles.ToArray());
HandleInputFiles(Cli.ValidFiles.ToArray());
}
if (Cli.InterpAi != (Implementations.Ai)(-1))
@@ -403,7 +411,7 @@ namespace Flowframes.Forms.Main
UpdateInputInfo();
}
void InitAis()
private void InitAis()
{
bool pytorchAvailable = Python.IsPytorchReady();
@@ -457,7 +465,7 @@ namespace Flowframes.Forms.Main
CommonOpenFileDialog dialog = new CommonOpenFileDialog { InitialDirectory = inputTbox.Text.Trim(), IsFolderPicker = true };
if (dialog.ShowDialog() == CommonFileDialogResult.Ok)
DragDropHandler(new string[] { dialog.FileName });
HandleInputFiles(new string[] { dialog.FileName });
}
private void browseInputFileBtn_Click(object sender, EventArgs e)
@@ -465,7 +473,7 @@ namespace Flowframes.Forms.Main
CommonOpenFileDialog dialog = new CommonOpenFileDialog { InitialDirectory = inputTbox.Text.Trim(), IsFolderPicker = false };
if (dialog.ShowDialog() == CommonFileDialogResult.Ok)
DragDropHandler(new string[] { dialog.FileName });
HandleInputFiles(new string[] { dialog.FileName });
}
private void browseOutBtn_Click(object sender, EventArgs e)
@@ -535,7 +543,7 @@ namespace Flowframes.Forms.Main
private void inputTbox_DragDrop(object sender, DragEventArgs e)
{
DragDropHandler((string[])e.Data.GetData(DataFormats.FileDrop));
HandleInputFiles((string[])e.Data.GetData(DataFormats.FileDrop));
}
void outputTbox_DragEnter(object sender, DragEventArgs e) { e.Effect = DragDropEffects.Copy; }
@@ -658,10 +666,10 @@ namespace Flowframes.Forms.Main
{
var files = (string[])e.Data.GetData(DataFormats.FileDrop);
await Task.Delay(1); // Release drop
DragDropHandler(files);
HandleInputFiles(files);
}
public void DragDropHandler(string[] files, bool first = true)
public void HandleInputFiles(string[] files)
{
if (Program.busy) return;
@@ -798,7 +806,7 @@ namespace Flowframes.Forms.Main
#region Quick Settings
public void SaveQuickSettings(object sender, EventArgs e)
public void SaveQuickSettings(object sender = null, EventArgs e = null)
{
if (!_quickSettingsInitialized) return;
@@ -813,6 +821,7 @@ namespace Flowframes.Forms.Main
ConfigParser.SaveGuiElement(scnDetect);
ConfigParser.SaveGuiElement(scnDetectValue);
ConfigParser.SaveGuiElement(maxFps);
ConfigParser.SaveComboxIndex(vfrHandling);
}
public void LoadQuickSettings(object sender = null, EventArgs e = null)
@@ -825,6 +834,7 @@ namespace Flowframes.Forms.Main
ConfigParser.LoadGuiElement(scnDetect);
ConfigParser.LoadGuiElement(scnDetectValue);
ConfigParser.LoadGuiElement(maxFps);
ConfigParser.LoadComboxIndex(vfrHandling);
_quickSettingsInitialized = true;
}

View File

@@ -111,20 +111,6 @@ namespace Flowframes.IO
}
}
// Get using fixed key
public static string Get(Key key, string defaultVal)
{
WriteIfDoesntExist(key.ToString(), defaultVal);
return Get(key);
}
// Get using string
public static string Get(string key, string defaultVal)
{
WriteIfDoesntExist(key, defaultVal);
return Get(key);
}
public static string Get(Key key, Type type = Type.String)
{
return Get(key.ToString(), type);
@@ -390,6 +376,7 @@ namespace Flowframes.IO
lastOutputSettings,
PerformedHwEncCheck,
SupportedHwEncoders,
vfrHandling,
}
}
}

View File

@@ -45,7 +45,7 @@ namespace Flowframes.IO
public static void SaveComboxIndex(ComboBox comboBox)
{
Config.Set(comboBox.Name, comboBox.SelectedIndex.ToString());
Config.Set(comboBox.Name, comboBox.SelectedIndex.Clamp(0, int.MaxValue).ToString());
}
public static void LoadGuiElement(ComboBox comboBox, string suffix = "")
@@ -70,7 +70,7 @@ namespace Flowframes.IO
public static void LoadComboxIndex(ComboBox comboBox)
{
comboBox.SelectedIndex = Config.GetInt(comboBox.Name);
comboBox.SelectedIndex = Config.GetInt(comboBox.Name).Clamp(0, int.MaxValue);
}
}
}

View File

@@ -129,6 +129,9 @@ namespace Flowframes.IO
public static bool IsPathOneDrive(string path)
{
if (path.IsEmpty())
return false;
return path.Lower().Replace("\\", "/").MatchesWildcard("*:/users/*/onedrive*");
}

View File

@@ -268,10 +268,11 @@ namespace Flowframes.Magick
Process ffmpeg = OsUtils.NewProcess(true);
string baseCmd = $"/C cd /D {Path.Combine(IO.Paths.GetPkgPath(), IO.Paths.audioVideoDir).Wrap()}";
string mpDec = FfmpegCommands.GetMpdecimate(wrap: false); // FfmpegCommands.GetMpdecimate((int)FfmpegCommands.MpDecSensitivity.Normal, false);
ffmpeg.StartInfo.Arguments = $"{baseCmd} & ffmpeg -loglevel debug -y -i {videoPath.Wrap()} -fps_mode vfr -vf {mpDec} -f null NUL 2>&1 | findstr keep_count:";
ffmpeg.StartInfo.Arguments = $"{baseCmd} & ffmpeg -loglevel debug -y {videoPath.GetConcStr()} -i {videoPath.Wrap()} -fps_mode vfr -vf {mpDec} -f null NUL 2>&1 | findstr keep_count:";
var ffmpegOutputLines = (await Task.Run(() => OsUtils.GetProcStdOut(ffmpeg, true))).SplitIntoLines();
var frames = new Dictionary<int, List<int>>();
int frameCount = 0;
int lastKeepFrameNum = 0;
for (int frameIdx = 0; frameIdx < ffmpegOutputLines.Length; frameIdx++)
@@ -286,16 +287,24 @@ namespace Flowframes.Magick
}
lastKeepFrameNum = frameIdx;
frameCount++;
}
else if (line.Contains(" drop pts:"))
{
frames[lastKeepFrameNum].Add(frameIdx);
frameCount++;
}
}
var inputFrames = new List<int>(frames.Keys);
float keepPercentage = (float)inputFrames.Count / frameCount * 100f;
Logger.Log($"Dedupe: Kept {inputFrames.Count}/{frameCount} frames ({keepPercentage.ToString("0.#")}%)");
Logger.Log($"Dedupe: Kept {inputFrames.Count}/{ffmpegOutputLines.Length} frames", true);
if (keepPercentage > 95f)
{
Logger.Log("Dedupe: Less than 5% duplicate frames detected, will not dedupe.");
Interpolate.currentSettings.dedupe = false;
}
if (loop)
{
@@ -303,7 +312,11 @@ namespace Flowframes.Magick
}
File.WriteAllText(Path.Combine(Interpolate.currentSettings.tempFolder, "input.json"), inputFrames.ToJson(true));
File.WriteAllText(Path.Combine(Interpolate.currentSettings.tempFolder, "dupes.test.json"), frames.ToJson(true));
if (Interpolate.currentSettings.dedupe)
{
File.WriteAllText(Path.Combine(Interpolate.currentSettings.tempFolder, "dupes.test.json"), frames.ToJson(true));
}
}
}
}

View File

@@ -335,7 +335,9 @@ namespace Flowframes.Main
static async Task Loop(string outPath, int looptimes)
{
if (looptimes < 1 || !Config.GetBool(Config.Key.enableLoop)) return;
if (looptimes < 1 || !Config.GetBool(Config.Key.enableLoop))
return;
Logger.Log($"Looping {looptimes} {(looptimes == 1 ? "time" : "times")} to reach target length of {Config.GetInt(Config.Key.minOutVidLength)}s...");
await FfmpegCommands.LoopVideo(outPath, looptimes, Config.GetInt(Config.Key.loopMode) == 0);
}
@@ -347,7 +349,7 @@ namespace Flowframes.Main
int minFrameCount = (minLength * I.currentSettings.outFps.Float).RoundToInt();
int outFrames = (I.currentMediaFile.FrameCount * I.currentSettings.interpFactor).RoundToInt();
if (outFrames / I.currentSettings.outFps.Float < minLength)
times = (int)Math.Ceiling((double)minFrameCount / (double)outFrames);
times = (int)Math.Ceiling((double)minFrameCount / outFrames);
times--; // Not counting the 1st play (0 loops)
if (times <= 0) return -1; // Never try to loop 0 times, idk what would happen, probably nothing
return times;

View File

@@ -204,19 +204,21 @@ namespace Flowframes
{
if (canceled) return;
bool dedupe = Config.GetInt(Config.Key.dedupMode) != 0;
if (currentSettings.dedupe)
{
await Task.Run(async () => { await Dedupe.CreateDupesFile(currentSettings.framesFolder, currentSettings.framesExt); });
}
if (!ai.Piped || (ai.Piped && currentSettings.inputIsFrames))
{
await Task.Run(async () => { await Dedupe.CreateDupesFile(currentSettings.framesFolder, currentSettings.framesExt); });
await Task.Run(async () => { await FrameRename.Rename(); });
}
else if (ai.Piped && dedupe)
else if (ai.Piped && currentSettings.dedupe)
{
await Task.Run(async () => { await Dedupe.CreateFramesFileVideo(currentSettings.inPath, Config.GetBool(Config.Key.enableLoop)); });
}
if (!ai.Piped || (ai.Piped && dedupe))
if (!ai.Piped || (ai.Piped && currentSettings.dedupe))
await Task.Run(async () => { await FrameOrder.CreateFrameOrderFile(currentSettings.tempFolder, Config.GetBool(Config.Key.enableLoop), currentSettings.interpFactor); });
if (currentSettings.model.FixedFactors.Count() > 0 && (currentSettings.interpFactor != (int)currentSettings.interpFactor || !currentSettings.model.FixedFactors.Contains(currentSettings.interpFactor.RoundToInt())))
@@ -247,7 +249,7 @@ namespace Flowframes
tasks.Add(AiProcess.RunFlavrCuda(currentSettings.framesFolder, currentSettings.interpFactor, currentSettings.model.Dir));
if (ai.NameInternal == Implementations.dainNcnn.NameInternal)
tasks.Add(AiProcess.RunDainNcnn(currentSettings.framesFolder, outpath, currentSettings.interpFactor, currentSettings.model.Dir, Config.GetInt(Config.Key.dainNcnnTilesize, 512)));
tasks.Add(AiProcess.RunDainNcnn(currentSettings.framesFolder, outpath, currentSettings.interpFactor, currentSettings.model.Dir, Config.GetInt(Config.Key.dainNcnnTilesize)));
if (ai.NameInternal == Implementations.xvfiCuda.NameInternal)
tasks.Add(AiProcess.RunXvfiCuda(currentSettings.framesFolder, currentSettings.interpFactor, currentSettings.model.Dir));

View File

@@ -107,13 +107,13 @@ namespace Flowframes.Main
bool passes = true;
bool isFile = !IoUtils.IsPathDirectory(s.inPath);
if (passes && IoUtils.IsPathOneDrive(s.inPath) || IoUtils.IsPathOneDrive(s.outPath))
if (passes && (IoUtils.IsPathOneDrive(s.inPath) || IoUtils.IsPathOneDrive(s.outPath)))
{
UiUtils.ShowMessageBox("OneDrive paths are not supported. Please use a local path instead.");
passes = false;
}
if ((passes && isFile && !IoUtils.IsFileValid(s.inPath)) || (!isFile && !IoUtils.IsDirValid(s.inPath)))
if ((passes && (isFile && !IoUtils.IsFileValid(s.inPath)) || (!isFile && !IoUtils.IsDirValid(s.inPath))))
{
UiUtils.ShowMessageBox("Input path is not valid!");
passes = false;
@@ -125,7 +125,7 @@ namespace Flowframes.Main
passes = false;
}
if (passes && s.tempFolder.StartsWith(@"\\") || IoUtils.IsPathOneDrive(s.tempFolder))
if (passes && (s.tempFolder.StartsWith(@"\\") || IoUtils.IsPathOneDrive(s.tempFolder)))
{
UiUtils.ShowMessageBox("Flowframes does not support network paths as a temp folder!\nPlease use a local path instead.");
passes = false;
@@ -134,7 +134,7 @@ namespace Flowframes.Main
float fpsLimit = s.outFpsResampled.Float;
int maxEncoderFps = s.outSettings.Encoder.GetInfo().MaxFramerate;
if (passes && s.outFps.Float < 1f || (s.outFps.Float > maxEncoderFps && !(fpsLimit > 0 && fpsLimit <= maxEncoderFps)))
if (passes && (s.outFps.Float < 1f || (s.outFps.Float > maxEncoderFps && !(fpsLimit > 0 && fpsLimit <= maxEncoderFps))))
{
string imgSeqNote = isFile ? "" : "\n\nWhen using an image sequence as input, you always have to specify the frame rate manually.";
UiUtils.ShowMessageBox($"Invalid output frame rate ({s.outFps.Float}).\nMust be 1-{maxEncoderFps}. Either lower the interpolation factor or use the \"Maximum Output Frame Rate\" option.{imgSeqNote}");

View File

@@ -228,6 +228,19 @@ namespace Flowframes
mediaFile.InputTimestampDurations = new List<float>(timestampDurations);
if(Config.GetInt(Config.Key.vfrHandling) == 1)
{
Logger.Log($"Ignoring VFR deviation threshold of {maxDeviationPercent.ToString("0.##")}%, force-enabling VFR mode due to settings");
mediaFile.IsVfr = true;
return;
}
else if (Config.GetInt(Config.Key.vfrHandling) == 2)
{
Logger.Log($"Ignoring VFR deviation threshold of {maxDeviationPercent.ToString("0.##")}%, force-disabling VFR mode due to settings");
mediaFile.IsVfr = false;
return;
}
if (maxDeviationPercent > 20f)
{
Logger.Log($"Max timestamp deviation is {maxDeviationPercent.ToString("0.##")}% or {maxDeviationMs} ms - Assuming VFR input!", hidden: true);

View File

@@ -70,13 +70,12 @@ namespace Flowframes.Media
{
if (Interpolate.currentMediaFile.IsVfr && !Interpolate.currentSettings.dedupe)
{
// Logger.Log($"Ignoring {resampleFps.Float} FPS limit as this is currently unsupported for variable framerate videos.");
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}");
}
// filters.Add($"fps={resampleFps}");
}
if (Config.GetBool(Config.Key.keepColorSpace) && extraData.HasAllColorValues())

View File

@@ -71,8 +71,6 @@ namespace Flowframes.Media
float currentTargetTime = 0.0f; // Start time for the target frame rate
int index = 0; // Index for iterating through the input timestamps
Console.WriteLine("--> Converting to constant frame rate...");
while (currentTargetTime <= inputTimestamps.Last()) // Use ^1 to get the last element
{
switch (roundMethod)
@@ -88,8 +86,10 @@ namespace Flowframes.Media
break;
}
// Debug message to show which frame index was picked
Console.WriteLine($"--> Frame {(outputTimestamps.Count + 1).ToString().PadLeft(3)} | Target Time: {(currentTargetTime * 1000f):F5} | Picked Input Index: {index} | Input TS: {(inputTimestamps[index] * 1000f):F3}");
if (Program.Debug)
{
Console.WriteLine($"-> Frame {(outputTimestamps.Count + 1).ToString().PadLeft(4)} | Target Time: {(currentTargetTime * 1000f):F5} | Picked Input Index: {(index).ToString().PadLeft(4)} | Input TS: {(inputTimestamps[index] * 1000f):F3}");
}
// Add the closest timestamp to the output list, along with the index of the input timestamp
outputTimestamps.Add(new float[] { inputTimestamps[index], index });
@@ -98,6 +98,7 @@ namespace Flowframes.Media
currentTargetTime += targetFrameInterval;
}
Logger.Log($"CFR Downsampling: Picked {outputTimestamps.Count} out of {inputTimestamps.Count} timestamps for {targetFrameRate} FPS (Round: {roundMethod})", true);
return outputTimestamps;
}
}

View File

@@ -393,7 +393,7 @@ namespace Flowframes.Os
SceneDetectSensitivity = Config.GetBool(Config.Key.scnDetect) ? Config.GetFloat(Config.Key.scnDetectValue) * 0.7f : 0f,
Loop = Config.GetBool(Config.Key.enableLoop),
MatchDuration = Config.GetBool(Config.Key.fixOutputDuration),
Dedupe = Config.GetInt(Config.Key.dedupMode) != 0,
Dedupe = Interpolate.currentSettings.dedupe,
Realtime = rt,
Osd = Config.GetBool(Config.Key.vsRtShowOsd),
};