From f24bcabaded9fcc13918977e681d20008257298e Mon Sep 17 00:00:00 2001 From: John Andrews Date: Mon, 28 Aug 2023 16:34:23 +1200 Subject: [PATCH] FF-1096 - added hardware encoding for AV1 using NVIDIA --- .../Video/FfmpegBuilderVideoEncode/AV1.cs | 65 +++++++++++++++++++ .../FfmpegBuilderVideoEncode.cs | 41 ++++-------- .../LogicalNodes/CanUseHardwareEncoding.cs | 7 ++ .../FfmpegBuilder_VideoEncodeTests.cs | 32 +++++++++ 4 files changed, 118 insertions(+), 27 deletions(-) create mode 100644 VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode/AV1.cs diff --git a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode/AV1.cs b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode/AV1.cs new file mode 100644 index 00000000..effc0aa8 --- /dev/null +++ b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode/AV1.cs @@ -0,0 +1,65 @@ +namespace FileFlows.VideoNodes.FfmpegBuilderNodes; + +public partial class FfmpegBuilderVideoEncode +{ + /// + /// AV1 CPU encoding + /// + /// the quality + /// the speed + /// the encoding parameters + 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", preset, + "-crf", quality.ToString() + }; + } + + /// + /// AV1 NVIDIA encoding + /// + /// the quality + /// the speed + /// the encoding parameters + private static IEnumerable AV1_Nvidia(int quality, string speed) + { + switch (speed) + { + case "ultrafast": speed = "p1"; break; + case "superfast": speed = "p1"; break; + case "veryfast": speed = "p1"; break; + case "faster": speed = "p2"; break; + case "fast": speed = "p3"; break; + case "medium": speed = "p4"; break; + case "slow": speed = "p5"; break; + case "slower": speed = "p6"; break; + case "veryslow": speed = "p7"; break; + default: speed = "p4"; break; // unexpected + } + return new [] + { + "av1_nvenc", + "-rc", "constqp", + "-qp", quality.ToString(), + "-preset", speed, + "-spatial-aq", "1" + }; + } +} \ No newline at end of file diff --git a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode/FfmpegBuilderVideoEncode.cs b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode/FfmpegBuilderVideoEncode.cs index d2a95dfa..49128d93 100644 --- a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode/FfmpegBuilderVideoEncode.cs +++ b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode/FfmpegBuilderVideoEncode.cs @@ -168,7 +168,7 @@ public partial class FfmpegBuilderVideoEncode:FfmpegBuilderNode else if (Codec == CODEC_H265 || Codec == CODEC_H265_10BIT) stream.EncodingParameters.AddRange(H265(args, Codec == CODEC_H265_10BIT, Quality, encoder, stream.Stream.FramesPerSecond, Speed)); else if (Codec == CODEC_AV1 || Codec == CODEC_AV1_10BIT) - stream.EncodingParameters.AddRange(AV1(args, Codec == CODEC_AV1_10BIT, Quality, Speed)); + stream.EncodingParameters.AddRange(AV1(args, Codec == CODEC_AV1_10BIT, Quality, encoder, Speed)); else if(Codec == CODEC_VP9) stream.EncodingParameters.AddRange(VP9(args, Quality, encoder, Speed)); else @@ -188,7 +188,7 @@ public partial class FfmpegBuilderVideoEncode:FfmpegBuilderNode if (codec == CODEC_H265 || codec == CODEC_H265_10BIT) return H265(args, codec == CODEC_H265_10BIT, quality, encoder, fps, speed).Select(x => x.Replace("{index}", "0")); if(codec == CODEC_AV1) - return AV1(args, codec == CODEC_AV1_10BIT, quality, speed).Select(x => x.Replace("{index}", "0")); + return AV1(args, codec == CODEC_AV1_10BIT, quality, encoder, speed).Select(x => x.Replace("{index}", "0")); throw new Exception("Unsupported codec: " + codec); } @@ -270,11 +270,21 @@ public partial class FfmpegBuilderVideoEncode:FfmpegBuilderNode } - private static IEnumerable AV1(NodeParameters args, bool tenBit, int quality, string speed) + private static IEnumerable AV1(NodeParameters args, bool tenBit, int quality, string encoder, 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, speed)); + + if (encoder == ENCODER_CPU) + parameters.AddRange(AV1_CPU(quality, speed)); + else if(encoder == ENCODER_NVIDIA) + parameters.AddRange(AV1_Nvidia(quality, speed)); + + else if (CanUseHardwareEncoding.CanProcess_Nvidia_AV1(args)) + parameters.AddRange(AV1_Nvidia(quality, speed)); + else + parameters.AddRange(AV1_CPU(quality, speed)); + if (tenBit) parameters.AddRange(new [] { "-pix_fmt:v:{index}", "yuv420p10le" }); return parameters; @@ -294,29 +304,6 @@ public partial class FfmpegBuilderVideoEncode:FfmpegBuilderNode return parameters; } - 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", preset, - "-crf", quality.ToString() - }; - } /// diff --git a/VideoNodes/LogicalNodes/CanUseHardwareEncoding.cs b/VideoNodes/LogicalNodes/CanUseHardwareEncoding.cs index c42553ab..d3a67fce 100644 --- a/VideoNodes/LogicalNodes/CanUseHardwareEncoding.cs +++ b/VideoNodes/LogicalNodes/CanUseHardwareEncoding.cs @@ -99,6 +99,13 @@ public class CanUseHardwareEncoding:Node /// the node parameters /// true if can use it, otherwise false internal static bool CanProcess_Nvidia_Hevc(NodeParameters args) => CanProcess(args, "hevc_nvenc"); + + /// + /// Checks if this flow runner can use NVIDIA AV1 encoder + /// + /// the node parameters + /// true if can use it, otherwise false + internal static bool CanProcess_Nvidia_AV1(NodeParameters args) => CanProcess(args, "av1_nvenc"); /// /// Checks if this flow runner can use NVIDIA H.264 encoder diff --git a/VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_VideoEncodeTests.cs b/VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_VideoEncodeTests.cs index 53c2c3a5..65cb36f2 100644 --- a/VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_VideoEncodeTests.cs +++ b/VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_VideoEncodeTests.cs @@ -167,6 +167,38 @@ public class FfmpegBuilder_VideoEncode_VideoEncodeTests: TestBase string log = logger.ToString(); Assert.AreEqual(1, result); } + + + [TestMethod] + public void FfmpegBuilder_VideoEncode_Av1() + { + var logger = new TestLogger(); + string ffmpeg = FfmpegPath; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(TestFile_BasicMkv); + var args = new NodeParameters(TestFile_BasicMkv, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = TempPath; + args.Parameters.Add("VideoInfo", vii); + + FfmpegBuilderStart ffStart = new(); + ffStart.PreExecute(args); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoEncode ffEncode = new(); + ffEncode.Quality = 28; + ffEncode.Speed = "veryslow"; + //ffEncode.Encoder = "Nvid; + ffEncode.Codec = "av1 10BIT"; + ffEncode.PreExecute(args); + ffEncode.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + ffExecutor.PreExecute(args); + int result = ffExecutor.Execute(args); + string log = logger.ToString(); + Assert.AreEqual(1, result); + } } #endif \ No newline at end of file