From 0a1a109b2e9503213debdc8445910cb4c93ae382 Mon Sep 17 00:00:00 2001 From: gnattu Date: Tue, 30 Jul 2024 23:50:22 +0800 Subject: Add RFC7845 downmix algorithm (#12300) --- .../MediaEncoding/DownMixAlgorithmsHelper.cs | 65 ++++++++++++++++++++++ .../MediaEncoding/EncodingHelper.cs | 28 ++++------ 2 files changed, 75 insertions(+), 18 deletions(-) create mode 100644 MediaBrowser.Controller/MediaEncoding/DownMixAlgorithmsHelper.cs (limited to 'MediaBrowser.Controller/MediaEncoding') diff --git a/MediaBrowser.Controller/MediaEncoding/DownMixAlgorithmsHelper.cs b/MediaBrowser.Controller/MediaEncoding/DownMixAlgorithmsHelper.cs new file mode 100644 index 0000000000..b90f9a4793 --- /dev/null +++ b/MediaBrowser.Controller/MediaEncoding/DownMixAlgorithmsHelper.cs @@ -0,0 +1,65 @@ +using System.Collections.Generic; +using MediaBrowser.Model.Entities; + +namespace MediaBrowser.Controller.MediaEncoding; + +/// +/// Describes the downmix algorithms capabilities. +/// +public static class DownMixAlgorithmsHelper +{ + /// + /// The filter string of the DownMixStereoAlgorithms. + /// The index is the tuple of (algorithm, layout). + /// + public static readonly Dictionary<(DownMixStereoAlgorithms, string), string> AlgorithmFilterStrings = new() + { + { (DownMixStereoAlgorithms.Dave750, "5.1"), "pan=stereo|c0=0.5*c2+0.707*c0+0.707*c4+0.5*c3|c1=0.5*c2+0.707*c1+0.707*c5+0.5*c3" }, + { (DownMixStereoAlgorithms.NightmodeDialogue, "5.1"), "pan=stereo|c0=c2+0.30*c0+0.30*c4|c1=c2+0.30*c1+0.30*c5" }, + { (DownMixStereoAlgorithms.Rfc7845, "3.0"), "pan=stereo|c0=0.414214*c2+0.585786*c0|c1=0.414214*c2+0.585786*c1" }, + { (DownMixStereoAlgorithms.Rfc7845, "quad"), "pan=stereo|c0=0.422650*c0+0.366025*c2+0.211325*c3|c1=0.422650*c1+0.366025*c3+0.211325*c2" }, + { (DownMixStereoAlgorithms.Rfc7845, "5.0"), "pan=stereo|c0=0.460186*c2+0.650802*c0+0.563611*c3+0.325401*c4|c1=0.460186*c2+0.650802*c1+0.563611*c4+0.325401*c3" }, + { (DownMixStereoAlgorithms.Rfc7845, "5.1"), "pan=stereo|c0=0.374107*c2+0.529067*c0+0.458186*c4+0.264534*c5+0.374107*c3|c1=0.374107*c2+0.529067*c1+0.458186*c5+0.264534*c4+0.374107*c3" }, + { (DownMixStereoAlgorithms.Rfc7845, "6.1"), "pan=stereo|c0=0.321953*c2+0.455310*c0+0.394310*c5+0.227655*c6+0.278819*c4+0.321953*c3|c1=0.321953*c2+0.455310*c1+0.394310*c6+0.227655*c5+0.278819*c4+0.321953*c3" }, + { (DownMixStereoAlgorithms.Rfc7845, "7.1"), "pan=stereo|c0=0.274804*c2+0.388631*c0+0.336565*c6+0.194316*c7+0.336565*c4+0.194316*c5+0.274804*c3|c1=0.274804*c2+0.388631*c1+0.336565*c7+0.194316*c6+0.336565*c5+0.194316*c4+0.274804*c3" }, + }; + + /// + /// Get the audio channel layout string from the audio stream + /// If the input audio string does not have a valid layout string, guess from channel count. + /// + /// The audio stream to get layout. + /// Channel Layout string. + public static string InferChannelLayout(MediaStream audioStream) + { + if (!string.IsNullOrWhiteSpace(audioStream.ChannelLayout)) + { + // Note: BDMVs do not derive this string from ffmpeg, which would cause ambiguity with 4-channel audio + // "quad" => 2 front and 2 rear, "4.0" => 3 front and 1 rear + // BDMV will always use "4.0" in this case + // Because the quad layout is super rare in BDs, we will use "4.0" as is here + return audioStream.ChannelLayout; + } + + if (audioStream.Channels is null) + { + return string.Empty; + } + + // When we don't have definitive channel layout, we have to guess from the channel count + // Guessing is not always correct, but for most videos we don't have to guess like this as the definitive layout is recorded during scan + var inferredLayout = audioStream.Channels.Value switch + { + 1 => "mono", + 2 => "stereo", + 3 => "2.1", // Could also be 3.0, prefer 2.1 + 4 => "4.0", // Could also be quad (with rear left and rear right) and 3.1 with LFE. prefer 4.0 with front center and back center + 5 => "5.0", + 6 => "5.1", // Could also be 6.0 or hexagonal, prefer 5.1 + 7 => "6.1", // Could also be 7.0, prefer 6.1 + 8 => "7.1", // Could also be 8.0, prefer 7.1 + _ => string.Empty // Return empty string for not supported layout + }; + return inferredLayout; + } +} diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 42b09a29e7..2c3d44bf83 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -2666,28 +2666,17 @@ namespace MediaBrowser.Controller.MediaEncoding var filters = new List(); - if (channels.HasValue - && channels.Value == 2 - && state.AudioStream is not null - && state.AudioStream.Channels.HasValue - && state.AudioStream.Channels.Value == 6) + if (channels is 2 && state.AudioStream?.Channels is > 2) { - if (!encodingOptions.DownMixAudioBoost.Equals(1)) + var hasDownMixFilter = DownMixAlgorithmsHelper.AlgorithmFilterStrings.TryGetValue((encodingOptions.DownMixStereoAlgorithm, DownMixAlgorithmsHelper.InferChannelLayout(state.AudioStream)), out var downMixFilterString); + if (hasDownMixFilter) { - filters.Add("volume=" + encodingOptions.DownMixAudioBoost.ToString(CultureInfo.InvariantCulture)); + filters.Add(downMixFilterString); } - switch (encodingOptions.DownMixStereoAlgorithm) + if (!encodingOptions.DownMixAudioBoost.Equals(1)) { - case DownMixStereoAlgorithms.Dave750: - filters.Add("pan=stereo|c0=0.5*c2+0.707*c0+0.707*c4+0.5*c3|c1=0.5*c2+0.707*c1+0.707*c5+0.5*c3"); - break; - case DownMixStereoAlgorithms.NightmodeDialogue: - filters.Add("pan=stereo|c0=c2+0.30*c0+0.30*c4|c1=c2+0.30*c1+0.30*c5"); - break; - case DownMixStereoAlgorithms.None: - default: - break; + filters.Add("volume=" + encodingOptions.DownMixAudioBoost.ToString(CultureInfo.InvariantCulture)); } } @@ -7008,7 +6997,10 @@ namespace MediaBrowser.Controller.MediaEncoding var channels = state.OutputAudioChannels; - if (channels.HasValue && ((channels.Value != 2 && state.AudioStream?.Channels != 6) || encodingOptions.DownMixStereoAlgorithm == DownMixStereoAlgorithms.None)) + var useDownMixAlgorithm = state.AudioStream is not null + && DownMixAlgorithmsHelper.AlgorithmFilterStrings.ContainsKey((encodingOptions.DownMixStereoAlgorithm, DownMixAlgorithmsHelper.InferChannelLayout(state.AudioStream))); + + if (channels.HasValue && !useDownMixAlgorithm) { args += " -ac " + channels.Value; } -- cgit v1.2.3 From daf8d649f2bcadddabb2293fdadee9df436e7bf1 Mon Sep 17 00:00:00 2001 From: gnattu Date: Mon, 29 Jul 2024 06:19:04 +0800 Subject: Add AC4 downmix Signed-off-by: gnattu --- .../MediaEncoding/DownMixAlgorithmsHelper.cs | 5 +++++ MediaBrowser.Model/Entities/DownMixStereoAlgorithms.cs | 13 ++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) (limited to 'MediaBrowser.Controller/MediaEncoding') diff --git a/MediaBrowser.Controller/MediaEncoding/DownMixAlgorithmsHelper.cs b/MediaBrowser.Controller/MediaEncoding/DownMixAlgorithmsHelper.cs index b90f9a4793..5d253184a7 100644 --- a/MediaBrowser.Controller/MediaEncoding/DownMixAlgorithmsHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/DownMixAlgorithmsHelper.cs @@ -15,13 +15,18 @@ public static class DownMixAlgorithmsHelper public static readonly Dictionary<(DownMixStereoAlgorithms, string), string> AlgorithmFilterStrings = new() { { (DownMixStereoAlgorithms.Dave750, "5.1"), "pan=stereo|c0=0.5*c2+0.707*c0+0.707*c4+0.5*c3|c1=0.5*c2+0.707*c1+0.707*c5+0.5*c3" }, + { (DownMixStereoAlgorithms.Dave750, "7.1"), "pan=5.1(side)|c0=c0|c1=c1|c2=c2|c3=c3|c4=0.707*c4+0.707*c6|c5=0.707*c5+0.707*c7,pan=stereo|c0=0.5*c2+0.707*c0+0.707*c4+0.5*c3|c1=0.5*c2+0.707*c1+0.707*c5+0.5*c3" }, { (DownMixStereoAlgorithms.NightmodeDialogue, "5.1"), "pan=stereo|c0=c2+0.30*c0+0.30*c4|c1=c2+0.30*c1+0.30*c5" }, + { (DownMixStereoAlgorithms.NightmodeDialogue, "7.1"), "pan=5.1(side)|c0=c0|c1=c1|c2=c2|c3=c3|c4=0.707*c4+0.707*c6|c5=0.707*c5+0.707*c7,pan=stereo|c0=c2+0.30*c0+0.30*c4|c1=c2+0.30*c1+0.30*c5" }, { (DownMixStereoAlgorithms.Rfc7845, "3.0"), "pan=stereo|c0=0.414214*c2+0.585786*c0|c1=0.414214*c2+0.585786*c1" }, { (DownMixStereoAlgorithms.Rfc7845, "quad"), "pan=stereo|c0=0.422650*c0+0.366025*c2+0.211325*c3|c1=0.422650*c1+0.366025*c3+0.211325*c2" }, { (DownMixStereoAlgorithms.Rfc7845, "5.0"), "pan=stereo|c0=0.460186*c2+0.650802*c0+0.563611*c3+0.325401*c4|c1=0.460186*c2+0.650802*c1+0.563611*c4+0.325401*c3" }, { (DownMixStereoAlgorithms.Rfc7845, "5.1"), "pan=stereo|c0=0.374107*c2+0.529067*c0+0.458186*c4+0.264534*c5+0.374107*c3|c1=0.374107*c2+0.529067*c1+0.458186*c5+0.264534*c4+0.374107*c3" }, { (DownMixStereoAlgorithms.Rfc7845, "6.1"), "pan=stereo|c0=0.321953*c2+0.455310*c0+0.394310*c5+0.227655*c6+0.278819*c4+0.321953*c3|c1=0.321953*c2+0.455310*c1+0.394310*c6+0.227655*c5+0.278819*c4+0.321953*c3" }, { (DownMixStereoAlgorithms.Rfc7845, "7.1"), "pan=stereo|c0=0.274804*c2+0.388631*c0+0.336565*c6+0.194316*c7+0.336565*c4+0.194316*c5+0.274804*c3|c1=0.274804*c2+0.388631*c1+0.336565*c7+0.194316*c6+0.336565*c5+0.194316*c4+0.274804*c3" }, + { (DownMixStereoAlgorithms.Ac4, "3.0"), "pan=stereo|c0=c0+0.707*c2|c1=c1+0.707*c2"}, + { (DownMixStereoAlgorithms.Ac4, "5.1"), "pan=stereo|c0=c0+0.707*c2+0.707*c4|c1=c1+0.707*c2+0.707*c5"}, + { (DownMixStereoAlgorithms.Ac4, "7.1"), "pan=5.1(side)|c0=c0|c1=c1|c2=c2|c3=c3|c4=0.707*c4+0.707*c6|c5=0.707*c5+0.707*c7,pan=stereo|c0=c0+0.707*c2+0.707*c4|c1=c1+0.707*c2+0.707*c5"}, }; /// diff --git a/MediaBrowser.Model/Entities/DownMixStereoAlgorithms.cs b/MediaBrowser.Model/Entities/DownMixStereoAlgorithms.cs index be43ef32d3..dcb2c802d9 100644 --- a/MediaBrowser.Model/Entities/DownMixStereoAlgorithms.cs +++ b/MediaBrowser.Model/Entities/DownMixStereoAlgorithms.cs @@ -1,8 +1,7 @@ namespace MediaBrowser.Model.Entities; /// -/// An enum representing an algorithm to downmix 6ch+ to stereo. -/// Algorithms sourced from https://superuser.com/questions/852400/properly-downmix-5-1-to-stereo-using-ffmpeg/1410620#1410620. +/// An enum representing an algorithm to downmix surround sound to stereo. /// public enum DownMixStereoAlgorithms { @@ -13,16 +12,24 @@ public enum DownMixStereoAlgorithms /// /// Algorithm by Dave_750. + /// Sourced from https://superuser.com/questions/852400/properly-downmix-5-1-to-stereo-using-ffmpeg/1410620#1410620. /// Dave750 = 1, /// /// Nightmode Dialogue algorithm. + /// Sourced from https://superuser.com/questions/852400/properly-downmix-5-1-to-stereo-using-ffmpeg/1410620#1410620. /// NightmodeDialogue = 2, /// /// RFC7845 Section 5.1.1.5 defined algorithm. /// - Rfc7845 = 3 + Rfc7845 = 3, + + /// + /// AC-4 standard algorithm with its default gain values. + /// Defined in ETSI TS 103 190 Section 6.2.17 + /// + Ac4 = 4 } -- cgit v1.2.3 From 31dccaca0f8d3d924756286af54c70101155cffb Mon Sep 17 00:00:00 2001 From: gnattu Date: Mon, 29 Jul 2024 10:04:44 +0800 Subject: Add 5.0 and 7.0 support to ac4 downmix Signed-off-by: gnattu --- MediaBrowser.Controller/MediaEncoding/DownMixAlgorithmsHelper.cs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'MediaBrowser.Controller/MediaEncoding') diff --git a/MediaBrowser.Controller/MediaEncoding/DownMixAlgorithmsHelper.cs b/MediaBrowser.Controller/MediaEncoding/DownMixAlgorithmsHelper.cs index 5d253184a7..7583961e96 100644 --- a/MediaBrowser.Controller/MediaEncoding/DownMixAlgorithmsHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/DownMixAlgorithmsHelper.cs @@ -25,7 +25,9 @@ public static class DownMixAlgorithmsHelper { (DownMixStereoAlgorithms.Rfc7845, "6.1"), "pan=stereo|c0=0.321953*c2+0.455310*c0+0.394310*c5+0.227655*c6+0.278819*c4+0.321953*c3|c1=0.321953*c2+0.455310*c1+0.394310*c6+0.227655*c5+0.278819*c4+0.321953*c3" }, { (DownMixStereoAlgorithms.Rfc7845, "7.1"), "pan=stereo|c0=0.274804*c2+0.388631*c0+0.336565*c6+0.194316*c7+0.336565*c4+0.194316*c5+0.274804*c3|c1=0.274804*c2+0.388631*c1+0.336565*c7+0.194316*c6+0.336565*c5+0.194316*c4+0.274804*c3" }, { (DownMixStereoAlgorithms.Ac4, "3.0"), "pan=stereo|c0=c0+0.707*c2|c1=c1+0.707*c2"}, + { (DownMixStereoAlgorithms.Ac4, "5.0"), "pan=stereo|c0=c0+0.707*c2+0.707*c3|c1=c1+0.707*c2+0.707*c4"}, { (DownMixStereoAlgorithms.Ac4, "5.1"), "pan=stereo|c0=c0+0.707*c2+0.707*c4|c1=c1+0.707*c2+0.707*c5"}, + { (DownMixStereoAlgorithms.Ac4, "7.0"), "pan=5.0(side)|c0=c0|c1=c1|c2=c2|c3=0.707*c3+0.707*c5|c4=0.707*c4+0.707*c6,pan=stereo|c0=c0+0.707*c2+0.707*c3|c1=c1+0.707*c2+0.707*c4"}, { (DownMixStereoAlgorithms.Ac4, "7.1"), "pan=5.1(side)|c0=c0|c1=c1|c2=c2|c3=c3|c4=0.707*c4+0.707*c6|c5=0.707*c5+0.707*c7,pan=stereo|c0=c0+0.707*c2+0.707*c4|c1=c1+0.707*c2+0.707*c5"}, }; -- cgit v1.2.3 From c171b6def22b32740654d7830f4ef6440854c404 Mon Sep 17 00:00:00 2001 From: gnattu Date: Mon, 29 Jul 2024 10:28:22 +0800 Subject: fix space Signed-off-by: gnattu --- .../MediaEncoding/DownMixAlgorithmsHelper.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'MediaBrowser.Controller/MediaEncoding') diff --git a/MediaBrowser.Controller/MediaEncoding/DownMixAlgorithmsHelper.cs b/MediaBrowser.Controller/MediaEncoding/DownMixAlgorithmsHelper.cs index 7583961e96..64a0f59920 100644 --- a/MediaBrowser.Controller/MediaEncoding/DownMixAlgorithmsHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/DownMixAlgorithmsHelper.cs @@ -24,11 +24,11 @@ public static class DownMixAlgorithmsHelper { (DownMixStereoAlgorithms.Rfc7845, "5.1"), "pan=stereo|c0=0.374107*c2+0.529067*c0+0.458186*c4+0.264534*c5+0.374107*c3|c1=0.374107*c2+0.529067*c1+0.458186*c5+0.264534*c4+0.374107*c3" }, { (DownMixStereoAlgorithms.Rfc7845, "6.1"), "pan=stereo|c0=0.321953*c2+0.455310*c0+0.394310*c5+0.227655*c6+0.278819*c4+0.321953*c3|c1=0.321953*c2+0.455310*c1+0.394310*c6+0.227655*c5+0.278819*c4+0.321953*c3" }, { (DownMixStereoAlgorithms.Rfc7845, "7.1"), "pan=stereo|c0=0.274804*c2+0.388631*c0+0.336565*c6+0.194316*c7+0.336565*c4+0.194316*c5+0.274804*c3|c1=0.274804*c2+0.388631*c1+0.336565*c7+0.194316*c6+0.336565*c5+0.194316*c4+0.274804*c3" }, - { (DownMixStereoAlgorithms.Ac4, "3.0"), "pan=stereo|c0=c0+0.707*c2|c1=c1+0.707*c2"}, - { (DownMixStereoAlgorithms.Ac4, "5.0"), "pan=stereo|c0=c0+0.707*c2+0.707*c3|c1=c1+0.707*c2+0.707*c4"}, - { (DownMixStereoAlgorithms.Ac4, "5.1"), "pan=stereo|c0=c0+0.707*c2+0.707*c4|c1=c1+0.707*c2+0.707*c5"}, - { (DownMixStereoAlgorithms.Ac4, "7.0"), "pan=5.0(side)|c0=c0|c1=c1|c2=c2|c3=0.707*c3+0.707*c5|c4=0.707*c4+0.707*c6,pan=stereo|c0=c0+0.707*c2+0.707*c3|c1=c1+0.707*c2+0.707*c4"}, - { (DownMixStereoAlgorithms.Ac4, "7.1"), "pan=5.1(side)|c0=c0|c1=c1|c2=c2|c3=c3|c4=0.707*c4+0.707*c6|c5=0.707*c5+0.707*c7,pan=stereo|c0=c0+0.707*c2+0.707*c4|c1=c1+0.707*c2+0.707*c5"}, + { (DownMixStereoAlgorithms.Ac4, "3.0"), "pan=stereo|c0=c0+0.707*c2|c1=c1+0.707*c2" }, + { (DownMixStereoAlgorithms.Ac4, "5.0"), "pan=stereo|c0=c0+0.707*c2+0.707*c3|c1=c1+0.707*c2+0.707*c4" }, + { (DownMixStereoAlgorithms.Ac4, "5.1"), "pan=stereo|c0=c0+0.707*c2+0.707*c4|c1=c1+0.707*c2+0.707*c5" }, + { (DownMixStereoAlgorithms.Ac4, "7.0"), "pan=5.0(side)|c0=c0|c1=c1|c2=c2|c3=0.707*c3+0.707*c5|c4=0.707*c4+0.707*c6,pan=stereo|c0=c0+0.707*c2+0.707*c3|c1=c1+0.707*c2+0.707*c4" }, + { (DownMixStereoAlgorithms.Ac4, "7.1"), "pan=5.1(side)|c0=c0|c1=c1|c2=c2|c3=c3|c4=0.707*c4+0.707*c6|c5=0.707*c5+0.707*c7,pan=stereo|c0=c0+0.707*c2+0.707*c4|c1=c1+0.707*c2+0.707*c5" }, }; /// -- cgit v1.2.3 From 3788ccd447ffaa4638f3fe5d235c5bb92b809692 Mon Sep 17 00:00:00 2001 From: gnattu Date: Thu, 1 Aug 2024 07:45:16 +0800 Subject: Add comments for Dave750/NightmodeDialogue 7.1 downmix Signed-off-by: gnattu --- MediaBrowser.Controller/MediaEncoding/DownMixAlgorithmsHelper.cs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'MediaBrowser.Controller/MediaEncoding') diff --git a/MediaBrowser.Controller/MediaEncoding/DownMixAlgorithmsHelper.cs b/MediaBrowser.Controller/MediaEncoding/DownMixAlgorithmsHelper.cs index 64a0f59920..749f872710 100644 --- a/MediaBrowser.Controller/MediaEncoding/DownMixAlgorithmsHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/DownMixAlgorithmsHelper.cs @@ -15,8 +15,10 @@ public static class DownMixAlgorithmsHelper public static readonly Dictionary<(DownMixStereoAlgorithms, string), string> AlgorithmFilterStrings = new() { { (DownMixStereoAlgorithms.Dave750, "5.1"), "pan=stereo|c0=0.5*c2+0.707*c0+0.707*c4+0.5*c3|c1=0.5*c2+0.707*c1+0.707*c5+0.5*c3" }, + // Use AC-4 algorithm to downmix 7.1 inputs to 5.1 first { (DownMixStereoAlgorithms.Dave750, "7.1"), "pan=5.1(side)|c0=c0|c1=c1|c2=c2|c3=c3|c4=0.707*c4+0.707*c6|c5=0.707*c5+0.707*c7,pan=stereo|c0=0.5*c2+0.707*c0+0.707*c4+0.5*c3|c1=0.5*c2+0.707*c1+0.707*c5+0.5*c3" }, { (DownMixStereoAlgorithms.NightmodeDialogue, "5.1"), "pan=stereo|c0=c2+0.30*c0+0.30*c4|c1=c2+0.30*c1+0.30*c5" }, + // Use AC-4 algorithm to downmix 7.1 inputs to 5.1 first { (DownMixStereoAlgorithms.NightmodeDialogue, "7.1"), "pan=5.1(side)|c0=c0|c1=c1|c2=c2|c3=c3|c4=0.707*c4+0.707*c6|c5=0.707*c5+0.707*c7,pan=stereo|c0=c2+0.30*c0+0.30*c4|c1=c2+0.30*c1+0.30*c5" }, { (DownMixStereoAlgorithms.Rfc7845, "3.0"), "pan=stereo|c0=0.414214*c2+0.585786*c0|c1=0.414214*c2+0.585786*c1" }, { (DownMixStereoAlgorithms.Rfc7845, "quad"), "pan=stereo|c0=0.422650*c0+0.366025*c2+0.211325*c3|c1=0.422650*c1+0.366025*c3+0.211325*c2" }, -- cgit v1.2.3 From 7ea91dfcc4030892fff164d49969f6e85c8493fe Mon Sep 17 00:00:00 2001 From: gnattu Date: Mon, 5 Aug 2024 10:37:40 +0800 Subject: Update VideoToolbox pipeline for jellyfin-ffmpeg7 (#12380) --- .../MediaEncoding/EncodingHelper.cs | 31 ++++++++++++---------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'MediaBrowser.Controller/MediaEncoding') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 2c3d44bf83..bfeabebde8 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -64,6 +64,7 @@ namespace MediaBrowser.Controller.MediaEncoding private readonly Version _minFFmpegSvtAv1Params = new Version(5, 1); private readonly Version _minFFmpegVaapiH26xEncA53CcSei = new Version(6, 0); private readonly Version _minFFmpegReadrateOption = new Version(5, 0); + private readonly Version _minFFmpegWorkingVtHwSurface = new Version(7, 0, 1); private static readonly Regex _validationRegex = new(ValidationRegex, RegexOptions.Compiled); @@ -5166,12 +5167,14 @@ namespace MediaBrowser.Controller.MediaEncoding var threeDFormat = state.MediaSource.Video3DFormat; var isVtEncoder = vidEncoder.Contains("videotoolbox", StringComparison.OrdinalIgnoreCase); + var isVtDecoder = vidDecoder.Contains("videotoolbox", StringComparison.OrdinalIgnoreCase); var doDeintH264 = state.DeInterlace("h264", true) || state.DeInterlace("avc", true); var doDeintHevc = state.DeInterlace("h265", true) || state.DeInterlace("hevc", true); var doDeintH2645 = doDeintH264 || doDeintHevc; var doVtTonemap = IsVideoToolboxTonemapAvailable(state, options); var doMetalTonemap = !doVtTonemap && IsHwTonemapAvailable(state, options); + var usingHwSurface = isVtDecoder && (_mediaEncoder.EncoderVersion >= _minFFmpegWorkingVtHwSurface); var scaleFormat = string.Empty; // Use P010 for Metal tone mapping, otherwise force an 8bit output. @@ -5259,23 +5262,25 @@ namespace MediaBrowser.Controller.MediaEncoding subFilters.Add(subTextSubtitlesFilter); } - subFilters.Add("hwupload=derive_device=videotoolbox"); + subFilters.Add("hwupload"); overlayFilters.Add("overlay_videotoolbox=eof_action=pass:repeatlast=0"); } + if (usingHwSurface) + { + return (mainFilters, subFilters, overlayFilters); + } + + // For old jellyfin-ffmpeg that has broken hwsurface, add a hwupload var needFiltering = mainFilters.Any(f => !string.IsNullOrEmpty(f)) || subFilters.Any(f => !string.IsNullOrEmpty(f)) || overlayFilters.Any(f => !string.IsNullOrEmpty(f)); - - // This is a workaround for ffmpeg's hwupload implementation - // For VideoToolbox encoders, a hwupload without a valid filter actually consuming its frame - // will cause the encoder to produce incorrect frames. if (needFiltering) { // INPUT videotoolbox/memory surface(vram/uma) // this will pass-through automatically if in/out format matches. mainFilters.Insert(0, "format=nv12|p010le|videotoolbox_vld"); - mainFilters.Insert(0, "hwupload=derive_device=videotoolbox"); + mainFilters.Insert(0, "hwupload"); } return (mainFilters, subFilters, overlayFilters); @@ -6283,22 +6288,20 @@ namespace MediaBrowser.Controller.MediaEncoding || string.Equals("yuvj420p", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); var is8_10bitSwFormatsVt = is8bitSwFormatsVt || string.Equals("yuv420p10le", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); - // VideoToolbox's Hardware surface in ffmpeg is not only slower than hwupload, but also breaks HDR in many cases. - // For example: https://trac.ffmpeg.org/ticket/10884 - // Disable it for now. - const bool UseHwSurface = false; + // The related patches make videotoolbox hardware surface working is only available in jellyfin-ffmpeg 7.0.1 at the moment. + bool useHwSurface = (_mediaEncoder.EncoderVersion >= _minFFmpegWorkingVtHwSurface) && IsVideoToolboxFullSupported(); if (is8bitSwFormatsVt) { if (string.Equals("avc", videoStream.Codec, StringComparison.OrdinalIgnoreCase) || string.Equals("h264", videoStream.Codec, StringComparison.OrdinalIgnoreCase)) { - return GetHwaccelType(state, options, "h264", bitDepth, UseHwSurface); + return GetHwaccelType(state, options, "h264", bitDepth, useHwSurface); } if (string.Equals("vp8", videoStream.Codec, StringComparison.OrdinalIgnoreCase)) { - return GetHwaccelType(state, options, "vp8", bitDepth, UseHwSurface); + return GetHwaccelType(state, options, "vp8", bitDepth, useHwSurface); } } @@ -6307,12 +6310,12 @@ namespace MediaBrowser.Controller.MediaEncoding if (string.Equals("hevc", videoStream.Codec, StringComparison.OrdinalIgnoreCase) || string.Equals("h265", videoStream.Codec, StringComparison.OrdinalIgnoreCase)) { - return GetHwaccelType(state, options, "hevc", bitDepth, UseHwSurface); + return GetHwaccelType(state, options, "hevc", bitDepth, useHwSurface); } if (string.Equals("vp9", videoStream.Codec, StringComparison.OrdinalIgnoreCase)) { - return GetHwaccelType(state, options, "vp9", bitDepth, UseHwSurface); + return GetHwaccelType(state, options, "vp9", bitDepth, useHwSurface); } } -- cgit v1.2.3