aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Model/Dlna/StreamBuilder.cs
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Model/Dlna/StreamBuilder.cs')
-rw-r--r--MediaBrowser.Model/Dlna/StreamBuilder.cs224
1 files changed, 150 insertions, 74 deletions
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs
index 6fa29a533..6edbe00da 100644
--- a/MediaBrowser.Model/Dlna/StreamBuilder.cs
+++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs
@@ -10,28 +10,40 @@ namespace MediaBrowser.Model.Dlna
{
public class StreamBuilder
{
+ private readonly ILocalPlayer _localPlayer;
+
+ public StreamBuilder(ILocalPlayer localPlayer)
+ {
+ _localPlayer = localPlayer;
+ }
+ public StreamBuilder()
+ : this(new NullLocalPlayer())
+ {
+ }
+
public StreamInfo BuildAudioItem(AudioOptions options)
{
ValidateAudioInput(options);
- List<MediaSourceInfo> mediaSources = options.MediaSources;
-
- // If the client wants a specific media source, filter now
- if (!string.IsNullOrEmpty(options.MediaSourceId))
+ List<MediaSourceInfo> mediaSources = new List<MediaSourceInfo>();
+ foreach (MediaSourceInfo i in options.MediaSources)
{
- List<MediaSourceInfo> newMediaSources = new List<MediaSourceInfo>();
- foreach (MediaSourceInfo i in mediaSources)
+ if (string.IsNullOrEmpty(options.MediaSourceId) ||
+ StringHelper.EqualsIgnoreCase(i.Id, options.MediaSourceId))
{
- if (StringHelper.EqualsIgnoreCase(i.Id, options.MediaSourceId))
- newMediaSources.Add(i);
+ mediaSources.Add(i);
}
-
- mediaSources = newMediaSources;
}
List<StreamInfo> streams = new List<StreamInfo>();
foreach (MediaSourceInfo i in mediaSources)
- streams.Add(BuildAudioItem(i, options));
+ {
+ StreamInfo streamInfo = BuildAudioItem(i, options);
+ if (streamInfo != null)
+ {
+ streams.Add(streamInfo);
+ }
+ }
foreach (StreamInfo stream in streams)
{
@@ -46,24 +58,25 @@ namespace MediaBrowser.Model.Dlna
{
ValidateInput(options);
- List<MediaSourceInfo> mediaSources = options.MediaSources;
-
- // If the client wants a specific media source, filter now
- if (!string.IsNullOrEmpty(options.MediaSourceId))
+ List<MediaSourceInfo> mediaSources = new List<MediaSourceInfo>();
+ foreach (MediaSourceInfo i in options.MediaSources)
{
- List<MediaSourceInfo> newMediaSources = new List<MediaSourceInfo>();
- foreach (MediaSourceInfo i in mediaSources)
+ if (string.IsNullOrEmpty(options.MediaSourceId) ||
+ StringHelper.EqualsIgnoreCase(i.Id, options.MediaSourceId))
{
- if (StringHelper.EqualsIgnoreCase(i.Id, options.MediaSourceId))
- newMediaSources.Add(i);
+ mediaSources.Add(i);
}
-
- mediaSources = newMediaSources;
}
List<StreamInfo> streams = new List<StreamInfo>();
foreach (MediaSourceInfo i in mediaSources)
- streams.Add(BuildVideoItem(i, options));
+ {
+ StreamInfo streamInfo = BuildVideoItem(i, options);
+ if (streamInfo != null)
+ {
+ streams.Add(streamInfo);
+ }
+ }
foreach (StreamInfo stream in streams)
{
@@ -97,7 +110,10 @@ namespace MediaBrowser.Model.Dlna
{
return stream;
}
- return null;
+
+ PlaybackException error = new PlaybackException();
+ error.ErrorCode = PlaybackErrorCode.NoCompatibleStream;
+ throw error;
}
private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options)
@@ -112,64 +128,66 @@ namespace MediaBrowser.Model.Dlna
DeviceProfile = options.Profile
};
- int? maxBitrateSetting = options.GetMaxBitrate();
-
- MediaStream audioStream = item.DefaultAudioStream;
+ List<PlayMethod> directPlayMethods = GetAudioDirectPlayMethods(item, options);
- // Honor the max bitrate setting
- if (IsAudioEligibleForDirectPlay(item, maxBitrateSetting))
+ if (directPlayMethods.Count > 0)
{
- DirectPlayProfile directPlay = null;
- foreach (DirectPlayProfile i in options.Profile.DirectPlayProfiles)
- {
- if (i.Type == playlistItem.MediaType && IsAudioDirectPlaySupported(i, item, audioStream))
- {
- directPlay = i;
- break;
- }
- }
+ MediaStream audioStream = item.DefaultAudioStream;
- if (directPlay != null)
+ string audioCodec = audioStream == null ? null : audioStream.Codec;
+
+ // Make sure audio codec profiles are satisfied
+ if (!string.IsNullOrEmpty(audioCodec))
{
- string audioCodec = audioStream == null ? null : audioStream.Codec;
+ ConditionProcessor conditionProcessor = new ConditionProcessor();
- // Make sure audio codec profiles are satisfied
- if (!string.IsNullOrEmpty(audioCodec))
+ List<ProfileCondition> conditions = new List<ProfileCondition>();
+ foreach (CodecProfile i in options.Profile.CodecProfiles)
{
- ConditionProcessor conditionProcessor = new ConditionProcessor();
-
- List<ProfileCondition> conditions = new List<ProfileCondition>();
- foreach (CodecProfile i in options.Profile.CodecProfiles)
+ if (i.Type == CodecType.Audio && i.ContainsCodec(audioCodec))
{
- if (i.Type == CodecType.Audio && i.ContainsCodec(audioCodec))
+ foreach (ProfileCondition c in i.Conditions)
{
- foreach (ProfileCondition c in i.Conditions)
- {
- conditions.Add(c);
- }
+ conditions.Add(c);
}
}
+ }
- int? audioChannels = audioStream.Channels;
- int? audioBitrate = audioStream.BitRate;
+ int? audioChannels = audioStream.Channels;
+ int? audioBitrate = audioStream.BitRate;
- bool all = true;
- foreach (ProfileCondition c in conditions)
+ bool all = true;
+ foreach (ProfileCondition c in conditions)
+ {
+ if (!conditionProcessor.IsAudioConditionSatisfied(c, audioChannels, audioBitrate))
{
- if (!conditionProcessor.IsAudioConditionSatisfied(c, audioChannels, audioBitrate))
- {
- all = false;
- break;
- }
+ all = false;
+ break;
}
+ }
- if (all)
+ if (all)
+ {
+ if (item.Protocol == MediaProtocol.File &&
+ directPlayMethods.Contains(PlayMethod.DirectPlay) &&
+ _localPlayer.CanAccessFile(item.Path))
+ {
+ playlistItem.PlayMethod = PlayMethod.DirectPlay;
+ }
+ else if (item.Protocol == MediaProtocol.Http &&
+ directPlayMethods.Contains(PlayMethod.DirectPlay) &&
+ _localPlayer.CanAccessUrl(item.Path, item.RequiredHttpHeaders.Count > 0))
+ {
+ playlistItem.PlayMethod = PlayMethod.DirectPlay;
+ }
+ else if (directPlayMethods.Contains(PlayMethod.DirectStream))
{
playlistItem.PlayMethod = PlayMethod.DirectStream;
- playlistItem.Container = item.Container;
-
- return playlistItem;
}
+
+ playlistItem.Container = item.Container;
+
+ return playlistItem;
}
}
}
@@ -186,6 +204,11 @@ namespace MediaBrowser.Model.Dlna
if (transcodingProfile != null)
{
+ if (!item.SupportsTranscoding)
+ {
+ return null;
+ }
+
playlistItem.PlayMethod = PlayMethod.Transcode;
playlistItem.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo;
playlistItem.EstimateContentLength = transcodingProfile.EstimateContentLength;
@@ -233,6 +256,41 @@ namespace MediaBrowser.Model.Dlna
return playlistItem;
}
+ private List<PlayMethod> GetAudioDirectPlayMethods(MediaSourceInfo item, AudioOptions options)
+ {
+ MediaStream audioStream = item.DefaultAudioStream;
+
+ DirectPlayProfile directPlayProfile = null;
+ foreach (DirectPlayProfile i in options.Profile.DirectPlayProfiles)
+ {
+ if (i.Type == DlnaProfileType.Audio && IsAudioDirectPlaySupported(i, item, audioStream))
+ {
+ directPlayProfile = i;
+ break;
+ }
+ }
+
+ List<PlayMethod> playMethods = new List<PlayMethod>();
+
+ if (directPlayProfile != null)
+ {
+ // While options takes the network and other factors into account. Only applies to direct stream
+ if (item.SupportsDirectStream && IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate()))
+ {
+ playMethods.Add(PlayMethod.DirectStream);
+ }
+
+ // The profile describes what the device supports
+ // If device requirements are satisfied then allow both direct stream and direct play
+ if (IsAudioEligibleForDirectPlay(item, options.Profile.MaxStaticBitrate))
+ {
+ playMethods.Add(PlayMethod.DirectPlay);
+ }
+ }
+
+ return playMethods;
+ }
+
private StreamInfo BuildVideoItem(MediaSourceInfo item, VideoOptions options)
{
StreamInfo playlistItem = new StreamInfo
@@ -267,7 +325,7 @@ namespace MediaBrowser.Model.Dlna
if (subtitleStream != null)
{
- SubtitleProfile subtitleProfile = GetSubtitleProfile(subtitleStream, options.Profile);
+ SubtitleProfile subtitleProfile = GetSubtitleProfile(subtitleStream, options.Profile, options.Context);
playlistItem.SubtitleDeliveryMethod = subtitleProfile.Method;
playlistItem.SubtitleFormat = subtitleProfile.Format;
@@ -290,9 +348,14 @@ namespace MediaBrowser.Model.Dlna
if (transcodingProfile != null)
{
+ if (!item.SupportsTranscoding)
+ {
+ return null;
+ }
+
if (subtitleStream != null)
{
- SubtitleProfile subtitleProfile = GetSubtitleProfile(subtitleStream, options.Profile);
+ SubtitleProfile subtitleProfile = GetSubtitleProfile(subtitleStream, options.Profile, options.Context);
playlistItem.SubtitleDeliveryMethod = subtitleProfile.Method;
playlistItem.SubtitleFormat = subtitleProfile.Format;
@@ -505,18 +568,25 @@ namespace MediaBrowser.Model.Dlna
if (mediaSource.Protocol == MediaProtocol.Http)
{
- if (!options.SupportsDirectRemoteContent)
+ if (_localPlayer.CanAccessUrl(mediaSource.Path, mediaSource.RequiredHttpHeaders.Count > 0))
{
- return null;
+ return PlayMethod.DirectPlay;
}
+ }
- if (mediaSource.RequiredHttpHeaders.Count > 0 && !options.SupportsCustomHttpHeaders)
+ else if (mediaSource.Protocol == MediaProtocol.File)
+ {
+ if (_localPlayer.CanAccessFile(mediaSource.Path))
{
- return null;
+ return PlayMethod.DirectPlay;
}
- return PlayMethod.DirectPlay;
}
+ if (!mediaSource.SupportsDirectStream)
+ {
+ return null;
+ }
+
return PlayMethod.DirectStream;
}
@@ -527,7 +597,7 @@ namespace MediaBrowser.Model.Dlna
{
if (subtitleStream != null)
{
- SubtitleProfile subtitleProfile = GetSubtitleProfile(subtitleStream, options.Profile);
+ SubtitleProfile subtitleProfile = GetSubtitleProfile(subtitleStream, options.Profile, options.Context);
if (subtitleProfile.Method != SubtitleDeliveryMethod.External && subtitleProfile.Method != SubtitleDeliveryMethod.Embed)
{
@@ -538,14 +608,20 @@ namespace MediaBrowser.Model.Dlna
return IsAudioEligibleForDirectPlay(item, maxBitrate);
}
- public static SubtitleProfile GetSubtitleProfile(MediaStream subtitleStream, DeviceProfile deviceProfile)
+ public static SubtitleProfile GetSubtitleProfile(MediaStream subtitleStream, DeviceProfile deviceProfile, EncodingContext context)
{
// Look for an external profile that matches the stream type (text/graphical)
foreach (SubtitleProfile profile in deviceProfile.SubtitleProfiles)
{
- if (subtitleStream.SupportsExternalStream)
+ if (profile.Method == SubtitleDeliveryMethod.External && subtitleStream.IsTextSubtitleStream == MediaStream.IsTextFormat(profile.Format))
{
- if (profile.Method == SubtitleDeliveryMethod.External && subtitleStream.IsTextSubtitleStream == MediaStream.IsTextFormat(profile.Format))
+ if (subtitleStream.SupportsExternalStream)
+ {
+ return profile;
+ }
+
+ // For sync we can handle the longer extraction times
+ if (context == EncodingContext.Static && subtitleStream.IsTextSubtitleStream)
{
return profile;
}