This commit is contained in:
N00MKRAD
2020-11-23 16:51:05 +01:00
parent 95b5df029e
commit 1bce73dea6
133 changed files with 25577 additions and 0 deletions

22
Code/App.config Normal file
View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Syncfusion.Licensing" publicKeyToken="632609b4d040f6b4" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-18.2460.0.56" newVersion="18.2460.0.56" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.4.0" newVersion="4.1.4.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Security.Principal.Windows" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View File

@@ -0,0 +1,114 @@
using Flowframes.IO;
using Flowframes.OS;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Flowframes
{
class AvProcess
{
public static Process lastProcess;
public static string lastOutputFfmpeg;
public static string lastOutputGifski;
static bool replaceLastLine = false;
public enum LogMode { Visible, OnlyLastLine, Hidden }
static LogMode currentLogMode;
public static async Task RunFfmpeg(string args, LogMode logMode)
{
lastOutputFfmpeg = "";
currentLogMode = logMode;
Process ffmpeg = new Process();
lastProcess = ffmpeg;
ffmpeg.StartInfo.UseShellExecute = false;
ffmpeg.StartInfo.RedirectStandardOutput = true;
ffmpeg.StartInfo.RedirectStandardError = true;
ffmpeg.StartInfo.CreateNoWindow = true;
ffmpeg.StartInfo.FileName = "cmd.exe";
ffmpeg.StartInfo.Arguments = "/C cd /D \"" + GetAvDir() + "\" & ffmpeg.exe -hide_banner -loglevel warning -y -stats " + args;
if(logMode != LogMode.Hidden) Logger.Log("Running ffmpeg...", false);
Logger.Log("cmd.exe " + ffmpeg.StartInfo.Arguments, true);
ffmpeg.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
ffmpeg.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
ffmpeg.Start();
ffmpeg.BeginOutputReadLine();
ffmpeg.BeginErrorReadLine();
while (!ffmpeg.HasExited)
await Task.Delay(100);
Logger.Log("Done running ffmpeg.", true);
}
static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
lastOutputFfmpeg = lastOutputFfmpeg + outLine.Data + "\n";
bool hidden = currentLogMode == LogMode.Hidden;
bool replaceLastLine = currentLogMode == LogMode.OnlyLastLine;
Logger.Log(outLine.Data, hidden, replaceLastLine, "ffmpeg.txt");
}
public static string GetFfmpegOutput (string args)
{
Process ffmpeg = OSUtils.NewProcess(true);
ffmpeg.StartInfo.Arguments = $"/C cd /D {GetAvDir().Wrap()} & ffmpeg.exe -hide_banner -y -stats {args}";
Logger.Log("cmd.exe " + ffmpeg.StartInfo.Arguments, true);
ffmpeg.Start();
ffmpeg.WaitForExit();
string output = ffmpeg.StandardOutput.ReadToEnd();
string err = ffmpeg.StandardError.ReadToEnd();
if (!string.IsNullOrWhiteSpace(err)) output += "\n" + err;
return output;
}
public static string GetFfprobeOutput (string args)
{
Process ffprobe = OSUtils.NewProcess(true);
ffprobe.StartInfo.Arguments = $"/C cd /D {GetAvDir().Wrap()} & ffprobe.exe {args}";
Logger.Log("cmd.exe " + ffprobe.StartInfo.Arguments, true);
ffprobe.Start();
ffprobe.WaitForExit();
string output = ffprobe.StandardOutput.ReadToEnd();
string err = ffprobe.StandardError.ReadToEnd();
if (!string.IsNullOrWhiteSpace(err)) output += "\n" + err;
return output;
}
public static async Task RunGifski(string args, LogMode logMode)
{
lastOutputGifski = "";
currentLogMode = logMode;
Process gifski = OSUtils.NewProcess(true);
lastProcess = gifski;
gifski.StartInfo.Arguments = $"/C cd /D {GetAvDir().Wrap()} & gifski.exe {args}";
Logger.Log("Running gifski...");
Logger.Log("cmd.exe " + gifski.StartInfo.Arguments, true);
gifski.OutputDataReceived += new DataReceivedEventHandler(OutputHandlerGifski);
gifski.ErrorDataReceived += new DataReceivedEventHandler(OutputHandlerGifski);
gifski.Start();
gifski.BeginOutputReadLine();
gifski.BeginErrorReadLine();
while (!gifski.HasExited)
await Task.Delay(100);
Logger.Log("Done running gifski.", true);
}
static void OutputHandlerGifski(object sendingProcess, DataReceivedEventArgs outLine)
{
lastOutputGifski = lastOutputGifski + outLine.Data + "\n";
bool hidden = currentLogMode == LogMode.Hidden;
bool replaceLastLine = currentLogMode == LogMode.OnlyLastLine;
Logger.Log(outLine.Data, hidden, replaceLastLine);
}
static string GetAvDir ()
{
return Path.Combine(Paths.GetPkgPath(), Path.GetFileNameWithoutExtension(Packages.audioVideo.fileName));
}
}
}

View File

@@ -0,0 +1,319 @@
using Flowframes.IO;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Flowframes
{
class FFmpegCommands
{
static string videoEncArgs = "-pix_fmt yuv420p -movflags +faststart -vf \"crop = trunc(iw / 2) * 2:trunc(ih / 2) * 2\"";
public static async Task VideoToFrames(string inputFile, string frameFolderPath, bool deDupe, bool rgb8, bool hdr, bool delSrc)
{
if (!Directory.Exists(frameFolderPath))
Directory.CreateDirectory(frameFolderPath);
string hdrStr = "";
if (hdr) hdrStr = FFmpegStrings.hdrFilter;
string deDupeStr = "";
if (deDupe) deDupeStr = "-vf mpdecimate";
string fmtStr = "";
if (rgb8) fmtStr = "-pix_fmt rgb8";
string args = $"-i {inputFile.Wrap()} {hdrStr} -vsync 0 {fmtStr} {deDupeStr} \"{frameFolderPath}/%08d.png\"";
await AvProcess.RunFfmpeg(args, AvProcess.LogMode.OnlyLastLine);
await Task.Delay(1);
if (delSrc)
DeleteSource(inputFile);
}
public static async Task VideoToFrames(string inputFile, string frameFolderPath, int w, int h, bool deDupe, bool rgb8, bool hdr, bool delSrc)
{
if (!Directory.Exists(frameFolderPath))
Directory.CreateDirectory(frameFolderPath);
string hdrStr = "";
if (hdr) hdrStr = FFmpegStrings.hdrFilter;
string deDupeStr = "";
if (deDupe) deDupeStr = "-vf mpdecimate";
string fmtStr = "";
if (rgb8) fmtStr = "-pix_fmt rgb8";
string args = $"-i {inputFile.Wrap()} {hdrStr} -vsync 0 {fmtStr} {deDupeStr} -s {w}x{h} \"{frameFolderPath}/%08d.png\"";
await AvProcess.RunFfmpeg(args, AvProcess.LogMode.OnlyLastLine);
await Task.Delay(1);
if (delSrc)
DeleteSource(inputFile);
}
public static async void ExtractSingleFrame(string inputFile, int frameNum, bool hdr, bool delSrc)
{
string hdrStr = "";
if (hdr) hdrStr = FFmpegStrings.hdrFilter;
string args = "-i \"" + inputFile + "\" " + hdrStr
+ " -vf \"select=eq(n\\," + frameNum + ")\" -vframes 1 \"" + inputFile + "-frame" + frameNum + ".png\"";
await AvProcess.RunFfmpeg(args, AvProcess.LogMode.Hidden);
if (delSrc)
DeleteSource(inputFile);
}
public static async Task FramesToMp4(string inputDir, string outPath, bool useH265, int crf, float fps, string prefix, bool delSrc, int looptimes = -1, string imgFormat = "png")
{
Logger.Log($"Encoding MP4 video with CRF {crf}...");
int nums = IOUtils.GetFilenameCounterLength(Directory.GetFiles(inputDir, $"*.{imgFormat}")[0], prefix);
string enc = "libx264";
if (useH265) enc = "libx265";
string loopStr = "";
if (looptimes > 0) loopStr = $"-stream_loop {looptimes}";
string args = $" {loopStr} -framerate {fps.ToString().Replace(",",".")} -i \"{inputDir}\\{prefix}%0{nums}d.{imgFormat}\" -c:v {enc} -crf {crf} {videoEncArgs} -threads {Config.GetInt("ffEncThreads")} -c:a copy {outPath.Wrap()}";
await AvProcess.RunFfmpeg(args, AvProcess.LogMode.OnlyLastLine);
if (delSrc)
DeleteSource(inputDir);
}
public static async Task ConvertFramerate (string inputPath, string outPath, bool useH265, int crf, float newFps, bool delSrc = false)
{
Logger.Log($"Changing video frame rate...");
string enc = "libx264";
if (useH265) enc = "libx265";
string args = $" -i {inputPath.Wrap()} -filter:v fps=fps={newFps} -c:v {enc} -crf {crf} -pix_fmt yuv420p -movflags +faststart {outPath.Wrap()}";
await AvProcess.RunFfmpeg(args, AvProcess.LogMode.OnlyLastLine);
if (delSrc)
DeleteSource(inputPath);
}
public static async void FramesToApng (string inputDir, bool opti, int fps, string prefix, bool delSrc)
{
int nums = IOUtils.GetFilenameCounterLength(Directory.GetFiles(inputDir, "*.png")[0], prefix);
string filter = "";
if(opti) filter = "-vf \"split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse\"";
string args = "-framerate " + fps + " -i \"" + inputDir + "\\" + prefix + "%0" + nums + "d.png\" -f apng -plays 0 " + filter + " \"" + inputDir + "-anim.png\"";
await AvProcess.RunFfmpeg(args, AvProcess.LogMode.OnlyLastLine);
if (delSrc)
DeleteSource(inputDir);
}
public static async void FramesToGif (string inputDir, bool opti, int fps, string prefix, bool delSrc)
{
int nums = IOUtils.GetFilenameCounterLength(Directory.GetFiles(inputDir, "*.png")[0], prefix);
string filter = "";
if (opti) filter = "-vf \"split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse\"";
string args = "-framerate " + fps + " -i \"" + inputDir + "\\" + prefix + "%0" + nums + "d.png\" -f gif " + filter + " \"" + inputDir + ".gif\"";
await AvProcess.RunFfmpeg(args, AvProcess.LogMode.OnlyLastLine);
if (delSrc)
DeleteSource(inputDir);
}
public static async Task LoopVideo (string inputFile, int times, bool delSrc)
{
string pathNoExt = Path.ChangeExtension(inputFile, null);
string ext = Path.GetExtension(inputFile);
string args = $" -stream_loop {times} -i {inputFile.Wrap()} -c copy \"{pathNoExt}-{times}xLoop{ext}\"";
await AvProcess.RunFfmpeg(args, AvProcess.LogMode.OnlyLastLine);
if (delSrc)
DeleteSource(inputFile);
}
public static async Task LoopVideoEnc (string inputFile, int times, bool useH265, int crf, bool delSrc)
{
string pathNoExt = Path.ChangeExtension(inputFile, null);
string ext = Path.GetExtension(inputFile);
string enc = "libx264";
if (useH265) enc = "libx265";
string args = " -stream_loop " + times + " -i \"" + inputFile + "\" -c:v " + enc + " -crf " + crf + " -c:a copy \"" + pathNoExt + "-" + times + "xLoop" + ext + "\"";
await AvProcess.RunFfmpeg(args, AvProcess.LogMode.OnlyLastLine);
if (delSrc)
DeleteSource(inputFile);
}
public static async Task ChangeSpeed (string inputFile, float newSpeedPercent, bool delSrc)
{
string pathNoExt = Path.ChangeExtension(inputFile, null);
string ext = Path.GetExtension(inputFile);
float val = newSpeedPercent / 100f;
string speedVal = (1f / val).ToString("0.0000").Replace(",", ".");
string args = " -itsscale " + speedVal + " -i \"" + inputFile + "\" -c copy \"" + pathNoExt + "-" + newSpeedPercent + "pcSpeed" + ext + "\"";
await AvProcess.RunFfmpeg(args, AvProcess.LogMode.OnlyLastLine);
if (delSrc)
DeleteSource(inputFile);
}
public static async Task Encode (string inputFile, string vcodec, string acodec, int crf, int audioKbps, bool delSrc)
{
string outPath = Path.ChangeExtension(inputFile, null) + "-convert.mp4";
string args = $" -i {inputFile.Wrap()} -c:v {vcodec} -crf {crf} -pix_fmt yuv420p -c:a {acodec} -b:a {audioKbps} {outPath.Wrap()}";
if (string.IsNullOrWhiteSpace(acodec))
args = args.Replace("-c:a", "-an");
if(audioKbps < 0)
args = args.Replace($" -b:a {audioKbps}", "");
await AvProcess.RunFfmpeg(args, AvProcess.LogMode.OnlyLastLine);
if (delSrc)
DeleteSource(inputFile);
}
public static async Task ExtractAudio (string inputFile, string outFile) // https://stackoverflow.com/a/27413824/14274419
{
Logger.Log($"[FFCmds] Extracting audio from {inputFile} to {outFile}", true);
string ext = GetAudioExt(inputFile);
outFile = Path.ChangeExtension(outFile, ext);
string args = $" -loglevel panic -i {inputFile.Wrap()} -vn -acodec copy {outFile.Wrap()}";
await AvProcess.RunFfmpeg(args, AvProcess.LogMode.Hidden);
if (AvProcess.lastOutputFfmpeg.ToLower().Contains("error") && File.Exists(outFile)) // If broken file was written
File.Delete(outFile);
}
static string GetAudioExt (string videoFile)
{
switch (GetAudioCodec(videoFile))
{
case "vorbis": return "ogg";
case "mp2": return "mp2";
default: return "m4a";
}
}
public static async Task MergeAudio(string inputFile, string audioPath, int looptimes = -1) // https://superuser.com/a/277667
{
Logger.Log($"[FFCmds] Merging audio from {audioPath} into {inputFile}", true);
string tempPath = inputFile + "-temp.mp4";
string args = $" -i {inputFile.Wrap()} -stream_loop {looptimes} -i {audioPath.Wrap()} -shortest -c copy {tempPath.Wrap()}";
await AvProcess.RunFfmpeg(args, AvProcess.LogMode.Hidden);
if(AvProcess.lastOutputFfmpeg.Contains("Invalid data"))
{
Logger.Log("Failed to merge audio!");
return;
}
File.Delete(inputFile);
File.Move(tempPath, inputFile);
}
public static float GetFramerate (string inputFile)
{
string args = $" -i {inputFile.Wrap()}";
string streamInfo = GetFirstStreamInfo(AvProcess.GetFfmpegOutput(args));
string[] entries = streamInfo.Split(',');
foreach(string entry in entries)
{
if (entry.Contains(" fps"))
{
Logger.Log("[FFCmds] FPS Entry: " + entry, true);
string num = entry.Replace(" fps", "").Trim().Replace(",", ".");
float value;
float.TryParse(num, NumberStyles.Any, CultureInfo.InvariantCulture, out value);
return value;
}
}
return 0f;
}
public static Size GetSize (string inputFile)
{
string args = $" -v error -select_streams v:0 -show_entries stream=width,height -of csv=s=x:p=0 {inputFile.Wrap()}";
string output = AvProcess.GetFfprobeOutput(args);
if (output.Length > 4 && output.Contains("x"))
{
string[] numbers = output.Split('x');
return new Size(numbers[0].GetInt(), numbers[1].GetInt());
}
return new Size(0, 0);
}
public static int GetFrameCount(string inputFile)
{
int frames = 0;
frames = ReadFrameCountFfprobe(inputFile, Config.GetBool("ffprobeCountFrames")); // Try reading frame count with ffprobe
if (frames > 0)
return frames;
frames = ReadFrameCountFfmpeg(inputFile); // Try reading frame count with ffmpeg
if (frames > 0)
return frames;
Logger.Log("Failed to get total frame count of video.");
return 0;
}
static int ReadFrameCountFfprobe (string inputFile, bool readFramesSlow)
{
string args = $" -v panic -select_streams v:0 -show_entries stream=nb_frames -of default=noprint_wrappers=1 {inputFile.Wrap()}";
if (readFramesSlow)
{
Logger.Log("Counting total frames using FFprobe. This can take a moment...");
args = $" -v panic -count_frames -select_streams v:0 -show_entries stream=nb_read_frames -of default=nokey=1:noprint_wrappers=1 {inputFile.Wrap()}";
}
string info = AvProcess.GetFfprobeOutput(args);
string[] entries = info.SplitIntoLines();
try
{
Logger.Log("[FFCmds] ReadFrameCountFfprobe - ffprobe output: " + info, true);
if (readFramesSlow)
return info.GetInt();
foreach (string entry in entries)
{
if (entry.Contains("nb_frames="))
{
Logger.Log("[FFCmds] Getting Int from " + entry, true);
return entry.GetInt();
}
}
}
catch { }
return -1;
}
static int ReadFrameCountFfmpeg(string inputFile)
{
string args = $" -loglevel panic -i {inputFile.Wrap()} -map 0:v:0 -c copy -f null - ";
string info = AvProcess.GetFfmpegOutput(args);
string[] entries = info.SplitIntoLines();
foreach (string entry in entries)
{
if (entry.Contains("frame="))
{
Logger.Log("[FFCmds] Getting Int from entry " + entry, true);
Logger.Log("[FFCmds] Getting Int from " + entry.Substring(0, entry.IndexOf("fps")), true);
return entry.Substring(0, entry.IndexOf("fps")).GetInt();
}
}
return -1;
}
static string GetAudioCodec (string path)
{
string args = $" -v panic -show_streams -select_streams a -show_entries stream=codec_name {path.Wrap()}";
string info = AvProcess.GetFfprobeOutput(args);
string[] entries = info.SplitIntoLines();
foreach (string entry in entries)
{
if (entry.Contains("codec_name="))
{
Logger.Log($"[FFCmds] Audio Codec Entry: {entry}", true);
return entry.Split('=')[1];
}
}
return "";
}
static string GetFirstStreamInfo (string ffmpegOutput)
{
foreach (string line in Regex.Split(ffmpegOutput, "\r\n|\r|\n"))
{
if (line.Contains("Stream #0"))
return line;
}
return "";
}
static void DeleteSource (string path)
{
Logger.Log("Deleting input file/dir: " + path);
if (IOUtils.IsPathDirectory(path) && Directory.Exists(path))
Directory.Delete(path, true);
if (!IOUtils.IsPathDirectory(path) && File.Exists(path))
File.Delete(path);
}
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Flowframes
{
class FFmpegStrings
{
public static string hdrFilter = @"-vf select=gte(n\,%frNum%),zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p";
}
}

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Flowframes.FFmpeg
{
class GifskiCommands
{
public static async Task CreateGifFromFrames (int fps, int quality, string framespath, string outpath)
{
Logger.Log($"Creating GIF from frames using quality {quality}...");
await AvProcess.RunGifski($" -r {fps} -W 4096 -Q {quality} -o \"{outpath}\" \"{framespath}/\"*.\"png\"", AvProcess.LogMode.OnlyLastLine);
}
}
}

28
Code/Data/AI.cs Normal file
View File

@@ -0,0 +1,28 @@
using Flowframes.IO;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Flowframes.Data
{
public struct AI
{
public string aiName;
public string aiNameShort;
public string friendlyName;
public string description;
public FlowPackage pkg;
public AI(string aiNameArg, string friendlyNameArg, string descArg, FlowPackage pkgArg)
{
aiName = aiNameArg;
aiNameShort = aiNameArg.Split(' ')[0];
aiNameShort = aiNameArg.Split('_')[0];
friendlyName = friendlyNameArg;
description = descArg;
pkg = pkgArg;
}
}
}

29
Code/Data/BatchEntry.cs Normal file
View File

@@ -0,0 +1,29 @@
using Flowframes.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Flowframes
{
public struct BatchEntry
{
public string inPath;
public string outPath;
public AI ai;
public float inFps;
public int interpFactor;
public Interpolate.OutMode outMode;
public BatchEntry(string inPathArg, string outPathArg, AI aiArg, float inFpsArg, int interpFactorArg, Interpolate.OutMode outModeArg)
{
inPath = inPathArg;
outPath = outPathArg;
ai = aiArg;
inFps = inFpsArg;
interpFactor = interpFactorArg;
outMode = outModeArg;
}
}
}

24
Code/Data/FlowPackage.cs Normal file
View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Flowframes.IO
{
public struct FlowPackage
{
public string friendlyName;
public string fileName;
public int downloadSizeMb;
public string desc;
public FlowPackage(string friendlyNameStr, string fileNameStr, int downloadSizeMbInt, string description)
{
friendlyName = friendlyNameStr;
fileName = fileNameStr;
downloadSizeMb = downloadSizeMbInt;
desc = description;
}
}
}

26
Code/Data/Networks.cs Normal file
View File

@@ -0,0 +1,26 @@
using Flowframes.IO;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Flowframes.Data
{
class Networks
{
public static AI rifeCuda = new AI("RIFE_CUDA", "RIFE", "Pytorch Implementation of RIFE", Packages.rifeCuda);
public static AI dainNcnn = new AI("DAIN_NCNN", "DAIN (NCNN)", "Vulkan/NCNN Implementation of DAIN", Packages.dainNcnn);
public static AI cainNcnn = new AI("CAIN_NCNN", "CAIN (NCNN)", "Vulkan/NCNN Implementation of CAIN", Packages.cainNcnn);
public static List<AI> networks = new List<AI>();
public static void Init ()
{
networks.Clear();
networks.Add(rifeCuda);
networks.Add(dainNcnn);
networks.Add(cainNcnn);
}
}
}

18
Code/Data/Packages.cs Normal file
View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Flowframes.IO
{
class Packages
{
public static FlowPackage dainNcnn = new FlowPackage("DAIN-NCNN (AMD/Nvidia)", "dain-ncnn.7z", 40, "NCNN/Vulkan implementation of DAIN. Very slow and VRAM-hungry.");
public static FlowPackage cainNcnn = new FlowPackage("CAIN-NCNN (AMD/Nvidia)", "cain-ncnn.7z", 75, "NCNN/Vulkan implementation of CAIN. About 8x faster than DAIN and very lightweight on VRAM.");
public static FlowPackage rifeCuda = new FlowPackage("RIFE (Nvidia)", "rife-cuda.7z", 50, "Pytorch implementation of RIFE. Very fast (~2x CAIN, >16x DAIN) and not too VRAM-heavy.");
public static FlowPackage python = new FlowPackage("Python Runtime", "py.7z", 640, "Embedded Python runtime including Pytorch and all other dependencies. Install this if you don't have system Python.");
public static FlowPackage audioVideo = new FlowPackage("Audio/Video Tools (Required)", "av.7z", 10, "Utilities for extracting frames, analysing videos, encoding videos and GIFs.");
public static FlowPackage licenses = new FlowPackage("Licenses (Required)", "licenses.7z", 1, "License files for redistributed software.");
}
}

117
Code/ExtensionMethods.cs Normal file
View File

@@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Flowframes
{
public static class ExtensionMethods
{
public static string TrimNumbers(this string s, bool allowDotComma = false)
{
if(!allowDotComma)
s = Regex.Replace(s, "[^0-9]", "");
else
s = Regex.Replace(s, "[^.,0-9]", "");
return s.Trim();
}
public static int GetInt(this TextBox textbox)
{
return GetInt(textbox.Text);
}
public static int GetInt(this ComboBox combobox)
{
return GetInt(combobox.Text);
}
public static int GetInt (this string str)
{
if (str.Length < 1 || str == null)
return 0;
try { return int.Parse(str.TrimNumbers()); }
catch (Exception e)
{
Logger.Log("Failed to parse \"" + str + "\" to int: " + e, true);
return 0;
}
}
public static float GetFloat(this TextBox textbox)
{
return GetFloat(textbox.Text);
}
public static float GetFloat(this ComboBox combobox)
{
return GetFloat(combobox.Text);
}
public static float GetFloat (this string str)
{
if (str.Length < 1 || str == null)
return 0f;
string num = str.TrimNumbers(true).Replace(",", ".");
float value;
float.TryParse(num, NumberStyles.Any, CultureInfo.InvariantCulture, out value);
return value;
}
public static string Wrap(this string path, bool addSpaceFront = false, bool addSpaceEnd = false)
{
string s = "\"" + path + "\"";
if (addSpaceFront)
s = " " + s;
if (addSpaceEnd)
s = s + " ";
return s;
}
public static string GetParentDir(this string path)
{
return Directory.GetParent(path).FullName;
}
public static int RoundToInt(this float f)
{
return (int)Math.Round(f);
}
public static int Clamp(this int i, int min, int max)
{
if (i < min)
i = min;
if (i > max)
i = max;
return i;
}
public static string[] SplitIntoLines (this string str)
{
return Regex.Split(str, "\r\n|\r|\n");
}
public static string Trunc (this string value, int maxChars)
{
return value.Length <= maxChars ? value : value.Substring(0, maxChars) + "…";
}
public static string StripBadChars (this string str)
{
string outStr = Regex.Replace(str, @"[^\u0020-\u007E]", string.Empty);
outStr = outStr.Replace("(", "").Replace(")", "").Replace("[", "").Replace("]", "").Replace("{", "").Replace("}", "").Replace("%", "");
return outStr;
}
public static string StripNumbers (this string str)
{
return new string(str.Where(c => c != '-' && (c < '0' || c > '9')).ToArray());
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

313
Code/Flowframes.csproj Normal file
View File

@@ -0,0 +1,313 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="packages\Costura.Fody.4.1.0\build\Costura.Fody.props" Condition="Exists('packages\Costura.Fody.4.1.0\build\Costura.Fody.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{389E42DD-A163-49D7-9E0A-AE41090A07B3}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>Flowframes</RootNamespace>
<AssemblyName>Flowframes</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<IsWebBootstrapper>false</IsWebBootstrapper>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>x64</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>flowframesIcoNew.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="7z.NET, Version=1.0.3.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>packages\7z.NET.1.0.3\lib\net463\7z.NET.dll</HintPath>
</Reference>
<Reference Include="CircularProgressBar, Version=2.8.0.16, Culture=neutral, PublicKeyToken=310fd07b25df79b3, processorArchitecture=MSIL">
<HintPath>packages\CircularProgressBar.2.8.0.16\lib\net40\CircularProgressBar.dll</HintPath>
</Reference>
<Reference Include="Costura, Version=4.1.0.0, Culture=neutral, PublicKeyToken=9919ef960d84173d, processorArchitecture=MSIL">
<HintPath>packages\Costura.Fody.4.1.0\lib\net40\Costura.dll</HintPath>
</Reference>
<Reference Include="CustomMarshalers" />
<Reference Include="Cyotek.Windows.Forms.TabList, Version=2.0.0.0, Culture=neutral, PublicKeyToken=58daa28b0b2de221, processorArchitecture=MSIL">
<HintPath>packages\CyotekTabList.2.0.0\lib\net35\Cyotek.Windows.Forms.TabList.dll</HintPath>
</Reference>
<Reference Include="DiskDetector, Version=0.3.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>packages\diskdetector-net.0.3.2\lib\netstandard2.0\DiskDetector.dll</HintPath>
</Reference>
<Reference Include="HTAlt WinForms, Version=0.1.6.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>packages\HTAlt.WinForms.0.1.6\lib\net461\HTAlt WinForms.dll</HintPath>
</Reference>
<Reference Include="HTAlt.Standart, Version=0.1.6.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>packages\HTAlt.Standart.0.1.6\lib\netstandard2.0\HTAlt.Standart.dll</HintPath>
</Reference>
<Reference Include="Magick.NET-Q16-AnyCPU, Version=7.21.1.0, Culture=neutral, PublicKeyToken=2004825badfa91ec, processorArchitecture=MSIL">
<HintPath>packages\Magick.NET-Q16-AnyCPU.7.21.1\lib\net40\Magick.NET-Q16-AnyCPU.dll</HintPath>
</Reference>
<Reference Include="Magick.NET.Core, Version=4.1.0.0, Culture=neutral, PublicKeyToken=2004825badfa91ec, processorArchitecture=MSIL">
<HintPath>packages\Magick.NET.Core.4.1.0\lib\net40\Magick.NET.Core.dll</HintPath>
</Reference>
<Reference Include="Microsoft.WindowsAPICodePack, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>packages\WindowsAPICodePack-Core.1.1.1\lib\Microsoft.WindowsAPICodePack.dll</HintPath>
</Reference>
<Reference Include="Microsoft.WindowsAPICodePack.Shell, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>packages\WindowsAPICodePack-Shell.1.1.1\lib\Microsoft.WindowsAPICodePack.Shell.dll</HintPath>
</Reference>
<Reference Include="NvAPIWrapper, Version=0.8.0.98, Culture=neutral, PublicKeyToken=310fd07b25df79b3, processorArchitecture=MSIL">
<HintPath>packages\NvAPIWrapper.Net.0.8.0.98\lib\net45\NvAPIWrapper.dll</HintPath>
</Reference>
<Reference Include="PagedControl, Version=2.2.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>packages\PagedControl.2.2.0\lib\net35\PagedControl.dll</HintPath>
</Reference>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Design" />
<Reference Include="System.Drawing.Common, Version=4.0.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>packages\System.Drawing.Common.5.0.0\lib\net461\System.Drawing.Common.dll</HintPath>
</Reference>
<Reference Include="System.Management" />
<Reference Include="System.Numerics" />
<Reference Include="System.Security.Claims, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Security.Claims.4.3.0\lib\net46\System.Security.Claims.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Security.Principal.Windows, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Security.Principal.Windows.4.3.0\lib\net46\System.Security.Principal.Windows.dll</HintPath>
</Reference>
<Reference Include="System.Xaml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="TabControl, Version=2.1.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>packages\TabControl.2.1.2\lib\net35\TabControl.dll</HintPath>
</Reference>
<Reference Include="Win32Interop.Dwmapi, Version=1.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>packages\Win32Interop.Dwmapi.1.0.1\lib\Win32Interop.Dwmapi.dll</HintPath>
</Reference>
<Reference Include="Win32Interop.Gdi32, Version=1.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>packages\Win32Interop.Gdi32.1.0.1\lib\Win32Interop.Gdi32.dll</HintPath>
</Reference>
<Reference Include="Win32Interop.Kernel32, Version=1.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>packages\Win32Interop.Kernel32.1.0.1\lib\Win32Interop.Kernel32.dll</HintPath>
</Reference>
<Reference Include="Win32Interop.User32, Version=1.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>packages\Win32Interop.User32.1.0.1\lib\Win32Interop.User32.dll</HintPath>
</Reference>
<Reference Include="Win32Interop.Uxtheme, Version=1.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>packages\Win32Interop.Uxtheme.1.0.1\lib\Win32Interop.Uxtheme.dll</HintPath>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="WindowsFormsIntegration" />
<Reference Include="WinFormAnimation, Version=1.6.0.4, Culture=neutral, PublicKeyToken=310fd07b25df79b3, processorArchitecture=MSIL">
<HintPath>packages\WinFormAnimation.1.6.0.4\lib\net40\WinFormAnimation.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="AudioVideo\GifskiCommands.cs" />
<Compile Include="Data\AI.cs" />
<Compile Include="Data\BatchEntry.cs" />
<Compile Include="Data\Networks.cs" />
<Compile Include="Forms\BatchForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\BatchForm.Designer.cs">
<DependentUpon>BatchForm.cs</DependentUpon>
</Compile>
<Compile Include="Forms\BigPreviewForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\BigPreviewForm.Designer.cs">
<DependentUpon>BigPreviewForm.cs</DependentUpon>
</Compile>
<Compile Include="Forms\InstallerForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\InstallerForm.Designer.cs">
<DependentUpon>InstallerForm.cs</DependentUpon>
</Compile>
<Compile Include="Forms\SettingsForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\SettingsForm.Designer.cs">
<DependentUpon>SettingsForm.cs</DependentUpon>
</Compile>
<Compile Include="Forms\UpdaterForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\UpdaterForm.Designer.cs">
<DependentUpon>UpdaterForm.cs</DependentUpon>
</Compile>
<Compile Include="IO\ConfigParser.cs" />
<Compile Include="Data\FlowPackage.cs" />
<Compile Include="IO\PkgInstaller.cs" />
<Compile Include="Data\Packages.cs" />
<Compile Include="Main\BatchProcessing.cs" />
<Compile Include="Main\CreateVideo.cs" />
<Compile Include="Main\InterpolateUtils.cs" />
<Compile Include="OS\AiProcess.cs" />
<Compile Include="ExtensionMethods.cs" />
<Compile Include="AudioVideo\AvProcess.cs" />
<Compile Include="AudioVideo\FFmpegCommands.cs" />
<Compile Include="AudioVideo\FFmpegStrings.cs" />
<Compile Include="Form1.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Form1.Designer.cs">
<DependentUpon>Form1.cs</DependentUpon>
</Compile>
<Compile Include="Main\Interpolate.cs" />
<Compile Include="IO\CfgStrings.cs" />
<Compile Include="IO\Config.cs" />
<Compile Include="IO\Formats.cs" />
<Compile Include="IO\IOUtils.cs" />
<Compile Include="IO\Paths.cs" />
<Compile Include="Logger.cs" />
<Compile Include="Magick\Coverter.cs" />
<Compile Include="Magick\FrameDedup.cs" />
<Compile Include="OS\NvApi.cs" />
<Compile Include="OS\OSUtils.cs" />
<Compile Include="OS\Python.cs" />
<Compile Include="OS\Updater.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="IO\Setup.cs" />
<Compile Include="UI\FormatUtils.cs" />
<Compile Include="UI\UIUtils.cs" />
<Compile Include="UI\UtilsTab.cs" />
<EmbeddedResource Include="Form1.resx">
<DependentUpon>Form1.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\BatchForm.resx">
<DependentUpon>BatchForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\BigPreviewForm.resx">
<DependentUpon>BigPreviewForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\InstallerForm.resx">
<DependentUpon>InstallerForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\SettingsForm.resx">
<DependentUpon>SettingsForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\UpdaterForm.resx">
<DependentUpon>UpdaterForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.7.2">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.7.2 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<Content Include="FlowFramesFunkyLogo1.ico" />
<Content Include="FlowFramesFunkyLogo2.ico" />
<None Include="Resources\questmark-72px-bordeer.png" />
<None Include="Resources\7za.exe" />
<None Include="Resources\baseline_fact_check_white_48dp.png" />
<None Include="Resources\discordIco.png" />
<None Include="Resources\paypal256px.png" />
<None Include="Resources\patreon256px.png" />
<None Include="Resources\baseline_settings_white_48dp.png" />
<None Include="Resources\baseline_image_white_48dp.png" />
<None Include="Resources\baseline_image_white_48dp-4x.png" />
<None Include="Resources\baseline_image_white_48dp-4x-25pcAlpha.png" />
<None Include="Resources\baseline_queue_white_48dp.png" />
<None Include="Resources\separatorTest1.png" />
<None Include="Resources\discordIcoColored.png" />
<None Include="Resources\patreon256pxColored.png" />
<None Include="Resources\baseline_create_white_18dp.png" />
<None Include="Resources\baseline_create_white_18dp-semiTransparent.png" />
<Content Include="flowframesIcoNew.ico" />
<None Include="Resources\baseline_system_update_alt_white_48dp.png" />
<None Include="Resources\baseline_system_update_alt_white_48dp1.png" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('packages\Costura.Fody.4.1.0\build\Costura.Fody.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Costura.Fody.4.1.0\build\Costura.Fody.props'))" />
<Error Condition="!Exists('packages\7z.NET.1.0.3\build\7z.NET.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\7z.NET.1.0.3\build\7z.NET.targets'))" />
<Error Condition="!Exists('packages\Fody.6.3.0\build\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Fody.6.3.0\build\Fody.targets'))" />
</Target>
<Import Project="packages\7z.NET.1.0.3\build\7z.NET.targets" Condition="Exists('packages\7z.NET.1.0.3\build\7z.NET.targets')" />
<Import Project="packages\Fody.6.3.0\build\Fody.targets" Condition="Exists('packages\Fody.6.3.0\build\Fody.targets')" />
</Project>

25
Code/Flowframes.sln Normal file
View File

@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30413.136
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flowframes", "Flowframes.csproj", "{389E42DD-A163-49D7-9E0A-AE41090A07B3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{389E42DD-A163-49D7-9E0A-AE41090A07B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{389E42DD-A163-49D7-9E0A-AE41090A07B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{389E42DD-A163-49D7-9E0A-AE41090A07B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{389E42DD-A163-49D7-9E0A-AE41090A07B3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4622DEE4-C34E-4439-A743-7B534210FDFA}
EndGlobalSection
EndGlobal

3
Code/FodyWeavers.xml Normal file
View File

@@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<Costura />
</Weavers>

111
Code/FodyWeavers.xsd Normal file
View File

@@ -0,0 +1,111 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="Costura" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:all>
<xs:attribute name="CreateTemporaryAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeDebugSymbols" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls if .pdbs for reference assemblies are also embedded.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCompression" type="xs:boolean">
<xs:annotation>
<xs:documentation>Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCleanup" type="xs:boolean">
<xs:annotation>
<xs:documentation>As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="LoadAtModuleInit" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IgnoreSatelliteAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

1336
Code/Form1.Designer.cs generated Normal file

File diff suppressed because it is too large Load Diff

366
Code/Form1.cs Normal file
View File

@@ -0,0 +1,366 @@
using Flowframes.Forms;
using Flowframes.IO;
using Flowframes.Magick;
using Flowframes.Main;
using Flowframes.OS;
using Flowframes.UI;
using Microsoft.WindowsAPICodePack.Dialogs;
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using HTAlt.WinForms;
using Flowframes.Data;
namespace Flowframes
{
public partial class Form1 : Form
{
public bool initialized = false;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
CheckForIllegalCrossThreadCalls = false;
Text = $"Flowframes v{Program.version}";
// Main Tab
UIUtils.InitCombox(interpFactorCombox, 0);
UIUtils.InitCombox(outModeCombox, 0);
UIUtils.InitCombox(tilesizeComboxDain, 3);
UIUtils.InitCombox(tilesizeComboxCain, 4);
// Video Utils
UIUtils.InitCombox(utilsLoopTimesCombox, 0);
UIUtils.InitCombox(utilsSpeedCombox, 0);
UIUtils.InitCombox(utilsConvCrf, 0);
//aiCombox_SelectedIndexChanged(null, null);
Program.mainForm = this;
Logger.textbox = logBox;
InitAis();
InterpolateUtils.preview = previewPicturebox;
ConfigParser.LoadComboxIndex(aiCombox);
Setup.Init();
Initialized();
Updater.AsyncUpdateCheck();
}
public HTTabControl GetMainTabControl() { return mainTabControl; }
public bool IsInFocus() { return (ActiveForm == this); }
public BatchEntry GetBatchEntry()
{
return new BatchEntry(inputTbox.Text.Trim(), outputTbox.Text.Trim(), GetAi(), fpsInTbox.GetFloat(), interpFactorCombox.GetInt(), GetOutMode());
}
public void LoadBatchEntry(BatchEntry entry)
{
inputTbox.Text = entry.inPath;
outputTbox.Text = entry.outPath;
interpFactorCombox.Text = entry.interpFactor.ToString();
aiCombox.SelectedIndex = Networks.networks.IndexOf(entry.ai);
SetOutMode(entry.outMode);
}
public void SetStatus(string str)
{
Logger.Log(str, true);
statusLabel.Text = str;
}
public void SetProgress(int percent)
{
longProgBar.Value = percent.Clamp(0, 100);
longProgBar.Refresh();
}
void InitAis()
{
foreach (AI ai in Networks.networks)
aiCombox.Items.Add(ai.friendlyName + " - " + ai.description);
aiCombox.SelectedIndex = 0;
}
public void Initialized()
{
initialized = true;
runBtn.Enabled = true;
}
private void browseInputBtn_Click(object sender, EventArgs e)
{
CommonOpenFileDialog dialog = new CommonOpenFileDialog();
dialog.InitialDirectory = inputTbox.Text.Trim();
dialog.IsFolderPicker = true;
if (dialog.ShowDialog() == CommonFileDialogResult.Ok)
{
inputTbox.Text = dialog.FileName;
InitInput();
}
}
private void browseInputFileBtn_Click(object sender, EventArgs e)
{
CommonOpenFileDialog dialog = new CommonOpenFileDialog();
dialog.InitialDirectory = inputTbox.Text.Trim();
dialog.IsFolderPicker = false;
if (dialog.ShowDialog() == CommonFileDialogResult.Ok)
{
inputTbox.Text = dialog.FileName;
InitInput();
}
}
void InitInput()
{
outputTbox.Text = inputTbox.Text.Trim().GetParentDir();
string path = inputTbox.Text.Trim();
Program.lastInputPath = path;
float fps = IOUtils.GetFpsFolderOrVideo(path);
string 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)}");
}
private void browseOutBtn_Click(object sender, EventArgs e)
{
CommonOpenFileDialog dialog = new CommonOpenFileDialog();
dialog.InitialDirectory = inputTbox.Text.Trim();
dialog.IsFolderPicker = true;
if (dialog.ShowDialog() == CommonFileDialogResult.Ok)
outputTbox.Text = dialog.FileName;
}
public void runBtn_Click(object sender, EventArgs e)
{
if (!BatchProcessing.busy)
mainTabControl.SelectedIndex = 0;
if (fpsInTbox.Visible)
Interpolate.SetFps(fpsInTbox.GetFloat());
if (interpFactorCombox.Visible)
Interpolate.interpFactor = interpFactorCombox.GetInt();
string inPath = inputTbox.Text.Trim();
string outPath = outputTbox.Text.Trim();
Interpolate.OutMode outMode = GetOutMode();
AI ai = GetAi();
int tilesize = tilesizeComboxDain.GetInt();
if (ai.aiName == Networks.cainNcnn.aiName)
tilesize = tilesizeComboxCain.GetInt();
Interpolate.Start(inPath, outPath, tilesize, outMode, ai);
}
Interpolate.OutMode GetOutMode()
{
Interpolate.OutMode outMode = Interpolate.OutMode.VidMp4;
if (outModeCombox.Text.ToLower().Contains("gif")) outMode = Interpolate.OutMode.VidGif;
if (outModeCombox.Text.ToLower().Contains("png")) outMode = Interpolate.OutMode.ImgPng;
return outMode;
}
public void SetOutMode(Interpolate.OutMode mode)
{
if (mode == Interpolate.OutMode.VidMp4) outModeCombox.SelectedIndex = 0;
if (mode == Interpolate.OutMode.VidGif) outModeCombox.SelectedIndex = 1;
if (mode == Interpolate.OutMode.ImgPng) outModeCombox.SelectedIndex = 2;
}
AI GetAi()
{
return Networks.networks[aiCombox.SelectedIndex];
}
void inputTbox_DragEnter(object sender, DragEventArgs e) { e.Effect = DragDropEffects.Copy; }
private void inputTbox_DragDrop(object sender, DragEventArgs e)
{
if (Program.busy) return;
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
inputTbox.Text = files[0];
InitInput();
//FFmpegCommands.GetFramerate(inputTbox.Text);
}
void outputTbox_DragEnter(object sender, DragEventArgs e) { e.Effect = DragDropEffects.Copy; }
private void outputTbox_DragDrop(object sender, DragEventArgs e)
{
if (Program.busy) return;
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
outputTbox.Text = files[0];
}
private void fpsInTbox_TextChanged(object sender, EventArgs e)
{
fpsInTbox.Text = fpsInTbox.Text.TrimNumbers(true);
Interpolate.SetFps(fpsInTbox.GetFloat());
UpdateOutputFPS();
}
public void UpdateOutputFPS()
{
float fpsOut = fpsInTbox.GetFloat() * interpFactorCombox.GetFloat();
fpsOutTbox.Text = fpsOut.ToString();
Interpolate.interpFactor = interpFactorCombox.GetInt();
}
private void interpFactorCombox_SelectedIndexChanged(object sender, EventArgs e)
{
if (initialized && GetAi().aiName == Networks.cainNcnn.aiName && interpFactorCombox.SelectedIndex != 0)
{
//MessageBox.Show("CAIN currently only supports x2 interpolation.");
//interpFactorCombox.SelectedIndex = 0; // TODO: Add CAIN 4x/8x workaround
}
UpdateOutputFPS();
}
public void SetWorking(bool state)
{
Control[] controlsToDisable = new Control[] { runBtn, settingsBtn, installerBtn };
Program.busy = state;
foreach (Control c in controlsToDisable)
c.Enabled = !state;
cancelBtn.Visible = state;
progressCircle.Visible = state;
}
private void aiCombox_SelectedIndexChanged(object sender, EventArgs e)
{
tilesizeComboxCain.Visible = GetAi().aiName == Networks.cainNcnn.aiName;
tilesizeComboxDain.Visible = GetAi().aiName == Networks.dainNcnn.aiName;
tileSizeInfoLabel.Visible = (tilesizeComboxCain.Visible || tilesizeComboxDain.Visible);
tilesizeNotAvailLabel.Visible = !tileSizeInfoLabel.Visible;
interpFactorCombox_SelectedIndexChanged(null, null);
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
ConfigParser.SaveComboxIndex(aiCombox);
}
private async void debugExtractFramesBtn_Click(object sender, EventArgs e)
{
await UtilsTab.ExtractVideo(inputTbox.Text.Trim(), utilsExtractAudioCbox.Checked);
}
private void licenseBtn_Click(object sender, EventArgs e)
{
Process.Start("explorer.exe", Path.Combine(Paths.GetPkgPath(), Path.GetFileNameWithoutExtension(Packages.licenses.fileName)));
}
private async void utilsLoopVidBtn_Click(object sender, EventArgs e)
{
await UtilsTab.LoopVideo(inputTbox.Text.Trim(), utilsLoopTimesCombox);
}
private async void utilsChangeSpeedBtn_Click(object sender, EventArgs e)
{
await UtilsTab.ChangeSpeed(inputTbox.Text.Trim(), utilsSpeedCombox);
}
private void Form1_DragEnter(object sender, DragEventArgs e) { e.Effect = DragDropEffects.Copy; }
private void Form1_DragDrop(object sender, DragEventArgs e)
{
if (Program.busy) return;
mainTabControl.SelectedIndex = 0; // Select main tab
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
inputTbox.Text = files[0];
Logger.Log("Selected video/directory: " + Path.GetFileName(files[0]));
InitInput();
}
private async void utilsConvertMp4Btn_Click(object sender, EventArgs e)
{
await UtilsTab.Convert(inputTbox.Text.Trim(), utilsConvCrf);
}
private void utilsDedupBtn_Click(object sender, EventArgs e)
{
UtilsTab.Dedupe(inputTbox.Text.Trim(), false);
}
private void utilsDedupTestBtn_Click(object sender, EventArgs e)
{
UtilsTab.Dedupe(inputTbox.Text.Trim(), true);
}
private void installerBtn_Click(object sender, EventArgs e)
{
new InstallerForm().ShowDialog();
}
private void cancelBtn_Click(object sender, EventArgs e)
{
mainTabControl.SelectedIndex = 0;
Interpolate.Cancel();
}
private void discordBtn_Click(object sender, EventArgs e)
{
Process.Start("https://discord.gg/eJHD2NSJRe");
}
private void paypalBtn_Click(object sender, EventArgs e)
{
Process.Start("https://www.paypal.com/paypalme/nmkd/10");
}
private void patreonBtn_Click(object sender, EventArgs e)
{
Process.Start("https://patreon.com/n00mkrad");
}
private void settingsBtn_Click(object sender, EventArgs e)
{
new SettingsForm().ShowDialog();
}
private void queueBtn_Click(object sender, EventArgs e)
{
if (BatchProcessing.currentBatchForm != null)
{
BatchProcessing.currentBatchForm.WindowState = FormWindowState.Normal;
BatchProcessing.currentBatchForm.BringToFront();
}
else
{
new BatchForm().Show();
}
}
private void previewPicturebox_MouseClick(object sender, MouseEventArgs e)
{
if (InterpolateUtils.bigPreviewForm == null)
{
InterpolateUtils.bigPreviewForm = new BigPreviewForm();
InterpolateUtils.bigPreviewForm.Show();
InterpolateUtils.bigPreviewForm.SetImage(previewPicturebox.Image);
}
}
private async void updateBtn_Click(object sender, EventArgs e)
{
new UpdaterForm().ShowDialog();
}
}
}

2465
Code/Form1.resx Normal file

File diff suppressed because it is too large Load Diff

225
Code/Forms/BatchForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,225 @@
namespace Flowframes.Forms
{
partial class BatchForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(BatchForm));
this.titleLabel = new System.Windows.Forms.Label();
this.stopBtn = new System.Windows.Forms.Button();
this.runBtn = new System.Windows.Forms.Button();
this.addToQueue = new System.Windows.Forms.Button();
this.forceStopBtn = new System.Windows.Forms.Button();
this.clearBtn = new System.Windows.Forms.Button();
this.taskList = new System.Windows.Forms.ListBox();
this.clearSelectedBtn = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.panel1 = new System.Windows.Forms.Panel();
this.panel1.SuspendLayout();
this.SuspendLayout();
//
// titleLabel
//
this.titleLabel.AutoSize = true;
this.titleLabel.Font = new System.Drawing.Font("Yu Gothic UI", 21.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.titleLabel.ForeColor = System.Drawing.Color.White;
this.titleLabel.Location = new System.Drawing.Point(12, 9);
this.titleLabel.Margin = new System.Windows.Forms.Padding(3, 0, 3, 10);
this.titleLabel.Name = "titleLabel";
this.titleLabel.Size = new System.Drawing.Size(323, 40);
this.titleLabel.TabIndex = 1;
this.titleLabel.Text = "Batch Processing Queue";
//
// stopBtn
//
this.stopBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.stopBtn.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(48)))), ((int)(((byte)(48)))), ((int)(((byte)(48)))));
this.stopBtn.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.stopBtn.ForeColor = System.Drawing.Color.White;
this.stopBtn.Location = new System.Drawing.Point(682, 351);
this.stopBtn.Name = "stopBtn";
this.stopBtn.Size = new System.Drawing.Size(250, 40);
this.stopBtn.TabIndex = 35;
this.stopBtn.Text = "Stop After Current Task";
this.stopBtn.UseVisualStyleBackColor = false;
this.stopBtn.Visible = false;
this.stopBtn.Click += new System.EventHandler(this.stopBtn_Click);
//
// runBtn
//
this.runBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.runBtn.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(48)))), ((int)(((byte)(48)))), ((int)(((byte)(48)))));
this.runBtn.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.runBtn.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.runBtn.ForeColor = System.Drawing.Color.White;
this.runBtn.Location = new System.Drawing.Point(682, 443);
this.runBtn.Name = "runBtn";
this.runBtn.Size = new System.Drawing.Size(250, 40);
this.runBtn.TabIndex = 36;
this.runBtn.Text = "Start";
this.runBtn.UseVisualStyleBackColor = false;
this.runBtn.Click += new System.EventHandler(this.runBtn_Click);
//
// addToQueue
//
this.addToQueue.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.addToQueue.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(48)))), ((int)(((byte)(48)))), ((int)(((byte)(48)))));
this.addToQueue.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.addToQueue.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.addToQueue.ForeColor = System.Drawing.Color.White;
this.addToQueue.Location = new System.Drawing.Point(682, 65);
this.addToQueue.Name = "addToQueue";
this.addToQueue.Size = new System.Drawing.Size(250, 40);
this.addToQueue.TabIndex = 39;
this.addToQueue.Text = "Add Current Configuration To Queue";
this.addToQueue.UseVisualStyleBackColor = false;
this.addToQueue.Click += new System.EventHandler(this.addToQueue_Click);
//
// forceStopBtn
//
this.forceStopBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.forceStopBtn.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(48)))), ((int)(((byte)(48)))), ((int)(((byte)(48)))));
this.forceStopBtn.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.forceStopBtn.ForeColor = System.Drawing.Color.White;
this.forceStopBtn.Location = new System.Drawing.Point(682, 397);
this.forceStopBtn.Name = "forceStopBtn";
this.forceStopBtn.Size = new System.Drawing.Size(250, 40);
this.forceStopBtn.TabIndex = 40;
this.forceStopBtn.Text = "Force Stop Now";
this.forceStopBtn.UseVisualStyleBackColor = false;
this.forceStopBtn.Visible = false;
this.forceStopBtn.Click += new System.EventHandler(this.forceStopBtn_Click);
//
// clearBtn
//
this.clearBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.clearBtn.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(48)))), ((int)(((byte)(48)))), ((int)(((byte)(48)))));
this.clearBtn.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.clearBtn.ForeColor = System.Drawing.Color.White;
this.clearBtn.Location = new System.Drawing.Point(682, 157);
this.clearBtn.Name = "clearBtn";
this.clearBtn.Size = new System.Drawing.Size(250, 40);
this.clearBtn.TabIndex = 41;
this.clearBtn.Text = "Clear All Queue Entries";
this.clearBtn.UseVisualStyleBackColor = false;
this.clearBtn.Click += new System.EventHandler(this.clearBtn_Click);
//
// taskList
//
this.taskList.AllowDrop = true;
this.taskList.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(48)))), ((int)(((byte)(48)))), ((int)(((byte)(48)))));
this.taskList.Font = new System.Drawing.Font("Microsoft Sans Serif", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.taskList.ForeColor = System.Drawing.Color.White;
this.taskList.FormattingEnabled = true;
this.taskList.ItemHeight = 18;
this.taskList.Location = new System.Drawing.Point(12, 65);
this.taskList.Name = "taskList";
this.taskList.Size = new System.Drawing.Size(664, 418);
this.taskList.TabIndex = 43;
this.taskList.SelectedIndexChanged += new System.EventHandler(this.taskList_SelectedIndexChanged);
this.taskList.DragDrop += new System.Windows.Forms.DragEventHandler(this.taskList_DragDrop);
this.taskList.DragEnter += new System.Windows.Forms.DragEventHandler(this.taskList_DragEnter);
//
// clearSelectedBtn
//
this.clearSelectedBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.clearSelectedBtn.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(48)))), ((int)(((byte)(48)))), ((int)(((byte)(48)))));
this.clearSelectedBtn.Enabled = false;
this.clearSelectedBtn.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.clearSelectedBtn.ForeColor = System.Drawing.Color.White;
this.clearSelectedBtn.Location = new System.Drawing.Point(682, 111);
this.clearSelectedBtn.Name = "clearSelectedBtn";
this.clearSelectedBtn.Size = new System.Drawing.Size(250, 40);
this.clearSelectedBtn.TabIndex = 44;
this.clearSelectedBtn.Text = "Clear Selected Queue Entry";
this.clearSelectedBtn.UseVisualStyleBackColor = false;
this.clearSelectedBtn.Click += new System.EventHandler(this.clearSelectedBtn_Click);
//
// label1
//
this.label1.ForeColor = System.Drawing.Color.White;
this.label1.Location = new System.Drawing.Point(6, 6);
this.label1.Margin = new System.Windows.Forms.Padding(6);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(238, 111);
this.label1.TabIndex = 45;
this.label1.Text = "Tip:\r\nYou can also drag and drop multiple videos into the list.\r\nThey will be add" +
"ed to the queue using the interpolation settings set in the GUI.";
//
// panel1
//
this.panel1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(40)))), ((int)(((byte)(40)))));
this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.panel1.Controls.Add(this.label1);
this.panel1.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.panel1.Location = new System.Drawing.Point(682, 203);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(250, 142);
this.panel1.TabIndex = 46;
//
// BatchForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(32)))), ((int)(((byte)(32)))));
this.ClientSize = new System.Drawing.Size(944, 501);
this.Controls.Add(this.panel1);
this.Controls.Add(this.clearSelectedBtn);
this.Controls.Add(this.taskList);
this.Controls.Add(this.clearBtn);
this.Controls.Add(this.forceStopBtn);
this.Controls.Add(this.addToQueue);
this.Controls.Add(this.runBtn);
this.Controls.Add(this.stopBtn);
this.Controls.Add(this.titleLabel);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "BatchForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Batch Processing";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.BatchForm_FormClosing);
this.Load += new System.EventHandler(this.BatchForm_Load);
this.panel1.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label titleLabel;
private System.Windows.Forms.Button stopBtn;
private System.Windows.Forms.Button runBtn;
private System.Windows.Forms.Button addToQueue;
private System.Windows.Forms.Button forceStopBtn;
private System.Windows.Forms.Button clearBtn;
private System.Windows.Forms.ListBox taskList;
private System.Windows.Forms.Button clearSelectedBtn;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Panel panel1;
}
}

143
Code/Forms/BatchForm.cs Normal file
View File

@@ -0,0 +1,143 @@
using Flowframes.IO;
using Flowframes.Main;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Flowframes.Forms
{
public partial class BatchForm : Form
{
public BatchForm()
{
InitializeComponent();
BatchProcessing.currentBatchForm = this;
}
private void addToQueue_Click(object sender, EventArgs e)
{
Program.batchQueue.Enqueue(Program.mainForm.GetBatchEntry());
RefreshGui();
}
public void RefreshGui ()
{
taskList.Items.Clear();
string nl = Environment.NewLine;
for (int i = 0; i < Program.batchQueue.Count; i++)
{
BatchEntry entry = Program.batchQueue.ElementAt(i);
string niceOutMode = entry.outMode.ToString().ToUpper().Replace("VID", "").Replace("IMG", "");
string str = $"#{i}: {Path.GetFileName(entry.inPath).Trunc(45)} - {entry.inFps} FPS => {entry.interpFactor}x{nl} {entry.ai.aiNameShort} => {niceOutMode}";
taskList.Items.Add(str);
}
}
public void SetWorking (bool working)
{
runBtn.Enabled = !working;
addToQueue.Enabled = !working;
stopBtn.Visible = working;
forceStopBtn.Visible = working;
stopBtn.Enabled = working;
}
private void BatchForm_Load(object sender, EventArgs e)
{
SetWorking(BatchProcessing.busy);
RefreshGui();
}
private void runBtn_Click(object sender, EventArgs e)
{
stopBtn.Enabled = true;
BatchProcessing.Start();
//WindowState = FormWindowState.Minimized;
Program.mainForm.WindowState = FormWindowState.Normal;
Program.mainForm.BringToFront();
}
private void clearBtn_Click(object sender, EventArgs e)
{
Program.batchQueue.Clear();
RefreshGui();
}
private void stopBtn_Click(object sender, EventArgs e)
{
stopBtn.Enabled = false;
BatchProcessing.stopped = true;
}
private void forceStopBtn_Click(object sender, EventArgs e)
{
Interpolate.Cancel("Force stopped by user.");
BatchProcessing.stopped = true;
}
private void BatchForm_FormClosing(object sender, FormClosingEventArgs e)
{
BatchProcessing.currentBatchForm = null;
}
private void clearSelectedBtn_Click(object sender, EventArgs e)
{
if (taskList.SelectedItem == null) return;
Queue<BatchEntry> temp = new Queue<BatchEntry>();
for(int i = 0; i < Program.batchQueue.Count; i++)
{
if (i != taskList.SelectedIndex)
temp.Enqueue(Program.batchQueue.ElementAt(i));
}
Program.batchQueue = temp;
RefreshGui();
}
private void taskList_SelectedIndexChanged(object sender, EventArgs e)
{
clearSelectedBtn.Enabled = taskList.SelectedItem != null;
}
private void taskList_DragEnter(object sender, DragEventArgs e) { e.Effect = DragDropEffects.Copy; }
private async void taskList_DragDrop(object sender, DragEventArgs e)
{
string[] droppedPaths = (string[])e.Data.GetData(DataFormats.FileDrop);
foreach(string path in droppedPaths)
{
string frame1 = Path.Combine(path, "00000001.png");
if (IOUtils.IsPathDirectory(path) && !File.Exists(frame1))
{
InterpolateUtils.ShowMessage($"Can't find frames in this folder:\n\n{frame1} does not exist.", "Error");
continue;
}
BatchEntry dragDropEntry = Program.mainForm.GetBatchEntry();
dragDropEntry.inPath = path;
dragDropEntry.outPath = path.GetParentDir();
dragDropEntry.inFps = GetFramerate(path);
Program.batchQueue.Enqueue(dragDropEntry);
RefreshGui();
await Task.Delay(100);
}
}
float GetFramerate (string path)
{
float fps = Interpolate.currentInFps;
float fpsFromFile = IOUtils.GetFpsFolderOrVideo(path);
if (fpsFromFile > 0)
return fpsFromFile;
return fps;
}
}
}

2445
Code/Forms/BatchForm.resx Normal file

File diff suppressed because it is too large Load Diff

70
Code/Forms/BigPreviewForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,70 @@
namespace Flowframes.Forms
{
partial class BigPreviewForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(BigPreviewForm));
this.picBox = new System.Windows.Forms.PictureBox();
((System.ComponentModel.ISupportInitialize)(this.picBox)).BeginInit();
this.SuspendLayout();
//
// picBox
//
this.picBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.picBox.Image = global::Flowframes.Properties.Resources.baseline_image_white_48dp_4x_25pcAlpha;
this.picBox.Location = new System.Drawing.Point(0, 0);
this.picBox.Margin = new System.Windows.Forms.Padding(0);
this.picBox.Name = "picBox";
this.picBox.Size = new System.Drawing.Size(704, 601);
this.picBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.picBox.TabIndex = 0;
this.picBox.TabStop = false;
//
// BigPreviewForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(32)))), ((int)(((byte)(32)))));
this.ClientSize = new System.Drawing.Size(704, 601);
this.Controls.Add(this.picBox);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "BigPreviewForm";
this.Text = "Resizable Preview";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.BigPreviewForm_FormClosing);
this.Load += new System.EventHandler(this.BigPreviewForm_Load);
((System.ComponentModel.ISupportInitialize)(this.picBox)).EndInit();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.PictureBox picBox;
}
}

View File

@@ -0,0 +1,36 @@
using Flowframes.Main;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Flowframes.Forms
{
public partial class BigPreviewForm : Form
{
public BigPreviewForm()
{
InitializeComponent();
}
private void BigPreviewForm_Load(object sender, EventArgs e)
{
}
public void SetImage (Image img)
{
picBox.Image = img;
}
private void BigPreviewForm_FormClosing(object sender, FormClosingEventArgs e)
{
InterpolateUtils.bigPreviewForm = null;
}
}
}

File diff suppressed because it is too large Load Diff

176
Code/Forms/InstallerForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,176 @@
namespace Flowframes.Forms
{
partial class InstallerForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(InstallerForm));
this.pkgList = new System.Windows.Forms.CheckedListBox();
this.titleLabel = new System.Windows.Forms.Label();
this.logBox = new System.Windows.Forms.TextBox();
this.downloadPackagesBtn = new System.Windows.Forms.Button();
this.doneBtn = new System.Windows.Forms.Button();
this.redownloadPkgsBtn = new System.Windows.Forms.Button();
this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
this.pkgInfoTextbox = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// pkgList
//
this.pkgList.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(48)))), ((int)(((byte)(48)))), ((int)(((byte)(48)))));
this.pkgList.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.pkgList.ForeColor = System.Drawing.Color.White;
this.pkgList.FormattingEnabled = true;
this.pkgList.Location = new System.Drawing.Point(12, 62);
this.pkgList.Name = "pkgList";
this.pkgList.RightToLeft = System.Windows.Forms.RightToLeft.No;
this.pkgList.Size = new System.Drawing.Size(398, 292);
this.pkgList.TabIndex = 0;
this.pkgList.SelectedIndexChanged += new System.EventHandler(this.pkgList_SelectedIndexChanged);
//
// titleLabel
//
this.titleLabel.AutoSize = true;
this.titleLabel.Font = new System.Drawing.Font("Yu Gothic UI", 21.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.titleLabel.ForeColor = System.Drawing.Color.White;
this.titleLabel.Location = new System.Drawing.Point(12, 9);
this.titleLabel.Margin = new System.Windows.Forms.Padding(3, 0, 3, 10);
this.titleLabel.Name = "titleLabel";
this.titleLabel.Size = new System.Drawing.Size(229, 40);
this.titleLabel.TabIndex = 1;
this.titleLabel.Text = "Package Installer";
//
// logBox
//
this.logBox.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
this.logBox.ForeColor = System.Drawing.Color.White;
this.logBox.Location = new System.Drawing.Point(622, 62);
this.logBox.MinimumSize = new System.Drawing.Size(4, 21);
this.logBox.Multiline = true;
this.logBox.Name = "logBox";
this.logBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.logBox.Size = new System.Drawing.Size(300, 427);
this.logBox.TabIndex = 6;
this.logBox.TabStop = false;
//
// downloadPackagesBtn
//
this.downloadPackagesBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.downloadPackagesBtn.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(48)))), ((int)(((byte)(48)))), ((int)(((byte)(48)))));
this.downloadPackagesBtn.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.downloadPackagesBtn.ForeColor = System.Drawing.Color.White;
this.downloadPackagesBtn.Location = new System.Drawing.Point(416, 62);
this.downloadPackagesBtn.Name = "downloadPackagesBtn";
this.downloadPackagesBtn.Size = new System.Drawing.Size(200, 60);
this.downloadPackagesBtn.TabIndex = 9;
this.downloadPackagesBtn.Text = "Install Selected Packages\r\n(Uninstall Deselected Packages)";
this.toolTip1.SetToolTip(this.downloadPackagesBtn, "This will install ticked packages and uninstall the ones you unticked (if they ar" +
"e installed).");
this.downloadPackagesBtn.UseVisualStyleBackColor = false;
this.downloadPackagesBtn.Click += new System.EventHandler(this.downloadPackagesBtn_Click);
//
// doneBtn
//
this.doneBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.doneBtn.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(48)))), ((int)(((byte)(48)))), ((int)(((byte)(48)))));
this.doneBtn.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.doneBtn.ForeColor = System.Drawing.Color.White;
this.doneBtn.Location = new System.Drawing.Point(416, 314);
this.doneBtn.Name = "doneBtn";
this.doneBtn.Size = new System.Drawing.Size(200, 40);
this.doneBtn.TabIndex = 10;
this.doneBtn.Text = "Done";
this.doneBtn.UseVisualStyleBackColor = false;
this.doneBtn.Click += new System.EventHandler(this.doneBtn_Click);
//
// redownloadPkgsBtn
//
this.redownloadPkgsBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.redownloadPkgsBtn.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(48)))), ((int)(((byte)(48)))), ((int)(((byte)(48)))));
this.redownloadPkgsBtn.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.redownloadPkgsBtn.ForeColor = System.Drawing.Color.White;
this.redownloadPkgsBtn.Location = new System.Drawing.Point(416, 128);
this.redownloadPkgsBtn.Name = "redownloadPkgsBtn";
this.redownloadPkgsBtn.Size = new System.Drawing.Size(200, 40);
this.redownloadPkgsBtn.TabIndex = 11;
this.redownloadPkgsBtn.Text = "Redownload Selected Package";
this.toolTip1.SetToolTip(this.redownloadPkgsBtn, "This will first uninstall the installed packages and then redownload them.");
this.redownloadPkgsBtn.UseVisualStyleBackColor = false;
this.redownloadPkgsBtn.Click += new System.EventHandler(this.redownloadPkgsBtn_Click);
//
// pkgInfoTextbox
//
this.pkgInfoTextbox.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(48)))), ((int)(((byte)(48)))), ((int)(((byte)(48)))));
this.pkgInfoTextbox.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.pkgInfoTextbox.ForeColor = System.Drawing.Color.White;
this.pkgInfoTextbox.Location = new System.Drawing.Point(12, 360);
this.pkgInfoTextbox.MinimumSize = new System.Drawing.Size(4, 21);
this.pkgInfoTextbox.Multiline = true;
this.pkgInfoTextbox.Name = "pkgInfoTextbox";
this.pkgInfoTextbox.Size = new System.Drawing.Size(604, 129);
this.pkgInfoTextbox.TabIndex = 12;
this.pkgInfoTextbox.TabStop = false;
this.pkgInfoTextbox.Text = "Friendly Name:\r\nPackage Name:\r\nDownload Size:\r\n\r\nDescription:";
//
// InstallerForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(32)))), ((int)(((byte)(32)))));
this.ClientSize = new System.Drawing.Size(934, 501);
this.Controls.Add(this.pkgInfoTextbox);
this.Controls.Add(this.redownloadPkgsBtn);
this.Controls.Add(this.doneBtn);
this.Controls.Add(this.downloadPackagesBtn);
this.Controls.Add(this.logBox);
this.Controls.Add(this.titleLabel);
this.Controls.Add(this.pkgList);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "InstallerForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Flowframes Package Installer";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.InstallerForm_FormClosing);
this.Load += new System.EventHandler(this.InstallerForm_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.CheckedListBox pkgList;
private System.Windows.Forms.Label titleLabel;
private System.Windows.Forms.TextBox logBox;
private System.Windows.Forms.Button downloadPackagesBtn;
private System.Windows.Forms.Button doneBtn;
private System.Windows.Forms.ToolTip toolTip1;
private System.Windows.Forms.Button redownloadPkgsBtn;
private System.Windows.Forms.TextBox pkgInfoTextbox;
}
}

164
Code/Forms/InstallerForm.cs Normal file
View File

@@ -0,0 +1,164 @@
using Flowframes.IO;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Flowframes.Forms
{
public partial class InstallerForm : Form
{
bool busy = false;
public InstallerForm()
{
InitializeComponent();
}
private void InstallerForm_Load(object sender, EventArgs e)
{
PkgInstaller.installerForm = this;
Print($"Welcome to the package manager.{Environment.NewLine}Here you can install packages by ticking or uninstall by unticking them.");
Refresh();
EnableRequired();
if (pkgList.SelectedIndex < 0)
pkgList.SelectedIndex = 0;
}
void SetBusy (bool state)
{
busy = state;
downloadPackagesBtn.Enabled = !state;
redownloadPkgsBtn.Enabled = !state;
doneBtn.Enabled = !state;
}
private void downloadPackagesBtn_Click(object sender, EventArgs e)
{
UpdatePackages(false);
}
private async void redownloadPkgsBtn_Click(object sender, EventArgs e)
{
FlowPackage pkg = PkgInstaller.GetPkg(pkgList.SelectedItem.ToString());
if (PkgInstaller.IsInstalled(pkg.fileName)) // Uninstall first if force = true, to ensure a clean reinstall
PkgInstaller.Uninstall(pkg.fileName);
await Task.Delay(10);
await PkgInstaller.DownloadAndInstall(pkg.fileName);
}
async void UpdatePackages (bool force)
{
SetBusy(true);
EnableRequired();
for (int i = 0; i < pkgList.Items.Count; i++)
{
FlowPackage pkg = PkgInstaller.GetPkg(pkgList.Items[i].ToString());
if(force && PkgInstaller.IsInstalled(pkg.fileName)) // Uninstall first if force = true, to ensure a clean reinstall
PkgInstaller.Uninstall(pkg.fileName);
bool install = pkgList.GetItemChecked(i);
if(install && !PkgInstaller.IsInstalled(pkg.fileName)) // Install if not installed
await PkgInstaller.DownloadAndInstall(pkg.fileName);
if (!install && PkgInstaller.IsInstalled(pkg.fileName)) // Uninstall if installed
PkgInstaller.Uninstall(pkg.fileName);
}
Print("All tasks completed.");
SetBusy(false);
}
void Refresh ()
{
pkgList.Items.Clear();
foreach (FlowPackage pkg in PkgInstaller.packages)
pkgList.Items.Add(pkg.friendlyName, PkgInstaller.IsInstalled(pkg.fileName));
}
void EnableRequired ()
{
for (int i = 0; i < pkgList.Items.Count; i++)
{
if(pkgList.Items[i].ToString().ToLower().Contains("required"))
pkgList.SetItemChecked(i, true);
}
}
public void Print(string s, bool replaceLastLine = false)
{
if (replaceLastLine)
{
try
{
logBox.Text = logBox.Text.Remove(logBox.Text.LastIndexOf(Environment.NewLine));
}
catch { }
}
if (string.IsNullOrWhiteSpace(logBox.Text))
logBox.Text += s;
else
logBox.Text += Environment.NewLine + s;
logBox.SelectionStart = logBox.Text.Length;
logBox.ScrollToCaret();
}
private void InstallerForm_FormClosing(object sender, FormClosingEventArgs e)
{
if(busy || !HasRequiredPkgs(true))
e.Cancel = true;
}
bool HasRequiredPkgs (bool silent = false)
{
bool isOk = true;
for (int i = 0; i < pkgList.Items.Count; i++)
{
if (pkgList.Items[i].ToString().ToLower().Contains("required"))
{
string frName = pkgList.Items[i].ToString();
if (!PkgInstaller.IsInstalled(PkgInstaller.GetPkg(frName).fileName))
{
if(!silent)
Print($"The package {pkgList.Items[i].ToString().Wrap()} is required but not installed!");
isOk = false;
EnableRequired();
}
}
}
return isOk;
}
private void doneBtn_Click(object sender, EventArgs e)
{
if (HasRequiredPkgs())
Close();
else
Print("Please click \"Download/Update Packages\".");
}
private void pkgList_SelectedIndexChanged(object sender, EventArgs e)
{
FlowPackage pkg = PkgInstaller.GetPkg(pkgList.SelectedItem.ToString());
GetPkgInfo(pkg);
}
void GetPkgInfo(FlowPackage pkg)
{
string nl = Environment.NewLine;
pkgInfoTextbox.Text = $"Friendly Name: {pkg.friendlyName}";
pkgInfoTextbox.Text += $"{nl}Package Name: {pkg.fileName}";
pkgInfoTextbox.Text += $"{nl}Download Size: {pkg.downloadSizeMb} MB";
pkgInfoTextbox.Text += $"{nl}{nl}Description:{nl}{pkg.desc}";
}
}
}

File diff suppressed because it is too large Load Diff

1314
Code/Forms/SettingsForm.Designer.cs generated Normal file

File diff suppressed because it is too large Load Diff

141
Code/Forms/SettingsForm.cs Normal file
View File

@@ -0,0 +1,141 @@
using Flowframes.IO;
using Microsoft.WindowsAPICodePack.Dialogs;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Flowframes.Forms
{
public partial class SettingsForm : Form
{
bool initialized = false;
public SettingsForm()
{
InitializeComponent();
}
private void SettingsForm_Load(object sender, EventArgs e)
{
LoadSettings();
initialized = true;
}
private void SettingsForm_FormClosing(object sender, FormClosingEventArgs e)
{
SaveSettings();
}
void SaveSettings ()
{
h264Crf.Text = h264Crf.GetInt().Clamp(0, 40).ToString();
h265Crf.Text = h265Crf.GetInt().Clamp(0, 40).ToString();
gifskiQ.Text = gifskiQ.GetInt().Clamp(0, 100).ToString();
torchGpus.Text = torchGpus.Text.Replace(" ", "");
ncnnGpus.Text = ncnnGpus.Text.Replace(" ", "");
ffEncThreads.Text = ffEncThreads.GetInt().ToString();
// General
ConfigParser.SaveGuiElement(maxVidHeight);
ConfigParser.SaveComboxIndex(tempFolderLoc);
ConfigParser.SaveGuiElement(keepTempFolder);
ConfigParser.SaveGuiElement(deleteLogsOnStartup);
// Interpolation
ConfigParser.SaveGuiElement(enableAudio);
ConfigParser.SaveComboxIndex(dedupMode);
ConfigParser.SaveGuiElement(dedupThresh, ConfigParser.StringMode.Float);
ConfigParser.SaveComboxIndex(timingMode);
ConfigParser.SaveGuiElement(enableLoop);
ConfigParser.SaveGuiElement(jpegInterps);
// AI
ConfigParser.SaveComboxIndex(rifeMode);
ConfigParser.SaveGuiElement(torchGpus);
ConfigParser.SaveGuiElement(ncnnGpus);
// Video Export
ConfigParser.SaveGuiElement(minOutVidLength, ConfigParser.StringMode.Int);
ConfigParser.SaveComboxIndex(mp4Enc);
ConfigParser.SaveGuiElement(h264Crf);
ConfigParser.SaveGuiElement(h265Crf);
ConfigParser.SaveGuiElement(gifskiQ);
ConfigParser.SaveGuiElement(maxFps);
ConfigParser.SaveComboxIndex(maxFpsMode);
// Debugging
ConfigParser.SaveComboxIndex(cmdDebugMode);
ConfigParser.SaveGuiElement(autoDedupFrames);
ConfigParser.SaveGuiElement(ffEncThreads);
ConfigParser.SaveGuiElement(ffprobeCountFrames);
}
void LoadSettings()
{
// REMOVE ME ONCE FINISHED!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
procedureMode.SelectedIndex = 0;
// General
ConfigParser.LoadGuiElement(maxVidHeight);
ConfigParser.LoadComboxIndex(tempFolderLoc); ConfigParser.LoadGuiElement(tempDirCustom);
ConfigParser.LoadGuiElement(deleteLogsOnStartup);
ConfigParser.LoadGuiElement(keepTempFolder);
// Interpolation
ConfigParser.LoadGuiElement(enableAudio);
ConfigParser.LoadComboxIndex(dedupMode);
ConfigParser.LoadGuiElement(dedupThresh, "%");
ConfigParser.LoadComboxIndex(timingMode);
ConfigParser.LoadGuiElement(enableLoop);
ConfigParser.LoadGuiElement(jpegInterps);
// AI
ConfigParser.LoadComboxIndex(rifeMode);
ConfigParser.LoadGuiElement(torchGpus);
ConfigParser.LoadGuiElement(ncnnGpus);
// Video Export
ConfigParser.LoadGuiElement(minOutVidLength);
ConfigParser.LoadComboxIndex(mp4Enc);
ConfigParser.LoadGuiElement(h264Crf);
ConfigParser.LoadGuiElement(h265Crf);
ConfigParser.LoadGuiElement(gifskiQ);
ConfigParser.LoadGuiElement(maxFps);
ConfigParser.LoadComboxIndex(maxFpsMode);
// Debugging
ConfigParser.LoadComboxIndex(cmdDebugMode);
ConfigParser.LoadGuiElement(autoDedupFrames);
ConfigParser.LoadGuiElement(ffEncThreads);
ConfigParser.LoadGuiElement(ffprobeCountFrames);
}
private void dedupThresh_Leave(object sender, EventArgs e)
{
dedupThresh.Text = dedupThresh.GetFloat().ToString() + "%";
}
private void tempFolderLoc_SelectedIndexChanged(object sender, EventArgs e)
{
tempDirBrowseBtn.Visible = tempFolderLoc.SelectedIndex == 4;
tempDirCustom.Visible = tempFolderLoc.SelectedIndex == 4;
}
private void tempDirBrowseBtn_Click(object sender, EventArgs e)
{
CommonOpenFileDialog dialog = new CommonOpenFileDialog();
dialog.InitialDirectory = tempDirCustom.Text.Trim();
dialog.IsFolderPicker = true;
if (dialog.ShowDialog() == CommonFileDialogResult.Ok)
tempDirCustom.Text = dialog.FileName;
ConfigParser.SaveGuiElement(tempDirCustom);
}
private void cmdDebugMode_SelectedIndexChanged(object sender, EventArgs e)
{
if (initialized && cmdDebugMode.SelectedIndex == 2)
MessageBox.Show("If you enable this, you need to close the CMD window manually after the process has finished, otherwise processing will be paused!", "Notice");
}
}
}

2448
Code/Forms/SettingsForm.resx Normal file

File diff suppressed because it is too large Load Diff

192
Code/Forms/UpdaterForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,192 @@
namespace Flowframes.Forms
{
partial class UpdaterForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(UpdaterForm));
this.titleLabel = new System.Windows.Forms.Label();
this.label13 = new System.Windows.Forms.Label();
this.updateBtn = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.installedLabel = new System.Windows.Forms.Label();
this.latestLabel = new System.Windows.Forms.Label();
this.statusLabel = new System.Windows.Forms.Label();
this.downloadingLabel = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// titleLabel
//
this.titleLabel.AutoSize = true;
this.titleLabel.Font = new System.Drawing.Font("Yu Gothic UI", 21.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.titleLabel.ForeColor = System.Drawing.Color.White;
this.titleLabel.Location = new System.Drawing.Point(12, 9);
this.titleLabel.Margin = new System.Windows.Forms.Padding(3, 0, 3, 10);
this.titleLabel.Name = "titleLabel";
this.titleLabel.Size = new System.Drawing.Size(121, 40);
this.titleLabel.TabIndex = 2;
this.titleLabel.Text = "Updater";
//
// label13
//
this.label13.AutoSize = true;
this.label13.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label13.ForeColor = System.Drawing.Color.White;
this.label13.Location = new System.Drawing.Point(17, 67);
this.label13.Margin = new System.Windows.Forms.Padding(8, 8, 3, 0);
this.label13.Name = "label13";
this.label13.Size = new System.Drawing.Size(110, 16);
this.label13.TabIndex = 35;
this.label13.Text = "Installed Version:";
//
// updateBtn
//
this.updateBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.updateBtn.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(48)))), ((int)(((byte)(48)))), ((int)(((byte)(48)))));
this.updateBtn.Enabled = false;
this.updateBtn.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.updateBtn.ForeColor = System.Drawing.Color.White;
this.updateBtn.Location = new System.Drawing.Point(12, 229);
this.updateBtn.Name = "updateBtn";
this.updateBtn.Size = new System.Drawing.Size(203, 40);
this.updateBtn.TabIndex = 36;
this.updateBtn.Text = "Update!";
this.updateBtn.UseVisualStyleBackColor = true;
this.updateBtn.Click += new System.EventHandler(this.updateBtn_Click);
//
// label1
//
this.label1.AutoSize = true;
this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label1.ForeColor = System.Drawing.Color.White;
this.label1.Location = new System.Drawing.Point(16, 93);
this.label1.Margin = new System.Windows.Forms.Padding(8, 10, 3, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(96, 16);
this.label1.TabIndex = 37;
this.label1.Text = "Latest Version:";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label2.ForeColor = System.Drawing.Color.White;
this.label2.Location = new System.Drawing.Point(16, 119);
this.label2.Margin = new System.Windows.Forms.Padding(8, 10, 3, 0);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(48, 16);
this.label2.TabIndex = 38;
this.label2.Text = "Status:";
//
// installedLabel
//
this.installedLabel.AutoSize = true;
this.installedLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.installedLabel.ForeColor = System.Drawing.Color.White;
this.installedLabel.Location = new System.Drawing.Point(200, 67);
this.installedLabel.Margin = new System.Windows.Forms.Padding(8, 8, 3, 0);
this.installedLabel.Name = "installedLabel";
this.installedLabel.Size = new System.Drawing.Size(76, 16);
this.installedLabel.TabIndex = 39;
this.installedLabel.Text = "Loading...";
//
// latestLabel
//
this.latestLabel.AutoSize = true;
this.latestLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.latestLabel.ForeColor = System.Drawing.Color.White;
this.latestLabel.Location = new System.Drawing.Point(200, 93);
this.latestLabel.Margin = new System.Windows.Forms.Padding(8, 8, 3, 0);
this.latestLabel.Name = "latestLabel";
this.latestLabel.Size = new System.Drawing.Size(76, 16);
this.latestLabel.TabIndex = 40;
this.latestLabel.Text = "Loading...";
//
// statusLabel
//
this.statusLabel.AutoSize = true;
this.statusLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.statusLabel.ForeColor = System.Drawing.Color.White;
this.statusLabel.Location = new System.Drawing.Point(200, 119);
this.statusLabel.Margin = new System.Windows.Forms.Padding(8, 8, 3, 0);
this.statusLabel.Name = "statusLabel";
this.statusLabel.Size = new System.Drawing.Size(76, 16);
this.statusLabel.TabIndex = 41;
this.statusLabel.Text = "Loading...";
//
// downloadingLabel
//
this.downloadingLabel.AutoSize = true;
this.downloadingLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.downloadingLabel.ForeColor = System.Drawing.Color.White;
this.downloadingLabel.Location = new System.Drawing.Point(226, 241);
this.downloadingLabel.Margin = new System.Windows.Forms.Padding(8, 10, 3, 0);
this.downloadingLabel.Name = "downloadingLabel";
this.downloadingLabel.Size = new System.Drawing.Size(0, 16);
this.downloadingLabel.TabIndex = 42;
//
// UpdaterForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(32)))), ((int)(((byte)(32)))));
this.ClientSize = new System.Drawing.Size(624, 281);
this.Controls.Add(this.downloadingLabel);
this.Controls.Add(this.statusLabel);
this.Controls.Add(this.latestLabel);
this.Controls.Add(this.installedLabel);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.updateBtn);
this.Controls.Add(this.label13);
this.Controls.Add(this.titleLabel);
this.ForeColor = System.Drawing.Color.White;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "UpdaterForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Updater";
this.Load += new System.EventHandler(this.UpdaterForm_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label titleLabel;
private System.Windows.Forms.Label label13;
private System.Windows.Forms.Button updateBtn;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label installedLabel;
private System.Windows.Forms.Label latestLabel;
private System.Windows.Forms.Label statusLabel;
private System.Windows.Forms.Label downloadingLabel;
}
}

60
Code/Forms/UpdaterForm.cs Normal file
View File

@@ -0,0 +1,60 @@
using Flowframes.OS;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Flowframes.Forms
{
public partial class UpdaterForm : Form
{
int installed;
int latest;
public UpdaterForm()
{
InitializeComponent();
}
private async void UpdaterForm_Load(object sender, EventArgs e)
{
installed = Updater.GetInstalledVer();
latest = Updater.GetLatestVer();
installedLabel.Text = "v" + installed;
await Task.Delay(100);
latestLabel.Text = "v" + latest;
if (installedLabel.Text == latestLabel.Text)
{
updateBtn.Text = "Redownload Latest Version";
statusLabel.Text = "Latest Version Is Installed.";
}
else
{
updateBtn.Text = "Update To Latest Version!";
statusLabel.Text = "Update Available!";
}
updateBtn.Enabled = true;
}
float lastProg = -1f;
public void SetProgLabel (float prog, string str)
{
if (prog == lastProg) return;
lastProg = prog;
downloadingLabel.Text = str;
}
private async void updateBtn_Click(object sender, EventArgs e)
{
await Task.Run(() => DoUpdate());
}
async void DoUpdate ()
{
await Updater.UpdateTo(latest, this);
}
}
}

2445
Code/Forms/UpdaterForm.resx Normal file

File diff suppressed because it is too large Load Diff

15
Code/IO/CfgStrings.cs Normal file
View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Flowframes.IO
{
class CfgStrings
{
// public static string dedupMode = "dedupMode";
// public static string dedupThresh = "dedupThresh";
// public static string keepFrames = "keepFrames";
}
}

120
Code/IO/Config.cs Normal file
View File

@@ -0,0 +1,120 @@
using Flowframes.OS;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
namespace Flowframes.IO
{
internal class Config
{
private static string configPath;
private static string[] cachedLines;
public static void Init()
{
configPath = Path.Combine(Paths.GetDataPath(), "config.ini");
if (!File.Exists(configPath))
{
File.Create(configPath).Close();
}
Reload();
}
public static void Set(string key, string value)
{
string[] lines = File.ReadAllLines(configPath);
for (int i = 0; i < lines.Length; i++)
{
if (lines[i].Split('|')[0] == key)
{
lines[i] = key + "|" + value;
File.WriteAllLines(configPath, lines);
cachedLines = lines;
return;
}
}
List<string> list = lines.ToList();
list.Add(key + "|" + value);
File.WriteAllLines(configPath, list.ToArray());
cachedLines = list.ToArray();
}
public static string Get(string key)
{
try
{
for (int i = 0; i < cachedLines.Length; i++)
{
string[] keyValuePair = cachedLines[i].Split('|');
if (keyValuePair[0] == key)
return keyValuePair[1];
}
return WriteDefaultValIfExists(key);
}
catch (Exception e)
{
Logger.Log($"Failed to get {key.Wrap()} from config! {e.Message}");
}
return null;
}
public static bool GetBool(string key)
{
return bool.Parse(Get(key));
}
public static int GetInt(string key)
{
return int.Parse(Get(key));
}
public static float GetFloat(string key)
{
return float.Parse(Get(key));
}
private static string WriteDefaultValIfExists(string key)
{
if (key == "dedupMode") return WriteDefault("dedupMode", "2");
if (key == "dedupThresh") return WriteDefault("dedupThresh", "2");
if (key == "keepFrames") return WriteDefault("keepFrames", "False");
if (key == "enableAudio") return WriteDefault("enableAudio", "True");
if (key == "logProcessOutput") return WriteDefault("logProcessOutput", "False");
if (key == "cmdDebugMode") return WriteDefault("cmdDebugMode", "0");
if (key == "enableLoop") return WriteDefault("enableLoop", "False");
if (key == "ncnnGpus") return WriteDefault("ncnnGpus", "0");
if (key == "torchGpus") return WriteDefault("torchGpus", "0");
if (key == "keepTempFolder") return WriteDefault("keepTempFolder", "False");
if (key == "deleteLogsOnStartup") return WriteDefault("deleteLogsOnStartup", "True");
if (key == "autoDedupFrames") return WriteDefault("autoDedupFrames", "10");
if (key == "minOutVidLength") return WriteDefault("minOutVidLength", "2");
if (key == "mp4Enc") return WriteDefault("mp4Enc", "0");
if (key == "h264Crf") return WriteDefault("h264Crf", "20");
if (key == "h265Crf") return WriteDefault("h265Crf", "22");
if (key == "gifskiQ") return WriteDefault("gifskiQ", "95");
if (key == "maxFps") return WriteDefault("maxFps", "0");
if (key == "maxFpsMode") return WriteDefault("maxFpsMode", "0");
if (key == "jpegInterps") return WriteDefault("jpegInterps", "False");
if (key == "rifeMode") return WriteDefault("rifeMode", ((NvApi.GetVramGb() > 5f) ? 1 : 0).ToString()); // Enable by default if GPU has >5gb VRAM
if (key == "maxVidHeight") return WriteDefault("maxVidHeight", "2160");
if (key == "timingMode") return WriteDefault("timingMode", "1");
if (key == "tempDirCustom") return WriteDefault("tempDirCustom", "C:/");
if (key == "ffprobeCountFrames") return WriteDefault("ffprobeCountFrames", "False");
return WriteDefault(key, "0");
}
private static string WriteDefault(string key, string def)
{
Set(key, def);
return def;
}
private static void Reload()
{
cachedLines = File.ReadAllLines(configPath);
}
}
}

65
Code/IO/ConfigParser.cs Normal file
View File

@@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Flowframes.IO
{
class ConfigParser
{
public enum StringMode { Any, Int, Float }
public static void SaveGuiElement(TextBox textbox, StringMode stringMode = StringMode.Any)
{
switch (stringMode)
{
case StringMode.Any: Config.Set(textbox.Name, textbox.Text); break;
case StringMode.Int: Config.Set(textbox.Name, textbox.Text.GetInt().ToString()); break;
case StringMode.Float: Config.Set(textbox.Name, textbox.Text.GetFloat().ToString()); break;
}
}
public static void SaveGuiElement(ComboBox comboBox, StringMode stringMode = StringMode.Any)
{
switch (stringMode)
{
case StringMode.Any: Config.Set(comboBox.Name, comboBox.Text); break;
case StringMode.Int: Config.Set(comboBox.Name, comboBox.Text.GetInt().ToString()); break;
case StringMode.Float: Config.Set(comboBox.Name, comboBox.Text.GetFloat().ToString()); break;
}
}
public static void SaveGuiElement(CheckBox checkbox)
{
Config.Set(checkbox.Name, checkbox.Checked.ToString());
}
public static void SaveComboxIndex(ComboBox comboBox)
{
Config.Set(comboBox.Name, comboBox.SelectedIndex.ToString());
}
public static void LoadGuiElement(ComboBox comboBox, string suffix = "")
{
comboBox.Text = Config.Get(comboBox.Name) + suffix;
}
public static void LoadGuiElement(TextBox textbox, string suffix = "")
{
textbox.Text = Config.Get(textbox.Name) + suffix; ;
}
public static void LoadGuiElement(CheckBox checkbox)
{
checkbox.Checked = bool.Parse(Config.Get(checkbox.Name));
}
public static void LoadComboxIndex(ComboBox comboBox)
{
comboBox.SelectedIndex = Config.GetInt(comboBox.Name);
}
}
}

15
Code/IO/Formats.cs Normal file
View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Flowframes.IO
{
class Formats
{
public static string[] supported = { ".mp4", ".m4v", ".gif", ".mkv", ".mpg", ".webm", ".avi", ".ts", ".bik" }; // Supported formats
public static string[] noEncodeSupport = { ".bik" }; // Files that have no encode support, but decode
public static string[] preprocess = { ".gif" }; // Files that get converted to MP4 first for compat reasons
}
}

398
Code/IO/IOUtils.cs Normal file
View File

@@ -0,0 +1,398 @@

using Flowframes.Data;
using Microsoft.WindowsAPICodePack.Shell;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Flowframes.IO
{
class IOUtils
{
public static string GetExe()
{
return System.Reflection.Assembly.GetEntryAssembly().GetName().CodeBase.Replace("file:///", "");
}
public static string GetExeDir()
{
return AppDomain.CurrentDomain.BaseDirectory;
}
public static Image GetImage(string path)
{
using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read))
return Image.FromStream(stream);
}
public static string[] ReadLines(string path)
{
List<string> lines = new List<string>();
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 0x1000, FileOptions.SequentialScan))
using (var sr = new StreamReader(fs, Encoding.UTF8))
{
string line;
while ((line = sr.ReadLine()) != null)
{
lines.Add(line);
}
}
return lines.ToArray();
}
public static bool IsPathDirectory(string path)
{
if (path == null)
{
throw new ArgumentNullException("path");
}
path = path.Trim();
if (Directory.Exists(path))
{
return true;
}
if (File.Exists(path))
{
return false;
}
if (new string[2]
{
"\\",
"/"
}.Any((string x) => path.EndsWith(x)))
{
return true;
}
return string.IsNullOrWhiteSpace(Path.GetExtension(path));
}
public static bool IsFileValid(string path)
{
if (path == null)
return false;
if (!File.Exists(path))
return false;
return true;
}
public static bool IsDirValid(string path)
{
if (path == null)
return false;
if (!Directory.Exists(path))
return false;
return true;
}
public static void Copy(string sourceDirectoryName, string targetDirectoryName, bool move = false)
{
Directory.CreateDirectory(targetDirectoryName);
DirectoryInfo source = new DirectoryInfo(sourceDirectoryName);
DirectoryInfo target = new DirectoryInfo(targetDirectoryName);
CopyWork(source, target, move);
}
private static void CopyWork(DirectoryInfo source, DirectoryInfo target, bool move)
{
DirectoryInfo[] directories = source.GetDirectories();
foreach (DirectoryInfo directoryInfo in directories)
{
CopyWork(directoryInfo, target.CreateSubdirectory(directoryInfo.Name), move);
}
FileInfo[] files = source.GetFiles();
foreach (FileInfo fileInfo in files)
{
if (move)
{
fileInfo.MoveTo(Path.Combine(target.FullName, fileInfo.Name));
}
else
{
fileInfo.CopyTo(Path.Combine(target.FullName, fileInfo.Name), overwrite: true);
}
}
}
public static void DeleteContentsOfDir(string path)
{
DirectoryInfo directoryInfo = new DirectoryInfo(path);
FileInfo[] files = directoryInfo.GetFiles();
foreach (FileInfo fileInfo in files)
{
fileInfo.Delete();
}
DirectoryInfo[] directories = directoryInfo.GetDirectories();
foreach (DirectoryInfo directoryInfo2 in directories)
{
directoryInfo2.Delete(recursive: true);
}
}
public static void ReplaceInFilenamesDir(string dir, string textToFind, string textToReplace, bool recursive = true, string wildcard = "*")
{
int counter = 1;
DirectoryInfo d = new DirectoryInfo(dir);
FileInfo[] files = null;
if (recursive)
files = d.GetFiles(wildcard, SearchOption.AllDirectories);
else
files = d.GetFiles(wildcard, SearchOption.TopDirectoryOnly);
foreach (FileInfo file in files)
{
ReplaceInFilename(file.FullName, textToFind, textToReplace);
counter++;
}
}
public static void ReplaceInFilename(string path, string textToFind, string textToReplace)
{
string ext = Path.GetExtension(path);
string newFilename = Path.GetFileNameWithoutExtension(path).Replace(textToFind, textToReplace);
string targetPath = Path.Combine(Path.GetDirectoryName(path), newFilename + ext);
if (File.Exists(targetPath))
{
//Program.Print("Skipped " + path + " because a file with the target name already exists.");
return;
}
File.Move(path, targetPath);
}
public static bool TryCopy(string source, string dest, bool overwrite) // Copy with error handling. Returns false if failed
{
try
{
File.Copy(source, dest, overwrite);
}
catch (Exception e)
{
MessageBox.Show("Copy from \"" + source + "\" to \"" + dest + " (Overwrite: " + overwrite + " failed: \n\n" + e.Message);
return false;
}
return true;
}
public static int GetFilenameCounterLength(string file, string prefixToRemove = "")
{
string filenameNoExt = Path.GetFileNameWithoutExtension(file);
if (!string.IsNullOrEmpty(prefixToRemove))
filenameNoExt = filenameNoExt.Replace(prefixToRemove, "");
string onlyNumbersFilename = Regex.Replace(filenameNoExt, "[^.0-9]", "");
return onlyNumbersFilename.Length;
}
public static int GetAmountOfFiles (string path, bool recursive, string wildcard = "*")
{
DirectoryInfo d = new DirectoryInfo(path);
FileInfo[] files = null;
if (recursive)
files = d.GetFiles(wildcard, SearchOption.AllDirectories);
else
files = d.GetFiles(wildcard, SearchOption.TopDirectoryOnly);
return files.Length;
}
public static void RenameCounterDir(string path, bool inverse = false)
{
int counter = 1;
DirectoryInfo d = new DirectoryInfo(path);
FileInfo[] files = d.GetFiles();
var filesSorted = files.OrderBy(n => n);
if (inverse)
filesSorted.Reverse();
foreach (FileInfo file in files)
{
string dir = new DirectoryInfo(file.FullName).Parent.FullName;
int filesDigits = (int)Math.Floor(Math.Log10((double)files.Length) + 1);
File.Move(file.FullName, Path.Combine(dir, counter.ToString().PadLeft(filesDigits, '0') + Path.GetExtension(file.FullName)));
counter++;
//if (counter % 100 == 0) Program.Print("Renamed " + counter + " files...");
}
}
public static float GetVideoFramerate (string path)
{
float fps = 0;
try
{
ShellFile shellFile = ShellFile.FromFilePath(path);
fps = (float)shellFile.Properties.System.Video.FrameRate.Value / 1000f;
Logger.Log("Detected FPS of " + Path.GetFileName(path) + " as " + fps + " FPS", true);
}
catch
{
Logger.Log("Failed to read FPS - Trying alternative method...", true);
try
{
fps = FFmpegCommands.GetFramerate(path);
Logger.Log("Detected FPS of " + Path.GetFileName(path) + " as " + fps + " FPS", true);
}
catch
{
Logger.Log("Failed to read FPS - Please enter it manually.");
}
}
return fps;
}
public static float GetVideoFramerateForDir(string path)
{
float fps = 0;
try
{
string parentDir = path.GetParentDir();
string fpsFile = Path.Combine(parentDir, "fps.ini");
fps = float.Parse(ReadLines(fpsFile)[0]);
Logger.Log($"Got {fps} FPS from file: " + fpsFile);
float guiFps = Program.mainForm.GetBatchEntry().inFps;
DialogResult dialogResult = MessageBox.Show("A frame rate file has been found in the parent directory.\n\n" +
$"Click \"Yes\" to use frame rate from the file ({fps}) or \"No\" to use current FPS set in GUI ({guiFps})", "Load Frame Rate From fps.ini?", MessageBoxButtons.YesNo);
if (dialogResult == DialogResult.Yes)
return fps;
else if (dialogResult == DialogResult.No)
return guiFps;
}
catch { }
return fps;
}
public static Size GetVideoRes (string path)
{
Size size = new Size(0, 0);
try
{
ShellFile shellFile = ShellFile.FromFilePath(path);
int w = (int)shellFile.Properties.System.Video.FrameWidth.Value;
int h = (int)shellFile.Properties.System.Video.FrameHeight.Value;
return new Size(w, h);
}
catch (Exception e)
{
Logger.Log($"Failed to read video size ({e.Message}) - Trying alternative method...", true);
try
{
size = FFmpegCommands.GetSize(path);
Logger.Log($"Detected video size of {Path.GetFileName(path)} as {size.Width}x{size.Height}", true);
}
catch
{
Logger.Log("Failed to read video size!");
}
}
return size;
}
public static bool TryDeleteIfExists(string path) // Returns true if no exception occurs
{
try
{
DeleteIfExists(path);
return true;
}
catch (Exception e)
{
Logger.Log($"Error trying to delete {path}: {e.Message}");
return false;
}
}
public static bool DeleteIfExists (string path) // Returns true if the file/dir exists
{
Logger.Log("DeleteIfExists: " + path, true);
if (!IsPathDirectory(path) && File.Exists(path))
{
File.Delete(path);
return true;
}
if (IsPathDirectory(path) && Directory.Exists(path))
{
Directory.Delete(path, true);
return true;
}
return false;
}
public static string GetAiSuffix (AI ai, int times)
{
return $"-{times}x-{ai.aiNameShort.ToUpper()}";
}
public static string GetHighestFrameNumPath (string path)
{
FileInfo highest = null;
int highestInt = -1;
foreach(FileInfo frame in new DirectoryInfo(path).GetFiles("*.*", SearchOption.TopDirectoryOnly))
{
int num = frame.Name.GetInt();
if (num > highestInt)
{
highest = frame;
highestInt = frame.Name.GetInt();
}
}
return highest.FullName;
}
public static string FilenameSuffix (string path, string suffix)
{
try
{
string ext = Path.GetExtension(path);
return Path.Combine(path.GetParentDir(), $"{Path.GetFileNameWithoutExtension(path)}{suffix}{ext}");
}
catch
{
return path;
}
}
public static string GetAudioFile (string basePath)
{
string[] exts = new string[] { "m4a", "ogg", "mp2", "mp3" };
foreach(string ext in exts)
{
string filename = Path.ChangeExtension(basePath, ext);
if (File.Exists(filename))
return filename;
}
return null;
}
public static float GetFpsFolderOrVideo(string path)
{
try
{
if (IsPathDirectory(path))
{
float dirFps = GetVideoFramerateForDir(path);
if (dirFps > 0)
return dirFps;
}
else
{
float vidFps = GetVideoFramerate(path);
if (vidFps > 0)
return vidFps;
}
}
catch (Exception e)
{
Logger.Log("GetFpsFolderOrVideo() Error: " + e.Message);
}
return 0;
}
}
}

41
Code/IO/Paths.cs Normal file
View File

@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Flowframes.IO
{
class Paths
{
public static void Init()
{
}
public static string GetDataPath ()
{
string path = Path.Combine(IOUtils.GetExeDir(), "FlowframesData");
Directory.CreateDirectory(path);
return path;
}
public static string GetPkgPath()
{
string path = Path.Combine(GetDataPath(), "pkgs");
Directory.CreateDirectory(path);
return path;
}
public static string GetLogPath()
{
string path = Path.Combine(GetDataPath(), "logs");
Directory.CreateDirectory(path);
return path;
}
}
}

140
Code/IO/PkgInstaller.cs Normal file
View File

@@ -0,0 +1,140 @@
using Flowframes.Data;
using Flowframes.Forms;
using Flowframes.Properties;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Flowframes.IO
{
class PkgInstaller
{
public static List<FlowPackage> packages = new List<FlowPackage>();
public static InstallerForm installerForm;
static string path7za = "";
public static void Init()
{
packages.Clear();
packages.Add(Packages.dainNcnn);
packages.Add(Packages.cainNcnn);
packages.Add(Packages.rifeCuda);
packages.Add(Packages.audioVideo);
packages.Add(Packages.python);
packages.Add(Packages.licenses);
}
public static FlowPackage GetPkg(string friendlyName)
{
foreach (FlowPackage pkg in packages)
{
if (pkg.friendlyName == friendlyName)
return pkg;
}
return new FlowPackage();
}
static Stopwatch sw = new Stopwatch();
public static async Task DownloadAndInstall(string filename, bool showDialog = true)
{
string savePath = Path.Combine(Paths.GetPkgPath(), filename);
string url = $"https://dl.nmkd.de/flowframes/pkgs/{filename}";
Logger.Log($"[PkgInstaller] Downloading {url}", true);
var client = new WebClient();
//client.Proxy = WebRequest.DefaultWebProxy;
Print($"Downloading {filename}...");
sw.Restart();
client.DownloadProgressChanged += (sender, args) =>
{
if (sw.ElapsedMilliseconds > 200)
{
sw.Restart();
Print($"Downloading {filename}... {args.ProgressPercentage}%", true);
}
};
client.DownloadFileCompleted += (sender, args) =>
{
Print($"Downloading {filename}... 100%", true);
};
await client.DownloadFileTaskAsync(new Uri(url), savePath);
try
{
if (Path.GetExtension(filename).ToLower() == ".7z") // Only run extractor if it's a 7z archive
{
Print($"Installing {filename}...");
await UnSevenzip(Path.Combine(Paths.GetPkgPath(), filename));
}
Print("Done installing.");
installerForm.Refresh();
}
catch (Exception e)
{
Print("Failed to install package: " + e.Message);
Logger.Log($"Failed to uninstall package {Path.GetFileNameWithoutExtension(filename)}: {e.Message}");
}
}
static async Task UnSevenzip(string path)
{
path7za = Path.Combine(Paths.GetDataPath(), "7za.exe");
if (!File.Exists(path7za))
File.WriteAllBytes(path7za, Resources.x64_7za);
Logger.Log("[PkgInstaller] Extracting " + path, true);
await Task.Delay(20);
SevenZipNET.SevenZipExtractor.Path7za = path7za;
SevenZipNET.SevenZipExtractor extractor = new SevenZipNET.SevenZipExtractor(path);
extractor.ExtractAll(Paths.GetPkgPath(), true, true);
File.Delete(path);
await Task.Delay(10);
}
public static void Uninstall(string filename)
{
try
{
string pkgName = Path.GetFileNameWithoutExtension(filename);
Logger.Log("[PkgInstaller] Uninstalling " + pkgName, true);
Print("Uninstalling " + pkgName);
Directory.Delete(Path.Combine(Paths.GetPkgPath(), pkgName), true);
Print("Done uninstalling.");
}
catch (Exception e)
{
Print("Failed to uninstall package!");
Logger.Log($"Failed to uninstall package {Path.GetFileNameWithoutExtension(filename)}: {e.Message}");
}
}
public static bool IsInstalled(FlowPackage pkg)
{
return IsInstalled(pkg.fileName);
}
public static bool IsInstalled(string filename)
{
Logger.Log("PkgInstaller.IsInstalled - Checking for pkg with filename " + filename, true);
string path = Path.Combine(Paths.GetPkgPath(), Path.GetFileNameWithoutExtension(filename));
return Directory.Exists(path);
}
public static bool IsAiAvailable(AI ai, bool msg = true)
{
Logger.Log("PkgInstaller.IsAiAvailable - Checking for AI " + ai.aiName, true);
return IsInstalled(ai.pkg);
}
static void Print(string s, bool replaceLastLine = false)
{
if (installerForm != null)
installerForm.Print(s, replaceLastLine);
}
}
}

48
Code/IO/Setup.cs Normal file
View File

@@ -0,0 +1,48 @@
using Flowframes.IO;
using Flowframes.Properties;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using Flowframes.Forms;
namespace Flowframes
{
class Setup
{
public static void Init()
{
Console.WriteLine("Setup Init()");
if (!InstallIsValid())
{
Logger.Log("No valid installation detected");
new InstallerForm().ShowDialog();
}
else
{
}
}
public static bool InstallIsValid ()
{
if (!Directory.Exists(Paths.GetPkgPath()))
{
Logger.Log("Install invalid - Reason: " + Paths.GetPkgPath() + " does not exist.");
return false;
}
foreach(FlowPackage pkg in PkgInstaller.packages)
{
// if pkg is required and not installed, return false
if (pkg.friendlyName.ToLower().Contains("required") && !PkgInstaller.IsInstalled(pkg.fileName))
return false;
}
return true;
}
}
}

62
Code/Logger.cs Normal file
View File

@@ -0,0 +1,62 @@
using Flowframes.IO;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using DT = System.DateTime;
namespace Flowframes
{
class Logger
{
public static TextBox textbox;
static string file;
public static void Log(string s, bool hidden = false, bool replaceLastLine = false, string filename = "")
{
if (s == null)
return;
Console.WriteLine(s);
try
{
if (replaceLastLine)
textbox.Text = textbox.Text.Remove(textbox.Text.LastIndexOf(Environment.NewLine));
}
catch { }
s = s.Replace("\n", Environment.NewLine);
if (!hidden && textbox != null)
textbox.AppendText(Environment.NewLine + s);
LogToFile(s, false, filename);
}
public static void LogToFile(string s, bool noLineBreak, string filename)
{
if (string.IsNullOrWhiteSpace(filename))
filename = "sessionlog.txt";
file = Path.Combine(Paths.GetLogPath(), filename);
string time = DT.Now.Month + "-" + DT.Now.Day + "-" + DT.Now.Year + " " + DT.Now.Hour + ":" + DT.Now.Minute + ":" + DT.Now.Second;
try
{
if (!noLineBreak)
File.AppendAllText(file, Environment.NewLine + time + ": " + s);
else
File.AppendAllText(file, " " + s);
}
catch
{
// this if fine, i forgot why
}
}
}
}

59
Code/Magick/Coverter.cs Normal file
View File

@@ -0,0 +1,59 @@
using Flowframes;
using Flowframes.UI;
using ImageMagick;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Flowframes.Magick
{
class Coverter
{
public static async Task Convert (string dir, MagickFormat format, int quality, string ext = "", bool print = true, bool setProgress = true)
{
var files = Directory.GetFiles(dir);
if(print) Logger.Log($"Converting {files.Length} files in {dir}");
int counter = 0;
foreach (string file in files)
{
if (print) Logger.Log("Converting " + Path.GetFileName(file) + " to " + format.ToString().StripNumbers().ToUpper(), false, true);
MagickImage img = new MagickImage(file);
img.Format = format;
img.Quality = quality;
string outpath = file;
if (!string.IsNullOrWhiteSpace(ext)) outpath = Path.ChangeExtension(outpath, ext);
img.Write(outpath);
counter++;
if(setProgress)
Program.mainForm.SetProgress((int)Math.Round(((float)counter / files.Length) * 100f));
await Task.Delay(1);
}
}
public static async Task Preprocess (string dir, bool setProgress = true)
{
var files = Directory.GetFiles(dir);
Logger.Log($"Preprocessing {files} files in {dir}");
int counter = 0;
foreach (string file in files)
{
//Logger.Log("Converting " + Path.GetFileName(file) + " to " + format, false, true);
MagickImage img = new MagickImage(file);
//img.Format = MagickFormat.Bmp;
//img.Write(file);
//img = new MagickImage(file);
img.Format = MagickFormat.Png24;
img.Quality = 10;
counter++;
if (setProgress)
Program.mainForm.SetProgress((int)Math.Round(((float)counter / files.Length) * 100f));
await Task.Delay(1);
}
}
}
}

334
Code/Magick/FrameDedup.cs Normal file
View File

@@ -0,0 +1,334 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Flowframes.IO;
using Flowframes.Main;
using ImageMagick;
namespace Flowframes.Magick
{
class FrameDedup
{
public enum Mode { None, Info, Enabled, Auto }
public static Mode currentMode;
public static float currentThreshold;
public static async Task Run(string path, bool testRun = false, bool setStatus = true)
{
UpdateCurrentMode();
if (currentMode == Mode.None)
return;
Program.mainForm.SetStatus("Running frame de-duplication");
currentThreshold = Config.GetFloat("dedupThresh");
Logger.Log("Running frame de-duplication with mode " + currentMode.ToString().Wrap());
if (currentMode == Mode.Enabled || currentMode == Mode.Auto)
await RemoveDupeFrames(path, currentThreshold, "png", testRun, false, (currentMode == Mode.Auto));
}
static void UpdateCurrentMode ()
{
switch (Config.GetInt("dedupMode"))
{
case 0: currentMode = Mode.None; break;
case 1: currentMode = Mode.Enabled; break;
case 2: currentMode = Mode.Auto; break;
}
}
public static async Task RemoveDupeFrames(string path, float threshold, string ext, bool testRun = false, bool debugLog = false, bool skipIfNoDupes = false)
{
Logger.Log("Removing duplicate frames - Threshold: " + threshold.ToString("0.00"));
//Logger.Log("Analyzing frames...");
DirectoryInfo dirInfo = new DirectoryInfo(path);
FileInfo[] framePaths = dirInfo.GetFiles("*." + ext, SearchOption.TopDirectoryOnly);
Dictionary<int, int> framesDupesDict = new Dictionary<int, int>();
int currentOutFrame = 1;
int currentDupeCount = 0;
string dupeInfoFile = Path.Combine(path, "..", "dupes.ini");
int lastFrameNum = 0;
int statsFramesKept = 0;
int statsFramesDeleted = 0;
IOUtils.TryDeleteIfExists(dupeInfoFile);
bool loopMode = Config.GetBool("enableLoop");
int skipAfterNoDupesFrames = Config.GetInt("autoDedupFrames");
bool hasEncounteredAnyDupes = false;
bool skipped = false;
int i = 0;
while (i < framePaths.Length)
{
string frame1 = framePaths[i].FullName;
if (!File.Exists(framePaths[i].FullName)) // Skip if file doesn't exist (used to be a duped frame)
{
i++;
continue;
}
i++;
string frame2;
int oldIndex = -1;
if (i >= framePaths.Length) // If this is the last frame, compare with 1st to avoid OutOfRange error
{
if (loopMode)
{
framesDupesDict = UpdateDupeDict(framesDupesDict, currentOutFrame, 0);
break;
}
oldIndex = i;
i = 0;
}
while (!File.Exists(framePaths[i].FullName)) // If frame2 doesn't exist, keep stepping thru the array
{
if (i >= framePaths.Length)
break;
i++;
}
frame2 = framePaths[i].FullName;
if (oldIndex >= 0)
i = oldIndex;
MagickImage img1 = new MagickImage(frame1);
MagickImage img2 = new MagickImage(frame2);
double err = img1.Compare(img2, ErrorMetric.Fuzz);
float errPercent = (float)err * 100f;
if (debugLog) Logger.Log("[dedup] current in frame: " + i);
if (debugLog) Logger.Log("[dedup] current out frame: " + currentOutFrame);
framesDupesDict = UpdateDupeDict(framesDupesDict, currentOutFrame, currentDupeCount);
lastFrameNum = currentOutFrame;
string delStr = "Keeping";
if (errPercent < threshold) // Is a duped frame.
{
if (!testRun)
{
delStr = "Deleting";
File.Delete(frame1);
if(debugLog) Logger.Log("[FrameDedup] Deleted " + Path.GetFileName(frame1));
hasEncounteredAnyDupes = true;
i--; // Turn the index back so we compare the same frame again, this time to the next one after the deleted frame
}
statsFramesDeleted++;
currentDupeCount++;
}
else
{
statsFramesKept++;
currentOutFrame++;
currentDupeCount = 0;
}
Logger.Log($"[FrameDedup] Difference from {Path.GetFileName(img1.FileName)} to {Path.GetFileName(img2.FileName)}: {errPercent.ToString("0.00")}% - {delStr}. Total: {statsFramesKept} kept / {statsFramesDeleted} deleted.", false, true);
img1.Dispose();
img2.Dispose();
Program.mainForm.SetProgress((int)Math.Round(((float)i / framePaths.Length) * 100f));
await Task.Delay(10);
if(!testRun && skipIfNoDupes && !hasEncounteredAnyDupes && i >= skipAfterNoDupesFrames)
{
skipped = true;
break;
}
}
string testStr = "";
if (testRun) testStr = " [TestRun]";
if (Interpolate.cancelled) return;
if (skipped)
{
Logger.Log($"[FrameDedup] First {skipAfterNoDupesFrames} frames did not have any duplicates - Skipping the rest!");
}
else
{
if(!testRun)
File.WriteAllLines(dupeInfoFile, framesDupesDict.Select(x => "frm" + x.Key + ":dup" + x.Value).ToArray());
Logger.Log($"[FrameDedup]{testStr} Done. Kept {statsFramesKept} frames, deleted {statsFramesDeleted} frames.", false, true);
}
RenameCounterDir(path, "png");
ZeroPadDir(path, ext, 8);
}
static Dictionary<int, int> UpdateDupeDict(Dictionary<int, int> dict, int frame, int amount)
{
if (dict.ContainsKey(frame))
dict[frame] = amount;
else
dict.Add(frame, amount);
return dict;
}
public static async Task Reduplicate(string path, bool debugLog = false)
{
if (currentMode == Mode.None)
return;
string ext = InterpolateUtils.lastExt;
string dupeInfoFile = Path.Combine(Interpolate.currentTempDir, "dupes.ini");
if (!File.Exists(dupeInfoFile)) return;
Logger.Log("Re-Duplicating frames to fix timing...");
RenameCounterDir(path, ext);
ZeroPadDir(path, ext, 8);
string[] dupeFrameLines = IOUtils.ReadLines(dupeInfoFile);
string tempSubFolder = Path.Combine(path, "temp");
Directory.CreateDirectory(tempSubFolder);
int interpFramesPerRealFrame = Interpolate.interpFactor - 1;
int sourceFrameNum = 0;
int outFrameNum = 1;
for (int i = 0; i < dupeFrameLines.Length; i++)
{
string line = dupeFrameLines[i];
sourceFrameNum++;
string paddedFilename = "";
string sourceFramePath = "";
string[] kvp = line.Split(':');
int currentInFrame = kvp[0].GetInt();
int currentDupesAmount = kvp[1].GetInt();
// Copy Source Frame
paddedFilename = sourceFrameNum.ToString().PadLeft(8, '0') + $".{ext}";
sourceFramePath = Path.Combine(path, paddedFilename);
if(debugLog) Logger.Log("[Source] Moving " + Path.GetFileName(sourceFramePath) + " => " + outFrameNum + $".{ext}");
if (!TryCopy(sourceFramePath, Path.Combine(tempSubFolder, outFrameNum + $".{ext}")))
break;
outFrameNum++;
// Insert dupes for source frame
for (int copyTimes = 0; copyTimes < currentDupesAmount; copyTimes++)
{
paddedFilename = sourceFrameNum.ToString().PadLeft(8, '0') + $".{ext}";
sourceFramePath = Path.Combine(path, paddedFilename);
if (debugLog) Logger.Log("[Source Dupes] Moving " + Path.GetFileName(sourceFramePath) + " => " + outFrameNum + $".{ext}");
if (!TryCopy(sourceFramePath, Path.Combine(tempSubFolder, outFrameNum + $".{ext}")))
break;
outFrameNum++;
}
if (i == dupeFrameLines.Length - 1) // Break loop if this is the last input frame (as it has no interps)
break;
for(int interpFrames = 0; interpFrames < interpFramesPerRealFrame; interpFrames++)
{
sourceFrameNum++;
// Copy Interp Frame
paddedFilename = sourceFrameNum.ToString().PadLeft(8, '0') + $".{ext}";
sourceFramePath = Path.Combine(path, paddedFilename);
if (debugLog) Logger.Log("[Interp] Moving " + Path.GetFileName(sourceFramePath) + " => " + outFrameNum + $".{ext}");
if (!TryCopy(sourceFramePath, Path.Combine(tempSubFolder, outFrameNum + $".{ext}")))
break;
outFrameNum++;
// Insert dupes for interp frame
for (int copyTimes = 0; copyTimes < currentDupesAmount; copyTimes++)
{
paddedFilename = sourceFrameNum.ToString().PadLeft(8, '0') + $".{ext}";
sourceFramePath = Path.Combine(path, paddedFilename);
if (debugLog) if (debugLog) Logger.Log("[Interp Dupes] Moving " + Path.GetFileName(sourceFramePath) + " => " + outFrameNum + $".{ext}");
if (!TryCopy(sourceFramePath, Path.Combine(tempSubFolder, outFrameNum + $".{ext}")))
break;
outFrameNum++;
}
}
}
ZeroPadDir(tempSubFolder, ext, 8);
foreach (FileInfo file in new DirectoryInfo(path).GetFiles($"*.{ext}", SearchOption.TopDirectoryOnly))
file.Delete();
foreach (FileInfo file in new DirectoryInfo(tempSubFolder).GetFiles($"*.{ext}", SearchOption.TopDirectoryOnly))
file.MoveTo(Path.Combine(path, file.Name));
}
static bool TryCopy(string source, string target)
{
try
{
File.Copy(source, target);
}
catch
{
return false;
}
return true;
}
static bool TryMove(string source, string target)
{
try
{
if (File.Exists(target))
File.Delete(target);
File.Move(source, target);
}
catch
{
return false;
}
return true;
}
public static void RenameCounterDir(string path, string ext, int sortMode = 0)
{
int counter = 1;
FileInfo[] files = new DirectoryInfo(path).GetFiles($"*.{ext}", SearchOption.TopDirectoryOnly);
var filesSorted = files.OrderBy(n => n);
if (sortMode == 1)
filesSorted.Reverse();
foreach (FileInfo file in files)
{
string dir = new DirectoryInfo(file.FullName).Parent.FullName;
int filesDigits = (int)Math.Floor(Math.Log10((double)files.Length) + 1);
File.Move(file.FullName, Path.Combine(dir, counter.ToString()/*.PadLeft(filesDigits, '8')*/ + Path.GetExtension(file.FullName)));
counter++;
}
}
static void ZeroPadDir(string path, string ext, int targetLength, bool recursive = false)
{
FileInfo[] files;
if (recursive)
files = new DirectoryInfo(path).GetFiles($"*.{ext}", SearchOption.AllDirectories);
else
files = new DirectoryInfo(path).GetFiles($"*.{ext}", SearchOption.TopDirectoryOnly);
foreach (FileInfo file in files)
{
string fnameNoExt = Path.GetFileNameWithoutExtension(file.Name);
string ext2 = Path.GetExtension(file.Name); ;
File.Move(file.FullName, Path.Combine(Path.GetDirectoryName(file.FullName), fnameNoExt.PadLeft(targetLength, '0') + ext2));
}
}
}
}

View File

@@ -0,0 +1,108 @@
using Flowframes.Forms;
using Flowframes.IO;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Flowframes.Main
{
class BatchProcessing
{
public static bool stopped = false;
public static BatchForm currentBatchForm;
public static bool busy = false;
public static async void Start()
{
stopped = false;
Program.mainForm.GetMainTabControl().SelectedIndex = 2;
int initTaskCount = Program.batchQueue.Count;
for (int i = 0; i < initTaskCount; i++)
{
if (!stopped && Program.batchQueue.Count > 0)
{
Logger.Log($"[Queue] Running queue task {i + 1}/{initTaskCount}, {Program.batchQueue.Count} tasks left.");
await RunEntry(Program.batchQueue.Peek());
if (currentBatchForm != null)
currentBatchForm.RefreshGui();
}
await Task.Delay(1000);
}
Logger.Log("[Queue] Finished queue processing.");
SetBusy(false);
Program.mainForm.GetMainTabControl().SelectedIndex = 0;
}
public static void Stop()
{
stopped = true;
}
static async Task RunEntry(BatchEntry entry)
{
if (!EntryIsValid(entry))
{
Logger.Log("[Queue] Skipping entry because it's invalid.");
Program.batchQueue.Dequeue();
return;
}
string fname = Path.GetFileName(entry.inPath);
if (IOUtils.IsPathDirectory(entry.inPath)) fname = Path.GetDirectoryName(entry.inPath);
Logger.Log($"[Queue] Processing {fname} ({entry.interpFactor}x {entry.ai.aiNameShort}).");
SetBusy(true);
Program.mainForm.LoadBatchEntry(entry); // Load entry into GUI
Interpolate.interpFactor = entry.interpFactor;
Interpolate.SetFps(entry.inFps);
Program.mainForm.runBtn_Click(null, null);
await Task.Delay(2000);
while (Program.busy)
await Task.Delay(1000);
SetBusy(false);
Program.batchQueue.Dequeue();
Logger.Log($"[Queue] Done processing {fname} ({entry.interpFactor}x {entry.ai.aiNameShort}).");
}
static void SetBusy(bool state)
{
busy = state;
if (currentBatchForm != null)
currentBatchForm.SetWorking(state);
Program.mainForm.SetWorking(state);
Program.mainForm.GetMainTabControl().Enabled = !state; // Lock GUI
}
static bool EntryIsValid(BatchEntry entry)
{
if (entry.inPath == null || (IOUtils.IsPathDirectory(entry.inPath) && !Directory.Exists(entry.inPath)) || (!IOUtils.IsPathDirectory(entry.inPath) && !File.Exists(entry.inPath)))
{
Logger.Log("[Queue] Can't process queue entry: Input path is invalid.");
return false;
}
if (entry.outPath == null || !Directory.Exists(entry.outPath))
{
Logger.Log("[Queue] Can't process queue entry: Output path is invalid.");
return false;
}
if (!PkgInstaller.IsAiAvailable(entry.ai))
{
Logger.Log("[Queue] Can't process queue entry: Selected AI is not available.");
return false;
}
return true;
}
}
}

127
Code/Main/CreateVideo.cs Normal file
View File

@@ -0,0 +1,127 @@
using Flowframes;
using Flowframes.FFmpeg;
using Flowframes.IO;
using Flowframes.Magick;
using Flowframes.Main;
using Flowframes.OS;
using Flowframes.UI;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using i = Flowframes.Interpolate;
namespace Flowframes.Main
{
class CreateVideo
{
public static async Task FramesToVideo(string path, string outPath, i.OutMode mode)
{
if (!mode.ToString().ToLower().Contains("vid")) // Skip output mode is not a video (e.g. image sequence)
return;
if (IOUtils.GetAmountOfFiles(path, false, $"*.{InterpolateUtils.lastExt}") <= 1)
{
i.Cancel("Output folder does not contain frames - An error must have occured during interpolation!");
return;
}
await Task.Delay(10);
if(Config.GetInt("timingMode") == 1)
await FrameDedup.Reduplicate(path);
Program.mainForm.SetStatus("Creating output video from frames...");
try
{
int maxFps = Config.GetInt("maxFps");
if (maxFps == 0) maxFps = 500;
if (mode == i.OutMode.VidMp4 && i.currentOutFps > maxFps)
{
bool createSecondVid = (Config.GetInt("maxFpsMode") == 1);
await Encode(mode, path, outPath, i.currentOutFps, maxFps, createSecondVid);
}
else
{
await Encode(mode, path, outPath, i.currentOutFps);
}
}
catch (Exception e)
{
Logger.Log("FramesToVideo Error: " + e.Message, false);
MessageBox.Show("An error occured while trying to convert the interpolated frames to a video.\nCheck the log for details.");
}
}
static async Task Encode(i.OutMode mode, string framesPath, string outPath, float fps, float changeFps = -1, bool keepOriginalFpsVid = true)
{
if (mode == i.OutMode.VidGif)
{
if (new DirectoryInfo(framesPath).GetFiles()[0].Extension != ".png")
{
Logger.Log("Converting output frames to PNG to encode with Gifski...");
await Coverter.Convert(framesPath, ImageMagick.MagickFormat.Png00, 20, "png", false);
}
await GifskiCommands.CreateGifFromFrames(i.currentOutFps.RoundToInt(), Config.GetInt("gifskiQ"), framesPath, outPath);
}
if (mode == i.OutMode.VidMp4)
{
string ext = InterpolateUtils.lastExt;
int looptimes = GetLoopTimes(framesPath);
if (looptimes > 0) Logger.Log($"Looping {looptimes} times to reach target length");
bool h265 = Config.GetInt("mp4Enc") == 1;
int crf = h265 ? Config.GetInt("h265Crf") : Config.GetInt("h264Crf");
await FFmpegCommands.FramesToMp4(framesPath, outPath, h265, crf, fps, "", false, looptimes, ext);
await MergeAudio(i.lastInputPath, outPath);
if (changeFps > 0)
{
string newOutPath = IOUtils.FilenameSuffix(outPath, $"-{changeFps.ToString("0")}fps");
Program.mainForm.SetStatus("Creating video with desired frame rate...");
await FFmpegCommands.ConvertFramerate(outPath, newOutPath, h265, crf, changeFps, !keepOriginalFpsVid);
await MergeAudio(i.lastInputPath, newOutPath);
}
}
}
static int GetLoopTimes(string framesOutPath)
{
int minLength = Config.GetInt("minOutVidLength");
int minFrameCount = (minLength * i.currentOutFps).RoundToInt();
int outFrames = new DirectoryInfo(framesOutPath).GetFiles($"*.{InterpolateUtils.lastExt}", SearchOption.TopDirectoryOnly).Length;
if (outFrames / i.currentOutFps < minLength)
return (int)Math.Ceiling((double)minFrameCount / (double)outFrames);
return -1;
}
public static async Task MergeAudio(string sourceVideo, string outVideo, int looptimes = -1)
{
if (!Config.GetBool("enableAudio")) return;
try
{
Logger.Log("Adding input audio to output video...");
string audioFileBasePath = Path.Combine(i.currentTempDir, "audio");
if(IOUtils.IsPathDirectory(sourceVideo) && !File.Exists(IOUtils.GetAudioFile(audioFileBasePath))) // Try loading out of same folder as input if input is a folder
audioFileBasePath = Path.Combine(i.currentTempDir.GetParentDir(), "audio");
if (!File.Exists(IOUtils.GetAudioFile(audioFileBasePath)))
await FFmpegCommands.ExtractAudio(sourceVideo, audioFileBasePath); // Extract from sourceVideo to audioFile unless it already exists
if (!File.Exists(IOUtils.GetAudioFile(audioFileBasePath)))
{
Logger.Log("No compatible audio stream found.");
return;
}
await FFmpegCommands.MergeAudio(outVideo, IOUtils.GetAudioFile(audioFileBasePath)); // Merge from audioFile into outVideo
}
catch
{
Logger.Log("Failed to copy audio!");
}
}
}
}

198
Code/Main/Interpolate.cs Normal file
View File

@@ -0,0 +1,198 @@
using Flowframes;
using Flowframes.Data;
using Flowframes.FFmpeg;
using Flowframes.IO;
using Flowframes.Magick;
using Flowframes.Main;
using Flowframes.OS;
using Flowframes.UI;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using Utils = Flowframes.Main.InterpolateUtils;
namespace Flowframes
{
public class Interpolate
{
public enum OutMode { VidMp4, VidGif, ImgPng, ImgJpg }
public static string currentTempDir;
static string framesPath;
public static int interpFactor;
public static float currentInFps;
public static float currentOutFps;
public static string lastInputPath;
public static bool cancelled = false;
static Stopwatch sw = new Stopwatch();
public static void SetFps(float inFps)
{
currentInFps = inFps;
currentOutFps = inFps * interpFactor;
}
public static async void Start(string inPath, string outDir, int tilesize, OutMode outMode, AI ai)
{
cancelled = false;
if (!Utils.InputIsValid(inPath, outDir, currentOutFps, interpFactor, tilesize)) return; // General input checks
if (!Utils.CheckAiAvailable(ai)) return; // Check if selected AI pkg is installed
lastInputPath = inPath;
currentTempDir = Utils.GetTempFolderLoc(inPath, outDir);
framesPath = Path.Combine(currentTempDir, "frames");
if (!Utils.CheckDeleteOldTempFolder()) return; // Try to delete temp folder if an old one exists
if(!Utils.CheckPathValid(inPath)) return; // Check if input path/file is valid
Utils.PathAsciiCheck(inPath, outDir);
Program.mainForm.SetStatus("Starting...");
Program.mainForm.SetWorking(true);
await Task.Delay(10);
if (!IOUtils.IsPathDirectory(inPath)) // Input is video - extract frames first
await ExtractFrames(inPath, framesPath);
else
IOUtils.Copy(inPath, framesPath);
if (cancelled) return;
sw.Restart();
await Task.Delay(10);
await FrameDedup.Run(framesPath);
if (cancelled) return;
string interpFramesDir = Path.Combine(currentTempDir, "frames-interpolated");
string outPath = Path.Combine(outDir, Path.GetFileNameWithoutExtension(inPath) + IOUtils.GetAiSuffix(ai, interpFactor) + Utils.GetExt(outMode));
int frames = IOUtils.GetAmountOfFiles(framesPath, false, "*.png");
int targetFrameCount = frames * interpFactor;
GetProgressByFrameAmount(interpFramesDir, targetFrameCount);
if (cancelled) return;
Program.mainForm.SetStatus("Running AI...");
await RunAi(interpFramesDir, targetFrameCount, tilesize, ai);
if (cancelled) return;
Program.mainForm.SetProgress(100);
await CreateVideo.FramesToVideo(interpFramesDir, outPath, outMode);
Cleanup(interpFramesDir);
Program.mainForm.SetWorking(false);
Logger.Log("Total processing time: " + FormatUtils.Time(sw.Elapsed));
sw.Stop();
Program.mainForm.SetStatus("Done interpolating!");
}
public static async Task ExtractFrames(string inPath, string outPath, bool extractAudio = true)
{
Logger.Log("Extracting frames using FFmpeg...");
await Task.Delay(10);
bool rgb8 = Formats.preprocess.Contains(Path.GetExtension(inPath).ToLower());
Program.mainForm.SetStatus("Extracting frames from video...");
Size resolution = IOUtils.GetVideoRes(inPath);
int maxHeight = Config.GetInt("maxVidHeight");
if (resolution.Height > maxHeight)
{
float factor = (float)maxHeight / resolution.Height;
int width = (resolution.Width * factor).RoundToInt();
Logger.Log($"Video is bigger than the maximum - Downscaling to {width}x{maxHeight}.");
await FFmpegCommands.VideoToFrames(inPath, outPath, width, maxHeight, false, rgb8, false, false);
}
else
{
await FFmpegCommands.VideoToFrames(inPath, outPath, false, rgb8, false, false);
}
/*
if (AvProcess.lastOutputFfmpeg.ToLower().Contains("invalid"))
{
Cancel("Failed to read input video.");
return;
}
*/
if (extractAudio)
{
string audioFile = Path.Combine(currentTempDir, "audio.m4a");
if (!File.Exists(audioFile))
await FFmpegCommands.ExtractAudio(inPath, audioFile);
}
if (!cancelled && Config.GetBool("enableLoop"))
{
string lastFrame = IOUtils.GetHighestFrameNumPath(outPath);
int newNum = Path.GetFileName(lastFrame).GetInt() + 1;
string newFilename = Path.Combine(lastFrame.GetParentDir(), newNum.ToString().PadLeft(8, '0') + ".png");
string firstFrame = Path.Combine(lastFrame.GetParentDir(), 1.ToString().PadLeft(8, '0') + ".png");
File.Copy(firstFrame, newFilename);
Logger.Log("Copied loop frame.");
}
}
static async Task RunAi(string outpath, int targetFrames, int tilesize, AI ai)
{
Directory.CreateDirectory(outpath);
if (ai.aiName == Networks.dainNcnn.aiName)
await AiProcess.RunDainNcnn(framesPath, outpath, targetFrames, tilesize);
if (ai.aiName == Networks.cainNcnn.aiName)
await AiProcess.RunCainNcnnMulti(framesPath, outpath, tilesize, interpFactor);
if (ai.aiName == Networks.rifeCuda.aiName)
await AiProcess.RunRifeCuda(framesPath, interpFactor);
}
public static async void GetProgressByFrameAmount(string outdir, int target)
{
bool firstProgUpd = true;
Program.mainForm.SetProgress(0);
while (Program.busy)
{
if (AiProcess.processTime.IsRunning && Directory.Exists(outdir))
{
if (firstProgUpd && Program.mainForm.IsInFocus())
Program.mainForm.GetMainTabControl().SelectedIndex = 2;
firstProgUpd = false;
string[] frames = Directory.GetFiles(outdir, $"*.{Utils.lastExt}");
if (frames.Length > 1)
Utils.UpdateInterpProgress(frames.Length, target, frames[frames.Length - 1]);
await Task.Delay(Utils.GetProgressWaitTime(frames.Length));
}
else
{
await Task.Delay(200);
}
}
Program.mainForm.SetProgress(-1);
}
public static void Cancel(string reason = "")
{
if (AiProcess.currentAiProcess != null && !AiProcess.currentAiProcess.HasExited)
OSUtils.KillProcessTree(AiProcess.currentAiProcess.Id);
if (AvProcess.lastProcess != null && !AvProcess.lastProcess.HasExited)
OSUtils.KillProcessTree(AvProcess.lastProcess.Id);
cancelled = true;
Program.mainForm.SetStatus("Cancelled.");
Program.mainForm.SetProgress(0);
IOUtils.TryDeleteIfExists(currentTempDir);
Program.mainForm.SetWorking(false);
Logger.Log("Cancelled interpolation.");
if (!string.IsNullOrWhiteSpace(reason))
Utils.ShowMessage($"Cancelled:\n\n{reason}");
}
static void Cleanup(string interpFramesDir)
{
if (Config.GetBool("keepTempFolder")) return;
Logger.Log("Deleting temporary files...");
try
{
if (Config.GetBool("keepFrames"))
IOUtils.Copy(interpFramesDir, Path.Combine(currentTempDir.GetParentDir(), Path.GetFileName(currentTempDir).Replace("-temp", "-interpframes")));
Directory.Delete(currentTempDir, true);
}
catch (Exception e)
{
Logger.Log("Cleanup Error: " + e.Message, true);
}
}
}
}

View File

@@ -0,0 +1,231 @@
using Flowframes.Data;
using Flowframes.Forms;
using Flowframes.IO;
using Flowframes.OS;
using Flowframes.UI;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using i = Flowframes.Interpolate;
namespace Flowframes.Main
{
class InterpolateUtils
{
public static PictureBox preview;
public static BigPreviewForm bigPreviewForm;
public static string lastExt = "png";
public static void UpdateInterpProgress(int frames, int target, string latestFramePath = "")
{
int percent = (int)Math.Round(((float)frames / target) * 100f);
Program.mainForm.SetProgress(percent);
float generousTime = ((AiProcess.processTime.ElapsedMilliseconds - 1000) / 1000f);
float fps = (float)frames / generousTime;
string fpsIn = (fps / Interpolate.interpFactor).ToString("0.00");
string fpsOut = fps.ToString("0.00");
float secondsPerFrame = generousTime / (float)frames;
int framesLeft = target - frames;
float eta = framesLeft * secondsPerFrame;
string etaStr = FormatUtils.Time(new TimeSpan(0, 0, eta.RoundToInt()));
bool replaceLine = Regex.Split(Logger.textbox.Text, "\r\n|\r|\n").Last().Contains("Average Speed: ");
Logger.Log($"Interpolated {frames}/{target} frames ({percent}%) - Average Speed: {fpsIn} FPS In / {fpsOut} FPS Out - Time: {FormatUtils.Time(AiProcess.processTime.Elapsed)} - ETA: {etaStr}", false, replaceLine);
try
{
if (!string.IsNullOrWhiteSpace(latestFramePath) && frames > Interpolate.interpFactor)
{
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);
}
}
catch { }
}
public static int GetProgressWaitTime(int numFrames)
{
float hddMultiplier = 2f;
if (Program.lastInputPathIsSsd)
hddMultiplier = 1f;
int waitMs = 200;
if (numFrames > 100)
waitMs = 500;
if (numFrames > 1000)
waitMs = 1000;
if (numFrames > 2500)
waitMs = 1500;
if (numFrames > 5000)
waitMs = 2500;
return (waitMs * hddMultiplier).RoundToInt();
}
public static string GetTempFolderLoc (string inPath, string outPath)
{
string basePath = inPath.GetParentDir();
if(Config.GetInt("tempFolderLoc") == 1)
basePath = outPath.GetParentDir();
if (Config.GetInt("tempFolderLoc") == 2)
basePath = outPath;
if (Config.GetInt("tempFolderLoc") == 3)
basePath = IOUtils.GetExeDir();
if (Config.GetInt("tempFolderLoc") == 4)
{
string custPath = Config.Get("tempDirCustom");
if(IOUtils.IsDirValid(custPath))
basePath = custPath;
}
return Path.Combine(basePath, Path.GetFileNameWithoutExtension(inPath).StripBadChars() + "-temp");
}
public static bool InputIsValid(string inDir, string outDir, float fpsOut, int interp, int tilesize)
{
bool passes = true;
bool isFile = !IOUtils.IsPathDirectory(inDir);
if ((isFile && !IOUtils.IsFileValid(inDir)) || (!isFile && !IOUtils.IsDirValid(inDir)))
{
ShowMessage("Input path is not valid!");
passes = false;
}
if (!IOUtils.IsDirValid(outDir))
{
ShowMessage("Output path is not valid!");
passes = false;
}
if (interp != 2 && interp != 4 && interp != 8)
{
ShowMessage("Interpolation factor is not valid!");
passes = false;
}
if (fpsOut < 1 || fpsOut > 500)
{
ShowMessage("Invalid target frame rate - Must be 1-500.");
passes = false;
}
if (tilesize % 32 != 0 || tilesize < 128)
{
ShowMessage("Tile size is not valid - Must be a multiple of 32 and at least 128!");
passes = false;
}
if (!passes)
i.Cancel("Invalid settings detected.");
return passes;
}
public static void PathAsciiCheck (string inpath, string outpath)
{
if (OSUtils.HasNonAsciiChars(inpath))
Logger.Log("Warning: Input path includes non-ASCII characters. This might cause problems.");
if (OSUtils.HasNonAsciiChars(outpath))
Logger.Log("Warning: Output path includes non-ASCII characters. This might cause problems.");
}
public static void GifCompatCheck (Interpolate.OutMode outMode, float fpsOut, int targetFrameCount)
{
if (outMode != Interpolate.OutMode.VidGif)
return;
if(fpsOut >= 50f)
Logger.Log("Warning: GIFs above 50 FPS might play slower on certain software/hardware! MP4 is recommended for higher frame rates.");
int maxGifFrames = 200;
if (targetFrameCount > maxGifFrames)
{
ShowMessage($"You can't use GIF with more than {maxGifFrames} output frames!\nPlease use MP4 for this.", "Error");
i.Cancel($"Can't use GIF encoding with more than {maxGifFrames} frames!");
}
}
public static bool CheckAiAvailable (AI ai)
{
if (!PkgInstaller.IsAiAvailable(ai))
{
ShowMessage("The selected AI is not installed!\nYou can download it from the package installer.", "Error");
i.Cancel("Selected AI not available.");
return false;
}
return true;
}
public static bool CheckDeleteOldTempFolder ()
{
if (!IOUtils.TryDeleteIfExists(i.currentTempDir))
{
ShowMessage("Failed to remove an existing temp folder of this video!\nMake sure you didn't open any frames in an editor.", "Error");
i.Cancel();
return false;
}
return true;
}
public static bool CheckPathValid (string path)
{
if (IOUtils.IsPathDirectory(path))
{
if (!IOUtils.IsDirValid(path))
{
ShowMessage("Input directory is not valid.");
i.Cancel();
return false;
}
}
else
{
if (!IsVideoValid(path))
{
ShowMessage("Input video file is not valid.");
return false;
}
}
return true;
}
public static bool IsVideoValid(string videoPath)
{
if (videoPath == null || !IOUtils.IsFileValid(videoPath))
return false;
string ext = Path.GetExtension(videoPath);
if (Formats.supported.Contains(ext))
return true;
return false;
}
public static string GetExt(i.OutMode format)
{
if (format == i.OutMode.VidMp4)
return ".mp4";
if (format == i.OutMode.VidGif)
return ".gif";
return ".mp4";
}
public static void ShowMessage(string msg, string title = "Message")
{
if (!BatchProcessing.busy)
MessageBox.Show(msg, title);
Logger.Log("Message: " + msg, true);
}
}
}

166
Code/OS/AiProcess.cs Normal file
View File

@@ -0,0 +1,166 @@
using Flowframes.IO;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Flowframes.OS;
using Flowframes.UI;
using Flowframes.Main;
namespace Flowframes
{
class AiProcess
{
public static Process currentAiProcess;
public static Stopwatch processTime = new Stopwatch();
public static async Task RunDainNcnn(string framesPath, string outPath, int targetFrames, int tilesize)
{
InterpolateUtils.lastExt = "png";
if (Config.GetBool("jpegInterps")) InterpolateUtils.lastExt = "jpg";
string args = $" -v -i {framesPath.Wrap()} -o {outPath.Wrap()} -n {targetFrames} -t {tilesize} -g {Config.Get("ncnnGpus")}";
string dainDir = Path.Combine(Paths.GetPkgPath(), Path.GetFileNameWithoutExtension(Packages.dainNcnn.fileName));
Process dain = OSUtils.NewProcess(!OSUtils.ShowHiddenCmd());
dain.StartInfo.Arguments = $"{OSUtils.GetHiddenCmdArg()} cd /D {dainDir.Wrap()} & dain-ncnn-vulkan.exe {args} -f {InterpolateUtils.lastExt}";
Logger.Log("Running DAIN...", false);
Logger.Log("cmd.exe " + dain.StartInfo.Arguments, true);
if (!OSUtils.ShowHiddenCmd())
{
dain.OutputDataReceived += (sender, outLine) => { LogOutput(outLine.Data, "dain-ncnn-log.txt"); };
dain.ErrorDataReceived += (sender, outLine) => { LogOutput("[E] " + outLine.Data, "dain-ncnn-log.txt"); };
}
processTime.Restart();
currentAiProcess = dain;
dain.Start();
if (!OSUtils.ShowHiddenCmd())
{
dain.BeginOutputReadLine();
dain.BeginErrorReadLine();
}
while (!dain.HasExited)
await Task.Delay(1);
Logger.Log($"Done running DAIN - Interpolation took " + FormatUtils.Time(processTime.Elapsed));
processTime.Stop();
}
public static async Task RunCainNcnnMulti (string framesPath, string outPath, int tilesize, int times)
{
InterpolateUtils.lastExt = "png";
if (Config.GetBool("jpegInterps")) InterpolateUtils.lastExt = "jpg";
Logger.Log("Running CAIN...", false);
string args = $" -v -i {framesPath.Wrap()} -o {outPath.Wrap()} -t {tilesize} -g {Config.Get("ncnnGpus")}";
await RunCainPartial(args);
if(times == 4 || times == 8) // #2
{
Logger.Log("Re-Running CAIN for 4x interpolation...", false);
string run1ResultsPath = outPath + "-run1";
IOUtils.TryDeleteIfExists(run1ResultsPath);
Directory.Move(outPath, run1ResultsPath);
Directory.CreateDirectory(outPath);
args = $" -v -i {run1ResultsPath.Wrap()} -o {outPath.Wrap()} -t {tilesize} -g {Config.Get("ncnnGpus")}";
await RunCainPartial(args);
Directory.Delete(run1ResultsPath, true);
}
if (times == 8) // #3
{
Logger.Log("Re-Running CAIN for 8x interpolation...", false);
string run2ResultsPath = outPath + "-run2";
IOUtils.TryDeleteIfExists(run2ResultsPath);
Directory.Move(outPath, run2ResultsPath);
Directory.CreateDirectory(outPath);
args = $" -v -i {run2ResultsPath.Wrap()} -o {outPath.Wrap()} -t {tilesize} -g {Config.Get("ncnnGpus")}";
await RunCainPartial(args);
Directory.Delete(run2ResultsPath, true);
}
Logger.Log($"Done running CAIN - Interpolation took " + FormatUtils.Time(processTime.Elapsed));
processTime.Stop();
}
static async Task RunCainPartial (string args)
{
string cainDir = Path.Combine(Paths.GetPkgPath(), Path.GetFileNameWithoutExtension(Packages.cainNcnn.fileName));
string cainExe = "cain-ncnn-vulkan.exe";
Process cain = OSUtils.NewProcess(!OSUtils.ShowHiddenCmd());
cain.StartInfo.Arguments = $"{OSUtils.GetHiddenCmdArg()} cd /D {cainDir.Wrap()} & {cainExe} {args} -f {InterpolateUtils.lastExt}";
Logger.Log("cmd.exe " + cain.StartInfo.Arguments, true);
if (!OSUtils.ShowHiddenCmd())
{
cain.OutputDataReceived += (sender, outLine) => { LogOutput(outLine.Data, "cain-ncnn-log.txt"); };
cain.ErrorDataReceived += (sender, outLine) => { LogOutput("[E] " + outLine.Data, "cain-ncnn-log.txt"); };
}
processTime.Restart();
currentAiProcess = cain;
cain.Start();
if (!OSUtils.ShowHiddenCmd())
{
cain.BeginOutputReadLine();
cain.BeginErrorReadLine();
}
while (!cain.HasExited) await Task.Delay(1);
}
public static async Task RunRifeCuda(string framesPath, int interpFactor)
{
InterpolateUtils.lastExt = "png";
if (Config.GetBool("jpegInterps")) InterpolateUtils.lastExt = "jpg";
string script = "interp-parallel.py";
if(Config.GetInt("rifeMode") == 0 || IOUtils.GetAmountOfFiles(framesPath, false) < 30)
script = "interp-basic.py";
string rifeDir = Path.Combine(Paths.GetPkgPath(), Path.GetFileNameWithoutExtension(Packages.rifeCuda.fileName));
Process rifePy = OSUtils.NewProcess(!OSUtils.ShowHiddenCmd());
string args = $" --input {framesPath.Wrap()} --times {(int)Math.Log(interpFactor, 2)}";
rifePy.StartInfo.Arguments = $"{OSUtils.GetHiddenCmdArg()} cd /D {rifeDir.Wrap()} & " +
$"set CUDA_VISIBLE_DEVICES={Config.Get("torchGpus")} & {Python.GetPyCmd()} {script} {args} --imgformat {InterpolateUtils.lastExt}";
Logger.Log($"Running RIFE ({script})...", false);
Logger.Log("cmd.exe " + rifePy.StartInfo.Arguments, true);
if (!OSUtils.ShowHiddenCmd())
{
rifePy.OutputDataReceived += (sender, outLine) => { LogOutput(outLine.Data, "rife-cuda-log.txt"); };
rifePy.ErrorDataReceived += (sender, outLine) => { LogOutput("[E] " + outLine.Data, "rife-cuda-log.txt"); };
}
processTime.Restart();
currentAiProcess = rifePy;
rifePy.Start();
if (!OSUtils.ShowHiddenCmd())
{
rifePy.BeginOutputReadLine();
rifePy.BeginErrorReadLine();
}
while (!rifePy.HasExited)
await Task.Delay(1);
Logger.Log($"Done running RIFE - Interpolation took " + FormatUtils.Time(processTime.Elapsed));
processTime.Stop();
}
static void LogOutput (string line, string logFilename)
{
if (line == null)
return;
Logger.LogToFile(line, false, logFilename);
if (line.ToLower().Contains("modulenotfounderror"))
InterpolateUtils.ShowMessage($"A python module is missing. Check {logFilename} for details.\n\n{line}", "Error");
if (line.ToLower().Contains("ff:nocuda-cpu"))
Logger.Log($"WARNING: CUDA-capable GPU device is not available, running on CPU instead!");
if (line.ToLower().Contains("no longer supports this gpu"))
InterpolateUtils.ShowMessage("Your GPU seems to be outdated and is not supported!\n\n{line}", "Error");
}
}
}

92
Code/OS/NvApi.cs Normal file
View File

@@ -0,0 +1,92 @@
using NvAPIWrapper;
using NvAPIWrapper.GPU;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Flowframes.OS
{
class NvApi
{
static PhysicalGPU gpu;
static float vramGb;
static float vramFreeGb;
public static async void Init()
{
try
{
NVIDIA.Initialize();
PhysicalGPU[] gpus = PhysicalGPU.GetPhysicalGPUs();
if (gpus.Length == 0)
return;
gpu = gpus[0];
Logger.Log("Init NvApi");
}
catch (Exception e)
{
Logger.Log($"Failed to initialize NvApi: {e.Message}\nIgnore this if you don't have an Nvidia GPU.");
}
}
public static void RefreshVram()
{
if (Form.ActiveForm != Program.mainForm || gpu == null) // Don't refresh if not in focus or no GPU detected
return;
vramGb = (gpu.MemoryInformation.AvailableDedicatedVideoMemoryInkB / 1000f / 1024f);
vramFreeGb = (gpu.MemoryInformation.CurrentAvailableDedicatedVideoMemoryInkB / 1000f / 1024f);
Color col = Color.White;
if (vramFreeGb < 2f)
col = Color.Orange;
if (vramFreeGb < 1f)
col = Color.OrangeRed;
//Program.mainForm.SetVramLabel($"{gpu.FullName}: {vramGb.ToString("0.00")} GB VRAM - {vramFreeGb.ToString("0.00")} GB Free", col);
}
public static float GetVramGb ()
{
try
{
return (gpu.MemoryInformation.AvailableDedicatedVideoMemoryInkB / 1000f / 1024f);
}
catch (Exception e)
{
return 0f;
}
}
public static float GetFreeVramGb()
{
try
{
return (gpu.MemoryInformation.CurrentAvailableDedicatedVideoMemoryInkB / 1000f / 1024f);
}
catch (Exception e)
{
return 0f;
}
}
public static string GetGpuName()
{
try
{
NVIDIA.Initialize();
PhysicalGPU[] gpus = PhysicalGPU.GetPhysicalGPUs();
if (gpus.Length == 0)
return "";
return gpus[0].FullName;
}
catch
{
return "";
}
}
}
}

118
Code/OS/OSUtils.cs Normal file
View File

@@ -0,0 +1,118 @@
using System.Collections.Generic;
using System.Text;
using System.Security.Principal;
using System;
using System.Diagnostics;
using System.Management;
using Flowframes.IO;
using DiskDetector;
using DiskDetector.Models;
namespace Flowframes.OS
{
class OSUtils
{
public static bool IsUserAdministrator()
{
//bool value to hold our return value
bool isAdmin;
WindowsIdentity user = null;
try
{
//get the currently logged in user
user = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal(user);
isAdmin = principal.IsInRole(WindowsBuiltInRole.Administrator);
}
catch (UnauthorizedAccessException ex)
{
isAdmin = false;
}
catch (Exception ex)
{
isAdmin = false;
}
finally
{
if (user != null)
user.Dispose();
}
return isAdmin;
}
public static Process SetStartInfo(Process proc, bool hidden, string filename = "cmd.exe")
{
proc.StartInfo.UseShellExecute = !hidden;
proc.StartInfo.RedirectStandardOutput = hidden;
proc.StartInfo.RedirectStandardError = hidden;
proc.StartInfo.CreateNoWindow = hidden;
proc.StartInfo.FileName = filename;
return proc;
}
public static Process NewProcess(bool hidden, string filename = "cmd.exe")
{
Process proc = new Process();
return SetStartInfo(proc, hidden, filename);
}
public static void KillProcessTree(int pid)
{
ManagementObjectSearcher processSearcher = new ManagementObjectSearcher
("Select * From Win32_Process Where ParentProcessID=" + pid);
ManagementObjectCollection processCollection = processSearcher.Get();
try
{
Process proc = Process.GetProcessById(pid);
if (!proc.HasExited) proc.Kill();
}
catch (ArgumentException)
{
// Process already exited.
}
if (processCollection != null)
{
foreach (ManagementObject mo in processCollection)
{
KillProcessTree(Convert.ToInt32(mo["ProcessID"])); //kill child processes(also kills childrens of childrens etc.)
}
}
}
public static string GetHiddenCmdArg()
{
bool stayOpen = Config.GetInt("cmdDebugMode") == 2;
if (stayOpen)
return "/K";
else
return "/C";
}
public static bool ShowHiddenCmd()
{
return Config.GetInt("cmdDebugMode") > 0;
}
public static bool DriveIsSSD(string path)
{
var detectedDrives = Detector.DetectFixedDrives(QueryType.SeekPenalty);
if (detectedDrives.Count != 0)
{
char pathDriveLetter = (path[0].ToString().ToUpper())[0];
foreach (var detectedDrive in detectedDrives)
{
if (detectedDrive.DriveLetter == pathDriveLetter && detectedDrive.HardwareType.ToString().ToLower().Trim() == "ssd")
return true;
}
}
return false;
}
public static bool HasNonAsciiChars(string str)
{
return (Encoding.UTF8.GetByteCount(str) != str.Length);
}
}
}

84
Code/OS/Python.cs Normal file
View File

@@ -0,0 +1,84 @@
using Flowframes.IO;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
namespace Flowframes.OS
{
class Python
{
static bool hasCheckedSysPy = false;
static bool sysPyInstalled = false;
public static string GetPyCmd ()
{
if (PkgInstaller.IsInstalled(Packages.python))
{
Logger.Log("Using embedded Python runtime.");
string pyPkgDir = Path.Combine(Paths.GetPkgPath(), Path.GetFileNameWithoutExtension(Packages.python.fileName));
return Path.Combine(pyPkgDir, "python.exe").Wrap();
}
else
{
if (IsSysPyInstalled())
{
return "python";
}
else
{
MessageBox.Show("System python installation not found!\nPlease install Python or download the package from the package installer.");
Interpolate.Cancel("Neither the Flowframes Python Runtime nor System Python installation could be found!");
}
}
return "";
}
public static bool IsSysPyInstalled ()
{
if (hasCheckedSysPy)
return sysPyInstalled;
bool isInstalled = false;
Logger.Log("Checking if system Python is available...");
string sysPyVer = GetSysPyVersion();
if (!string.IsNullOrWhiteSpace(sysPyVer) && !sysPyVer.ToLower().Contains("not found") && sysPyVer.Length <= 35)
isInstalled = true;
hasCheckedSysPy = true;
sysPyInstalled = isInstalled;
return sysPyInstalled;
}
static string GetSysPyVersion()
{
string pythonOut = GetSysPythonOutput();
Logger.Log("[DepCheck] System Python Check Output: " + pythonOut.Trim(), true);
try
{
string ver = pythonOut.Split('(')[0].Trim();
Logger.Log("[DepCheck] Sys Python Ver: " + ver, true);
return ver;
}
catch
{
return "";
}
}
static string GetSysPythonOutput()
{
Process py = OSUtils.NewProcess(true);
py.StartInfo.Arguments = "/C python -V";
Logger.Log("[DepCheck] CMD: " + py.StartInfo.Arguments, true);
py.Start();
py.WaitForExit();
string output = py.StandardOutput.ReadToEnd();
string err = py.StandardError.ReadToEnd();
return output + "\n" + err;
}
}
}

91
Code/OS/Updater.cs Normal file
View File

@@ -0,0 +1,91 @@
using Flowframes.Forms;
using Flowframes.IO;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Flowframes.OS
{
class Updater
{
public static string latestVerUrl = "https://dl.nmkd.de/flowframes/exe/latest.txt";
public static int GetInstalledVer()
{
return Program.version;
}
public static int GetLatestVer ()
{
var client = new WebClient();
return client.DownloadString(latestVerUrl).GetInt();
}
public static async Task UpdateTo (int version, UpdaterForm form = null)
{
Logger.Log("Updating to v" + version, true);
string savePath = Path.Combine(IOUtils.GetExeDir(), $"FlowframesV{version}");
try
{
var client = new WebClient();
client.DownloadProgressChanged += async (sender, args) =>
{
if (form != null && (args.ProgressPercentage % 5 == 0))
{
Logger.Log("Downloading update... " + args.ProgressPercentage, true);
form.SetProgLabel(args.ProgressPercentage, $"Downloading latest version... {args.ProgressPercentage}%");
await Task.Delay(20);
}
};
client.DownloadFileCompleted += (sender, args) =>
{
form.SetProgLabel(100f, $"Downloading latest version... 100%");
};
await client.DownloadFileTaskAsync(new Uri($"https://dl.nmkd.de/flowframes/exe/{version}/Flowframes.exe"), savePath);
}
catch (Exception e)
{
MessageBox.Show("Error: Failed to download update.\n\n" + e.Message, "Error");
Logger.Log("Updater Error during download: " + e.Message, true);
return;
}
try
{
Logger.Log("Installing v" + version, true);
string runningExePath = IOUtils.GetExe();
string oldExePath = runningExePath + ".old";
IOUtils.TryDeleteIfExists(oldExePath);
File.Move(runningExePath, oldExePath);
File.Move(savePath, runningExePath);
}
catch (Exception e)
{
MessageBox.Show("Error: Failed to install update.\n\n" + e.Message, "Error");
Logger.Log("Updater Error during install: " + e.Message, true);
return;
}
form.SetProgLabel(101f, $"Update downloaded.");
await Task.Delay(20);
MessageBox.Show("Update was installed!\nFlowframes will now close. Restart it to use the new version.", "Message");
Application.Exit();
}
public static async Task AsyncUpdateCheck ()
{
var client = new WebClient();
var latestVer = await client.DownloadStringTaskAsync(latestVerUrl);
int latest = latestVer.GetInt();
int installed = GetInstalledVer();
if (installed != latest)
Logger.Log("An update for Flowframes is available! Download it using the Updater.");
else
Logger.Log("Flowframes is up to date.");
}
}
}

50
Code/Program.cs Normal file
View File

@@ -0,0 +1,50 @@
using Flowframes.Data;
using Flowframes.IO;
using Flowframes.OS;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Flowframes
{
static class Program
{
public const int version = 15;
public static Form1 mainForm;
public static bool busy = false;
public static string lastInputPath;
public static bool lastInputPathIsSsd;
public static Queue<BatchEntry> batchQueue = new Queue<BatchEntry>();
[STAThread]
static void Main()
{
Paths.Init();
Config.Init();
if (Config.GetBool("deleteLogsOnStartup"))
IOUtils.DeleteContentsOfDir(Paths.GetLogPath()); // Clear out older logs not from this session
string oldExePath = IOUtils.GetExe() + ".old";
IOUtils.TryDeleteIfExists(oldExePath);
PkgInstaller.Init();
Networks.Init();
NvApi.Init();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
mainForm = new Form1();
Application.Run(mainForm);
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Flowframes")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Flowframes")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("389e42dd-a163-49d7-9e0a-ae41090a07b3")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

233
Code/Properties/Resources.Designer.cs generated Normal file
View File

@@ -0,0 +1,233 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Flowframes.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Flowframes.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap baseline_create_white_18dp {
get {
object obj = ResourceManager.GetObject("baseline_create_white_18dp", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap baseline_create_white_18dp_semiTransparent {
get {
object obj = ResourceManager.GetObject("baseline_create_white_18dp-semiTransparent", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap baseline_fact_check_white_48dp {
get {
object obj = ResourceManager.GetObject("baseline_fact_check_white_48dp", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap baseline_image_white_48dp {
get {
object obj = ResourceManager.GetObject("baseline_image_white_48dp", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap baseline_image_white_48dp_4x {
get {
object obj = ResourceManager.GetObject("baseline_image_white_48dp-4x", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap baseline_image_white_48dp_4x_25pcAlpha {
get {
object obj = ResourceManager.GetObject("baseline_image_white_48dp-4x-25pcAlpha", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap baseline_queue_white_48dp {
get {
object obj = ResourceManager.GetObject("baseline_queue_white_48dp", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap baseline_settings_white_48dp {
get {
object obj = ResourceManager.GetObject("baseline_settings_white_48dp", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap baseline_system_update_alt_white_48dp {
get {
object obj = ResourceManager.GetObject("baseline_system_update_alt_white_48dp", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap discordIco {
get {
object obj = ResourceManager.GetObject("discordIco", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap discordIcoColored {
get {
object obj = ResourceManager.GetObject("discordIcoColored", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap patreon256px {
get {
object obj = ResourceManager.GetObject("patreon256px", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap patreon256pxColored {
get {
object obj = ResourceManager.GetObject("patreon256pxColored", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap paypal256px {
get {
object obj = ResourceManager.GetObject("paypal256px", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap questmark_72px_bordeer {
get {
object obj = ResourceManager.GetObject("questmark-72px-bordeer", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap separatorTest1 {
get {
object obj = ResourceManager.GetObject("separatorTest1", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] x64_7za {
get {
object obj = ResourceManager.GetObject("x64_7za", resourceCulture);
return ((byte[])(obj));
}
}
}
}

View File

@@ -0,0 +1,172 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="baseline_image_white_48dp-4x" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\baseline_image_white_48dp-4x.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="baseline_image_white_48dp" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\baseline_image_white_48dp.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="baseline_queue_white_48dp" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\baseline_queue_white_48dp.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="x64_7za" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\7za.exe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="baseline_fact_check_white_48dp" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\baseline_fact_check_white_48dp.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="paypal256px" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\paypal256px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="baseline_system_update_alt_white_48dp" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\baseline_system_update_alt_white_48dp.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="questmark-72px-bordeer" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\questmark-72px-bordeer.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="baseline_create_white_18dp" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\baseline_create_white_18dp.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="discordIco" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\discordIco.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="patreon256pxColored" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\patreon256pxColored.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="discordIcoColored" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\discordIcoColored.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="separatorTest1" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\separatorTest1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="patreon256px" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\patreon256px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="baseline_create_white_18dp-semiTransparent" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\baseline_create_white_18dp-semiTransparent.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="baseline_settings_white_48dp" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\baseline_settings_white_48dp.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="baseline_image_white_48dp-4x-25pcAlpha" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\baseline_image_white_48dp-4x-25pcAlpha.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

26
Code/Properties/Settings.Designer.cs generated Normal file
View File

@@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Flowframes.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.7.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

View File

@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

BIN
Code/Resources/7za.exe Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

69
Code/UI/FormatUtils.cs Normal file
View File

@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Flowframes.UI
{
class FormatUtils
{
public static string Bytes(long sizeBytes)
{
int sizeKb = (int)Math.Round(sizeBytes / 1024f);
int sizeMb = (int)Math.Round(sizeKb / 1024f);
if (sizeBytes <= 8192)
{
return sizeBytes + " B";
}
if (sizeKb <= 8192)
{
return sizeKb + " KB";
}
return sizeMb + " MB"; ;
}
public static string Time(long milliseconds)
{
double secs = (milliseconds / 1000f);
if (milliseconds <= 1000)
{
return milliseconds + "ms";
}
return secs.ToString("0.00") + "s";
}
public static string Time (TimeSpan span)
{
if(span.TotalHours >= 1f)
return span.ToString(@"hh\:mm\:ss");
if (span.TotalMinutes >= 1f)
return span.ToString(@"mm\:ss");
if (span.TotalSeconds >= 1f)
return span.ToString(@"ss") + "s";
return span.Milliseconds.ToString() + "ms";
}
public static string TimeSw(Stopwatch sw)
{
long elapsedMs = sw.ElapsedMilliseconds;
return Time(elapsedMs);
}
public static string Ratio(long numFrom, long numTo)
{
float ratio = ((float)numTo / (float)numFrom) * 100f;
return ratio.ToString("0.00") + "%";
}
public static string RatioInt(long numFrom, long numTo)
{
double ratio = Math.Round(((float)numTo / (float)numFrom) * 100f);
return ratio + "%";
}
}
}

36
Code/UI/UIUtils.cs Normal file
View File

@@ -0,0 +1,36 @@
using Flowframes.IO;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Flowframes.UI
{
class UIUtils
{
public static void InitCombox(ComboBox box, int index)
{
if (box.Items.Count >= 1)
{
box.SelectedIndex = index;
box.Text = box.Items[index].ToString();
}
}
public static bool AssignComboxIndexFromText (ComboBox box, string text) // Set index to corresponding text
{
int index = box.Items.IndexOf(text);
if (index == -1) // custom value, index not found
return false;
box.SelectedIndex = index;
return true;
}
}
}

112
Code/UI/UtilsTab.cs Normal file
View File

@@ -0,0 +1,112 @@
using Flowframes.IO;
using Flowframes.Magick;
using Flowframes.Main;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Flowframes.UI
{
class UtilsTab
{
public static async Task ExtractVideo(string videoPath, bool withAudio)
{
string outPath = Path.ChangeExtension(videoPath, null) + "-extracted";
bool rgb8 = Formats.preprocess.Contains(Path.GetExtension(videoPath).ToLower());
Program.mainForm.SetWorking(true);
await FFmpegCommands.VideoToFrames(videoPath, Path.Combine(outPath, "frames"), false, rgb8, false, false);
File.WriteAllText(Path.Combine(outPath, "fps.ini"), Interpolate.currentInFps.ToString());
if (withAudio)
await FFmpegCommands.ExtractAudio(videoPath, Path.Combine(outPath, "audio"));
Program.mainForm.SetWorking(false);
Logger.Log("Done.");
}
public static async Task LoopVideo (string inputFile, ComboBox loopTimes)
{
if (!InputIsValid(inputFile))
return;
int times = loopTimes.GetInt();
Logger.Log("Lopping video " + times + "x...", true);
await FFmpegCommands.LoopVideo(inputFile, times, false);
Logger.Log("Done", true);
}
public static async Task ChangeSpeed(string inputFile, ComboBox speed)
{
if (!InputIsValid(inputFile))
return;
float speedFloat = speed.GetFloat();
Logger.Log("Creating video with " + speed + "% speed...", true);
await FFmpegCommands.ChangeSpeed(inputFile, speedFloat, false);
Logger.Log("Done", true);
}
public static async Task Convert(string inputFile, ComboBox crfBox)
{
if (!InputIsValid(inputFile))
return;
int crf = crfBox.GetInt();
Logger.Log("Creating MP4 with CRF " + crf + "...", true);
if(Formats.noEncodeSupport.Contains(Path.GetExtension(inputFile)))
await FFmpegCommands.Encode(inputFile, "libx264", "aac", crf, 112, false); // Use AAC if there is no audio enc for this format
else
await FFmpegCommands.Encode(inputFile, "libx264", "copy", crf, 0, false); // Copy audio if compatible
Logger.Log("Done", true);
}
static bool InputIsValid (string inPath)
{
bool isFile = !IOUtils.IsPathDirectory(inPath);
if ((isFile && !IOUtils.IsFileValid(inPath)) || (!isFile && !IOUtils.IsDirValid(inPath)))
{
MessageBox.Show("Input path is not valid!");
return false;
}
return true;
}
public static async void Dedupe (string inPath, bool testRun)
{
bool isFile = !IOUtils.IsPathDirectory(inPath);
if ((isFile && !IOUtils.IsFileValid(inPath)) || (!isFile && !IOUtils.IsDirValid(inPath)))
{
MessageBox.Show("Input path is not valid!");
return;
}
string framesPath;
if (isFile)
{
Logger.Log("Input is a file, not directory");
if (!InterpolateUtils.IsVideoValid(inPath))
{
MessageBox.Show("Input file is not valid!", "Error");
return;
}
Program.mainForm.SetWorking(true);
await Task.Delay(10);
framesPath = Path.ChangeExtension(inPath, null) + "-frames";
await Interpolate.ExtractFrames(inPath, framesPath);
}
else
{
framesPath = inPath;
}
Program.mainForm.SetWorking(true);
Logger.Log("Running frame de-duplication", true);
await Task.Delay(10);
await FrameDedup.Run(framesPath, testRun);
IOUtils.TryDeleteIfExists(framesPath);
Program.mainForm.SetProgress(0);
Program.mainForm.SetWorking(false);
}
}
}

BIN
Code/flowframesIcoNew.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

30
Code/packages.config Normal file
View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="7z.NET" version="1.0.3" targetFramework="net472" />
<package id="CircularProgressBar" version="2.8.0.16" targetFramework="net472" />
<package id="Costura.Fody" version="4.1.0" targetFramework="net472" />
<package id="CyotekTabList" version="2.0.0" targetFramework="net472" />
<package id="diskdetector-net" version="0.3.2" targetFramework="net472" />
<package id="Fody" version="6.3.0" targetFramework="net472" developmentDependency="true" />
<package id="HTAlt.Standart" version="0.1.6" targetFramework="net472" />
<package id="HTAlt.WinForms" version="0.1.6" targetFramework="net472" />
<package id="Magick.NET.Core" version="4.1.0" targetFramework="net472" />
<package id="Magick.NET-Q16-AnyCPU" version="7.21.1" targetFramework="net472" />
<package id="Microsoft-WindowsAPICodePack-Core" version="1.1.4" targetFramework="net472" />
<package id="Microsoft-WindowsAPICodePack-Shell" version="1.1.4" targetFramework="net472" />
<package id="NvAPIWrapper.Net" version="0.8.0.98" targetFramework="net472" />
<package id="PagedControl" version="2.2.0" targetFramework="net472" />
<package id="System.Drawing.Common" version="5.0.0" targetFramework="net472" />
<package id="System.Management" version="5.0.0" targetFramework="net472" />
<package id="System.Security.Claims" version="4.3.0" targetFramework="net472" />
<package id="System.Security.Principal.Windows" version="4.3.0" targetFramework="net472" />
<package id="TabControl" version="2.1.2" targetFramework="net472" />
<package id="Win32Interop.Dwmapi" version="1.0.1" targetFramework="net472" />
<package id="Win32Interop.Gdi32" version="1.0.1" targetFramework="net472" />
<package id="Win32Interop.Kernel32" version="1.0.1" targetFramework="net472" />
<package id="Win32Interop.User32" version="1.0.1" targetFramework="net472" />
<package id="Win32Interop.Uxtheme" version="1.0.1" targetFramework="net472" />
<package id="WindowsAPICodePack-Core" version="1.1.1" targetFramework="net472" />
<package id="WindowsAPICodePack-Shell" version="1.1.1" targetFramework="net472" />
<package id="WinFormAnimation" version="1.6.0.4" targetFramework="net472" />
</packages>

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Media/discordIco.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
Media/discordIcoColored.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
Media/flowframesIcoNew.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Some files were not shown because too many files have changed in this diff Show More