mirror of https://github.com/n00mkrad/flowframes
Fully implemented new output options, but no saving or custom q yet
This commit is contained in:
parent
3fa47a70a4
commit
82ecb5e7ba
|
@ -18,5 +18,7 @@ namespace Flowframes.Data
|
|||
public PixelFormat PixelFormatDefault { get; set; }
|
||||
public bool IsImageSequence { get; set; } = false;
|
||||
public string OverideExtension { get; set; } = "";
|
||||
public List<string> QualityLevels { get; set; } = new List<string> ();
|
||||
public int QualityDefault { get; set; } = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,13 @@
|
|||
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 }
|
||||
|
||||
public class Quality
|
||||
{
|
||||
public enum Common { Lossless, VeryHigh, High, Medium, Low, VeryLow }
|
||||
public enum ProResProfile { Proxy, Lt, Standard, Hq, Quad4, Quad4Xq }
|
||||
public enum GifColors { Max256, High128, Medium64, Low32, VeryLow16 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,10 +6,11 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace Flowframes.Data
|
||||
{
|
||||
public class ExportSettings
|
||||
public class OutputSettings
|
||||
{
|
||||
public Enums.Output.Format Format { get; set; }
|
||||
public Enums.Encoding.Encoder Encoder { get; set; }
|
||||
public Enums.Encoding.PixelFormat PixelFormat { get; set; }
|
||||
public string Quality { get; set; } = "";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace Flowframes
|
|||
public Fraction outFps;
|
||||
public float outItsScale;
|
||||
public float interpFactor;
|
||||
public ExportSettings outSettings;
|
||||
public OutputSettings 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, ExportSettings outSettingsArg, ModelCollection.ModelInfo modelArg)
|
||||
public InterpSettings(string inPathArg, string outPathArg, AI aiArg, Fraction inFpsDetectedArg, Fraction inFpsArg, float interpFactorArg, float itsScale, OutputSettings outSettingsArg, ModelCollection.ModelInfo modelArg)
|
||||
{
|
||||
inPath = inPathArg;
|
||||
outPath = outPathArg;
|
||||
|
@ -95,7 +95,7 @@ namespace Flowframes
|
|||
inFps = new Fraction();
|
||||
interpFactor = 0;
|
||||
outFps = new Fraction();
|
||||
outSettings = new ExportSettings();
|
||||
outSettings = new OutputSettings();
|
||||
model = null;
|
||||
alpha = false;
|
||||
stepByStep = false;
|
||||
|
|
|
@ -50,5 +50,26 @@ namespace Flowframes.Data
|
|||
{ Enums.Encoding.PixelFormat.Rgb8.ToString(), "RGB 256-color" },
|
||||
{ Enums.Encoding.PixelFormat.Rgba.ToString(), "RGBA 8-bit" },
|
||||
};
|
||||
|
||||
public static Dictionary<string, string> VideoQuality = new Dictionary<string, string>
|
||||
{
|
||||
{ Enums.Encoding.Quality.Common.Lossless.ToString(), "Lossless" },
|
||||
{ Enums.Encoding.Quality.Common.VeryHigh.ToString(), "Very High" },
|
||||
{ Enums.Encoding.Quality.Common.High.ToString(), "High" },
|
||||
{ Enums.Encoding.Quality.Common.Medium.ToString(), "Medium" },
|
||||
{ Enums.Encoding.Quality.Common.Low.ToString(), "Low" },
|
||||
{ Enums.Encoding.Quality.Common.VeryLow.ToString(), "Very Low" },
|
||||
{ Enums.Encoding.Quality.ProResProfile.Proxy.ToString(), "Proxy" },
|
||||
{ Enums.Encoding.Quality.ProResProfile.Lt.ToString(), "LT" },
|
||||
{ Enums.Encoding.Quality.ProResProfile.Standard.ToString(), "Standard" },
|
||||
{ Enums.Encoding.Quality.ProResProfile.Hq.ToString(), "HQ" },
|
||||
{ Enums.Encoding.Quality.ProResProfile.Quad4.ToString(), "4444" },
|
||||
{ Enums.Encoding.Quality.ProResProfile.Quad4Xq.ToString(), "4444 XQ" },
|
||||
{ Enums.Encoding.Quality.GifColors.Max256.ToString(), "Max (256)" },
|
||||
{ Enums.Encoding.Quality.GifColors.High128.ToString(), "High (128)" },
|
||||
{ Enums.Encoding.Quality.GifColors.Medium64.ToString(), "Medium (64)" },
|
||||
{ Enums.Encoding.Quality.GifColors.Low32.ToString(), "Low (32)" },
|
||||
{ Enums.Encoding.Quality.GifColors.VeryLow16.ToString(), "Very Low (16)" },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -300,27 +300,37 @@ namespace Flowframes
|
|||
|
||||
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;
|
||||
var strings = entriesToAdd.Select(x => stringMap.Get(x.ToString(), true));
|
||||
comboBox.FillFromEnum(strings, stringMap, defaultIndex);
|
||||
}
|
||||
|
||||
public static void FillFromEnum<TEnum>(this ComboBox comboBox, IEnumerable<TEnum> entries, Dictionary<string, string> stringMap = null, int defaultIndex = -1) where TEnum : Enum
|
||||
{
|
||||
var strings = entries.Select(x => stringMap.Get(x.ToString(), true));
|
||||
comboBox.FillFromEnum(strings, stringMap, defaultIndex);
|
||||
}
|
||||
|
||||
public static void FillFromEnum<TEnum>(this ComboBox comboBox, IEnumerable<TEnum> entries, Dictionary<string, string> stringMap, TEnum defaultEntry) 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());
|
||||
comboBox.Text = stringMap.Get(defaultEntry.ToString(), true);
|
||||
}
|
||||
|
||||
public static void FillFromEnum(this ComboBox comboBox, IEnumerable<string> entries, Dictionary<string, string> stringMap = null, int defaultIndex = -1)
|
||||
{
|
||||
if (stringMap == null)
|
||||
stringMap = new Dictionary<string, string>();
|
||||
|
||||
comboBox.Items.Clear();
|
||||
comboBox.Items.AddRange(entries.Select(x => stringMap.Get(x, true)).ToArray());
|
||||
|
||||
if (defaultIndex >= 0 && comboBox.Items.Count > 0)
|
||||
comboBox.SelectedIndex = defaultIndex;
|
||||
|
|
|
@ -92,7 +92,8 @@
|
|||
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.comboxOutputEncoder = new System.Windows.Forms.ComboBox();
|
||||
this.comboxOutputQuality = 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();
|
||||
|
@ -141,7 +142,6 @@
|
|||
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();
|
||||
|
@ -965,7 +965,7 @@
|
|||
//
|
||||
this.flowLayoutPanel1.Controls.Add(this.comboxOutputFormat);
|
||||
this.flowLayoutPanel1.Controls.Add(this.comboxOutputEncoder);
|
||||
this.flowLayoutPanel1.Controls.Add(this.comboxOutputCrf);
|
||||
this.flowLayoutPanel1.Controls.Add(this.comboxOutputQuality);
|
||||
this.flowLayoutPanel1.Controls.Add(this.comboxOutputColors);
|
||||
this.flowLayoutPanel1.Location = new System.Drawing.Point(281, 157);
|
||||
this.flowLayoutPanel1.Name = "flowLayoutPanel1";
|
||||
|
@ -995,18 +995,41 @@
|
|||
this.comboxOutputFormat.TabIndex = 47;
|
||||
this.comboxOutputFormat.SelectedIndexChanged += new System.EventHandler(this.comboxOutputFormat_SelectedIndexChanged);
|
||||
//
|
||||
// comboxOutputCrf
|
||||
// comboxOutputEncoder
|
||||
//
|
||||
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";
|
||||
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);
|
||||
//
|
||||
// comboxOutputQuality
|
||||
//
|
||||
this.comboxOutputQuality.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
|
||||
this.comboxOutputQuality.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.comboxOutputQuality.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.comboxOutputQuality.ForeColor = System.Drawing.Color.White;
|
||||
this.comboxOutputQuality.FormattingEnabled = true;
|
||||
this.comboxOutputQuality.Location = new System.Drawing.Point(182, 0);
|
||||
this.comboxOutputQuality.Margin = new System.Windows.Forms.Padding(0, 0, 6, 0);
|
||||
this.comboxOutputQuality.Name = "comboxOutputQuality";
|
||||
this.comboxOutputQuality.Size = new System.Drawing.Size(100, 23);
|
||||
this.comboxOutputQuality.TabIndex = 48;
|
||||
//
|
||||
// comboxOutputColors
|
||||
//
|
||||
|
@ -1015,7 +1038,7 @@
|
|||
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.Location = new System.Drawing.Point(288, 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);
|
||||
|
@ -1708,29 +1731,6 @@
|
|||
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;
|
||||
|
@ -1917,7 +1917,7 @@
|
|||
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 comboxOutputQuality;
|
||||
public System.Windows.Forms.ComboBox comboxOutputColors;
|
||||
public System.Windows.Forms.ComboBox comboxOutputEncoder;
|
||||
}
|
||||
|
|
|
@ -105,17 +105,23 @@ namespace Flowframes
|
|||
var encoder = ParseUtils.GetEnum<Enums.Encoding.Encoder>(comboxOutputEncoder.Text, true, Strings.Encoder);
|
||||
bool noEncoder = (int)encoder == -1;
|
||||
|
||||
comboxOutputCrf.Visible = !noEncoder;
|
||||
comboxOutputQuality.Visible = !noEncoder;
|
||||
comboxOutputColors.Visible = !noEncoder;
|
||||
|
||||
if (noEncoder)
|
||||
return;
|
||||
|
||||
EncoderInfoVideo info = OutputUtils.GetEncoderInfoVideo(encoder);
|
||||
comboxOutputCrf.Visible = !info.Lossless;
|
||||
|
||||
comboxOutputQuality.Visible = !info.Lossless;
|
||||
comboxOutputQuality.Items.Clear();
|
||||
|
||||
if(info.QualityLevels.Count > 0)
|
||||
comboxOutputQuality.FillFromEnum(info.QualityLevels, Strings.VideoQuality, info.QualityDefault);
|
||||
|
||||
var pixelFormats = info.PixelFormats;
|
||||
comboxOutputColors.Visible = pixelFormats.Count > 0;
|
||||
comboxOutputColors.FillFromEnum(pixelFormats, Strings.PixelFormat, 0);
|
||||
comboxOutputColors.FillFromEnum(pixelFormats, Strings.PixelFormat, info.PixelFormatDefault);
|
||||
}
|
||||
|
||||
async Task Checks()
|
||||
|
@ -393,7 +399,7 @@ namespace Flowframes
|
|||
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 }; } }
|
||||
OutputSettings GetExportSettings { get { return new OutputSettings() { Encoder = GetEncoder, Format = GetOutputFormat, PixelFormat = GetPixelFormat, Quality = comboxOutputQuality.Text }; } }
|
||||
|
||||
public void SetFormat(Enums.Output.Format format)
|
||||
{
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace Flowframes.Main
|
|||
{
|
||||
|
||||
|
||||
public static async Task ExportFrames(string path, string outFolder, ExportSettings exportSettings, bool stepByStep)
|
||||
public static async Task ExportFrames(string path, string outFolder, OutputSettings exportSettings, bool stepByStep)
|
||||
{
|
||||
if(Config.GetInt(Config.Key.sceneChangeFillMode) == 1)
|
||||
{
|
||||
|
@ -76,7 +76,7 @@ namespace Flowframes.Main
|
|||
public static async Task<string> GetPipedFfmpegCmd(bool ffplay = false)
|
||||
{
|
||||
InterpSettings s = I.currentSettings;
|
||||
string encArgs = FfmpegUtils.GetEncArgs(s.outSettings.Encoder, s.outSettings.PixelFormat, (s.ScaledResolution.IsEmpty ? s.InputResolution : s.ScaledResolution), s.outFps.GetFloat(), true).FirstOrDefault();
|
||||
string encArgs = FfmpegUtils.GetEncArgs(s.outSettings, (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());
|
||||
|
@ -196,7 +196,7 @@ namespace Flowframes.Main
|
|||
}
|
||||
}
|
||||
|
||||
static async Task Encode(ExportSettings settings, string framesPath, string outPath, Fraction fps, Fraction resampleFps)
|
||||
static async Task Encode(OutputSettings settings, string framesPath, string outPath, Fraction fps, Fraction resampleFps)
|
||||
{
|
||||
string framesFile = Path.Combine(framesPath.GetParentDir(), Paths.GetFrameOrderFilename(I.currentSettings.interpFactor));
|
||||
|
||||
|
@ -209,7 +209,8 @@ namespace Flowframes.Main
|
|||
|
||||
if (settings.Format == Enums.Output.Format.Gif)
|
||||
{
|
||||
await FfmpegEncode.FramesToGifConcat(framesFile, outPath, fps, true, Config.GetInt(Config.Key.gifColors), resampleFps, I.currentSettings.outItsScale);
|
||||
int paletteColors = OutputUtils.GetGifColors(ParseUtils.GetEnum<Enums.Encoding.Quality.GifColors>(settings.Quality, true, Strings.VideoQuality));
|
||||
await FfmpegEncode.FramesToGifConcat(framesFile, outPath, fps, true, paletteColors, resampleFps, I.currentSettings.outItsScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -289,7 +290,7 @@ namespace Flowframes.Main
|
|||
await Loop(outPath, await GetLoopTimes());
|
||||
}
|
||||
|
||||
public static async Task EncodeChunk(string outPath, string interpDir, int chunkNo, ExportSettings settings, int firstFrameNum, int framesAmount)
|
||||
public static async Task EncodeChunk(string outPath, string interpDir, int chunkNo, OutputSettings 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));
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media;
|
||||
using static Flowframes.AvProcess;
|
||||
using Utils = Flowframes.Media.FfmpegUtils;
|
||||
|
||||
|
@ -13,14 +14,14 @@ namespace Flowframes.Media
|
|||
{
|
||||
partial class FfmpegEncode : FfmpegCommands
|
||||
{
|
||||
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)
|
||||
public static async Task FramesToVideo(string framesFile, string outPath, OutputSettings 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(settings.Encoder, settings.PixelFormat, (Interpolate.currentSettings.ScaledResolution.IsEmpty ? Interpolate.currentSettings.InputResolution : Interpolate.currentSettings.ScaledResolution), Interpolate.currentSettings.outFps.GetFloat());
|
||||
string[] encArgs = Utils.GetEncArgs(settings, (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);
|
||||
|
@ -50,7 +51,7 @@ namespace Flowframes.Media
|
|||
return $"-r {fps}";
|
||||
}
|
||||
|
||||
public static string GetFfmpegExportArgsOut(Fraction resampleFps, VidExtraData extraData, ExportSettings settings, bool isChunk = false)
|
||||
public static string GetFfmpegExportArgsOut(Fraction resampleFps, VidExtraData extraData, OutputSettings settings, bool isChunk = false)
|
||||
{
|
||||
List<string> filters = new List<string>();
|
||||
string extraArgs = Config.Get(Config.Key.ffEncArgs);
|
||||
|
@ -71,6 +72,14 @@ namespace Flowframes.Media
|
|||
if (!isChunk && settings.Format == Enums.Output.Format.Mp4)
|
||||
extraArgs += $" -movflags +faststart";
|
||||
|
||||
if(settings.Format == Enums.Output.Format.Gif)
|
||||
{
|
||||
string dither = Config.Get(Config.Key.gifDitherType).Split(' ').First();
|
||||
int colors = OutputUtils.GetGifColors(ParseUtils.GetEnum<Enums.Encoding.Quality.GifColors>(settings.Quality, true, Strings.VideoQuality));
|
||||
string paletteFilter = $"\"split[s0][s1];[s0]palettegen={colors}[p];[s1][p]paletteuse=dither={dither}\"";
|
||||
filters.Add(paletteFilter);
|
||||
}
|
||||
|
||||
filters.Add(GetPadFilter());
|
||||
return filters.Count > 0 ? $"-vf {string.Join(",", filters)}" : "" + $" {extraArgs}";
|
||||
}
|
||||
|
|
|
@ -171,8 +171,10 @@ namespace Flowframes.Media
|
|||
return false;
|
||||
}
|
||||
|
||||
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.
|
||||
public static string[] GetEncArgs(OutputSettings settings, Size res, float fps, bool realtime = false) // Array contains as many entries as there are encoding passes. If "realtime" is true, force single pass.
|
||||
{
|
||||
Encoder enc = settings.Encoder;
|
||||
PixelFormat pixFmt = settings.PixelFormat;
|
||||
int keyint = 10;
|
||||
|
||||
var args = new List<string>();
|
||||
|
@ -189,25 +191,26 @@ namespace Flowframes.Media
|
|||
if (enc == Encoder.X264)
|
||||
{
|
||||
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}");
|
||||
int crf = OutputUtils.GetCrf(ParseUtils.GetEnum<Quality.Common>(settings.Quality, true, Strings.VideoQuality), enc);
|
||||
args.Add($"-crf {crf} -preset {preset}");
|
||||
}
|
||||
|
||||
if (enc == Encoder.X265)
|
||||
{
|
||||
string preset = Config.Get(Config.Key.ffEncPreset).ToLowerInvariant().Remove(" "); // TODO: Replace this ugly stuff with enums
|
||||
int crf = Config.GetInt(Config.Key.h265Crf);
|
||||
int crf = OutputUtils.GetCrf(ParseUtils.GetEnum<Quality.Common>(settings.Quality, true, Strings.VideoQuality), enc);
|
||||
args.Add($"{(crf > 0 ? $"-crf {crf}" : "-x265-params lossless=1")} -preset {preset}");
|
||||
}
|
||||
|
||||
if (enc == Encoder.SvtAv1)
|
||||
{
|
||||
int cq = Config.GetInt(Config.Key.av1Crf);
|
||||
args.Add($"-b:v 0 -qp {cq} {GetSvtAv1Speed()} -svtav1-params enable-qm=1:enable-overlays=1:enable-tf=0:scd=0");
|
||||
int crf = OutputUtils.GetCrf(ParseUtils.GetEnum<Quality.Common>(settings.Quality, true, Strings.VideoQuality), enc);
|
||||
args.Add($"-crf {crf} {GetSvtAv1Speed()} -svtav1-params enable-qm=1:enable-overlays=1:enable-tf=0:scd=0");
|
||||
}
|
||||
|
||||
if (enc == Encoder.VpxVp9)
|
||||
{
|
||||
int crf = Config.GetInt(Config.Key.vp9Crf);
|
||||
int crf = OutputUtils.GetCrf(ParseUtils.GetEnum<Quality.Common>(settings.Quality, true, Strings.VideoQuality), enc);
|
||||
string qualityStr = (crf > 0) ? $"-crf {crf}" : "-lossless 1";
|
||||
string t = GetTilingArgs(res, "-tile-columns ", "-tile-rows ");
|
||||
|
||||
|
@ -226,20 +229,20 @@ namespace Flowframes.Media
|
|||
|
||||
if (enc == Encoder.Nvenc264)
|
||||
{
|
||||
int cq = (Config.GetInt(Config.Key.h264Crf) * 1.1f).RoundToInt();
|
||||
args.Add($"-b:v 0 {(cq > 0 ? $"-cq {cq} -preset p7" : "-preset lossless")}");
|
||||
int crf = OutputUtils.GetCrf(ParseUtils.GetEnum<Quality.Common>(settings.Quality, true, Strings.VideoQuality), enc);
|
||||
args.Add($"-b:v 0 {(crf > 0 ? $"-cq {crf} -preset p7" : "-preset lossless")}");
|
||||
}
|
||||
|
||||
if (enc == Encoder.Nvenc265)
|
||||
{
|
||||
int cq = (Config.GetInt(Config.Key.h265Crf) * 1.1f).RoundToInt();
|
||||
args.Add($"-b:v 0 {(cq > 0 ? $"-cq {cq} -preset p7" : "-preset lossless")}");
|
||||
int crf = OutputUtils.GetCrf(ParseUtils.GetEnum<Quality.Common>(settings.Quality, true, Strings.VideoQuality), enc);
|
||||
args.Add($"-b:v 0 {(crf > 0 ? $"-cq {crf} -preset p7" : "-preset lossless")}");
|
||||
}
|
||||
|
||||
if (enc == Encoder.NvencAv1)
|
||||
{
|
||||
int cq = (Config.GetInt(Config.Key.av1Crf) * 1.1f).RoundToInt();
|
||||
args.Add($"-b:v 0 {(cq > 0 ? $"-cq {cq} -preset p7" : "-preset lossless")}");
|
||||
int crf = OutputUtils.GetCrf(ParseUtils.GetEnum<Quality.Common>(settings.Quality, true, Strings.VideoQuality), enc);
|
||||
args.Add($"-b:v 0 -preset p7 {(crf > 0 ? $"-cq {crf}" : "-tune lossless")}"); // Lossless not supported as of Jan 2023!!
|
||||
}
|
||||
|
||||
if (enc == Encoder.ProResKs)
|
||||
|
@ -348,7 +351,7 @@ namespace Flowframes.Media
|
|||
return supported;
|
||||
}
|
||||
|
||||
public static string GetExt(ExportSettings settings, bool dot = true)
|
||||
public static string GetExt(OutputSettings settings, bool dot = true)
|
||||
{
|
||||
string ext = dot ? "." : "";
|
||||
EncoderInfoVideo info = settings.Encoder.GetInfo();
|
||||
|
|
|
@ -23,6 +23,8 @@ namespace Flowframes.MiscUtils
|
|||
Codec = Codec.H264,
|
||||
Name = "libx264",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Yuv420P, PixFmt.Yuv444P },
|
||||
QualityLevels = ParseUtils.GetEnumStrings<Quality.Common>(),
|
||||
QualityDefault = (int)Quality.Common.VeryHigh,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -33,6 +35,8 @@ namespace Flowframes.MiscUtils
|
|||
Codec = Codec.H265,
|
||||
Name = "libx265",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Yuv420P, PixFmt.Yuv444P, PixFmt.Yuv420P10Le, PixFmt.Yuv444P10Le },
|
||||
QualityLevels = ParseUtils.GetEnumStrings<Quality.Common>(),
|
||||
QualityDefault = (int)Quality.Common.VeryHigh,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -43,6 +47,8 @@ namespace Flowframes.MiscUtils
|
|||
Codec = Codec.H264,
|
||||
Name = "h264_nvenc",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Yuv420P, PixFmt.Yuv444P },
|
||||
QualityLevels = ParseUtils.GetEnumStrings<Quality.Common>(),
|
||||
QualityDefault = (int)Quality.Common.VeryHigh,
|
||||
HwAccelerated = true,
|
||||
};
|
||||
}
|
||||
|
@ -55,6 +61,8 @@ namespace Flowframes.MiscUtils
|
|||
Name = "libsvtav1",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Yuv420P, PixFmt.Yuv420P10Le },
|
||||
PixelFormatDefault = PixFmt.Yuv420P10Le,
|
||||
QualityLevels = ParseUtils.GetEnumStrings<Quality.Common>(),
|
||||
QualityDefault = (int)Quality.Common.VeryHigh,
|
||||
MaxFramerate = 240,
|
||||
};
|
||||
}
|
||||
|
@ -66,6 +74,8 @@ namespace Flowframes.MiscUtils
|
|||
Codec = Codec.VP9,
|
||||
Name = "libvpx-vp9",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Yuv420P, PixFmt.Yuv444P, PixFmt.Yuv420P10Le, PixFmt.Yuv444P, PixFmt.Yuv444P10Le },
|
||||
QualityLevels = ParseUtils.GetEnumStrings<Quality.Common>(),
|
||||
QualityDefault = (int)Quality.Common.VeryHigh,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -76,6 +86,8 @@ namespace Flowframes.MiscUtils
|
|||
Codec = Codec.H265,
|
||||
Name = "hevc_nvenc",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Yuv420P, PixFmt.Yuv444P, PixFmt.Yuv420P10Le },
|
||||
QualityLevels = ParseUtils.GetEnumStrings<Quality.Common>(),
|
||||
QualityDefault = (int)Quality.Common.VeryHigh,
|
||||
HwAccelerated = true,
|
||||
};
|
||||
}
|
||||
|
@ -87,6 +99,8 @@ namespace Flowframes.MiscUtils
|
|||
Codec = Codec.AV1,
|
||||
Name = "av1_nvenc",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Yuv420P, PixFmt.Yuv444P, PixFmt.Yuv420P10Le },
|
||||
QualityLevels = ParseUtils.GetEnumStrings<Quality.Common>(),
|
||||
QualityDefault = (int)Quality.Common.VeryHigh,
|
||||
PixelFormatDefault = PixFmt.Yuv420P10Le,
|
||||
HwAccelerated = true,
|
||||
};
|
||||
|
@ -99,6 +113,8 @@ namespace Flowframes.MiscUtils
|
|||
Codec = Codec.ProRes,
|
||||
Name = "prores_ks",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Yuv422P10Le, PixFmt.Yuv444P10Le, PixFmt.Yuva444P10Le },
|
||||
QualityLevels = ParseUtils.GetEnumStrings<Quality.ProResProfile>(),
|
||||
QualityDefault = (int)Quality.ProResProfile.Hq,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -109,6 +125,8 @@ namespace Flowframes.MiscUtils
|
|||
Codec = Codec.Gif,
|
||||
Name = "gif",
|
||||
PixelFormats = new List<PixFmt>() { PixFmt.Rgb8 },
|
||||
QualityLevels = ParseUtils.GetEnumStrings<Quality.GifColors>(),
|
||||
QualityDefault = (int)Quality.GifColors.High128,
|
||||
OverideExtension = "gif",
|
||||
MaxFramerate = 50,
|
||||
};
|
||||
|
@ -199,7 +217,7 @@ namespace Flowframes.MiscUtils
|
|||
|
||||
public static List<Codec> GetSupportedCodecs(Enums.Output.Format format)
|
||||
{
|
||||
switch(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 };
|
||||
|
@ -216,8 +234,53 @@ namespace Flowframes.MiscUtils
|
|||
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();
|
||||
var supportedCodecs = GetSupportedCodecs(format);
|
||||
var availableEncoders = supportedCodecs.SelectMany(codec => allEncoders.Where(enc => enc.GetInfo().Codec == codec));
|
||||
return availableEncoders.ToList();
|
||||
}
|
||||
|
||||
public static int GetCrf (Quality.Common qualityLevel, Encoder encoder)
|
||||
{
|
||||
int baseCrf = Crfs[qualityLevel];
|
||||
float multiplier = 1f;
|
||||
|
||||
if (encoder == Encoder.X265)
|
||||
multiplier = 1.0f;
|
||||
if (encoder == Encoder.VpxVp9)
|
||||
multiplier = 1.3f;
|
||||
if (encoder == Encoder.SvtAv1)
|
||||
multiplier = 1.3f;
|
||||
if (encoder == Encoder.Nvenc264)
|
||||
multiplier = 1.1f;
|
||||
if (encoder == Encoder.Nvenc265)
|
||||
multiplier = 1.15f;
|
||||
if (encoder == Encoder.NvencAv1)
|
||||
multiplier = 1.3f;
|
||||
|
||||
return (baseCrf * multiplier).RoundToInt();
|
||||
}
|
||||
|
||||
public static int GetGifColors (Quality.GifColors qualityLevel)
|
||||
{
|
||||
switch (qualityLevel)
|
||||
{
|
||||
case Quality.GifColors.Max256: return 256;
|
||||
case Quality.GifColors.High128: return 128;
|
||||
case Quality.GifColors.Medium64: return 64;
|
||||
case Quality.GifColors.Low32: return 32;
|
||||
case Quality.GifColors.VeryLow16: return 16;
|
||||
default: return 128;
|
||||
}
|
||||
}
|
||||
|
||||
public static Dictionary<Quality.Common, int> Crfs = new Dictionary<Quality.Common, int>
|
||||
{
|
||||
{ Quality.Common.Lossless, 0 },
|
||||
{ Quality.Common.VeryHigh, 16 },
|
||||
{ Quality.Common.High, 20 },
|
||||
{ Quality.Common.Medium, 26 },
|
||||
{ Quality.Common.Low, 32 },
|
||||
{ Quality.Common.VeryLow, 40 },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,5 +34,11 @@ namespace Flowframes.MiscUtils
|
|||
|
||||
return (TEnum)(object)(-1);
|
||||
}
|
||||
|
||||
public static List<string> GetEnumStrings<TEnum>() where TEnum : Enum
|
||||
{
|
||||
var entries = Enum.GetValues(typeof(TEnum)).Cast<TEnum>();
|
||||
return entries.Select(e => e.ToString()).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
Flowframes 1.40.0 Changelog:
|
||||
- New: Added RIFE 4.6 model
|
||||
- Improved: Updated ffmpeg, includes SVT-AV1 1.4.1 which speeds up encoding by ~12%
|
||||
- Fixed: RIFE-NCNN-VS did not work with input resolutions not divisible by 2
|
||||
- Fixed: Issues with certain system languages (e.g. Turkish)
|
||||
|
||||
|
||||
Flowframes 1.39.0 Changelog:
|
||||
- Added real-time interpolation output mode (with RIFE-NCNN-VS)
|
||||
- Added RIFE 4.4 and RIFE 4.3 models
|
||||
|
|
Loading…
Reference in New Issue