From e3c52b6f73d938033d5d4d5db1284a2367c75ecd Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 5 Aug 2014 22:26:12 -0400 Subject: [PATCH] support srt in didl --- .../Playback/BaseStreamingService.cs | 5 ++- .../Playback/Hls/DynamicHlsService.cs | 2 -- MediaBrowser.Api/Playback/StreamRequest.cs | 6 +++- MediaBrowser.Common/Net/MimeTypes.cs | 5 +++ .../ContentDirectory/ControlHandler.cs | 25 ++++++++++++--- MediaBrowser.Dlna/Didl/DidlBuilder.cs | 19 ++++++++++- MediaBrowser.Model/Dlna/StreamInfo.cs | 32 +++++++++++++++++-- 7 files changed, 81 insertions(+), 13 deletions(-) diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index bfbad56359..9d54458a6e 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1642,7 +1642,10 @@ namespace MediaBrowser.Api.Playback // Can't stream copy if we're burning in subtitles if (request.SubtitleStreamIndex.HasValue) { - return false; + if (request.SubtitleMethod == SubtitleDeliveryMethod.Encode) + { + return false; + } } // Source and target codecs must match diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index 53cc41501e..42fa63fb7a 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -25,8 +25,6 @@ namespace MediaBrowser.Api.Playback.Hls { public bool EnableAdaptiveBitrateStreaming { get; set; } - public SubtitleDeliveryMethod SubtitleMethod { get; set; } - public GetMasterHlsVideoStream() { EnableAdaptiveBitrateStreaming = true; diff --git a/MediaBrowser.Api/Playback/StreamRequest.cs b/MediaBrowser.Api/Playback/StreamRequest.cs index dfb57ef0d7..c72ead949d 100644 --- a/MediaBrowser.Api/Playback/StreamRequest.cs +++ b/MediaBrowser.Api/Playback/StreamRequest.cs @@ -1,4 +1,5 @@ -using ServiceStack; +using MediaBrowser.Model.Dlna; +using ServiceStack; namespace MediaBrowser.Api.Playback { @@ -160,6 +161,9 @@ namespace MediaBrowser.Api.Playback [ApiMember(Name = "Level", Description = "Optional. Specify a level for the h264 profile, e.g. 3, 3.1.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string Level { get; set; } + [ApiMember(Name = "SubtitleDeliveryMethod", Description = "Optional. Specify the subtitle delivery method.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public SubtitleDeliveryMethod SubtitleMethod { get; set; } + /// /// Gets a value indicating whether this instance has fixed resolution. /// diff --git a/MediaBrowser.Common/Net/MimeTypes.cs b/MediaBrowser.Common/Net/MimeTypes.cs index 0740bf6d13..ee3b7dad6e 100644 --- a/MediaBrowser.Common/Net/MimeTypes.cs +++ b/MediaBrowser.Common/Net/MimeTypes.cs @@ -236,6 +236,11 @@ namespace MediaBrowser.Common.Net return "text/vtt"; } + if (ext.Equals(".ttml", StringComparison.OrdinalIgnoreCase)) + { + return "application/ttml+xml"; + } + if (ext.Equals(".bif", StringComparison.OrdinalIgnoreCase)) { return "application/octet-stream"; diff --git a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs index 4eb6baeed2..05d822185f 100644 --- a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs +++ b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs @@ -183,19 +183,34 @@ namespace MediaBrowser.Dlna.ContentDirectory //didl.SetAttribute("xmlns:sec", NS_SEC); result.AppendChild(didl); - var folder = (Folder)GetItemFromObjectId(id, user); + var item = GetItemFromObjectId(id, user); - var childrenResult = (await GetChildrenSorted(folder, user, sortCriteria, start, requested).ConfigureAwait(false)); - - var totalCount = childrenResult.TotalRecordCount; + var totalCount = 0; if (string.Equals(flag, "BrowseMetadata")) { - result.DocumentElement.AppendChild(_didlBuilder.GetFolderElement(result, folder, totalCount, filter)); + var folder = item as Folder; + + if (folder == null) + { + result.DocumentElement.AppendChild(_didlBuilder.GetItemElement(result, item, deviceId, filter)); + } + else + { + var childrenResult = (await GetChildrenSorted(folder, user, sortCriteria, start, requested).ConfigureAwait(false)); + totalCount = childrenResult.TotalRecordCount; + + result.DocumentElement.AppendChild(_didlBuilder.GetFolderElement(result, folder, totalCount, filter)); + } provided++; } else { + var folder = (Folder)item; + + var childrenResult = (await GetChildrenSorted(folder, user, sortCriteria, start, requested).ConfigureAwait(false)); + totalCount = childrenResult.TotalRecordCount; + provided = childrenResult.Items.Length; foreach (var i in childrenResult.Items) diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs index ec86f69e79..cbdd427afb 100644 --- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs +++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs @@ -101,7 +101,7 @@ namespace MediaBrowser.Dlna.Didl { var sources = _user == null ? video.GetMediaSources(true).ToList() : video.GetMediaSources(true, _user).ToList(); - streamInfo = new StreamBuilder().BuildVideoItem(new VideoOptions + streamInfo = new StreamBuilder().BuildVideoItem(new VideoOptions { ItemId = video.Id.ToString("N"), MediaSources = sources, @@ -137,6 +137,23 @@ namespace MediaBrowser.Dlna.Didl { AddVideoResource(container, video, deviceId, filter, contentFeature, streamInfo); } + + foreach (var subtitle in streamInfo.GetExternalSubtitles(_serverAddress)) + { + AddSubtitleElement(container, subtitle); + } + } + + private void AddSubtitleElement(XmlElement container, SubtitleStreamInfo info) + { + var res = container.OwnerDocument.CreateElement(string.Empty, "res", NS_DIDL); + + res.InnerText = info.Url; + + // TODO: Remove this hard-coding + res.SetAttribute("protocolInfo", "http-get:*:text/srt:*"); + + container.AppendChild(res); } private void AddVideoResource(XmlElement container, Video video, string deviceId, Filter filter, string contentFeatures, StreamInfo streamInfo) diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index f299a30c9b..a38a6aff8c 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -131,7 +131,7 @@ namespace MediaBrowser.Model.Dlna return string.Format("Params={0}", string.Join(";", list.ToArray())); } - public string ToSubtitleUrl(string baseUrl) + public List GetExternalSubtitles(string baseUrl) { if (SubtitleDeliveryMethod != SubtitleDeliveryMethod.External) { @@ -148,13 +148,31 @@ namespace MediaBrowser.Model.Dlna ? 0 : StartPositionTicks; - return string.Format("{0}/Videos/{1}/{2}/Subtitles/{3}/{4}/Stream.{5}", + string url = string.Format("{0}/Videos/{1}/{2}/Subtitles/{3}/{4}/Stream.{5}", baseUrl, ItemId, MediaSourceId, StringHelper.ToStringCultureInvariant(SubtitleStreamIndex.Value), StringHelper.ToStringCultureInvariant(startPositionTicks), SubtitleFormat); + + List list = new List(); + + foreach (MediaStream stream in MediaSource.MediaStreams) + { + if (stream.Type == MediaStreamType.Subtitle && stream.Index == SubtitleStreamIndex.Value) + { + list.Add(new SubtitleStreamInfo + { + Url = url, + IsForced = stream.IsForced, + Language = stream.Language, + Name = stream.Language ?? "Unknown" + }); + } + } + + return list; } /// @@ -170,7 +188,7 @@ namespace MediaBrowser.Model.Dlna { foreach (MediaStream i in MediaSource.MediaStreams) { - if (i.Index == AudioStreamIndex.Value && i.Type == MediaStreamType.Audio) + if (i.Index == AudioStreamIndex.Value && i.Type == MediaStreamType.Audio) return i; } return null; @@ -482,4 +500,12 @@ namespace MediaBrowser.Model.Dlna /// Hls = 3 } + + public class SubtitleStreamInfo + { + public string Url { get; set; } + public string Language { get; set; } + public string Name { get; set; } + public bool IsForced { get; set; } + } }