2
0
Эх сурвалжийг харах

Merge pull request #7699 from Shadowghost/streambuilder-fix

Joshua M. Boniface 3 жил өмнө
parent
commit
b46d61dfdf

+ 24 - 26
MediaBrowser.Model/Dlna/StreamBuilder.cs

@@ -385,7 +385,7 @@ namespace MediaBrowser.Model.Dlna
             // If device requirements are satisfied then allow both direct stream and direct play
             if (item.SupportsDirectPlay)
             {
-                if (IsItemBitrateEligibleForDirectPlay(item, options.GetMaxBitrate(true) ?? 0, PlayMethod.DirectPlay))
+                if (IsItemBitrateEligibleForDirectPlayback(item, options.GetMaxBitrate(true) ?? 0, PlayMethod.DirectPlay))
                 {
                     if (options.EnableDirectPlay)
                     {
@@ -401,7 +401,7 @@ namespace MediaBrowser.Model.Dlna
             // While options takes the network and other factors into account. Only applies to direct stream
             if (item.SupportsDirectStream)
             {
-                if (IsItemBitrateEligibleForDirectPlay(item, options.GetMaxBitrate(true) ?? 0, PlayMethod.DirectStream))
+                if (IsItemBitrateEligibleForDirectPlayback(item, options.GetMaxBitrate(true) ?? 0, PlayMethod.DirectStream))
                 {
                     if (options.EnableDirectStream)
                     {
@@ -604,11 +604,11 @@ namespace MediaBrowser.Model.Dlna
 
             var videoStream = item.VideoStream;
 
-            var directPlayEligibilityResult = IsEligibleForDirectPlay(item, options.GetMaxBitrate(false) ?? 0, options, PlayMethod.DirectPlay);
-            var directStreamEligibilityResult = IsEligibleForDirectPlay(item, options.GetMaxBitrate(false) ?? 0, options, PlayMethod.DirectStream);
-            bool isEligibleForDirectPlay = options.EnableDirectPlay && (options.ForceDirectPlay || directPlayEligibilityResult == 0);
-            bool isEligibleForDirectStream = options.EnableDirectStream && (options.ForceDirectStream || directPlayEligibilityResult == 0);
-            var transcodeReasons = directPlayEligibilityResult | directStreamEligibilityResult;
+            var directPlayBitrateEligibility = IsBitrateEligibleForDirectPlayback(item, options.GetMaxBitrate(false) ?? 0, options, PlayMethod.DirectPlay);
+            var directStreamBitrateEligibility = IsBitrateEligibleForDirectPlayback(item, options.GetMaxBitrate(false) ?? 0, options, PlayMethod.DirectStream);
+            bool isEligibleForDirectPlay = options.EnableDirectPlay && (options.ForceDirectPlay || directPlayBitrateEligibility == 0);
+            bool isEligibleForDirectStream = options.EnableDirectStream && (options.ForceDirectStream || directStreamBitrateEligibility == 0);
+            var transcodeReasons = directPlayBitrateEligibility | directStreamBitrateEligibility;
 
             _logger.LogDebug(
                 "Profile: {0}, Path: {1}, isEligibleForDirectPlay: {2}, isEligibleForDirectStream: {3}",
@@ -625,7 +625,7 @@ namespace MediaBrowser.Model.Dlna
                 var directPlay = directPlayInfo.PlayMethod;
                 transcodeReasons |= directPlayInfo.TranscodeReasons;
 
-                if (directPlay != null)
+                if (directPlay.HasValue)
                 {
                     directPlayProfile = directPlayInfo.Profile;
                     playlistItem.PlayMethod = directPlay.Value;
@@ -676,7 +676,7 @@ namespace MediaBrowser.Model.Dlna
 
             playlistItem.TranscodeReasons = transcodeReasons;
 
-            if (playlistItem.PlayMethod != PlayMethod.DirectStream || !options.EnableDirectStream)
+            if (playlistItem.PlayMethod != PlayMethod.DirectStream && playlistItem.PlayMethod != PlayMethod.DirectPlay)
             {
                 // Can't direct play, find the transcoding profile
                 // If we do this for direct-stream we will overwrite the info
@@ -687,6 +687,8 @@ namespace MediaBrowser.Model.Dlna
 
                     BuildStreamVideoItem(playlistItem, options, item, videoStream, audioStream, candidateAudioStreams, transcodingProfile.Container, transcodingProfile.VideoCodec, transcodingProfile.AudioCodec);
 
+                    playlistItem.PlayMethod = PlayMethod.Transcode;
+
                     if (subtitleStream != null)
                     {
                         var subtitleProfile = GetSubtitleProfile(item, subtitleStream, options.Profile.SubtitleProfiles, PlayMethod.Transcode, _transcoderSupport, transcodingProfile.Container, transcodingProfile.Protocol);
@@ -696,14 +698,9 @@ namespace MediaBrowser.Model.Dlna
                         playlistItem.SubtitleCodecs = new[] { subtitleProfile.Format };
                     }
 
-                    if (playlistItem.PlayMethod != PlayMethod.DirectPlay)
+                    if ((playlistItem.TranscodeReasons & (VideoReasons | TranscodeReason.ContainerBitrateExceedsLimit)) != 0)
                     {
-                        playlistItem.PlayMethod = PlayMethod.Transcode;
-
-                        if ((playlistItem.TranscodeReasons & (VideoReasons | TranscodeReason.ContainerBitrateExceedsLimit)) != 0)
-                        {
-                            ApplyTranscodingConditions(playlistItem, transcodingProfile.Conditions, null, true, true);
-                        }
+                        ApplyTranscodingConditions(playlistItem, transcodingProfile.Conditions, null, true, true);
                     }
                 }
             }
@@ -771,12 +768,12 @@ namespace MediaBrowser.Model.Dlna
 
         private void BuildStreamVideoItem(StreamInfo playlistItem, VideoOptions options, MediaSourceInfo item, MediaStream videoStream, MediaStream audioStream, IEnumerable<MediaStream> candidateAudioStreams, string container, string videoCodec, string audioCodec)
         {
-            // prefer matching video codecs
+            // Prefer matching video codecs
             var videoCodecs = ContainerProfile.SplitValue(videoCodec);
             var directVideoCodec = ContainerProfile.ContainsContainer(videoCodecs, videoStream?.Codec) ? videoStream?.Codec : null;
             playlistItem.VideoCodecs = directVideoCodec != null ? new[] { directVideoCodec } : videoCodecs;
 
-            // copy video codec options as a starting point, this applies to transcode and direct-stream
+            // Copy video codec options as a starting point, this applies to transcode and direct-stream
             playlistItem.MaxFramerate = videoStream?.AverageFrameRate;
             var qualifier = videoStream?.Codec;
             if (videoStream?.Level != null)
@@ -799,7 +796,7 @@ namespace MediaBrowser.Model.Dlna
                 playlistItem.SetOption(qualifier, "level", videoStream.Level.ToString());
             }
 
-            // prefer matching audio codecs, could do better here
+            // Prefer matching audio codecs, could do better here
             var audioCodecs = ContainerProfile.SplitValue(audioCodec);
             var directAudioStream = candidateAudioStreams.FirstOrDefault(stream => ContainerProfile.ContainsContainer(audioCodecs, stream.Codec));
             playlistItem.AudioCodecs = audioCodecs;
@@ -809,7 +806,7 @@ namespace MediaBrowser.Model.Dlna
                 playlistItem.AudioStreamIndex = audioStream.Index;
                 playlistItem.AudioCodecs = new[] { audioStream.Codec };
 
-                // copy matching audio codec options
+                // Copy matching audio codec options
                 playlistItem.AudioSampleRate = audioStream.SampleRate;
                 playlistItem.SetOption(qualifier, "audiochannels", audioStream.Channels.ToString());
 
@@ -1070,7 +1067,7 @@ namespace MediaBrowser.Model.Dlna
             DeviceProfile profile = options.Profile;
             string container = mediaSource.Container;
 
-            // video
+            // Video
             int? width = videoStream?.Width;
             int? height = videoStream?.Height;
             int? bitDepth = videoStream?.BitDepth;
@@ -1082,7 +1079,7 @@ namespace MediaBrowser.Model.Dlna
             bool? isInterlaced = videoStream?.IsInterlaced;
             string videoCodecTag = videoStream?.CodecTag;
             bool? isAvc = videoStream?.IsAVC;
-            // audio
+            // Audio
             var defaultLanguage = audioStream?.Language ?? string.Empty;
             var defaultMarked = audioStream?.IsDefault ?? false;
 
@@ -1211,6 +1208,7 @@ namespace MediaBrowser.Model.Dlna
                     return (Result: (Profile: directPlayProfile, PlayMethod: playMethod, AudioStreamIndex: selectedAudioStream?.Index, TranscodeReason: failureReasons), Order: order, Rank: ranked);
                 })
                 .OrderByDescending(analysis => analysis.Result.PlayMethod)
+                .ThenByDescending(analysis => analysis.Rank)
                 .ThenBy(analysis => analysis.Order)
                 .ToArray()
                 .ToLookup(analysis => analysis.Result.PlayMethod != null);
@@ -1223,7 +1221,7 @@ namespace MediaBrowser.Model.Dlna
                 return profileMatch;
             }
 
-            var failureReasons = analyzedProfiles[false].OrderBy(a => a.Result.TranscodeReason).ThenBy(analysis => analysis.Order).FirstOrDefault().Result.TranscodeReason;
+            var failureReasons = analyzedProfiles[false].Select(analysis => analysis.Result).FirstOrDefault().TranscodeReason;
             if (failureReasons == 0)
             {
                 failureReasons = TranscodeReason.DirectPlayError;
@@ -1269,13 +1267,13 @@ namespace MediaBrowser.Model.Dlna
                 mediaSource.Path ?? "Unknown path");
         }
 
-        private TranscodeReason IsEligibleForDirectPlay(
+        private TranscodeReason IsBitrateEligibleForDirectPlayback(
             MediaSourceInfo item,
             long maxBitrate,
             VideoOptions options,
             PlayMethod playMethod)
         {
-            bool result = IsItemBitrateEligibleForDirectPlay(item, maxBitrate, playMethod);
+            bool result = IsItemBitrateEligibleForDirectPlayback(item, maxBitrate, playMethod);
             if (!result)
             {
                 return TranscodeReason.ContainerBitrateExceedsLimit;
@@ -1443,7 +1441,7 @@ namespace MediaBrowser.Model.Dlna
             return null;
         }
 
-        private bool IsItemBitrateEligibleForDirectPlay(MediaSourceInfo item, long maxBitrate, PlayMethod playMethod)
+        private bool IsItemBitrateEligibleForDirectPlayback(MediaSourceInfo item, long maxBitrate, PlayMethod playMethod)
         {
             // Don't restrict by bitrate if coming from an external domain
             if (item.IsRemote)

+ 28 - 21
tests/Jellyfin.Model.Tests/Dlna/StreamBuilderTests.cs

@@ -27,7 +27,7 @@ namespace Jellyfin.Model.Tests
         [InlineData("Chrome", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
         [InlineData("Chrome", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")]
         [InlineData("Chrome", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")]
-        [InlineData("Chrome", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
+        [InlineData("Chrome", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.ContainerNotSupported)] // #6450
         [InlineData("Chrome", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
         [InlineData("Chrome", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] // #6450
         // Firefox
@@ -38,7 +38,7 @@ namespace Jellyfin.Model.Tests
         [InlineData("Firefox", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
         [InlineData("Firefox", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")]
         [InlineData("Firefox", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")]
-        [InlineData("Firefox", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
+        [InlineData("Firefox", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.ContainerNotSupported)] // #6450
         [InlineData("Firefox", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
         [InlineData("Firefox", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] // #6450
         // Safari
@@ -89,7 +89,7 @@ namespace Jellyfin.Model.Tests
         [InlineData("Chrome-NoHLS", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
         [InlineData("Chrome-NoHLS", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode", "http")]
         [InlineData("Chrome-NoHLS", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode", "http")]
-        [InlineData("Chrome-NoHLS", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
+        [InlineData("Chrome-NoHLS", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.ContainerNotSupported)] // #6450
         [InlineData("Chrome-NoHLS", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
         [InlineData("Chrome-NoHLS", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] // #6450
         // TranscodeMedia
@@ -177,7 +177,7 @@ namespace Jellyfin.Model.Tests
         [InlineData("Chrome", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
         [InlineData("Chrome", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")]
         [InlineData("Chrome", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")]
-        [InlineData("Chrome", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
+        [InlineData("Chrome", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.ContainerNotSupported)] // #6450
         [InlineData("Chrome", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
         [InlineData("Chrome", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] // #6450
         // Firefox
@@ -187,7 +187,7 @@ namespace Jellyfin.Model.Tests
         [InlineData("Firefox", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
         [InlineData("Firefox", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")]
         [InlineData("Firefox", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")]
-        [InlineData("Firefox", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
+        [InlineData("Firefox", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.ContainerNotSupported)] // #6450
         [InlineData("Firefox", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
         [InlineData("Firefox", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] // #6450
         // Safari
@@ -338,23 +338,23 @@ namespace Jellyfin.Model.Tests
             Assert.NotNull(mediaSource);
             var videoStreams = mediaSource.MediaStreams.Where(stream => stream.Type == MediaStreamType.Video);
             var audioStreams = mediaSource.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio);
-            // TODO: check AudioStreamIndex vs options.AudioStreamIndex
+            // TODO: Check AudioStreamIndex vs options.AudioStreamIndex
             var inputAudioStream = mediaSource.GetDefaultAudioStream(audioStreamIndexInput ?? mediaSource.DefaultAudioStreamIndex);
 
             var uri = ParseUri(val);
 
             if (playMethod == PlayMethod.DirectPlay)
             {
-                // check expected container
+                // Check expected container
                 var containers = ContainerProfile.SplitValue(mediaSource.Container);
-                // TODO: test transcode too
+                // TODO: Test transcode too
                 // Assert.Contains(uri.Extension, containers);
 
-                // check expected video codec (1)
+                // Check expected video codec (1)
                 Assert.Contains(targetVideoStream.Codec, val.TargetVideoCodec);
                 Assert.Single(val.TargetVideoCodec);
 
-                // check expected audio codecs (1)
+                // Check expected audio codecs (1)
                 Assert.Contains(targetAudioStream.Codec, val.TargetAudioCodec);
                 Assert.Single(val.TargetAudioCodec);
                 // Assert.Single(val.AudioCodecs);
@@ -370,7 +370,7 @@ namespace Jellyfin.Model.Tests
                 Assert.NotEmpty(val.VideoCodecs);
                 Assert.NotEmpty(val.AudioCodecs);
 
-                // check expected container (todo: this could be a test param)
+                // Check expected container (todo: this could be a test param)
                 if (transcodeProtocol == "http")
                 {
                     // Assert.Equal("webm", val.Container);
@@ -403,32 +403,39 @@ namespace Jellyfin.Model.Tests
                             stream => Assert.DoesNotContain(stream.Codec, val.VideoCodecs));
                     }
 
-                    // todo: fill out tests here
+                    // TODO: Fill out tests here
                 }
 
                 // DirectStream and Remux
                 else
                 {
-                    // check expected video codec (1)
+                    // Check expected video codec (1)
                     Assert.Contains(targetVideoStream.Codec, val.TargetVideoCodec);
                     Assert.Single(val.TargetVideoCodec);
 
                     if (transcodeMode == "DirectStream")
                     {
+                        // Check expected audio codecs (1)
                         if (!targetAudioStream.IsExternal)
                         {
-                            // check expected audio codecs (1)
-                            Assert.DoesNotContain(targetAudioStream.Codec, val.AudioCodecs);
+                            if (val.TranscodeReasons.HasFlag(TranscodeReason.ContainerNotSupported))
+                            {
+                                Assert.Contains(targetAudioStream.Codec, val.AudioCodecs);
+                            }
+                            else
+                            {
+                                Assert.DoesNotContain(targetAudioStream.Codec, val.AudioCodecs);
+                            }
                         }
                     }
                     else if (transcodeMode == "Remux")
                     {
-                        // check expected audio codecs (1)
+                        // Check expected audio codecs (1)
                         Assert.Contains(targetAudioStream.Codec, val.AudioCodecs);
                         Assert.Single(val.AudioCodecs);
                     }
 
-                    // video details
+                    // Video details
                     var videoStream = targetVideoStream;
                     Assert.False(val.EstimateContentLength);
                     Assert.Equal(TranscodeSeekInfo.Auto, val.TranscodeSeekInfo);
@@ -437,10 +444,10 @@ namespace Jellyfin.Model.Tests
                     Assert.Equal(videoStream.BitDepth, val.TargetVideoBitDepth);
                     Assert.InRange(val.VideoBitrate.GetValueOrDefault(), videoStream.BitRate.GetValueOrDefault(), int.MaxValue);
 
-                    // audio codec not supported
+                    // Audio codec not supported
                     if ((why & TranscodeReason.AudioCodecNotSupported) != 0)
                     {
-                        // audio stream specified
+                        // Audio stream specified
                         if (options.AudioStreamIndex >= 0)
                         {
                             // TODO:fixme
@@ -450,10 +457,10 @@ namespace Jellyfin.Model.Tests
                             }
                         }
 
-                        // audio stream not specified
+                        // Audio stream not specified
                         else
                         {
-                            // TODO:fixme
+                            // TODO: Fixme
                             Assert.All(audioStreams, stream =>
                             {
                                 if (!stream.IsExternal)

+ 4 - 4
tests/Jellyfin.Model.Tests/Test Data/DeviceProfile-Tizen3-stereo.json

@@ -45,8 +45,8 @@
         },
         {
             "Container": "wmv",
-            "AudioCodec": "",
-            "VideoCodec": "",
+            "AudioCodec": "wma",
+            "VideoCodec": "wmv,vc1",
             "Type": "Video",
             "$type": "DirectPlayProfile"
         },
@@ -59,8 +59,8 @@
         },
         {
             "Container": "asf",
-            "AudioCodec": "",
-            "VideoCodec": "",
+            "AudioCodec": "wma",
+            "VideoCodec": "wmv,vc1",
             "Type": "Video",
             "$type": "DirectPlayProfile"
         },

+ 4 - 4
tests/Jellyfin.Model.Tests/Test Data/DeviceProfile-Tizen4-4K-5.1.json

@@ -45,8 +45,8 @@
         },
         {
             "Container": "wmv",
-            "AudioCodec": "",
-            "VideoCodec": "",
+            "AudioCodec": "wma",
+            "VideoCodec": "wmv,vc1",
             "Type": "Video",
             "$type": "DirectPlayProfile"
         },
@@ -59,8 +59,8 @@
         },
         {
             "Container": "asf",
-            "AudioCodec": "",
-            "VideoCodec": "",
+            "AudioCodec": "wma",
+            "VideoCodec": "wmv,vc1",
             "Type": "Video",
             "$type": "DirectPlayProfile"
         },