aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Model/Dlna
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Model/Dlna')
-rw-r--r--MediaBrowser.Model/Dlna/AudioOptions.cs6
-rw-r--r--MediaBrowser.Model/Dlna/DeviceProfile.cs6
-rw-r--r--MediaBrowser.Model/Dlna/StreamBuilder.cs159
-rw-r--r--MediaBrowser.Model/Dlna/StreamInfo.cs24
-rw-r--r--MediaBrowser.Model/Dlna/SubtitleProfile.cs8
-rw-r--r--MediaBrowser.Model/Dlna/TranscodingProfile.cs9
-rw-r--r--MediaBrowser.Model/Dlna/VideoOptions.cs6
7 files changed, 183 insertions, 35 deletions
diff --git a/MediaBrowser.Model/Dlna/AudioOptions.cs b/MediaBrowser.Model/Dlna/AudioOptions.cs
index d04133a3d..6e630ee55 100644
--- a/MediaBrowser.Model/Dlna/AudioOptions.cs
+++ b/MediaBrowser.Model/Dlna/AudioOptions.cs
@@ -29,5 +29,11 @@ namespace MediaBrowser.Model.Dlna
/// The application's configured quality setting
/// </summary>
public int? MaxBitrate { get; set; }
+
+ /// <summary>
+ /// Gets or sets the context.
+ /// </summary>
+ /// <value>The context.</value>
+ public EncodingContext Context { get; set; }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs
index deaa30714..4040b57f9 100644
--- a/MediaBrowser.Model/Dlna/DeviceProfile.cs
+++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs
@@ -89,6 +89,9 @@ namespace MediaBrowser.Model.Dlna
public CodecProfile[] CodecProfiles { get; set; }
public ResponseProfile[] ResponseProfiles { get; set; }
+ public SubtitleProfile[] SoftSubtitleProfiles { get; set; }
+ public SubtitleProfile[] ExternalSubtitleProfiles { get; set; }
+
public DeviceProfile()
{
DirectPlayProfiles = new DirectPlayProfile[] { };
@@ -97,6 +100,9 @@ namespace MediaBrowser.Model.Dlna
CodecProfiles = new CodecProfile[] { };
ContainerProfiles = new ContainerProfile[] { };
+ SoftSubtitleProfiles = new SubtitleProfile[] { };
+ ExternalSubtitleProfiles = new SubtitleProfile[] { };
+
XmlRootAttributes = new XmlAttribute[] { };
SupportedMediaTypes = "Audio,Photo,Video";
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
diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs
index e5e013b2a..96aa2167f 100644
--- a/MediaBrowser.Model/Dlna/StreamInfo.cs
+++ b/MediaBrowser.Model/Dlna/StreamInfo.cs
@@ -58,6 +58,8 @@ namespace MediaBrowser.Model.Dlna
public MediaSourceInfo MediaSource { get; set; }
+ public SubtitleDeliveryMethod SubtitleDeliveryMethod { get; set; }
+
public string MediaSourceId
{
get
@@ -108,7 +110,7 @@ namespace MediaBrowser.Model.Dlna
item.VideoCodec ?? string.Empty,
item.AudioCodec ?? string.Empty,
item.AudioStreamIndex.HasValue ? StringHelper.ToStringCultureInvariant(item.AudioStreamIndex.Value) : string.Empty,
- item.SubtitleStreamIndex.HasValue ? StringHelper.ToStringCultureInvariant(item.SubtitleStreamIndex.Value) : string.Empty,
+ item.SubtitleStreamIndex.HasValue && item.SubtitleDeliveryMethod != SubtitleDeliveryMethod.External ? StringHelper.ToStringCultureInvariant(item.SubtitleStreamIndex.Value) : string.Empty,
item.VideoBitrate.HasValue ? StringHelper.ToStringCultureInvariant(item.VideoBitrate.Value) : string.Empty,
item.AudioBitrate.HasValue ? StringHelper.ToStringCultureInvariant(item.AudioBitrate.Value) : string.Empty,
item.MaxAudioChannels.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxAudioChannels.Value) : string.Empty,
@@ -427,4 +429,24 @@ namespace MediaBrowser.Model.Dlna
}
}
}
+
+ public enum SubtitleDeliveryMethod
+ {
+ /// <summary>
+ /// The encode
+ /// </summary>
+ Encode = 0,
+ /// <summary>
+ /// Internal format is supported natively
+ /// </summary>
+ Direct = 1,
+ /// <summary>
+ /// The embed
+ /// </summary>
+ Embed = 2,
+ /// <summary>
+ /// The external
+ /// </summary>
+ External = 3
+ }
}
diff --git a/MediaBrowser.Model/Dlna/SubtitleProfile.cs b/MediaBrowser.Model/Dlna/SubtitleProfile.cs
new file mode 100644
index 000000000..ec38d96ae
--- /dev/null
+++ b/MediaBrowser.Model/Dlna/SubtitleProfile.cs
@@ -0,0 +1,8 @@
+
+namespace MediaBrowser.Model.Dlna
+{
+ public class SubtitleProfile
+ {
+ public string Format { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/Dlna/TranscodingProfile.cs b/MediaBrowser.Model/Dlna/TranscodingProfile.cs
index 51f4bfe61..976f8e8d1 100644
--- a/MediaBrowser.Model/Dlna/TranscodingProfile.cs
+++ b/MediaBrowser.Model/Dlna/TranscodingProfile.cs
@@ -32,6 +32,9 @@ namespace MediaBrowser.Model.Dlna
[XmlAttribute("videoProfile")]
public string VideoProfile { get; set; }
+ [XmlAttribute("context")]
+ public EncodingContext Context { get; set; }
+
public List<string> GetAudioCodecs()
{
List<string> list = new List<string>();
@@ -42,4 +45,10 @@ namespace MediaBrowser.Model.Dlna
return list;
}
}
+
+ public enum EncodingContext
+ {
+ Streaming = 0,
+ Static = 1
+ }
}
diff --git a/MediaBrowser.Model/Dlna/VideoOptions.cs b/MediaBrowser.Model/Dlna/VideoOptions.cs
index 39a5ab1b1..041d2cd5d 100644
--- a/MediaBrowser.Model/Dlna/VideoOptions.cs
+++ b/MediaBrowser.Model/Dlna/VideoOptions.cs
@@ -7,11 +7,5 @@
{
public int? AudioStreamIndex { get; set; }
public int? SubtitleStreamIndex { get; set; }
- public int? MaxAudioTranscodingBitrate { get; set; }
-
- public VideoOptions()
- {
- MaxAudioTranscodingBitrate = 128000;
- }
}
} \ No newline at end of file