Browse Source

Add stereo downmix algorithm selection.

Shadowghost 2 years ago
parent
commit
407c716f82

+ 7 - 1
Jellyfin.Api/Controllers/DynamicHlsController.cs

@@ -22,6 +22,7 @@ using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Net;
 using Microsoft.AspNetCore.Authorization;
@@ -1731,7 +1732,12 @@ namespace Jellyfin.Api.Controllers
 
             var channels = state.OutputAudioChannels;
 
-            if (channels.HasValue)
+            if (channels.HasValue
+                && (channels.Value != 2
+                    || (state.AudioStream is not null
+                        && state.AudioStream.Channels.HasValue
+                        && state.AudioStream.Channels.Value > 5
+                        && _encodingOptions.DownMixStereoAlgorithm == DownMixStereoAlgorithms.None)))
             {
                 args += " -ac " + channels.Value;
             }

+ 21 - 7
MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs

@@ -2129,15 +2129,30 @@ namespace MediaBrowser.Controller.MediaEncoding
 
             var filters = new List<string>();
 
-            // Boost volume to 200% when downsampling from 6ch to 2ch
             if (channels.HasValue
-                && channels.Value <= 2
+                && channels.Value == 2
                 && state.AudioStream is not null
                 && state.AudioStream.Channels.HasValue
-                && state.AudioStream.Channels.Value > 5
-                && !encodingOptions.DownMixAudioBoost.Equals(1))
+                && state.AudioStream.Channels.Value > 5)
             {
-                filters.Add("volume=" + encodingOptions.DownMixAudioBoost.ToString(CultureInfo.InvariantCulture));
+                switch (encodingOptions.DownMixStereoAlgorithm)
+                {
+                    case DownMixStereoAlgorithms.Dave750:
+                        filters.Add("volume=4.25");
+                        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:
+                        if (!encodingOptions.DownMixAudioBoost.Equals(1))
+                        {
+                            filters.Add("volume=" + encodingOptions.DownMixAudioBoost.ToString(CultureInfo.InvariantCulture));
+                        }
+
+                        break;
+                }
             }
 
             var isCopyingTimestamps = state.CopyTimestamps || state.TranscodingType != TranscodingJobType.Progressive;
@@ -5711,10 +5726,9 @@ namespace MediaBrowser.Controller.MediaEncoding
                 return args;
             }
 
-            // Add the number of audio channels
             var channels = state.OutputAudioChannels;
 
-            if (channels.HasValue)
+            if (channels.HasValue && ((channels.Value != 2 && state.AudioStream.Channels <= 5) || encodingOptions.DownMixStereoAlgorithm == DownMixStereoAlgorithms.None))
             {
                 args += " -ac " + channels.Value;
             }

+ 241 - 122
MediaBrowser.Model/Configuration/EncodingOptions.cs

@@ -1,128 +1,247 @@
 #nullable disable
-#pragma warning disable CS1591
+using MediaBrowser.Model.Entities;
 
-namespace MediaBrowser.Model.Configuration
+namespace MediaBrowser.Model.Configuration;
+
+/// <summary>
+/// Class EncodingOptions.
+/// </summary>
+public class EncodingOptions
 {
-    public class EncodingOptions
+    /// <summary>
+    /// Initializes a new instance of the <see cref="EncodingOptions" /> class.
+    /// </summary>
+    public EncodingOptions()
     {
-        public EncodingOptions()
-        {
-            EnableFallbackFont = false;
-            DownMixAudioBoost = 2;
-            MaxMuxingQueueSize = 2048;
-            EnableThrottling = false;
-            ThrottleDelaySeconds = 180;
-            EncodingThreadCount = -1;
-            // This is a DRM device that is almost guaranteed to be there on every intel platform,
-            // plus it's the default one in ffmpeg if you don't specify anything
-            VaapiDevice = "/dev/dri/renderD128";
-            EnableTonemapping = false;
-            EnableVppTonemapping = false;
-            TonemappingAlgorithm = "bt2390";
-            TonemappingRange = "auto";
-            TonemappingDesat = 0;
-            TonemappingThreshold = 0.8;
-            TonemappingPeak = 100;
-            TonemappingParam = 0;
-            VppTonemappingBrightness = 0;
-            VppTonemappingContrast = 1.2;
-            H264Crf = 23;
-            H265Crf = 28;
-            DeinterlaceDoubleRate = false;
-            DeinterlaceMethod = "yadif";
-            EnableDecodingColorDepth10Hevc = true;
-            EnableDecodingColorDepth10Vp9 = true;
-            EnableEnhancedNvdecDecoder = false;
-            PreferSystemNativeHwDecoder = true;
-            EnableIntelLowPowerH264HwEncoder = false;
-            EnableIntelLowPowerHevcHwEncoder = false;
-            EnableHardwareEncoding = true;
-            AllowHevcEncoding = false;
-            EnableSubtitleExtraction = true;
-            AllowOnDemandMetadataBasedKeyframeExtractionForExtensions = new[] { "mkv" };
-            HardwareDecodingCodecs = new string[] { "h264", "vc1" };
-        }
-
-        public int EncodingThreadCount { get; set; }
-
-        public string TranscodingTempPath { get; set; }
-
-        public string FallbackFontPath { get; set; }
-
-        public bool EnableFallbackFont { get; set; }
-
-        public double DownMixAudioBoost { get; set; }
-
-        public int MaxMuxingQueueSize { get; set; }
-
-        public bool EnableThrottling { get; set; }
-
-        public int ThrottleDelaySeconds { get; set; }
-
-        public string HardwareAccelerationType { get; set; }
-
-        /// <summary>
-        /// Gets or sets the FFmpeg path as set by the user via the UI.
-        /// </summary>
-        public string EncoderAppPath { get; set; }
-
-        /// <summary>
-        /// Gets or sets the current FFmpeg path being used by the system and displayed on the transcode page.
-        /// </summary>
-        public string EncoderAppPathDisplay { get; set; }
-
-        public string VaapiDevice { get; set; }
-
-        public bool EnableTonemapping { get; set; }
-
-        public bool EnableVppTonemapping { get; set; }
-
-        public string TonemappingAlgorithm { get; set; }
-
-        public string TonemappingRange { get; set; }
-
-        public double TonemappingDesat { get; set; }
-
-        public double TonemappingThreshold { get; set; }
-
-        public double TonemappingPeak { get; set; }
-
-        public double TonemappingParam { get; set; }
-
-        public double VppTonemappingBrightness { get; set; }
-
-        public double VppTonemappingContrast { get; set; }
-
-        public int H264Crf { get; set; }
-
-        public int H265Crf { get; set; }
-
-        public string EncoderPreset { get; set; }
-
-        public bool DeinterlaceDoubleRate { get; set; }
-
-        public string DeinterlaceMethod { get; set; }
-
-        public bool EnableDecodingColorDepth10Hevc { get; set; }
-
-        public bool EnableDecodingColorDepth10Vp9 { get; set; }
-
-        public bool EnableEnhancedNvdecDecoder { get; set; }
-
-        public bool PreferSystemNativeHwDecoder { get; set; }
-
-        public bool EnableIntelLowPowerH264HwEncoder { get; set; }
-
-        public bool EnableIntelLowPowerHevcHwEncoder { get; set; }
-
-        public bool EnableHardwareEncoding { get; set; }
-
-        public bool AllowHevcEncoding { get; set; }
-
-        public bool EnableSubtitleExtraction { get; set; }
-
-        public string[] HardwareDecodingCodecs { get; set; }
-
-        public string[] AllowOnDemandMetadataBasedKeyframeExtractionForExtensions { get; set; }
+        EnableFallbackFont = false;
+        DownMixAudioBoost = 2;
+        DownMixStereoAlgorithm = DownMixStereoAlgorithms.None;
+        MaxMuxingQueueSize = 2048;
+        EnableThrottling = false;
+        ThrottleDelaySeconds = 180;
+        EncodingThreadCount = -1;
+        // This is a DRM device that is almost guaranteed to be there on every intel platform,
+        // plus it's the default one in ffmpeg if you don't specify anything
+        VaapiDevice = "/dev/dri/renderD128";
+        EnableTonemapping = false;
+        EnableVppTonemapping = false;
+        TonemappingAlgorithm = "bt2390";
+        TonemappingRange = "auto";
+        TonemappingDesat = 0;
+        TonemappingThreshold = 0.8;
+        TonemappingPeak = 100;
+        TonemappingParam = 0;
+        VppTonemappingBrightness = 0;
+        VppTonemappingContrast = 1.2;
+        H264Crf = 23;
+        H265Crf = 28;
+        DeinterlaceDoubleRate = false;
+        DeinterlaceMethod = "yadif";
+        EnableDecodingColorDepth10Hevc = true;
+        EnableDecodingColorDepth10Vp9 = true;
+        EnableEnhancedNvdecDecoder = false;
+        PreferSystemNativeHwDecoder = true;
+        EnableIntelLowPowerH264HwEncoder = false;
+        EnableIntelLowPowerHevcHwEncoder = false;
+        EnableHardwareEncoding = true;
+        AllowHevcEncoding = false;
+        EnableSubtitleExtraction = true;
+        AllowOnDemandMetadataBasedKeyframeExtractionForExtensions = new[] { "mkv" };
+        HardwareDecodingCodecs = new string[] { "h264", "vc1" };
     }
+
+    /// <summary>
+    /// Gets or sets the thread count used for encoding.
+    /// </summary>
+    public int EncodingThreadCount { get; set; }
+
+    /// <summary>
+    /// Gets or sets the temporary transcoding path.
+    /// </summary>
+    public string TranscodingTempPath { get; set; }
+
+    /// <summary>
+    /// Gets or sets the path to the fallback font.
+    /// </summary>
+    public string FallbackFontPath { get; set; }
+
+    /// <summary>
+    /// Gets or sets a value indicating whether to use the fallback font.
+    /// </summary>
+    public bool EnableFallbackFont { get; set; }
+
+    /// <summary>
+    /// Gets or sets the audio boost applied when downmixing audio.
+    /// </summary>
+    public double DownMixAudioBoost { get; set; }
+
+    /// <summary>
+    /// Gets or sets the algorithm used for downmixing audio to stereo.
+    /// </summary>
+    public DownMixStereoAlgorithms DownMixStereoAlgorithm { get; set; }
+
+    /// <summary>
+    /// Gets or sets the maximum size of the muxing queue.
+    /// </summary>
+    public int MaxMuxingQueueSize { get; set; }
+
+    /// <summary>
+    /// Gets or sets a value indicating whether throttling is enabled.
+    /// </summary>
+    public bool EnableThrottling { get; set; }
+
+    /// <summary>
+    /// Gets or sets the delay after which throttling happens.
+    /// </summary>
+    public int ThrottleDelaySeconds { get; set; }
+
+    /// <summary>
+    /// Gets or sets the hardware acceleration type.
+    /// </summary>
+    public string HardwareAccelerationType { get; set; }
+
+    /// <summary>
+    /// Gets or sets the FFmpeg path as set by the user via the UI.
+    /// </summary>
+    public string EncoderAppPath { get; set; }
+
+    /// <summary>
+    /// Gets or sets the current FFmpeg path being used by the system and displayed on the transcode page.
+    /// </summary>
+    public string EncoderAppPathDisplay { get; set; }
+
+    /// <summary>
+    /// Gets or sets the VA-API device.
+    /// </summary>
+    public string VaapiDevice { get; set; }
+
+    /// <summary>
+    /// Gets or sets a value indicating whether tonemapping is enabled.
+    /// </summary>
+    public bool EnableTonemapping { get; set; }
+
+    /// <summary>
+    /// Gets or sets a value indicating whether VPP tonemapping is enabled.
+    /// </summary>
+    public bool EnableVppTonemapping { get; set; }
+
+    /// <summary>
+    /// Gets or sets the tone-mapping algorithm.
+    /// </summary>
+    public string TonemappingAlgorithm { get; set; }
+
+    /// <summary>
+    /// Gets or sets the tone-mapping range.
+    /// </summary>
+    public string TonemappingRange { get; set; }
+
+    /// <summary>
+    /// Gets or sets the tone-mapping desaturation.
+    /// </summary>
+    public double TonemappingDesat { get; set; }
+
+    /// <summary>
+    /// Gets or sets the tone-mapping threshold.
+    /// </summary>
+    public double TonemappingThreshold { get; set; }
+
+    /// <summary>
+    /// Gets or sets the tone-mapping peak.
+    /// </summary>
+    public double TonemappingPeak { get; set; }
+
+    /// <summary>
+    /// Gets or sets the tone-mapping parameters.
+    /// </summary>
+    public double TonemappingParam { get; set; }
+
+    /// <summary>
+    /// Gets or sets the VPP tone-mapping brightness.
+    /// </summary>
+    public double VppTonemappingBrightness { get; set; }
+
+    /// <summary>
+    /// Gets or sets the VPP tone-mapping contrast.
+    /// </summary>
+    public double VppTonemappingContrast { get; set; }
+
+    /// <summary>
+    /// Gets or sets the H264 CRF.
+    /// </summary>
+    public int H264Crf { get; set; }
+
+    /// <summary>
+    /// Gets or sets the H265 CRF.
+    /// </summary>
+    public int H265Crf { get; set; }
+
+    /// <summary>
+    /// Gets or sets the encoder preset.
+    /// </summary>
+    public string EncoderPreset { get; set; }
+
+    /// <summary>
+    /// Gets or sets a value indicating whether the framerate is doubled when deinterlacing.
+    /// </summary>
+    public bool DeinterlaceDoubleRate { get; set; }
+
+    /// <summary>
+    /// Gets or sets the deinterlace method.
+    /// </summary>
+    public string DeinterlaceMethod { get; set; }
+
+    /// <summary>
+    /// Gets or sets a value indicating whether 10bit HEVC decoding is enabled.
+    /// </summary>
+    public bool EnableDecodingColorDepth10Hevc { get; set; }
+
+    /// <summary>
+    /// Gets or sets a value indicating whether 10bit VP9 decoding is enabled.
+    /// </summary>
+    public bool EnableDecodingColorDepth10Vp9 { get; set; }
+
+    /// <summary>
+    /// Gets or sets a value indicating whether the enhanced NVDEC is enabled.
+    /// </summary>
+    public bool EnableEnhancedNvdecDecoder { get; set; }
+
+    /// <summary>
+    /// Gets or sets a value indicating whether the system native hardware decoder should be used.
+    /// </summary>
+    public bool PreferSystemNativeHwDecoder { get; set; }
+
+    /// <summary>
+    /// Gets or sets a value indicating whether the Intel H264 low-power hardware encoder should be used.
+    /// </summary>
+    public bool EnableIntelLowPowerH264HwEncoder { get; set; }
+
+    /// <summary>
+    /// Gets or sets a value indicating whether the Intel HEVC low-power hardware encoder should be used.
+    /// </summary>
+    public bool EnableIntelLowPowerHevcHwEncoder { get; set; }
+
+    /// <summary>
+    /// Gets or sets a value indicating whether hardware encoding is enabled.
+    /// </summary>
+    public bool EnableHardwareEncoding { get; set; }
+
+    /// <summary>
+    /// Gets or sets a value indicating whether HEVC encoding is enabled.
+    /// </summary>
+    public bool AllowHevcEncoding { get; set; }
+
+    /// <summary>
+    /// Gets or sets a value indicating whether subtitle extraction is enabled.
+    /// </summary>
+    public bool EnableSubtitleExtraction { get; set; }
+
+    /// <summary>
+    /// Gets or sets the codecs hardware encoding is used for.
+    /// </summary>
+    public string[] HardwareDecodingCodecs { get; set; }
+
+    /// <summary>
+    /// Gets or sets the file extensions on-demand metadata based keyframe extraction is enabled for.
+    /// </summary>
+    public string[] AllowOnDemandMetadataBasedKeyframeExtractionForExtensions { get; set; }
 }

+ 23 - 0
MediaBrowser.Model/Entities/DownMixStereoAlgorithms.cs

@@ -0,0 +1,23 @@
+namespace MediaBrowser.Model.Entities;
+
+/// <summary>
+/// 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.
+/// </summary>
+public enum DownMixStereoAlgorithms
+{
+    /// <summary>
+    /// No special algorithm.
+    /// </summary>
+    None = 0,
+
+    /// <summary>
+    /// Algorithm by Dave_750.
+    /// </summary>
+    Dave750 = 1,
+
+    /// <summary>
+    /// Nightmode Dialogue algorithm.
+    /// </summary>
+    NightmodeDialogue = 2
+}