|
@@ -93,19 +93,10 @@ namespace MediaBrowser.Model.Dlna
|
|
return GetOptimalStream(streams, options.GetMaxBitrate(false) ?? 0);
|
|
return GetOptimalStream(streams, options.GetMaxBitrate(false) ?? 0);
|
|
}
|
|
}
|
|
|
|
|
|
- private StreamInfo GetOptimalStream(List<StreamInfo> streams, long maxBitrate)
|
|
|
|
- {
|
|
|
|
- var sorted = SortMediaSources(streams, maxBitrate);
|
|
|
|
-
|
|
|
|
- foreach (StreamInfo stream in sorted)
|
|
|
|
- {
|
|
|
|
- return stream;
|
|
|
|
- }
|
|
|
|
|
|
+ private static StreamInfo GetOptimalStream(List<StreamInfo> streams, long maxBitrate)
|
|
|
|
+ => SortMediaSources(streams, maxBitrate).FirstOrDefault();
|
|
|
|
|
|
- return null;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private StreamInfo[] SortMediaSources(List<StreamInfo> streams, long maxBitrate)
|
|
|
|
|
|
+ private static IOrderedEnumerable<StreamInfo> SortMediaSources(List<StreamInfo> streams, long maxBitrate)
|
|
{
|
|
{
|
|
return streams.OrderBy(i =>
|
|
return streams.OrderBy(i =>
|
|
{
|
|
{
|
|
@@ -151,25 +142,17 @@ namespace MediaBrowser.Model.Dlna
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
- }).ThenBy(streams.IndexOf).ToArray();
|
|
|
|
|
|
+ }).ThenBy(streams.IndexOf);
|
|
}
|
|
}
|
|
|
|
|
|
- private TranscodeReason? GetTranscodeReasonForFailedCondition(ProfileCondition condition)
|
|
|
|
|
|
+ private static TranscodeReason? GetTranscodeReasonForFailedCondition(ProfileCondition condition)
|
|
{
|
|
{
|
|
switch (condition.Property)
|
|
switch (condition.Property)
|
|
{
|
|
{
|
|
case ProfileConditionValue.AudioBitrate:
|
|
case ProfileConditionValue.AudioBitrate:
|
|
- if (condition.Condition == ProfileConditionType.LessThanEqual)
|
|
|
|
- {
|
|
|
|
- return TranscodeReason.AudioBitrateNotSupported;
|
|
|
|
- }
|
|
|
|
return TranscodeReason.AudioBitrateNotSupported;
|
|
return TranscodeReason.AudioBitrateNotSupported;
|
|
|
|
|
|
case ProfileConditionValue.AudioChannels:
|
|
case ProfileConditionValue.AudioChannels:
|
|
- if (condition.Condition == ProfileConditionType.LessThanEqual)
|
|
|
|
- {
|
|
|
|
- return TranscodeReason.AudioChannelsNotSupported;
|
|
|
|
- }
|
|
|
|
return TranscodeReason.AudioChannelsNotSupported;
|
|
return TranscodeReason.AudioChannelsNotSupported;
|
|
|
|
|
|
case ProfileConditionValue.AudioProfile:
|
|
case ProfileConditionValue.AudioProfile:
|
|
@@ -246,7 +229,7 @@ namespace MediaBrowser.Model.Dlna
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- public static string NormalizeMediaSourceFormatIntoSingleContainer(string inputContainer, string unused1, DeviceProfile profile, DlnaProfileType type)
|
|
|
|
|
|
+ public static string NormalizeMediaSourceFormatIntoSingleContainer(string inputContainer, string _, DeviceProfile profile, DlnaProfileType type)
|
|
{
|
|
{
|
|
if (string.IsNullOrEmpty(inputContainer))
|
|
if (string.IsNullOrEmpty(inputContainer))
|
|
{
|
|
{
|
|
@@ -266,12 +249,10 @@ namespace MediaBrowser.Model.Dlna
|
|
{
|
|
{
|
|
foreach (var directPlayProfile in profile.DirectPlayProfiles)
|
|
foreach (var directPlayProfile in profile.DirectPlayProfiles)
|
|
{
|
|
{
|
|
- if (directPlayProfile.Type == type)
|
|
|
|
|
|
+ if (directPlayProfile.Type == type
|
|
|
|
+ && directPlayProfile.SupportsContainer(format))
|
|
{
|
|
{
|
|
- if (directPlayProfile.SupportsContainer(format))
|
|
|
|
- {
|
|
|
|
- return format;
|
|
|
|
- }
|
|
|
|
|
|
+ return format;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -282,9 +263,7 @@ namespace MediaBrowser.Model.Dlna
|
|
|
|
|
|
private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options)
|
|
private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options)
|
|
{
|
|
{
|
|
- var transcodeReasons = new List<TranscodeReason>();
|
|
|
|
-
|
|
|
|
- var playlistItem = new StreamInfo
|
|
|
|
|
|
+ StreamInfo playlistItem = new StreamInfo
|
|
{
|
|
{
|
|
ItemId = options.ItemId,
|
|
ItemId = options.ItemId,
|
|
MediaType = DlnaProfileType.Audio,
|
|
MediaType = DlnaProfileType.Audio,
|
|
@@ -313,18 +292,16 @@ namespace MediaBrowser.Model.Dlna
|
|
var directPlayInfo = GetAudioDirectPlayMethods(item, audioStream, options);
|
|
var directPlayInfo = GetAudioDirectPlayMethods(item, audioStream, options);
|
|
|
|
|
|
var directPlayMethods = directPlayInfo.Item1;
|
|
var directPlayMethods = directPlayInfo.Item1;
|
|
- transcodeReasons.AddRange(directPlayInfo.Item2);
|
|
|
|
-
|
|
|
|
- var conditionProcessor = new ConditionProcessor();
|
|
|
|
|
|
+ var transcodeReasons = directPlayInfo.Item2.ToList();
|
|
|
|
|
|
- int? inputAudioChannels = audioStream == null ? null : audioStream.Channels;
|
|
|
|
- int? inputAudioBitrate = audioStream == null ? null : audioStream.BitDepth;
|
|
|
|
- int? inputAudioSampleRate = audioStream == null ? null : audioStream.SampleRate;
|
|
|
|
- int? inputAudioBitDepth = audioStream == null ? null : audioStream.BitDepth;
|
|
|
|
|
|
+ int? inputAudioChannels = audioStream?.Channels;
|
|
|
|
+ int? inputAudioBitrate = audioStream?.BitDepth;
|
|
|
|
+ int? inputAudioSampleRate = audioStream?.SampleRate;
|
|
|
|
+ int? inputAudioBitDepth = audioStream.BitDepth;
|
|
|
|
|
|
- if (directPlayMethods.Count > 0)
|
|
|
|
|
|
+ if (directPlayMethods.Count() > 0)
|
|
{
|
|
{
|
|
- string audioCodec = audioStream == null ? null : audioStream.Codec;
|
|
|
|
|
|
+ string audioCodec = audioStream?.Codec;
|
|
|
|
|
|
// Make sure audio codec profiles are satisfied
|
|
// Make sure audio codec profiles are satisfied
|
|
var conditions = new List<ProfileCondition>();
|
|
var conditions = new List<ProfileCondition>();
|
|
@@ -335,7 +312,7 @@ namespace MediaBrowser.Model.Dlna
|
|
bool applyConditions = true;
|
|
bool applyConditions = true;
|
|
foreach (ProfileCondition applyCondition in i.ApplyConditions)
|
|
foreach (ProfileCondition applyCondition in i.ApplyConditions)
|
|
{
|
|
{
|
|
- if (!conditionProcessor.IsAudioConditionSatisfied(applyCondition, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth))
|
|
|
|
|
|
+ if (!ConditionProcessor.IsAudioConditionSatisfied(applyCondition, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth))
|
|
{
|
|
{
|
|
LogConditionFailure(options.Profile, "AudioCodecProfile", applyCondition, item);
|
|
LogConditionFailure(options.Profile, "AudioCodecProfile", applyCondition, item);
|
|
applyConditions = false;
|
|
applyConditions = false;
|
|
@@ -345,10 +322,7 @@ namespace MediaBrowser.Model.Dlna
|
|
|
|
|
|
if (applyConditions)
|
|
if (applyConditions)
|
|
{
|
|
{
|
|
- foreach (ProfileCondition c in i.Conditions)
|
|
|
|
- {
|
|
|
|
- conditions.Add(c);
|
|
|
|
- }
|
|
|
|
|
|
+ conditions.AddRange(i.Conditions);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -356,7 +330,7 @@ namespace MediaBrowser.Model.Dlna
|
|
bool all = true;
|
|
bool all = true;
|
|
foreach (ProfileCondition c in conditions)
|
|
foreach (ProfileCondition c in conditions)
|
|
{
|
|
{
|
|
- if (!conditionProcessor.IsAudioConditionSatisfied(c, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth))
|
|
|
|
|
|
+ if (!ConditionProcessor.IsAudioConditionSatisfied(c, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth))
|
|
{
|
|
{
|
|
LogConditionFailure(options.Profile, "AudioCodecProfile", c, item);
|
|
LogConditionFailure(options.Profile, "AudioCodecProfile", c, item);
|
|
var transcodeReason = GetTranscodeReasonForFailedCondition(c);
|
|
var transcodeReason = GetTranscodeReasonForFailedCondition(c);
|
|
@@ -385,13 +359,12 @@ namespace MediaBrowser.Model.Dlna
|
|
TranscodingProfile transcodingProfile = null;
|
|
TranscodingProfile transcodingProfile = null;
|
|
foreach (var i in options.Profile.TranscodingProfiles)
|
|
foreach (var i in options.Profile.TranscodingProfiles)
|
|
{
|
|
{
|
|
- if (i.Type == playlistItem.MediaType && i.Context == options.Context)
|
|
|
|
|
|
+ if (i.Type == playlistItem.MediaType
|
|
|
|
+ && i.Context == options.Context
|
|
|
|
+ && _transcoderSupport.CanEncodeToAudioCodec(i.AudioCodec ?? i.Container))
|
|
{
|
|
{
|
|
- if (_transcoderSupport.CanEncodeToAudioCodec(i.AudioCodec ?? i.Container))
|
|
|
|
- {
|
|
|
|
- transcodingProfile = i;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
|
|
+ transcodingProfile = i;
|
|
|
|
+ break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -421,7 +394,7 @@ namespace MediaBrowser.Model.Dlna
|
|
bool applyConditions = true;
|
|
bool applyConditions = true;
|
|
foreach (var applyCondition in i.ApplyConditions)
|
|
foreach (var applyCondition in i.ApplyConditions)
|
|
{
|
|
{
|
|
- if (!conditionProcessor.IsAudioConditionSatisfied(applyCondition, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth))
|
|
|
|
|
|
+ if (!ConditionProcessor.IsAudioConditionSatisfied(applyCondition, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth))
|
|
{
|
|
{
|
|
LogConditionFailure(options.Profile, "AudioCodecProfile", applyCondition, item);
|
|
LogConditionFailure(options.Profile, "AudioCodecProfile", applyCondition, item);
|
|
applyConditions = false;
|
|
applyConditions = false;
|
|
@@ -463,7 +436,7 @@ namespace MediaBrowser.Model.Dlna
|
|
return playlistItem;
|
|
return playlistItem;
|
|
}
|
|
}
|
|
|
|
|
|
- private long? GetBitrateForDirectPlayCheck(MediaSourceInfo item, AudioOptions options, bool isAudio)
|
|
|
|
|
|
+ private static long? GetBitrateForDirectPlayCheck(MediaSourceInfo item, AudioOptions options, bool isAudio)
|
|
{
|
|
{
|
|
if (item.Protocol == MediaProtocol.File)
|
|
if (item.Protocol == MediaProtocol.File)
|
|
{
|
|
{
|
|
@@ -473,65 +446,56 @@ namespace MediaBrowser.Model.Dlna
|
|
return options.GetMaxBitrate(isAudio);
|
|
return options.GetMaxBitrate(isAudio);
|
|
}
|
|
}
|
|
|
|
|
|
- private Tuple<List<PlayMethod>, List<TranscodeReason>> GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options)
|
|
|
|
|
|
+ private (IEnumerable<PlayMethod>, IEnumerable<TranscodeReason>) GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options)
|
|
{
|
|
{
|
|
- var transcodeReasons = new List<TranscodeReason>();
|
|
|
|
|
|
+ DirectPlayProfile directPlayProfile = options.Profile.DirectPlayProfiles
|
|
|
|
+ .FirstOrDefault(x => x.Type == DlnaProfileType.Audio && IsAudioDirectPlaySupported(x, item, audioStream));
|
|
|
|
|
|
- DirectPlayProfile directPlayProfile = null;
|
|
|
|
- foreach (var i in options.Profile.DirectPlayProfiles)
|
|
|
|
|
|
+ if (directPlayProfile == null)
|
|
{
|
|
{
|
|
- if (i.Type == DlnaProfileType.Audio && IsAudioDirectPlaySupported(i, item, audioStream))
|
|
|
|
- {
|
|
|
|
- directPlayProfile = i;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
|
|
+ _logger.LogInformation("Profile: {0}, No direct play profiles found for Path: {1}",
|
|
|
|
+ options.Profile.Name ?? "Unknown Profile",
|
|
|
|
+ item.Path ?? "Unknown path");
|
|
|
|
+
|
|
|
|
+ return (Enumerable.Empty<PlayMethod>(), GetTranscodeReasonsFromDirectPlayProfile(item, null, audioStream, options.Profile.DirectPlayProfiles));
|
|
}
|
|
}
|
|
|
|
|
|
var playMethods = new List<PlayMethod>();
|
|
var playMethods = new List<PlayMethod>();
|
|
|
|
+ var transcodeReasons = new List<TranscodeReason>();
|
|
|
|
|
|
- if (directPlayProfile != null)
|
|
|
|
|
|
+ // While options takes the network and other factors into account. Only applies to direct stream
|
|
|
|
+ if (item.SupportsDirectStream)
|
|
{
|
|
{
|
|
- // While options takes the network and other factors into account. Only applies to direct stream
|
|
|
|
- if (item.SupportsDirectStream)
|
|
|
|
|
|
+ if (IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate(true) ?? 0, PlayMethod.DirectStream))
|
|
{
|
|
{
|
|
- if (IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate(true) ?? 0, PlayMethod.DirectStream))
|
|
|
|
- {
|
|
|
|
- if (options.EnableDirectStream)
|
|
|
|
- {
|
|
|
|
- playMethods.Add(PlayMethod.DirectStream);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
|
|
+ if (options.EnableDirectStream)
|
|
{
|
|
{
|
|
- transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit);
|
|
|
|
|
|
+ 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)
|
|
|
|
|
|
+ // The profile describes what the device supports
|
|
|
|
+ // If device requirements are satisfied then allow both direct stream and direct play
|
|
|
|
+ if (item.SupportsDirectPlay)
|
|
|
|
+ {
|
|
|
|
+ if (IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true) ?? 0, PlayMethod.DirectPlay))
|
|
{
|
|
{
|
|
- if (IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true) ?? 0, PlayMethod.DirectPlay))
|
|
|
|
- {
|
|
|
|
- if (options.EnableDirectPlay)
|
|
|
|
- {
|
|
|
|
- playMethods.Add(PlayMethod.DirectPlay);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
|
|
+ if (options.EnableDirectPlay)
|
|
{
|
|
{
|
|
- transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit);
|
|
|
|
|
|
+ playMethods.Add(PlayMethod.DirectPlay);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- else
|
|
|
|
- {
|
|
|
|
- transcodeReasons.InsertRange(0, GetTranscodeReasonsFromDirectPlayProfile(item, null, audioStream, options.Profile.DirectPlayProfiles));
|
|
|
|
|
|
|
|
- _logger.LogInformation("Profile: {0}, No direct play profiles found for Path: {1}",
|
|
|
|
- options.Profile.Name ?? "Unknown Profile",
|
|
|
|
- item.Path ?? "Unknown path");
|
|
|
|
- }
|
|
|
|
|
|
|
|
if (playMethods.Count > 0)
|
|
if (playMethods.Count > 0)
|
|
{
|
|
{
|
|
@@ -542,41 +506,25 @@ namespace MediaBrowser.Model.Dlna
|
|
transcodeReasons = transcodeReasons.Distinct().ToList();
|
|
transcodeReasons = transcodeReasons.Distinct().ToList();
|
|
}
|
|
}
|
|
|
|
|
|
- return new Tuple<List<PlayMethod>, List<TranscodeReason>>(playMethods, transcodeReasons);
|
|
|
|
|
|
+ return (playMethods, transcodeReasons);
|
|
}
|
|
}
|
|
|
|
|
|
- private List<TranscodeReason> GetTranscodeReasonsFromDirectPlayProfile(MediaSourceInfo item, MediaStream videoStream, MediaStream audioStream, IEnumerable<DirectPlayProfile> directPlayProfiles)
|
|
|
|
|
|
+ private static List<TranscodeReason> GetTranscodeReasonsFromDirectPlayProfile(MediaSourceInfo item, MediaStream videoStream, MediaStream audioStream, IEnumerable<DirectPlayProfile> directPlayProfiles)
|
|
{
|
|
{
|
|
- var list = new List<TranscodeReason>();
|
|
|
|
var containerSupported = false;
|
|
var containerSupported = false;
|
|
var audioSupported = false;
|
|
var audioSupported = false;
|
|
var videoSupported = false;
|
|
var videoSupported = false;
|
|
|
|
|
|
foreach (var profile in directPlayProfiles)
|
|
foreach (var profile in directPlayProfiles)
|
|
{
|
|
{
|
|
- audioSupported = false;
|
|
|
|
- videoSupported = false;
|
|
|
|
-
|
|
|
|
// Check container type
|
|
// Check container type
|
|
if (profile.SupportsContainer(item.Container))
|
|
if (profile.SupportsContainer(item.Container))
|
|
{
|
|
{
|
|
containerSupported = true;
|
|
containerSupported = true;
|
|
|
|
|
|
- if (videoStream != null)
|
|
|
|
- {
|
|
|
|
- if (profile.SupportsVideoCodec(videoStream.Codec))
|
|
|
|
- {
|
|
|
|
- videoSupported = true;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ videoSupported = videoStream != null && profile.SupportsVideoCodec(videoStream.Codec);
|
|
|
|
|
|
- if (audioStream != null)
|
|
|
|
- {
|
|
|
|
- if (profile.SupportsAudioCodec(audioStream.Codec))
|
|
|
|
- {
|
|
|
|
- audioSupported = true;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ audioSupported = audioStream != null && profile.SupportsAudioCodec(audioStream.Codec);
|
|
|
|
|
|
if (videoSupported && audioSupported)
|
|
if (videoSupported && audioSupported)
|
|
{
|
|
{
|
|
@@ -585,6 +533,7 @@ namespace MediaBrowser.Model.Dlna
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ var list = new List<TranscodeReason>();
|
|
if (!containerSupported)
|
|
if (!containerSupported)
|
|
{
|
|
{
|
|
list.Add(TranscodeReason.ContainerNotSupported);
|
|
list.Add(TranscodeReason.ContainerNotSupported);
|
|
@@ -603,18 +552,17 @@ namespace MediaBrowser.Model.Dlna
|
|
return list;
|
|
return list;
|
|
}
|
|
}
|
|
|
|
|
|
- private int? GetDefaultSubtitleStreamIndex(MediaSourceInfo item, SubtitleProfile[] subtitleProfiles)
|
|
|
|
|
|
+ private static int? GetDefaultSubtitleStreamIndex(MediaSourceInfo item, SubtitleProfile[] subtitleProfiles)
|
|
{
|
|
{
|
|
int highestScore = -1;
|
|
int highestScore = -1;
|
|
|
|
|
|
foreach (var stream in item.MediaStreams)
|
|
foreach (var stream in item.MediaStreams)
|
|
{
|
|
{
|
|
- if (stream.Type == MediaStreamType.Subtitle && stream.Score.HasValue)
|
|
|
|
|
|
+ if (stream.Type == MediaStreamType.Subtitle
|
|
|
|
+ && stream.Score.HasValue
|
|
|
|
+ && stream.Score.Value > highestScore)
|
|
{
|
|
{
|
|
- if (stream.Score.Value > highestScore)
|
|
|
|
- {
|
|
|
|
- highestScore = stream.Score.Value;
|
|
|
|
- }
|
|
|
|
|
|
+ highestScore = stream.Score.Value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -646,7 +594,7 @@ namespace MediaBrowser.Model.Dlna
|
|
return item.DefaultSubtitleStreamIndex;
|
|
return item.DefaultSubtitleStreamIndex;
|
|
}
|
|
}
|
|
|
|
|
|
- private void SetStreamInfoOptionsFromTranscodingProfile(StreamInfo playlistItem, TranscodingProfile transcodingProfile)
|
|
|
|
|
|
+ private static void SetStreamInfoOptionsFromTranscodingProfile(StreamInfo playlistItem, TranscodingProfile transcodingProfile)
|
|
{
|
|
{
|
|
if (string.IsNullOrEmpty(transcodingProfile.AudioCodec))
|
|
if (string.IsNullOrEmpty(transcodingProfile.AudioCodec))
|
|
{
|
|
{
|
|
@@ -686,12 +634,10 @@ namespace MediaBrowser.Model.Dlna
|
|
}
|
|
}
|
|
playlistItem.SubProtocol = transcodingProfile.Protocol;
|
|
playlistItem.SubProtocol = transcodingProfile.Protocol;
|
|
|
|
|
|
- if (!string.IsNullOrEmpty(transcodingProfile.MaxAudioChannels))
|
|
|
|
|
|
+ if (!string.IsNullOrEmpty(transcodingProfile.MaxAudioChannels)
|
|
|
|
+ && int.TryParse(transcodingProfile.MaxAudioChannels, NumberStyles.Any, CultureInfo.InvariantCulture, out int transcodingMaxAudioChannels))
|
|
{
|
|
{
|
|
- if (int.TryParse(transcodingProfile.MaxAudioChannels, NumberStyles.Any, CultureInfo.InvariantCulture, out var transcodingMaxAudioChannels))
|
|
|
|
- {
|
|
|
|
- playlistItem.TranscodingMaxAudioChannels = transcodingMaxAudioChannels;
|
|
|
|
- }
|
|
|
|
|
|
+ playlistItem.TranscodingMaxAudioChannels = transcodingMaxAudioChannels;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -702,9 +648,7 @@ namespace MediaBrowser.Model.Dlna
|
|
throw new ArgumentNullException(nameof(item));
|
|
throw new ArgumentNullException(nameof(item));
|
|
}
|
|
}
|
|
|
|
|
|
- var transcodeReasons = new List<TranscodeReason>();
|
|
|
|
-
|
|
|
|
- var playlistItem = new StreamInfo
|
|
|
|
|
|
+ StreamInfo playlistItem = new StreamInfo
|
|
{
|
|
{
|
|
ItemId = options.ItemId,
|
|
ItemId = options.ItemId,
|
|
MediaType = DlnaProfileType.Video,
|
|
MediaType = DlnaProfileType.Video,
|
|
@@ -737,6 +681,8 @@ namespace MediaBrowser.Model.Dlna
|
|
isEligibleForDirectPlay,
|
|
isEligibleForDirectPlay,
|
|
isEligibleForDirectStream);
|
|
isEligibleForDirectStream);
|
|
|
|
|
|
|
|
+ var transcodeReasons = new List<TranscodeReason>();
|
|
|
|
+
|
|
if (isEligibleForDirectPlay || isEligibleForDirectStream)
|
|
if (isEligibleForDirectPlay || isEligibleForDirectStream)
|
|
{
|
|
{
|
|
// See if it can be direct played
|
|
// See if it can be direct played
|
|
@@ -803,8 +749,6 @@ namespace MediaBrowser.Model.Dlna
|
|
|
|
|
|
SetStreamInfoOptionsFromTranscodingProfile(playlistItem, transcodingProfile);
|
|
SetStreamInfoOptionsFromTranscodingProfile(playlistItem, transcodingProfile);
|
|
|
|
|
|
- var conditionProcessor = new ConditionProcessor();
|
|
|
|
-
|
|
|
|
var isFirstAppliedCodecProfile = true;
|
|
var isFirstAppliedCodecProfile = true;
|
|
foreach (var i in options.Profile.CodecProfiles)
|
|
foreach (var i in options.Profile.CodecProfiles)
|
|
{
|
|
{
|
|
@@ -813,26 +757,26 @@ namespace MediaBrowser.Model.Dlna
|
|
bool applyConditions = true;
|
|
bool applyConditions = true;
|
|
foreach (ProfileCondition applyCondition in i.ApplyConditions)
|
|
foreach (ProfileCondition applyCondition in i.ApplyConditions)
|
|
{
|
|
{
|
|
- int? width = videoStream == null ? null : videoStream.Width;
|
|
|
|
- int? height = videoStream == null ? null : videoStream.Height;
|
|
|
|
- int? bitDepth = videoStream == null ? null : videoStream.BitDepth;
|
|
|
|
- int? videoBitrate = videoStream == null ? null : videoStream.BitRate;
|
|
|
|
- double? videoLevel = videoStream == null ? null : videoStream.Level;
|
|
|
|
- string videoProfile = videoStream == null ? null : videoStream.Profile;
|
|
|
|
|
|
+ int? width = videoStream?.Width;
|
|
|
|
+ int? height = videoStream?.Height;
|
|
|
|
+ int? bitDepth = videoStream?.BitDepth;
|
|
|
|
+ int? videoBitrate = videoStream?.BitRate;
|
|
|
|
+ double? videoLevel = videoStream?.Level;
|
|
|
|
+ string videoProfile = videoStream?.Profile;
|
|
float videoFramerate = videoStream == null ? 0 : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate ?? 0;
|
|
float videoFramerate = videoStream == null ? 0 : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate ?? 0;
|
|
- bool? isAnamorphic = videoStream == null ? null : videoStream.IsAnamorphic;
|
|
|
|
- bool? isInterlaced = videoStream == null ? (bool?)null : videoStream.IsInterlaced;
|
|
|
|
- string videoCodecTag = videoStream == null ? null : videoStream.CodecTag;
|
|
|
|
- bool? isAvc = videoStream == null ? null : videoStream.IsAVC;
|
|
|
|
|
|
+ bool? isAnamorphic = videoStream?.IsAnamorphic;
|
|
|
|
+ bool? isInterlaced = videoStream?.IsInterlaced;
|
|
|
|
+ string videoCodecTag = videoStream?.CodecTag;
|
|
|
|
+ bool? isAvc = videoStream?.IsAVC;
|
|
|
|
|
|
TransportStreamTimestamp? timestamp = videoStream == null ? TransportStreamTimestamp.None : item.Timestamp;
|
|
TransportStreamTimestamp? timestamp = videoStream == null ? TransportStreamTimestamp.None : item.Timestamp;
|
|
- int? packetLength = videoStream == null ? null : videoStream.PacketLength;
|
|
|
|
- int? refFrames = videoStream == null ? null : videoStream.RefFrames;
|
|
|
|
|
|
+ int? packetLength = videoStream?.PacketLength;
|
|
|
|
+ int? refFrames = videoStream?.RefFrames;
|
|
|
|
|
|
int? numAudioStreams = item.GetStreamCount(MediaStreamType.Audio);
|
|
int? numAudioStreams = item.GetStreamCount(MediaStreamType.Audio);
|
|
int? numVideoStreams = item.GetStreamCount(MediaStreamType.Video);
|
|
int? numVideoStreams = item.GetStreamCount(MediaStreamType.Video);
|
|
|
|
|
|
- if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
|
|
|
|
|
|
+ if (!ConditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
|
|
{
|
|
{
|
|
//LogConditionFailure(options.Profile, "VideoCodecProfile.ApplyConditions", applyCondition, item);
|
|
//LogConditionFailure(options.Profile, "VideoCodecProfile.ApplyConditions", applyCondition, item);
|
|
applyConditions = false;
|
|
applyConditions = false;
|
|
@@ -876,7 +820,7 @@ namespace MediaBrowser.Model.Dlna
|
|
int? inputAudioSampleRate = audioStream == null ? null : audioStream.SampleRate;
|
|
int? inputAudioSampleRate = audioStream == null ? null : audioStream.SampleRate;
|
|
int? inputAudioBitDepth = audioStream == null ? null : audioStream.BitDepth;
|
|
int? inputAudioBitDepth = audioStream == null ? null : audioStream.BitDepth;
|
|
|
|
|
|
- if (!conditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth, audioProfile, isSecondaryAudio))
|
|
|
|
|
|
+ if (!ConditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth, audioProfile, isSecondaryAudio))
|
|
{
|
|
{
|
|
//LogConditionFailure(options.Profile, "VideoCodecProfile.ApplyConditions", applyCondition, item);
|
|
//LogConditionFailure(options.Profile, "VideoCodecProfile.ApplyConditions", applyCondition, item);
|
|
applyConditions = false;
|
|
applyConditions = false;
|
|
@@ -922,7 +866,7 @@ namespace MediaBrowser.Model.Dlna
|
|
return playlistItem;
|
|
return playlistItem;
|
|
}
|
|
}
|
|
|
|
|
|
- private int GetDefaultAudioBitrateIfUnknown(MediaStream audioStream)
|
|
|
|
|
|
+ private static int GetDefaultAudioBitrateIfUnknown(MediaStream audioStream)
|
|
{
|
|
{
|
|
if ((audioStream.Channels ?? 0) >= 6)
|
|
if ((audioStream.Channels ?? 0) >= 6)
|
|
{
|
|
{
|
|
@@ -932,33 +876,37 @@ namespace MediaBrowser.Model.Dlna
|
|
return 192000;
|
|
return 192000;
|
|
}
|
|
}
|
|
|
|
|
|
- private int GetAudioBitrate(string subProtocol, long maxTotalBitrate, string[] targetAudioCodecs, MediaStream audioStream, StreamInfo item)
|
|
|
|
|
|
+ private static int GetAudioBitrate(string subProtocol, long maxTotalBitrate, string[] targetAudioCodecs, MediaStream audioStream, StreamInfo item)
|
|
{
|
|
{
|
|
- var targetAudioCodec = targetAudioCodecs.Length == 0 ? null : targetAudioCodecs[0];
|
|
|
|
|
|
+ string targetAudioCodec = targetAudioCodecs.Length == 0 ? null : targetAudioCodecs[0];
|
|
|
|
|
|
- var targetAudioChannels = item.GetTargetAudioChannels(targetAudioCodec);
|
|
|
|
|
|
+ int? targetAudioChannels = item.GetTargetAudioChannels(targetAudioCodec);
|
|
|
|
|
|
- int defaultBitrate = audioStream == null ? 192000 : audioStream.BitRate ?? GetDefaultAudioBitrateIfUnknown(audioStream);
|
|
|
|
|
|
+ int defaultBitrate;
|
|
|
|
+ int encoderAudioBitrateLimit = int.MaxValue;
|
|
|
|
|
|
- // Reduce the bitrate if we're downmixing
|
|
|
|
- if (targetAudioChannels.HasValue && audioStream != null && audioStream.Channels.HasValue && targetAudioChannels.Value < audioStream.Channels.Value)
|
|
|
|
|
|
+ if (audioStream == null)
|
|
{
|
|
{
|
|
- defaultBitrate = targetAudioChannels.Value <= 2 ? 128000 : 192000;
|
|
|
|
|
|
+ defaultBitrate = 192000;
|
|
}
|
|
}
|
|
-
|
|
|
|
- int encoderAudioBitrateLimit = int.MaxValue;
|
|
|
|
-
|
|
|
|
- if (audioStream != null)
|
|
|
|
|
|
+ else
|
|
{
|
|
{
|
|
|
|
+ if (targetAudioChannels.HasValue && audioStream.Channels.HasValue && targetAudioChannels.Value < audioStream.Channels.Value)
|
|
|
|
+ {
|
|
|
|
+ // Reduce the bitrate if we're downmixing
|
|
|
|
+ defaultBitrate = targetAudioChannels.Value < 2 ? 128000 : 192000;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ defaultBitrate = audioStream.BitRate ?? GetDefaultAudioBitrateIfUnknown(audioStream);
|
|
|
|
+ }
|
|
|
|
+
|
|
// Seeing webm encoding failures when source has 1 audio channel and 22k bitrate.
|
|
// Seeing webm encoding failures when source has 1 audio channel and 22k bitrate.
|
|
// Any attempts to transcode over 64k will fail
|
|
// Any attempts to transcode over 64k will fail
|
|
- if (audioStream.Channels.HasValue &&
|
|
|
|
- audioStream.Channels.Value == 1)
|
|
|
|
|
|
+ if (audioStream.Channels == 1
|
|
|
|
+ && (audioStream.BitRate ?? 0) < 64000)
|
|
{
|
|
{
|
|
- if ((audioStream.BitRate ?? 0) < 64000)
|
|
|
|
- {
|
|
|
|
- encoderAudioBitrateLimit = 64000;
|
|
|
|
- }
|
|
|
|
|
|
+ encoderAudioBitrateLimit = 64000;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -970,19 +918,17 @@ namespace MediaBrowser.Model.Dlna
|
|
return Math.Min(defaultBitrate, encoderAudioBitrateLimit);
|
|
return Math.Min(defaultBitrate, encoderAudioBitrateLimit);
|
|
}
|
|
}
|
|
|
|
|
|
- private int GetMaxAudioBitrateForTotalBitrate(long totalBitrate)
|
|
|
|
|
|
+ private static int GetMaxAudioBitrateForTotalBitrate(long totalBitrate)
|
|
{
|
|
{
|
|
if (totalBitrate <= 640000)
|
|
if (totalBitrate <= 640000)
|
|
{
|
|
{
|
|
return 128000;
|
|
return 128000;
|
|
}
|
|
}
|
|
-
|
|
|
|
- if (totalBitrate <= 2000000)
|
|
|
|
|
|
+ else if (totalBitrate <= 2000000)
|
|
{
|
|
{
|
|
return 384000;
|
|
return 384000;
|
|
}
|
|
}
|
|
-
|
|
|
|
- if (totalBitrate <= 3000000)
|
|
|
|
|
|
+ else if (totalBitrate <= 3000000)
|
|
{
|
|
{
|
|
return 448000;
|
|
return 448000;
|
|
}
|
|
}
|
|
@@ -990,24 +936,25 @@ namespace MediaBrowser.Model.Dlna
|
|
return 640000;
|
|
return 640000;
|
|
}
|
|
}
|
|
|
|
|
|
- private Tuple<PlayMethod?, List<TranscodeReason>> GetVideoDirectPlayProfile(VideoOptions options,
|
|
|
|
|
|
+ private (PlayMethod?, List<TranscodeReason>) GetVideoDirectPlayProfile(
|
|
|
|
+ VideoOptions options,
|
|
MediaSourceInfo mediaSource,
|
|
MediaSourceInfo mediaSource,
|
|
MediaStream videoStream,
|
|
MediaStream videoStream,
|
|
MediaStream audioStream,
|
|
MediaStream audioStream,
|
|
bool isEligibleForDirectPlay,
|
|
bool isEligibleForDirectPlay,
|
|
bool isEligibleForDirectStream)
|
|
bool isEligibleForDirectStream)
|
|
{
|
|
{
|
|
- DeviceProfile profile = options.Profile;
|
|
|
|
-
|
|
|
|
if (options.ForceDirectPlay)
|
|
if (options.ForceDirectPlay)
|
|
{
|
|
{
|
|
- return new Tuple<PlayMethod?, List<TranscodeReason>>(PlayMethod.DirectPlay, new List<TranscodeReason>());
|
|
|
|
|
|
+ return (PlayMethod.DirectPlay, new List<TranscodeReason>());
|
|
}
|
|
}
|
|
if (options.ForceDirectStream)
|
|
if (options.ForceDirectStream)
|
|
{
|
|
{
|
|
- return new Tuple<PlayMethod?, List<TranscodeReason>>(PlayMethod.DirectStream, new List<TranscodeReason>());
|
|
|
|
|
|
+ return (PlayMethod.DirectStream, new List<TranscodeReason>());
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ DeviceProfile profile = options.Profile;
|
|
|
|
+
|
|
// See if it can be direct played
|
|
// See if it can be direct played
|
|
DirectPlayProfile directPlay = null;
|
|
DirectPlayProfile directPlay = null;
|
|
foreach (var i in profile.DirectPlayProfiles)
|
|
foreach (var i in profile.DirectPlayProfiles)
|
|
@@ -1025,7 +972,7 @@ namespace MediaBrowser.Model.Dlna
|
|
profile.Name ?? "Unknown Profile",
|
|
profile.Name ?? "Unknown Profile",
|
|
mediaSource.Path ?? "Unknown path");
|
|
mediaSource.Path ?? "Unknown path");
|
|
|
|
|
|
- return new Tuple<PlayMethod?, List<TranscodeReason>>(null, GetTranscodeReasonsFromDirectPlayProfile(mediaSource, videoStream, audioStream, profile.DirectPlayProfiles));
|
|
|
|
|
|
+ return (null, GetTranscodeReasonsFromDirectPlayProfile(mediaSource, videoStream, audioStream, profile.DirectPlayProfiles));
|
|
}
|
|
}
|
|
|
|
|
|
string container = mediaSource.Container;
|
|
string container = mediaSource.Container;
|
|
@@ -1033,8 +980,8 @@ namespace MediaBrowser.Model.Dlna
|
|
var conditions = new List<ProfileCondition>();
|
|
var conditions = new List<ProfileCondition>();
|
|
foreach (var i in profile.ContainerProfiles)
|
|
foreach (var i in profile.ContainerProfiles)
|
|
{
|
|
{
|
|
- if (i.Type == DlnaProfileType.Video &&
|
|
|
|
- i.ContainsContainer(container))
|
|
|
|
|
|
+ if (i.Type == DlnaProfileType.Video
|
|
|
|
+ && i.ContainsContainer(container))
|
|
{
|
|
{
|
|
foreach (var c in i.Conditions)
|
|
foreach (var c in i.Conditions)
|
|
{
|
|
{
|
|
@@ -1043,29 +990,27 @@ namespace MediaBrowser.Model.Dlna
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- var conditionProcessor = new ConditionProcessor();
|
|
|
|
-
|
|
|
|
- int? width = videoStream == null ? null : videoStream.Width;
|
|
|
|
- int? height = videoStream == null ? null : videoStream.Height;
|
|
|
|
- int? bitDepth = videoStream == null ? null : videoStream.BitDepth;
|
|
|
|
- int? videoBitrate = videoStream == null ? null : videoStream.BitRate;
|
|
|
|
- double? videoLevel = videoStream == null ? null : videoStream.Level;
|
|
|
|
- string videoProfile = videoStream == null ? null : videoStream.Profile;
|
|
|
|
|
|
+ int? width = videoStream?.Width;
|
|
|
|
+ int? height = videoStream?.Height;
|
|
|
|
+ int? bitDepth = videoStream?.BitDepth;
|
|
|
|
+ int? videoBitrate = videoStream?.BitRate;
|
|
|
|
+ double? videoLevel = videoStream?.Level;
|
|
|
|
+ string videoProfile = videoStream?.Profile;
|
|
float videoFramerate = videoStream == null ? 0 : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate ?? 0;
|
|
float videoFramerate = videoStream == null ? 0 : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate ?? 0;
|
|
- bool? isAnamorphic = videoStream == null ? null : videoStream.IsAnamorphic;
|
|
|
|
- bool? isInterlaced = videoStream == null ? (bool?)null : videoStream.IsInterlaced;
|
|
|
|
- string videoCodecTag = videoStream == null ? null : videoStream.CodecTag;
|
|
|
|
- bool? isAvc = videoStream == null ? null : videoStream.IsAVC;
|
|
|
|
|
|
+ bool? isAnamorphic = videoStream?.IsAnamorphic;
|
|
|
|
+ bool? isInterlaced = videoStream?.IsInterlaced;
|
|
|
|
+ string videoCodecTag = videoStream?.CodecTag;
|
|
|
|
+ bool? isAvc = videoStream?.IsAVC;
|
|
|
|
|
|
- int? audioBitrate = audioStream == null ? null : audioStream.BitRate;
|
|
|
|
- int? audioChannels = audioStream == null ? null : audioStream.Channels;
|
|
|
|
- string audioProfile = audioStream == null ? null : audioStream.Profile;
|
|
|
|
- int? audioSampleRate = audioStream == null ? null : audioStream.SampleRate;
|
|
|
|
- int? audioBitDepth = audioStream == null ? null : audioStream.BitDepth;
|
|
|
|
|
|
+ int? audioBitrate = audioStream?.BitRate;
|
|
|
|
+ int? audioChannels = audioStream?.Channels;
|
|
|
|
+ string audioProfile = audioStream?.Profile;
|
|
|
|
+ int? audioSampleRate = audioStream?.SampleRate;
|
|
|
|
+ int? audioBitDepth = audioStream?.BitDepth;
|
|
|
|
|
|
TransportStreamTimestamp? timestamp = videoStream == null ? TransportStreamTimestamp.None : mediaSource.Timestamp;
|
|
TransportStreamTimestamp? timestamp = videoStream == null ? TransportStreamTimestamp.None : mediaSource.Timestamp;
|
|
- int? packetLength = videoStream == null ? null : videoStream.PacketLength;
|
|
|
|
- int? refFrames = videoStream == null ? null : videoStream.RefFrames;
|
|
|
|
|
|
+ int? packetLength = videoStream?.PacketLength;
|
|
|
|
+ int? refFrames = videoStream?.RefFrames;
|
|
|
|
|
|
int? numAudioStreams = mediaSource.GetStreamCount(MediaStreamType.Audio);
|
|
int? numAudioStreams = mediaSource.GetStreamCount(MediaStreamType.Audio);
|
|
int? numVideoStreams = mediaSource.GetStreamCount(MediaStreamType.Video);
|
|
int? numVideoStreams = mediaSource.GetStreamCount(MediaStreamType.Video);
|
|
@@ -1073,20 +1018,20 @@ namespace MediaBrowser.Model.Dlna
|
|
// Check container conditions
|
|
// Check container conditions
|
|
foreach (ProfileCondition i in conditions)
|
|
foreach (ProfileCondition i in conditions)
|
|
{
|
|
{
|
|
- if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
|
|
|
|
|
|
+ if (!ConditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
|
|
{
|
|
{
|
|
LogConditionFailure(profile, "VideoContainerProfile", i, mediaSource);
|
|
LogConditionFailure(profile, "VideoContainerProfile", i, mediaSource);
|
|
|
|
|
|
var transcodeReason = GetTranscodeReasonForFailedCondition(i);
|
|
var transcodeReason = GetTranscodeReasonForFailedCondition(i);
|
|
var transcodeReasons = transcodeReason.HasValue
|
|
var transcodeReasons = transcodeReason.HasValue
|
|
? new List<TranscodeReason> { transcodeReason.Value }
|
|
? new List<TranscodeReason> { transcodeReason.Value }
|
|
- : new List<TranscodeReason> { };
|
|
|
|
|
|
+ : new List<TranscodeReason>();
|
|
|
|
|
|
- return new Tuple<PlayMethod?, List<TranscodeReason>>(null, transcodeReasons);
|
|
|
|
|
|
+ return (null, transcodeReasons);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- string videoCodec = videoStream == null ? null : videoStream.Codec;
|
|
|
|
|
|
+ string videoCodec = videoStream?.Codec;
|
|
|
|
|
|
conditions = new List<ProfileCondition>();
|
|
conditions = new List<ProfileCondition>();
|
|
foreach (var i in profile.CodecProfiles)
|
|
foreach (var i in profile.CodecProfiles)
|
|
@@ -1096,7 +1041,7 @@ namespace MediaBrowser.Model.Dlna
|
|
bool applyConditions = true;
|
|
bool applyConditions = true;
|
|
foreach (ProfileCondition applyCondition in i.ApplyConditions)
|
|
foreach (ProfileCondition applyCondition in i.ApplyConditions)
|
|
{
|
|
{
|
|
- if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
|
|
|
|
|
|
+ if (!ConditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
|
|
{
|
|
{
|
|
//LogConditionFailure(profile, "VideoCodecProfile.ApplyConditions", applyCondition, mediaSource);
|
|
//LogConditionFailure(profile, "VideoCodecProfile.ApplyConditions", applyCondition, mediaSource);
|
|
applyConditions = false;
|
|
applyConditions = false;
|
|
@@ -1116,23 +1061,22 @@ namespace MediaBrowser.Model.Dlna
|
|
|
|
|
|
foreach (ProfileCondition i in conditions)
|
|
foreach (ProfileCondition i in conditions)
|
|
{
|
|
{
|
|
- if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
|
|
|
|
|
|
+ if (!ConditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
|
|
{
|
|
{
|
|
LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource);
|
|
LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource);
|
|
|
|
|
|
var transcodeReason = GetTranscodeReasonForFailedCondition(i);
|
|
var transcodeReason = GetTranscodeReasonForFailedCondition(i);
|
|
var transcodeReasons = transcodeReason.HasValue
|
|
var transcodeReasons = transcodeReason.HasValue
|
|
? new List<TranscodeReason> { transcodeReason.Value }
|
|
? new List<TranscodeReason> { transcodeReason.Value }
|
|
- : new List<TranscodeReason> { };
|
|
|
|
|
|
+ : new List<TranscodeReason>();
|
|
|
|
|
|
- return new Tuple<PlayMethod?, List<TranscodeReason>>(null, transcodeReasons);
|
|
|
|
|
|
+ return (null, transcodeReasons);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (audioStream != null)
|
|
if (audioStream != null)
|
|
{
|
|
{
|
|
string audioCodec = audioStream.Codec;
|
|
string audioCodec = audioStream.Codec;
|
|
-
|
|
|
|
conditions = new List<ProfileCondition>();
|
|
conditions = new List<ProfileCondition>();
|
|
bool? isSecondaryAudio = audioStream == null ? null : mediaSource.IsSecondaryAudio(audioStream);
|
|
bool? isSecondaryAudio = audioStream == null ? null : mediaSource.IsSecondaryAudio(audioStream);
|
|
|
|
|
|
@@ -1143,7 +1087,7 @@ namespace MediaBrowser.Model.Dlna
|
|
bool applyConditions = true;
|
|
bool applyConditions = true;
|
|
foreach (ProfileCondition applyCondition in i.ApplyConditions)
|
|
foreach (ProfileCondition applyCondition in i.ApplyConditions)
|
|
{
|
|
{
|
|
- if (!conditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, isSecondaryAudio))
|
|
|
|
|
|
+ if (!ConditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, isSecondaryAudio))
|
|
{
|
|
{
|
|
//LogConditionFailure(profile, "VideoAudioCodecProfile.ApplyConditions", applyCondition, mediaSource);
|
|
//LogConditionFailure(profile, "VideoAudioCodecProfile.ApplyConditions", applyCondition, mediaSource);
|
|
applyConditions = false;
|
|
applyConditions = false;
|
|
@@ -1163,26 +1107,26 @@ namespace MediaBrowser.Model.Dlna
|
|
|
|
|
|
foreach (ProfileCondition i in conditions)
|
|
foreach (ProfileCondition i in conditions)
|
|
{
|
|
{
|
|
- if (!conditionProcessor.IsVideoAudioConditionSatisfied(i, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, isSecondaryAudio))
|
|
|
|
|
|
+ if (!ConditionProcessor.IsVideoAudioConditionSatisfied(i, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, isSecondaryAudio))
|
|
{
|
|
{
|
|
LogConditionFailure(profile, "VideoAudioCodecProfile", i, mediaSource);
|
|
LogConditionFailure(profile, "VideoAudioCodecProfile", i, mediaSource);
|
|
|
|
|
|
var transcodeReason = GetTranscodeReasonForFailedCondition(i);
|
|
var transcodeReason = GetTranscodeReasonForFailedCondition(i);
|
|
var transcodeReasons = transcodeReason.HasValue
|
|
var transcodeReasons = transcodeReason.HasValue
|
|
? new List<TranscodeReason> { transcodeReason.Value }
|
|
? new List<TranscodeReason> { transcodeReason.Value }
|
|
- : new List<TranscodeReason> { };
|
|
|
|
|
|
+ : new List<TranscodeReason>();
|
|
|
|
|
|
- return new Tuple<PlayMethod?, List<TranscodeReason>>(null, transcodeReasons);
|
|
|
|
|
|
+ return (null, transcodeReasons);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (isEligibleForDirectStream && mediaSource.SupportsDirectStream)
|
|
if (isEligibleForDirectStream && mediaSource.SupportsDirectStream)
|
|
{
|
|
{
|
|
- return new Tuple<PlayMethod?, List<TranscodeReason>>(PlayMethod.DirectStream, new List<TranscodeReason>());
|
|
|
|
|
|
+ return (PlayMethod.DirectStream, new List<TranscodeReason>());
|
|
}
|
|
}
|
|
|
|
|
|
- return new Tuple<PlayMethod?, List<TranscodeReason>>(null, new List<TranscodeReason> { TranscodeReason.ContainerBitrateExceedsLimit });
|
|
|
|
|
|
+ return (null, new List<TranscodeReason> { TranscodeReason.ContainerBitrateExceedsLimit });
|
|
}
|
|
}
|
|
|
|
|
|
private void LogConditionFailure(DeviceProfile profile, string type, ProfileCondition condition, MediaSourceInfo mediaSource)
|
|
private void LogConditionFailure(DeviceProfile profile, string type, ProfileCondition condition, MediaSourceInfo mediaSource)
|
|
@@ -1197,7 +1141,8 @@ namespace MediaBrowser.Model.Dlna
|
|
mediaSource.Path ?? "Unknown path");
|
|
mediaSource.Path ?? "Unknown path");
|
|
}
|
|
}
|
|
|
|
|
|
- private ValueTuple<bool, TranscodeReason?> IsEligibleForDirectPlay(MediaSourceInfo item,
|
|
|
|
|
|
+ private (bool directPlay, TranscodeReason? reason) IsEligibleForDirectPlay(
|
|
|
|
+ MediaSourceInfo item,
|
|
long maxBitrate,
|
|
long maxBitrate,
|
|
MediaStream subtitleStream,
|
|
MediaStream subtitleStream,
|
|
VideoOptions options,
|
|
VideoOptions options,
|
|
@@ -1210,21 +1155,23 @@ namespace MediaBrowser.Model.Dlna
|
|
if (subtitleProfile.Method != SubtitleDeliveryMethod.External && subtitleProfile.Method != SubtitleDeliveryMethod.Embed)
|
|
if (subtitleProfile.Method != SubtitleDeliveryMethod.External && subtitleProfile.Method != SubtitleDeliveryMethod.Embed)
|
|
{
|
|
{
|
|
_logger.LogInformation("Not eligible for {0} due to unsupported subtitles", playMethod);
|
|
_logger.LogInformation("Not eligible for {0} due to unsupported subtitles", playMethod);
|
|
- return new ValueTuple<bool, TranscodeReason?>(false, TranscodeReason.SubtitleCodecNotSupported);
|
|
|
|
|
|
+ return (false, TranscodeReason.SubtitleCodecNotSupported);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- var result = IsAudioEligibleForDirectPlay(item, maxBitrate, playMethod);
|
|
|
|
-
|
|
|
|
- if (result)
|
|
|
|
- {
|
|
|
|
- return new ValueTuple<bool, TranscodeReason?>(result, null);
|
|
|
|
- }
|
|
|
|
|
|
+ bool result = IsAudioEligibleForDirectPlay(item, maxBitrate, playMethod);
|
|
|
|
|
|
- return new ValueTuple<bool, TranscodeReason?>(result, TranscodeReason.ContainerBitrateExceedsLimit);
|
|
|
|
|
|
+ return (result, result ? (TranscodeReason?)null : TranscodeReason.ContainerBitrateExceedsLimit);
|
|
}
|
|
}
|
|
|
|
|
|
- public static SubtitleProfile GetSubtitleProfile(MediaSourceInfo mediaSource, MediaStream subtitleStream, SubtitleProfile[] subtitleProfiles, PlayMethod playMethod, ITranscoderSupport transcoderSupport, string outputContainer, string transcodingSubProtocol)
|
|
|
|
|
|
+ public static SubtitleProfile GetSubtitleProfile(
|
|
|
|
+ MediaSourceInfo mediaSource,
|
|
|
|
+ MediaStream subtitleStream,
|
|
|
|
+ SubtitleProfile[] subtitleProfiles,
|
|
|
|
+ PlayMethod playMethod,
|
|
|
|
+ ITranscoderSupport transcoderSupport,
|
|
|
|
+ string outputContainer,
|
|
|
|
+ string transcodingSubProtocol)
|
|
{
|
|
{
|
|
if (!subtitleStream.IsExternal && (playMethod != PlayMethod.Transcode || !string.Equals(transcodingSubProtocol, "hls", StringComparison.OrdinalIgnoreCase)))
|
|
if (!subtitleStream.IsExternal && (playMethod != PlayMethod.Transcode || !string.Equals(transcodingSubProtocol, "hls", StringComparison.OrdinalIgnoreCase)))
|
|
{
|
|
{
|
|
@@ -1301,27 +1248,20 @@ namespace MediaBrowser.Model.Dlna
|
|
{
|
|
{
|
|
if (!string.IsNullOrEmpty(transcodingContainer))
|
|
if (!string.IsNullOrEmpty(transcodingContainer))
|
|
{
|
|
{
|
|
- var normalizedContainers = ContainerProfile.SplitValue(transcodingContainer);
|
|
|
|
|
|
+ string[] normalizedContainers = ContainerProfile.SplitValue(transcodingContainer);
|
|
|
|
|
|
- if (ContainerProfile.ContainsContainer(normalizedContainers, "ts"))
|
|
|
|
- {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- if (ContainerProfile.ContainsContainer(normalizedContainers, "mpegts"))
|
|
|
|
- {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- if (ContainerProfile.ContainsContainer(normalizedContainers, "mp4"))
|
|
|
|
|
|
+ if (ContainerProfile.ContainsContainer(normalizedContainers, "ts")
|
|
|
|
+ || ContainerProfile.ContainsContainer(normalizedContainers, "mpegts")
|
|
|
|
+ || ContainerProfile.ContainsContainer(normalizedContainers, "mp4"))
|
|
{
|
|
{
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
- if (ContainerProfile.ContainsContainer(normalizedContainers, "mkv") ||
|
|
|
|
- ContainerProfile.ContainsContainer(normalizedContainers, "matroska"))
|
|
|
|
|
|
+ else if (ContainerProfile.ContainsContainer(normalizedContainers, "mkv")
|
|
|
|
+ || ContainerProfile.ContainsContainer(normalizedContainers, "matroska"))
|
|
{
|
|
{
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1388,22 +1328,22 @@ namespace MediaBrowser.Model.Dlna
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
- var requestedMaxBitrate = maxBitrate > 0 ? maxBitrate : 1000000;
|
|
|
|
|
|
+ long requestedMaxBitrate = maxBitrate > 0 ? maxBitrate : 1000000;
|
|
|
|
|
|
// If we don't know the bitrate, then force a transcode if requested max bitrate is under 40 mbps
|
|
// If we don't know the bitrate, then force a transcode if requested max bitrate is under 40 mbps
|
|
- var itemBitrate = item.Bitrate ??
|
|
|
|
- 40000000;
|
|
|
|
|
|
+ int itemBitrate = item.Bitrate ?? 40000000;
|
|
|
|
|
|
if (itemBitrate > requestedMaxBitrate)
|
|
if (itemBitrate > requestedMaxBitrate)
|
|
{
|
|
{
|
|
- _logger.LogInformation("Bitrate exceeds " + playMethod + " limit: media bitrate: {0}, max bitrate: {1}", itemBitrate.ToString(CultureInfo.InvariantCulture), requestedMaxBitrate.ToString(CultureInfo.InvariantCulture));
|
|
|
|
|
|
+ _logger.LogInformation("Bitrate exceeds {PlayBackMethod} limit: media bitrate: {MediaBitrate}, max bitrate: {MaxBitrate}",
|
|
|
|
+ playMethod, itemBitrate, requestedMaxBitrate);
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
- private void ValidateInput(VideoOptions options)
|
|
|
|
|
|
+ private static void ValidateInput(VideoOptions options)
|
|
{
|
|
{
|
|
ValidateAudioInput(options);
|
|
ValidateAudioInput(options);
|
|
|
|
|
|
@@ -1418,7 +1358,7 @@ namespace MediaBrowser.Model.Dlna
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- private void ValidateAudioInput(AudioOptions options)
|
|
|
|
|
|
+ private static void ValidateAudioInput(AudioOptions options)
|
|
{
|
|
{
|
|
if (options.ItemId.Equals(Guid.Empty))
|
|
if (options.ItemId.Equals(Guid.Empty))
|
|
{
|
|
{
|
|
@@ -1438,32 +1378,6 @@ namespace MediaBrowser.Model.Dlna
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- private void ApplyTranscodingConditions(StreamInfo item, List<CodecProfile> codecProfiles)
|
|
|
|
- {
|
|
|
|
- foreach (var profile in codecProfiles)
|
|
|
|
- {
|
|
|
|
- ApplyTranscodingConditions(item, profile);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void ApplyTranscodingConditions(StreamInfo item, CodecProfile codecProfile)
|
|
|
|
- {
|
|
|
|
- var codecs = ContainerProfile.SplitValue(codecProfile.Codec);
|
|
|
|
- if (codecs.Length == 0)
|
|
|
|
- {
|
|
|
|
- ApplyTranscodingConditions(item, codecProfile.Conditions, null, true, true);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- var enableNonQualified = true;
|
|
|
|
-
|
|
|
|
- foreach (var codec in codecs)
|
|
|
|
- {
|
|
|
|
- ApplyTranscodingConditions(item, codecProfile.Conditions, codec, true, enableNonQualified);
|
|
|
|
- enableNonQualified = false;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
private void ApplyTranscodingConditions(StreamInfo item, IEnumerable<ProfileCondition> conditions, string qualifier, bool enableQualifiedConditions, bool enableNonQualifiedConditions)
|
|
private void ApplyTranscodingConditions(StreamInfo item, IEnumerable<ProfileCondition> conditions, string qualifier, bool enableQualifiedConditions, bool enableNonQualifiedConditions)
|
|
{
|
|
{
|
|
foreach (ProfileCondition condition in conditions)
|
|
foreach (ProfileCondition condition in conditions)
|
|
@@ -1838,7 +1752,7 @@ namespace MediaBrowser.Model.Dlna
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- private bool IsAudioDirectPlaySupported(DirectPlayProfile profile, MediaSourceInfo item, MediaStream audioStream)
|
|
|
|
|
|
+ private static bool IsAudioDirectPlaySupported(DirectPlayProfile profile, MediaSourceInfo item, MediaStream audioStream)
|
|
{
|
|
{
|
|
// Check container type
|
|
// Check container type
|
|
if (!profile.SupportsContainer(item.Container))
|
|
if (!profile.SupportsContainer(item.Container))
|
|
@@ -1847,7 +1761,7 @@ namespace MediaBrowser.Model.Dlna
|
|
}
|
|
}
|
|
|
|
|
|
// Check audio codec
|
|
// Check audio codec
|
|
- string audioCodec = audioStream == null ? null : audioStream.Codec;
|
|
|
|
|
|
+ string audioCodec = audioStream?.Codec;
|
|
if (!profile.SupportsAudioCodec(audioCodec))
|
|
if (!profile.SupportsAudioCodec(audioCodec))
|
|
{
|
|
{
|
|
return false;
|
|
return false;
|
|
@@ -1865,20 +1779,16 @@ namespace MediaBrowser.Model.Dlna
|
|
}
|
|
}
|
|
|
|
|
|
// Check video codec
|
|
// Check video codec
|
|
- string videoCodec = videoStream == null ? null : videoStream.Codec;
|
|
|
|
|
|
+ string videoCodec = videoStream?.Codec;
|
|
if (!profile.SupportsVideoCodec(videoCodec))
|
|
if (!profile.SupportsVideoCodec(videoCodec))
|
|
{
|
|
{
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
// Check audio codec
|
|
// Check audio codec
|
|
- if (audioStream != null)
|
|
|
|
|
|
+ if (audioStream != null && !profile.SupportsAudioCodec(audioStream.Codec))
|
|
{
|
|
{
|
|
- string audioCodec = audioStream == null ? null : audioStream.Codec;
|
|
|
|
- if (!profile.SupportsAudioCodec(audioCodec))
|
|
|
|
- {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
|
|
+ return false;
|
|
}
|
|
}
|
|
|
|
|
|
return true;
|
|
return true;
|