From 046cbaddb1fff832da927ca008fc690981e4dd85 Mon Sep 17 00:00:00 2001 From: N00MKRAD <61149547+n00mkrad@users.noreply.github.com> Date: Tue, 3 Dec 2024 00:40:24 +0100 Subject: [PATCH] VFR option in GUI, logic fixes and sanity check improvs, disable dedupe if <5% dupes --- CodeLegacy/Data/Enums.cs | 1 + CodeLegacy/Data/InterpSettings.cs | 3 ++ CodeLegacy/Data/Strings.cs | 7 ++++ CodeLegacy/Extensions/ExtensionMethods.cs | 5 --- CodeLegacy/Forms/Main/Form1.Designer.cs | 29 +++++++++++++ CodeLegacy/Forms/Main/Form1.cs | 50 ++++++++++++++--------- CodeLegacy/IO/Config.cs | 15 +------ CodeLegacy/IO/ConfigParser.cs | 4 +- CodeLegacy/IO/IoUtils.cs | 3 ++ CodeLegacy/Magick/Dedupe.cs | 19 +++++++-- CodeLegacy/Main/Export.cs | 6 ++- CodeLegacy/Main/Interpolate.cs | 12 +++--- CodeLegacy/Main/InterpolateUtils.cs | 8 ++-- CodeLegacy/Media/FfmpegCommands.cs | 13 ++++++ CodeLegacy/Media/FfmpegEncode.cs | 3 +- CodeLegacy/Media/TimestampUtils.cs | 9 ++-- CodeLegacy/Os/AiProcess.cs | 2 +- 17 files changed, 127 insertions(+), 62 deletions(-) diff --git a/CodeLegacy/Data/Enums.cs b/CodeLegacy/Data/Enums.cs index cbca6a8..bb5ba5d 100644 --- a/CodeLegacy/Data/Enums.cs +++ b/CodeLegacy/Data/Enums.cs @@ -2,6 +2,7 @@ { public class Enums { + public enum VfrMode { Auto, All, None } public enum Round { Near, Up, Down } public class Output diff --git a/CodeLegacy/Data/InterpSettings.cs b/CodeLegacy/Data/InterpSettings.cs index be9eb5b..2cffe97 100644 --- a/CodeLegacy/Data/InterpSettings.cs +++ b/CodeLegacy/Data/InterpSettings.cs @@ -99,6 +99,9 @@ public void InitArgs () 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); diff --git a/CodeLegacy/Data/Strings.cs b/CodeLegacy/Data/Strings.cs index 1334f78..ff33366 100644 --- a/CodeLegacy/Data/Strings.cs +++ b/CodeLegacy/Data/Strings.cs @@ -92,5 +92,12 @@ public class Strings { Enums.Encoding.Quality.JpegWebm.ImgLow.ToString(), "Low" }, { Enums.Encoding.Quality.JpegWebm.ImgLowest.ToString(), "Lowest" }, }; + + public static Dictionary VfrMode = new Dictionary + { + { Enums.VfrMode.Auto.ToString(), "Automatic" }, + { Enums.VfrMode.All.ToString(), "Treat all videos as VFR" }, + { Enums.VfrMode.None.ToString(), "Treat no videos as VFR" }, + }; } } diff --git a/CodeLegacy/Extensions/ExtensionMethods.cs b/CodeLegacy/Extensions/ExtensionMethods.cs index c6283e3..5ec71e5 100644 --- a/CodeLegacy/Extensions/ExtensionMethods.cs +++ b/CodeLegacy/Extensions/ExtensionMethods.cs @@ -285,11 +285,6 @@ public static string GetConcStr(this string filePath, int rate = -1) 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 dict, string key, bool returnKeyInsteadOfEmptyString = false, bool ignoreCase = false) { if (key == null) diff --git a/CodeLegacy/Forms/Main/Form1.Designer.cs b/CodeLegacy/Forms/Main/Form1.Designer.cs index 0de553d..9907650 100644 --- a/CodeLegacy/Forms/Main/Form1.Designer.cs +++ b/CodeLegacy/Forms/Main/Form1.Designer.cs @@ -141,6 +141,8 @@ private void InitializeComponent() 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 @@ private void InitializeComponent() // 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 @@ private void InitializeComponent() 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 @@ private void InitializeComponent() 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; } } diff --git a/CodeLegacy/Forms/Main/Form1.cs b/CodeLegacy/Forms/Main/Form1.cs index 671ff3b..b63c409 100644 --- a/CodeLegacy/Forms/Main/Form1.cs +++ b/CodeLegacy/Forms/Main/Form1.cs @@ -35,6 +35,8 @@ public enum EXECUTION_STATE : uint { ES_AWAYMODE_REQUIRED = 0x00000040, ES_CONTI public bool ShowModelDownloader = false; + private Enums.VfrMode prevVfrMode = (Enums.VfrMode)(-1); + protected override CreateParams CreateParams { get @@ -68,6 +70,7 @@ private void Form1_Load(object sender, EventArgs e) private async void Form1_Shown(object sender, EventArgs e) { + Program.mainForm = this; Refresh(); await Task.Delay(1); @@ -77,12 +80,12 @@ private async void Form1_Shown(object sender, EventArgs e) // Main Tab UiUtils.InitCombox(interpFactorCombox, 0); UiUtils.InitCombox(outSpeedCombox, 0); - // Video Utils - UiUtils.InitCombox(trimCombox, 0); // Quick Settings + UiUtils.InitCombox(trimCombox, 0); mpdecimateMode.FillFromEnum(useKeyNames: true); + vfrHandling.FillFromEnum(stringMap: Strings.VfrMode); + vfrHandling.SelectedIndexChanged += (s, ev) => VfrModeChange(); - Program.mainForm = this; Logger.textbox = logBox; VulkanUtils.Init(); NvApi.Init(); @@ -101,19 +104,24 @@ private async void Form1_Shown(object sender, EventArgs e) completionAction.SelectedIndex = 0; } - private void InitOutputUi() + private void VfrModeChange() { - comboxOutputFormat.FillFromEnum(Strings.OutputFormat, 0); - UpdateOutputUi(); + var oldMode = (Enums.VfrMode)Config.GetInt(Config.Key.vfrHandling); + var newMode = ParseUtils.GetEnum(vfrHandling.Text, stringMap: Strings.VfrMode); - if (Debugger.IsAttached) + if (newMode != oldMode) { - Logger.Log($"Formats: {string.Join(", ", Enum.GetValues(typeof(Enums.Output.Format)).Cast().Select(e => Strings.OutputFormat.Get(e.ToString())))}", true); - Logger.Log($"Encoders: {string.Join(", ", Enum.GetValues(typeof(Enums.Encoding.Encoder)).Cast().Select(e => Strings.Encoder.Get(e.ToString())))}", true); - Logger.Log($"Pixel Formats: {string.Join(", ", Enum.GetValues(typeof(Enums.Encoding.PixelFormat)).Cast().Select(e => Strings.PixelFormat.Get(e.ToString())))}", true); + SaveQuickSettings(); + HandleInputFiles(new[] { inputTbox.Text }); } } + private void InitOutputUi() + { + comboxOutputFormat.FillFromEnum(Strings.OutputFormat, 0); + UpdateOutputUi(); + } + public async void ResetOutputUi() { comboxOutputEncoder.Items.Clear(); @@ -168,7 +176,7 @@ private void UpdateOutputEncodingUi() labelOutput.Text = $"Set {string.Join(", ", infoStrings)}"; } - async Task Checks() + private async Task Checks() { try { @@ -187,14 +195,14 @@ async Task Checks() } } - 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 @@ public void ResetInputInfo() UpdateInputInfo(); } - void InitAis() + private void InitAis() { bool pytorchAvailable = Python.IsPytorchReady(); @@ -457,7 +465,7 @@ private void browseInputBtn_Click(object sender, EventArgs e) 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 @@ private void browseInputFileBtn_Click(object sender, EventArgs e) 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 @@ public void SetFormat(Enums.Output.Format format) 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 @@ private async void Form1_DragDrop(object sender, DragEventArgs e) { 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 @@ private void trimBox_TextChanged(object sender, EventArgs e) #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 @@ public void SaveQuickSettings(object sender, EventArgs e) 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 @@ public void LoadQuickSettings(object sender = null, EventArgs e = null) ConfigParser.LoadGuiElement(scnDetect); ConfigParser.LoadGuiElement(scnDetectValue); ConfigParser.LoadGuiElement(maxFps); + ConfigParser.LoadComboxIndex(vfrHandling); _quickSettingsInitialized = true; } diff --git a/CodeLegacy/IO/Config.cs b/CodeLegacy/IO/Config.cs index b7612eb..3b31d38 100644 --- a/CodeLegacy/IO/Config.cs +++ b/CodeLegacy/IO/Config.cs @@ -111,20 +111,6 @@ private static void Reload() } } - // 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 @@ public enum Key lastOutputSettings, PerformedHwEncCheck, SupportedHwEncoders, + vfrHandling, } } } diff --git a/CodeLegacy/IO/ConfigParser.cs b/CodeLegacy/IO/ConfigParser.cs index 9b7640c..b1ea4cf 100644 --- a/CodeLegacy/IO/ConfigParser.cs +++ b/CodeLegacy/IO/ConfigParser.cs @@ -45,7 +45,7 @@ public static void SaveGuiElement(NumericUpDown upDown, StringMode stringMode = 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 @@ public static void LoadGuiElement(NumericUpDown upDown) public static void LoadComboxIndex(ComboBox comboBox) { - comboBox.SelectedIndex = Config.GetInt(comboBox.Name); + comboBox.SelectedIndex = Config.GetInt(comboBox.Name).Clamp(0, int.MaxValue); } } } diff --git a/CodeLegacy/IO/IoUtils.cs b/CodeLegacy/IO/IoUtils.cs index 89e48ed..5cc4860 100644 --- a/CodeLegacy/IO/IoUtils.cs +++ b/CodeLegacy/IO/IoUtils.cs @@ -129,6 +129,9 @@ public static bool IsPathValid(string path) public static bool IsPathOneDrive(string path) { + if (path.IsEmpty()) + return false; + return path.Lower().Replace("\\", "/").MatchesWildcard("*:/users/*/onedrive*"); } diff --git a/CodeLegacy/Magick/Dedupe.cs b/CodeLegacy/Magick/Dedupe.cs index 0c0ec82..4d6c2c4 100644 --- a/CodeLegacy/Magick/Dedupe.cs +++ b/CodeLegacy/Magick/Dedupe.cs @@ -268,10 +268,11 @@ public static async Task CreateFramesFileVideo(string videoPath, bool loop) 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 frameCount = 0; int lastKeepFrameNum = 0; for (int frameIdx = 0; frameIdx < ffmpegOutputLines.Length; frameIdx++) @@ -286,16 +287,24 @@ public static async Task CreateFramesFileVideo(string videoPath, bool loop) } lastKeepFrameNum = frameIdx; + frameCount++; } else if (line.Contains(" drop pts:")) { frames[lastKeepFrameNum].Add(frameIdx); + frameCount++; } } var inputFrames = new List(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 @@ public static async Task CreateFramesFileVideo(string videoPath, bool loop) } 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)); + } } } } diff --git a/CodeLegacy/Main/Export.cs b/CodeLegacy/Main/Export.cs index c8b2944..3564b96 100644 --- a/CodeLegacy/Main/Export.cs +++ b/CodeLegacy/Main/Export.cs @@ -335,7 +335,9 @@ public static async Task EncodeChunk(string outPath, string interpDir, int chunk 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 @@ private static int GetLoopTimes() 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; diff --git a/CodeLegacy/Main/Interpolate.cs b/CodeLegacy/Main/Interpolate.cs index 5b1dbc8..2e49f6c 100644 --- a/CodeLegacy/Main/Interpolate.cs +++ b/CodeLegacy/Main/Interpolate.cs @@ -204,19 +204,21 @@ public static async Task RunAi(string outpath, AiInfo ai, bool stepByStep = fals { 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 @@ public static async Task RunAi(string outpath, AiInfo ai, bool stepByStep = fals 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)); diff --git a/CodeLegacy/Main/InterpolateUtils.cs b/CodeLegacy/Main/InterpolateUtils.cs index 2a87c70..31f3cb7 100644 --- a/CodeLegacy/Main/InterpolateUtils.cs +++ b/CodeLegacy/Main/InterpolateUtils.cs @@ -107,13 +107,13 @@ public static bool InputIsValid(InterpSettings s) 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 @@ public static bool InputIsValid(InterpSettings s) 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 @@ public static bool InputIsValid(InterpSettings s) 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}"); diff --git a/CodeLegacy/Media/FfmpegCommands.cs b/CodeLegacy/Media/FfmpegCommands.cs index 85a6bc1..f8c61ea 100644 --- a/CodeLegacy/Media/FfmpegCommands.cs +++ b/CodeLegacy/Media/FfmpegCommands.cs @@ -228,6 +228,19 @@ public static void CheckVfr(string inputFile, MediaFile mediaFile, List mediaFile.InputTimestampDurations = new List(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); diff --git a/CodeLegacy/Media/FfmpegEncode.cs b/CodeLegacy/Media/FfmpegEncode.cs index 31ba3b9..f015032 100644 --- a/CodeLegacy/Media/FfmpegEncode.cs +++ b/CodeLegacy/Media/FfmpegEncode.cs @@ -70,13 +70,12 @@ public static async Task GetFfmpegExportArgsOut(Fraction resampleFps, Vi { 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()) diff --git a/CodeLegacy/Media/TimestampUtils.cs b/CodeLegacy/Media/TimestampUtils.cs index 3cb110e..9e8e7a4 100644 --- a/CodeLegacy/Media/TimestampUtils.cs +++ b/CodeLegacy/Media/TimestampUtils.cs @@ -71,8 +71,6 @@ public static List ConvertToConstantFrameRate(List inputTimestam 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 @@ public static List ConvertToConstantFrameRate(List inputTimestam 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 @@ public static List ConvertToConstantFrameRate(List inputTimestam currentTargetTime += targetFrameInterval; } + Logger.Log($"CFR Downsampling: Picked {outputTimestamps.Count} out of {inputTimestamps.Count} timestamps for {targetFrameRate} FPS (Round: {roundMethod})", true); return outputTimestamps; } } diff --git a/CodeLegacy/Os/AiProcess.cs b/CodeLegacy/Os/AiProcess.cs index 9ee9ebf..476cf73 100644 --- a/CodeLegacy/Os/AiProcess.cs +++ b/CodeLegacy/Os/AiProcess.cs @@ -393,7 +393,7 @@ static async Task RunRifeNcnnVsProcess(string inPath, float factor, string outPa 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), };