From 44bfad70d2cdce3c63ea551cc4205d5cba09056c Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 22 Apr 2014 22:47:46 -0400 Subject: [PATCH] Normalize orgPn usage --- .../Playback/BaseStreamingService.cs | 136 ++++++++---------- MediaBrowser.Api/Playback/StreamState.cs | 3 +- MediaBrowser.Dlna/PlayTo/DlnaController.cs | 90 +++++------- MediaBrowser.Dlna/PlayTo/PlayToManager.cs | 4 - .../PlayTo/PlayToServerEntryPoint.cs | 1 - MediaBrowser.Dlna/PlayTo/PlaylistItem.cs | 2 + .../PlayTo/PlaylistItemFactory.cs | 4 +- MediaBrowser.Dlna/Server/ControlHandler.cs | 13 +- .../Dlna/ContentFeatureBuilder.cs | 130 +++++++++++++++++ MediaBrowser.Model/Dlna/DeviceProfile.cs | 4 +- .../Dlna/MediaFormatProfileResolver.cs | 4 +- MediaBrowser.Model/Dlna/StreamInfo.cs | 67 ++++++++- MediaBrowser.Model/MediaBrowser.Model.csproj | 1 + 13 files changed, 302 insertions(+), 157 deletions(-) create mode 100644 MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index a470bc2fa..93f3e2d9f 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1507,6 +1507,16 @@ namespace MediaBrowser.Api.Playback } } + var headers = new Dictionary(); + foreach (var key in Request.Headers.AllKeys) + { + headers[key] = Request.Headers[key]; + } + + state.DeviceProfile = string.IsNullOrWhiteSpace(state.Request.DeviceProfileId) ? + DlnaManager.GetProfile(headers) : + DlnaManager.GetProfile(state.Request.DeviceProfileId); + return state; } @@ -1631,16 +1641,7 @@ namespace MediaBrowser.Api.Playback private void ApplyDeviceProfileSettings(StreamState state) { - var headers = new Dictionary(); - - foreach (var key in Request.Headers.AllKeys) - { - headers[key] = Request.Headers[key]; - } - - var profile = string.IsNullOrWhiteSpace(state.Request.DeviceProfileId) ? - DlnaManager.GetProfile(headers) : - DlnaManager.GetProfile(state.Request.DeviceProfileId); + var profile = state.DeviceProfile; if (profile == null) { @@ -1664,13 +1665,12 @@ namespace MediaBrowser.Api.Playback } var mediaProfile = state.VideoRequest == null ? - profile.GetAudioMediaProfile(state.OutputContainer, audioCodec, state.AudioStream) : - profile.GetVideoMediaProfile(state.OutputContainer, audioCodec, videoCodec, state.AudioStream, state.VideoStream); + profile.GetAudioMediaProfile(state.OutputContainer, audioCodec) : + profile.GetVideoMediaProfile(state.OutputContainer, audioCodec, videoCodec); if (mediaProfile != null) { state.MimeType = mediaProfile.MimeType; - state.OrgPn = mediaProfile.OrgPn; } var transcodingProfile = state.VideoRequest == null ? @@ -1699,45 +1699,65 @@ namespace MediaBrowser.Api.Playback /// true if XXXX, false otherwise protected void AddDlnaHeaders(StreamState state, IDictionary responseHeaders, bool isStaticallyStreamed) { + var profile = state.DeviceProfile; + + if (profile == null) + { + return; + } + var transferMode = GetHeader("transferMode.dlna.org"); responseHeaders["transferMode.dlna.org"] = string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode; responseHeaders["realTimeInfo.dlna.org"] = "DLNA.ORG_TLAG=*"; - // 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 - var orgOp = ";DLNA.ORG_OP=" + DlnaMaps.GetOrgOpValue(state.RunTimeTicks.HasValue, isStaticallyStreamed, state.TranscodeSeekInfo); - if (state.RunTimeTicks.HasValue && !isStaticallyStreamed) { AddTimeSeekResponseHeaders(state, responseHeaders); } - // 0 = native, 1 = transcoded - var orgCi = isStaticallyStreamed ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1"; + var audioCodec = state.Request.AudioCodec; - var flagValue = DlnaFlags.StreamingTransferMode | - DlnaFlags.BackgroundTransferMode | - DlnaFlags.DlnaV15; - - if (isStaticallyStreamed) + if (state.VideoRequest == null) { - //flagValue = flagValue | DlnaFlags.DLNA_ORG_FLAG_BYTE_BASED_SEEK; + responseHeaders["contentFeatures.dlna.org"] = new ContentFeatureBuilder(profile) + .BuildAudioHeader( + state.OutputContainer, + audioCodec, + state.OutputAudioBitrate, + state.OutputAudioSampleRate, + state.OutputAudioChannels, + isStaticallyStreamed, + state.RunTimeTicks, + state.TranscodeSeekInfo + ); } - else if (state.RunTimeTicks.HasValue) + else { - //flagValue = flagValue | DlnaFlags.DLNA_ORG_FLAG_TIME_BASED_SEEK; - } + if (string.Equals(audioCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.AudioStream != null) + { + audioCodec = state.AudioStream.Codec; + } - var dlnaflags = string.Format(";DLNA.ORG_FLAGS={0}000000000000000000000000", - Enum.Format(typeof(DlnaFlags), flagValue, "x")); + var videoCodec = state.VideoRequest == null ? null : state.VideoRequest.VideoCodec; - var orgPn = GetOrgPnValue(state); + if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.VideoStream != null) + { + videoCodec = state.VideoStream.Codec; + } - var contentFeatures = string.IsNullOrEmpty(orgPn) ? string.Empty : - "DLNA.ORG_PN=" + orgPn; - - if (!string.IsNullOrEmpty(contentFeatures)) - { - responseHeaders["contentFeatures.dlna.org"] = (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';'); + responseHeaders["contentFeatures.dlna.org"] = new ContentFeatureBuilder(profile) + .BuildVideoHeader( + state.OutputContainer, + videoCodec, + audioCodec, + state.OutputWidth, + state.OutputHeight, + state.TotalOutputBitrate, + TransportStreamTimestamp.VALID, + isStaticallyStreamed, + state.RunTimeTicks, + state.TranscodeSeekInfo + ); } foreach (var item in responseHeaders) @@ -1746,50 +1766,6 @@ namespace MediaBrowser.Api.Playback } } - private string GetOrgPnValue(StreamState state) - { - if (!string.IsNullOrWhiteSpace(state.OrgPn)) - { - return state.OrgPn; - } - - if (state.VideoRequest == null) - { - var format = new MediaFormatProfileResolver() - .ResolveAudioFormat(state.OutputContainer, - state.OutputAudioBitrate, - state.OutputAudioSampleRate, - state.OutputAudioChannels); - - return format.HasValue ? format.Value.ToString() : null; - } - - var audioCodec = state.Request.AudioCodec; - - if (string.Equals(audioCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.AudioStream != null) - { - audioCodec = state.AudioStream.Codec; - } - - var videoCodec = state.VideoRequest == null ? null : state.VideoRequest.VideoCodec; - - if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.VideoStream != null) - { - videoCodec = state.VideoStream.Codec; - } - - var videoFormat = new MediaFormatProfileResolver() - .ResolveVideoFormat(state.OutputContainer, - videoCodec, - audioCodec, - state.OutputWidth, - state.OutputHeight, - state.TotalOutputBitrate, - TransportStreamTimestamp.VALID); - - return videoFormat.HasValue ? videoFormat.Value.ToString() : null; - } - private void AddTimeSeekResponseHeaders(StreamState state, IDictionary responseHeaders) { var runtimeSeconds = TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalSeconds.ToString(UsCulture); diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index 067a3f978..8a8246b69 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -84,7 +84,6 @@ namespace MediaBrowser.Api.Playback public string InputAudioCodec { get; set; } public string MimeType { get; set; } - public string OrgPn { get; set; } public bool EstimateContentLength { get; set; } public bool EnableMpegtsM2TsMode { get; set; } @@ -163,6 +162,8 @@ namespace MediaBrowser.Api.Playback public string OutputContainer { get; set; } + public DeviceProfile DeviceProfile { get; set; } + public int? TotalOutputBitrate { get diff --git a/MediaBrowser.Dlna/PlayTo/DlnaController.cs b/MediaBrowser.Dlna/PlayTo/DlnaController.cs index 1fa913e0e..1c5503abb 100644 --- a/MediaBrowser.Dlna/PlayTo/DlnaController.cs +++ b/MediaBrowser.Dlna/PlayTo/DlnaController.cs @@ -401,66 +401,38 @@ namespace MediaBrowser.Dlna.PlayTo private string GetDlnaHeaders(PlaylistItem item) { + var profile = item.Profile; var streamInfo = item.StreamInfo; - var orgOp = !streamInfo.IsDirectStream ? ";DLNA.ORG_OP=00" : ";DLNA.ORG_OP=01"; - - var orgCi = !streamInfo.IsDirectStream ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1"; - - const string dlnaflags = ";DLNA.ORG_FLAGS=01500000000000000000000000000000"; - - string contentFeatures; - - var container = streamInfo.Container.TrimStart('.'); - - if (string.Equals(container, "mp3", StringComparison.OrdinalIgnoreCase)) + if (streamInfo.MediaType == DlnaProfileType.Audio) { - contentFeatures = "DLNA.ORG_PN=MP3"; - } - else if (string.Equals(container, "wma", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=WMABASE"; - } - else if (string.Equals(container, "wmw", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=WMVMED_BASE"; - } - else if (string.Equals(container, "asf", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=WMVMED_BASE"; - } - else if (string.Equals(container, "avi", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=AVI"; - } - else if (string.Equals(container, "mkv", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=MATROSKA"; - } - else if (string.Equals(container, "mp4", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=AVC_MP4_MP_HD_720p_AAC"; - } - else if (string.Equals(container, "mpeg", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL"; - } - else if (string.Equals(container, "ts", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL"; - } - else if (streamInfo.MediaType == DlnaProfileType.Video) - { - // Default to AVI for video - contentFeatures = "DLNA.ORG_PN=AVI"; - } - else - { - // Default to MP3 for audio - contentFeatures = "DLNA.ORG_PN=MP3"; + return new ContentFeatureBuilder(profile) + .BuildAudioHeader(streamInfo.Container, + streamInfo.AudioCodec, + streamInfo.TargetAudioBitrate, + streamInfo.TargetAudioSampleRate, + streamInfo.TargetAudioChannels, + streamInfo.IsDirectStream, + streamInfo.RunTimeTicks, + streamInfo.TranscodeSeekInfo); } - return (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';'); + if (streamInfo.MediaType == DlnaProfileType.Video) + { + return new ContentFeatureBuilder(profile) + .BuildVideoHeader(streamInfo.Container, + streamInfo.VideoCodec, + streamInfo.AudioCodec, + streamInfo.TargetWidth, + streamInfo.TargetHeight, + streamInfo.TotalOutputBitrate, + streamInfo.TargetTimestamp, + streamInfo.IsDirectStream, + streamInfo.RunTimeTicks, + streamInfo.TranscodeSeekInfo); + } + + return null; } private PlaylistItem GetPlaylistItem(BaseItem item, List mediaSources, DeviceProfile profile, string deviceId) @@ -477,7 +449,9 @@ namespace MediaBrowser.Dlna.PlayTo MediaSources = mediaSources, Profile = profile, DeviceId = deviceId - }) + }), + + Profile = profile }; } @@ -493,7 +467,9 @@ namespace MediaBrowser.Dlna.PlayTo MediaSources = mediaSources, Profile = profile, DeviceId = deviceId - }) + }), + + Profile = profile }; } diff --git a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs index e0e795429..a7a04038c 100644 --- a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs +++ b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs @@ -104,10 +104,6 @@ namespace MediaBrowser.Dlna.PlayTo } } - public void Stop() - { - } - /// /// Creates a socket for the interface and listends for data. /// diff --git a/MediaBrowser.Dlna/PlayTo/PlayToServerEntryPoint.cs b/MediaBrowser.Dlna/PlayTo/PlayToServerEntryPoint.cs index c0af1295f..c6fbcb90f 100644 --- a/MediaBrowser.Dlna/PlayTo/PlayToServerEntryPoint.cs +++ b/MediaBrowser.Dlna/PlayTo/PlayToServerEntryPoint.cs @@ -104,7 +104,6 @@ namespace MediaBrowser.Dlna.PlayTo { try { - _manager.Stop(); _manager.Dispose(); } catch (Exception ex) diff --git a/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs b/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs index 95167cfe9..2af9f8da9 100644 --- a/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs +++ b/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs @@ -11,5 +11,7 @@ namespace MediaBrowser.Dlna.PlayTo public string Didl { get; set; } public StreamInfo StreamInfo { get; set; } + + public DeviceProfile Profile { get; set; } } } \ No newline at end of file diff --git a/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs b/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs index 29d44bca0..796ccb004 100644 --- a/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs +++ b/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs @@ -19,7 +19,9 @@ namespace MediaBrowser.Dlna.PlayTo { ItemId = item.Id.ToString("N"), MediaType = DlnaProfileType.Photo, - } + }, + + Profile = profile }; var directPlay = profile.DirectPlayProfiles diff --git a/MediaBrowser.Dlna/Server/ControlHandler.cs b/MediaBrowser.Dlna/Server/ControlHandler.cs index 368f06df4..2146317d2 100644 --- a/MediaBrowser.Dlna/Server/ControlHandler.cs +++ b/MediaBrowser.Dlna/Server/ControlHandler.cs @@ -632,9 +632,7 @@ namespace MediaBrowser.Dlna.Server var mediaProfile = _profile.GetVideoMediaProfile(streamInfo.Container, streamInfo.AudioCodec, - streamInfo.VideoCodec, - streamInfo.TargetAudioStream, - streamInfo.TargetVideoStream); + streamInfo.VideoCodec); var formatProfile = mediaProfile == null ? null : mediaProfile.OrgPn; @@ -646,7 +644,7 @@ namespace MediaBrowser.Dlna.Server targetWidth, targetHeight, targetBitrate, - TransportStreamTimestamp.VALID); + streamInfo.TargetTimestamp); formatProfile = format.HasValue ? format.Value.ToString() : null; } @@ -731,8 +729,7 @@ namespace MediaBrowser.Dlna.Server } var mediaProfile = _profile.GetAudioMediaProfile(streamInfo.Container, - streamInfo.AudioCodec, - streamInfo.TargetAudioStream); + streamInfo.AudioCodec); var formatProfile = mediaProfile == null ? null : mediaProfile.OrgPn; @@ -780,11 +777,11 @@ namespace MediaBrowser.Dlna.Server { if (item is MusicAlbum) { - classType = "object.container.musicAlbum"; + classType = "object.container.album.musicAlbum"; } if (item is MusicArtist) { - classType = "object.container.musicArtist"; + classType = "object.container.person.musicArtist"; } } diff --git a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs new file mode 100644 index 000000000..bd98704a9 --- /dev/null +++ b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs @@ -0,0 +1,130 @@ +using System; + +namespace MediaBrowser.Model.Dlna +{ + public class ContentFeatureBuilder + { + private readonly DeviceProfile _profile; + + public ContentFeatureBuilder(DeviceProfile profile) + { + _profile = profile; + } + + public string BuildAudioHeader(string container, + string audioCodec, + int? audioBitrate, + int? audioSampleRate, + int? audioChannels, + bool isDirectStream, + long? runtimeTicks, + TranscodeSeekInfo transcodeSeekInfo) + { + // 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 + var orgOp = ";DLNA.ORG_OP=" + DlnaMaps.GetOrgOpValue(runtimeTicks.HasValue, isDirectStream, transcodeSeekInfo); + + // 0 = native, 1 = transcoded + var orgCi = isDirectStream ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1"; + + var flagValue = DlnaFlags.StreamingTransferMode | + DlnaFlags.BackgroundTransferMode | + DlnaFlags.DlnaV15; + + if (isDirectStream) + { + //flagValue = flagValue | DlnaFlags.DLNA_ORG_FLAG_BYTE_BASED_SEEK; + } + else if (runtimeTicks.HasValue) + { + //flagValue = flagValue | DlnaFlags.DLNA_ORG_FLAG_TIME_BASED_SEEK; + } + + var dlnaflags = string.Format(";DLNA.ORG_FLAGS={0}000000000000000000000000", + Enum.Format(typeof(DlnaFlags), flagValue, "x")); + + var mediaProfile = _profile.GetAudioMediaProfile(container, audioCodec); + + var orgPn = mediaProfile == null ? null : mediaProfile.OrgPn; + + if (string.IsNullOrEmpty(orgPn)) + { + orgPn = GetAudioOrgPnValue(container, audioBitrate, audioSampleRate, audioChannels); + } + + var contentFeatures = string.IsNullOrEmpty(orgPn) ? string.Empty : "DLNA.ORG_PN=" + orgPn; + + return (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';'); + } + + public string BuildVideoHeader(string container, + string videoCodec, + string audioCodec, + int? width, + int? height, + int? bitrate, + TransportStreamTimestamp timestamp, + bool isDirectStream, + long? runtimeTicks, + TranscodeSeekInfo transcodeSeekInfo) + { + // 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 + var orgOp = ";DLNA.ORG_OP=" + DlnaMaps.GetOrgOpValue(runtimeTicks.HasValue, isDirectStream, transcodeSeekInfo); + + // 0 = native, 1 = transcoded + var orgCi = isDirectStream ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1"; + + var flagValue = DlnaFlags.StreamingTransferMode | + DlnaFlags.BackgroundTransferMode | + DlnaFlags.DlnaV15; + + if (isDirectStream) + { + //flagValue = flagValue | DlnaFlags.DLNA_ORG_FLAG_BYTE_BASED_SEEK; + } + else if (runtimeTicks.HasValue) + { + //flagValue = flagValue | DlnaFlags.DLNA_ORG_FLAG_TIME_BASED_SEEK; + } + + var dlnaflags = string.Format(";DLNA.ORG_FLAGS={0}000000000000000000000000", + Enum.Format(typeof(DlnaFlags), flagValue, "x")); + + var mediaProfile = _profile.GetVideoMediaProfile(container, audioCodec, videoCodec); + var orgPn = mediaProfile == null ? null : mediaProfile.OrgPn; + + if (string.IsNullOrEmpty(orgPn)) + { + orgPn = GetVideoOrgPnValue(container, videoCodec, audioCodec, width, height, bitrate, timestamp); + } + + var contentFeatures = string.IsNullOrEmpty(orgPn) ? string.Empty : "DLNA.ORG_PN=" + orgPn; + + return (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';'); + } + + private string GetAudioOrgPnValue(string container, int? audioBitrate, int? audioSampleRate, int? audioChannels) + { + var format = new MediaFormatProfileResolver() + .ResolveAudioFormat(container, + audioBitrate, + audioSampleRate, + audioChannels); + + return format.HasValue ? format.Value.ToString() : null; + } + + private string GetVideoOrgPnValue(string container, string videoCodec, string audioCodec, int? width, int? height, int? bitrate, TransportStreamTimestamp timestamp) + { + var videoFormat = new MediaFormatProfileResolver() + .ResolveVideoFormat(container, + videoCodec, + audioCodec, + width, + height, + bitrate, + timestamp); + + return videoFormat.HasValue ? videoFormat.Value.ToString() : null; + } + } +} diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs index df717fd10..106ba75b0 100644 --- a/MediaBrowser.Model/Dlna/DeviceProfile.cs +++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs @@ -159,7 +159,7 @@ namespace MediaBrowser.Model.Dlna }); } - public ResponseProfile GetAudioMediaProfile(string container, string audioCodec, MediaStream audioStream) + public ResponseProfile GetAudioMediaProfile(string container, string audioCodec) { container = (container ?? string.Empty).TrimStart('.'); @@ -186,7 +186,7 @@ namespace MediaBrowser.Model.Dlna }); } - public ResponseProfile GetVideoMediaProfile(string container, string audioCodec, string videoCodec, MediaStream audioStream, MediaStream videoStream) + public ResponseProfile GetVideoMediaProfile(string container, string audioCodec, string videoCodec) { container = (container ?? string.Empty).TrimStart('.'); diff --git a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs index 7034aee72..02400a7ff 100644 --- a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs +++ b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs @@ -33,7 +33,7 @@ namespace MediaBrowser.Model.Dlna string.Equals(container, "m2ts", StringComparison.OrdinalIgnoreCase)) { - var list = ResolveVideoMPEG2TSFormat(videoCodec, audioCodec, width, height, bitrate, timestampType) + var list = ResolveVideoMPEG2TSFormat(videoCodec, audioCodec, width, height, timestampType) .ToList(); return list.Count > 0 ? list[0] : (MediaFormatProfile?)null; @@ -54,7 +54,7 @@ namespace MediaBrowser.Model.Dlna return null; } - private IEnumerable ResolveVideoMPEG2TSFormat(string videoCodec, string audioCodec, int? width, int? height, int? bitrate, TransportStreamTimestamp timestampType) + private IEnumerable ResolveVideoMPEG2TSFormat(string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType) { var suffix = ""; diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index a0cfe037b..c5589322d 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Drawing; +using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using System; using System.Collections.Generic; @@ -56,6 +57,8 @@ namespace MediaBrowser.Model.Dlna public MediaSourceInfo MediaSource { get; set; } + public TransportStreamTimestamp TargetTimestamp { get; set; } + public string MediaSourceId { get @@ -252,6 +255,68 @@ namespace MediaBrowser.Model.Dlna : stream == null ? null : stream.Channels; } } + + public int? TotalOutputBitrate + { + get + { + return (TargetAudioBitrate ?? 0) + (VideoBitrate ?? 0); + } + } + + public int? TargetWidth + { + get + { + var videoStream = TargetVideoStream; + + if (videoStream != null && videoStream.Width.HasValue && videoStream.Height.HasValue) + { + var size = new ImageSize + { + Width = videoStream.Width.Value, + Height = videoStream.Height.Value + }; + + var newSize = DrawingUtils.Resize(size, + null, + null, + MaxWidth, + MaxHeight); + + return Convert.ToInt32(newSize.Width); + } + + return MaxWidth; + } + } + + public int? TargetHeight + { + get + { + var videoStream = TargetVideoStream; + + if (videoStream != null && videoStream.Width.HasValue && videoStream.Height.HasValue) + { + var size = new ImageSize + { + Width = videoStream.Width.Value, + Height = videoStream.Height.Value + }; + + var newSize = DrawingUtils.Resize(size, + null, + null, + MaxWidth, + MaxHeight); + + return Convert.ToInt32(newSize.Height); + } + + return MaxHeight; + } + } } /// diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index c18d7e8dc..4d0214eb8 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -68,6 +68,7 @@ +