From adb5e784523f1b767ad3cf6c168c08dad50df7ba Mon Sep 17 00:00:00 2001 From: John Andrews Date: Thu, 27 Jul 2023 16:34:47 +1200 Subject: [PATCH] FF-1036 - High efficiency --- AudioNodes/AudioNodes.en.json | 4 +- AudioNodes/Nodes/ConvertNode.cs | 277 ++++++++++--------------------- AudioNodes/Tests/ConvertTests.cs | 36 ++-- 3 files changed, 118 insertions(+), 199 deletions(-) diff --git a/AudioNodes/AudioNodes.en.json b/AudioNodes/AudioNodes.en.json index 01cab891..348445e3 100644 --- a/AudioNodes/AudioNodes.en.json +++ b/AudioNodes/AudioNodes.en.json @@ -39,7 +39,9 @@ }, "Fields": { "Bitrate": "Bitrate", - "Bitrate-Help": "The bitrate for the new AAC file, the higher the bitrate the better the quality but larger the file. 192 Kbps is the recommended rate." + "Bitrate-Help": "The bitrate for the new AAC file, the higher the bitrate the better the quality but larger the file. 192 Kbps is the recommended rate.", + "HighEfficiency": "High Efficiency", + "HighEfficiency-Help": "Will use high efficiency mode, this will change the extension to m4a and will reduce supported playback devices, but may reduce the size of the file." } }, "ConvertToFLAC": { diff --git a/AudioNodes/Nodes/ConvertNode.cs b/AudioNodes/Nodes/ConvertNode.cs index 17d1f8ec..68b07a75 100644 --- a/AudioNodes/Nodes/ConvertNode.cs +++ b/AudioNodes/Nodes/ConvertNode.cs @@ -1,6 +1,5 @@ using FileFlows.Plugin; using FileFlows.Plugin.Attributes; -using TagLib.Gif; namespace FileFlows.AudioNodes { @@ -8,27 +7,6 @@ namespace FileFlows.AudioNodes { public override string HelpUrl => "https://fileflows.com/docs/plugins/audio-nodes/convert-to-mp3"; protected override string Extension => "mp3"; - public static List BitrateOptions => ConvertNode.BitrateOptions; - protected override List GetArguments(NodeParameters args, out string? extension) - { - extension = null; - if (Bitrate == 0) - { - // automatic - return new List - { - "-c:a", - "mp3" - }; - } - return new List - { - "-c:a", - "mp3", - "-ab", - (Bitrate == -1 ? GetSourceBitrate(args).ToString() : Bitrate + "k") - }; - } } public class ConvertToWAV : ConvertNode { @@ -36,7 +14,6 @@ namespace FileFlows.AudioNodes protected override string Extension => "wav"; private static List _BitrateOptions; - public new static List BitrateOptions { get @@ -61,111 +38,28 @@ namespace FileFlows.AudioNodes return _BitrateOptions; } } - - protected override List GetArguments(NodeParameters args, out string? extension) - { - extension = null; - if (Bitrate == 0) - { - // automatic - return new List - { - "-c:a", - "pcm_s16le" - }; - } - return new List - { - "-c:a", - "pcm_s16le", - "-ab", - (Bitrate == -1 ? GetSourceBitrate(args).ToString() : Bitrate + "k") - }; - } } public class ConvertToAAC : ConvertNode { public override string HelpUrl => "https://fileflows.com/docs/plugins/audio-nodes/convert-to-aac"; protected override string Extension => "aac"; - public static List BitrateOptions => ConvertNode.BitrateOptions; + /// + /// Gets or sets if high efficiency should be used + /// + [Boolean(5)] + public bool HighEfficiency { get => base.HighEfficiency; set =>base.HighEfficiency = value; } + protected override bool SetId3Tags => true; - - protected override List GetArguments(NodeParameters args, out string? extension) - { - extension = null; - if (Bitrate == 0) - { - // automatic - return new List - { - "-c:a", - "aac" - }; - } - return new List - { - "-c:a", - "aac", - "-ab", - (Bitrate == -1 ? GetSourceBitrate(args).ToString() : Bitrate + "k") - }; - } } public class ConvertToOGG: ConvertNode { public override string HelpUrl => "https://fileflows.com/docs/plugins/audio-nodes/convert-to-ogg"; protected override string Extension => "ogg"; public static List BitrateOptions => ConvertNode.BitrateOptions; - protected override List GetArguments(NodeParameters args, out string? extension) - { - extension = null; - if (Bitrate == 0) - { - // automatic - return new List - { - "-c:a", - "libvorbis" - }; - } - return new List - { - "-c:a", - "libvorbis", - "-ab", - (Bitrate == -1 ? GetSourceBitrate(args).ToString() : Bitrate + "k") - }; - } } - //public class ConvertToFLAC : ConvertNode - //{ - // protected override string Extension => "flac"; - // public static List BitrateOptions => ConvertNode.BitrateOptions; - // protected override List GetArguments() - // { - // if (Bitrate == 0) - // { - // // automatic - // return new List - // { - // "-c:a", - // "c:a", - // // "flac" - // }; - // } - // return new List - // { - // "-c:a", - // "flac", - // "-ab", - // Bitrate + "k" - // }; - // } - //} - public class ConvertAudio : ConvertNode { protected override string Extension => Codec; @@ -185,7 +79,7 @@ namespace FileFlows.AudioNodes /// [Boolean(5)] [ConditionEquals(nameof(Codec), "aac")] - public bool HighEfficiency { get; set; } + public bool HighEfficiency { get => base.HighEfficiency; set =>base.HighEfficiency = value; } public override int Outputs => 2; private static List _CodecOptions; @@ -207,70 +101,6 @@ namespace FileFlows.AudioNodes } } - protected override List GetArguments(NodeParameters args, out string? extension) - { - extension = null; - string codec = Codec switch - { - "ogg" => "libvorbis", - "wav" => "pcm_s16le", - _ => Codec.ToLower() - }; - - int bitrate = Bitrate; - if (Codec.ToLowerInvariant() == "mp3" || Codec.ToLowerInvariant() == "ogg" || Codec.ToLowerInvariant() == "aac") - { - if (bitrate is >= 10 and <= 20) - { - bitrate = (Bitrate - 10); - if (Codec.ToLowerInvariant() == "mp3") - { - // ogg is reversed - bitrate = 10 - bitrate; - } - - args.Logger?.ILog($"Using variable bitrate setting '{bitrate}' for codec '{Codec}'"); - - var results = new List - { - "-c:a", - codec, - "-qscale:a", - bitrate.ToString() - }; - if (Codec == "aac" && HighEfficiency) - { - extension = "m4a"; - results.AddRange(new[] { "-profile:a", "aac_he_v2" }); - } - - return results; - } - } - else if(bitrate is > 10 and <= 20) - { - throw new Exception("Variable bitrate not supported in codec: " + Codec); - } - - if (bitrate == 0) - { - // automatic - return new List - { - "-c:a", - codec - }; - } - - return new List - { - "-c:a", - codec, - "-ab", - (bitrate == -1 ? GetSourceBitrate(args).ToString() : bitrate + "k") - }; - } - public override int Execute(NodeParameters args) { AudioInfo AudioInfo = GetAudioInfo(args); @@ -304,6 +134,10 @@ namespace FileFlows.AudioNodes public abstract class ConvertNode:AudioNode { protected abstract string Extension { get; } + /// + /// Gets or sets if using high efficiency + /// + protected bool HighEfficiency { get; set; } protected long GetSourceBitrate(NodeParameters args) { @@ -318,23 +152,96 @@ namespace FileFlows.AudioNodes protected virtual List GetArguments(NodeParameters args, out string? extension) { + string Codec = Extension; extension = null; - if (Bitrate == 0) + string codecKey = Codec + "_codec"; + string codec = args.GetToolPathActual(codecKey); + if (codec == "mp3") + extension = "mp3"; + if (codec == "libvorbis" || codec == "ogg") + { + codec = "libvorbis"; + extension = "ogg"; + } + + if (codec == codecKey || string.IsNullOrWhiteSpace(codec)) + { + codec = Codec switch + { + "ogg" => "libvorbis", + "wav" => "pcm_s16le", + _ => Codec.ToLower() + }; + } + + int bitrate = Bitrate; + if (Codec.ToLowerInvariant() == "mp3" || Codec.ToLowerInvariant() == "ogg" || Codec.ToLowerInvariant() == "aac") + { + if (bitrate is >= 10 and <= 20) + { + bitrate = (Bitrate - 10); + if (Codec.ToLowerInvariant() == "mp3") + { + // ogg is reversed + bitrate = 10 - bitrate; + } + + + args.Logger?.ILog($"Using variable bitrate setting '{bitrate}' for codec '{Codec}'"); + + List results; + + if (codec == "libfdk_aac") + { + results = new() + { + "-c:a", + codec, + "-vbr", + Math.Min(Math.Max(1, bitrate / 2), 5).ToString() + }; + } + else + { + results = new() + { + "-c:a", + codec, + "-qscale:a", + bitrate.ToString() + }; + } + + if (Codec == "aac" && HighEfficiency) + { + extension = "m4a"; + results.AddRange(new[] { "-profile:a", "aac_he_v2" }); + } + + return results; + } + } + else if(bitrate is > 10 and <= 20) + { + throw new Exception("Variable bitrate not supported in codec: " + Codec); + } + + if (bitrate == 0) { // automatic return new List { - "-map_metadata", - "0:0" + "-c:a", + codec }; } - + return new List { - "-map_metadata", - "0:0", + "-c:a", + codec, "-ab", - (Bitrate == -1 ? GetSourceBitrate(args).ToString() : Bitrate + "k") + (bitrate == -1 ? GetSourceBitrate(args).ToString() : bitrate + "k") }; } @@ -405,8 +312,6 @@ namespace FileFlows.AudioNodes // } - - var ffArgs = GetArguments(args, out string extension); string outputFile = Path.Combine(args.TempPath, Guid.NewGuid().ToString() + "." + (extension?.EmptyAsNull() ?? Extension)); diff --git a/AudioNodes/Tests/ConvertTests.cs b/AudioNodes/Tests/ConvertTests.cs index 0a6cff9f..b964b96f 100644 --- a/AudioNodes/Tests/ConvertTests.cs +++ b/AudioNodes/Tests/ConvertTests.cs @@ -19,19 +19,31 @@ namespace FileFlows.AudioNodes.Tests { const string file = @"/home/john/Music/Aquarium (1997)/Aqua - Aquarium - 03 - Barbie Girl.flac"; - var logger = new TestLogger(); - ConvertAudio node = new (); - node.Codec = "aac"; - node.Bitrate = 10; - node.HighEfficiency = true; - var args = new FileFlows.Plugin.NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => @"/usr/bin/ffmpeg"; - args.TempPath = @"/home/john/temp"; - new AudioFile().Execute(args); // need to read the Audio info and set it - int output = node.Execute(args); + foreach (var codec in new[] { "aac", "ogg", "MP3" }) + { + foreach (int quality in new[] { 0, 10 }) + { + var logger = new TestLogger(); + ConvertAudio node = new(); + node.Codec = codec; + node.Bitrate = quality + 10; + node.HighEfficiency = true; + var args = new FileFlows.Plugin.NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => + { + if(tool.ToLowerInvariant().Contains("ffmpeg")) return @"/usr/bin/ffmpeg"; + return tool; + }; + args.TempPath = @"/home/john/temp"; + new AudioFile().Execute(args); // need to read the Audio info and set it + int output = node.Execute(args); - var log = logger.ToString(); - Assert.AreEqual(1, output); + var log = logger.ToString(); + Assert.AreEqual(1, output); + var fi = new FileInfo(args.WorkingFile); + File.Move(args.WorkingFile, Path.Combine(fi.DirectoryName, quality + fi.Extension), true); + } + } } [TestMethod]