From 162ea38a95560f19e0a2df8a54c1ac117d6d91bc Mon Sep 17 00:00:00 2001 From: gnattu Date: Mon, 29 Jul 2024 06:11:59 +0800 Subject: [PATCH] Check MaxAudioChannels for directAudioStream candidates (#12319) * Check MaxAudioChannels for directAudioStream candidates The current stream builder logic does not check the channel limit when determining if the audio stream can be directly used, and this can cause some undesired effects: - A high channel count surround sound stream might be picked even if a stereo one exists when the user requires stereo audio. - The user's preferred audio codec might not be respected during the downmix because the requested codec is now forced to be the same as the original source. Signed-off-by: gnattu * Fix unit test Signed-off-by: gnattu * Set correct transcode reason and target channels for unit test Signed-off-by: gnattu * Match old stream selection behavior Signed-off-by: gnattu * Fix reason matching Signed-off-by: gnattu --------- Signed-off-by: gnattu --- MediaBrowser.Model/Dlna/StreamBuilder.cs | 15 +++++++++++++-- .../Dlna/StreamBuilderTests.cs | 17 ++++++++++++----- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index d37528ede..4815dcc04 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -908,7 +908,18 @@ namespace MediaBrowser.Model.Dlna } } - var directAudioStream = candidateAudioStreams.FirstOrDefault(stream => ContainerProfile.ContainsContainer(audioCodecs, stream.Codec)); + var audioStreamWithSupportedCodec = candidateAudioStreams.Where(stream => ContainerProfile.ContainsContainer(audioCodecs, stream.Codec)).FirstOrDefault(); + + var directAudioStream = audioStreamWithSupportedCodec?.Channels is not null && audioStreamWithSupportedCodec.Channels.Value <= (playlistItem.TranscodingMaxAudioChannels ?? int.MaxValue) ? audioStreamWithSupportedCodec : null; + + var channelsExceedsLimit = audioStreamWithSupportedCodec is not null && directAudioStream is null; + + if (channelsExceedsLimit && playlistItem.TargetAudioStream is not null) + { + playlistItem.TranscodeReasons |= TranscodeReason.AudioChannelsNotSupported; + playlistItem.TargetAudioStream.Channels = playlistItem.TranscodingMaxAudioChannels; + } + playlistItem.AudioCodecs = audioCodecs; if (directAudioStream is not null) { @@ -971,7 +982,7 @@ namespace MediaBrowser.Model.Dlna } // Honor requested max channels - playlistItem.GlobalMaxAudioChannels = options.MaxAudioChannels; + playlistItem.GlobalMaxAudioChannels = channelsExceedsLimit ? playlistItem.TranscodingMaxAudioChannels : options.MaxAudioChannels; int audioBitrate = GetAudioBitrate(options.GetMaxBitrate(true) ?? 0, playlistItem.TargetAudioCodec, audioStream, playlistItem); playlistItem.AudioBitrate = Math.Min(playlistItem.AudioBitrate ?? audioBitrate, audioBitrate); diff --git a/tests/Jellyfin.Model.Tests/Dlna/StreamBuilderTests.cs b/tests/Jellyfin.Model.Tests/Dlna/StreamBuilderTests.cs index 6d88dbb8e..31ddd427c 100644 --- a/tests/Jellyfin.Model.Tests/Dlna/StreamBuilderTests.cs +++ b/tests/Jellyfin.Model.Tests/Dlna/StreamBuilderTests.cs @@ -51,8 +51,8 @@ namespace Jellyfin.Model.Tests [InlineData("SafariNext", "mp4-h264-ac3-aacExt-srt-2600k", PlayMethod.DirectPlay)] // #6450 [InlineData("SafariNext", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectPlay)] // #6450 [InlineData("SafariNext", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Remux", "HLS.mp4")] // #6450 - [InlineData("SafariNext", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Remux", "HLS.mp4")] // #6450 - [InlineData("SafariNext", "mp4-hevc-ac3-aacExt-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Remux", "HLS.mp4")] // #6450 + [InlineData("SafariNext", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.AudioChannelsNotSupported, "DirectStream", "HLS.mp4")] // #6450 + [InlineData("SafariNext", "mp4-hevc-ac3-aacExt-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.AudioChannelsNotSupported, "DirectStream", "HLS.mp4")] // #6450 // AndroidPixel [InlineData("AndroidPixel", "mp4-h264-aac-srt-2600k", PlayMethod.DirectPlay)] // #6450 [InlineData("AndroidPixel", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay)] // #6450 @@ -205,8 +205,8 @@ namespace Jellyfin.Model.Tests [InlineData("SafariNext", "mp4-h264-ac3-aacExt-srt-2600k", PlayMethod.DirectPlay)] // #6450 [InlineData("SafariNext", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectPlay)] // #6450 [InlineData("SafariNext", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Remux", "HLS.mp4")] // #6450 - [InlineData("SafariNext", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Remux", "HLS.mp4")] // #6450 - [InlineData("SafariNext", "mp4-hevc-ac3-aacExt-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Remux", "HLS.mp4")] // #6450 + [InlineData("SafariNext", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.AudioChannelsNotSupported, "DirectStream", "HLS.mp4")] // #6450 + [InlineData("SafariNext", "mp4-hevc-ac3-aacExt-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.AudioChannelsNotSupported, "DirectStream", "HLS.mp4")] // #6450 // AndroidPixel [InlineData("AndroidPixel", "mp4-h264-aac-srt-2600k", PlayMethod.DirectPlay)] // #6450 [InlineData("AndroidPixel", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectPlay)] // #6450 @@ -432,7 +432,14 @@ namespace Jellyfin.Model.Tests if (targetAudioStream?.IsExternal == false) { // Check expected audio codecs (1) - Assert.DoesNotContain(targetAudioStream.Codec, streamInfo.AudioCodecs); + if ((why & TranscodeReason.AudioChannelsNotSupported) == 0) + { + Assert.DoesNotContain(targetAudioStream.Codec, streamInfo.AudioCodecs); + } + else + { + Assert.Equal(targetAudioStream.Channels, streamInfo.TranscodingMaxAudioChannels); + } } } else if (transcodeMode.Equals("Remux", StringComparison.Ordinal))