diff options
Diffstat (limited to 'MediaBrowser.Model/Dlna/StreamBuilder.cs')
| -rw-r--r-- | MediaBrowser.Model/Dlna/StreamBuilder.cs | 159 |
1 files changed, 131 insertions, 28 deletions
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 8aadd428f..57dedf6cf 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -9,6 +9,8 @@ namespace MediaBrowser.Model.Dlna { public class StreamBuilder { + private string[] _serverTextSubtitleOutputs = new string[] { "srt", "vtt" }; + public StreamInfo BuildAudioItem(AudioOptions options) { ValidateAudioInput(options); @@ -48,16 +50,13 @@ namespace MediaBrowser.Model.Dlna List<MediaSourceInfo> mediaSources = options.MediaSources; - // If the client wants a specific media soure, filter now + // If the client wants a specific media source, filter now if (!string.IsNullOrEmpty(options.MediaSourceId)) { - // Avoid implicitly captured closure - string mediaSourceId = options.MediaSourceId; - var newMediaSources = new List<MediaSourceInfo>(); foreach (MediaSourceInfo i in mediaSources) { - if (StringHelper.EqualsIgnoreCase(i.Id, mediaSourceId)) + if (StringHelper.EqualsIgnoreCase(i.Id, options.MediaSourceId)) newMediaSources.Add(i); } @@ -171,7 +170,7 @@ namespace MediaBrowser.Model.Dlna TranscodingProfile transcodingProfile = null; foreach (TranscodingProfile i in options.Profile.TranscodingProfiles) { - if (i.Type == playlistItem.MediaType) + if (i.Type == playlistItem.MediaType && i.Context == options.Context) { transcodingProfile = i; break; @@ -217,12 +216,9 @@ namespace MediaBrowser.Model.Dlna playlistItem.MaxAudioChannels = Math.Min(options.MaxAudioChannels.Value, currentValue); } - // Honor requested max bitrate - if (maxBitrateSetting.HasValue) + if (!playlistItem.AudioBitrate.HasValue) { - int currentValue = playlistItem.AudioBitrate ?? maxBitrateSetting.Value; - - playlistItem.AudioBitrate = Math.Min(maxBitrateSetting.Value, currentValue); + playlistItem.AudioBitrate = 128000; } } @@ -239,12 +235,17 @@ namespace MediaBrowser.Model.Dlna RunTimeTicks = item.RunTimeTicks }; - MediaStream audioStream = item.DefaultAudioStream; + int? audioStreamIndex = options.AudioStreamIndex ?? item.DefaultAudioStreamIndex; + playlistItem.SubtitleStreamIndex = options.SubtitleStreamIndex ?? item.DefaultSubtitleStreamIndex; + + MediaStream audioStream = audioStreamIndex.HasValue ? item.GetMediaStream(MediaStreamType.Audio, audioStreamIndex.Value) : null; + MediaStream subtitleStream = playlistItem.SubtitleStreamIndex.HasValue ? item.GetMediaStream(MediaStreamType.Subtitle, playlistItem.SubtitleStreamIndex.Value) : null; + MediaStream videoStream = item.VideoStream; int? maxBitrateSetting = options.MaxBitrate ?? options.Profile.MaxBitrate; - if (IsEligibleForDirectPlay(item, options, maxBitrateSetting)) + if (IsEligibleForDirectPlay(item, maxBitrateSetting, subtitleStream, options)) { // See if it can be direct played DirectPlayProfile directPlay = GetVideoDirectPlayProfile(options.Profile, item, videoStream, audioStream); @@ -254,6 +255,11 @@ namespace MediaBrowser.Model.Dlna playlistItem.IsDirectStream = true; playlistItem.Container = item.Container; + if (subtitleStream != null) + { + playlistItem.SubtitleDeliveryMethod = GetDirectStreamSubtitleDeliveryMethod(subtitleStream, options); + } + return playlistItem; } } @@ -262,7 +268,7 @@ namespace MediaBrowser.Model.Dlna TranscodingProfile transcodingProfile = null; foreach (TranscodingProfile i in options.Profile.TranscodingProfiles) { - if (i.Type == playlistItem.MediaType) + if (i.Type == playlistItem.MediaType && i.Context == options.Context) { transcodingProfile = i; break; @@ -271,6 +277,11 @@ namespace MediaBrowser.Model.Dlna if (transcodingProfile != null) { + if (subtitleStream != null) + { + playlistItem.SubtitleDeliveryMethod = GetTranscodedSubtitleDeliveryMethod(subtitleStream, options); + } + playlistItem.IsDirectStream = false; playlistItem.Container = transcodingProfile.Container; playlistItem.EstimateContentLength = transcodingProfile.EstimateContentLength; @@ -278,8 +289,7 @@ namespace MediaBrowser.Model.Dlna playlistItem.AudioCodec = transcodingProfile.AudioCodec.Split(',')[0]; playlistItem.VideoCodec = transcodingProfile.VideoCodec; playlistItem.Protocol = transcodingProfile.Protocol; - playlistItem.AudioStreamIndex = options.AudioStreamIndex ?? item.DefaultAudioStreamIndex; - playlistItem.SubtitleStreamIndex = options.SubtitleStreamIndex ?? item.DefaultSubtitleStreamIndex; + playlistItem.AudioStreamIndex = audioStreamIndex; List<ProfileCondition> videoTranscodingConditions = new List<ProfileCondition>(); foreach (CodecProfile i in options.Profile.CodecProfiles) @@ -317,12 +327,9 @@ namespace MediaBrowser.Model.Dlna playlistItem.MaxAudioChannels = Math.Min(options.MaxAudioChannels.Value, currentValue); } - // Honor requested max bitrate - if (options.MaxAudioTranscodingBitrate.HasValue) + if (!playlistItem.AudioBitrate.HasValue) { - int currentValue = playlistItem.AudioBitrate ?? options.MaxAudioTranscodingBitrate.Value; - - playlistItem.AudioBitrate = Math.Min(options.MaxAudioTranscodingBitrate.Value, currentValue); + playlistItem.AudioBitrate = GetAudioBitrate(playlistItem.TargetAudioChannels, playlistItem.TargetAudioCodec); } // Honor max rate @@ -339,15 +346,22 @@ namespace MediaBrowser.Model.Dlna playlistItem.VideoBitrate = Math.Min(videoBitrate, currentValue); } + } - // Hate to hard-code this, but it's still probably better than being subjected to encoder defaults - if (!playlistItem.VideoBitrate.HasValue) + return playlistItem; + } + + private int GetAudioBitrate(int? channels, string codec) + { + if (channels.HasValue) + { + if (channels.Value >= 5) { - playlistItem.VideoBitrate = 5000000; + return 320000; } } - return playlistItem; + return 128000; } private DirectPlayProfile GetVideoDirectPlayProfile(DeviceProfile profile, @@ -473,16 +487,105 @@ namespace MediaBrowser.Model.Dlna return directPlay; } - private bool IsEligibleForDirectPlay(MediaSourceInfo item, VideoOptions options, int? maxBitrate) + private bool IsEligibleForDirectPlay(MediaSourceInfo item, + int? maxBitrate, + MediaStream subtitleStream, + VideoOptions options) { - if (options.SubtitleStreamIndex.HasValue) + if (subtitleStream != null) { - return false; + if (!subtitleStream.IsTextSubtitleStream) + { + return false; + } + + SubtitleDeliveryMethod subtitleMethod = GetDirectStreamSubtitleDeliveryMethod(subtitleStream, options); + + if (subtitleMethod != SubtitleDeliveryMethod.External && subtitleMethod != SubtitleDeliveryMethod.Direct) + { + return false; + } } return IsAudioEligibleForDirectPlay(item, maxBitrate); } + private SubtitleDeliveryMethod GetDirectStreamSubtitleDeliveryMethod(MediaStream subtitleStream, + VideoOptions options) + { + if (subtitleStream.IsTextSubtitleStream) + { + string subtitleFormat = NormalizeSubtitleFormat(subtitleStream.Codec); + + bool supportsDirect = ContainsSubtitleFormat(options.Profile.SoftSubtitleProfiles, new[] { subtitleFormat }); + + if (supportsDirect) + { + return SubtitleDeliveryMethod.Direct; + } + + // See if the device can retrieve the subtitles externally + bool supportsSubsExternally = options.Context == EncodingContext.Streaming && + ContainsSubtitleFormat(options.Profile.ExternalSubtitleProfiles, _serverTextSubtitleOutputs); + + if (supportsSubsExternally) + { + return SubtitleDeliveryMethod.External; + } + } + + return SubtitleDeliveryMethod.Encode; + } + + private SubtitleDeliveryMethod GetTranscodedSubtitleDeliveryMethod(MediaStream subtitleStream, + VideoOptions options) + { + if (subtitleStream.IsTextSubtitleStream) + { + // See if the device can retrieve the subtitles externally + bool supportsSubsExternally = options.Context == EncodingContext.Streaming && + ContainsSubtitleFormat(options.Profile.ExternalSubtitleProfiles, _serverTextSubtitleOutputs); + + if (supportsSubsExternally) + { + return SubtitleDeliveryMethod.External; + } + + // See if the device can retrieve the subtitles externally + bool supportsEmbedded = ContainsSubtitleFormat(options.Profile.SoftSubtitleProfiles, _serverTextSubtitleOutputs); + + if (supportsEmbedded) + { + return SubtitleDeliveryMethod.Embed; + } + } + + return SubtitleDeliveryMethod.Encode; + } + + private string NormalizeSubtitleFormat(string codec) + { + if (StringHelper.EqualsIgnoreCase(codec, "subrip")) + { + return SubtitleFormat.SRT; + } + + return codec; + } + + private bool ContainsSubtitleFormat(SubtitleProfile[] profiles, string[] formats) + { + foreach (SubtitleProfile profile in profiles) + { + if (ListHelper.ContainsIgnoreCase(formats, profile.Format)) + { + return true; + } + } + + return false; + } + private bool IsAudioEligibleForDirectPlay(MediaSourceInfo item, int? maxBitrate) { // Honor the max bitrate setting |
