mirror of
https://github.com/n00mkrad/flowframes.git
synced 2025-12-16 16:37:48 +01:00
Completely revamped output settings (quality settings WIP)
This commit is contained in:
20
Code/Data/EncoderInfo.cs
Normal file
20
Code/Data/EncoderInfo.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Flowframes.Data
|
||||
{
|
||||
public class EncoderInfo
|
||||
{
|
||||
public string Name { get; set; } = "unknown";
|
||||
|
||||
public EncoderInfo() { }
|
||||
|
||||
public EncoderInfo(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Code/Data/EncoderInfoVideo.cs
Normal file
22
Code/Data/EncoderInfoVideo.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static Flowframes.Data.Enums.Encoding;
|
||||
|
||||
namespace Flowframes.Data
|
||||
{
|
||||
public class EncoderInfoVideo : EncoderInfo
|
||||
{
|
||||
public Codec Codec { get; set; } = (Codec)(-1);
|
||||
public bool Lossless { get; set; } = false;
|
||||
public bool HwAccelerated { get; set; } = false;
|
||||
public int Modulo { get; set; } = 2;
|
||||
public int MaxFramerate { get; set; } = 1000;
|
||||
public List<PixelFormat> PixelFormats { get; set; } = new List<PixelFormat>();
|
||||
public PixelFormat PixelFormatDefault { get; set; }
|
||||
public bool IsImageSequence { get; set; } = false;
|
||||
public string OverideExtension { get; set; } = "";
|
||||
}
|
||||
}
|
||||
20
Code/Data/Enums.cs
Normal file
20
Code/Data/Enums.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace Flowframes.Data
|
||||
{
|
||||
public class Enums
|
||||
{
|
||||
public class Output
|
||||
{
|
||||
public enum Format { Mp4, Mkv, Webm, Mov, Avi, Gif, Images, Realtime };
|
||||
public enum ImageFormat { Png, Jpeg, Webp };
|
||||
public enum Dithering { None, Bayer, FloydSteinberg };
|
||||
}
|
||||
|
||||
public class Encoding
|
||||
{
|
||||
public enum Codec { H264, H265, AV1, VP9, ProRes, Gif, Png, Jpeg, Webp, Ffv1, Huffyuv, Magicyuv, Rawvideo }
|
||||
public enum Encoder { X264, X265, SvtAv1, VpxVp9, Nvenc264, Nvenc265, NvencAv1, ProResKs, Gif, Png, Jpeg, Webp, Ffv1, Huffyuv, Magicyuv, Rawvideo }
|
||||
public enum PixelFormat { Yuv420P, Yuva420P, Yuv420P10Le, Yuv422P, Yuv422P10Le, Yuv444P, Yuv444P10Le, Yuva444P10Le, Rgb24, Rgba, Rgb8 };
|
||||
public enum ProResProfiles { Proxy, Lt, Standard, Hq, Quad4, Quad4Xq }
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Code/Data/ExportSettings.cs
Normal file
15
Code/Data/ExportSettings.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.Data
|
||||
{
|
||||
public class ExportSettings
|
||||
{
|
||||
public Enums.Output.Format Format { get; set; }
|
||||
public Enums.Encoding.Encoder Encoder { get; set; }
|
||||
public Enums.Encoding.PixelFormat PixelFormat { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ namespace Flowframes
|
||||
public Fraction outFps;
|
||||
public float outItsScale;
|
||||
public float interpFactor;
|
||||
public Interpolate.OutMode outMode;
|
||||
public ExportSettings outSettings;
|
||||
public ModelCollection.ModelInfo model;
|
||||
|
||||
public string tempFolder;
|
||||
@@ -46,7 +46,7 @@ namespace Flowframes
|
||||
|
||||
public InterpSettings() { }
|
||||
|
||||
public InterpSettings(string inPathArg, string outPathArg, AI aiArg, Fraction inFpsDetectedArg, Fraction inFpsArg, float interpFactorArg, float itsScale, Interpolate.OutMode outModeArg, ModelCollection.ModelInfo modelArg)
|
||||
public InterpSettings(string inPathArg, string outPathArg, AI aiArg, Fraction inFpsDetectedArg, Fraction inFpsArg, float interpFactorArg, float itsScale, ExportSettings outSettingsArg, ModelCollection.ModelInfo modelArg)
|
||||
{
|
||||
inPath = inPathArg;
|
||||
outPath = outPathArg;
|
||||
@@ -56,7 +56,7 @@ namespace Flowframes
|
||||
interpFactor = interpFactorArg;
|
||||
outFps = inFpsArg * (double)interpFactorArg;
|
||||
outItsScale = itsScale;
|
||||
outMode = outModeArg;
|
||||
outSettings = outSettingsArg;
|
||||
model = modelArg;
|
||||
|
||||
alpha = false;
|
||||
@@ -95,7 +95,7 @@ namespace Flowframes
|
||||
inFps = new Fraction();
|
||||
interpFactor = 0;
|
||||
outFps = new Fraction();
|
||||
outMode = Interpolate.OutMode.VidMp4;
|
||||
outSettings = new ExportSettings();
|
||||
model = null;
|
||||
alpha = false;
|
||||
stepByStep = false;
|
||||
@@ -112,6 +112,7 @@ namespace Flowframes
|
||||
entries.Add(keyValuePair[0], keyValuePair[1]);
|
||||
}
|
||||
|
||||
// TODO: Rework this ugly stuff, JSON?
|
||||
foreach (KeyValuePair<string, string> entry in entries)
|
||||
{
|
||||
switch (entry.Key)
|
||||
@@ -123,7 +124,7 @@ namespace Flowframes
|
||||
case "INFPS": inFps = new Fraction(entry.Value); break;
|
||||
case "OUTFPS": outFps = new Fraction(entry.Value); break;
|
||||
case "INTERPFACTOR": interpFactor = float.Parse(entry.Value); break;
|
||||
case "OUTMODE": outMode = (Interpolate.OutMode)Enum.Parse(typeof(Interpolate.OutMode), entry.Value); break;
|
||||
case "OUTMODE": outSettings.Format = (Enums.Output.Format)Enum.Parse(typeof(Enums.Output.Format), entry.Value); break;
|
||||
case "MODEL": model = AiModels.GetModelByName(ai, entry.Value); break;
|
||||
case "INPUTRES": _inputResolution = FormatUtils.ParseSize(entry.Value); break;
|
||||
case "ALPHA": alpha = bool.Parse(entry.Value); break;
|
||||
@@ -173,14 +174,13 @@ namespace Flowframes
|
||||
try
|
||||
{
|
||||
bool alphaModel = model.SupportsAlpha;
|
||||
bool png = outMode == Interpolate.OutMode.ImgPng;
|
||||
bool gif = outMode == Interpolate.OutMode.VidGif;
|
||||
bool proResAlpha = outMode == Interpolate.OutMode.VidProRes && Config.GetInt(Config.Key.proResProfile) > 3;
|
||||
bool outputSupportsAlpha = png || gif || proResAlpha;
|
||||
bool pngOutput = outSettings.Encoder == Enums.Encoding.Encoder.Png;
|
||||
bool gifOutput = outSettings.Encoder == Enums.Encoding.Encoder.Gif;
|
||||
bool proResAlpha = outSettings.Encoder == Enums.Encoding.Encoder.ProResKs && Config.GetInt(Config.Key.proResProfile) > 3; // TODO: CHECK IF WORKS WITH NEW ENCODING SETTINGS CODE
|
||||
bool outputSupportsAlpha = pngOutput || gifOutput || proResAlpha;
|
||||
string ext = inputIsFrames ? Path.GetExtension(IoUtils.GetFilesSorted(inPath).First()).ToLowerInvariant() : Path.GetExtension(inPath).ToLowerInvariant();
|
||||
alpha = (alphaModel && outputSupportsAlpha && (ext == ".gif" || ext == ".png" || ext == ".apng" || ext == ".mov"));
|
||||
Logger.Log($"RefreshAlpha: model.supportsAlpha = {alphaModel} - outputSupportsAlpha = {outputSupportsAlpha} - " +
|
||||
$"input ext: {ext} => alpha = {alpha}", true);
|
||||
Logger.Log($"RefreshAlpha: model.supportsAlpha = {alphaModel} - outputSupportsAlpha = {outputSupportsAlpha} - input ext: {ext} => alpha = {alpha}", true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -193,9 +193,9 @@ namespace Flowframes
|
||||
|
||||
public void RefreshExtensions(FrameType type = FrameType.Both)
|
||||
{
|
||||
bool pngOutput = outMode == Interpolate.OutMode.ImgPng;
|
||||
bool aviHqChroma = outMode == Interpolate.OutMode.VidAvi && Config.Get(Config.Key.aviColors) != "yuv420p";
|
||||
bool proresHqChroma = outMode == Interpolate.OutMode.VidProRes && Config.GetInt(Config.Key.proResProfile) > 3;
|
||||
bool pngOutput = outSettings.Encoder == Enums.Encoding.Encoder.Png;
|
||||
bool aviHqChroma = outSettings.Format == Enums.Output.Format.Avi && outSettings.PixelFormat != Enums.Encoding.PixelFormat.Yuv420P; // TODO: CHECK IF WORKS WITH NEW ENCODING SETTINGS CODE
|
||||
bool proresHqChroma = outSettings.Encoder == Enums.Encoding.Encoder.ProResKs && Config.GetInt(Config.Key.proResProfile) > 3; // TODO: CHECK IF WORKS WITH NEW ENCODING SETTINGS CODE
|
||||
|
||||
bool forceHqChroma = pngOutput || aviHqChroma || proresHqChroma;
|
||||
|
||||
@@ -230,7 +230,7 @@ namespace Flowframes
|
||||
s += $"INFPS|{inFps}\n";
|
||||
s += $"OUTFPS|{outFps}\n";
|
||||
s += $"INTERPFACTOR|{interpFactor}\n";
|
||||
s += $"OUTMODE|{outMode}\n";
|
||||
s += $"OUTMODE|{outSettings.Format}\n";
|
||||
s += $"MODEL|{model.Name}\n";
|
||||
s += $"INPUTRES|{InputResolution.Width}x{InputResolution.Height}\n";
|
||||
s += $"OUTPUTRES|{ScaledResolution.Width}x{ScaledResolution.Height}\n";
|
||||
|
||||
54
Code/Data/Strings.cs
Normal file
54
Code/Data/Strings.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Flowframes.Data
|
||||
{
|
||||
public class Strings
|
||||
{
|
||||
public static Dictionary<string, string> OutputFormat = new Dictionary<string, string>
|
||||
{
|
||||
{ Enums.Output.Format.Mp4.ToString(), "MP4" },
|
||||
{ Enums.Output.Format.Mkv.ToString(), "MKV" },
|
||||
{ Enums.Output.Format.Webm.ToString(), "WEBM" },
|
||||
{ Enums.Output.Format.Mov.ToString(), "MOV" },
|
||||
{ Enums.Output.Format.Avi.ToString(), "AVI" },
|
||||
{ Enums.Output.Format.Gif.ToString(), "GIF" },
|
||||
{ Enums.Output.Format.Images.ToString(), "Images" },
|
||||
{ Enums.Output.Format.Realtime.ToString(), "Real-time" },
|
||||
};
|
||||
|
||||
public static Dictionary<string, string> Encoder = new Dictionary<string, string>
|
||||
{
|
||||
{ Enums.Encoding.Encoder.X264.ToString(), "h264" },
|
||||
{ Enums.Encoding.Encoder.X265.ToString(), "h265" },
|
||||
{ Enums.Encoding.Encoder.SvtAv1.ToString(), "AV1" },
|
||||
{ Enums.Encoding.Encoder.VpxVp9.ToString(), "VP9" },
|
||||
{ Enums.Encoding.Encoder.ProResKs.ToString(), "ProRes" },
|
||||
{ Enums.Encoding.Encoder.Nvenc264.ToString(), "h264 (NVENC)" },
|
||||
{ Enums.Encoding.Encoder.Nvenc265.ToString(), "h265 (NVENC)" },
|
||||
{ Enums.Encoding.Encoder.NvencAv1.ToString(), "AV1 (NVENC)" },
|
||||
{ Enums.Encoding.Encoder.Gif.ToString(), "Animated GIF" },
|
||||
{ Enums.Encoding.Encoder.Png.ToString(), "PNG" },
|
||||
{ Enums.Encoding.Encoder.Jpeg.ToString(), "JPEG" },
|
||||
{ Enums.Encoding.Encoder.Webp.ToString(), "WEBP" },
|
||||
{ Enums.Encoding.Encoder.Ffv1.ToString(), "FFV1" },
|
||||
{ Enums.Encoding.Encoder.Huffyuv.ToString(), "HuffYUV" },
|
||||
{ Enums.Encoding.Encoder.Magicyuv.ToString(), "MagicYUV" },
|
||||
{ Enums.Encoding.Encoder.Rawvideo.ToString(), "Raw Video" },
|
||||
};
|
||||
|
||||
public static Dictionary<string, string> PixelFormat = new Dictionary<string, string>
|
||||
{
|
||||
{ Enums.Encoding.PixelFormat.Yuv420P.ToString(), "YUV 4:2:0 8-bit" },
|
||||
{ Enums.Encoding.PixelFormat.Yuva420P.ToString(), "YUVA 4:2:0 8-bit" },
|
||||
{ Enums.Encoding.PixelFormat.Yuv420P10Le.ToString(), "YUV 4:2:0 10-bit" },
|
||||
{ Enums.Encoding.PixelFormat.Yuv422P.ToString(), "YUV 4:2:2 8-bit" },
|
||||
{ Enums.Encoding.PixelFormat.Yuv422P10Le.ToString(), "YUV 4:2:2 10-bit" },
|
||||
{ Enums.Encoding.PixelFormat.Yuv444P.ToString(), "YUV 4:4:4 8-bit" },
|
||||
{ Enums.Encoding.PixelFormat.Yuv444P10Le.ToString(), "YUV 4:4:4 10-bit" },
|
||||
{ Enums.Encoding.PixelFormat.Yuva444P10Le.ToString(), "YUVA 4:4:4 10-bit" },
|
||||
{ Enums.Encoding.PixelFormat.Rgb24.ToString(), "RGB 8-bit" },
|
||||
{ Enums.Encoding.PixelFormat.Rgb8.ToString(), "RGB 256-color" },
|
||||
{ Enums.Encoding.PixelFormat.Rgba.ToString(), "RGBA 8-bit" },
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ using System.Windows.Forms;
|
||||
using Flowframes.Data;
|
||||
using System.Management.Automation;
|
||||
using System.Drawing;
|
||||
using Flowframes.MiscUtils;
|
||||
|
||||
namespace Flowframes
|
||||
{
|
||||
@@ -271,5 +272,99 @@ namespace Flowframes
|
||||
{
|
||||
return $"{(filePath.IsConcatFile() ? filePath.GetConcStr() : "")} -i {filePath.Wrap()}";
|
||||
}
|
||||
|
||||
public static string Get(this Dictionary<string, string> dict, string key, bool returnKeyInsteadOfEmptyString = false, bool ignoreCase = false)
|
||||
{
|
||||
if (key == null)
|
||||
key = "";
|
||||
|
||||
for (int i = 0; i < dict.Count; i++)
|
||||
{
|
||||
if (ignoreCase)
|
||||
{
|
||||
if (key.Lower() == dict.ElementAt(i).Key.Lower())
|
||||
return dict.ElementAt(i).Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (key == dict.ElementAt(i).Key)
|
||||
return dict.ElementAt(i).Value;
|
||||
}
|
||||
}
|
||||
|
||||
if (returnKeyInsteadOfEmptyString)
|
||||
return key;
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
public static void FillFromEnum<TEnum>(this ComboBox comboBox, Dictionary<string, string> stringMap = null, int defaultIndex = -1, List<TEnum> exclusionList = null) where TEnum : Enum
|
||||
{
|
||||
if (stringMap == null)
|
||||
stringMap = new Dictionary<string, string>();
|
||||
|
||||
if (exclusionList == null)
|
||||
exclusionList = new List<TEnum>();
|
||||
|
||||
comboBox.Items.Clear();
|
||||
var entriesToAdd = Enum.GetValues(typeof(TEnum)).Cast<TEnum>().Except(exclusionList);
|
||||
comboBox.Items.AddRange(entriesToAdd.Select(x => stringMap.Get(x.ToString(), true)).ToArray());
|
||||
|
||||
if (defaultIndex >= 0)
|
||||
comboBox.SelectedIndex = defaultIndex;
|
||||
}
|
||||
|
||||
public static void FillFromEnum<TEnum>(this ComboBox comboBox, IEnumerable<TEnum> entries, Dictionary<string, string> stringMap = null, int defaultIndex = -1) where TEnum : Enum
|
||||
{
|
||||
if (stringMap == null)
|
||||
stringMap = new Dictionary<string, string>();
|
||||
|
||||
comboBox.Items.Clear();
|
||||
comboBox.Items.AddRange(entries.Select(x => stringMap.Get(x.ToString(), true)).ToArray());
|
||||
|
||||
if (defaultIndex >= 0 && comboBox.Items.Count > 0)
|
||||
comboBox.SelectedIndex = defaultIndex;
|
||||
}
|
||||
|
||||
public static void SetIfTextMatches(this ComboBox comboBox, string str, bool ignoreCase = true, Dictionary<string, string> stringMap = null)
|
||||
{
|
||||
if (stringMap == null)
|
||||
stringMap = new Dictionary<string, string>();
|
||||
|
||||
str = stringMap.Get(str, true, true);
|
||||
|
||||
for (int i = 0; i < comboBox.Items.Count; i++)
|
||||
{
|
||||
if (ignoreCase)
|
||||
{
|
||||
if (comboBox.Items[i].ToString().Lower() == str.Lower())
|
||||
{
|
||||
comboBox.SelectedIndex = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (comboBox.Items[i].ToString() == str)
|
||||
{
|
||||
comboBox.SelectedIndex = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string Lower(this string s)
|
||||
{
|
||||
if (s == null)
|
||||
return s;
|
||||
|
||||
return s.ToLowerInvariant();
|
||||
}
|
||||
|
||||
public static EncoderInfoVideo GetInfo (this Enums.Encoding.Encoder enc)
|
||||
{
|
||||
return OutputUtils.GetEncoderInfoVideo(enc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,6 +334,10 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="Data\AI.cs" />
|
||||
<Compile Include="Data\AudioTrack.cs" />
|
||||
<Compile Include="Data\EncoderInfo.cs" />
|
||||
<Compile Include="Data\EncoderInfoVideo.cs" />
|
||||
<Compile Include="Data\Enums.cs" />
|
||||
<Compile Include="Data\ExportSettings.cs" />
|
||||
<Compile Include="Data\Filetypes.cs" />
|
||||
<Compile Include="Data\MediaFile.cs" />
|
||||
<Compile Include="Data\ModelCollection.cs" />
|
||||
@@ -344,6 +348,7 @@
|
||||
<Compile Include="Data\Streams\Stream.cs" />
|
||||
<Compile Include="Data\Streams\SubtitleStream.cs" />
|
||||
<Compile Include="Data\Streams\VideoStream.cs" />
|
||||
<Compile Include="Data\Strings.cs" />
|
||||
<Compile Include="Data\VideoColorData.cs" />
|
||||
<Compile Include="Data\VidExtraData.cs" />
|
||||
<Compile Include="Data\Fraction.cs" />
|
||||
@@ -439,6 +444,8 @@
|
||||
<Compile Include="MiscUtils\FrameRename.cs" />
|
||||
<Compile Include="MiscUtils\ModelDownloadFormUtils.cs" />
|
||||
<Compile Include="MiscUtils\NmkdStopwatch.cs" />
|
||||
<Compile Include="MiscUtils\OutputUtils.cs" />
|
||||
<Compile Include="MiscUtils\ParseUtils.cs" />
|
||||
<Compile Include="Os\AiProcess.cs" />
|
||||
<Compile Include="Extensions\ExtensionMethods.cs" />
|
||||
<Compile Include="Form1.cs">
|
||||
|
||||
100
Code/Form1.Designer.cs
generated
100
Code/Form1.Designer.cs
generated
@@ -90,6 +90,10 @@
|
||||
this.label15 = new System.Windows.Forms.Label();
|
||||
this.label11 = new System.Windows.Forms.Label();
|
||||
this.interpOptsTab = new System.Windows.Forms.TabPage();
|
||||
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.comboxOutputFormat = new System.Windows.Forms.ComboBox();
|
||||
this.comboxOutputCrf = new System.Windows.Forms.ComboBox();
|
||||
this.comboxOutputColors = new System.Windows.Forms.ComboBox();
|
||||
this.aiInfoBtn = new HTAlt.WinForms.HTButton();
|
||||
this.outSpeedCombox = new System.Windows.Forms.ComboBox();
|
||||
this.completionActionPanel = new System.Windows.Forms.Panel();
|
||||
@@ -137,6 +141,7 @@
|
||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.pauseBtn = new System.Windows.Forms.Button();
|
||||
this.cancelBtn = new System.Windows.Forms.Button();
|
||||
this.comboxOutputEncoder = new System.Windows.Forms.ComboBox();
|
||||
this.panel1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBox4)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBox3)).BeginInit();
|
||||
@@ -149,6 +154,7 @@
|
||||
this.panel8.SuspendLayout();
|
||||
this.panel6.SuspendLayout();
|
||||
this.interpOptsTab.SuspendLayout();
|
||||
this.flowLayoutPanel1.SuspendLayout();
|
||||
this.completionActionPanel.SuspendLayout();
|
||||
this.quickSettingsTab.SuspendLayout();
|
||||
this.mpDedupePanel.SuspendLayout();
|
||||
@@ -228,7 +234,7 @@
|
||||
"Animated GIF (Only supports up to 50 FPS)",
|
||||
"Image Sequence (PNG, JPG, WEBP)",
|
||||
"Real-time Interpolation (Video only)"});
|
||||
this.outModeCombox.Location = new System.Drawing.Point(281, 157);
|
||||
this.outModeCombox.Location = new System.Drawing.Point(283, 229);
|
||||
this.outModeCombox.Name = "outModeCombox";
|
||||
this.outModeCombox.Size = new System.Drawing.Size(400, 23);
|
||||
this.outModeCombox.TabIndex = 16;
|
||||
@@ -915,6 +921,7 @@
|
||||
//
|
||||
this.interpOptsTab.AllowDrop = true;
|
||||
this.interpOptsTab.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(48)))), ((int)(((byte)(48)))), ((int)(((byte)(48)))));
|
||||
this.interpOptsTab.Controls.Add(this.flowLayoutPanel1);
|
||||
this.interpOptsTab.Controls.Add(this.aiInfoBtn);
|
||||
this.interpOptsTab.Controls.Add(this.pictureBox5);
|
||||
this.interpOptsTab.Controls.Add(this.outSpeedCombox);
|
||||
@@ -954,6 +961,66 @@
|
||||
this.interpOptsTab.DragDrop += new System.Windows.Forms.DragEventHandler(this.Form1_DragDrop);
|
||||
this.interpOptsTab.DragEnter += new System.Windows.Forms.DragEventHandler(this.Form1_DragEnter);
|
||||
//
|
||||
// flowLayoutPanel1
|
||||
//
|
||||
this.flowLayoutPanel1.Controls.Add(this.comboxOutputFormat);
|
||||
this.flowLayoutPanel1.Controls.Add(this.comboxOutputEncoder);
|
||||
this.flowLayoutPanel1.Controls.Add(this.comboxOutputCrf);
|
||||
this.flowLayoutPanel1.Controls.Add(this.comboxOutputColors);
|
||||
this.flowLayoutPanel1.Location = new System.Drawing.Point(281, 157);
|
||||
this.flowLayoutPanel1.Name = "flowLayoutPanel1";
|
||||
this.flowLayoutPanel1.Size = new System.Drawing.Size(614, 23);
|
||||
this.flowLayoutPanel1.TabIndex = 46;
|
||||
//
|
||||
// comboxOutputFormat
|
||||
//
|
||||
this.comboxOutputFormat.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
|
||||
this.comboxOutputFormat.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.comboxOutputFormat.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.comboxOutputFormat.ForeColor = System.Drawing.Color.White;
|
||||
this.comboxOutputFormat.FormattingEnabled = true;
|
||||
this.comboxOutputFormat.Items.AddRange(new object[] {
|
||||
"MP4 Video (h264, h265, AV1)",
|
||||
"MKV Video (h264, h265, AV1) (Best Audio/Subtitles Support)",
|
||||
"WEBM Video (Google VP9)",
|
||||
"MOV Video (Apple ProRes)",
|
||||
"AVI Video (ffv1, huffyuv, magicyuv, rawvideo)",
|
||||
"Animated GIF (Only supports up to 50 FPS)",
|
||||
"Image Sequence (PNG, JPG, WEBP)",
|
||||
"Real-time Interpolation (Video only)"});
|
||||
this.comboxOutputFormat.Location = new System.Drawing.Point(0, 0);
|
||||
this.comboxOutputFormat.Margin = new System.Windows.Forms.Padding(0, 0, 6, 0);
|
||||
this.comboxOutputFormat.Name = "comboxOutputFormat";
|
||||
this.comboxOutputFormat.Size = new System.Drawing.Size(80, 23);
|
||||
this.comboxOutputFormat.TabIndex = 47;
|
||||
this.comboxOutputFormat.SelectedIndexChanged += new System.EventHandler(this.comboxOutputFormat_SelectedIndexChanged);
|
||||
//
|
||||
// comboxOutputCrf
|
||||
//
|
||||
this.comboxOutputCrf.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
|
||||
this.comboxOutputCrf.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.comboxOutputCrf.ForeColor = System.Drawing.Color.White;
|
||||
this.comboxOutputCrf.FormattingEnabled = true;
|
||||
this.comboxOutputCrf.Location = new System.Drawing.Point(182, 0);
|
||||
this.comboxOutputCrf.Margin = new System.Windows.Forms.Padding(0, 0, 6, 0);
|
||||
this.comboxOutputCrf.Name = "comboxOutputCrf";
|
||||
this.comboxOutputCrf.Size = new System.Drawing.Size(50, 23);
|
||||
this.comboxOutputCrf.TabIndex = 48;
|
||||
this.comboxOutputCrf.Text = "24";
|
||||
//
|
||||
// comboxOutputColors
|
||||
//
|
||||
this.comboxOutputColors.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
|
||||
this.comboxOutputColors.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.comboxOutputColors.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.comboxOutputColors.ForeColor = System.Drawing.Color.White;
|
||||
this.comboxOutputColors.FormattingEnabled = true;
|
||||
this.comboxOutputColors.Location = new System.Drawing.Point(238, 0);
|
||||
this.comboxOutputColors.Margin = new System.Windows.Forms.Padding(0, 0, 6, 0);
|
||||
this.comboxOutputColors.Name = "comboxOutputColors";
|
||||
this.comboxOutputColors.Size = new System.Drawing.Size(110, 23);
|
||||
this.comboxOutputColors.TabIndex = 49;
|
||||
//
|
||||
// aiInfoBtn
|
||||
//
|
||||
this.aiInfoBtn.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
|
||||
@@ -1033,7 +1100,7 @@
|
||||
this.encodingSettingsBtn.FlatAppearance.BorderSize = 0;
|
||||
this.encodingSettingsBtn.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.encodingSettingsBtn.ForeColor = System.Drawing.Color.White;
|
||||
this.encodingSettingsBtn.Location = new System.Drawing.Point(689, 157);
|
||||
this.encodingSettingsBtn.Location = new System.Drawing.Point(689, 192);
|
||||
this.encodingSettingsBtn.Name = "encodingSettingsBtn";
|
||||
this.encodingSettingsBtn.Size = new System.Drawing.Size(206, 23);
|
||||
this.encodingSettingsBtn.TabIndex = 39;
|
||||
@@ -1641,6 +1708,29 @@
|
||||
this.cancelBtn.UseVisualStyleBackColor = true;
|
||||
this.cancelBtn.Click += new System.EventHandler(this.cancelBtn_Click);
|
||||
//
|
||||
// comboxOutputEncoder
|
||||
//
|
||||
this.comboxOutputEncoder.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
|
||||
this.comboxOutputEncoder.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.comboxOutputEncoder.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.comboxOutputEncoder.ForeColor = System.Drawing.Color.White;
|
||||
this.comboxOutputEncoder.FormattingEnabled = true;
|
||||
this.comboxOutputEncoder.Items.AddRange(new object[] {
|
||||
"MP4 Video (h264, h265, AV1)",
|
||||
"MKV Video (h264, h265, AV1) (Best Audio/Subtitles Support)",
|
||||
"WEBM Video (Google VP9)",
|
||||
"MOV Video (Apple ProRes)",
|
||||
"AVI Video (ffv1, huffyuv, magicyuv, rawvideo)",
|
||||
"Animated GIF (Only supports up to 50 FPS)",
|
||||
"Image Sequence (PNG, JPG, WEBP)",
|
||||
"Real-time Interpolation (Video only)"});
|
||||
this.comboxOutputEncoder.Location = new System.Drawing.Point(86, 0);
|
||||
this.comboxOutputEncoder.Margin = new System.Windows.Forms.Padding(0, 0, 6, 0);
|
||||
this.comboxOutputEncoder.Name = "comboxOutputEncoder";
|
||||
this.comboxOutputEncoder.Size = new System.Drawing.Size(90, 23);
|
||||
this.comboxOutputEncoder.TabIndex = 50;
|
||||
this.comboxOutputEncoder.SelectedIndexChanged += new System.EventHandler(this.comboxOutputEncoder_SelectedIndexChanged);
|
||||
//
|
||||
// Form1
|
||||
//
|
||||
this.AllowDrop = true;
|
||||
@@ -1694,6 +1784,7 @@
|
||||
this.panel6.PerformLayout();
|
||||
this.interpOptsTab.ResumeLayout(false);
|
||||
this.interpOptsTab.PerformLayout();
|
||||
this.flowLayoutPanel1.ResumeLayout(false);
|
||||
this.completionActionPanel.ResumeLayout(false);
|
||||
this.completionActionPanel.PerformLayout();
|
||||
this.quickSettingsTab.ResumeLayout(false);
|
||||
@@ -1824,6 +1915,11 @@
|
||||
private System.Windows.Forms.ComboBox outSpeedCombox;
|
||||
private System.Windows.Forms.PictureBox pictureBox5;
|
||||
private HTAlt.WinForms.HTButton aiInfoBtn;
|
||||
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
|
||||
public System.Windows.Forms.ComboBox comboxOutputFormat;
|
||||
public System.Windows.Forms.ComboBox comboxOutputCrf;
|
||||
public System.Windows.Forms.ComboBox comboxOutputColors;
|
||||
public System.Windows.Forms.ComboBox comboxOutputEncoder;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
100
Code/Form1.cs
100
Code/Form1.cs
@@ -55,7 +55,8 @@ namespace Flowframes
|
||||
// Main Tab
|
||||
UiUtils.InitCombox(interpFactorCombox, 0);
|
||||
UiUtils.InitCombox(outSpeedCombox, 0);
|
||||
UiUtils.InitCombox(outModeCombox, 0);
|
||||
//UiUtils.InitCombox(outModeCombox, 0);
|
||||
InitOutputUi();
|
||||
UiUtils.InitCombox(aiModel, 2);
|
||||
// Video Utils
|
||||
UiUtils.InitCombox(trimCombox, 0);
|
||||
@@ -84,6 +85,39 @@ namespace Flowframes
|
||||
await Checks();
|
||||
}
|
||||
|
||||
private void InitOutputUi()
|
||||
{
|
||||
comboxOutputFormat.FillFromEnum<Enums.Output.Format>(Strings.OutputFormat, 0);
|
||||
UpdateOutputUi();
|
||||
}
|
||||
|
||||
private void UpdateOutputUi()
|
||||
{
|
||||
var outMode = ParseUtils.GetEnum<Enums.Output.Format>(comboxOutputFormat.Text, true, Strings.OutputFormat);
|
||||
comboxOutputEncoder.FillFromEnum(OutputUtils.GetAvailableEncoders(outMode), Strings.Encoder, 0);
|
||||
comboxOutputEncoder.Visible = comboxOutputEncoder.Items.Count > 1;
|
||||
|
||||
UpdateOutputEncodingUi();
|
||||
}
|
||||
|
||||
private void UpdateOutputEncodingUi()
|
||||
{
|
||||
var encoder = ParseUtils.GetEnum<Enums.Encoding.Encoder>(comboxOutputEncoder.Text, true, Strings.Encoder);
|
||||
bool noEncoder = (int)encoder == -1;
|
||||
|
||||
comboxOutputCrf.Visible = !noEncoder;
|
||||
comboxOutputColors.Visible = !noEncoder;
|
||||
|
||||
if (noEncoder)
|
||||
return;
|
||||
|
||||
EncoderInfoVideo info = OutputUtils.GetEncoderInfoVideo(encoder);
|
||||
comboxOutputCrf.Visible = !info.Lossless;
|
||||
var pixelFormats = info.PixelFormats;
|
||||
comboxOutputColors.Visible = pixelFormats.Count > 0;
|
||||
comboxOutputColors.FillFromEnum(pixelFormats, Strings.PixelFormat, 0);
|
||||
}
|
||||
|
||||
async Task Checks()
|
||||
{
|
||||
try
|
||||
@@ -164,8 +198,7 @@ namespace Flowframes
|
||||
public InterpSettings GetCurrentSettings()
|
||||
{
|
||||
SetTab("interpolate");
|
||||
return new InterpSettings(inputTbox.Text.Trim(), outputTbox.Text.Trim(), GetAi(), currInFpsDetected, currInFps,
|
||||
interpFactorCombox.GetFloat(), outSpeedCombox.GetInt().Clamp(1, 64), GetOutMode(), GetModel(GetAi()));
|
||||
return new InterpSettings(inputTbox.Text.Trim(), outputTbox.Text.Trim(), GetAi(), currInFpsDetected, currInFps, interpFactorCombox.GetFloat(), outSpeedCombox.GetInt().Clamp(1, 64), GetExportSettings, GetModel(GetAi()));
|
||||
}
|
||||
|
||||
public InterpSettings UpdateCurrentSettings(InterpSettings settings)
|
||||
@@ -185,7 +218,7 @@ namespace Flowframes
|
||||
settings.inFps = currInFps;
|
||||
settings.interpFactor = interpFactorCombox.GetFloat();
|
||||
settings.outFps = settings.inFps * settings.interpFactor;
|
||||
settings.outMode = GetOutMode();
|
||||
settings.outSettings = GetExportSettings;
|
||||
settings.model = GetModel(GetAi());
|
||||
|
||||
return settings;
|
||||
@@ -197,7 +230,7 @@ namespace Flowframes
|
||||
MainUiFunctions.SetOutPath(outputTbox, entry.outPath);
|
||||
interpFactorCombox.Text = entry.interpFactor.ToString();
|
||||
aiCombox.SelectedIndex = Implementations.NetworksAvailable.IndexOf(Implementations.NetworksAvailable.Where(x => x.NameInternal == entry.ai.NameInternal).FirstOrDefault());
|
||||
SetOutMode(entry.outMode);
|
||||
SetFormat(entry.outSettings.Format);
|
||||
}
|
||||
|
||||
public void SetStatus(string str)
|
||||
@@ -287,7 +320,7 @@ namespace Flowframes
|
||||
ConfigParser.LoadComboxIndex(outModeCombox);
|
||||
}
|
||||
|
||||
private string GetAiComboboxName (AI ai)
|
||||
private string GetAiComboboxName(AI ai)
|
||||
{
|
||||
return ai.FriendlyName + " - " + ai.Description;
|
||||
}
|
||||
@@ -334,7 +367,7 @@ namespace Flowframes
|
||||
|
||||
AiProcessSuspend.Reset();
|
||||
|
||||
if(Interpolate.currentSettings.outMode == Interpolate.OutMode.Realtime)
|
||||
if (Interpolate.currentSettings.outSettings.Format == Enums.Output.Format.Realtime)
|
||||
{
|
||||
await Interpolate.Realtime();
|
||||
SetProgress(0);
|
||||
@@ -345,11 +378,6 @@ namespace Flowframes
|
||||
}
|
||||
}
|
||||
|
||||
private async void RealtimeInterp(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ModelCollection.ModelInfo GetModel(AI currentAi)
|
||||
{
|
||||
try
|
||||
@@ -362,36 +390,14 @@ namespace Flowframes
|
||||
}
|
||||
}
|
||||
|
||||
Interpolate.OutMode GetOutMode()
|
||||
Enums.Output.Format GetOutputFormat { get { return ParseUtils.GetEnum<Enums.Output.Format>(comboxOutputFormat.Text, true, Strings.OutputFormat); } }
|
||||
Enums.Encoding.Encoder GetEncoder { get { return ParseUtils.GetEnum<Enums.Encoding.Encoder>(comboxOutputEncoder.Text, true, Strings.Encoder); } }
|
||||
Enums.Encoding.PixelFormat GetPixelFormat { get { return ParseUtils.GetEnum<Enums.Encoding.PixelFormat>(comboxOutputColors.Text, true, Strings.PixelFormat); } }
|
||||
ExportSettings GetExportSettings { get { return new ExportSettings() { Encoder = GetEncoder, Format = GetOutputFormat, PixelFormat = GetPixelFormat }; } }
|
||||
|
||||
public void SetFormat(Enums.Output.Format format)
|
||||
{
|
||||
Interpolate.OutMode outMode = Interpolate.OutMode.VidMp4;
|
||||
if (outModeCombox.Text.ToLowerInvariant().Contains("mkv")) outMode = Interpolate.OutMode.VidMkv;
|
||||
if (outModeCombox.Text.ToLowerInvariant().Contains("webm")) outMode = Interpolate.OutMode.VidWebm;
|
||||
if (outModeCombox.Text.ToLowerInvariant().Contains("prores")) outMode = Interpolate.OutMode.VidProRes;
|
||||
if (outModeCombox.Text.ToLowerInvariant().Contains("avi")) outMode = Interpolate.OutMode.VidAvi;
|
||||
if (outModeCombox.Text.ToLowerInvariant().Contains("gif")) outMode = Interpolate.OutMode.VidGif;
|
||||
if (outModeCombox.Text.ToLowerInvariant().Contains("image")) outMode = Interpolate.OutMode.ImgPng;
|
||||
if (outModeCombox.Text.ToLowerInvariant().Contains("real")) outMode = Interpolate.OutMode.Realtime;
|
||||
return outMode;
|
||||
}
|
||||
|
||||
public void SetOutMode(Interpolate.OutMode mode)
|
||||
{
|
||||
int targetIndex = 0;
|
||||
|
||||
for (int i = 0; i < outModeCombox.Items.Count; i++)
|
||||
{
|
||||
string currentItem = outModeCombox.Items[i].ToString().ToLowerInvariant();
|
||||
if (mode == Interpolate.OutMode.VidMkv && currentItem.Contains("mkv")) targetIndex = i;
|
||||
if (mode == Interpolate.OutMode.VidWebm && currentItem.Contains("webm")) targetIndex = i;
|
||||
if (mode == Interpolate.OutMode.VidProRes && currentItem.Contains("prores")) targetIndex = i;
|
||||
if (mode == Interpolate.OutMode.VidAvi && currentItem.Contains("avi")) targetIndex = i;
|
||||
if (mode == Interpolate.OutMode.VidGif && currentItem.Contains("gif")) targetIndex = i;
|
||||
if (mode == Interpolate.OutMode.ImgPng && currentItem.Contains("image")) targetIndex = i;
|
||||
if (mode == Interpolate.OutMode.Realtime && currentItem.Contains("real")) targetIndex = i;
|
||||
}
|
||||
|
||||
outModeCombox.SelectedIndex = targetIndex;
|
||||
outModeCombox.Text = Strings.OutputFormat.Get(format.ToString());
|
||||
}
|
||||
|
||||
public AI GetAi()
|
||||
@@ -768,8 +774,18 @@ namespace Flowframes
|
||||
{
|
||||
var ai = GetAi();
|
||||
|
||||
if(ai != null)
|
||||
if (ai != null)
|
||||
UiUtils.ShowMessageBox(ai.GetVerboseInfo(), UiUtils.MessageType.Message);
|
||||
}
|
||||
|
||||
private void comboxOutputFormat_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
UpdateOutputUi();
|
||||
}
|
||||
|
||||
private void comboxOutputEncoder_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
UpdateOutputEncodingUi();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,9 +32,8 @@ namespace Flowframes.Forms
|
||||
for (int i = 0; i < Program.batchQueue.Count; i++)
|
||||
{
|
||||
InterpSettings entry = Program.batchQueue.ElementAt(i);
|
||||
string niceOutMode = entry.outMode.ToString().ToUpper().Remove("VID").Remove("IMG");
|
||||
string str = $"#{i+1}: {Path.GetFileName(entry.inPath).Trunc(40)} - {entry.inFps.GetFloat()} FPS => " +
|
||||
$"{entry.interpFactor}x {entry.ai.NameShort} ({entry.model.Name}) => {niceOutMode}";
|
||||
string outFormat = Strings.OutputFormat.Get(entry.outSettings.Format.ToString());
|
||||
string str = $"#{i+1}: {Path.GetFileName(entry.inPath).Trunc(40)} - {entry.inFps.GetFloat()} FPS => {entry.interpFactor}x {entry.ai.NameShort} ({entry.model.Name}) => {outFormat}";
|
||||
taskList.Items.Add(str);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,18 +253,19 @@ namespace Flowframes.Forms
|
||||
|
||||
private void mp4Enc_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
string text = mp4Enc.Text.ToUpper().Remove(" ");
|
||||
|
||||
if (text.Contains(FfmpegUtils.Codec.H264.ToString().ToUpper()))
|
||||
mp4CrfConfigKey = "h264Crf";
|
||||
|
||||
if (text.Contains(FfmpegUtils.Codec.H265.ToString().ToUpper()))
|
||||
mp4CrfConfigKey = "h265Crf";
|
||||
|
||||
if (text.Contains(FfmpegUtils.Codec.Av1.ToString().ToUpper()))
|
||||
mp4CrfConfigKey = "av1Crf";
|
||||
|
||||
mp4Crf.Value = Config.GetInt(mp4CrfConfigKey);
|
||||
// string text = mp4Enc.Text.ToUpper().Remove(" ");
|
||||
//
|
||||
// if (text.Contains(FfmpegUtils.Codec.H264.ToString().ToUpper()))
|
||||
// mp4CrfConfigKey = "h264Crf";
|
||||
//
|
||||
// if (text.Contains(FfmpegUtils.Codec.H265.ToString().ToUpper()))
|
||||
// mp4CrfConfigKey = "h265Crf";
|
||||
//
|
||||
// if (text.Contains(FfmpegUtils.Codec.Av1.ToString().ToUpper()))
|
||||
// mp4CrfConfigKey = "av1Crf";
|
||||
//
|
||||
// mp4Crf.Value = Config.GetInt(mp4CrfConfigKey);
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void modelDownloaderBtn_Click(object sender, EventArgs e)
|
||||
|
||||
@@ -565,9 +565,6 @@ namespace Flowframes.IO
|
||||
Fraction maxFps = max.Contains("/") ? new Fraction(max) : new Fraction(max.GetFloat());
|
||||
float fps = fpsLimit ? maxFps.GetFloat() : curr.outFps.GetFloat();
|
||||
|
||||
if (curr.outMode == Interpolate.OutMode.VidGif && fps > 50f)
|
||||
fps = 50f;
|
||||
|
||||
Size outRes = await InterpolateUtils.GetOutputResolution(curr.inPath, true);
|
||||
string pattern = Config.Get(Config.Key.exportNamePattern);
|
||||
string inName = Interpolate.currentSettings.inputIsFrames ? Path.GetFileName(curr.inPath) : Path.GetFileNameWithoutExtension(curr.inPath);
|
||||
@@ -580,7 +577,7 @@ namespace Flowframes.IO
|
||||
filename = filename.Replace("[FACTOR]", curr.interpFactor.ToStringDot());
|
||||
filename = filename.Replace("[AI]", curr.ai.NameShort.ToUpper());
|
||||
filename = filename.Replace("[MODEL]", curr.model.Name.Remove(" "));
|
||||
filename = filename.Replace("[FPS]", fps.ToStringDot());
|
||||
filename = filename.Replace("[FPS]", fps.ToStringDot("0.###"));
|
||||
filename = filename.Replace("[ROUNDFPS]", fps.RoundToInt().ToString());
|
||||
filename = filename.Replace("[RES]", $"{outRes.Width}x{outRes.Height}");
|
||||
filename = filename.Replace("[H]", $"{outRes.Height}p");
|
||||
@@ -589,7 +586,7 @@ namespace Flowframes.IO
|
||||
filename += Paths.fpsLimitSuffix;
|
||||
|
||||
if (withExt)
|
||||
filename += FfmpegUtils.GetExt(curr.outMode);
|
||||
filename += FfmpegUtils.GetExt(curr.outSettings);
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace Flowframes.Main
|
||||
{
|
||||
UpdateChunkAndBufferSizes();
|
||||
|
||||
bool imgSeq = Interpolate.currentSettings.outMode.ToString().ToLowerInvariant().StartsWith("img");
|
||||
bool imgSeq = Interpolate.currentSettings.outSettings.Encoder.GetInfo().IsImageSequence;
|
||||
interpFramesFolder = interpFramesPath;
|
||||
videoChunksFolder = Path.Combine(interpFramesPath.GetParentDir(), Paths.chunksDir);
|
||||
|
||||
@@ -130,12 +130,12 @@ namespace Flowframes.Main
|
||||
}
|
||||
|
||||
busy = true;
|
||||
string outpath = Path.Combine(videoChunksFolder, "chunks", $"{chunkNo.ToString().PadLeft(4, '0')}{FfmpegUtils.GetExt(Interpolate.currentSettings.outMode)}");
|
||||
string outpath = Path.Combine(videoChunksFolder, "chunks", $"{chunkNo.ToString().PadLeft(4, '0')}{FfmpegUtils.GetExt(Interpolate.currentSettings.outSettings)}");
|
||||
string firstFile = Path.GetFileName(interpFramesLines[frameLinesToEncode.First()].Trim());
|
||||
string lastFile = Path.GetFileName(interpFramesLines[frameLinesToEncode.Last()].Trim());
|
||||
Logger.Log($"[AE] Encoding Chunk #{chunkNo} to using line {frameLinesToEncode.First()} ({firstFile}) through {frameLinesToEncode.Last()} ({lastFile}) - {unencodedFrameLines.Count} unencoded frames left in total", true, false, "ffmpeg");
|
||||
|
||||
await Export.EncodeChunk(outpath, Interpolate.currentSettings.interpFolder, chunkNo, Interpolate.currentSettings.outMode, frameLinesToEncode.First(), frameLinesToEncode.Count);
|
||||
await Export.EncodeChunk(outpath, Interpolate.currentSettings.interpFolder, chunkNo, Interpolate.currentSettings.outSettings, frameLinesToEncode.First(), frameLinesToEncode.Count);
|
||||
|
||||
if (Interpolate.canceled) return;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Flowframes.Main
|
||||
{
|
||||
|
||||
|
||||
public static async Task ExportFrames(string path, string outFolder, I.OutMode mode, bool stepByStep)
|
||||
public static async Task ExportFrames(string path, string outFolder, ExportSettings exportSettings, bool stepByStep)
|
||||
{
|
||||
if(Config.GetInt(Config.Key.sceneChangeFillMode) == 1)
|
||||
{
|
||||
@@ -30,7 +30,7 @@ namespace Flowframes.Main
|
||||
await Blend.BlendSceneChanges(frameFile);
|
||||
}
|
||||
|
||||
if (!mode.ToString().ToLowerInvariant().Contains("vid")) // Copy interp frames out of temp folder and skip video export for image seq export
|
||||
if (exportSettings.Encoder.GetInfo().IsImageSequence) // Copy interp frames out of temp folder and skip video export for image seq export
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -61,10 +61,10 @@ namespace Flowframes.Main
|
||||
bool dontEncodeFullFpsVid = fpsLimit && Config.GetInt(Config.Key.maxFpsMode) == 0;
|
||||
|
||||
if (!dontEncodeFullFpsVid)
|
||||
await Encode(mode, path, Path.Combine(outFolder, await IoUtils.GetCurrentExportFilename(false, true)), I.currentSettings.outFps, new Fraction());
|
||||
await Encode(exportSettings, path, Path.Combine(outFolder, await IoUtils.GetCurrentExportFilename(false, true)), I.currentSettings.outFps, new Fraction());
|
||||
|
||||
if (fpsLimit)
|
||||
await Encode(mode, path, Path.Combine(outFolder, await IoUtils.GetCurrentExportFilename(true, true)), I.currentSettings.outFps, maxFps);
|
||||
await Encode(exportSettings, path, Path.Combine(outFolder, await IoUtils.GetCurrentExportFilename(true, true)), I.currentSettings.outFps, maxFps);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -76,7 +76,7 @@ namespace Flowframes.Main
|
||||
public static async Task<string> GetPipedFfmpegCmd(bool ffplay = false)
|
||||
{
|
||||
InterpSettings s = I.currentSettings;
|
||||
string encArgs = FfmpegUtils.GetEncArgs(FfmpegUtils.GetCodec(s.outMode), (s.ScaledResolution.IsEmpty ? s.InputResolution : s.ScaledResolution), s.outFps.GetFloat(), true).FirstOrDefault();
|
||||
string encArgs = FfmpegUtils.GetEncArgs(s.outSettings.Encoder, s.outSettings.PixelFormat, (s.ScaledResolution.IsEmpty ? s.InputResolution : s.ScaledResolution), s.outFps.GetFloat(), true).FirstOrDefault();
|
||||
|
||||
string max = Config.Get(Config.Key.maxFps);
|
||||
Fraction maxFps = max.Contains("/") ? new Fraction(max) : new Fraction(max.GetFloat());
|
||||
@@ -84,7 +84,7 @@ namespace Flowframes.Main
|
||||
|
||||
VidExtraData extraData = await FfmpegCommands.GetVidExtraInfo(s.inPath);
|
||||
string extraArgsIn = FfmpegEncode.GetFfmpegExportArgsIn(s.outFps, s.outItsScale);
|
||||
string extraArgsOut = FfmpegEncode.GetFfmpegExportArgsOut(fpsLimit ? maxFps : new Fraction(), extraData, s.outMode);
|
||||
string extraArgsOut = FfmpegEncode.GetFfmpegExportArgsOut(fpsLimit ? maxFps : new Fraction(), extraData, s.outSettings);
|
||||
|
||||
if (ffplay)
|
||||
{
|
||||
@@ -196,7 +196,7 @@ namespace Flowframes.Main
|
||||
}
|
||||
}
|
||||
|
||||
static async Task Encode(I.OutMode mode, string framesPath, string outPath, Fraction fps, Fraction resampleFps)
|
||||
static async Task Encode(ExportSettings settings, string framesPath, string outPath, Fraction fps, Fraction resampleFps)
|
||||
{
|
||||
string framesFile = Path.Combine(framesPath.GetParentDir(), Paths.GetFrameOrderFilename(I.currentSettings.interpFactor));
|
||||
|
||||
@@ -207,14 +207,14 @@ namespace Flowframes.Main
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode == I.OutMode.VidGif)
|
||||
if (settings.Format == Enums.Output.Format.Gif)
|
||||
{
|
||||
await FfmpegEncode.FramesToGifConcat(framesFile, outPath, fps, true, Config.GetInt(Config.Key.gifColors), resampleFps, I.currentSettings.outItsScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
VidExtraData extraData = await FfmpegCommands.GetVidExtraInfo(I.currentSettings.inPath);
|
||||
await FfmpegEncode.FramesToVideo(framesFile, outPath, mode, fps, resampleFps, I.currentSettings.outItsScale, extraData);
|
||||
await FfmpegEncode.FramesToVideo(framesFile, outPath, settings, fps, resampleFps, I.currentSettings.outItsScale, extraData);
|
||||
await MuxOutputVideo(I.currentSettings.inPath, outPath);
|
||||
await Loop(outPath, await GetLoopTimes());
|
||||
}
|
||||
@@ -228,7 +228,7 @@ namespace Flowframes.Main
|
||||
|
||||
public static async Task ChunksToVideo(string tempFolder, string chunksFolder, string baseOutPath, bool isBackup = false)
|
||||
{
|
||||
if (IoUtils.GetAmountOfFiles(chunksFolder, true, "*" + FfmpegUtils.GetExt(I.currentSettings.outMode)) < 1)
|
||||
if (IoUtils.GetAmountOfFiles(chunksFolder, true, "*" + FfmpegUtils.GetExt(I.currentSettings.outSettings)) < 1)
|
||||
{
|
||||
I.Cancel("No video chunks found - An error must have occured during chunk encoding!", AiProcess.hasShownError);
|
||||
return;
|
||||
@@ -289,7 +289,7 @@ namespace Flowframes.Main
|
||||
await Loop(outPath, await GetLoopTimes());
|
||||
}
|
||||
|
||||
public static async Task EncodeChunk(string outPath, string interpDir, int chunkNo, I.OutMode mode, int firstFrameNum, int framesAmount)
|
||||
public static async Task EncodeChunk(string outPath, string interpDir, int chunkNo, ExportSettings settings, int firstFrameNum, int framesAmount)
|
||||
{
|
||||
string framesFileFull = Path.Combine(I.currentSettings.tempFolder, Paths.GetFrameOrderFilename(I.currentSettings.interpFactor));
|
||||
string concatFile = Path.Combine(I.currentSettings.tempFolder, Paths.GetFrameOrderFilenameChunk(firstFrameNum, firstFrameNum + framesAmount));
|
||||
@@ -307,7 +307,7 @@ namespace Flowframes.Main
|
||||
|
||||
bool dontEncodeFullFpsVid = fpsLimit && Config.GetInt(Config.Key.maxFpsMode) == 0;
|
||||
|
||||
if (mode.ToString().ToLowerInvariant().StartsWith("img")) // Image Sequence output mode, not video
|
||||
if (settings.Encoder.GetInfo().IsImageSequence) // Image Sequence output mode, not video
|
||||
{
|
||||
string desiredFormat = Config.Get(Config.Key.imgSeqFormat);
|
||||
string availableFormat = Path.GetExtension(IoUtils.GetFilesSorted(interpDir)[0]).Remove(".").ToUpper();
|
||||
@@ -336,14 +336,14 @@ namespace Flowframes.Main
|
||||
else
|
||||
{
|
||||
if (!dontEncodeFullFpsVid)
|
||||
await FfmpegEncode.FramesToVideo(concatFile, outPath, mode, I.currentSettings.outFps, new Fraction(), I.currentSettings.outItsScale, extraData, AvProcess.LogMode.Hidden, true); // Encode
|
||||
await FfmpegEncode.FramesToVideo(concatFile, outPath, settings, I.currentSettings.outFps, new Fraction(), I.currentSettings.outItsScale, extraData, AvProcess.LogMode.Hidden, true); // Encode
|
||||
|
||||
if (fpsLimit)
|
||||
{
|
||||
string filename = Path.GetFileName(outPath);
|
||||
string newParentDir = outPath.GetParentDir() + Paths.fpsLimitSuffix;
|
||||
outPath = Path.Combine(newParentDir, filename);
|
||||
await FfmpegEncode.FramesToVideo(concatFile, outPath, mode, I.currentSettings.outFps, maxFps, I.currentSettings.outItsScale, extraData, AvProcess.LogMode.Hidden, true); // Encode with limited fps
|
||||
await FfmpegEncode.FramesToVideo(concatFile, outPath, settings, I.currentSettings.outFps, maxFps, I.currentSettings.outItsScale, extraData, AvProcess.LogMode.Hidden, true); // Encode with limited fps
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@ namespace Flowframes
|
||||
{
|
||||
public class Interpolate
|
||||
{
|
||||
public enum OutMode { VidMp4, VidMkv, VidWebm, VidProRes, VidAvi, VidGif, ImgPng, Realtime }
|
||||
|
||||
public static bool currentlyUsingAutoEnc;
|
||||
public static InterpSettings currentSettings;
|
||||
public static MediaFile currentMediaFile;
|
||||
@@ -40,7 +38,7 @@ namespace Flowframes
|
||||
if (!Utils.CheckPathValid(currentSettings.inPath)) return; // Check if input path/file is valid
|
||||
if (!Utils.CheckAiAvailable(currentSettings.ai, currentSettings.model)) return; // Check if selected AI pkg is installed
|
||||
if (!AutoEncodeResume.resumeNextRun && !Utils.CheckDeleteOldTempFolder()) return; // Try to delete temp folder if an old one exists
|
||||
if (!(await Utils.CheckEncoderValid(currentSettings.outFps.GetFloat()))) return; // Check encoder compat
|
||||
if (!(await Utils.CheckEncoderValid())) return; // Check encoder compat
|
||||
Utils.ShowWarnings(currentSettings.interpFactor, currentSettings.ai);
|
||||
currentSettings.stepByStep = false;
|
||||
Program.mainForm.SetStatus("Starting...");
|
||||
@@ -65,7 +63,7 @@ namespace Flowframes
|
||||
if (currentSettings.ai.Piped)
|
||||
await Export.MuxPipedVideo(currentSettings.inPath, currentSettings.FullOutPath);
|
||||
else
|
||||
await Export.ExportFrames(currentSettings.interpFolder, currentSettings.outPath, currentSettings.outMode, false);
|
||||
await Export.ExportFrames(currentSettings.interpFolder, currentSettings.outPath, currentSettings.outSettings, false);
|
||||
}
|
||||
|
||||
if (!AutoEncodeResume.resumeNextRun && Config.GetBool(Config.Key.keepTempFolder) && IoUtils.GetAmountOfFiles(currentSettings.framesFolder, false) > 0)
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace Flowframes.Main
|
||||
return;
|
||||
}
|
||||
|
||||
if (Config.GetBool(Config.Key.sbsAllowAutoEnc) && !(await InterpolateUtils.CheckEncoderValid(currentSettings.outFps.GetFloat()))) return;
|
||||
if (Config.GetBool(Config.Key.sbsAllowAutoEnc) && !(await InterpolateUtils.CheckEncoderValid())) return;
|
||||
|
||||
if (canceled) return;
|
||||
Program.mainForm.SetStatus("Running AI...");
|
||||
@@ -119,7 +119,7 @@ namespace Flowframes.Main
|
||||
}
|
||||
}
|
||||
|
||||
if (!(await InterpolateUtils.CheckEncoderValid(currentSettings.outFps.GetFloat()))) return;
|
||||
if (!(await InterpolateUtils.CheckEncoderValid())) return;
|
||||
|
||||
string[] outFrames = IoUtils.GetFilesSorted(currentSettings.interpFolder, currentSettings.interpExt);
|
||||
|
||||
@@ -130,7 +130,7 @@ namespace Flowframes.Main
|
||||
return;
|
||||
}
|
||||
|
||||
await Export.ExportFrames(currentSettings.interpFolder, currentSettings.outPath, currentSettings.outMode, true);
|
||||
await Export.ExportFrames(currentSettings.interpFolder, currentSettings.outPath, currentSettings.outSettings, true);
|
||||
}
|
||||
|
||||
public static async Task Reset()
|
||||
|
||||
@@ -121,18 +121,16 @@ namespace Flowframes.Main
|
||||
passes = false;
|
||||
}
|
||||
|
||||
if (passes && s.outFps.GetFloat() < 1f || s.outFps.GetFloat() > 1000f)
|
||||
{
|
||||
string imgSeqNote = isFile ? "" : "\n\nWhen using an image sequence as input, you always have to specify the frame rate manually.";
|
||||
UiUtils.ShowMessageBox($"Invalid output frame rate ({s.outFps.GetFloat()}).\nMust be 1-1000.{imgSeqNote}");
|
||||
passes = false;
|
||||
}
|
||||
|
||||
string fpsLimitValue = Config.Get(Config.Key.maxFps);
|
||||
float fpsLimit = (fpsLimitValue.Contains("/") ? new Fraction(Config.Get(Config.Key.maxFps)).GetFloat() : fpsLimitValue.GetFloat());
|
||||
int maxFps = s.outSettings.Encoder.GetInfo().MaxFramerate;
|
||||
|
||||
if (s.outMode == I.OutMode.VidGif && s.outFps.GetFloat() > 50 && !(fpsLimit > 0 && fpsLimit <= 50))
|
||||
Logger.Log($"Warning: GIF will be encoded at 50 FPS instead of {s.outFps.GetFloat()} as the format doesn't support frame rates that high.");
|
||||
if (passes && s.outFps.GetFloat() < 1f || (s.outFps.GetFloat() > maxFps && !(fpsLimit > 0 && fpsLimit <= maxFps)))
|
||||
{
|
||||
string imgSeqNote = isFile ? "" : "\n\nWhen using an image sequence as input, you always have to specify the frame rate manually.";
|
||||
UiUtils.ShowMessageBox($"Invalid output frame rate ({s.outFps.GetFloat()}).\nMust be 1-{maxFps}. Either lower the interpolation factor or use the \"Maximum Output Frame Rate\" option.{imgSeqNote}");
|
||||
passes = false;
|
||||
}
|
||||
|
||||
if (!passes)
|
||||
I.Cancel("Invalid settings detected.", true);
|
||||
@@ -222,20 +220,9 @@ namespace Flowframes.Main
|
||||
return true;
|
||||
}
|
||||
|
||||
public static async Task<bool> CheckEncoderValid(float interpFps)
|
||||
public static async Task<bool> CheckEncoderValid()
|
||||
{
|
||||
string enc = FfmpegUtils.GetEnc(FfmpegUtils.GetCodec(I.currentSettings.outMode));
|
||||
|
||||
float maxAv1Fps = 240; // SVT-AV1 only supports up to 240 FPS as of 2022-08
|
||||
float maxFps = Config.GetFloat(Config.Key.maxFps);
|
||||
float encodeFps = maxFps > 0 ? interpFps.Clamp(0, maxFps) : interpFps;
|
||||
|
||||
if (enc.ToLowerInvariant().Contains("av1") && encodeFps > maxAv1Fps)
|
||||
{
|
||||
UiUtils.ShowMessageBox($"The selected encoder only supports up to {maxAv1Fps} FPS!\nPlease use a different encoder or reduce the interpolation factor.", UiUtils.MessageType.Error);
|
||||
I.Cancel();
|
||||
return false;
|
||||
}
|
||||
string enc = I.currentSettings.outSettings.Encoder.ToString();
|
||||
|
||||
if (enc.ToLowerInvariant().Contains("nvenc") && !(await FfmpegCommands.IsEncoderCompatible(enc)))
|
||||
{
|
||||
@@ -302,7 +289,7 @@ namespace Flowframes.Main
|
||||
return false;
|
||||
}
|
||||
|
||||
if (current.outMode == I.OutMode.VidGif)
|
||||
if (current.outSettings.Format == Enums.Output.Format.Gif)
|
||||
{
|
||||
Logger.Log($"Not Using AutoEnc: Using GIF output", true);
|
||||
return false;
|
||||
|
||||
@@ -29,9 +29,9 @@ namespace Flowframes.Media
|
||||
|
||||
string subArgs = "-c:s " + Utils.GetSubCodecForContainer(containerExt);
|
||||
|
||||
bool audioCompat = Utils.ContainerSupportsAllAudioFormats(I.currentSettings.outMode, GetAudioCodecs(inputVideo));
|
||||
bool audioCompat = Utils.ContainerSupportsAllAudioFormats(I.currentSettings.outSettings.Format, GetAudioCodecs(inputVideo));
|
||||
bool slowmo = I.currentSettings.outItsScale != 0 && I.currentSettings.outItsScale != 1;
|
||||
string audioArgs = audioCompat && !slowmo ? "" : await Utils.GetAudioFallbackArgs(inputVideo, I.currentSettings.outMode, I.currentSettings.outItsScale);
|
||||
string audioArgs = audioCompat && !slowmo ? "" : await Utils.GetAudioFallbackArgs(inputVideo, I.currentSettings.outSettings.Format, I.currentSettings.outItsScale);
|
||||
|
||||
if (!audioCompat && !slowmo)
|
||||
Logger.Log("Warning: Input audio format(s) not fully supported in output container - Will re-encode.", true, false, "ffmpeg");
|
||||
@@ -46,7 +46,7 @@ namespace Flowframes.Media
|
||||
if (!subs || (subs && !Utils.ContainerSupportsSubs(containerExt)))
|
||||
subArgs = "-sn";
|
||||
|
||||
bool isMkv = I.currentSettings.outMode == I.OutMode.VidMkv;
|
||||
bool isMkv = I.currentSettings.outSettings.Format == Data.Enums.Output.Format.Mkv;
|
||||
string mkvFix = isMkv ? "-max_interleave_delta 0" : ""; // https://reddit.com/r/ffmpeg/comments/efddfs/starting_new_cluster_due_to_timestamp/
|
||||
string metaArg = (isMkv && meta) ? "-map 1:t?" : ""; // https://reddit.com/r/ffmpeg/comments/fw4jnh/how_to_make_ffmpeg_keep_attached_images_in_mkv_as/
|
||||
string shortestArg = shortest ? "-shortest" : "";
|
||||
|
||||
@@ -24,12 +24,19 @@ namespace Flowframes
|
||||
|
||||
public static int GetModulo ()
|
||||
{
|
||||
return (Interpolate.currentSettings.ai.NameInternal == Implementations.flavrCuda.NameInternal) ? 8 : 2; // FLAVR input needs to be divisible by 8
|
||||
if (Interpolate.currentSettings.ai.NameInternal == Implementations.flavrCuda.NameInternal)
|
||||
return 8;
|
||||
|
||||
return Interpolate.currentSettings.outSettings.Encoder.GetInfo().Modulo;
|
||||
}
|
||||
|
||||
public static string GetPadFilter ()
|
||||
{
|
||||
int mod = GetModulo();
|
||||
|
||||
if (mod < 2)
|
||||
return "";
|
||||
|
||||
return $"pad=width=ceil(iw/{mod})*{mod}:height=ceil(ih/{mod})*{mod}:color=black@0";
|
||||
}
|
||||
|
||||
|
||||
@@ -13,14 +13,14 @@ namespace Flowframes.Media
|
||||
{
|
||||
partial class FfmpegEncode : FfmpegCommands
|
||||
{
|
||||
public static async Task FramesToVideo(string framesFile, string outPath, Interpolate.OutMode outMode, Fraction fps, Fraction resampleFps, float itsScale, VidExtraData extraData, LogMode logMode = LogMode.OnlyLastLine, bool isChunk = false)
|
||||
public static async Task FramesToVideo(string framesFile, string outPath, ExportSettings settings, Fraction fps, Fraction resampleFps, float itsScale, VidExtraData extraData, LogMode logMode = LogMode.OnlyLastLine, bool isChunk = false)
|
||||
{
|
||||
if (logMode != LogMode.Hidden)
|
||||
Logger.Log((resampleFps.GetFloat() <= 0) ? "Encoding video..." : $"Encoding video resampled to {resampleFps.GetString()} FPS...");
|
||||
|
||||
IoUtils.RenameExistingFile(outPath);
|
||||
Directory.CreateDirectory(outPath.GetParentDir());
|
||||
string[] encArgs = Utils.GetEncArgs(Utils.GetCodec(outMode), (Interpolate.currentSettings.ScaledResolution.IsEmpty ? Interpolate.currentSettings.InputResolution : Interpolate.currentSettings.ScaledResolution), Interpolate.currentSettings.outFps.GetFloat());
|
||||
string[] encArgs = Utils.GetEncArgs(settings.Encoder, settings.PixelFormat, (Interpolate.currentSettings.ScaledResolution.IsEmpty ? Interpolate.currentSettings.InputResolution : Interpolate.currentSettings.ScaledResolution), Interpolate.currentSettings.outFps.GetFloat());
|
||||
|
||||
string inArg = $"-f concat -i {Path.GetFileName(framesFile)}";
|
||||
string linksDir = Path.Combine(framesFile + Paths.symlinksSuffix);
|
||||
@@ -33,11 +33,11 @@ namespace Flowframes.Media
|
||||
|
||||
string args = "";
|
||||
|
||||
for(int i = 0; i < encArgs.Length; i++)
|
||||
for (int i = 0; i < encArgs.Length; i++)
|
||||
{
|
||||
string pre = i == 0 ? "" : $" && ffmpeg {AvProcess.GetFfmpegDefaultArgs()}";
|
||||
string post = (i == 0 && encArgs.Length > 1) ? $"-f null -" : outPath.Wrap();
|
||||
args += $"{pre} {GetFfmpegExportArgsIn(fps, itsScale)} {inArg} {encArgs[i]} {GetFfmpegExportArgsOut(resampleFps, extraData, Interpolate.currentSettings.outMode, isChunk)} {post} ";
|
||||
args += $"{pre} {GetFfmpegExportArgsIn(fps, itsScale)} {inArg} {encArgs[i]} {GetFfmpegExportArgsOut(resampleFps, extraData, settings, isChunk)} {post} ";
|
||||
}
|
||||
|
||||
await RunFfmpeg(args, framesFile.GetParentDir(), logMode, !isChunk);
|
||||
@@ -50,7 +50,7 @@ namespace Flowframes.Media
|
||||
return $"-r {fps}";
|
||||
}
|
||||
|
||||
public static string GetFfmpegExportArgsOut (Fraction resampleFps, VidExtraData extraData, Interpolate.OutMode outMode, bool isChunk = false)
|
||||
public static string GetFfmpegExportArgsOut(Fraction resampleFps, VidExtraData extraData, ExportSettings settings, bool isChunk = false)
|
||||
{
|
||||
List<string> filters = new List<string>();
|
||||
string extraArgs = Config.Get(Config.Key.ffEncArgs);
|
||||
@@ -68,14 +68,14 @@ namespace Flowframes.Media
|
||||
if (!string.IsNullOrWhiteSpace(extraData.displayRatio) && !extraData.displayRatio.MatchesWildcard("*N/A*"))
|
||||
extraArgs += $" -aspect {extraData.displayRatio}";
|
||||
|
||||
if(!isChunk && outMode == Interpolate.OutMode.VidMp4)
|
||||
if (!isChunk && settings.Format == Enums.Output.Format.Mp4)
|
||||
extraArgs += $" -movflags +faststart";
|
||||
|
||||
filters.Add(GetPadFilter());
|
||||
return filters.Count > 0 ? $"-vf {string.Join(",", filters)}" : "" + $" {extraArgs}";
|
||||
}
|
||||
|
||||
public static string GetConcatFileExt (string concatFilePath)
|
||||
public static string GetConcatFileExt(string concatFilePath)
|
||||
{
|
||||
return Path.GetExtension(File.ReadAllLines(concatFilePath).FirstOrDefault().Split('\'')[1]);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using static Flowframes.Data.Enums.Encoding;
|
||||
using static Flowframes.Media.GetVideoInfo;
|
||||
using Stream = Flowframes.Data.Streams.Stream;
|
||||
|
||||
@@ -170,127 +171,88 @@ namespace Flowframes.Media
|
||||
return false;
|
||||
}
|
||||
|
||||
public enum Codec { H264, H265, H264Nvenc, H265Nvenc, Av1, Vp9, ProRes, AviRaw, Gif }
|
||||
|
||||
public static Codec GetCodec(Interpolate.OutMode mode)
|
||||
{
|
||||
if (mode == Interpolate.OutMode.VidMp4 || mode == Interpolate.OutMode.VidMkv)
|
||||
{
|
||||
int mp4MkvEnc = Config.GetInt(Config.Key.mp4Enc);
|
||||
if (mp4MkvEnc == 0) return Codec.H264;
|
||||
if (mp4MkvEnc == 1) return Codec.H265;
|
||||
if (mp4MkvEnc == 2) return Codec.H264Nvenc;
|
||||
if (mp4MkvEnc == 3) return Codec.H265Nvenc;
|
||||
if (mp4MkvEnc == 4) return Codec.Av1;
|
||||
}
|
||||
|
||||
if (mode == Interpolate.OutMode.VidWebm)
|
||||
return Codec.Vp9;
|
||||
|
||||
if (mode == Interpolate.OutMode.VidProRes)
|
||||
return Codec.ProRes;
|
||||
|
||||
if (mode == Interpolate.OutMode.VidAvi)
|
||||
return Codec.AviRaw;
|
||||
|
||||
if (mode == Interpolate.OutMode.VidGif)
|
||||
return Codec.Gif;
|
||||
|
||||
return Codec.H264;
|
||||
}
|
||||
|
||||
public static string GetEnc(Codec codec)
|
||||
{
|
||||
switch (codec)
|
||||
{
|
||||
case Codec.H264: return "libx264";
|
||||
case Codec.H265: return "libx265";
|
||||
case Codec.H264Nvenc: return "h264_nvenc";
|
||||
case Codec.H265Nvenc: return "hevc_nvenc";
|
||||
case Codec.Av1: return "libsvtav1";
|
||||
case Codec.Vp9: return "libvpx-vp9";
|
||||
case Codec.ProRes: return "prores_ks";
|
||||
case Codec.AviRaw: return Config.Get(Config.Key.aviCodec);
|
||||
case Codec.Gif: return "gif";
|
||||
}
|
||||
|
||||
return "libx264";
|
||||
}
|
||||
|
||||
public static string[] GetEncArgs(Codec codec, Size res, float fps, bool realtime = false) // Array contains as many entries as there are encoding passes. If "realtime" is true, force single pass.
|
||||
public static string[] GetEncArgs(Encoder enc, PixelFormat pixFmt, Size res, float fps, bool realtime = false) // Array contains as many entries as there are encoding passes. If "realtime" is true, force single pass.
|
||||
{
|
||||
int keyint = 10;
|
||||
|
||||
if (codec == Codec.H264)
|
||||
var args = new List<string>();
|
||||
|
||||
EncoderInfoVideo info = OutputUtils.GetEncoderInfoVideo(enc);
|
||||
args.Add($"-c:v {info.Name}");
|
||||
|
||||
if (enc == Encoder.X264 || enc == Encoder.X265 || enc == Encoder.SvtAv1 || enc == Encoder.VpxVp9 || enc == Encoder.Nvenc264 || enc == Encoder.Nvenc265 || enc == Encoder.NvencAv1)
|
||||
args.Add(GetKeyIntArg(fps, keyint));
|
||||
|
||||
if (pixFmt != (PixelFormat)(-1))
|
||||
args.Add($"-pix_fmt {pixFmt.ToString().Lower()}");
|
||||
|
||||
if (enc == Encoder.X264)
|
||||
{
|
||||
string preset = Config.Get(Config.Key.ffEncPreset).ToLowerInvariant().Remove(" ");
|
||||
string g = GetKeyIntArg(fps, keyint);
|
||||
return new string[] { $"-c:v {GetEnc(codec)} -crf {Config.GetInt(Config.Key.h264Crf)} -preset {preset} {g} -pix_fmt {GetPixFmt()}" };
|
||||
string preset = Config.Get(Config.Key.ffEncPreset).ToLowerInvariant().Remove(" "); // TODO: Replace this ugly stuff with enums
|
||||
args.Add($"-crf {Config.GetInt(Config.Key.h264Crf)} -preset {preset}");
|
||||
}
|
||||
|
||||
if (codec == Codec.H265)
|
||||
if (enc == Encoder.X265)
|
||||
{
|
||||
string preset = Config.Get(Config.Key.ffEncPreset).ToLowerInvariant().Remove(" ");
|
||||
string preset = Config.Get(Config.Key.ffEncPreset).ToLowerInvariant().Remove(" "); // TODO: Replace this ugly stuff with enums
|
||||
int crf = Config.GetInt(Config.Key.h265Crf);
|
||||
string g = GetKeyIntArg(fps, keyint);
|
||||
return new string[] { $"-c:v {GetEnc(codec)} {(crf > 0 ? $"-crf {crf}" : "-x265-params lossless=1")} -preset {preset} {g} -pix_fmt {GetPixFmt()}" };
|
||||
args.Add($"{(crf > 0 ? $"-crf {crf}" : "-x265-params lossless=1")} -preset {preset}");
|
||||
}
|
||||
|
||||
if (codec == Codec.H264Nvenc)
|
||||
{
|
||||
int cq = (Config.GetInt(Config.Key.h264Crf) * 1.1f).RoundToInt();
|
||||
return new string[] { $"-c:v {GetEnc(codec)} -b:v 0 {(cq > 0 ? $"-cq {cq} -preset p7" : "-preset lossless")} -pix_fmt {GetPixFmt()}" };
|
||||
}
|
||||
|
||||
if (codec == Codec.H265Nvenc)
|
||||
{
|
||||
int cq = (Config.GetInt(Config.Key.h265Crf) * 1.1f).RoundToInt();
|
||||
return new string[] { $"-c:v {GetEnc(codec)} -b:v 0 {(cq > 0 ? $"-cq {cq} -preset p7" : "-preset lossless")} -pix_fmt {GetPixFmt()}" };
|
||||
}
|
||||
|
||||
if (codec == Codec.Av1)
|
||||
if (enc == Encoder.SvtAv1)
|
||||
{
|
||||
int cq = Config.GetInt(Config.Key.av1Crf);
|
||||
string g = GetKeyIntArg(fps, keyint);
|
||||
return new string[] { $"-c:v {GetEnc(codec)} -b:v 0 -qp {cq} {GetSvtAv1Speed()} {g} -svtav1-params enable-qm=1:enable-overlays=1:enable-tf=0:scd=0 -pix_fmt {GetPixFmt()}" };
|
||||
args.Add($"-b:v 0 -qp {cq} {GetSvtAv1Speed()} -svtav1-params enable-qm=1:enable-overlays=1:enable-tf=0:scd=0");
|
||||
}
|
||||
|
||||
if (codec == Codec.Vp9)
|
||||
if (enc == Encoder.VpxVp9)
|
||||
{
|
||||
int crf = Config.GetInt(Config.Key.vp9Crf);
|
||||
string qualityStr = (crf > 0) ? $"-crf {crf}" : "-lossless 1";
|
||||
string g = GetKeyIntArg(fps, keyint);
|
||||
string t = GetTilingArgs(res, "-tile-columns ", "-tile-rows ");
|
||||
|
||||
if (realtime) // Force 1-pass
|
||||
{
|
||||
return new string[] { $"-c:v {GetEnc(codec)} -b:v 0 {qualityStr} {GetVp9Speed()} {t} -row-mt 1 {g} -pix_fmt {GetPixFmt()}" };
|
||||
args.Add($"-b:v 0 {qualityStr} {GetVp9Speed()} {t} -row-mt 1");
|
||||
}
|
||||
else
|
||||
{
|
||||
return new string[] {
|
||||
$"-c:v {GetEnc(codec)} -b:v 0 {qualityStr} {GetVp9Speed()} {t} -row-mt 1 {g} -pass 1 -pix_fmt {GetPixFmt()} -an",
|
||||
$"-c:v {GetEnc(codec)} -b:v 0 {qualityStr} {GetVp9Speed()} {t} -row-mt 1 {g} -pass 2 -pix_fmt {GetPixFmt()}"
|
||||
$"{string.Join(" ", args)} -b:v 0 {qualityStr} {GetVp9Speed()} {t} -row-mt 1 -pass 1 -an",
|
||||
$"{string.Join(" ", args)} -b:v 0 {qualityStr} {GetVp9Speed()} {t} -row-mt 1 -pass 2"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (codec == Codec.ProRes)
|
||||
if (enc == Encoder.Nvenc264)
|
||||
{
|
||||
return new string[] { $"-c:v {GetEnc(codec)} -profile:v {Config.GetInt(Config.Key.proResProfile)} -pix_fmt {GetPixFmt()}" };
|
||||
int cq = (Config.GetInt(Config.Key.h264Crf) * 1.1f).RoundToInt();
|
||||
args.Add($"-b:v 0 {(cq > 0 ? $"-cq {cq} -preset p7" : "-preset lossless")}");
|
||||
}
|
||||
|
||||
if (codec == Codec.AviRaw)
|
||||
if (enc == Encoder.Nvenc265)
|
||||
{
|
||||
return new string[] { $"-c:v {GetEnc(codec)} -pix_fmt {Config.Get(Config.Key.aviColors)}" };
|
||||
int cq = (Config.GetInt(Config.Key.h265Crf) * 1.1f).RoundToInt();
|
||||
args.Add($"-b:v 0 {(cq > 0 ? $"-cq {cq} -preset p7" : "-preset lossless")}");
|
||||
}
|
||||
|
||||
if (codec == Codec.Gif)
|
||||
if (enc == Encoder.NvencAv1)
|
||||
{
|
||||
return new string[] { $"-c:v {GetEnc(codec)} -gifflags -offsetting" };
|
||||
int cq = (Config.GetInt(Config.Key.av1Crf) * 1.1f).RoundToInt();
|
||||
args.Add($"-b:v 0 {(cq > 0 ? $"-cq {cq} -preset p7" : "-preset lossless")}");
|
||||
}
|
||||
|
||||
return new string[0];
|
||||
if (enc == Encoder.ProResKs)
|
||||
{
|
||||
args.Add($"-profile:v {Config.GetInt(Config.Key.proResProfile)}");
|
||||
}
|
||||
|
||||
if (enc == Encoder.Gif)
|
||||
{
|
||||
args.Add("-gifflags -offsetting");
|
||||
}
|
||||
|
||||
return new string[] { string.Join(" ", args) };
|
||||
}
|
||||
|
||||
public static string GetTilingArgs(Size resolution, string colArg, string rowArg)
|
||||
@@ -307,12 +269,12 @@ namespace Flowframes.Media
|
||||
|
||||
Logger.Log($"GetTilingArgs: Video resolution is {resolution.Width}x{resolution.Height} - Using 2^{cols} columns, 2^{rows} rows (=> {Math.Pow(2, cols)}x{Math.Pow(2, rows)} = {Math.Pow(2, cols) * Math.Pow(2, rows)} Tiles)", true);
|
||||
|
||||
return $"{(cols > 0 ? colArg+cols : "")} {(rows > 0 ? rowArg + rows : "")}";
|
||||
return $"{(cols > 0 ? colArg + cols : "")} {(rows > 0 ? rowArg + rows : "")}";
|
||||
}
|
||||
|
||||
public static string GetKeyIntArg(float fps, int intervalSeconds, string arg = "-g ")
|
||||
{
|
||||
int keyInt = (fps * intervalSeconds).RoundToInt().Clamp(20, 300);
|
||||
int keyInt = (fps * intervalSeconds).RoundToInt().Clamp(30, 600);
|
||||
return $"{arg}{keyInt}";
|
||||
}
|
||||
|
||||
@@ -348,34 +310,21 @@ namespace Flowframes.Media
|
||||
return $"-preset {arg}";
|
||||
}
|
||||
|
||||
static string GetPixFmt()
|
||||
{
|
||||
switch (Config.GetInt(Config.Key.pixFmt))
|
||||
{
|
||||
case 0: return "yuv420p";
|
||||
case 1: return "yuv444p";
|
||||
case 2: return "yuv420p10le";
|
||||
case 3: return "yuv444p10le";
|
||||
}
|
||||
|
||||
return "yuv420p";
|
||||
}
|
||||
|
||||
public static bool ContainerSupportsAllAudioFormats(Interpolate.OutMode outMode, List<string> codecs)
|
||||
public static bool ContainerSupportsAllAudioFormats(Enums.Output.Format outFormat, List<string> codecs)
|
||||
{
|
||||
if (codecs.Count < 1)
|
||||
Logger.Log($"Warning: ContainerSupportsAllAudioFormats() was called, but codec list has {codecs.Count} entries.", true, false, "ffmpeg");
|
||||
|
||||
foreach (string format in codecs)
|
||||
{
|
||||
if (!ContainerSupportsAudioFormat(outMode, format))
|
||||
if (!ContainerSupportsAudioFormat(outFormat, format))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool ContainerSupportsAudioFormat(Interpolate.OutMode outMode, string format)
|
||||
public static bool ContainerSupportsAudioFormat(Enums.Output.Format outFormat, string format)
|
||||
{
|
||||
bool supported = false;
|
||||
string alias = GetAudioExt(format);
|
||||
@@ -383,35 +332,31 @@ namespace Flowframes.Media
|
||||
string[] formatsMp4 = new string[] { "m4a", "mp3", "ac3", "dts" };
|
||||
string[] formatsMkv = new string[] { "m4a", "mp3", "ac3", "dts", "ogg", "mp2", "wav", "wma" };
|
||||
string[] formatsWebm = new string[] { "ogg" };
|
||||
string[] formatsProres = new string[] { "m4a", "ac3", "dts", "wav" };
|
||||
string[] formatsMov = new string[] { "m4a", "ac3", "dts", "wav" };
|
||||
string[] formatsAvi = new string[] { "m4a", "ac3", "dts" };
|
||||
|
||||
switch (outMode)
|
||||
switch (outFormat)
|
||||
{
|
||||
case Interpolate.OutMode.VidMp4: supported = formatsMp4.Contains(alias); break;
|
||||
case Interpolate.OutMode.VidMkv: supported = formatsMkv.Contains(alias); break;
|
||||
case Interpolate.OutMode.VidWebm: supported = formatsWebm.Contains(alias); break;
|
||||
case Interpolate.OutMode.VidProRes: supported = formatsProres.Contains(alias); break;
|
||||
case Interpolate.OutMode.VidAvi: supported = formatsAvi.Contains(alias); break;
|
||||
case Enums.Output.Format.Mp4: supported = formatsMp4.Contains(alias); break;
|
||||
case Enums.Output.Format.Mkv: supported = formatsMkv.Contains(alias); break;
|
||||
case Enums.Output.Format.Webm: supported = formatsWebm.Contains(alias); break;
|
||||
case Enums.Output.Format.Mov: supported = formatsMov.Contains(alias); break;
|
||||
case Enums.Output.Format.Avi: supported = formatsAvi.Contains(alias); break;
|
||||
}
|
||||
|
||||
Logger.Log($"Checking if {outMode} supports audio format '{format}' ({alias}): {supported}", true, false, "ffmpeg");
|
||||
Logger.Log($"Checking if {outFormat} supports audio format '{format}' ({alias}): {supported}", true, false, "ffmpeg");
|
||||
return supported;
|
||||
}
|
||||
|
||||
public static string GetExt(Interpolate.OutMode outMode, bool dot = true)
|
||||
public static string GetExt(ExportSettings settings, bool dot = true)
|
||||
{
|
||||
string ext = dot ? "." : "";
|
||||
EncoderInfoVideo info = settings.Encoder.GetInfo();
|
||||
|
||||
switch (outMode)
|
||||
{
|
||||
case Interpolate.OutMode.VidMp4: ext += "mp4"; break;
|
||||
case Interpolate.OutMode.VidMkv: ext += "mkv"; break;
|
||||
case Interpolate.OutMode.VidWebm: ext += "webm"; break;
|
||||
case Interpolate.OutMode.VidProRes: ext += "mov"; break;
|
||||
case Interpolate.OutMode.VidAvi: ext += "avi"; break;
|
||||
case Interpolate.OutMode.VidGif: ext += "gif"; break;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(info.OverideExtension))
|
||||
ext += settings.Format.ToString().Lower();
|
||||
else
|
||||
ext += info.OverideExtension;
|
||||
|
||||
return ext;
|
||||
}
|
||||
@@ -440,7 +385,7 @@ namespace Flowframes.Media
|
||||
return "unsupported";
|
||||
}
|
||||
|
||||
public static async Task<string> GetAudioFallbackArgs(string videoPath, Interpolate.OutMode outMode, float itsScale)
|
||||
public static async Task<string> GetAudioFallbackArgs(string videoPath, Enums.Output.Format outFormat, float itsScale)
|
||||
{
|
||||
bool opusMp4 = Config.GetBool(Config.Key.allowOpusInMp4);
|
||||
int opusBr = Config.GetInt(Config.Key.opusBitrate, 128);
|
||||
@@ -448,7 +393,7 @@ namespace Flowframes.Media
|
||||
int ac = (await GetVideoInfo.GetFfprobeInfoAsync(videoPath, GetVideoInfo.FfprobeMode.ShowStreams, "channels", 0)).GetInt();
|
||||
string af = GetAudioFilters(itsScale);
|
||||
|
||||
if (outMode == Interpolate.OutMode.VidMkv || outMode == Interpolate.OutMode.VidWebm || (outMode == Interpolate.OutMode.VidMp4 && opusMp4))
|
||||
if (outFormat == Enums.Output.Format.Mkv || outFormat == Enums.Output.Format.Webm || (outFormat == Enums.Output.Format.Mp4 && opusMp4))
|
||||
return $"-c:a libopus -b:a {(ac > 4 ? $"{opusBr * 2}" : $"{opusBr}")}k -ac {(ac > 0 ? $"{ac}" : "2")} {af}"; // Double bitrate if 5ch or more, ignore ac if <= 0
|
||||
else
|
||||
return $"-c:a aac -b:a {(ac > 4 ? $"{aacBr * 2}" : $"{aacBr}")}k -aac_coder twoloop -ac {(ac > 0 ? $"{ac}" : "2")} {af}";
|
||||
|
||||
223
Code/MiscUtils/OutputUtils.cs
Normal file
223
Code/MiscUtils/OutputUtils.cs
Normal file
@@ -0,0 +1,223 @@
|
||||
using Flowframes.Data;
|
||||
using Flowframes.IO;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media;
|
||||
using static Flowframes.Data.Enums.Encoding;
|
||||
using Encoder = Flowframes.Data.Enums.Encoding.Encoder;
|
||||
using PixFmt = Flowframes.Data.Enums.Encoding.PixelFormat;
|
||||
|
||||
namespace Flowframes.MiscUtils
|
||||
{
|
||||
internal class OutputUtils
|
||||
{
|
||||
public static EncoderInfoVideo GetEncoderInfoVideo(Encoder encoder)
|
||||
{
|
||||
if (encoder == Encoder.X264)
|
||||
{
|
||||
return new EncoderInfoVideo
|
||||
{
|
||||
Codec = Codec.H264,
|
||||
Name = "libx264",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Yuv420P, PixFmt.Yuv444P },
|
||||
};
|
||||
}
|
||||
|
||||
if (encoder == Encoder.X265)
|
||||
{
|
||||
return new EncoderInfoVideo
|
||||
{
|
||||
Codec = Codec.H265,
|
||||
Name = "libx265",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Yuv420P, PixFmt.Yuv444P, PixFmt.Yuv420P10Le, PixFmt.Yuv444P10Le },
|
||||
};
|
||||
}
|
||||
|
||||
if (encoder == Encoder.Nvenc264)
|
||||
{
|
||||
return new EncoderInfoVideo
|
||||
{
|
||||
Codec = Codec.H264,
|
||||
Name = "h264_nvenc",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Yuv420P, PixFmt.Yuv444P },
|
||||
HwAccelerated = true,
|
||||
};
|
||||
}
|
||||
|
||||
if (encoder == Encoder.SvtAv1)
|
||||
{
|
||||
return new EncoderInfoVideo
|
||||
{
|
||||
Codec = Codec.AV1,
|
||||
Name = "libsvtav1",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Yuv420P, PixFmt.Yuv420P10Le },
|
||||
PixelFormatDefault = PixFmt.Yuv420P10Le,
|
||||
MaxFramerate = 240,
|
||||
};
|
||||
}
|
||||
|
||||
if (encoder == Encoder.VpxVp9)
|
||||
{
|
||||
return new EncoderInfoVideo
|
||||
{
|
||||
Codec = Codec.VP9,
|
||||
Name = "libvpx-vp9",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Yuv420P, PixFmt.Yuv444P, PixFmt.Yuv420P10Le, PixFmt.Yuv444P, PixFmt.Yuv444P10Le },
|
||||
};
|
||||
}
|
||||
|
||||
if (encoder == Encoder.Nvenc265)
|
||||
{
|
||||
return new EncoderInfoVideo
|
||||
{
|
||||
Codec = Codec.H265,
|
||||
Name = "hevc_nvenc",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Yuv420P, PixFmt.Yuv444P, PixFmt.Yuv420P10Le },
|
||||
HwAccelerated = true,
|
||||
};
|
||||
}
|
||||
|
||||
if (encoder == Encoder.NvencAv1)
|
||||
{
|
||||
return new EncoderInfoVideo
|
||||
{
|
||||
Codec = Codec.AV1,
|
||||
Name = "av1_nvenc",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Yuv420P, PixFmt.Yuv444P, PixFmt.Yuv420P10Le },
|
||||
PixelFormatDefault = PixFmt.Yuv420P10Le,
|
||||
HwAccelerated = true,
|
||||
};
|
||||
}
|
||||
|
||||
if (encoder == Encoder.ProResKs)
|
||||
{
|
||||
return new EncoderInfoVideo
|
||||
{
|
||||
Codec = Codec.ProRes,
|
||||
Name = "prores_ks",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Yuv422P10Le, PixFmt.Yuv444P10Le, PixFmt.Yuva444P10Le },
|
||||
};
|
||||
}
|
||||
|
||||
if (encoder == Encoder.Gif)
|
||||
{
|
||||
return new EncoderInfoVideo
|
||||
{
|
||||
Codec = Codec.Gif,
|
||||
Name = "gif",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Rgb8 },
|
||||
OverideExtension = "gif",
|
||||
MaxFramerate = 50,
|
||||
};
|
||||
}
|
||||
|
||||
if (encoder == Encoder.Ffv1)
|
||||
{
|
||||
return new EncoderInfoVideo
|
||||
{
|
||||
Codec = Codec.Ffv1,
|
||||
Name = "ffv1",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Yuv420P, PixFmt.Yuv444P, PixFmt.Yuv422P, PixFmt.Yuv422P, PixFmt.Yuv420P10Le, PixFmt.Yuv444P10Le },
|
||||
Lossless = true,
|
||||
};
|
||||
}
|
||||
|
||||
if (encoder == Encoder.Huffyuv)
|
||||
{
|
||||
return new EncoderInfoVideo
|
||||
{
|
||||
Codec = Codec.Huffyuv,
|
||||
Name = "huffyuv",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Yuv422P, PixFmt.Rgb24 },
|
||||
Lossless = true,
|
||||
};
|
||||
}
|
||||
|
||||
if (encoder == Encoder.Magicyuv)
|
||||
{
|
||||
return new EncoderInfoVideo
|
||||
{
|
||||
Codec = Codec.Magicyuv,
|
||||
Name = "magicyuv",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Yuv420P, PixFmt.Yuv422P, PixFmt.Yuv444P },
|
||||
Lossless = true,
|
||||
};
|
||||
}
|
||||
|
||||
if (encoder == Encoder.Rawvideo)
|
||||
{
|
||||
return new EncoderInfoVideo
|
||||
{
|
||||
Codec = Codec.Rawvideo,
|
||||
Name = "rawvideo",
|
||||
Lossless = true,
|
||||
};
|
||||
}
|
||||
|
||||
if (encoder == Encoder.Png)
|
||||
{
|
||||
return new EncoderInfoVideo
|
||||
{
|
||||
Codec = Codec.Png,
|
||||
Name = "png",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Rgb24, PixFmt.Rgba },
|
||||
Lossless = true,
|
||||
IsImageSequence = true,
|
||||
OverideExtension = "png",
|
||||
};
|
||||
}
|
||||
|
||||
if (encoder == Encoder.Jpeg)
|
||||
{
|
||||
return new EncoderInfoVideo
|
||||
{
|
||||
Codec = Codec.Jpeg,
|
||||
Name = "mjpeg",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Yuv420P, PixFmt.Yuv422P, PixFmt.Yuv444P },
|
||||
IsImageSequence = true,
|
||||
OverideExtension = "jpg",
|
||||
};
|
||||
}
|
||||
|
||||
if (encoder == Encoder.Webp)
|
||||
{
|
||||
return new EncoderInfoVideo
|
||||
{
|
||||
Codec = Codec.Webp,
|
||||
Name = "libwebp",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Yuv420P, PixFmt.Yuva420P },
|
||||
IsImageSequence = true,
|
||||
OverideExtension = "webp",
|
||||
};
|
||||
}
|
||||
|
||||
return new EncoderInfoVideo();
|
||||
}
|
||||
|
||||
public static List<Codec> GetSupportedCodecs(Enums.Output.Format format)
|
||||
{
|
||||
switch(format)
|
||||
{
|
||||
case Enums.Output.Format.Mp4: return new List<Codec> { Codec.H264, Codec.H265, Codec.AV1 };
|
||||
case Enums.Output.Format.Mkv: return new List<Codec> { Codec.H264, Codec.H265, Codec.AV1, Codec.VP9 };
|
||||
case Enums.Output.Format.Webm: return new List<Codec> { Codec.VP9, Codec.AV1 };
|
||||
case Enums.Output.Format.Mov: return new List<Codec> { Codec.ProRes };
|
||||
case Enums.Output.Format.Avi: return new List<Codec> { Codec.Ffv1, Codec.Huffyuv, Codec.Magicyuv, Codec.Rawvideo };
|
||||
case Enums.Output.Format.Gif: return new List<Codec> { Codec.Gif };
|
||||
case Enums.Output.Format.Images: return new List<Codec> { Codec.Png, Codec.Jpeg, Codec.Webp };
|
||||
case Enums.Output.Format.Realtime: return new List<Codec> { };
|
||||
default: return new List<Codec> { };
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Encoder> GetAvailableEncoders(Enums.Output.Format format)
|
||||
{
|
||||
var allEncoders = Enum.GetValues(typeof(Encoder)).Cast<Encoder>();
|
||||
var supported = GetSupportedCodecs(format);
|
||||
return allEncoders.Where(e => supported.Contains(GetEncoderInfoVideo(e).Codec)).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
38
Code/MiscUtils/ParseUtils.cs
Normal file
38
Code/MiscUtils/ParseUtils.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Flowframes.MiscUtils
|
||||
{
|
||||
internal class ParseUtils
|
||||
{
|
||||
public static TEnum GetEnum<TEnum>(string str, bool ignoreCase = true, Dictionary<string, string> stringMap = null) where TEnum : Enum
|
||||
{
|
||||
if (stringMap == null)
|
||||
stringMap = new Dictionary<string, string>();
|
||||
|
||||
str = stringMap.Get(str, true, true);
|
||||
var values = Enum.GetValues(typeof(TEnum)).Cast<TEnum>();
|
||||
|
||||
foreach (var entry in values)
|
||||
{
|
||||
string entryString = stringMap.Get(entry.ToString(), true);
|
||||
|
||||
if (ignoreCase)
|
||||
{
|
||||
if (entryString.Lower() == str.Lower())
|
||||
return entry;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (entryString == str)
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
return (TEnum)(object)(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -678,7 +678,7 @@ namespace Flowframes.Os
|
||||
|
||||
if (ai.Piped) // VS specific
|
||||
{
|
||||
if (!hasShownError && Interpolate.currentSettings.outMode != Interpolate.OutMode.Realtime && line.ToLowerInvariant().Contains("fwrite() call failed"))
|
||||
if (!hasShownError && Interpolate.currentSettings.outSettings.Format != Enums.Output.Format.Realtime && line.ToLowerInvariant().Contains("fwrite() call failed"))
|
||||
{
|
||||
hasShownError = true;
|
||||
UiUtils.ShowMessageBox($"VapourSynth interpolation failed with an unknown error. Check the log for details:\n\n{lastLogLines}", UiUtils.MessageType.Error);
|
||||
|
||||
Reference in New Issue
Block a user