AMD AMF encoder support, autodetect HW enc support

This commit is contained in:
N00MKRAD 2023-10-24 17:39:44 +02:00
parent 693a2471d1
commit 2886d5ce42
16 changed files with 171 additions and 34 deletions

View File

@ -12,7 +12,7 @@
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 Encoder { X264, X265, SvtAv1, VpxVp9, Nvenc264, Nvenc265, NvencAv1, Amf264, Amf265, ProResKs, Gif, Png, Jpeg, Webp, Ffv1, Huffyuv, Magicyuv, Rawvideo }
public enum PixelFormat { Yuv420P, Yuva420P, Yuv420P10Le, Yuv422P, Yuv422P10Le, Yuv444P, Yuv444P10Le, Yuva444P10Le, Rgb24, Rgba, Pal8 };
public class Quality

View File

@ -26,6 +26,8 @@ namespace Flowframes.Data
{ Enums.Encoding.Encoder.Nvenc264.ToString(), "h264 NVENC" },
{ Enums.Encoding.Encoder.Nvenc265.ToString(), "h265 NVENC" },
{ Enums.Encoding.Encoder.NvencAv1.ToString(), "AV1 NVENC" },
{ Enums.Encoding.Encoder.Amf264.ToString(), "h264 AMF" },
{ Enums.Encoding.Encoder.Amf265.ToString(), "h265 AMF" },
{ Enums.Encoding.Encoder.Gif.ToString(), "GIF" },
{ Enums.Encoding.Encoder.Png.ToString(), "PNG" },
{ Enums.Encoding.Encoder.Jpeg.ToString(), "JPEG" },

View File

@ -390,7 +390,7 @@ namespace Flowframes
return string.IsNullOrWhiteSpace(s);
}
public static bool NotEmpty(this string s)
public static bool IsNotEmpty(this string s)
{
return !string.IsNullOrWhiteSpace(s);
}

View File

@ -972,15 +972,6 @@
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";
@ -995,15 +986,6 @@
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(81, 0);
this.comboxOutputEncoder.Margin = new System.Windows.Forms.Padding(0, 0, 6, 0);
this.comboxOutputEncoder.Name = "comboxOutputEncoder";

View File

@ -13,7 +13,7 @@ namespace Flowframes.Forms.Main
{
Enums.Output.Format OutputFormat { get { return ParseUtils.GetEnum<Enums.Output.Format>(comboxOutputFormat.Text, true, Strings.OutputFormat); } }
Enums.Encoding.Encoder Encoder
Enums.Encoding.Encoder CurrentEncoder
{
get
{
@ -24,7 +24,7 @@ namespace Flowframes.Forms.Main
}
}
Enums.Encoding.PixelFormat PixelFormat
Enums.Encoding.PixelFormat CurrentPixFmt
{
get
{
@ -68,7 +68,7 @@ namespace Flowframes.Forms.Main
public OutputSettings GetOutputSettings()
{
string custQ = textboxOutputQualityCust.Visible ? textboxOutputQualityCust.Text.Trim() : "";
return new OutputSettings() { Encoder = Encoder, Format = OutputFormat, PixelFormat = PixelFormat, Quality = comboxOutputQuality.Text, CustomQuality = custQ };
return new OutputSettings() { Encoder = CurrentEncoder, Format = OutputFormat, PixelFormat = CurrentPixFmt, Quality = comboxOutputQuality.Text, CustomQuality = custQ };
}
}
}

View File

@ -54,7 +54,7 @@ namespace Flowframes.Forms.Main
// Main Tab
UiUtils.InitCombox(interpFactorCombox, 0);
UiUtils.InitCombox(outSpeedCombox, 0);
InitOutputUi();
UiUtils.InitCombox(aiModel, 2);
// Video Utils
UiUtils.InitCombox(trimCombox, 0);
@ -65,6 +65,7 @@ namespace Flowframes.Forms.Main
InterpolationProgress.preview = previewPicturebox;
RemovePreviewIfDisabled();
await Checks();
InitOutputUi();
InitAis();
UpdateStepByStepControls();
Initialized();
@ -87,6 +88,14 @@ namespace Flowframes.Forms.Main
UpdateOutputUi();
}
public async void ResetOutputUi ()
{
comboxOutputEncoder.Items.Clear();
Config.Set(Config.Key.PerformedHwEncCheck, false.ToString());
await StartupChecks.DetectHwEncoders();
UpdateOutputUi();
}
private void UpdateOutputUi()
{
var outMode = ParseUtils.GetEnum<Enums.Output.Format>(comboxOutputFormat.Text, true, Strings.OutputFormat);
@ -143,6 +152,7 @@ namespace Flowframes.Forms.Main
Task.Run(() => Servers.Init());
await Python.CheckCompression();
await StartupChecks.SymlinksCheck();
await StartupChecks.DetectHwEncoders();
}
catch (Exception e)
{

View File

@ -157,6 +157,8 @@
this.titleLabel = new System.Windows.Forms.Label();
this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
this.resetBtn = new HTAlt.WinForms.HTButton();
this.label10 = new System.Windows.Forms.Label();
this.btnResetHwEnc = new HTAlt.WinForms.HTButton();
this.settingsTabList.SuspendLayout();
this.generalTab.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.info1)).BeginInit();
@ -193,6 +195,8 @@
// generalTab
//
this.generalTab.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(48)))), ((int)(((byte)(48)))), ((int)(((byte)(48)))));
this.generalTab.Controls.Add(this.btnResetHwEnc);
this.generalTab.Controls.Add(this.label10);
this.generalTab.Controls.Add(this.custOutDirBrowseBtn);
this.generalTab.Controls.Add(this.custOutDir);
this.generalTab.Controls.Add(this.outFolderLoc);
@ -1775,6 +1779,30 @@
this.resetBtn.UseVisualStyleBackColor = false;
this.resetBtn.Click += new System.EventHandler(this.resetBtn_Click);
//
// label10
//
this.label10.AutoSize = true;
this.label10.Location = new System.Drawing.Point(10, 250);
this.label10.Margin = new System.Windows.Forms.Padding(10, 10, 10, 7);
this.label10.Name = "label10";
this.label10.Size = new System.Drawing.Size(186, 13);
this.label10.TabIndex = 94;
this.label10.Text = "Manage Detected Hardware Features";
//
// btnResetHwEnc
//
this.btnResetHwEnc.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
this.btnResetHwEnc.FlatAppearance.BorderSize = 0;
this.btnResetHwEnc.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnResetHwEnc.ForeColor = System.Drawing.Color.White;
this.btnResetHwEnc.Location = new System.Drawing.Point(280, 245);
this.btnResetHwEnc.Name = "btnResetHwEnc";
this.btnResetHwEnc.Size = new System.Drawing.Size(206, 23);
this.btnResetHwEnc.TabIndex = 95;
this.btnResetHwEnc.Text = "Re-Detected Hardware Encoders";
this.btnResetHwEnc.UseVisualStyleBackColor = false;
this.btnResetHwEnc.Click += new System.EventHandler(this.btnResetHwEnc_Click);
//
// SettingsForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -1945,5 +1973,7 @@
private System.Windows.Forms.Label label78;
private System.Windows.Forms.Label label7;
private System.Windows.Forms.ComboBox serverCombox;
private HTAlt.WinForms.HTButton btnResetHwEnc;
private System.Windows.Forms.Label label10;
}
}

View File

@ -244,5 +244,11 @@ namespace Flowframes.Forms
await Config.Reset(3, this);
SettingsForm_Load(null, null);
}
private void btnResetHwEnc_Click(object sender, EventArgs e)
{
Close();
Program.mainForm.ResetOutputUi();
}
}
}

View File

@ -362,6 +362,8 @@ namespace Flowframes.IO
vsRtShowOsd,
vsUseLsmash,
lastOutputSettings,
PerformedHwEncCheck,
SupportedHwEncoders,
}
}
}

View File

@ -217,7 +217,7 @@ namespace Flowframes.Main
public static async Task<bool> CheckEncoderValid()
{
string enc = I.currentSettings.outSettings.Encoder.ToString();
string enc = I.currentSettings.outSettings.Encoder.GetInfo().Name;
if (enc.ToLowerInvariant().Contains("nvenc") && !(await FfmpegCommands.IsEncoderCompatible(enc)))
{

View File

@ -249,9 +249,9 @@ namespace Flowframes
public static async Task<bool> IsEncoderCompatible(string enc)
{
Logger.Log($"IsEncoderCompatible('{enc}')", true, false, "ffmpeg");
string args = $"-loglevel error -f lavfi -i color=black:s=540x540 -vframes 1 -an -c:v {enc} -f null -";
string args = $"-loglevel error -f lavfi -i color=black:s=1920x1080 -vframes 1 -c:v {enc} -f null -";
string output = await RunFfmpeg(args, LogMode.Hidden);
return !output.ToLowerInvariant().Contains("error");
return !output.SplitIntoLines().Where(l => !l.Lower().StartsWith("frame") && l.IsNotEmpty()).Any();
}
public static string GetAudioCodec(string path, int streamIndex = -1)

View File

@ -2,8 +2,11 @@
using Flowframes.Data.Streams;
using Flowframes.IO;
using Flowframes.MiscUtils;
using Flowframes.Os;
using Flowframes.Properties;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
@ -19,6 +22,9 @@ namespace Flowframes.Media
private readonly static FfprobeMode showStreams = FfprobeMode.ShowStreams;
private readonly static FfprobeMode showFormat = FfprobeMode.ShowFormat;
public static List<Encoder> CompatibleHwEncoders = new List<Encoder>();
public static bool NvencSupportsBFrames = false;
public static async Task<int> GetStreamCount(string path)
{
Logger.Log($"GetStreamCount({path})", true);
@ -174,7 +180,7 @@ namespace Flowframes.Media
return false;
}
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.
public static string[] GetEncArgs(OutputSettings settings, Size res, float fps, bool forceSinglePass = false) // Array contains as many entries as there are encoding passes.
{
Encoder enc = settings.Encoder;
int keyint = 10;
@ -222,7 +228,7 @@ namespace Flowframes.Media
string qualityStr = (crf > 0) ? $"-crf {crf}" : "-lossless 1";
string t = GetTilingArgs(res, "-tile-columns ", "-tile-rows ");
if (realtime) // Force 1-pass
if (forceSinglePass) // Force 1-pass
{
args.Add($"-b:v 0 {qualityStr} {GetVp9Speed()} {t} -row-mt 1");
}
@ -253,6 +259,18 @@ namespace Flowframes.Media
args.Add($"-b:v 0 -preset p7 {(crf > 0 ? $"-cq {crf}" : "-tune lossless")}"); // Lossless not supported as of Jan 2023!!
}
if (enc == Encoder.Amf264)
{
int crf = GetCrf(settings);
args.Add($"-b:v 0 -rc cqp -qp_i {crf} -qp_p {crf} -quality 2");
}
if (enc == Encoder.Amf265)
{
int crf = GetCrf(settings);
args.Add($"-b:v 0 -rc cqp -qp_i {crf} -qp_p {crf} -quality 2");
}
if (enc == Encoder.ProResKs)
{
var profile = ParseUtils.GetEnum<Quality.ProResProfile>(settings.Quality, true, Strings.VideoQuality);
@ -281,7 +299,7 @@ namespace Flowframes.Media
private static int GetCrf(OutputSettings settings)
{
if (settings.CustomQuality.NotEmpty())
if (settings.CustomQuality.IsNotEmpty())
return settings.CustomQuality.GetInt();
else
return OutputUtils.GetCrf(ParseUtils.GetEnum<Quality.Common>(settings.Quality, true, Strings.VideoQuality), settings.Encoder);

View File

@ -1,7 +1,12 @@
using Flowframes.Data;
using Flowframes.IO;
using Flowframes.Os;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Win32Interop.Enums;
using static Flowframes.Data.Enums.Encoding;
using Encoder = Flowframes.Data.Enums.Encoding.Encoder;
@ -105,6 +110,32 @@ namespace Flowframes.MiscUtils
};
}
if (encoder == Encoder.Amf264)
{
return new EncoderInfoVideo
{
Codec = Codec.H264,
Name = "h264_amf",
PixelFormats = new List<PixFmt>() { PixFmt.Yuv420P },
QualityLevels = ParseUtils.GetEnumStrings<Quality.Common>(),
QualityDefault = (int)Quality.Common.VeryHigh,
HwAccelerated = true,
};
}
if (encoder == Encoder.Amf265)
{
return new EncoderInfoVideo
{
Codec = Codec.H265,
Name = "hevc_amf",
PixelFormats = new List<PixFmt>() { PixFmt.Yuv420P },
QualityLevels = ParseUtils.GetEnumStrings<Quality.Common>(),
QualityDefault = (int)Quality.Common.VeryHigh,
HwAccelerated = true,
};
}
if (encoder == Encoder.ProResKs)
{
return new EncoderInfoVideo
@ -242,8 +273,20 @@ namespace Flowframes.MiscUtils
{
var allEncoders = Enum.GetValues(typeof(Encoder)).Cast<Encoder>();
var supportedCodecs = GetSupportedCodecs(format);
var availableEncoders = supportedCodecs.SelectMany(codec => allEncoders.Where(enc => enc.GetInfo().Codec == codec));
return availableEncoders.ToList();
var availableEncoders = supportedCodecs.SelectMany(codec => allEncoders.Where(enc => enc.GetInfo().Codec == codec)).ToList();
RemoveIncompatibleEncoders(ref availableEncoders, new[] { Encoder.Nvenc264, Encoder.Nvenc265, Encoder.NvencAv1, Encoder.Amf264, Encoder.Amf265 });
return availableEncoders;
}
private static void RemoveIncompatibleEncoders (ref List<Encoder> encoders, IEnumerable<Encoder> encodersToCheck)
{
var availHwEncs = Config.Get(Config.Key.SupportedHwEncoders).Split(',');
foreach(Encoder enc in encodersToCheck)
{
if (encoders.Contains(enc) && !availHwEncs.Contains(enc.GetInfo().Name))
encoders.Remove(enc);
}
}
public static int GetCrf (Quality.Common qualityLevel, Encoder encoder)

View File

@ -325,7 +325,7 @@ namespace Flowframes.Os
string ttaStr = Config.GetBool(Config.Key.rifeNcnnUseTta, false) ? "-x" : "";
rifeNcnn.StartInfo.Arguments = $"{OsUtils.GetCmdArg()} cd /D {Path.Combine(Paths.GetPkgPath(), Implementations.rifeNcnn.PkgDir).Wrap()} & rife-ncnn-vulkan.exe " +
$" -v -i {inPath.Wrap()} -o {outPath.Wrap()} {frames} -m {mdl.ToLowerInvariant()} {ttaStr} {uhdStr} -g {Config.Get(Config.Key.ncnnGpus)} -f {NcnnUtils.GetNcnnPattern()} -j {NcnnUtils.GetNcnnThreads(Implementations.rifeNcnn)}";
$" -v -i {inPath.Wrap()} -o {outPath.Wrap()} {frames} -m {mdl.ToLowerInvariant()} {ttaStr} {uhdStr} -g {Config.Get(Config.Key.ncnnGpus)} -f {NcnnUtils.GetNcnnPattern()} -j {await NcnnUtils.GetNcnnThreads(Implementations.rifeNcnn)}";
Logger.Log("cmd.exe " + rifeNcnn.StartInfo.Arguments, true);
@ -580,7 +580,7 @@ namespace Flowframes.Os
string ttaStr = ""; // Config.GetBool(Config.Key.rifeNcnnUseTta, false) ? "-x" : "";
ifrnetNcnn.StartInfo.Arguments = $"{OsUtils.GetCmdArg()} cd /D {Path.Combine(Paths.GetPkgPath(), Implementations.ifrnetNcnn.PkgDir).Wrap()} & ifrnet-ncnn-vulkan.exe " +
$" -v -i {inPath.Wrap()} -o {outPath.Wrap()} -m {mdl} {ttaStr} {uhdStr} -g {Config.Get(Config.Key.ncnnGpus)} -f {NcnnUtils.GetNcnnPattern()} -j {NcnnUtils.GetNcnnThreads(Implementations.ifrnetNcnn)}";
$" -v -i {inPath.Wrap()} -o {outPath.Wrap()} -m {mdl} {ttaStr} {uhdStr} -g {Config.Get(Config.Key.ncnnGpus)} -f {NcnnUtils.GetNcnnPattern()} -j {await NcnnUtils.GetNcnnThreads(Implementations.ifrnetNcnn)}";
Logger.Log("cmd.exe " + ifrnetNcnn.StartInfo.Arguments, true);

View File

@ -310,5 +310,23 @@ namespace Flowframes.Os
return string.Join(", ", gpus);
}
public static string GetPathVar(string additionalPath = null)
{
return GetPathVar(new[] { additionalPath });
}
public static string GetPathVar(IEnumerable<string> additionalPaths)
{
var paths = Environment.GetEnvironmentVariable("PATH").Split(';');
List<string> newPaths = new List<string>();
if (paths != null)
newPaths.AddRange(additionalPaths.Where(p => p.IsNotEmpty()));
newPaths.AddRange(paths.Where(x => x.Lower().Replace("\\", "/").StartsWith("c:/windows")).ToList());
return string.Join(";", newPaths.Select(x => x.Replace("\\", "/"))) + ";";
}
}
}

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using Flowframes.IO;
@ -124,5 +125,30 @@ namespace Flowframes.Os
IoUtils.TryDeleteIfExists(devmodeBatchPath);
}
}
public static async Task DetectHwEncoders ()
{
if (Config.GetBool(Config.Key.PerformedHwEncCheck))
return;
Logger.Log($"Detecting hardare encoding support...");
var encoders = new[] { "h264_nvenc", "hevc_nvenc", "av1_nvenc", "h264_amf", "hevc_amf" };
var compatEncoders = new List<string>();
foreach(string e in encoders)
{
bool compat = await FfmpegCommands.IsEncoderCompatible(e);
if (compat)
{
compatEncoders.Add(e);
Logger.Log($"HW Encoder supported: {e}", true);
}
}
Logger.Log($"Available hardware encoders: {string.Join(", ", compatEncoders.Select(e => e.Replace("_", " ").Upper()))}");
Config.Set(Config.Key.SupportedHwEncoders, string.Join(",", compatEncoders));
Config.Set(Config.Key.PerformedHwEncCheck, true.ToString());
}
}
}