diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index 3dcdaf2efc..e968509b5e 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -207,7 +207,8 @@ namespace Emby.Dlna.Didl streamInfo.TargetVideoStreamCount, streamInfo.TargetAudioStreamCount, streamInfo.TargetVideoCodecTag, - streamInfo.IsTargetAVC); + streamInfo.IsTargetAVC, + streamInfo.AllAudioCodecs); foreach (var contentFeature in contentFeatureList) { @@ -347,7 +348,8 @@ namespace Emby.Dlna.Didl streamInfo.TargetVideoStreamCount, streamInfo.TargetAudioStreamCount, streamInfo.TargetVideoCodecTag, - streamInfo.IsTargetAVC); + streamInfo.IsTargetAVC, + streamInfo.AllAudioCodecs); var filename = url.Substring(0, url.IndexOf('?')); diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs index 7dff8bda13..bfc29d0f5f 100644 --- a/Emby.Dlna/PlayTo/PlayToController.cs +++ b/Emby.Dlna/PlayTo/PlayToController.cs @@ -541,7 +541,8 @@ namespace Emby.Dlna.PlayTo streamInfo.TargetVideoStreamCount, streamInfo.TargetAudioStreamCount, streamInfo.TargetVideoCodecTag, - streamInfo.IsTargetAVC); + streamInfo.IsTargetAVC, + streamInfo.AllAudioCodecs); return list.FirstOrDefault(); } diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 3718edba49..288553ade0 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -2358,7 +2358,8 @@ namespace MediaBrowser.Api.Playback state.TargetVideoStreamCount, state.TargetAudioStreamCount, state.TargetVideoCodecTag, - state.IsTargetAVC); + state.IsTargetAVC, + state.AllAudioCodecs); if (mediaProfile != null) { @@ -2580,7 +2581,8 @@ namespace MediaBrowser.Api.Playback state.TargetVideoStreamCount, state.TargetAudioStreamCount, state.TargetVideoCodecTag, - state.IsTargetAVC + state.IsTargetAVC, + state.AllAudioCodecs ).FirstOrDefault() ?? string.Empty; } diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index 003599390e..9c337781cb 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.IO; +using System.Linq; using System.Threading; namespace MediaBrowser.Api.Playback @@ -244,6 +245,17 @@ namespace MediaBrowser.Api.Playback public int? OutputAudioBitrate; public int? OutputVideoBitrate; + public List AllAudioCodecs + { + get + { + return MediaSource.MediaStreams.Where(i => i.Type == MediaStreamType.Audio) + .Select(i => i.Codec) + .Where(i => !string.IsNullOrWhiteSpace(i)) + .ToList(); + } + } + public string ActualOutputVideoCodec { get diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs index 0c7ff1b760..145337a2a4 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs @@ -11,6 +11,7 @@ using MediaBrowser.Model.Net; using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -117,6 +118,17 @@ namespace MediaBrowser.MediaEncoding.Encoder } } + public List AllAudioCodecs + { + get + { + return MediaSource.MediaStreams.Where(i => i.Type == MediaStreamType.Audio) + .Select(i => i.Codec) + .Where(i => !string.IsNullOrWhiteSpace(i)) + .ToList(); + } + } + private void DisposeIsoMount() { if (IsoMount != null) diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs index e197bdb6fd..70d02901ec 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs @@ -846,7 +846,8 @@ namespace MediaBrowser.MediaEncoding.Encoder state.TargetVideoStreamCount, state.TargetAudioStreamCount, state.TargetVideoCodecTag, - state.IsTargetAVC); + state.IsTargetAVC, + state.AllAudioCodecs); if (mediaProfile != null) { diff --git a/MediaBrowser.Model/Dlna/ConditionProcessor.cs b/MediaBrowser.Model/Dlna/ConditionProcessor.cs index 1fbb4ffa17..aa0b6f4319 100644 --- a/MediaBrowser.Model/Dlna/ConditionProcessor.cs +++ b/MediaBrowser.Model/Dlna/ConditionProcessor.cs @@ -1,7 +1,9 @@ using MediaBrowser.Model.Extensions; using MediaBrowser.Model.MediaInfo; using System; +using System.Collections.Generic; using System.Globalization; +using System.Linq; namespace MediaBrowser.Model.Dlna { @@ -22,12 +24,15 @@ namespace MediaBrowser.Model.Dlna int? numVideoStreams, int? numAudioStreams, string videoCodecTag, - bool? isAvc) + bool? isAvc, + List allAudioCodecs ) { switch (condition.Property) { case ProfileConditionValue.IsAnamorphic: return IsConditionSatisfied(condition, isAnamorphic); + case ProfileConditionValue.HasAudioCodec: + return IsHasAudioCodecConditionSatisfied(condition, allAudioCodecs); case ProfileConditionValue.IsAvc: return IsConditionSatisfied(condition, isAvc); case ProfileConditionValue.VideoFramerate: @@ -162,6 +167,25 @@ namespace MediaBrowser.Model.Dlna } } + private bool IsHasAudioCodecConditionSatisfied(ProfileCondition condition, List allAudioCodecs) + { + if (allAudioCodecs.Count == 0) + { + // If the value is unknown, it satisfies if not marked as required + return !condition.IsRequired; + } + + switch (condition.Condition) + { + case ProfileConditionType.Equals: + return allAudioCodecs.Contains(condition.Value, StringComparer.Ordinal); + case ProfileConditionType.NotEquals: + return !allAudioCodecs.Contains(condition.Value, StringComparer.Ordinal); + default: + throw new InvalidOperationException("Unexpected ProfileConditionType"); + } + } + private bool IsConditionSatisfied(ProfileCondition condition, bool? currentValue) { if (!currentValue.HasValue) diff --git a/MediaBrowser.Model/Dlna/ContainerProfile.cs b/MediaBrowser.Model/Dlna/ContainerProfile.cs index d9b75dfc23..35d7ada6b9 100644 --- a/MediaBrowser.Model/Dlna/ContainerProfile.cs +++ b/MediaBrowser.Model/Dlna/ContainerProfile.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Xml.Serialization; using MediaBrowser.Model.Dlna; +using MediaBrowser.Model.Extensions; namespace MediaBrowser.Model.Dlna { @@ -27,5 +28,12 @@ namespace MediaBrowser.Model.Dlna } return list; } + + public bool ContainsContainer(string container) + { + List containers = GetContainers(); + + return containers.Count == 0 || ListHelper.ContainsIgnoreCase(containers, container ?? string.Empty); + } } } diff --git a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs index 4a16a27805..c6a5116b4d 100644 --- a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs +++ b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs @@ -119,7 +119,8 @@ namespace MediaBrowser.Model.Dlna int? numVideoStreams, int? numAudioStreams, string videoCodecTag, - bool? isAvc) + bool? isAvc, + List allAudioCodecs) { // first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none string orgOp = ";DLNA.ORG_OP=" + DlnaMaps.GetOrgOpValue(runtimeTicks.HasValue, isDirectStream, transcodeSeekInfo); @@ -161,7 +162,8 @@ namespace MediaBrowser.Model.Dlna numVideoStreams, numAudioStreams, videoCodecTag, - isAvc); + isAvc, + allAudioCodecs); List orgPnValues = new List(); diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs index 821531ed06..638f78dcbb 100644 --- a/MediaBrowser.Model/Dlna/DeviceProfile.cs +++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs @@ -297,7 +297,8 @@ namespace MediaBrowser.Model.Dlna int? numVideoStreams, int? numAudioStreams, string videoCodecTag, - bool? isAvc) + bool? isAvc, + List allAudioCodecs) { container = StringHelper.TrimStart(container ?? string.Empty, '.'); @@ -331,7 +332,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, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)) + if (!conditionProcessor.IsVideoConditionSatisfied(GetModelProfileCondition(c), width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc, allAudioCodecs)) { anyOff = true; break; diff --git a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs index 7e2002f179..9d6321c848 100644 --- a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs +++ b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs @@ -21,6 +21,7 @@ NumVideoStreams = 17, IsSecondaryAudio = 18, VideoCodecTag = 19, - IsAvc = 20 + IsAvc = 20, + HasAudioCodec = 21 } } \ No newline at end of file diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 71f0fd541b..dee1605f36 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -7,6 +7,7 @@ using MediaBrowser.Model.Session; using System; using System.Collections.Generic; using System.Globalization; +using System.Linq; namespace MediaBrowser.Model.Dlna { @@ -409,6 +410,9 @@ namespace MediaBrowser.Model.Dlna audioStreamIndex = audioStream.Index; } + var allMediaStreams = item.MediaStreams; + var allAudioCodecs = allMediaStreams.Where(i => i.Type == MediaStreamType.Audio).Select(i => i.Codec).Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); + MediaStream videoStream = item.VideoStream; // TODO: This doesn't accout for situation of device being able to handle media bitrate, but wifi connection not fast enough @@ -424,7 +428,7 @@ namespace MediaBrowser.Model.Dlna if (isEligibleForDirectPlay || isEligibleForDirectStream) { // See if it can be direct played - PlayMethod? directPlay = GetVideoDirectPlayProfile(options, item, videoStream, audioStream, isEligibleForDirectPlay, isEligibleForDirectStream); + PlayMethod? directPlay = GetVideoDirectPlayProfile(options, item, videoStream, audioStream, isEligibleForDirectPlay, isEligibleForDirectStream, allMediaStreams); if (directPlay != null) { @@ -552,7 +556,7 @@ namespace MediaBrowser.Model.Dlna int? numAudioStreams = item.GetStreamCount(MediaStreamType.Audio); int? numVideoStreams = item.GetStreamCount(MediaStreamType.Video); - if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)) + if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc, allAudioCodecs)) { LogConditionFailure(options.Profile, "VideoCodecProfile", applyCondition, item); applyConditions = false; @@ -653,7 +657,8 @@ namespace MediaBrowser.Model.Dlna MediaStream videoStream, MediaStream audioStream, bool isEligibleForDirectPlay, - bool isEligibleForDirectStream) + bool isEligibleForDirectStream, + List allMediaStreams) { DeviceProfile profile = options.Profile; @@ -701,7 +706,7 @@ namespace MediaBrowser.Model.Dlna foreach (ContainerProfile i in profile.ContainerProfiles) { if (i.Type == DlnaProfileType.Video && - ListHelper.ContainsIgnoreCase(i.GetContainers(), container)) + i.ContainsContainer(container)) { foreach (ProfileCondition c in i.Conditions) { @@ -734,10 +739,12 @@ namespace MediaBrowser.Model.Dlna int? numAudioStreams = mediaSource.GetStreamCount(MediaStreamType.Audio); int? numVideoStreams = mediaSource.GetStreamCount(MediaStreamType.Video); + var allAudioCodecs = allMediaStreams.Where(i => i.Type == MediaStreamType.Audio).Select(i => i.Codec).Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); + // Check container conditions foreach (ProfileCondition i in conditions) { - if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)) + if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc, allAudioCodecs)) { LogConditionFailure(profile, "VideoContainerProfile", i, mediaSource); @@ -764,7 +771,7 @@ namespace MediaBrowser.Model.Dlna bool applyConditions = true; foreach (ProfileCondition applyCondition in i.ApplyConditions) { - if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)) + if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc, allAudioCodecs)) { LogConditionFailure(profile, "VideoCodecProfile", applyCondition, mediaSource); applyConditions = false; @@ -784,7 +791,7 @@ namespace MediaBrowser.Model.Dlna foreach (ProfileCondition i in conditions) { - if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)) + if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc, allAudioCodecs)) { LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource); diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index e5dd0353e0..105edb131e 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -6,6 +6,7 @@ using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Session; using System; using System.Collections.Generic; +using System.Linq; namespace MediaBrowser.Model.Dlna { @@ -412,6 +413,17 @@ namespace MediaBrowser.Model.Dlna } } + public List AllAudioCodecs + { + get + { + return MediaSource.MediaStreams.Where(i => i.Type == MediaStreamType.Audio) + .Select(i => i.Codec) + .Where(i => !string.IsNullOrWhiteSpace(i)) + .ToList(); + } + } + /// /// Returns the video stream that will be used ///