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 childrenResult = (await GetChildrenSorted(folder, user, sortCriteria, start, requested).ConfigureAwait(false));
+ var item = GetItemFromObjectId(id, user);
- 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; }
+ }
}