From a813bfbe747fcd6bde0e3fc640a187509498a4b4 Mon Sep 17 00:00:00 2001 From: John Andrews Date: Tue, 3 Oct 2023 15:03:41 +1300 Subject: [PATCH] FF-1127 - added bitrate per channel and updated bitrate on added audio tracks --- AudioNodes/Nodes/ConvertNode.cs | 6 +- .../Audio/FfmpegBuilderAudioAddTrack.cs | 61 ++++++++++++++++--- .../Video/FfmpegBuilderVideoBitrate.cs | 6 +- VideoNodes/VideoNodes.en.json | 4 +- VideoNodes/VideoNodes/VideoNode.cs | 12 ++-- 5 files changed, 68 insertions(+), 21 deletions(-) diff --git a/AudioNodes/Nodes/ConvertNode.cs b/AudioNodes/Nodes/ConvertNode.cs index 68b07a75..ec92497d 100644 --- a/AudioNodes/Nodes/ConvertNode.cs +++ b/AudioNodes/Nodes/ConvertNode.cs @@ -119,10 +119,10 @@ namespace FileFlows.AudioNodes return 2; } - args.Logger?.ILog($"Comparing bitrate {AudioInfo.Bitrate} is less than or equal to {(Bitrate * 1024)}"); - if(AudioInfo.Bitrate <= Bitrate * 1024) // this bitrate is in Kbps, whereas AudioInfo.Bitrate is bytes per second + args.Logger?.ILog($"Comparing bitrate {AudioInfo.Bitrate} is less than or equal to {(Bitrate * 1000)}"); + if(AudioInfo.Bitrate <= Bitrate * 1000) // this bitrate is in Kbps, whereas AudioInfo.Bitrate is bytes per second { - args.Logger?.ILog($"Audio file already '{Codec}' at bitrate '{AudioInfo.Bitrate} bps ({(AudioInfo.Bitrate / 1024)} KiBps)'"); + args.Logger?.ILog($"Audio file already '{Codec}' at bitrate '{AudioInfo.Bitrate} bps ({(AudioInfo.Bitrate / 1000)} KBps)'"); return 2; } } diff --git a/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioAddTrack.cs b/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioAddTrack.cs index ba6f37fc..d13e23a7 100644 --- a/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioAddTrack.cs +++ b/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioAddTrack.cs @@ -1,4 +1,6 @@ -using FileFlows.VideoNodes.FfmpegBuilderNodes.Models; +using System.Diagnostics; +using System.Runtime.InteropServices; +using FileFlows.VideoNodes.FfmpegBuilderNodes.Models; namespace FileFlows.VideoNodes.FfmpegBuilderNodes; @@ -85,6 +87,12 @@ public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode /// [Select(nameof(BitrateOptions), 3)] public int Bitrate { get; set; } + + /// + /// Gets or sets if the bitrate specified should be per channel + /// + [Boolean(4)] + public bool BitratePerChannel { get; set; } private static List _BitrateOptions; /// @@ -115,7 +123,7 @@ public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode /// Gets or sets the sample rate /// [DefaultValue(0)] - [Select(nameof(SampleRateOptions), 4)] + [Select(nameof(SampleRateOptions), 5)] public int SampleRate { get; set; } private static List _SampleRateOptions; @@ -148,17 +156,17 @@ public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode /// Gets or sets the language of the new track /// [DefaultValue("eng")] - [TextVariable(5)] + [TextVariable(6)] public string Language { get; set; } /// /// Gets or sets if the title of the new track should be removed /// - [Boolean(6)] + [Boolean(7)] public bool RemoveTitle { get; set; } /// /// Gets or sets the title of the new track /// - [TextVariable(7)] + [TextVariable(8)] [ConditionEquals(nameof(RemoveTitle), false)] public string NewTitle { get; set; } @@ -189,7 +197,7 @@ public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode bool directCopy = false; if(bestAudio.Codec.ToLower() == this.Codec.ToLower()) { - if(this.Channels == 0 || this.Channels == bestAudio.Channels) + if((Channels == 0 || Channels == bestAudio.Channels) && Bitrate <= 2) { directCopy = true; } @@ -202,7 +210,19 @@ public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode else { int sampleRate = SampleRate == 1 ? audio.Stream.SampleRate : SampleRate; - audio.EncodingParameters.AddRange(GetNewAudioTrackParameters(args, audio, Codec, Channels, Bitrate, sampleRate)); + + int bitrate = Bitrate; + if (BitratePerChannel) + { + int totalChannels = GetAudioBitrateChannels(audio); + args.Logger?.ILog("Total channels: " + totalChannels); + args.Logger?.ILog("Bitrate Per Channel: " + bitrate); + + bitrate = totalChannels * bitrate; + args.Logger?.ILog("Total Bitrate: " + bitrate); + } + + audio.EncodingParameters.AddRange(GetNewAudioTrackParameters(args, audio, Codec, Channels, bitrate, sampleRate)); if (this.Channels > 0) audio.Channels = this.Channels; } @@ -220,6 +240,27 @@ public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode return 1; } + /// + /// Gets how many channels there are including sub channels, eg. 5.1 is 6 channels + /// + /// the audio track + /// the number of channels for the bitrate calculation + private int GetAudioBitrateChannels(FfmpegAudioStream audio) + { + float channels = (Channels > 0 ? Channels : audio.Channels); + + // Check if there are any decimal parts in the channels + float decimalPart = channels - (int)channels; + + // Calculate the additional channels based on the decimal part + int additionalChannels = (int)(decimalPart * 10); + + // Total channels including sub-channels + int totalChannels = (int)channels + additionalChannels; + + return totalChannels; + } + /// /// Gets the best audio track /// @@ -353,12 +394,16 @@ public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode { options.Add("-b:a:{index}"); options.Add((stream.Stream.Bitrate / 1000) + "k"); + options.Add("-metadata:s:a:{index}"); + options.Add($"BPS={stream.Stream.Bitrate}"); } } else if (bitrate > 0) { options.Add("-b:a:{index}"); options.Add(bitrate + "k"); + options.Add("-metadata:s:a:{index}"); + options.Add($"BPS={bitrate * 1000}"); } // Handle sample rate @@ -368,7 +413,7 @@ public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode options.Add(sampleRate.ToString()); } - args.Logger.ILog("New Audo Arguments: " + string.Join(" ", options)); + args.Logger.ILog("New Audio Arguments: " + string.Join(" ", options)); return options.ToArray(); } diff --git a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoBitrate.cs b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoBitrate.cs index f6999b58..3ee39155 100644 --- a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoBitrate.cs +++ b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoBitrate.cs @@ -28,14 +28,14 @@ public class FfmpegBuilderVideoBitrate : FfmpegBuilderNode args.Logger?.ELog("Minimum birate not set"); return -1; } - float currentBitrate = (int)(video.Stream.Bitrate / 1024f); + float currentBitrate = (int)(video.Stream.Bitrate / 1000f); if (currentBitrate <= 0 && Model.VideoInfo.Bitrate > 0) - currentBitrate = (int)(Model.VideoInfo.Bitrate/ 1024f); + currentBitrate = (int)(Model.VideoInfo.Bitrate/ 1000f); if (currentBitrate <= 0) { // need to work it out currentBitrate = args.WorkingFileSize; - //currentBitrate /= 1024f; + //currentBitrate /= 1000f; currentBitrate = (float)(currentBitrate / video.Stream.Duration.TotalSeconds); // rough estimate of 75% of the file is video currentBitrate *= 0.75f; diff --git a/VideoNodes/VideoNodes.en.json b/VideoNodes/VideoNodes.en.json index 994b1210..130db0d8 100644 --- a/VideoNodes/VideoNodes.en.json +++ b/VideoNodes/VideoNodes.en.json @@ -130,7 +130,9 @@ "NewTitle": "New Title", "NewTitle-Help": "Optional title for the newly created audio track. If left blank the source title will be used", "RemoveTitle": "Remove Title", - "RemoveTitle-Help": "If the source title should be removed and the track should have no title" + "RemoveTitle-Help": "If the source title should be removed and the track should have no title", + "BitratePerChannel": "Bitrate Per Channel", + "BitratePerChannel-Help": "If the bitrate specified should be per channel" } }, "FfmpegBuilderAudioAdjustVolume": { diff --git a/VideoNodes/VideoNodes/VideoNode.cs b/VideoNodes/VideoNodes/VideoNode.cs index 83d04479..0f1f5b5f 100644 --- a/VideoNodes/VideoNodes/VideoNode.cs +++ b/VideoNodes/VideoNodes/VideoNode.cs @@ -142,14 +142,14 @@ namespace FileFlows.VideoNodes if (stream.Bitrate > 0) metadata.Add(prefix + "Bitrate", stream.Bitrate); } - foreach (var (strream, i) in videoInfo.SubtitleStreams.Select((value, i) => (value, i))) + foreach (var (stream, i) in videoInfo.SubtitleStreams.Select((value, i) => (value, i))) { string prefix = "Subtitle" + (i == 0 ? "" : " " + (i + 1)) + " "; - metadata.Add(prefix + "Codec", strream.Codec); - if (string.IsNullOrEmpty(strream.Title) == false) - metadata.Add(prefix + "Title", strream.Title); - if (string.IsNullOrEmpty(strream.Language) == false) - metadata.Add(prefix + "Language", strream.Language); + metadata.Add(prefix + "Codec", stream.Codec); + if (string.IsNullOrEmpty(stream.Title) == false) + metadata.Add(prefix + "Title", stream.Title); + if (string.IsNullOrEmpty(stream.Language) == false) + metadata.Add(prefix + "Language", stream.Language); } args.SetMetadata(metadata); }