From 4eeb522144037d9102b63478d7d5c0195a1ceef8 Mon Sep 17 00:00:00 2001 From: David Fairbrother Date: Sat, 7 Jan 2023 19:25:24 +0000 Subject: Add dts to list of audio codecs which require strict -2 Adds dts to the list of audio codecs where ffmpeg will throw asking us to opt into experimental support. This is seen when the original content is based on dts and we don't acopy using ffmpeg. --- Jellyfin.Api/Controllers/DynamicHlsController.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'Jellyfin.Api/Controllers/DynamicHlsController.cs') diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index af43bb578..5f5f34b0d 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -1704,11 +1704,12 @@ namespace Jellyfin.Api.Controllers return audioTranscodeParams; } - // flac and opus are experimental in mp4 muxer + // dts, flac and opus are experimental in mp4 muxer var strictArgs = string.Empty; if (string.Equals(state.ActualOutputAudioCodec, "flac", StringComparison.OrdinalIgnoreCase) - || string.Equals(state.ActualOutputAudioCodec, "opus", StringComparison.OrdinalIgnoreCase)) + || string.Equals(state.ActualOutputAudioCodec, "opus", StringComparison.OrdinalIgnoreCase) + || string.Equals(state.ActualOutputAudioCodec, "dts", StringComparison.OrdinalIgnoreCase)) { strictArgs = " -strict -2"; } -- cgit v1.2.3 From 407c716f82da25fa5ffe30a819ea1adb5c6873ab Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Mon, 2 Jan 2023 22:26:54 +0100 Subject: Add stereo downmix algorithm selection. --- Jellyfin.Api/Controllers/DynamicHlsController.cs | 8 +- .../MediaEncoding/EncodingHelper.cs | 28 +- .../Configuration/EncodingOptions.cs | 363 ++++++++++++++------- .../Entities/DownMixStereoAlgorithms.cs | 23 ++ 4 files changed, 292 insertions(+), 130 deletions(-) create mode 100644 MediaBrowser.Model/Entities/DownMixStereoAlgorithms.cs (limited to 'Jellyfin.Api/Controllers/DynamicHlsController.cs') diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index af43bb578..e0c5bcc84 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/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; } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index b40c224d5..e94a04a7d 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -2129,15 +2129,30 @@ namespace MediaBrowser.Controller.MediaEncoding var filters = new List(); - // 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; } diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs index f4cd2f006..0ff95a2e1 100644 --- a/MediaBrowser.Model/Configuration/EncodingOptions.cs +++ b/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; + +/// +/// Class EncodingOptions. +/// +public class EncodingOptions { - public class EncodingOptions + /// + /// Initializes a new instance of the class. + /// + 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; } - - /// - /// Gets or sets the FFmpeg path as set by the user via the UI. - /// - public string EncoderAppPath { get; set; } - - /// - /// Gets or sets the current FFmpeg path being used by the system and displayed on the transcode page. - /// - 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" }; } + + /// + /// Gets or sets the thread count used for encoding. + /// + public int EncodingThreadCount { get; set; } + + /// + /// Gets or sets the temporary transcoding path. + /// + public string TranscodingTempPath { get; set; } + + /// + /// Gets or sets the path to the fallback font. + /// + public string FallbackFontPath { get; set; } + + /// + /// Gets or sets a value indicating whether to use the fallback font. + /// + public bool EnableFallbackFont { get; set; } + + /// + /// Gets or sets the audio boost applied when downmixing audio. + /// + public double DownMixAudioBoost { get; set; } + + /// + /// Gets or sets the algorithm used for downmixing audio to stereo. + /// + public DownMixStereoAlgorithms DownMixStereoAlgorithm { get; set; } + + /// + /// Gets or sets the maximum size of the muxing queue. + /// + public int MaxMuxingQueueSize { get; set; } + + /// + /// Gets or sets a value indicating whether throttling is enabled. + /// + public bool EnableThrottling { get; set; } + + /// + /// Gets or sets the delay after which throttling happens. + /// + public int ThrottleDelaySeconds { get; set; } + + /// + /// Gets or sets the hardware acceleration type. + /// + public string HardwareAccelerationType { get; set; } + + /// + /// Gets or sets the FFmpeg path as set by the user via the UI. + /// + public string EncoderAppPath { get; set; } + + /// + /// Gets or sets the current FFmpeg path being used by the system and displayed on the transcode page. + /// + public string EncoderAppPathDisplay { get; set; } + + /// + /// Gets or sets the VA-API device. + /// + public string VaapiDevice { get; set; } + + /// + /// Gets or sets a value indicating whether tonemapping is enabled. + /// + public bool EnableTonemapping { get; set; } + + /// + /// Gets or sets a value indicating whether VPP tonemapping is enabled. + /// + public bool EnableVppTonemapping { get; set; } + + /// + /// Gets or sets the tone-mapping algorithm. + /// + public string TonemappingAlgorithm { get; set; } + + /// + /// Gets or sets the tone-mapping range. + /// + public string TonemappingRange { get; set; } + + /// + /// Gets or sets the tone-mapping desaturation. + /// + public double TonemappingDesat { get; set; } + + /// + /// Gets or sets the tone-mapping threshold. + /// + public double TonemappingThreshold { get; set; } + + /// + /// Gets or sets the tone-mapping peak. + /// + public double TonemappingPeak { get; set; } + + /// + /// Gets or sets the tone-mapping parameters. + /// + public double TonemappingParam { get; set; } + + /// + /// Gets or sets the VPP tone-mapping brightness. + /// + public double VppTonemappingBrightness { get; set; } + + /// + /// Gets or sets the VPP tone-mapping contrast. + /// + public double VppTonemappingContrast { get; set; } + + /// + /// Gets or sets the H264 CRF. + /// + public int H264Crf { get; set; } + + /// + /// Gets or sets the H265 CRF. + /// + public int H265Crf { get; set; } + + /// + /// Gets or sets the encoder preset. + /// + public string EncoderPreset { get; set; } + + /// + /// Gets or sets a value indicating whether the framerate is doubled when deinterlacing. + /// + public bool DeinterlaceDoubleRate { get; set; } + + /// + /// Gets or sets the deinterlace method. + /// + public string DeinterlaceMethod { get; set; } + + /// + /// Gets or sets a value indicating whether 10bit HEVC decoding is enabled. + /// + public bool EnableDecodingColorDepth10Hevc { get; set; } + + /// + /// Gets or sets a value indicating whether 10bit VP9 decoding is enabled. + /// + public bool EnableDecodingColorDepth10Vp9 { get; set; } + + /// + /// Gets or sets a value indicating whether the enhanced NVDEC is enabled. + /// + public bool EnableEnhancedNvdecDecoder { get; set; } + + /// + /// Gets or sets a value indicating whether the system native hardware decoder should be used. + /// + public bool PreferSystemNativeHwDecoder { get; set; } + + /// + /// Gets or sets a value indicating whether the Intel H264 low-power hardware encoder should be used. + /// + public bool EnableIntelLowPowerH264HwEncoder { get; set; } + + /// + /// Gets or sets a value indicating whether the Intel HEVC low-power hardware encoder should be used. + /// + public bool EnableIntelLowPowerHevcHwEncoder { get; set; } + + /// + /// Gets or sets a value indicating whether hardware encoding is enabled. + /// + public bool EnableHardwareEncoding { get; set; } + + /// + /// Gets or sets a value indicating whether HEVC encoding is enabled. + /// + public bool AllowHevcEncoding { get; set; } + + /// + /// Gets or sets a value indicating whether subtitle extraction is enabled. + /// + public bool EnableSubtitleExtraction { get; set; } + + /// + /// Gets or sets the codecs hardware encoding is used for. + /// + public string[] HardwareDecodingCodecs { get; set; } + + /// + /// Gets or sets the file extensions on-demand metadata based keyframe extraction is enabled for. + /// + public string[] AllowOnDemandMetadataBasedKeyframeExtractionForExtensions { get; set; } } diff --git a/MediaBrowser.Model/Entities/DownMixStereoAlgorithms.cs b/MediaBrowser.Model/Entities/DownMixStereoAlgorithms.cs new file mode 100644 index 000000000..385cd6a34 --- /dev/null +++ b/MediaBrowser.Model/Entities/DownMixStereoAlgorithms.cs @@ -0,0 +1,23 @@ +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. +/// +public enum DownMixStereoAlgorithms +{ + /// + /// No special algorithm. + /// + None = 0, + + /// + /// Algorithm by Dave_750. + /// + Dave750 = 1, + + /// + /// Nightmode Dialogue algorithm. + /// + NightmodeDialogue = 2 +} -- cgit v1.2.3