aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MediaBrowser.Api/ApiEntryPoint.cs3
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs4
-rw-r--r--MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs5
-rw-r--r--MediaBrowser.Api/Playback/MediaInfoService.cs2
-rw-r--r--MediaBrowser.Api/Playback/UniversalAudioService.cs7
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs8
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs22
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs2
-rw-r--r--MediaBrowser.Model/Configuration/UserConfiguration.cs1
-rw-r--r--MediaBrowser.Model/Dlna/ProfileCondition.cs1
-rw-r--r--MediaBrowser.Model/Dlna/StreamBuilder.cs271
-rw-r--r--MediaBrowser.Model/Dlna/StreamInfo.cs20
-rw-r--r--MediaBrowser.Model/Dto/MediaSourceInfo.cs4
-rw-r--r--MediaBrowser.Model/Session/TranscodingInfo.cs33
14 files changed, 338 insertions, 45 deletions
diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs
index e4abe96f3..34d0bd413 100644
--- a/MediaBrowser.Api/ApiEntryPoint.cs
+++ b/MediaBrowser.Api/ApiEntryPoint.cs
@@ -265,7 +265,8 @@ namespace MediaBrowser.Api
Height = state.OutputHeight,
AudioChannels = state.OutputAudioChannels,
IsAudioDirect = string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase),
- IsVideoDirect = string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)
+ IsVideoDirect = string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase),
+ TranscodeReasons = state.TranscodeReasons
});
}
}
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index bbee36199..e4ef294d1 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -583,6 +583,10 @@ namespace MediaBrowser.Api.Playback
videoRequest.DeInterlace = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
}
}
+ else if (i == 33)
+ {
+ request.TranscodeReasons = val;
+ }
}
}
diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
index ddd2d8cd2..c6282bbad 100644
--- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
@@ -541,6 +541,11 @@ namespace MediaBrowser.Api.Playback.Hls
{
queryString += "&SegmentContainer=" + state.Request.SegmentContainer;
}
+ // from universal audio service
+ if (!string.IsNullOrWhiteSpace(state.Request.TranscodeReasons) && queryString.IndexOf("TranscodeReasons=", StringComparison.OrdinalIgnoreCase) == -1)
+ {
+ queryString += "&TranscodeReasons=" + state.Request.TranscodeReasons;
+ }
// Main stream
var playlistUrl = isLiveStream ? "live.m3u8" : "main.m3u8";
diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs
index bba8094b6..6853ddbeb 100644
--- a/MediaBrowser.Api/Playback/MediaInfoService.cs
+++ b/MediaBrowser.Api/Playback/MediaInfoService.cs
@@ -513,6 +513,8 @@ namespace MediaBrowser.Api.Playback
var profiles = info.GetSubtitleProfiles(false, "-", accessToken);
mediaSource.DefaultSubtitleStreamIndex = info.SubtitleStreamIndex;
+ mediaSource.TranscodeReasons = info.TranscodeReasons;
+
foreach (var profile in profiles)
{
foreach (var stream in mediaSource.MediaStreams)
diff --git a/MediaBrowser.Api/Playback/UniversalAudioService.cs b/MediaBrowser.Api/Playback/UniversalAudioService.cs
index fffec6948..b9bcd106e 100644
--- a/MediaBrowser.Api/Playback/UniversalAudioService.cs
+++ b/MediaBrowser.Api/Playback/UniversalAudioService.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
+using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Api.Playback.Hls;
using MediaBrowser.Api.Playback.Progressive;
@@ -265,7 +266,8 @@ namespace MediaBrowser.Api.Playback
Static = isStatic,
SegmentContainer = request.TranscodingContainer,
AudioSampleRate = request.MaxAudioSampleRate,
- BreakOnNonKeyFrames = transcodingProfile.BreakOnNonKeyFrames
+ BreakOnNonKeyFrames = transcodingProfile.BreakOnNonKeyFrames,
+ TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray())
};
if (isHeadRequest)
@@ -307,7 +309,8 @@ namespace MediaBrowser.Api.Playback
PlaySessionId = playbackInfoResult.PlaySessionId,
StartTimeTicks = request.StartTimeTicks,
Static = isStatic,
- AudioSampleRate = request.MaxAudioSampleRate
+ AudioSampleRate = request.MaxAudioSampleRate,
+ TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray())
};
if (isHeadRequest)
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index 34b33fde0..ea442ba1e 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -487,7 +487,7 @@ namespace MediaBrowser.Controller.Entities
var folder = this;
innerProgress.RegisterAction(p =>
{
- double newPct = .70 * p + 10;
+ double newPct = .80 * p + 10;
progress.Report(newPct);
ProviderManager.OnRefreshProgress(folder, newPct);
});
@@ -498,11 +498,11 @@ namespace MediaBrowser.Controller.Entities
if (refreshChildMetadata)
{
- progress.Report(80);
+ progress.Report(90);
if (recursive)
{
- ProviderManager.OnRefreshProgress(this, 80);
+ ProviderManager.OnRefreshProgress(this, 90);
}
var container = this as IMetadataContainer;
@@ -512,7 +512,7 @@ namespace MediaBrowser.Controller.Entities
var folder = this;
innerProgress.RegisterAction(p =>
{
- double newPct = .20 * p + 80;
+ double newPct = .10 * p + 90;
progress.Report(newPct);
if (recursive)
{
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
index 57c81ddf7..a83a6a15e 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
+using System.Linq;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
@@ -9,6 +10,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Drawing;
+using MediaBrowser.Model.Session;
namespace MediaBrowser.Controller.MediaEncoding
{
@@ -40,6 +42,24 @@ namespace MediaBrowser.Controller.MediaEncoding
public bool ReadInputAtNativeFramerate { get; set; }
+ private List<TranscodeReason> _transcodeReasons = null;
+ public List<TranscodeReason> TranscodeReasons
+ {
+ get
+ {
+ if (_transcodeReasons == null)
+ {
+ _transcodeReasons = (BaseRequest.TranscodeReasons ?? string.Empty)
+ .Split(',')
+ .Where(i => !string.IsNullOrWhiteSpace(i))
+ .Select(v => (TranscodeReason)Enum.Parse(typeof(TranscodeReason), v, true))
+ .ToList();
+ }
+
+ return _transcodeReasons;
+ }
+ }
+
public bool IgnoreInputDts
{
get
@@ -251,7 +271,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
return AudioStream.SampleRate;
}
- }
+ }
else if (BaseRequest.AudioSampleRate.HasValue)
{
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
index 632c350ad..28ef66566 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
@@ -204,6 +204,8 @@ namespace MediaBrowser.Controller.MediaEncoding
public string SubtitleCodec { get; set; }
+ public string TranscodeReasons { get; set; }
+
/// <summary>
/// Gets or sets the index of the audio stream.
/// </summary>
diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs
index 5567063fe..30b5f384f 100644
--- a/MediaBrowser.Model/Configuration/UserConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs
@@ -55,7 +55,6 @@ namespace MediaBrowser.Model.Configuration
HidePlayedInLatest = true;
PlayDefaultAudioTrack = true;
- DisplayMissingEpisodes = true;
LatestItemsExcludes = new string[] { };
OrderedViews = new string[] { };
diff --git a/MediaBrowser.Model/Dlna/ProfileCondition.cs b/MediaBrowser.Model/Dlna/ProfileCondition.cs
index 3d104f9c4..9234a2713 100644
--- a/MediaBrowser.Model/Dlna/ProfileCondition.cs
+++ b/MediaBrowser.Model/Dlna/ProfileCondition.cs
@@ -1,5 +1,4 @@
using System.Xml.Serialization;
-using MediaBrowser.Model.Dlna;
namespace MediaBrowser.Model.Dlna
{
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs
index 0ecc413f2..b758d5ed5 100644
--- a/MediaBrowser.Model/Dlna/StreamBuilder.cs
+++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs
@@ -105,8 +105,99 @@ namespace MediaBrowser.Model.Dlna
return null;
}
+ private TranscodeReason? GetTranscodeReasonForFailedCondition(ProfileCondition condition)
+ {
+ switch (condition.Property)
+ {
+ case ProfileConditionValue.AudioBitrate:
+ if (condition.Condition == ProfileConditionType.LessThanEqual)
+ {
+ return TranscodeReason.AudioBitrateNotSupported;
+ }
+ return TranscodeReason.AudioBitrateNotSupported;
+
+ case ProfileConditionValue.AudioChannels:
+ if (condition.Condition == ProfileConditionType.LessThanEqual)
+ {
+ return TranscodeReason.AudioChannelsNotSupported;
+ }
+ return TranscodeReason.AudioChannelsNotSupported;
+
+ case ProfileConditionValue.AudioProfile:
+ return TranscodeReason.AudioProfileNotSupported;
+
+ case ProfileConditionValue.AudioSampleRate:
+ return TranscodeReason.AudioSampleRateNotSupported;
+
+ case ProfileConditionValue.Has64BitOffsets:
+ // TODO
+ return null;
+
+ case ProfileConditionValue.Height:
+ return TranscodeReason.VideoResolutionNotSupported;
+
+ case ProfileConditionValue.IsAnamorphic:
+ return TranscodeReason.AnamorphicVideoNotSupported;
+
+ case ProfileConditionValue.IsAvc:
+ // TODO
+ return null;
+
+ case ProfileConditionValue.IsInterlaced:
+ return TranscodeReason.InterlacedVideoNotSupported;
+
+ case ProfileConditionValue.IsSecondaryAudio:
+ return TranscodeReason.SecondaryAudioNotSupported;
+
+ case ProfileConditionValue.NumAudioStreams:
+ // TODO
+ return null;
+
+ case ProfileConditionValue.NumVideoStreams:
+ // TODO
+ return null;
+
+ case ProfileConditionValue.PacketLength:
+ // TODO
+ return null;
+
+ case ProfileConditionValue.RefFrames:
+ return TranscodeReason.RefFramesNotSupported;
+
+ case ProfileConditionValue.VideoBitDepth:
+ return TranscodeReason.VideoBitDepthNotSupported;
+
+ case ProfileConditionValue.VideoBitrate:
+ return TranscodeReason.VideoBitrateNotSupported;
+
+ case ProfileConditionValue.VideoCodecTag:
+ return TranscodeReason.VideoCodecNotSupported;
+
+ case ProfileConditionValue.VideoFramerate:
+ return TranscodeReason.VideoFramerateNotSupported;
+
+ case ProfileConditionValue.VideoLevel:
+ return TranscodeReason.VideoLevelNotSupported;
+
+ case ProfileConditionValue.VideoProfile:
+ return TranscodeReason.VideoProfileNotSupported;
+
+ case ProfileConditionValue.VideoTimestamp:
+ // TODO
+ return null;
+
+ case ProfileConditionValue.Width:
+ return TranscodeReason.VideoResolutionNotSupported;
+
+ default:
+ return null;
+ }
+ }
+
private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options)
{
+ List<TranscodeReason> transcodeReasons = new List<TranscodeReason>();
+
StreamInfo playlistItem = new StreamInfo
{
ItemId = options.ItemId,
@@ -133,7 +224,10 @@ namespace MediaBrowser.Model.Dlna
MediaStream audioStream = item.GetDefaultAudioStream(null);
- List<PlayMethod> directPlayMethods = GetAudioDirectPlayMethods(item, audioStream, options);
+ var directPlayInfo = GetAudioDirectPlayMethods(item, audioStream, options);
+
+ List<PlayMethod> directPlayMethods = directPlayInfo.Item1;
+ transcodeReasons.AddRange(directPlayInfo.Item2);
ConditionProcessor conditionProcessor = new ConditionProcessor();
@@ -180,6 +274,11 @@ namespace MediaBrowser.Model.Dlna
if (!conditionProcessor.IsAudioConditionSatisfied(c, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate))
{
LogConditionFailure(options.Profile, "AudioCodecProfile", c, item);
+ var transcodeReason = GetTranscodeReasonForFailedCondition(c);
+ if (transcodeReason.HasValue)
+ {
+ transcodeReasons.Add(transcodeReason.Value);
+ }
all = false;
break;
}
@@ -292,9 +391,9 @@ namespace MediaBrowser.Model.Dlna
var longBitrate = Math.Min(transcodingBitrate, playlistItem.AudioBitrate ?? transcodingBitrate);
playlistItem.AudioBitrate = longBitrate > int.MaxValue ? int.MaxValue : Convert.ToInt32(longBitrate);
-
}
+ playlistItem.TranscodeReasons = transcodeReasons;
return playlistItem;
}
@@ -308,8 +407,10 @@ namespace MediaBrowser.Model.Dlna
return options.GetMaxBitrate(isAudio);
}
- private List<PlayMethod> GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options)
+ private Tuple<List<PlayMethod>, List<TranscodeReason>> GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options)
{
+ List<TranscodeReason> transcodeReasons = new List<TranscodeReason>();
+
DirectPlayProfile directPlayProfile = null;
foreach (DirectPlayProfile i in options.Profile.DirectPlayProfiles)
{
@@ -325,27 +426,134 @@ namespace MediaBrowser.Model.Dlna
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(true), PlayMethod.DirectStream) && options.EnableDirectStream)
+ if (item.SupportsDirectStream)
{
- playMethods.Add(PlayMethod.DirectStream);
+ if (IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate(true), PlayMethod.DirectStream))
+ {
+ if (options.EnableDirectStream)
+ {
+ playMethods.Add(PlayMethod.DirectStream);
+ }
+ }
+ else
+ {
+ transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit);
+ }
}
// The profile describes what the device supports
// If device requirements are satisfied then allow both direct stream and direct play
- if (item.SupportsDirectPlay &&
- IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true), PlayMethod.DirectPlay) && options.EnableDirectPlay)
+ if (item.SupportsDirectPlay)
{
- playMethods.Add(PlayMethod.DirectPlay);
+ if (IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true), PlayMethod.DirectPlay))
+ {
+ if (options.EnableDirectPlay)
+ {
+ playMethods.Add(PlayMethod.DirectPlay);
+ }
+ }
+ else
+ {
+ transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit);
+ }
}
}
else
{
+ transcodeReasons.InsertRange(0, GetTranscodeReasonsFromDirectPlayProfile(item, null, audioStream, options.Profile.DirectPlayProfiles));
+
_logger.Info("Profile: {0}, No direct play profiles found for Path: {1}",
options.Profile.Name ?? "Unknown Profile",
item.Path ?? "Unknown path");
}
- return playMethods;
+ if (playMethods.Count > 0)
+ {
+ transcodeReasons.Clear();
+ }
+ else
+ {
+ transcodeReasons = transcodeReasons.Distinct().ToList();
+ }
+
+ return new Tuple<List<PlayMethod>, List<TranscodeReason>>(playMethods, transcodeReasons);
+ }
+
+ private List<TranscodeReason> GetTranscodeReasonsFromDirectPlayProfile(MediaSourceInfo item, MediaStream videoStream, MediaStream audioStream, IEnumerable<DirectPlayProfile> directPlayProfiles)
+ {
+ var list = new List<TranscodeReason>();
+ var containerSupported = false;
+ var audioSupported = false;
+ var videoSupported = false;
+
+ foreach (var profile in directPlayProfiles)
+ {
+ if (profile.Container.Length > 0)
+ {
+ // Check container type
+ string mediaContainer = item.Container ?? string.Empty;
+ foreach (string i in profile.GetContainers())
+ {
+ if (StringHelper.EqualsIgnoreCase(i, mediaContainer))
+ {
+ containerSupported = true;
+
+ if (videoStream != null)
+ {
+ // Check video codec
+ List<string> videoCodecs = profile.GetVideoCodecs();
+ if (videoCodecs.Count > 0)
+ {
+ string videoCodec = videoStream.Codec;
+ if (!string.IsNullOrEmpty(videoCodec) && ListHelper.ContainsIgnoreCase(videoCodecs, videoCodec))
+ {
+ videoSupported = true;
+ }
+ }
+ else
+ {
+ videoSupported = true;
+ }
+ }
+
+ if (audioStream != null)
+ {
+ // Check audio codec
+ List<string> audioCodecs = profile.GetAudioCodecs();
+ if (audioCodecs.Count > 0)
+ {
+ string audioCodec = audioStream.Codec;
+ if (!string.IsNullOrEmpty(audioCodec) && ListHelper.ContainsIgnoreCase(audioCodecs, audioCodec))
+ {
+ audioSupported = true;
+ }
+ }
+ else
+ {
+ audioSupported = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!containerSupported)
+ {
+ list.Add(TranscodeReason.ContainerNotSupported);
+ }
+
+ if (videoStream != null && !videoSupported)
+ {
+ list.Add(TranscodeReason.VideoCodecNotSupported);
+ }
+
+ if (audioStream != null && !audioSupported)
+ {
+ list.Add(TranscodeReason.VideoCodecNotSupported);
+ }
+
+ return list;
}
private int? GetDefaultSubtitleStreamIndex(MediaSourceInfo item, SubtitleProfile[] subtitleProfiles)
@@ -393,6 +601,8 @@ namespace MediaBrowser.Model.Dlna
private StreamInfo BuildVideoItem(MediaSourceInfo item, VideoOptions options)
{
+ List<TranscodeReason> transcodeReasons = new List<TranscodeReason>();
+
StreamInfo playlistItem = new StreamInfo
{
ItemId = options.ItemId,
@@ -428,7 +638,8 @@ namespace MediaBrowser.Model.Dlna
if (isEligibleForDirectPlay || isEligibleForDirectStream)
{
// See if it can be direct played
- PlayMethod? directPlay = GetVideoDirectPlayProfile(options, item, videoStream, audioStream, isEligibleForDirectPlay, isEligibleForDirectStream);
+ var directPlayInfo = GetVideoDirectPlayProfile(options, item, videoStream, audioStream, isEligibleForDirectPlay, isEligibleForDirectStream);
+ var directPlay = directPlayInfo.Item1;
if (directPlay != null)
{
@@ -445,6 +656,8 @@ namespace MediaBrowser.Model.Dlna
return playlistItem;
}
+
+ transcodeReasons.AddRange(directPlayInfo.Item2);
}
// Can't direct play, find the transcoding profile
@@ -618,6 +831,8 @@ namespace MediaBrowser.Model.Dlna
}
}
+ playlistItem.TranscodeReasons = transcodeReasons;
+
return playlistItem;
}
@@ -677,7 +892,7 @@ namespace MediaBrowser.Model.Dlna
return Math.Min(defaultBitrate, encoderAudioBitrateLimit);
}
- private PlayMethod? GetVideoDirectPlayProfile(VideoOptions options,
+ private Tuple<PlayMethod?, List<TranscodeReason>> GetVideoDirectPlayProfile(VideoOptions options,
MediaSourceInfo mediaSource,
MediaStream videoStream,
MediaStream audioStream,
@@ -688,11 +903,11 @@ namespace MediaBrowser.Model.Dlna
if (options.ForceDirectPlay)
{
- return PlayMethod.DirectPlay;
+ return new Tuple<PlayMethod?, List<TranscodeReason>>(PlayMethod.DirectPlay, new List<TranscodeReason>());
}
if (options.ForceDirectStream)
{
- return PlayMethod.DirectStream;
+ return new Tuple<PlayMethod?, List<TranscodeReason>>(PlayMethod.DirectStream, new List<TranscodeReason>());
}
if (videoStream == null)
@@ -701,7 +916,7 @@ namespace MediaBrowser.Model.Dlna
profile.Name ?? "Unknown Profile",
mediaSource.Path ?? "Unknown path");
- return null;
+ return new Tuple<PlayMethod?, List<TranscodeReason>>(null, new List<TranscodeReason> { TranscodeReason.UnknownVideoStreamInfo });
}
// See if it can be direct played
@@ -721,7 +936,7 @@ namespace MediaBrowser.Model.Dlna
profile.Name ?? "Unknown Profile",
mediaSource.Path ?? "Unknown path");
- return null;
+ return new Tuple<PlayMethod?, List<TranscodeReason>>(null, GetTranscodeReasonsFromDirectPlayProfile(mediaSource, videoStream, audioStream, profile.DirectPlayProfiles));
}
string container = mediaSource.Container;
@@ -784,7 +999,7 @@ namespace MediaBrowser.Model.Dlna
profile.Name ?? "Unknown Profile",
mediaSource.Path ?? "Unknown path");
- return null;
+ return new Tuple<PlayMethod?, List<TranscodeReason>>(null, new List<TranscodeReason> { TranscodeReason.UnknownVideoStreamInfo });
}
conditions = new List<ProfileCondition>();
@@ -819,7 +1034,12 @@ namespace MediaBrowser.Model.Dlna
{
LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource);
- return null;
+ var transcodeReason = GetTranscodeReasonForFailedCondition(i);
+ var transcodeReasons = transcodeReason.HasValue
+ ? new List<TranscodeReason> { transcodeReason.Value }
+ : new List<TranscodeReason> { };
+
+ return new Tuple<PlayMethod?, List<TranscodeReason>>(null, transcodeReasons);
}
}
@@ -833,7 +1053,7 @@ namespace MediaBrowser.Model.Dlna
profile.Name ?? "Unknown Profile",
mediaSource.Path ?? "Unknown path");
- return null;
+ return new Tuple<PlayMethod?, List<TranscodeReason>>(null, new List<TranscodeReason> { TranscodeReason.UnknownAudioStreamInfo });
}
conditions = new List<ProfileCondition>();
@@ -870,17 +1090,22 @@ namespace MediaBrowser.Model.Dlna
{
LogConditionFailure(profile, "VideoAudioCodecProfile", i, mediaSource);
- return null;
+ var transcodeReason = GetTranscodeReasonForFailedCondition(i);
+ var transcodeReasons = transcodeReason.HasValue
+ ? new List<TranscodeReason> { transcodeReason.Value }
+ : new List<TranscodeReason> { };
+
+ return new Tuple<PlayMethod?, List<TranscodeReason>>(null, transcodeReasons);
}
}
}
if (isEligibleForDirectStream && mediaSource.SupportsDirectStream)
{
- return PlayMethod.DirectStream;
+ return new Tuple<PlayMethod?, List<TranscodeReason>>(PlayMethod.DirectStream, new List<TranscodeReason>());
}
- return null;
+ return new Tuple<PlayMethod?, List<TranscodeReason>>(null, new List<TranscodeReason> { TranscodeReason.ContainerBitrateExceedsLimit });
}
private void LogConditionFailure(DeviceProfile profile, string type, ProfileCondition condition, MediaSourceInfo mediaSource)
@@ -1047,12 +1272,12 @@ namespace MediaBrowser.Model.Dlna
// Don't restrict by bitrate if coming from an external domain
if (item.IsRemote)
{
- return true;
+ return true;
}
if (!maxBitrate.HasValue)
{
- _logger.Info("Cannot "+ playMethod + " due to unknown supported bitrate");
+ _logger.Info("Cannot " + playMethod + " due to unknown supported bitrate");
return false;
}
diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs
index ba5251e8c..d70d89cf7 100644
--- a/MediaBrowser.Model/Dlna/StreamInfo.cs
+++ b/MediaBrowser.Model/Dlna/StreamInfo.cs
@@ -21,6 +21,7 @@ namespace MediaBrowser.Model.Dlna
AudioCodecs = new string[] { };
VideoCodecs = new string[] { };
SubtitleCodecs = new string[] { };
+ TranscodeReasons = new List<TranscodeReason>();
}
public string ItemId { get; set; }
@@ -89,6 +90,7 @@ namespace MediaBrowser.Model.Dlna
public string PlaySessionId { get; set; }
public List<MediaSourceInfo> AllMediaSources { get; set; }
+ public List<TranscodeReason> TranscodeReasons { get; set; }
public string MediaSourceId
{
@@ -231,22 +233,11 @@ namespace MediaBrowser.Model.Dlna
list.Add(new NameValuePair("MaxWidth", item.MaxWidth.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxWidth.Value) : string.Empty));
list.Add(new NameValuePair("MaxHeight", item.MaxHeight.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxHeight.Value) : string.Empty));
- var forceStartPosition = false;
long startPositionTicks = item.StartPositionTicks;
- //if (item.MediaSource.DateLiveStreamOpened.HasValue && startPositionTicks == 0)
- //{
- // var elapsed = DateTime.UtcNow - item.MediaSource.DateLiveStreamOpened.Value;
- // elapsed -= TimeSpan.FromSeconds(20);
- // if (elapsed.TotalSeconds >= 0)
- // {
- // startPositionTicks = elapsed.Ticks + startPositionTicks;
- // forceStartPosition = true;
- // }
- //}
var isHls = StringHelper.EqualsIgnoreCase(item.SubProtocol, "hls");
- if (isHls && !forceStartPosition)
+ if (isHls)
{
list.Add(new NameValuePair("StartTimeTicks", string.Empty));
}
@@ -310,6 +301,11 @@ namespace MediaBrowser.Model.Dlna
list.Add(new NameValuePair("BreakOnNonKeyFrames", item.BreakOnNonKeyFrames.ToString()));
}
+ if (isDlna || !item.IsDirectStream)
+ {
+ list.Add(new NameValuePair("TranscodeReasons", string.Join(",", item.TranscodeReasons.Distinct().Select(i => i.ToString()).ToArray())));
+ }
+
return list;
}
diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs
index c93eca0e7..08824913f 100644
--- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs
+++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs
@@ -4,6 +4,7 @@ using MediaBrowser.Model.MediaInfo;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Session;
namespace MediaBrowser.Model.Dto
{
@@ -110,6 +111,9 @@ namespace MediaBrowser.Model.Dto
}
}
+ [IgnoreDataMember]
+ public List<TranscodeReason> TranscodeReasons { get; set; }
+
public int? DefaultAudioStreamIndex { get; set; }
public int? DefaultSubtitleStreamIndex { get; set; }
diff --git a/MediaBrowser.Model/Session/TranscodingInfo.cs b/MediaBrowser.Model/Session/TranscodingInfo.cs
index e646d80d3..67eac6fd5 100644
--- a/MediaBrowser.Model/Session/TranscodingInfo.cs
+++ b/MediaBrowser.Model/Session/TranscodingInfo.cs
@@ -1,3 +1,5 @@
+using System.Collections.Generic;
+
namespace MediaBrowser.Model.Session
{
public class TranscodingInfo
@@ -15,5 +17,36 @@ namespace MediaBrowser.Model.Session
public int? Width { get; set; }
public int? Height { get; set; }
public int? AudioChannels { get; set; }
+
+ public List<TranscodeReason> TranscodeReasons { get; set; }
+
+ public TranscodingInfo()
+ {
+ TranscodeReasons = new List<TranscodeReason>();
+ }
+ }
+
+ public enum TranscodeReason
+ {
+ ContainerNotSupported = 0,
+ VideoCodecNotSupported = 1,
+ AudioCodecNotSupported = 2,
+ ContainerBitrateExceedsLimit = 3,
+ AudioBitrateNotSupported = 4,
+ AudioChannelsNotSupported = 5,
+ VideoResolutionNotSupported = 6,
+ UnknownVideoStreamInfo = 7,
+ UnknownAudioStreamInfo = 8,
+ AudioProfileNotSupported = 9,
+ AudioSampleRateNotSupported = 10,
+ AnamorphicVideoNotSupported = 11,
+ InterlacedVideoNotSupported = 12,
+ SecondaryAudioNotSupported = 13,
+ RefFramesNotSupported = 14,
+ VideoBitDepthNotSupported = 15,
+ VideoBitrateNotSupported = 16,
+ VideoFramerateNotSupported = 17,
+ VideoLevelNotSupported = 18,
+ VideoProfileNotSupported = 19
}
} \ No newline at end of file