diff --git a/Code/AudioVideo/FFmpegCommands.cs b/Code/AudioVideo/FFmpegCommands.cs index 808e28d..935599f 100644 --- a/Code/AudioVideo/FFmpegCommands.cs +++ b/Code/AudioVideo/FFmpegCommands.cs @@ -47,12 +47,16 @@ namespace Flowframes DeleteSource(inputFile); } - public static async void ExtractSingleFrame(string inputFile, int frameNum, bool hdr, bool delSrc) + public static async Task ExtractSingleFrame(string inputFile, int frameNum, bool hdr, bool delSrc) { - string hdrStr = ""; - if (hdr) hdrStr = hdrFilter; - string args = "-i \"" + inputFile + "\" " + hdrStr - + " -vf \"select=eq(n\\," + frameNum + ")\" -vframes 1 \"" + inputFile + "-frame" + frameNum + ".png\""; + string outPath = $"{inputFile}-frame{frameNum}.png"; + await ExtractSingleFrame(inputFile, outPath, frameNum, hdr, delSrc); + } + + public static async Task ExtractSingleFrame(string inputFile, string outputPath, int frameNum, bool hdr, bool delSrc) + { + string hdrStr = hdr ? hdrFilter : ""; + string args = $"-i {inputFile.Wrap()} {hdrStr }-vf \"select=eq(n\\,{frameNum})\" -vframes 1 {outputPath.Wrap()}"; await AvProcess.RunFfmpeg(args, AvProcess.LogMode.Hidden); if (delSrc) DeleteSource(inputFile); diff --git a/Code/Flowframes.csproj b/Code/Flowframes.csproj index 24024da..e42c650 100644 --- a/Code/Flowframes.csproj +++ b/Code/Flowframes.csproj @@ -234,6 +234,7 @@ + diff --git a/Code/Form1.Designer.cs b/Code/Form1.Designer.cs index 9230f14..e9acada 100644 --- a/Code/Form1.Designer.cs +++ b/Code/Form1.Designer.cs @@ -95,7 +95,7 @@ this.cancelBtn = new System.Windows.Forms.Button(); this.mainTabControl = new HTAlt.WinForms.HTTabControl(); this.welcomeTab = new System.Windows.Forms.TabPage(); - this.label22 = new System.Windows.Forms.Label(); + this.welcomeLabel2 = new System.Windows.Forms.Label(); this.panel8 = new System.Windows.Forms.Panel(); this.patronsLabel = new System.Windows.Forms.Label(); this.label21 = new System.Windows.Forms.Label(); @@ -959,7 +959,7 @@ // welcomeTab // this.welcomeTab.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(48)))), ((int)(((byte)(48)))), ((int)(((byte)(48))))); - this.welcomeTab.Controls.Add(this.label22); + this.welcomeTab.Controls.Add(this.welcomeLabel2); this.welcomeTab.Controls.Add(this.panel8); this.welcomeTab.Controls.Add(this.panel6); this.welcomeTab.Controls.Add(this.label11); @@ -970,17 +970,18 @@ this.welcomeTab.TabIndex = 4; this.welcomeTab.Text = "Welcome"; // - // label22 + // welcomeLabel2 // - this.label22.AutoSize = true; - this.label22.Font = new System.Drawing.Font("Yu Gothic UI", 21.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label22.ForeColor = System.Drawing.Color.Gray; - this.label22.Location = new System.Drawing.Point(142, 3); - this.label22.Margin = new System.Windows.Forms.Padding(3, 0, 3, 10); - this.label22.Name = "label22"; - this.label22.Size = new System.Drawing.Size(478, 40); - this.label22.TabIndex = 5; - this.label22.Text = "Click The Interpolation Tab To Begin."; + this.welcomeLabel2.AutoSize = true; + this.welcomeLabel2.Font = new System.Drawing.Font("Yu Gothic UI", 21.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.welcomeLabel2.ForeColor = System.Drawing.Color.Gray; + this.welcomeLabel2.Location = new System.Drawing.Point(142, 3); + this.welcomeLabel2.Margin = new System.Windows.Forms.Padding(3, 0, 3, 10); + this.welcomeLabel2.Name = "welcomeLabel2"; + this.welcomeLabel2.Size = new System.Drawing.Size(478, 40); + this.welcomeLabel2.TabIndex = 5; + this.welcomeLabel2.Text = "Click The Interpolation Tab To Begin."; + this.welcomeLabel2.Click += new System.EventHandler(this.welcomeLabel2_Click); // // panel8 // @@ -1431,7 +1432,7 @@ private System.Windows.Forms.Label patronsLabel; private System.Windows.Forms.Label label21; private System.Windows.Forms.Label newsLabel; - private System.Windows.Forms.Label label22; + private System.Windows.Forms.Label welcomeLabel2; } } diff --git a/Code/Form1.cs b/Code/Form1.cs index 17b30ac..b4f8e38 100644 --- a/Code/Form1.cs +++ b/Code/Form1.cs @@ -14,6 +14,7 @@ using System.Windows.Forms; using HTAlt.WinForms; using Flowframes.Data; using Microsoft.WindowsAPICodePack.Taskbar; +using System.Threading.Tasks; namespace Flowframes { @@ -125,7 +126,7 @@ namespace Flowframes if (dialog.ShowDialog() == CommonFileDialogResult.Ok) { inputTbox.Text = dialog.FileName; - InitInput(); + MainUiFunctions.InitInput(outputTbox, inputTbox, fpsInTbox); } } @@ -137,34 +138,10 @@ namespace Flowframes if (dialog.ShowDialog() == CommonFileDialogResult.Ok) { inputTbox.Text = dialog.FileName; - InitInput(); + MainUiFunctions.InitInput(outputTbox, inputTbox, fpsInTbox); } } - void InitInput() - { - outputTbox.Text = inputTbox.Text.Trim().GetParentDir(); - string path = inputTbox.Text.Trim(); - Program.lastInputPath = path; - string fpsStr = "Not Found"; - float fps = IOUtils.GetFpsFolderOrVideo(path); - if(fps > 0) - { - fpsStr = fps.ToString(); - fpsInTbox.Text = fpsStr; - } - Interpolate.SetFps(fps); - Program.lastInputPathIsSsd = OSUtils.DriveIsSSD(path); - if (!Program.lastInputPathIsSsd) - Logger.Log("Your file seems to be on an HDD or USB device. It is recommended to interpolate videos on an SSD drive for best performance."); - if (IOUtils.IsPathDirectory(path)) - Logger.Log($"Video FPS (Loaded from fps.ini): {fpsStr} - Total Number Of Frames: {IOUtils.GetAmountOfFiles(path, false)}"); - else - Logger.Log($"Video FPS: {fpsStr} - Total Number Of Frames: {FFmpegCommands.GetFrameCount(path)}"); - MagickDedupe.ClearCache(); - } - - private void browseOutBtn_Click(object sender, EventArgs e) { CommonOpenFileDialog dialog = new CommonOpenFileDialog(); @@ -214,8 +191,7 @@ namespace Flowframes if (Program.busy) return; string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); inputTbox.Text = files[0]; - InitInput(); - //FFmpegCommands.GetFramerate(inputTbox.Text); + MainUiFunctions.InitInput(outputTbox, inputTbox, fpsInTbox); } void outputTbox_DragEnter(object sender, DragEventArgs e) { e.Effect = DragDropEffects.Copy; } @@ -304,7 +280,7 @@ namespace Flowframes string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); inputTbox.Text = files[0]; Logger.Log("Selected video/directory: " + Path.GetFileName(files[0])); - InitInput(); + MainUiFunctions.InitInput(outputTbox, inputTbox, fpsInTbox); } private async void utilsConvertMp4Btn_Click(object sender, EventArgs e) @@ -386,5 +362,10 @@ namespace Flowframes if (!initialized || !GetAi().supportsTiling) return; Config.Set($"tilesize_{GetAi().aiName}", tilesize.GetInt().ToString()); } + + private void welcomeLabel2_Click(object sender, EventArgs e) + { + SetTab("interpolation"); + } } } diff --git a/Code/Main/InterpolateUtils.cs b/Code/Main/InterpolateUtils.cs index 7e34edd..9a02e4e 100644 --- a/Code/Main/InterpolateUtils.cs +++ b/Code/Main/InterpolateUtils.cs @@ -45,14 +45,21 @@ namespace Flowframes.Main { if (bigPreviewForm == null && !preview.Visible /* ||Program.mainForm.WindowState != FormWindowState.Minimized */ /* || !Program.mainForm.IsInFocus()*/) return; // Skip if the preview is not visible or the form is not in focus Image img = IOUtils.GetImage(latestFramePath); - preview.Image = img; - if (bigPreviewForm != null) - bigPreviewForm.SetImage(img); + SetPreviewImg(img); } } catch { } } + public static void SetPreviewImg (Image img) + { + if (img == null) + return; + preview.Image = img; + if (bigPreviewForm != null) + bigPreviewForm.SetImage(img); + } + public static int GetProgressWaitTime(int numFrames) { float hddMultiplier = 2f; diff --git a/Code/Program.cs b/Code/Program.cs index dae9c14..9f94c43 100644 --- a/Code/Program.cs +++ b/Code/Program.cs @@ -12,7 +12,7 @@ namespace Flowframes { static class Program { - public const int version = 16; + public const int version = 17; public static Form1 mainForm; diff --git a/Code/UI/MainUiFunctions.cs b/Code/UI/MainUiFunctions.cs new file mode 100644 index 0000000..5dc53c5 --- /dev/null +++ b/Code/UI/MainUiFunctions.cs @@ -0,0 +1,61 @@ +using Flowframes.IO; +using Flowframes.Magick; +using Flowframes.Main; +using Flowframes.OS; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Flowframes.UI +{ + class MainUiFunctions + { + public static async Task InitInput (TextBox outputTbox, TextBox inputTbox, TextBox fpsInTbox) + { + outputTbox.Text = inputTbox.Text.Trim().GetParentDir(); + string path = inputTbox.Text.Trim(); + Program.lastInputPath = path; + string fpsStr = "Not Found"; + float fps = IOUtils.GetFpsFolderOrVideo(path); + if (fps > 0) + { + fpsStr = fps.ToString(); + fpsInTbox.Text = fpsStr; + } + Interpolate.SetFps(fps); + Program.lastInputPathIsSsd = OSUtils.DriveIsSSD(path); + if (!Program.lastInputPathIsSsd) + Logger.Log("Your file seems to be on an HDD or USB device. It is recommended to interpolate videos on an SSD drive for best performance."); + if (IOUtils.IsPathDirectory(path)) + Logger.Log($"Video FPS (Loaded from fps.ini): {fpsStr} - Total Number Of Frames: {IOUtils.GetAmountOfFiles(path, false)}"); + else + Logger.Log($"Video FPS: {fpsStr} - Total Number Of Frames: {FFmpegCommands.GetFrameCount(path)}"); + await Task.Delay(10); + Size res = FFmpegCommands.GetSize(path); + Logger.Log($"Video Resolution: {res.Width}x{res.Height}"); + MagickDedupe.ClearCache(); + await Task.Delay(10); + InterpolateUtils.SetPreviewImg(await GetThumbnail(path)); + } + + static async Task GetThumbnail (string videoPath) + { + string imgOnDisk = Path.Combine(Paths.GetDataPath(), "thumb-temp.png"); + try + { + await FFmpegCommands.ExtractSingleFrame(videoPath, imgOnDisk, 1, false, false); + return IOUtils.GetImage(imgOnDisk); + } + catch (Exception e) + { + Logger.Log("GetThumbnail Error: " + e.Message, true); + return null; + } + } + } +} diff --git a/README.md b/README.md index 7c7ba0e..f74cd7c 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,32 @@ -# flowframes +# Flowframes - Windows GUI for Video Interpolation Flowframes Windows GUI for video interpolation - RIFE, DAIN-NCNN, CAIN-NCNN. + + + +## Installation + +* Download the latest version on [itch](https://nmkd.itch.io/flowframes) or, for the most recent beta versions, on [Patreon](https://www.patreon.com/n00mkrad). This repo does not provide downloads. +* Run Flowframes.exe +* Select the components you want to install (certain packages are required, cannot be unticked) + + + +## Using A Pytorch AI + +Some of the AI networks run on Tencent's NCNN framework, which allows them to run on any modern (Vulkan-capable) GPU. + +However, others (like RIFE) run best via their original Pytorch implementation. + +The requirements to run these are the following: + +* A **modern Nvidia GPU** (750 Ti, 900/1000/1600/2000/3000 Series). +* A **Python** installation including Pytorch (1.5 or later) as well as the packages `opencv-python` and `imageio`. + * You can install a portable version of all those requirements from the Flowframes Installer. However, this does not support RTX 3000 cards yet. + + + +#### Running A Pytorch AI on Nvidia Ampere (RTX 3000) GPUs + +I do not have an Ampere card yet, so I can't fully test Flowframes on an RTX 3000 series GPU. + +However, users have reported that you can run it by installing a recent **nightly build of Pytorch**. NCNN-based AIs however should work out of the box. \ No newline at end of file