Merge pull request #535 from Bond-009/streambuilder

Clean up streambuilder
This commit is contained in:
Andrew Rabert 2019-01-22 19:40:59 -05:00 committed by GitHub
commit becbad981c
4 changed files with 225 additions and 319 deletions

View file

@ -66,21 +66,21 @@ namespace MediaBrowser.Model.Dlna
return MaxBitrate;
}
if (Profile != null)
if (Profile == null)
{
if (Context == EncodingContext.Static)
{
if (isAudio && Profile.MaxStaticMusicBitrate.HasValue)
{
return Profile.MaxStaticMusicBitrate;
}
return Profile.MaxStaticBitrate;
}
return Profile.MaxStreamingBitrate;
return null;
}
return null;
if (Context == EncodingContext.Static)
{
if (isAudio && Profile.MaxStaticMusicBitrate.HasValue)
{
return Profile.MaxStaticMusicBitrate;
}
return Profile.MaxStaticBitrate;
}
return Profile.MaxStreamingBitrate;
}
}
}

View file

@ -5,9 +5,10 @@ using MediaBrowser.Model.MediaInfo;
namespace MediaBrowser.Model.Dlna
{
public class ConditionProcessor
public static class ConditionProcessor
{
public bool IsVideoConditionSatisfied(ProfileCondition condition,
public static bool IsVideoConditionSatisfied(
ProfileCondition condition,
int? width,
int? height,
int? videoBitDepth,
@ -64,7 +65,7 @@ namespace MediaBrowser.Model.Dlna
}
}
public bool IsImageConditionSatisfied(ProfileCondition condition, int? width, int? height)
public static bool IsImageConditionSatisfied(ProfileCondition condition, int? width, int? height)
{
switch (condition.Property)
{
@ -77,7 +78,7 @@ namespace MediaBrowser.Model.Dlna
}
}
public bool IsAudioConditionSatisfied(ProfileCondition condition, int? audioChannels, int? audioBitrate, int? audioSampleRate, int? audioBitDepth)
public static bool IsAudioConditionSatisfied(ProfileCondition condition, int? audioChannels, int? audioBitrate, int? audioSampleRate, int? audioBitDepth)
{
switch (condition.Property)
{
@ -94,7 +95,8 @@ namespace MediaBrowser.Model.Dlna
}
}
public bool IsVideoAudioConditionSatisfied(ProfileCondition condition,
public static bool IsVideoAudioConditionSatisfied(
ProfileCondition condition,
int? audioChannels,
int? audioBitrate,
int? audioSampleRate,
@ -121,7 +123,7 @@ namespace MediaBrowser.Model.Dlna
}
}
private bool IsConditionSatisfied(ProfileCondition condition, int? currentValue)
private static bool IsConditionSatisfied(ProfileCondition condition, int? currentValue)
{
if (!currentValue.HasValue)
{
@ -150,7 +152,7 @@ namespace MediaBrowser.Model.Dlna
return false;
}
private bool IsConditionSatisfied(ProfileCondition condition, string currentValue)
private static bool IsConditionSatisfied(ProfileCondition condition, string currentValue)
{
if (string.IsNullOrEmpty(currentValue))
{
@ -175,7 +177,7 @@ namespace MediaBrowser.Model.Dlna
}
}
private bool IsConditionSatisfied(ProfileCondition condition, bool? currentValue)
private static bool IsConditionSatisfied(ProfileCondition condition, bool? currentValue)
{
if (!currentValue.HasValue)
{
@ -199,7 +201,7 @@ namespace MediaBrowser.Model.Dlna
return false;
}
private bool IsConditionSatisfied(ProfileCondition condition, float currentValue)
private static bool IsConditionSatisfied(ProfileCondition condition, float currentValue)
{
if (currentValue <= 0)
{
@ -227,7 +229,7 @@ namespace MediaBrowser.Model.Dlna
return false;
}
private bool IsConditionSatisfied(ProfileCondition condition, double? currentValue)
private static bool IsConditionSatisfied(ProfileCondition condition, double? currentValue)
{
if (!currentValue.HasValue)
{
@ -255,7 +257,7 @@ namespace MediaBrowser.Model.Dlna
return false;
}
private bool IsConditionSatisfied(ProfileCondition condition, TransportStreamTimestamp? timestamp)
private static bool IsConditionSatisfied(ProfileCondition condition, TransportStreamTimestamp? timestamp)
{
if (!timestamp.HasValue)
{

View file

@ -188,12 +188,10 @@ namespace MediaBrowser.Model.Dlna
continue;
}
var conditionProcessor = new ConditionProcessor();
var anyOff = false;
foreach (ProfileCondition c in i.Conditions)
{
if (!conditionProcessor.IsAudioConditionSatisfied(GetModelProfileCondition(c), audioChannels, audioBitrate, audioSampleRate, audioBitDepth))
if (!ConditionProcessor.IsAudioConditionSatisfied(GetModelProfileCondition(c), audioChannels, audioBitrate, audioSampleRate, audioBitDepth))
{
anyOff = true;
break;
@ -235,12 +233,10 @@ namespace MediaBrowser.Model.Dlna
continue;
}
var conditionProcessor = new ConditionProcessor();
var anyOff = false;
foreach (var c in i.Conditions)
{
if (!conditionProcessor.IsImageConditionSatisfied(GetModelProfileCondition(c), width, height))
if (!ConditionProcessor.IsImageConditionSatisfied(GetModelProfileCondition(c), width, height))
{
anyOff = true;
break;
@ -301,12 +297,10 @@ namespace MediaBrowser.Model.Dlna
continue;
}
var conditionProcessor = new ConditionProcessor();
var anyOff = false;
foreach (ProfileCondition c in i.Conditions)
{
if (!conditionProcessor.IsVideoConditionSatisfied(GetModelProfileCondition(c), width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
if (!ConditionProcessor.IsVideoConditionSatisfied(GetModelProfileCondition(c), width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
{
anyOff = true;
break;

View file

@ -93,19 +93,10 @@ namespace MediaBrowser.Model.Dlna
return GetOptimalStream(streams, options.GetMaxBitrate(false) ?? 0);
}
private StreamInfo GetOptimalStream(List<StreamInfo> streams, long maxBitrate)
{
var sorted = SortMediaSources(streams, maxBitrate);
private static StreamInfo GetOptimalStream(List<StreamInfo> streams, long maxBitrate)
=> SortMediaSources(streams, maxBitrate).FirstOrDefault();
foreach (StreamInfo stream in sorted)
{
return stream;
}
return null;
}
private StreamInfo[] SortMediaSources(List<StreamInfo> streams, long maxBitrate)
private static IOrderedEnumerable<StreamInfo> SortMediaSources(List<StreamInfo> streams, long maxBitrate)
{
return streams.OrderBy(i =>
{
@ -151,25 +142,17 @@ namespace MediaBrowser.Model.Dlna
return 0;
}).ThenBy(streams.IndexOf).ToArray();
}).ThenBy(streams.IndexOf);
}
private TranscodeReason? GetTranscodeReasonForFailedCondition(ProfileCondition condition)
private static 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:
@ -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))
{
@ -266,12 +249,10 @@ namespace MediaBrowser.Model.Dlna
{
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)
{
var transcodeReasons = new List<TranscodeReason>();
var playlistItem = new StreamInfo
StreamInfo playlistItem = new StreamInfo
{
ItemId = options.ItemId,
MediaType = DlnaProfileType.Audio,
@ -313,18 +292,16 @@ namespace MediaBrowser.Model.Dlna
var directPlayInfo = GetAudioDirectPlayMethods(item, audioStream, options);
var directPlayMethods = directPlayInfo.Item1;
transcodeReasons.AddRange(directPlayInfo.Item2);
var transcodeReasons = directPlayInfo.Item2.ToList();
var conditionProcessor = new ConditionProcessor();
int? inputAudioChannels = audioStream?.Channels;
int? inputAudioBitrate = audioStream?.BitDepth;
int? inputAudioSampleRate = audioStream?.SampleRate;
int? inputAudioBitDepth = audioStream.BitDepth;
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;
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
var conditions = new List<ProfileCondition>();
@ -335,7 +312,7 @@ namespace MediaBrowser.Model.Dlna
bool applyConditions = true;
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);
applyConditions = false;
@ -345,10 +322,7 @@ namespace MediaBrowser.Model.Dlna
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;
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);
var transcodeReason = GetTranscodeReasonForFailedCondition(c);
@ -385,13 +359,12 @@ namespace MediaBrowser.Model.Dlna
TranscodingProfile transcodingProfile = null;
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;
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);
applyConditions = false;
@ -463,7 +436,7 @@ namespace MediaBrowser.Model.Dlna
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)
{
@ -473,66 +446,57 @@ namespace MediaBrowser.Model.Dlna
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;
}
}
var 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)
{
if (IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate(true) ?? 0, 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)
{
if (IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true) ?? 0, 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.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 transcodeReasons = new List<TranscodeReason>();
// 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 (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)
{
if (IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true) ?? 0, PlayMethod.DirectPlay))
{
if (options.EnableDirectPlay)
{
playMethods.Add(PlayMethod.DirectPlay);
}
}
else
{
transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit);
}
}
if (playMethods.Count > 0)
{
transcodeReasons.Clear();
@ -542,41 +506,25 @@ namespace MediaBrowser.Model.Dlna
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 audioSupported = false;
var videoSupported = false;
foreach (var profile in directPlayProfiles)
{
audioSupported = false;
videoSupported = false;
// Check container type
if (profile.SupportsContainer(item.Container))
{
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)
{
@ -585,6 +533,7 @@ namespace MediaBrowser.Model.Dlna
}
}
var list = new List<TranscodeReason>();
if (!containerSupported)
{
list.Add(TranscodeReason.ContainerNotSupported);
@ -603,18 +552,17 @@ namespace MediaBrowser.Model.Dlna
return list;
}
private int? GetDefaultSubtitleStreamIndex(MediaSourceInfo item, SubtitleProfile[] subtitleProfiles)
private static int? GetDefaultSubtitleStreamIndex(MediaSourceInfo item, SubtitleProfile[] subtitleProfiles)
{
int highestScore = -1;
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;
}
private void SetStreamInfoOptionsFromTranscodingProfile(StreamInfo playlistItem, TranscodingProfile transcodingProfile)
private static void SetStreamInfoOptionsFromTranscodingProfile(StreamInfo playlistItem, TranscodingProfile transcodingProfile)
{
if (string.IsNullOrEmpty(transcodingProfile.AudioCodec))
{
@ -686,12 +634,10 @@ namespace MediaBrowser.Model.Dlna
}
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));
}
var transcodeReasons = new List<TranscodeReason>();
var playlistItem = new StreamInfo
StreamInfo playlistItem = new StreamInfo
{
ItemId = options.ItemId,
MediaType = DlnaProfileType.Video,
@ -737,6 +681,8 @@ namespace MediaBrowser.Model.Dlna
isEligibleForDirectPlay,
isEligibleForDirectStream);
var transcodeReasons = new List<TranscodeReason>();
if (isEligibleForDirectPlay || isEligibleForDirectStream)
{
// See if it can be direct played
@ -803,8 +749,6 @@ namespace MediaBrowser.Model.Dlna
SetStreamInfoOptionsFromTranscodingProfile(playlistItem, transcodingProfile);
var conditionProcessor = new ConditionProcessor();
var isFirstAppliedCodecProfile = true;
foreach (var i in options.Profile.CodecProfiles)
{
@ -813,26 +757,26 @@ namespace MediaBrowser.Model.Dlna
bool applyConditions = true;
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;
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;
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? 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);
applyConditions = false;
@ -876,7 +820,7 @@ namespace MediaBrowser.Model.Dlna
int? inputAudioSampleRate = audioStream == null ? null : audioStream.SampleRate;
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);
applyConditions = false;
@ -922,7 +866,7 @@ namespace MediaBrowser.Model.Dlna
return playlistItem;
}
private int GetDefaultAudioBitrateIfUnknown(MediaStream audioStream)
private static int GetDefaultAudioBitrateIfUnknown(MediaStream audioStream)
{
if ((audioStream.Channels ?? 0) >= 6)
{
@ -932,33 +876,37 @@ namespace MediaBrowser.Model.Dlna
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 defaultBitrate = audioStream == null ? 192000 : audioStream.BitRate ?? GetDefaultAudioBitrateIfUnknown(audioStream);
// Reduce the bitrate if we're downmixing
if (targetAudioChannels.HasValue && audioStream != null && audioStream.Channels.HasValue && targetAudioChannels.Value < audioStream.Channels.Value)
{
defaultBitrate = targetAudioChannels.Value <= 2 ? 128000 : 192000;
}
int? targetAudioChannels = item.GetTargetAudioChannels(targetAudioCodec);
int defaultBitrate;
int encoderAudioBitrateLimit = int.MaxValue;
if (audioStream != null)
if (audioStream == null)
{
defaultBitrate = 192000;
}
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.
// 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);
}
private int GetMaxAudioBitrateForTotalBitrate(long totalBitrate)
private static int GetMaxAudioBitrateForTotalBitrate(long totalBitrate)
{
if (totalBitrate <= 640000)
{
return 128000;
}
if (totalBitrate <= 2000000)
else if (totalBitrate <= 2000000)
{
return 384000;
}
if (totalBitrate <= 3000000)
else if (totalBitrate <= 3000000)
{
return 448000;
}
@ -990,24 +936,25 @@ namespace MediaBrowser.Model.Dlna
return 640000;
}
private Tuple<PlayMethod?, List<TranscodeReason>> GetVideoDirectPlayProfile(VideoOptions options,
private (PlayMethod?, List<TranscodeReason>) GetVideoDirectPlayProfile(
VideoOptions options,
MediaSourceInfo mediaSource,
MediaStream videoStream,
MediaStream audioStream,
bool isEligibleForDirectPlay,
bool isEligibleForDirectStream)
{
DeviceProfile profile = options.Profile;
if (options.ForceDirectPlay)
{
return new Tuple<PlayMethod?, List<TranscodeReason>>(PlayMethod.DirectPlay, new List<TranscodeReason>());
return (PlayMethod.DirectPlay, new List<TranscodeReason>());
}
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
DirectPlayProfile directPlay = null;
foreach (var i in profile.DirectPlayProfiles)
@ -1025,7 +972,7 @@ namespace MediaBrowser.Model.Dlna
profile.Name ?? "Unknown Profile",
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;
@ -1033,8 +980,8 @@ namespace MediaBrowser.Model.Dlna
var conditions = new List<ProfileCondition>();
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)
{
@ -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;
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;
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? numVideoStreams = mediaSource.GetStreamCount(MediaStreamType.Video);
@ -1073,20 +1018,20 @@ namespace MediaBrowser.Model.Dlna
// Check container 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);
var transcodeReason = GetTranscodeReasonForFailedCondition(i);
var transcodeReasons = transcodeReason.HasValue
? 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>();
foreach (var i in profile.CodecProfiles)
@ -1096,7 +1041,7 @@ namespace MediaBrowser.Model.Dlna
bool applyConditions = true;
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);
applyConditions = false;
@ -1116,23 +1061,22 @@ namespace MediaBrowser.Model.Dlna
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);
var transcodeReason = GetTranscodeReasonForFailedCondition(i);
var transcodeReasons = transcodeReason.HasValue
? 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)
{
string audioCodec = audioStream.Codec;
conditions = new List<ProfileCondition>();
bool? isSecondaryAudio = audioStream == null ? null : mediaSource.IsSecondaryAudio(audioStream);
@ -1143,7 +1087,7 @@ namespace MediaBrowser.Model.Dlna
bool applyConditions = true;
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);
applyConditions = false;
@ -1163,26 +1107,26 @@ namespace MediaBrowser.Model.Dlna
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);
var transcodeReason = GetTranscodeReasonForFailedCondition(i);
var transcodeReasons = transcodeReason.HasValue
? 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)
{
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)
@ -1197,7 +1141,8 @@ namespace MediaBrowser.Model.Dlna
mediaSource.Path ?? "Unknown path");
}
private ValueTuple<bool, TranscodeReason?> IsEligibleForDirectPlay(MediaSourceInfo item,
private (bool directPlay, TranscodeReason? reason) IsEligibleForDirectPlay(
MediaSourceInfo item,
long maxBitrate,
MediaStream subtitleStream,
VideoOptions options,
@ -1210,21 +1155,23 @@ namespace MediaBrowser.Model.Dlna
if (subtitleProfile.Method != SubtitleDeliveryMethod.External && subtitleProfile.Method != SubtitleDeliveryMethod.Embed)
{
_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);
bool result = IsAudioEligibleForDirectPlay(item, maxBitrate, playMethod);
if (result)
{
return new ValueTuple<bool, TranscodeReason?>(result, null);
}
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)))
{
@ -1301,27 +1248,20 @@ namespace MediaBrowser.Model.Dlna
{
if (!string.IsNullOrEmpty(transcodingContainer))
{
var normalizedContainers = ContainerProfile.SplitValue(transcodingContainer);
string[] normalizedContainers = ContainerProfile.SplitValue(transcodingContainer);
if (ContainerProfile.ContainsContainer(normalizedContainers, "ts"))
if (ContainerProfile.ContainsContainer(normalizedContainers, "ts")
|| ContainerProfile.ContainsContainer(normalizedContainers, "mpegts")
|| ContainerProfile.ContainsContainer(normalizedContainers, "mp4"))
{
return false;
}
if (ContainerProfile.ContainsContainer(normalizedContainers, "mpegts"))
{
return false;
}
if (ContainerProfile.ContainsContainer(normalizedContainers, "mp4"))
{
return false;
}
if (ContainerProfile.ContainsContainer(normalizedContainers, "mkv") ||
ContainerProfile.ContainsContainer(normalizedContainers, "matroska"))
else if (ContainerProfile.ContainsContainer(normalizedContainers, "mkv")
|| ContainerProfile.ContainsContainer(normalizedContainers, "matroska"))
{
return true;
}
}
return false;
}
@ -1388,22 +1328,22 @@ namespace MediaBrowser.Model.Dlna
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
var itemBitrate = item.Bitrate ??
40000000;
int itemBitrate = item.Bitrate ?? 40000000;
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 true;
}
private void ValidateInput(VideoOptions options)
private static void ValidateInput(VideoOptions 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))
{
@ -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)
{
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
if (!profile.SupportsContainer(item.Container))
@ -1847,7 +1761,7 @@ namespace MediaBrowser.Model.Dlna
}
// Check audio codec
string audioCodec = audioStream == null ? null : audioStream.Codec;
string audioCodec = audioStream?.Codec;
if (!profile.SupportsAudioCodec(audioCodec))
{
return false;
@ -1865,20 +1779,16 @@ namespace MediaBrowser.Model.Dlna
}
// Check video codec
string videoCodec = videoStream == null ? null : videoStream.Codec;
string videoCodec = videoStream?.Codec;
if (!profile.SupportsVideoCodec(videoCodec))
{
return false;
}
// 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;