diff options
| author | Bond-009 <bond.009@outlook.com> | 2023-03-20 17:46:11 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-03-20 17:46:11 +0100 |
| commit | 2ce08eb1842777e5d9f3369dfb61c73992bf4f54 (patch) | |
| tree | dd980b4d3da3b6b4bf1eccf6f37c0099f8a2400a /MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | |
| parent | dd491ce8ffe520f992dd5441d3017a0d6c622790 (diff) | |
| parent | e57c33c4420da4336dacb59c0fc784a7000e71a0 (diff) | |
Merge pull request #9388 from Shadowghost/output-bitrate-channels-master
Diffstat (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs')
| -rw-r--r-- | MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 168 |
1 files changed, 124 insertions, 44 deletions
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 5de57917e..960b0b7cd 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -89,6 +89,16 @@ namespace MediaBrowser.Controller.MediaEncoding { "truehd", 6 }, }; + public static readonly string[] LosslessAudioCodecs = new string[] + { + "alac", + "ape", + "flac", + "mlp", + "truehd", + "wavpack" + }; + public EncodingHelper( IApplicationPaths appPaths, IMediaEncoder mediaEncoder, @@ -620,6 +630,11 @@ namespace MediaBrowser.Controller.MediaEncoding return "flac"; } + if (string.Equals(codec, "dts", StringComparison.OrdinalIgnoreCase)) + { + return "dca"; + } + return codec.ToLowerInvariant(); } @@ -2050,9 +2065,9 @@ namespace MediaBrowser.Controller.MediaEncoding } } - // Video bitrate must fall within requested value + // Audio bitrate must fall within requested value if (request.AudioBitRate.HasValue - && audioStream.BitDepth.HasValue + && audioStream.BitRate.HasValue && audioStream.BitRate.Value > request.AudioBitRate.Value) { return false; @@ -2161,56 +2176,96 @@ namespace MediaBrowser.Controller.MediaEncoding return Convert.ToInt32(scaleFactor * bitrate); } - public int? GetAudioBitrateParam(BaseEncodingJobOptions request, MediaStream audioStream) + public int? GetAudioBitrateParam(BaseEncodingJobOptions request, MediaStream audioStream, int? outputAudioChannels) { - return GetAudioBitrateParam(request.AudioBitRate, request.AudioCodec, audioStream); + return GetAudioBitrateParam(request.AudioBitRate, request.AudioCodec, audioStream, outputAudioChannels); } - public int? GetAudioBitrateParam(int? audioBitRate, string audioCodec, MediaStream audioStream) + public int? GetAudioBitrateParam(int? audioBitRate, string audioCodec, MediaStream audioStream, int? outputAudioChannels) { if (audioStream is null) { return null; } - if (audioBitRate.HasValue && string.IsNullOrEmpty(audioCodec)) + var inputChannels = audioStream.Channels ?? 0; + var outputChannels = outputAudioChannels ?? 0; + var bitrate = audioBitRate ?? int.MaxValue; + + if (string.IsNullOrEmpty(audioCodec) + || string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase) + || string.Equals(audioCodec, "mp3", StringComparison.OrdinalIgnoreCase) + || string.Equals(audioCodec, "opus", StringComparison.OrdinalIgnoreCase) + || string.Equals(audioCodec, "vorbis", StringComparison.OrdinalIgnoreCase) + || string.Equals(audioCodec, "ac3", StringComparison.OrdinalIgnoreCase) + || string.Equals(audioCodec, "eac3", StringComparison.OrdinalIgnoreCase)) { - return Math.Min(384000, audioBitRate.Value); + return (inputChannels, outputChannels) switch + { + (>= 6, >= 6 or 0) => Math.Min(640000, bitrate), + (> 0, > 0) => Math.Min(outputChannels * 128000, bitrate), + (> 0, _) => Math.Min(inputChannels * 128000, bitrate), + (_, _) => Math.Min(384000, bitrate) + }; } - if (audioBitRate.HasValue && !string.IsNullOrEmpty(audioCodec)) + if (string.Equals(audioCodec, "dts", StringComparison.OrdinalIgnoreCase) + || string.Equals(audioCodec, "dca", StringComparison.OrdinalIgnoreCase)) { - if (string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase) - || string.Equals(audioCodec, "mp3", StringComparison.OrdinalIgnoreCase) - || string.Equals(audioCodec, "opus", StringComparison.OrdinalIgnoreCase) - || string.Equals(audioCodec, "vorbis", StringComparison.OrdinalIgnoreCase) - || string.Equals(audioCodec, "ac3", StringComparison.OrdinalIgnoreCase) - || string.Equals(audioCodec, "eac3", StringComparison.OrdinalIgnoreCase)) + return (inputChannels, outputChannels) switch { - if ((audioStream.Channels ?? 0) >= 6) - { - return Math.Min(640000, audioBitRate.Value); - } + (>= 6, >= 6 or 0) => Math.Min(768000, bitrate), + (> 0, > 0) => Math.Min(outputChannels * 136000, bitrate), + (> 0, _) => Math.Min(inputChannels * 136000, bitrate), + (_, _) => Math.Min(672000, bitrate) + }; + } - return Math.Min(384000, audioBitRate.Value); - } + // Empty bitrate area is not allow on iOS + // Default audio bitrate to 128K per channel if we don't have codec specific defaults + // https://ffmpeg.org/ffmpeg-codecs.html#toc-Codec-Options + return 128000 * (outputAudioChannels ?? audioStream.Channels ?? 2); + } - if (string.Equals(audioCodec, "flac", StringComparison.OrdinalIgnoreCase) - || string.Equals(audioCodec, "alac", StringComparison.OrdinalIgnoreCase)) + public string GetAudioVbrModeParam(string encoder, int bitratePerChannel) + { + if (string.Equals(encoder, "libfdk_aac", StringComparison.OrdinalIgnoreCase)) + { + return " -vbr:a " + bitratePerChannel switch { - if ((audioStream.Channels ?? 0) >= 6) - { - return Math.Min(3584000, audioBitRate.Value); - } + < 32000 => "1", + < 48000 => "2", + < 64000 => "3", + < 96000 => "4", + _ => "5" + }; + } - return Math.Min(1536000, audioBitRate.Value); - } + if (string.Equals(encoder, "libmp3lame", StringComparison.OrdinalIgnoreCase)) + { + return " -qscale:a " + bitratePerChannel switch + { + < 48000 => "8", + < 64000 => "6", + < 88000 => "4", + < 112000 => "2", + _ => "0" + }; } - // Empty bitrate area is not allow on iOS - // Default audio bitrate to 128K if it is not being requested - // https://ffmpeg.org/ffmpeg-codecs.html#toc-Codec-Options - return 128000; + if (string.Equals(encoder, "libvorbis", StringComparison.OrdinalIgnoreCase)) + { + return " -qscale:a " + bitratePerChannel switch + { + < 40000 => "0", + < 56000 => "2", + < 80000 => "4", + < 112000 => "6", + _ => "8" + }; + } + + return null; } public string GetAudioFilterParam(EncodingJobInfo state, EncodingOptions encodingOptions) @@ -5670,14 +5725,22 @@ namespace MediaBrowser.Controller.MediaEncoding } var inputChannels = audioStream is null ? 6 : audioStream.Channels ?? 6; + var shiftAudioCodecs = new List<string>(); if (inputChannels >= 6) { - return; + // DTS and TrueHD are not supported by HLS + // Keep them in the supported codecs list, but shift them to the end of the list so that if transcoding happens, another codec is used + shiftAudioCodecs.Add("dca"); + shiftAudioCodecs.Add("truehd"); + } + else + { + // Transcoding to 2ch ac3 or eac3 almost always causes a playback failure + // Keep them in the supported codecs list, but shift them to the end of the list so that if transcoding happens, another codec is used + shiftAudioCodecs.Add("ac3"); + shiftAudioCodecs.Add("eac3"); } - // Transcoding to 2ch ac3 almost always causes a playback failure - // Keep it in the supported codecs list, but shift it to the end of the list so that if transcoding happens, another codec is used - var shiftAudioCodecs = new[] { "ac3", "eac3" }; if (audioCodecs.All(i => shiftAudioCodecs.Contains(i, StringComparison.OrdinalIgnoreCase))) { return; @@ -5919,10 +5982,17 @@ namespace MediaBrowser.Controller.MediaEncoding } var bitrate = state.OutputAudioBitrate; - - if (bitrate.HasValue) + if (bitrate.HasValue && !LosslessAudioCodecs.Contains(codec, StringComparison.OrdinalIgnoreCase)) { - args += " -ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture); + var vbrParam = GetAudioVbrModeParam(codec, bitrate.Value / (channels ?? 2)); + if (encodingOptions.EnableAudioVbr && vbrParam is not null) + { + args += vbrParam; + } + else + { + args += " -ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture); + } } if (state.OutputAudioSampleRate.HasValue) @@ -5940,23 +6010,33 @@ namespace MediaBrowser.Controller.MediaEncoding var audioTranscodeParams = new List<string>(); var bitrate = state.OutputAudioBitrate; + var channels = state.OutputAudioChannels; + var outputCodec = state.OutputAudioCodec; - if (bitrate.HasValue) + if (bitrate.HasValue && !LosslessAudioCodecs.Contains(outputCodec, StringComparison.OrdinalIgnoreCase)) { - audioTranscodeParams.Add("-ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture)); + var vbrParam = GetAudioVbrModeParam(outputCodec, bitrate.Value / (channels ?? 2)); + if (encodingOptions.EnableAudioVbr && vbrParam is not null) + { + audioTranscodeParams.Add(vbrParam); + } + else + { + audioTranscodeParams.Add("-ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture)); + } } - if (state.OutputAudioChannels.HasValue) + if (channels.HasValue) { audioTranscodeParams.Add("-ac " + state.OutputAudioChannels.Value.ToString(CultureInfo.InvariantCulture)); } - if (!string.IsNullOrEmpty(state.OutputAudioCodec)) + if (!string.IsNullOrEmpty(outputCodec)) { audioTranscodeParams.Add("-acodec " + GetAudioEncoder(state)); } - if (!string.Equals(state.OutputAudioCodec, "opus", StringComparison.OrdinalIgnoreCase)) + if (!string.Equals(outputCodec, "opus", StringComparison.OrdinalIgnoreCase)) { // opus only supports specific sampling rates var sampleRate = state.OutputAudioSampleRate; |
