diff --git a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode/FfmpegBuilderVideoEncode.cs b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode/FfmpegBuilderVideoEncode.cs index b8d9b08a..e01070a3 100644 --- a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode/FfmpegBuilderVideoEncode.cs +++ b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode/FfmpegBuilderVideoEncode.cs @@ -79,6 +79,39 @@ public partial class FfmpegBuilderVideoEncode:FfmpegBuilderNode [Range(0, 51)] [DefaultValue(28)] public int Quality { get; set; } + + /// + /// Gets or sets the speed to encode + /// + [Select(nameof(SpeedOptions), 4)] + public string Speed { get; set; } + + private static List _SpeedOptions; + /// + /// Gets or sets the codec options + /// + public static List SpeedOptions + { + get + { + if (_SpeedOptions == null) + { + _SpeedOptions = new List + { + new () { Label = "Very Slow", Value = "veryslow" }, + new () { Label = "Slower", Value = "slower" }, + new () { Label = "Slow", Value = "slow" }, + new () { Label = "Medium", Value = "medium" }, + new () { Label = "Fast", Value = "fast" }, + new () { Label = "Faster", Value = "faster" }, + new () { Label = "Very Fast", Value = "veryfast" }, + new () { Label = "Super Fast", Value = "superfast" }, + new () { Label = "Ultra Fast", Value = "ultrafast" }, + }; + } + return _SpeedOptions; + } + } //private string bit10Filter = "yuv420p10le"; private string[] bit10Filters = new[] @@ -103,13 +136,13 @@ public partial class FfmpegBuilderVideoEncode:FfmpegBuilderNode useHardwareEncoding = false; if (Codec == CODEC_H264) - stream.EncodingParameters.AddRange(H264(args, false, Quality, useHardwareEncoding)); + stream.EncodingParameters.AddRange(H264(args, false, Quality, useHardwareEncoding, Speed)); else if (Codec == CODEC_H265 || Codec == CODEC_H265_10BIT) - stream.EncodingParameters.AddRange(H265(args, Codec == CODEC_H265_10BIT, Quality, useHardwareEncoding, stream.Stream.FramesPerSecond)); + stream.EncodingParameters.AddRange(H265(args, Codec == CODEC_H265_10BIT, Quality, useHardwareEncoding, stream.Stream.FramesPerSecond, Speed)); else if (Codec == CODEC_AV1 || Codec == CODEC_AV1_10BIT) - stream.EncodingParameters.AddRange(AV1(args, Codec == CODEC_AV1_10BIT, Quality)); + stream.EncodingParameters.AddRange(AV1(args, Codec == CODEC_AV1_10BIT, Quality, Speed)); else if(Codec == CODEC_VP9) - stream.EncodingParameters.AddRange(VP9(args, Quality, useHardwareEncoding)); + stream.EncodingParameters.AddRange(VP9(args, Quality, useHardwareEncoding, Speed)); else { args.Logger?.ILog("Unknown codec: " + Codec); @@ -120,65 +153,65 @@ public partial class FfmpegBuilderVideoEncode:FfmpegBuilderNode return 1; } - internal static IEnumerable GetEncodingParameters(NodeParameters args, string codec, int quality, bool useHardwareEncoder, float fps) + internal static IEnumerable GetEncodingParameters(NodeParameters args, string codec, int quality, bool useHardwareEncoder, float fps, string speed) { if (codec == CODEC_H264) - return H264(args, false, quality, useHardwareEncoder).Select(x => x.Replace("{index}", "0")); + return H264(args, false, quality, useHardwareEncoder, speed).Select(x => x.Replace("{index}", "0")); if (codec == CODEC_H265 || codec == CODEC_H265_10BIT) - return H265(args, codec == CODEC_H265_10BIT, quality, useHardwareEncoder, fps).Select(x => x.Replace("{index}", "0")); + return H265(args, codec == CODEC_H265_10BIT, quality, useHardwareEncoder, fps, speed).Select(x => x.Replace("{index}", "0")); if(codec == CODEC_AV1) - return AV1(args, codec == CODEC_AV1_10BIT, quality).Select(x => x.Replace("{index}", "0")); + return AV1(args, codec == CODEC_AV1_10BIT, quality, speed).Select(x => x.Replace("{index}", "0")); throw new Exception("Unsupported codec: " + codec); } private static readonly bool IsMac = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); - private static IEnumerable H264(NodeParameters args, bool tenBit, int quality, bool useHardwareEncoding) + private static IEnumerable H264(NodeParameters args, bool tenBit, int quality, bool useHardwareEncoding, string speed) { List parameters = new List(); string[] bit10Filters = null; string[] non10BitFilters = null; if (useHardwareEncoding == false) - parameters.AddRange(H26x_CPU(false, quality, out bit10Filters)); + parameters.AddRange(H26x_CPU(false, quality, speed, out bit10Filters)); else if(IsMac && CanUseHardwareEncoding.CanProcess_VideoToolbox_H264(args)) - parameters.AddRange(H26x_VideoToolbox(false, quality)); + parameters.AddRange(H26x_VideoToolbox(false, quality, speed)); else if (CanUseHardwareEncoding.CanProcess_Nvidia_H264(args)) - parameters.AddRange(H26x_Nvidia(false, quality, out non10BitFilters)); + parameters.AddRange(H26x_Nvidia(false, quality, speed, out non10BitFilters)); else if (CanUseHardwareEncoding.CanProcess_Qsv_H264(args)) - parameters.AddRange(H26x_Qsv(false, quality, 0)); + parameters.AddRange(H26x_Qsv(false, quality, 0, speed)); else if (CanUseHardwareEncoding.CanProcess_Amd_H264(args)) - parameters.AddRange(H26x_Amd(false, quality)); + parameters.AddRange(H26x_Amd(false, quality, speed)); else if (CanUseHardwareEncoding.CanProcess_Vaapi_H264(args)) - parameters.AddRange(H26x_Vaapi(false, quality)); + parameters.AddRange(H26x_Vaapi(false, quality, speed)); else - parameters.AddRange(H26x_CPU(false, quality, out bit10Filters)); + parameters.AddRange(H26x_CPU(false, quality, speed, out bit10Filters)); if (tenBit) parameters.AddRange(bit10Filters ?? new string[] { "-pix_fmt:v:{index}", "p010le", "-profile:v:{index}", "main10" }); return parameters; } - private static IEnumerable H265(NodeParameters args, bool tenBit, int quality, bool useHardwareEncoding, float fps) + private static IEnumerable H265(NodeParameters args, bool tenBit, int quality, bool useHardwareEncoding, float fps, string speed) { // hevc_qsv -load_plugin hevc_hw -pix_fmt p010le -profile:v main10 -global_quality 21 -g 24 -look_ahead 1 -look_ahead_depth 60 List parameters = new List(); string[] bit10Filters = null; string[] non10BitFilters = null; if (useHardwareEncoding == false) - parameters.AddRange(H26x_CPU(true, quality, out bit10Filters)); + parameters.AddRange(H26x_CPU(true, quality, speed, out bit10Filters)); else if (IsMac && CanUseHardwareEncoding.CanProcess_VideoToolbox_Hevc(args)) - parameters.AddRange(H26x_VideoToolbox(true, quality)); + parameters.AddRange(H26x_VideoToolbox(true, quality, speed)); else if (CanUseHardwareEncoding.CanProcess_Nvidia_Hevc(args)) - parameters.AddRange(H26x_Nvidia(true, quality, out non10BitFilters)); + parameters.AddRange(H26x_Nvidia(true, quality, speed, out non10BitFilters)); else if (CanUseHardwareEncoding.CanProcess_Qsv_Hevc(args)) - parameters.AddRange(H26x_Qsv(true, quality, fps)); + parameters.AddRange(H26x_Qsv(true, quality, fps, speed)); else if (CanUseHardwareEncoding.CanProcess_Amd_Hevc(args)) - parameters.AddRange(H26x_Amd(true, quality)); + parameters.AddRange(H26x_Amd(true, quality, speed)); else if (CanUseHardwareEncoding.CanProcess_Vaapi_Hevc(args)) - parameters.AddRange(H26x_Vaapi(true, quality)); + parameters.AddRange(H26x_Vaapi(true, quality, speed)); else - parameters.AddRange(H26x_CPU(true, quality, out bit10Filters)); + parameters.AddRange(H26x_CPU(true, quality, speed, out bit10Filters)); if (tenBit) parameters.AddRange(bit10Filters ?? new string[] { "-pix_fmt:v:{index}", "p010le", "-profile:v:{index}", "main10" }); @@ -188,36 +221,79 @@ public partial class FfmpegBuilderVideoEncode:FfmpegBuilderNode } - private static IEnumerable AV1(NodeParameters args, bool tenBit, int quality) + private static IEnumerable AV1(NodeParameters args, bool tenBit, int quality, string speed) { // hevc_qsv -load_plugin hevc_hw -pix_fmt p010le -profile:v main10 -global_quality 21 -g 24 -look_ahead 1 -look_ahead_depth 60 List parameters = new List(); - parameters.AddRange(AV1_CPU(quality)); + parameters.AddRange(AV1_CPU(quality, speed)); if (tenBit) parameters.AddRange(new [] { "-pix_fmt:v:{index}", "yuv420p10le" }); return parameters; } - private static IEnumerable VP9(NodeParameters args, int quality, bool useHardwareEncoding) + private static IEnumerable VP9(NodeParameters args, int quality, bool useHardwareEncoding, string speed) { List parameters = new List(); if (useHardwareEncoding == false) - parameters.AddRange(VP9_CPU(quality)); + parameters.AddRange(VP9_CPU(quality, speed)); else if (CanUseHardwareEncoding.CanProcess_Qsv_Hevc(args)) // if can use hevc they can use vp9 - parameters.AddRange(VP9_Qsv(quality)); + parameters.AddRange(VP9_Qsv(quality, speed)); else - parameters.AddRange(VP9_CPU(quality)); + parameters.AddRange(VP9_CPU(quality, speed)); return parameters; } - private static IEnumerable AV1_CPU(int quality) + private static IEnumerable AV1_CPU(int quality, string speed) { + string preset = "4"; + switch (speed) + { + case "ultrafast": preset = "13"; break; + case "superfast": preset = "11"; break; + case "veryfast": preset = "10"; break; + case "faster": preset = "9"; break; + case "fast": preset = "8"; break; + case "medium": preset = "6"; break; + case "slow": preset = "4"; break; + case "slower": preset = "2"; break; + case "veryslow": preset = "1"; break; + } return new [] { //"libaom-av1", "libsvtav1", - "-preset", "4", + "-preset", speed, "-crf", quality.ToString() }; } + + + /// + /// Gets the actually speed variable to use + /// + /// true if using nvidia or not + /// the speed variable + private static string GetSpeed(string speed, bool nvidia = false) + { + if (string.IsNullOrWhiteSpace(speed)) + return nvidia ? "p6" : "slower"; + if (nvidia) + { + switch (speed) + { + case "ultrafast": + case "superfast": + case "veryfast": return "p0"; + case "faster": return "p1"; + case "fast": return "p2"; + case "medium": return "p3"; + case "slow": return "p5"; + case "slower": return "p6"; + case "veryslow": return "p7"; + } + + return "p6"; // unknown + } + return speed.ToLowerInvariant(); + } } diff --git a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode/VP9.cs b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode/VP9.cs index 3961b269..1ef9b24f 100644 --- a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode/VP9.cs +++ b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode/VP9.cs @@ -6,13 +6,14 @@ public partial class FfmpegBuilderVideoEncode /// Gets FFmpeg arguments for encoding VP9 using the CPU /// /// the quality of the video + /// the encoding speed /// the FFmpeg arguments - private static IEnumerable VP9_CPU(int quality) + private static IEnumerable VP9_CPU(int quality, string speed) { return new [] { "libvpx-vp9", - "-preset", "slow", + "-preset", speed?.EmptyAsNull() ?? "slow", "-crf", quality.ToString() }; } @@ -21,15 +22,16 @@ public partial class FfmpegBuilderVideoEncode /// Gets FFmpeg arguments for encoding VP9 using the Intel's QSV hardware encoder /// /// the quality of the video + /// the encoding speed /// the FFmpeg arguments - private static IEnumerable VP9_Qsv(int quality) + private static IEnumerable VP9_Qsv(int quality, string speed) { var parameters = new List(); parameters.AddRange(new[] { "vp9_qsv", "-global_quality", quality.ToString(), - "-preset", "slower", + "-preset", speed?.EmptyAsNull() ?? "slower", }); return parameters; } diff --git a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode/h26x.cs b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode/h26x.cs index fc549bb0..666780e6 100644 --- a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode/h26x.cs +++ b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode/h26x.cs @@ -4,7 +4,8 @@ namespace FileFlows.VideoNodes.FfmpegBuilderNodes; public partial class FfmpegBuilderVideoEncode { - private static IEnumerable H26x_CPU(bool h265, int quality, out string[] bit10Filters) + + private static IEnumerable H26x_CPU(bool h265, int quality, string speed, out string[] bit10Filters) { bit10Filters = new[] { @@ -13,12 +14,12 @@ public partial class FfmpegBuilderVideoEncode return new [] { h265 ? "libx265" : "libx264", - "-preset", "slow", + "-preset", speed?.EmptyAsNull() ?? "slow", "-crf", quality.ToString() }; } - private static IEnumerable H26x_Nvidia(bool h265, int quality, out string[] non10BitFilters) + private static IEnumerable H26x_Nvidia(bool h265, int quality, string speed, out string[] non10BitFilters) { if (h265 == false) non10BitFilters = new[] { "-pix_fmt:v:{index}", "yuv420p" }; @@ -30,12 +31,12 @@ public partial class FfmpegBuilderVideoEncode h265 ? "hevc_nvenc" : "h264_nvenc", "-rc", "constqp", "-qp", quality.ToString(), - "-preset", "p6", + "-preset", GetSpeed(speed, nvidia:true), "-spatial-aq", "1" }; } - private static IEnumerable H26x_Qsv(bool h265, int quality, float fps) + private static IEnumerable H26x_Qsv(bool h265, int quality, float fps, string speed) { //hevc_qsv -load_plugin hevc_hw -pix_fmt p010le -profile:v main10 -global_quality 21 -g 24 -look_ahead 1 -look_ahead_depth 60 var parameters = new List(); @@ -60,38 +61,38 @@ public partial class FfmpegBuilderVideoEncode parameters.AddRange(new[] { "-global_quality", quality.ToString(), - "-preset", "slower", + "-preset", speed?.EmptyAsNull() ?? "slower", }); return parameters; } - private static IEnumerable H26x_Amd(bool h265, int quality) + private static IEnumerable H26x_Amd(bool h265, int quality, string speed) { return new[] { h265 ? "hevc_amf" : "h264_amf", "-qp", quality.ToString(), - "-preset", "slower", + "-preset", speed?.EmptyAsNull() ?? "slower", "-spatial-aq", "1" }; } - private static IEnumerable H26x_Vaapi(bool h265, int quality) + private static IEnumerable H26x_Vaapi(bool h265, int quality, string speed) { return new[] { h265 ? "hevc_vaapi" : "h264_vaapi", "-qp", quality.ToString(), - "-preset", "slower", + "-preset", speed?.EmptyAsNull() ?? "slower", "-spatial-aq", "1" }; } - private static IEnumerable H26x_VideoToolbox(bool h265, int quality) + private static IEnumerable H26x_VideoToolbox(bool h265, int quality, string speed) { return new[] { h265 ? "hevc_videotoolbox" : "h264_videotoolbox", "-qp", quality.ToString(), - "-preset", "slower" + "-preset", speed?.EmptyAsNull() ?? "slower" }; } } \ No newline at end of file diff --git a/VideoNodes/VideoNodes.en.json b/VideoNodes/VideoNodes.en.json index db510c88..3151069e 100644 --- a/VideoNodes/VideoNodes.en.json +++ b/VideoNodes/VideoNodes.en.json @@ -482,6 +482,7 @@ }, "Fields": { "Codec": "Codec", + "Speed": "Speed", "HardwareEncoding": "Hardware Encode", "HardwareEncoding-Help": "When checked, will test to see if hardware encoders are found on the Processing Node, and if found will use hardware encoding, otherwise will fallback to CPU encoding.", "Quality": "Quality", diff --git a/VideoNodes/VideoNodes/AudioToVideo.cs b/VideoNodes/VideoNodes/AudioToVideo.cs index b4a241ef..5d6faf73 100644 --- a/VideoNodes/VideoNodes/AudioToVideo.cs +++ b/VideoNodes/VideoNodes/AudioToVideo.cs @@ -135,7 +135,7 @@ public class AudioToVideo : EncodingNode if (Environment.GetEnvironmentVariable("HW_OFF") == "1") useHardwareEncoding = false; - var encodingParameters = FfmpegBuilderVideoEncode.GetEncodingParameters(args, this.Codec, 28, useHardwareEncoding, 29.97f); + var encodingParameters = FfmpegBuilderVideoEncode.GetEncodingParameters(args, this.Codec, 28, useHardwareEncoding, 29.97f, speed: "fast"); if (Container.ToLower() == "mp4") ffArgs.AddRange(new[] { "-movflags", "+faststart" });