diff options
Diffstat (limited to 'MediaBrowser.Model/Dlna')
| -rw-r--r-- | MediaBrowser.Model/Dlna/ConditionProcessor.cs | 3 | ||||
| -rw-r--r-- | MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs | 6 | ||||
| -rw-r--r-- | MediaBrowser.Model/Dlna/DeviceProfile.cs | 4 | ||||
| -rw-r--r-- | MediaBrowser.Model/Dlna/ProfileConditionValue.cs | 3 | ||||
| -rw-r--r-- | MediaBrowser.Model/Dlna/StreamBuilder.cs | 162 | ||||
| -rw-r--r-- | MediaBrowser.Model/Dlna/StreamInfo.cs | 24 |
6 files changed, 138 insertions, 64 deletions
diff --git a/MediaBrowser.Model/Dlna/ConditionProcessor.cs b/MediaBrowser.Model/Dlna/ConditionProcessor.cs index 8d03b4c0b3..5734224167 100644 --- a/MediaBrowser.Model/Dlna/ConditionProcessor.cs +++ b/MediaBrowser.Model/Dlna/ConditionProcessor.cs @@ -16,6 +16,7 @@ namespace MediaBrowser.Model.Dlna int? videoBitDepth, int? videoBitrate, string? videoProfile, + string? videoRangeType, double? videoLevel, float? videoFramerate, int? packetLength, @@ -42,6 +43,8 @@ namespace MediaBrowser.Model.Dlna return IsConditionSatisfied(condition, videoLevel); case ProfileConditionValue.VideoProfile: return IsConditionSatisfied(condition, videoProfile); + case ProfileConditionValue.VideoRangeType: + return IsConditionSatisfied(condition, videoRangeType); case ProfileConditionValue.VideoCodecTag: return IsConditionSatisfied(condition, videoCodecTag); case ProfileConditionValue.PacketLength: diff --git a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs index 6e129246b0..1a95763610 100644 --- a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs +++ b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs @@ -8,7 +8,7 @@ using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.Model.Dlna { - public class ContentFeatureBuilder + public static class ContentFeatureBuilder { public static string BuildImageHeader( DeviceProfile profile, @@ -128,6 +128,7 @@ namespace MediaBrowser.Model.Dlna bool isDirectStream, long? runtimeTicks, string videoProfile, + string videoRangeType, double? videoLevel, float? videoFramerate, int? packetLength, @@ -156,7 +157,7 @@ namespace MediaBrowser.Model.Dlna flagValue |= DlnaFlags.ByteBasedSeek; } - // Time based seek is curently disabled when streaming. On LG CX3 adding DlnaFlags.TimeBasedSeek and orgPn causes the DLNA playback to fail (format not supported). Further investigations are needed before enabling the remaining code paths. + // Time based seek is currently disabled when streaming. On LG CX3 adding DlnaFlags.TimeBasedSeek and orgPn causes the DLNA playback to fail (format not supported). Further investigations are needed before enabling the remaining code paths. // else if (runtimeTicks.HasValue) // { // flagValue = flagValue | DlnaFlags.TimeBasedSeek; @@ -176,6 +177,7 @@ namespace MediaBrowser.Model.Dlna bitDepth, videoBitrate, videoProfile, + videoRangeType, videoLevel, videoFramerate, packetLength, diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs index 6170ff5bd6..79ae951708 100644 --- a/MediaBrowser.Model/Dlna/DeviceProfile.cs +++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs @@ -423,6 +423,7 @@ namespace MediaBrowser.Model.Dlna /// <param name="bitDepth">The bit depth.</param> /// <param name="videoBitrate">The video bitrate.</param> /// <param name="videoProfile">The video profile.</param> + /// <param name="videoRangeType">The video range type.</param> /// <param name="videoLevel">The video level.</param> /// <param name="videoFramerate">The video framerate.</param> /// <param name="packetLength">The packet length.</param> @@ -444,6 +445,7 @@ namespace MediaBrowser.Model.Dlna int? bitDepth, int? videoBitrate, string videoProfile, + string videoRangeType, double? videoLevel, float? videoFramerate, int? packetLength, @@ -483,7 +485,7 @@ namespace MediaBrowser.Model.Dlna var anyOff = false; foreach (ProfileCondition c in i.Conditions) { - if (!ConditionProcessor.IsVideoConditionSatisfied(GetModelProfileCondition(c), width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)) + if (!ConditionProcessor.IsVideoConditionSatisfied(GetModelProfileCondition(c), width, height, bitDepth, videoBitrate, videoProfile, videoRangeType, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)) { anyOff = true; break; diff --git a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs index eb81fde751..a32433e185 100644 --- a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs +++ b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs @@ -26,6 +26,7 @@ namespace MediaBrowser.Model.Dlna IsAvc = 20, IsInterlaced = 21, AudioSampleRate = 22, - AudioBitDepth = 23 + AudioBitDepth = 23, + VideoRangeType = 24 } } diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 8671e5cbbf..b121a29058 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -221,6 +221,9 @@ namespace MediaBrowser.Model.Dlna case ProfileConditionValue.VideoProfile: return TranscodeReason.VideoProfileNotSupported; + case ProfileConditionValue.VideoRangeType: + return TranscodeReason.VideoRangeTypeNotSupported; + case ProfileConditionValue.VideoTimestamp: // TODO return 0; @@ -385,7 +388,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 +404,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) { @@ -562,10 +565,7 @@ namespace MediaBrowser.Model.Dlna private StreamInfo BuildVideoItem(MediaSourceInfo item, VideoOptions options) { - if (item == null) - { - throw new ArgumentNullException(nameof(item)); - } + ArgumentNullException.ThrowIfNull(item); StreamInfo playlistItem = new StreamInfo { @@ -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); } } } @@ -744,16 +741,19 @@ namespace MediaBrowser.Model.Dlna { var videoCodecs = ContainerProfile.SplitValue(transcodingProfile.VideoCodec); - if (ContainerProfile.ContainsContainer(videoCodecs, item.VideoStream.Codec)) + if (ContainerProfile.ContainsContainer(videoCodecs, item.VideoStream?.Codec)) { var videoCodec = transcodingProfile.VideoCodec; var container = transcodingProfile.Container; var appliedVideoConditions = options.Profile.CodecProfiles .Where(i => i.Type == CodecType.Video && - i.ContainsAnyCodec(videoCodec, container)) + i.ContainsAnyCodec(videoCodec, container) && + i.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoConditionSatisfied(applyCondition, videoStream?.Width, videoStream?.Height, videoStream?.BitDepth, videoStream?.BitRate, videoStream?.Profile, videoStream?.VideoRangeType, videoStream?.Level, videoFramerate, videoStream?.PacketLength, timestamp, videoStream?.IsAnamorphic, videoStream?.IsInterlaced, videoStream?.RefFrames, numVideoStreams, numAudioStreams, videoStream?.CodecTag, videoStream?.IsAVC))) .Select(i => - i.ApplyConditions.Any(applyCondition => ConditionProcessor.IsVideoConditionSatisfied(applyCondition, videoStream?.Width, videoStream?.Height, videoStream?.BitDepth, videoStream?.BitRate, videoStream?.Profile, videoStream?.Level, videoFramerate, videoStream?.PacketLength, timestamp, videoStream?.IsAnamorphic, videoStream?.IsInterlaced, videoStream?.RefFrames, numVideoStreams, numAudioStreams, videoStream?.CodecTag, videoStream?.IsAVC))); - var conditionsSatisfied = !appliedVideoConditions.Any() || !appliedVideoConditions.Any(satisfied => !satisfied); + i.Conditions.All(condition => ConditionProcessor.IsVideoConditionSatisfied(condition, videoStream?.Width, videoStream?.Height, videoStream?.BitDepth, videoStream?.BitRate, videoStream?.Profile, videoStream?.VideoRangeType, videoStream?.Level, videoFramerate, videoStream?.PacketLength, timestamp, videoStream?.IsAnamorphic, videoStream?.IsInterlaced, videoStream?.RefFrames, numVideoStreams, numAudioStreams, videoStream?.CodecTag, videoStream?.IsAVC))); + + // An empty appliedVideoConditions means that the codec has no conditions for the current video stream + var conditionsSatisfied = appliedVideoConditions.All(satisfied => satisfied); return conditionsSatisfied ? 1 : 2; } @@ -768,35 +768,42 @@ 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; + var directVideoCodec = ContainerProfile.ContainsContainer(videoCodecs, videoStream?.Codec) ? videoStream?.Codec : null; + if (directVideoCodec != null) + { + // merge directVideoCodec to videoCodecs + Array.Resize(ref videoCodecs, videoCodecs.Length + 1); + videoCodecs[^1] = directVideoCodec; + } + + playlistItem.VideoCodecs = videoCodecs; - // 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.HasValue) + // 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) { playlistItem.SetOption(qualifier, "level", videoStream.Level.Value.ToString(CultureInfo.InvariantCulture)); } - if (videoStream.BitDepth.HasValue) + if (videoStream?.BitDepth != null) { playlistItem.SetOption(qualifier, "videobitdepth", videoStream.BitDepth.Value.ToString(CultureInfo.InvariantCulture)); } - if (!string.IsNullOrEmpty(videoStream.Profile)) + if (!string.IsNullOrEmpty(videoStream?.Profile)) { playlistItem.SetOption(qualifier, "profile", videoStream.Profile.ToLowerInvariant()); } - if (videoStream.Level != 0) + if (videoStream != null && videoStream.Level != 0) { 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; @@ -806,7 +813,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()); @@ -827,6 +834,7 @@ namespace MediaBrowser.Model.Dlna int? videoBitrate = videoStream?.BitRate; double? videoLevel = videoStream?.Level; string videoProfile = videoStream?.Profile; + string videoRangeType = videoStream?.VideoRangeType; float videoFramerate = videoStream == null ? 0 : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate ?? 0; bool? isAnamorphic = videoStream?.IsAnamorphic; bool? isInterlaced = videoStream?.IsInterlaced; @@ -843,7 +851,7 @@ namespace MediaBrowser.Model.Dlna var appliedVideoConditions = options.Profile.CodecProfiles .Where(i => i.Type == CodecType.Video && i.ContainsAnyCodec(videoCodec, container) && - i.ApplyConditions.Any(applyCondition => ConditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))); + i.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoRangeType, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))); var isFirstAppliedCodecProfile = true; foreach (var i in appliedVideoConditions) { @@ -873,9 +881,9 @@ namespace MediaBrowser.Model.Dlna int? inputAudioBitDepth = audioStream == null ? null : audioStream.BitDepth; var appliedAudioConditions = options.Profile.CodecProfiles - .Where(i => i.Type == CodecType.Video && + .Where(i => i.Type == CodecType.VideoAudio && i.ContainsAnyCodec(audioCodec, container) && - i.ApplyConditions.Any(applyCondition => ConditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth, audioProfile, isSecondaryAudio))); + i.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth, audioProfile, isSecondaryAudio))); isFirstAppliedCodecProfile = true; foreach (var i in appliedAudioConditions) { @@ -1067,19 +1075,20 @@ 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; int? videoBitrate = videoStream?.BitRate; double? videoLevel = videoStream?.Level; string videoProfile = videoStream?.Profile; + string videoRangeType = videoStream?.VideoRangeType; float videoFramerate = videoStream == null ? 0 : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate ?? 0; bool? isAnamorphic = videoStream?.IsAnamorphic; 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; @@ -1091,7 +1100,7 @@ namespace MediaBrowser.Model.Dlna int? numVideoStreams = mediaSource.GetStreamCount(MediaStreamType.Video); var checkVideoConditions = (ProfileCondition[] conditions) => - conditions.Where(applyCondition => !ConditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)); + conditions.Where(applyCondition => !ConditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoRangeType, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)); // Check container conditions var containerProfileReasons = AggregateFailureConditions( @@ -1108,18 +1117,9 @@ namespace MediaBrowser.Model.Dlna profile, "VideoCodecProfile", profile.CodecProfiles - .Where(codecProfile => codecProfile.Type == CodecType.Video && codecProfile.ContainsAnyCodec(videoStream?.Codec, container)) - .SelectMany(codecProfile => - { - var failedApplyConditions = checkVideoConditions(codecProfile.ApplyConditions); - if (!failedApplyConditions.Any()) - { - return Array.Empty<ProfileCondition>(); - } - - var failedConditions = checkVideoConditions(codecProfile.Conditions); - return failedApplyConditions.Concat(failedConditions); - })); + .Where(codecProfile => codecProfile.Type == CodecType.Video && codecProfile.ContainsAnyCodec(videoStream?.Codec, container) && + !checkVideoConditions(codecProfile.ApplyConditions).Any()) + .SelectMany(codecProfile => checkVideoConditions(codecProfile.Conditions))); // Check audiocandidates profile conditions var audioStreamMatches = candidateAudioStreams.ToDictionary(s => s, audioStream => CheckVideoAudioStreamDirectPlay(options, mediaSource, container, audioStream, defaultLanguage, defaultMarked)); @@ -1189,7 +1189,18 @@ namespace MediaBrowser.Model.Dlna audioCodecProfileReasons = audioStreamMatches.GetValueOrDefault(selectedAudioStream); } - var failureReasons = directPlayProfileReasons | containerProfileReasons | videoCodecProfileReasons | audioCodecProfileReasons | subtitleProfileReasons; + var failureReasons = directPlayProfileReasons | containerProfileReasons | subtitleProfileReasons; + + if ((failureReasons & TranscodeReason.VideoCodecNotSupported) == 0) + { + failureReasons |= videoCodecProfileReasons; + } + + if ((failureReasons & TranscodeReason.AudioCodecNotSupported) == 0) + { + failureReasons |= audioCodecProfileReasons; + } + var directStreamFailureReasons = failureReasons & (~DirectStreamReasons); PlayMethod? playMethod = null; @@ -1206,6 +1217,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); @@ -1218,7 +1230,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; @@ -1264,13 +1276,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; @@ -1438,7 +1450,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) @@ -1842,6 +1854,38 @@ namespace MediaBrowser.Model.Dlna break; } + case ProfileConditionValue.VideoRangeType: + { + if (string.IsNullOrEmpty(qualifier)) + { + continue; + } + + // change from split by | to comma + // strip spaces to avoid having to encode + var values = value + .Split('|', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); + + if (condition.Condition == ProfileConditionType.Equals) + { + item.SetOption(qualifier, "rangetype", string.Join(',', values)); + } + else if (condition.Condition == ProfileConditionType.EqualsAny) + { + var currentValue = item.GetOption(qualifier, "rangetype"); + if (!string.IsNullOrEmpty(currentValue) && values.Any(v => string.Equals(v, currentValue, StringComparison.OrdinalIgnoreCase))) + { + item.SetOption(qualifier, "rangetype", currentValue); + } + else + { + item.SetOption(qualifier, "rangetype", string.Join(',', values)); + } + } + + break; + } + case ProfileConditionValue.Height: { if (!enableNonQualifiedConditions) diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index da089602f1..5cfa2e7e3c 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.Linq; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; @@ -281,6 +280,29 @@ namespace MediaBrowser.Model.Dlna } /// <summary> + /// Gets the target video range type that will be in the output stream. + /// </summary> + public string TargetVideoRangeType + { + get + { + if (IsDirectStream) + { + return TargetVideoStream?.VideoRangeType; + } + + var targetVideoCodecs = TargetVideoCodec; + var videoCodec = targetVideoCodecs.Length == 0 ? null : targetVideoCodecs[0]; + if (!string.IsNullOrEmpty(videoCodec)) + { + return GetOption(videoCodec, "rangetype"); + } + + return TargetVideoStream?.VideoRangeType; + } + } + + /// <summary> /// Gets the target video codec tag. /// </summary> /// <value>The target video codec tag.</value> |
