Initial
22
Code/App.config
Normal 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>
|
||||
114
Code/AudioVideo/AvProcess.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
319
Code/AudioVideo/FFmpegCommands.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
13
Code/AudioVideo/FFmpegStrings.cs
Normal 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";
|
||||
}
|
||||
}
|
||||
17
Code/AudioVideo/GifskiCommands.cs
Normal 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
Code/FlowFramesFunkyLogo1.ico
Normal file
|
After Width: | Height: | Size: 196 KiB |
BIN
Code/FlowFramesFunkyLogo2.ico
Normal file
|
After Width: | Height: | Size: 196 KiB |
313
Code/Flowframes.csproj
Normal 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
@@ -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
@@ -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
@@ -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
366
Code/Form1.cs
Normal 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
225
Code/Forms/BatchForm.Designer.cs
generated
Normal 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
@@ -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
70
Code/Forms/BigPreviewForm.Designer.cs
generated
Normal 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;
|
||||
}
|
||||
}
|
||||
36
Code/Forms/BigPreviewForm.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
2445
Code/Forms/BigPreviewForm.resx
Normal file
176
Code/Forms/InstallerForm.Designer.cs
generated
Normal 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
@@ -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}";
|
||||
}
|
||||
}
|
||||
}
|
||||
2448
Code/Forms/InstallerForm.resx
Normal file
1314
Code/Forms/SettingsForm.Designer.cs
generated
Normal file
141
Code/Forms/SettingsForm.cs
Normal 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
192
Code/Forms/UpdaterForm.Designer.cs
generated
Normal 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
@@ -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
15
Code/IO/CfgStrings.cs
Normal 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
108
Code/Main/BatchProcessing.cs
Normal 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
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
231
Code/Main/InterpolateUtils.cs
Normal 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
36
Code/Properties/AssemblyInfo.cs
Normal 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
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
172
Code/Properties/Resources.resx
Normal 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
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
7
Code/Properties/Settings.settings
Normal 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
BIN
Code/Resources/baseline_create_white_18dp-semiTransparent.png
Normal file
|
After Width: | Height: | Size: 431 B |
BIN
Code/Resources/baseline_create_white_18dp.png
Normal file
|
After Width: | Height: | Size: 206 B |
BIN
Code/Resources/baseline_fact_check_white_48dp.png
Normal file
|
After Width: | Height: | Size: 485 B |
BIN
Code/Resources/baseline_image_white_48dp-4x-25pcAlpha.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
Code/Resources/baseline_image_white_48dp-4x.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
Code/Resources/baseline_image_white_48dp.png
Normal file
|
After Width: | Height: | Size: 597 B |
BIN
Code/Resources/baseline_queue_white_48dp.png
Normal file
|
After Width: | Height: | Size: 371 B |
BIN
Code/Resources/baseline_settings_white_48dp.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
Code/Resources/baseline_system_update_alt_white_48dp.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Code/Resources/discordIco.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
Code/Resources/discordIcoColored.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
Code/Resources/patreon256px.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
Code/Resources/patreon256pxColored.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
Code/Resources/paypal256px.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
Code/Resources/questmark-72px-bordeer.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
Code/Resources/separatorTest1.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
69
Code/UI/FormatUtils.cs
Normal 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
@@ -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
@@ -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
|
After Width: | Height: | Size: 136 KiB |
30
Code/packages.config
Normal 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>
|
||||
BIN
Media/FlowFramesFunkyLogo1.png
Normal file
|
After Width: | Height: | Size: 136 KiB |
BIN
Media/FlowFramesFunkyLogo2.ico
Normal file
|
After Width: | Height: | Size: 196 KiB |
BIN
Media/SixtyDainLogo1-xbrz6-ai.ico
Normal file
|
After Width: | Height: | Size: 149 KiB |
BIN
Media/SixtyDainLogo1-xbrz6-ai.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
Media/baseline_create_white_18dp-semiTransparent.png
Normal file
|
After Width: | Height: | Size: 431 B |
BIN
Media/baseline_create_white_18dp.png
Normal file
|
After Width: | Height: | Size: 206 B |
BIN
Media/baseline_fact_check_white_48dp.png
Normal file
|
After Width: | Height: | Size: 485 B |
BIN
Media/baseline_folder_open_white_48dp.png
Normal file
|
After Width: | Height: | Size: 356 B |
BIN
Media/baseline_image_white_48dp-4x-25pcAlpha.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
Media/baseline_image_white_48dp-4x.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
Media/baseline_image_white_48dp.png
Normal file
|
After Width: | Height: | Size: 597 B |
BIN
Media/baseline_queue_white_48dp.png
Normal file
|
After Width: | Height: | Size: 371 B |
BIN
Media/baseline_settings_white_48dp.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
Media/baseline_system_update_alt_white_48dp.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Media/discordIco.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
Media/discordIcoColored.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
Media/flowframesIcoNew.ico
Normal file
|
After Width: | Height: | Size: 136 KiB |