diff options
Diffstat (limited to 'MediaBrowser.Model/Dlna')
| -rw-r--r-- | MediaBrowser.Model/Dlna/ConditionProcessor.cs | 13 | ||||
| -rw-r--r-- | MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs | 4 | ||||
| -rw-r--r-- | MediaBrowser.Model/Dlna/DeviceProfile.cs | 4 | ||||
| -rw-r--r-- | MediaBrowser.Model/Dlna/ProfileCondition.cs | 1 | ||||
| -rw-r--r-- | MediaBrowser.Model/Dlna/ProfileConditionValue.cs | 3 | ||||
| -rw-r--r-- | MediaBrowser.Model/Dlna/StreamBuilder.cs | 289 | ||||
| -rw-r--r-- | MediaBrowser.Model/Dlna/StreamInfo.cs | 32 |
7 files changed, 296 insertions, 50 deletions
diff --git a/MediaBrowser.Model/Dlna/ConditionProcessor.cs b/MediaBrowser.Model/Dlna/ConditionProcessor.cs index a388bf98b..291096f75 100644 --- a/MediaBrowser.Model/Dlna/ConditionProcessor.cs +++ b/MediaBrowser.Model/Dlna/ConditionProcessor.cs @@ -12,7 +12,7 @@ namespace MediaBrowser.Model.Dlna public bool IsVideoConditionSatisfied(ProfileCondition condition, int? width, int? height, - int? bitDepth, + int? videoBitDepth, int? videoBitrate, string videoProfile, double? videoLevel, @@ -46,7 +46,7 @@ namespace MediaBrowser.Model.Dlna case ProfileConditionValue.PacketLength: return IsConditionSatisfied(condition, packetLength); case ProfileConditionValue.VideoBitDepth: - return IsConditionSatisfied(condition, bitDepth); + return IsConditionSatisfied(condition, videoBitDepth); case ProfileConditionValue.VideoBitrate: return IsConditionSatisfied(condition, videoBitrate); case ProfileConditionValue.Height: @@ -79,7 +79,7 @@ namespace MediaBrowser.Model.Dlna } } - public bool IsAudioConditionSatisfied(ProfileCondition condition, int? audioChannels, int? audioBitrate, int? audioSampleRate) + public bool IsAudioConditionSatisfied(ProfileCondition condition, int? audioChannels, int? audioBitrate, int? audioSampleRate, int? audioBitDepth) { switch (condition.Property) { @@ -89,6 +89,8 @@ namespace MediaBrowser.Model.Dlna return IsConditionSatisfied(condition, audioChannels); case ProfileConditionValue.AudioSampleRate: return IsConditionSatisfied(condition, audioSampleRate); + case ProfileConditionValue.AudioBitDepth: + return IsConditionSatisfied(condition, audioBitDepth); default: throw new ArgumentException("Unexpected condition on audio file: " + condition.Property); } @@ -97,7 +99,8 @@ namespace MediaBrowser.Model.Dlna public bool IsVideoAudioConditionSatisfied(ProfileCondition condition, int? audioChannels, int? audioBitrate, - int? audioSampleRate, + int? audioSampleRate, + int? audioBitDepth, string audioProfile, bool? isSecondaryTrack) { @@ -113,6 +116,8 @@ namespace MediaBrowser.Model.Dlna return IsConditionSatisfied(condition, isSecondaryTrack); case ProfileConditionValue.AudioSampleRate: return IsConditionSatisfied(condition, audioSampleRate); + case ProfileConditionValue.AudioBitDepth: + return IsConditionSatisfied(condition, audioBitDepth); default: throw new ArgumentException("Unexpected condition on audio file: " + condition.Property); } diff --git a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs index 6f6994a7e..8a9dc1dd1 100644 --- a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs +++ b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs @@ -55,6 +55,7 @@ namespace MediaBrowser.Model.Dlna int? audioBitrate, int? audioSampleRate, int? audioChannels, + int? audioBitDepth, bool isDirectStream, long? runtimeTicks, TranscodeSeekInfo transcodeSeekInfo) @@ -86,7 +87,8 @@ namespace MediaBrowser.Model.Dlna audioCodec, audioChannels, audioBitrate, - audioSampleRate); + audioSampleRate, + audioBitDepth); string orgPn = mediaProfile == null ? null : mediaProfile.OrgPn; diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs index 33d73e3bb..cd7ff08d6 100644 --- a/MediaBrowser.Model/Dlna/DeviceProfile.cs +++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs @@ -185,7 +185,7 @@ namespace MediaBrowser.Model.Dlna return null; } - public ResponseProfile GetAudioMediaProfile(string container, string audioCodec, int? audioChannels, int? audioBitrate, int? audioSampleRate) + public ResponseProfile GetAudioMediaProfile(string container, string audioCodec, int? audioChannels, int? audioBitrate, int? audioSampleRate, int? audioBitDepth) { container = StringHelper.TrimStart(container ?? string.Empty, '.'); @@ -213,7 +213,7 @@ namespace MediaBrowser.Model.Dlna var anyOff = false; foreach (ProfileCondition c in i.Conditions) { - if (!conditionProcessor.IsAudioConditionSatisfied(GetModelProfileCondition(c), audioChannels, audioBitrate, audioSampleRate)) + if (!conditionProcessor.IsAudioConditionSatisfied(GetModelProfileCondition(c), audioChannels, audioBitrate, audioSampleRate, audioBitDepth)) { anyOff = true; break; diff --git a/MediaBrowser.Model/Dlna/ProfileCondition.cs b/MediaBrowser.Model/Dlna/ProfileCondition.cs index 3d104f9c4..9234a2713 100644 --- a/MediaBrowser.Model/Dlna/ProfileCondition.cs +++ b/MediaBrowser.Model/Dlna/ProfileCondition.cs @@ -1,5 +1,4 @@ using System.Xml.Serialization; -using MediaBrowser.Model.Dlna; namespace MediaBrowser.Model.Dlna { diff --git a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs index 208a7df7e..a96e9ac36 100644 --- a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs +++ b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs @@ -23,6 +23,7 @@ VideoCodecTag = 19, IsAvc = 20, IsInterlaced = 21, - AudioSampleRate = 22 + AudioSampleRate = 22, + AudioBitDepth = 23 } }
\ No newline at end of file diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 0ecc413f2..342796a10 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -105,8 +105,102 @@ namespace MediaBrowser.Model.Dlna return null; } + private TranscodeReason? GetTranscodeReasonForFailedCondition(ProfileCondition condition) + { + switch (condition.Property) + { + case ProfileConditionValue.AudioBitrate: + if (condition.Condition == ProfileConditionType.LessThanEqual) + { + return TranscodeReason.AudioBitrateNotSupported; + } + return TranscodeReason.AudioBitrateNotSupported; + + case ProfileConditionValue.AudioChannels: + if (condition.Condition == ProfileConditionType.LessThanEqual) + { + return TranscodeReason.AudioChannelsNotSupported; + } + return TranscodeReason.AudioChannelsNotSupported; + + case ProfileConditionValue.AudioProfile: + return TranscodeReason.AudioProfileNotSupported; + + case ProfileConditionValue.AudioSampleRate: + return TranscodeReason.AudioSampleRateNotSupported; + + case ProfileConditionValue.Has64BitOffsets: + // TODO + return null; + + case ProfileConditionValue.Height: + return TranscodeReason.VideoResolutionNotSupported; + + case ProfileConditionValue.IsAnamorphic: + return TranscodeReason.AnamorphicVideoNotSupported; + + case ProfileConditionValue.IsAvc: + // TODO + return null; + + case ProfileConditionValue.IsInterlaced: + return TranscodeReason.InterlacedVideoNotSupported; + + case ProfileConditionValue.IsSecondaryAudio: + return TranscodeReason.SecondaryAudioNotSupported; + + case ProfileConditionValue.NumAudioStreams: + // TODO + return null; + + case ProfileConditionValue.NumVideoStreams: + // TODO + return null; + + case ProfileConditionValue.PacketLength: + // TODO + return null; + + case ProfileConditionValue.RefFrames: + return TranscodeReason.RefFramesNotSupported; + + case ProfileConditionValue.VideoBitDepth: + return TranscodeReason.VideoBitDepthNotSupported; + + case ProfileConditionValue.AudioBitDepth: + return TranscodeReason.AudioBitDepthNotSupported; + + case ProfileConditionValue.VideoBitrate: + return TranscodeReason.VideoBitrateNotSupported; + + case ProfileConditionValue.VideoCodecTag: + return TranscodeReason.VideoCodecNotSupported; + + case ProfileConditionValue.VideoFramerate: + return TranscodeReason.VideoFramerateNotSupported; + + case ProfileConditionValue.VideoLevel: + return TranscodeReason.VideoLevelNotSupported; + + case ProfileConditionValue.VideoProfile: + return TranscodeReason.VideoProfileNotSupported; + + case ProfileConditionValue.VideoTimestamp: + // TODO + return null; + + case ProfileConditionValue.Width: + return TranscodeReason.VideoResolutionNotSupported; + + default: + return null; + } + } + private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options) { + List<TranscodeReason> transcodeReasons = new List<TranscodeReason>(); + StreamInfo playlistItem = new StreamInfo { ItemId = options.ItemId, @@ -133,13 +227,17 @@ namespace MediaBrowser.Model.Dlna MediaStream audioStream = item.GetDefaultAudioStream(null); - List<PlayMethod> directPlayMethods = GetAudioDirectPlayMethods(item, audioStream, options); + var directPlayInfo = GetAudioDirectPlayMethods(item, audioStream, options); + + List<PlayMethod> directPlayMethods = directPlayInfo.Item1; + transcodeReasons.AddRange(directPlayInfo.Item2); ConditionProcessor conditionProcessor = new ConditionProcessor(); int? inputAudioChannels = audioStream == null ? null : audioStream.Channels; int? inputAudioBitrate = audioStream == null ? null : audioStream.BitDepth; int? inputAudioSampleRate = audioStream == null ? null : audioStream.SampleRate; + int? inputAudioBitDepth = audioStream == null ? null : audioStream.BitDepth; if (directPlayMethods.Count > 0) { @@ -156,7 +254,7 @@ namespace MediaBrowser.Model.Dlna bool applyConditions = true; foreach (ProfileCondition applyCondition in i.ApplyConditions) { - if (!conditionProcessor.IsAudioConditionSatisfied(applyCondition, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate)) + if (!conditionProcessor.IsAudioConditionSatisfied(applyCondition, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth)) { LogConditionFailure(options.Profile, "AudioCodecProfile", applyCondition, item); applyConditions = false; @@ -177,9 +275,14 @@ namespace MediaBrowser.Model.Dlna bool all = true; foreach (ProfileCondition c in conditions) { - if (!conditionProcessor.IsAudioConditionSatisfied(c, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate)) + if (!conditionProcessor.IsAudioConditionSatisfied(c, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth)) { LogConditionFailure(options.Profile, "AudioCodecProfile", c, item); + var transcodeReason = GetTranscodeReasonForFailedCondition(c); + if (transcodeReason.HasValue) + { + transcodeReasons.Add(transcodeReason.Value); + } all = false; break; } @@ -252,7 +355,7 @@ namespace MediaBrowser.Model.Dlna bool applyConditions = true; foreach (ProfileCondition applyCondition in i.ApplyConditions) { - if (!conditionProcessor.IsAudioConditionSatisfied(applyCondition, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate)) + if (!conditionProcessor.IsAudioConditionSatisfied(applyCondition, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth)) { LogConditionFailure(options.Profile, "AudioCodecProfile", applyCondition, item); applyConditions = false; @@ -292,9 +395,9 @@ namespace MediaBrowser.Model.Dlna var longBitrate = Math.Min(transcodingBitrate, playlistItem.AudioBitrate ?? transcodingBitrate); playlistItem.AudioBitrate = longBitrate > int.MaxValue ? int.MaxValue : Convert.ToInt32(longBitrate); - } + playlistItem.TranscodeReasons = transcodeReasons; return playlistItem; } @@ -308,8 +411,10 @@ namespace MediaBrowser.Model.Dlna return options.GetMaxBitrate(isAudio); } - private List<PlayMethod> GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options) + private Tuple<List<PlayMethod>, List<TranscodeReason>> GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options) { + List<TranscodeReason> transcodeReasons = new List<TranscodeReason>(); + DirectPlayProfile directPlayProfile = null; foreach (DirectPlayProfile i in options.Profile.DirectPlayProfiles) { @@ -325,27 +430,134 @@ namespace MediaBrowser.Model.Dlna if (directPlayProfile != null) { // While options takes the network and other factors into account. Only applies to direct stream - if (item.SupportsDirectStream && IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate(true), PlayMethod.DirectStream) && options.EnableDirectStream) + if (item.SupportsDirectStream) { - playMethods.Add(PlayMethod.DirectStream); + if (IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate(true), PlayMethod.DirectStream)) + { + if (options.EnableDirectStream) + { + playMethods.Add(PlayMethod.DirectStream); + } + } + else + { + transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit); + } } // The profile describes what the device supports // If device requirements are satisfied then allow both direct stream and direct play - if (item.SupportsDirectPlay && - IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true), PlayMethod.DirectPlay) && options.EnableDirectPlay) + if (item.SupportsDirectPlay) { - playMethods.Add(PlayMethod.DirectPlay); + if (IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true), PlayMethod.DirectPlay)) + { + if (options.EnableDirectPlay) + { + playMethods.Add(PlayMethod.DirectPlay); + } + } + else + { + transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit); + } } } else { + transcodeReasons.InsertRange(0, GetTranscodeReasonsFromDirectPlayProfile(item, null, audioStream, options.Profile.DirectPlayProfiles)); + _logger.Info("Profile: {0}, No direct play profiles found for Path: {1}", options.Profile.Name ?? "Unknown Profile", item.Path ?? "Unknown path"); } - return playMethods; + if (playMethods.Count > 0) + { + transcodeReasons.Clear(); + } + else + { + transcodeReasons = transcodeReasons.Distinct().ToList(); + } + + return new Tuple<List<PlayMethod>, List<TranscodeReason>>(playMethods, transcodeReasons); + } + + private List<TranscodeReason> GetTranscodeReasonsFromDirectPlayProfile(MediaSourceInfo item, MediaStream videoStream, MediaStream audioStream, IEnumerable<DirectPlayProfile> directPlayProfiles) + { + var list = new List<TranscodeReason>(); + var containerSupported = false; + var audioSupported = false; + var videoSupported = false; + + foreach (var profile in directPlayProfiles) + { + if (profile.Container.Length > 0) + { + // Check container type + string mediaContainer = item.Container ?? string.Empty; + foreach (string i in profile.GetContainers()) + { + if (StringHelper.EqualsIgnoreCase(i, mediaContainer)) + { + containerSupported = true; + + if (videoStream != null) + { + // Check video codec + List<string> videoCodecs = profile.GetVideoCodecs(); + if (videoCodecs.Count > 0) + { + string videoCodec = videoStream.Codec; + if (!string.IsNullOrEmpty(videoCodec) && ListHelper.ContainsIgnoreCase(videoCodecs, videoCodec)) + { + videoSupported = true; + } + } + else + { + videoSupported = true; + } + } + + if (audioStream != null) + { + // Check audio codec + List<string> audioCodecs = profile.GetAudioCodecs(); + if (audioCodecs.Count > 0) + { + string audioCodec = audioStream.Codec; + if (!string.IsNullOrEmpty(audioCodec) && ListHelper.ContainsIgnoreCase(audioCodecs, audioCodec)) + { + audioSupported = true; + } + } + else + { + audioSupported = true; + } + } + } + } + } + } + + if (!containerSupported) + { + list.Add(TranscodeReason.ContainerNotSupported); + } + + if (videoStream != null && !videoSupported) + { + list.Add(TranscodeReason.VideoCodecNotSupported); + } + + if (audioStream != null && !audioSupported) + { + list.Add(TranscodeReason.AudioCodecNotSupported); + } + + return list; } private int? GetDefaultSubtitleStreamIndex(MediaSourceInfo item, SubtitleProfile[] subtitleProfiles) @@ -393,6 +605,8 @@ namespace MediaBrowser.Model.Dlna private StreamInfo BuildVideoItem(MediaSourceInfo item, VideoOptions options) { + List<TranscodeReason> transcodeReasons = new List<TranscodeReason>(); + StreamInfo playlistItem = new StreamInfo { ItemId = options.ItemId, @@ -428,7 +642,8 @@ namespace MediaBrowser.Model.Dlna if (isEligibleForDirectPlay || isEligibleForDirectStream) { // See if it can be direct played - PlayMethod? directPlay = GetVideoDirectPlayProfile(options, item, videoStream, audioStream, isEligibleForDirectPlay, isEligibleForDirectStream); + var directPlayInfo = GetVideoDirectPlayProfile(options, item, videoStream, audioStream, isEligibleForDirectPlay, isEligibleForDirectStream); + var directPlay = directPlayInfo.Item1; if (directPlay != null) { @@ -445,6 +660,8 @@ namespace MediaBrowser.Model.Dlna return playlistItem; } + + transcodeReasons.AddRange(directPlayInfo.Item2); } // Can't direct play, find the transcoding profile @@ -521,8 +738,9 @@ namespace MediaBrowser.Model.Dlna int? audioChannels = audioStream == null ? null : audioStream.Channels; string audioProfile = audioStream == null ? null : audioStream.Profile; int? inputAudioSampleRate = audioStream == null ? null : audioStream.SampleRate; + int? inputAudioBitDepth = audioStream == null ? null : audioStream.BitDepth; - if (!conditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, inputAudioBitrate, inputAudioSampleRate, audioProfile, isSecondaryAudio)) + if (!conditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth, audioProfile, isSecondaryAudio)) { LogConditionFailure(options.Profile, "AudioCodecProfile", applyCondition, item); applyConditions = false; @@ -618,6 +836,8 @@ namespace MediaBrowser.Model.Dlna } } + playlistItem.TranscodeReasons = transcodeReasons; + return playlistItem; } @@ -677,7 +897,7 @@ namespace MediaBrowser.Model.Dlna return Math.Min(defaultBitrate, encoderAudioBitrateLimit); } - private PlayMethod? GetVideoDirectPlayProfile(VideoOptions options, + private Tuple<PlayMethod?, List<TranscodeReason>> GetVideoDirectPlayProfile(VideoOptions options, MediaSourceInfo mediaSource, MediaStream videoStream, MediaStream audioStream, @@ -688,11 +908,11 @@ namespace MediaBrowser.Model.Dlna if (options.ForceDirectPlay) { - return PlayMethod.DirectPlay; + return new Tuple<PlayMethod?, List<TranscodeReason>>(PlayMethod.DirectPlay, new List<TranscodeReason>()); } if (options.ForceDirectStream) { - return PlayMethod.DirectStream; + return new Tuple<PlayMethod?, List<TranscodeReason>>(PlayMethod.DirectStream, new List<TranscodeReason>()); } if (videoStream == null) @@ -701,7 +921,7 @@ namespace MediaBrowser.Model.Dlna profile.Name ?? "Unknown Profile", mediaSource.Path ?? "Unknown path"); - return null; + return new Tuple<PlayMethod?, List<TranscodeReason>>(null, new List<TranscodeReason> { TranscodeReason.UnknownVideoStreamInfo }); } // See if it can be direct played @@ -721,7 +941,7 @@ namespace MediaBrowser.Model.Dlna profile.Name ?? "Unknown Profile", mediaSource.Path ?? "Unknown path"); - return null; + return new Tuple<PlayMethod?, List<TranscodeReason>>(null, GetTranscodeReasonsFromDirectPlayProfile(mediaSource, videoStream, audioStream, profile.DirectPlayProfiles)); } string container = mediaSource.Container; @@ -757,6 +977,7 @@ namespace MediaBrowser.Model.Dlna int? audioChannels = audioStream == null ? null : audioStream.Channels; string audioProfile = audioStream == null ? null : audioStream.Profile; int? audioSampleRate = audioStream == null ? null : audioStream.SampleRate; + int? audioBitDepth = audioStream == null ? null : audioStream.BitDepth; TransportStreamTimestamp? timestamp = videoStream == null ? TransportStreamTimestamp.None : mediaSource.Timestamp; int? packetLength = videoStream == null ? null : videoStream.PacketLength; @@ -784,7 +1005,7 @@ namespace MediaBrowser.Model.Dlna profile.Name ?? "Unknown Profile", mediaSource.Path ?? "Unknown path"); - return null; + return new Tuple<PlayMethod?, List<TranscodeReason>>(null, new List<TranscodeReason> { TranscodeReason.UnknownVideoStreamInfo }); } conditions = new List<ProfileCondition>(); @@ -819,7 +1040,12 @@ namespace MediaBrowser.Model.Dlna { LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource); - return null; + var transcodeReason = GetTranscodeReasonForFailedCondition(i); + var transcodeReasons = transcodeReason.HasValue + ? new List<TranscodeReason> { transcodeReason.Value } + : new List<TranscodeReason> { }; + + return new Tuple<PlayMethod?, List<TranscodeReason>>(null, transcodeReasons); } } @@ -833,7 +1059,7 @@ namespace MediaBrowser.Model.Dlna profile.Name ?? "Unknown Profile", mediaSource.Path ?? "Unknown path"); - return null; + return new Tuple<PlayMethod?, List<TranscodeReason>>(null, new List<TranscodeReason> { TranscodeReason.UnknownAudioStreamInfo }); } conditions = new List<ProfileCondition>(); @@ -846,7 +1072,7 @@ namespace MediaBrowser.Model.Dlna bool applyConditions = true; foreach (ProfileCondition applyCondition in i.ApplyConditions) { - if (!conditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, audioBitrate, audioSampleRate, audioProfile, isSecondaryAudio)) + if (!conditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, isSecondaryAudio)) { LogConditionFailure(profile, "VideoAudioCodecProfile", applyCondition, mediaSource); applyConditions = false; @@ -866,21 +1092,26 @@ namespace MediaBrowser.Model.Dlna foreach (ProfileCondition i in conditions) { - if (!conditionProcessor.IsVideoAudioConditionSatisfied(i, audioChannels, audioBitrate, audioSampleRate, audioProfile, isSecondaryAudio)) + if (!conditionProcessor.IsVideoAudioConditionSatisfied(i, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, isSecondaryAudio)) { LogConditionFailure(profile, "VideoAudioCodecProfile", i, mediaSource); - return null; + var transcodeReason = GetTranscodeReasonForFailedCondition(i); + var transcodeReasons = transcodeReason.HasValue + ? new List<TranscodeReason> { transcodeReason.Value } + : new List<TranscodeReason> { }; + + return new Tuple<PlayMethod?, List<TranscodeReason>>(null, transcodeReasons); } } } if (isEligibleForDirectStream && mediaSource.SupportsDirectStream) { - return PlayMethod.DirectStream; + return new Tuple<PlayMethod?, List<TranscodeReason>>(PlayMethod.DirectStream, new List<TranscodeReason>()); } - return null; + return new Tuple<PlayMethod?, List<TranscodeReason>>(null, new List<TranscodeReason> { TranscodeReason.ContainerBitrateExceedsLimit }); } private void LogConditionFailure(DeviceProfile profile, string type, ProfileCondition condition, MediaSourceInfo mediaSource) @@ -1047,12 +1278,12 @@ namespace MediaBrowser.Model.Dlna // Don't restrict by bitrate if coming from an external domain if (item.IsRemote) { - return true; + return true; } if (!maxBitrate.HasValue) { - _logger.Info("Cannot "+ playMethod + " due to unknown supported bitrate"); + _logger.Info("Cannot " + playMethod + " due to unknown supported bitrate"); return false; } diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index ba5251e8c..9c8e8b030 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -21,6 +21,7 @@ namespace MediaBrowser.Model.Dlna AudioCodecs = new string[] { }; VideoCodecs = new string[] { }; SubtitleCodecs = new string[] { }; + TranscodeReasons = new List<TranscodeReason>(); } public string ItemId { get; set; } @@ -89,6 +90,7 @@ namespace MediaBrowser.Model.Dlna public string PlaySessionId { get; set; } public List<MediaSourceInfo> AllMediaSources { get; set; } + public List<TranscodeReason> TranscodeReasons { get; set; } public string MediaSourceId { @@ -231,22 +233,11 @@ namespace MediaBrowser.Model.Dlna list.Add(new NameValuePair("MaxWidth", item.MaxWidth.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxWidth.Value) : string.Empty)); list.Add(new NameValuePair("MaxHeight", item.MaxHeight.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxHeight.Value) : string.Empty)); - var forceStartPosition = false; long startPositionTicks = item.StartPositionTicks; - //if (item.MediaSource.DateLiveStreamOpened.HasValue && startPositionTicks == 0) - //{ - // var elapsed = DateTime.UtcNow - item.MediaSource.DateLiveStreamOpened.Value; - // elapsed -= TimeSpan.FromSeconds(20); - // if (elapsed.TotalSeconds >= 0) - // { - // startPositionTicks = elapsed.Ticks + startPositionTicks; - // forceStartPosition = true; - // } - //} var isHls = StringHelper.EqualsIgnoreCase(item.SubProtocol, "hls"); - if (isHls && !forceStartPosition) + if (isHls) { list.Add(new NameValuePair("StartTimeTicks", string.Empty)); } @@ -310,6 +301,11 @@ namespace MediaBrowser.Model.Dlna list.Add(new NameValuePair("BreakOnNonKeyFrames", item.BreakOnNonKeyFrames.ToString())); } + if (isDlna || !item.IsDirectStream) + { + list.Add(new NameValuePair("TranscodeReasons", string.Join(",", item.TranscodeReasons.Distinct().Select(i => i.ToString()).ToArray()))); + } + return list; } @@ -484,6 +480,18 @@ namespace MediaBrowser.Model.Dlna /// <summary> /// Predicts the audio sample rate that will be in the output stream /// </summary> + public int? TargetAudioBitDepth + { + get + { + MediaStream stream = TargetAudioStream; + return stream == null ? null : stream.BitDepth; + } + } + + /// <summary> + /// Predicts the audio sample rate that will be in the output stream + /// </summary> public int? TargetVideoBitDepth { get |
