From d9a50cb510cfe7b5a97def22fe3bc090cafc0638 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Fri, 2 Apr 2021 19:06:38 +0100 Subject: [PATCH] Various DLNA Optimizations --- Emby.Dlna/Didl/DidlBuilder.cs | 9 +- Emby.Dlna/PlayTo/PlayToController.cs | 8 +- Jellyfin.Api/Helpers/StreamingHelpers.cs | 5 +- .../Dlna/ContentFeatureBuilder.cs | 85 +++++++++---------- .../Dlna/MediaFormatProfileResolver.cs | 37 ++++---- 5 files changed, 68 insertions(+), 76 deletions(-) diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index 8b50d47fbd..66ae07329e 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -208,7 +208,8 @@ namespace Emby.Dlna.Didl var targetWidth = streamInfo.TargetWidth; var targetHeight = streamInfo.TargetHeight; - var contentFeatureList = new ContentFeatureBuilder(_profile).BuildVideoHeader( + var contentFeatureList = ContentFeatureBuilder.BuildVideoHeader( + _profile, streamInfo.Container, streamInfo.TargetVideoCodec.FirstOrDefault(), streamInfo.TargetAudioCodec.FirstOrDefault(), @@ -599,7 +600,8 @@ namespace Emby.Dlna.Didl ? MimeTypes.GetMimeType(filename) : mediaProfile.MimeType; - var contentFeatures = new ContentFeatureBuilder(_profile).BuildAudioHeader( + var contentFeatures = ContentFeatureBuilder.BuildAudioHeader( + _profile, streamInfo.Container, streamInfo.TargetAudioCodec.FirstOrDefault(), targetAudioBitrate, @@ -1033,8 +1035,7 @@ namespace Emby.Dlna.Didl var width = albumartUrlInfo.width ?? maxWidth; var height = albumartUrlInfo.height ?? maxHeight; - var contentFeatures = new ContentFeatureBuilder(_profile) - .BuildImageHeader(format, width, height, imageInfo.IsDirectStream, org_Pn); + var contentFeatures = ContentFeatureBuilder.BuildImageHeader(_profile, format, width, height, imageInfo.IsDirectStream, org_Pn); writer.WriteAttributeString( "protocolInfo", diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs index e4923b9eb0..c6fdcd8eaf 100644 --- a/Emby.Dlna/PlayTo/PlayToController.cs +++ b/Emby.Dlna/PlayTo/PlayToController.cs @@ -499,8 +499,8 @@ namespace Emby.Dlna.PlayTo if (streamInfo.MediaType == DlnaProfileType.Audio) { - return new ContentFeatureBuilder(profile) - .BuildAudioHeader( + return ContentFeatureBuilder.BuildAudioHeader( + profile, streamInfo.Container, streamInfo.TargetAudioCodec.FirstOrDefault(), streamInfo.TargetAudioBitrate, @@ -514,8 +514,8 @@ namespace Emby.Dlna.PlayTo if (streamInfo.MediaType == DlnaProfileType.Video) { - var list = new ContentFeatureBuilder(profile) - .BuildVideoHeader( + var list = ContentFeatureBuilder.BuildVideoHeader( + profile, streamInfo.Container, streamInfo.TargetVideoCodec.FirstOrDefault(), streamInfo.TargetAudioCodec.FirstOrDefault(), diff --git a/Jellyfin.Api/Helpers/StreamingHelpers.cs b/Jellyfin.Api/Helpers/StreamingHelpers.cs index d20a02cf5d..23f90052a0 100644 --- a/Jellyfin.Api/Helpers/StreamingHelpers.cs +++ b/Jellyfin.Api/Helpers/StreamingHelpers.cs @@ -306,7 +306,8 @@ namespace Jellyfin.Api.Helpers if (!state.IsVideoRequest) { - responseHeaders.Add("contentFeatures.dlna.org", new ContentFeatureBuilder(profile).BuildAudioHeader( + responseHeaders.Add("contentFeatures.dlna.org", ContentFeatureBuilder.BuildAudioHeader( + profile, state.OutputContainer, audioCodec, state.OutputAudioBitrate, @@ -323,7 +324,7 @@ namespace Jellyfin.Api.Helpers responseHeaders.Add( "contentFeatures.dlna.org", - new ContentFeatureBuilder(profile).BuildVideoHeader(state.OutputContainer, videoCodec, audioCodec, state.OutputWidth, state.OutputHeight, state.TargetVideoBitDepth, state.OutputVideoBitrate, state.TargetTimestamp, isStaticallyStreamed, state.RunTimeTicks, state.TargetVideoProfile, state.TargetVideoLevel, state.TargetFramerate, state.TargetPacketLength, state.TranscodeSeekInfo, state.IsTargetAnamorphic, state.IsTargetInterlaced, state.TargetRefFrames, state.TargetVideoStreamCount, state.TargetAudioStreamCount, state.TargetVideoCodecTag, state.IsTargetAVC).FirstOrDefault() ?? string.Empty); + ContentFeatureBuilder.BuildVideoHeader(profile, state.OutputContainer, videoCodec, audioCodec, state.OutputWidth, state.OutputHeight, state.TargetVideoBitDepth, state.OutputVideoBitrate, state.TargetTimestamp, isStaticallyStreamed, state.RunTimeTicks, state.TargetVideoProfile, state.TargetVideoLevel, state.TargetFramerate, state.TargetPacketLength, state.TranscodeSeekInfo, state.IsTargetAnamorphic, state.IsTargetInterlaced, state.TargetRefFrames, state.TargetVideoStreamCount, state.TargetAudioStreamCount, state.TargetVideoCodecTag, state.IsTargetAVC).FirstOrDefault() ?? string.Empty); } } diff --git a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs index ec106f1054..600a441570 100644 --- a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs +++ b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs @@ -10,14 +10,8 @@ namespace MediaBrowser.Model.Dlna { public class ContentFeatureBuilder { - private readonly DeviceProfile _profile; - - public ContentFeatureBuilder(DeviceProfile profile) - { - _profile = profile; - } - - public string BuildImageHeader( + public static string BuildImageHeader( + DeviceProfile profile, string container, int? width, int? height, @@ -38,27 +32,31 @@ namespace MediaBrowser.Model.Dlna ";DLNA.ORG_FLAGS={0}", DlnaMaps.FlagsToString(flagValue)); - ResponseProfile mediaProfile = _profile.GetImageMediaProfile( - container, - width, - height); - if (string.IsNullOrEmpty(orgPn)) { + ResponseProfile mediaProfile = profile.GetImageMediaProfile( + container, + width, + height); + orgPn = mediaProfile?.OrgPn; + + if (string.IsNullOrEmpty(orgPn)) + { + orgPn = GetImageOrgPnValue(container, width, height); + } } if (string.IsNullOrEmpty(orgPn)) { - orgPn = GetImageOrgPnValue(container, width, height); + return orgOp.TrimStart(';') + orgCi + dlnaflags; } - string contentFeatures = string.IsNullOrEmpty(orgPn) ? string.Empty : "DLNA.ORG_PN=" + orgPn; - - return (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';'); + return "DLNA.ORG_PN=" + orgPn + orgOp + orgCi + dlnaflags; } - public string BuildAudioHeader( + public static string BuildAudioHeader( + DeviceProfile profile, string container, string audioCodec, int? audioBitrate, @@ -94,7 +92,7 @@ namespace MediaBrowser.Model.Dlna ";DLNA.ORG_FLAGS={0}", DlnaMaps.FlagsToString(flagValue)); - ResponseProfile mediaProfile = _profile.GetAudioMediaProfile( + ResponseProfile mediaProfile = profile.GetAudioMediaProfile( container, audioCodec, audioChannels, @@ -109,12 +107,16 @@ namespace MediaBrowser.Model.Dlna orgPn = GetAudioOrgPnValue(container, audioBitrate, audioSampleRate, audioChannels); } - string contentFeatures = string.IsNullOrEmpty(orgPn) ? string.Empty : "DLNA.ORG_PN=" + orgPn; + if (string.IsNullOrEmpty(orgPn)) + { + return orgOp.TrimStart(';') + orgCi + dlnaflags; + } - return (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';'); + return "DLNA.ORG_PN=" + orgPn + orgOp + orgCi + dlnaflags; } - public List BuildVideoHeader( + public static List BuildVideoHeader( + DeviceProfile profile, string container, string videoCodec, string audioCodec, @@ -163,7 +165,7 @@ namespace MediaBrowser.Model.Dlna ";DLNA.ORG_FLAGS={0}", DlnaMaps.FlagsToString(flagValue)); - ResponseProfile mediaProfile = _profile.GetVideoMediaProfile( + ResponseProfile mediaProfile = profile.GetVideoMediaProfile( container, audioCodec, videoCodec, @@ -192,9 +194,9 @@ namespace MediaBrowser.Model.Dlna } else { - foreach (string s in GetVideoOrgPnValue(container, videoCodec, audioCodec, width, height, timestamp)) + foreach (var s in GetVideoOrgPnValue(container, videoCodec, audioCodec, width, height, timestamp)) { - orgPnValues.Add(s); + orgPnValues.Add(s.ToString()); break; } } @@ -203,20 +205,20 @@ namespace MediaBrowser.Model.Dlna foreach (string orgPn in orgPnValues) { - string contentFeatures = string.IsNullOrEmpty(orgPn) ? string.Empty : "DLNA.ORG_PN=" + orgPn; - - var value = (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';'); - - contentFeatureList.Add(value); + if (string.IsNullOrEmpty(orgPn)) + { + contentFeatureList.Add(orgOp.TrimStart(';') + orgCi + dlnaflags); + continue; + } + else + { + contentFeatureList.Add("DLNA.ORG_PN=" + orgPn + orgCi + dlnaflags); + } } if (orgPnValues.Count == 0) { - string contentFeatures = string.Empty; - - var value = (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';'); - - contentFeatureList.Add(value); + contentFeatureList.Add(orgOp.TrimStart(';') + orgCi + dlnaflags); } return contentFeatureList; @@ -224,19 +226,14 @@ namespace MediaBrowser.Model.Dlna private static string GetImageOrgPnValue(string container, int? width, int? height) { - MediaFormatProfile? format = new MediaFormatProfileResolver() - .ResolveImageFormat( - container, - width, - height); + MediaFormatProfile? format = MediaFormatProfileResolver.ResolveImageFormat(container, width, height); return format.HasValue ? format.Value.ToString() : null; } private static string GetAudioOrgPnValue(string container, int? audioBitrate, int? audioSampleRate, int? audioChannels) { - MediaFormatProfile? format = new MediaFormatProfileResolver() - .ResolveAudioFormat( + MediaFormatProfile? format = MediaFormatProfileResolver.ResolveAudioFormat( container, audioBitrate, audioSampleRate, @@ -245,9 +242,9 @@ namespace MediaBrowser.Model.Dlna return format.HasValue ? format.Value.ToString() : null; } - private static string[] GetVideoOrgPnValue(string container, string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestamp) + private static MediaFormatProfile[] GetVideoOrgPnValue(string container, string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestamp) { - return new MediaFormatProfileResolver().ResolveVideoFormat(container, videoCodec, audioCodec, width, height, timestamp); + return MediaFormatProfileResolver.ResolveVideoFormat(container, videoCodec, audioCodec, width, height, timestamp); } } } diff --git a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs index f61b8d59e8..7ce248509c 100644 --- a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs +++ b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs @@ -9,16 +9,9 @@ using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.Model.Dlna { - public class MediaFormatProfileResolver + public static class MediaFormatProfileResolver { - public string[] ResolveVideoFormat(string container, string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType) - { - return ResolveVideoFormatInternal(container, videoCodec, audioCodec, width, height, timestampType) - .Select(i => i.ToString()) - .ToArray(); - } - - private MediaFormatProfile[] ResolveVideoFormatInternal(string container, string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType) + public static MediaFormatProfile[] ResolveVideoFormat(string container, string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType) { if (string.Equals(container, "asf", StringComparison.OrdinalIgnoreCase)) { @@ -84,7 +77,7 @@ namespace MediaBrowser.Model.Dlna return Array.Empty(); } - private MediaFormatProfile[] ResolveVideoMPEG2TSFormat(string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType) + private static MediaFormatProfile[] ResolveVideoMPEG2TSFormat(string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType) { string suffix = string.Empty; @@ -209,12 +202,12 @@ namespace MediaBrowser.Model.Dlna return Array.Empty(); } - private MediaFormatProfile ValueOf(string value) + private static MediaFormatProfile ValueOf(string value) { return (MediaFormatProfile)Enum.Parse(typeof(MediaFormatProfile), value, true); } - private MediaFormatProfile? ResolveVideoMP4Format(string videoCodec, string audioCodec, int? width, int? height) + private static MediaFormatProfile? ResolveVideoMP4Format(string videoCodec, string audioCodec, int? width, int? height) { if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase)) { @@ -287,7 +280,7 @@ namespace MediaBrowser.Model.Dlna return null; } - private MediaFormatProfile? ResolveVideo3GPFormat(string videoCodec, string audioCodec) + private static MediaFormatProfile? ResolveVideo3GPFormat(string videoCodec, string audioCodec) { if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase)) { @@ -317,7 +310,7 @@ namespace MediaBrowser.Model.Dlna return null; } - private MediaFormatProfile? ResolveVideoASFFormat(string videoCodec, string audioCodec, int? width, int? height) + private static MediaFormatProfile? ResolveVideoASFFormat(string videoCodec, string audioCodec, int? width, int? height) { if (string.Equals(videoCodec, "wmv", StringComparison.OrdinalIgnoreCase) && (string.IsNullOrEmpty(audioCodec) || string.Equals(audioCodec, "wma", StringComparison.OrdinalIgnoreCase) || string.Equals(videoCodec, "wmapro", StringComparison.OrdinalIgnoreCase))) @@ -371,7 +364,7 @@ namespace MediaBrowser.Model.Dlna return null; } - public MediaFormatProfile? ResolveAudioFormat(string container, int? bitrate, int? frequency, int? channels) + public static MediaFormatProfile? ResolveAudioFormat(string container, int? bitrate, int? frequency, int? channels) { if (string.Equals(container, "asf", StringComparison.OrdinalIgnoreCase)) { @@ -413,7 +406,7 @@ namespace MediaBrowser.Model.Dlna return null; } - private MediaFormatProfile ResolveAudioASFFormat(int? bitrate) + private static MediaFormatProfile ResolveAudioASFFormat(int? bitrate) { if (bitrate.HasValue && bitrate.Value <= 193) { @@ -423,7 +416,7 @@ namespace MediaBrowser.Model.Dlna return MediaFormatProfile.WMA_FULL; } - private MediaFormatProfile? ResolveAudioLPCMFormat(int? frequency, int? channels) + private static MediaFormatProfile? ResolveAudioLPCMFormat(int? frequency, int? channels) { if (frequency.HasValue && channels.HasValue) { @@ -453,7 +446,7 @@ namespace MediaBrowser.Model.Dlna return MediaFormatProfile.LPCM16_48_STEREO; } - private MediaFormatProfile ResolveAudioMP4Format(int? bitrate) + private static MediaFormatProfile ResolveAudioMP4Format(int? bitrate) { if (bitrate.HasValue && bitrate.Value <= 320) { @@ -463,7 +456,7 @@ namespace MediaBrowser.Model.Dlna return MediaFormatProfile.AAC_ISO; } - private MediaFormatProfile ResolveAudioADTSFormat(int? bitrate) + private static MediaFormatProfile ResolveAudioADTSFormat(int? bitrate) { if (bitrate.HasValue && bitrate.Value <= 320) { @@ -473,7 +466,7 @@ namespace MediaBrowser.Model.Dlna return MediaFormatProfile.AAC_ADTS; } - public MediaFormatProfile? ResolveImageFormat(string container, int? width, int? height) + public static MediaFormatProfile? ResolveImageFormat(string container, int? width, int? height) { if (string.Equals(container, "jpeg", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "jpg", StringComparison.OrdinalIgnoreCase)) @@ -499,7 +492,7 @@ namespace MediaBrowser.Model.Dlna return null; } - private MediaFormatProfile ResolveImageJPGFormat(int? width, int? height) + private static MediaFormatProfile ResolveImageJPGFormat(int? width, int? height) { if (width.HasValue && height.HasValue) { @@ -524,7 +517,7 @@ namespace MediaBrowser.Model.Dlna return MediaFormatProfile.JPEG_SM; } - private MediaFormatProfile ResolveImagePNGFormat(int? width, int? height) + private static MediaFormatProfile ResolveImagePNGFormat(int? width, int? height) { if (width.HasValue && height.HasValue) {