mirror of
https://github.com/n00mkrad/flowframes.git
synced 2026-02-24 12:12:36 +01:00
VFR option in GUI, logic fixes and sanity check improvs, disable dedupe if <5% dupes
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
{
|
||||
public class Enums
|
||||
{
|
||||
public enum VfrMode { Auto, All, None }
|
||||
public enum Round { Near, Up, Down }
|
||||
|
||||
public class Output
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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" },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
29
CodeLegacy/Forms/Main/Form1.Designer.cs
generated
29
CodeLegacy/Forms/Main/Form1.Designer.cs
generated
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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*");
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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}");
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user