aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Model
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Model')
-rw-r--r--MediaBrowser.Model/Configuration/EncodingOptions.cs3
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs10
-rw-r--r--MediaBrowser.Model/Dlna/ConditionProcessor.cs39
-rw-r--r--MediaBrowser.Model/Dlna/ContainerProfile.cs2
-rw-r--r--MediaBrowser.Model/Dlna/DirectPlayProfile.cs6
-rw-r--r--MediaBrowser.Model/Dlna/ITranscoderSupport.cs18
-rw-r--r--MediaBrowser.Model/Dlna/MediaOptions.cs10
-rw-r--r--MediaBrowser.Model/Dlna/StreamBuilder.cs146
-rw-r--r--MediaBrowser.Model/Dlna/StreamInfo.cs5
-rw-r--r--MediaBrowser.Model/Globalization/ILocalizationManager.cs3
-rw-r--r--MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs41
-rw-r--r--MediaBrowser.Model/MediaInfo/IBlurayExaminer.cs14
12 files changed, 179 insertions, 118 deletions
diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs
index b43e0f024..f9f63f751 100644
--- a/MediaBrowser.Model/Configuration/EncodingOptions.cs
+++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs
@@ -40,7 +40,8 @@ public class EncodingOptions
DeinterlaceMethod = "yadif";
EnableDecodingColorDepth10Hevc = true;
EnableDecodingColorDepth10Vp9 = true;
- EnableEnhancedNvdecDecoder = false;
+ // Enhanced Nvdec or system native decoder is required for DoVi to SDR tone-mapping.
+ EnableEnhancedNvdecDecoder = true;
PreferSystemNativeHwDecoder = true;
EnableIntelLowPowerH264HwEncoder = false;
EnableIntelLowPowerHevcHwEncoder = false;
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index c39162250..7cb07a2f7 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -243,16 +243,10 @@ namespace MediaBrowser.Model.Configuration
public bool AllowClientLogUpload { get; set; } = true;
/// <summary>
- /// Gets or sets the dummy chapters duration in seconds.
+ /// Gets or sets the dummy chapter duration in seconds, use 0 (zero) or less to disable generation alltogether.
/// </summary>
/// <value>The dummy chapters duration.</value>
- public int DummyChapterDuration { get; set; } = 300;
-
- /// <summary>
- /// Gets or sets the dummy chapter count.
- /// </summary>
- /// <value>The dummy chapter count.</value>
- public int DummyChapterCount { get; set; } = 100;
+ public int DummyChapterDuration { get; set; } = 0;
/// <summary>
/// Gets or sets the chapter image resolution.
diff --git a/MediaBrowser.Model/Dlna/ConditionProcessor.cs b/MediaBrowser.Model/Dlna/ConditionProcessor.cs
index 00b406bbe..f5e1a3c49 100644
--- a/MediaBrowser.Model/Dlna/ConditionProcessor.cs
+++ b/MediaBrowser.Model/Dlna/ConditionProcessor.cs
@@ -136,12 +136,26 @@ namespace MediaBrowser.Model.Dlna
return !condition.IsRequired;
}
- if (int.TryParse(condition.Value, CultureInfo.InvariantCulture, out var expected))
+ var conditionType = condition.Condition;
+ if (condition.Condition == ProfileConditionType.EqualsAny)
{
- switch (condition.Condition)
+ foreach (var singleConditionString in condition.Value.AsSpan().Split('|'))
+ {
+ if (int.TryParse(singleConditionString, NumberStyles.Integer, CultureInfo.InvariantCulture, out int conditionValue)
+ && conditionValue.Equals(currentValue))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ if (int.TryParse(condition.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var expected))
+ {
+ switch (conditionType)
{
case ProfileConditionType.Equals:
- case ProfileConditionType.EqualsAny:
return currentValue.Value.Equals(expected);
case ProfileConditionType.GreaterThanEqual:
return currentValue.Value >= expected;
@@ -212,9 +226,24 @@ namespace MediaBrowser.Model.Dlna
return !condition.IsRequired;
}
- if (double.TryParse(condition.Value, CultureInfo.InvariantCulture, out var expected))
+ var conditionType = condition.Condition;
+ if (condition.Condition == ProfileConditionType.EqualsAny)
{
- switch (condition.Condition)
+ foreach (var singleConditionString in condition.Value.AsSpan().Split('|'))
+ {
+ if (double.TryParse(singleConditionString, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out double conditionValue)
+ && conditionValue.Equals(currentValue))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ if (double.TryParse(condition.Value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var expected))
+ {
+ switch (conditionType)
{
case ProfileConditionType.Equals:
return currentValue.Value.Equals(expected);
diff --git a/MediaBrowser.Model/Dlna/ContainerProfile.cs b/MediaBrowser.Model/Dlna/ContainerProfile.cs
index 927df8e4e..978004268 100644
--- a/MediaBrowser.Model/Dlna/ContainerProfile.cs
+++ b/MediaBrowser.Model/Dlna/ContainerProfile.cs
@@ -11,7 +11,7 @@ namespace MediaBrowser.Model.Dlna
[XmlAttribute("type")]
public DlnaProfileType Type { get; set; }
- public ProfileCondition[]? Conditions { get; set; } = Array.Empty<ProfileCondition>();
+ public ProfileCondition[] Conditions { get; set; } = Array.Empty<ProfileCondition>();
[XmlAttribute("container")]
public string Container { get; set; } = string.Empty;
diff --git a/MediaBrowser.Model/Dlna/DirectPlayProfile.cs b/MediaBrowser.Model/Dlna/DirectPlayProfile.cs
index 03c3a7265..f68235d86 100644
--- a/MediaBrowser.Model/Dlna/DirectPlayProfile.cs
+++ b/MediaBrowser.Model/Dlna/DirectPlayProfile.cs
@@ -18,17 +18,17 @@ namespace MediaBrowser.Model.Dlna
[XmlAttribute("type")]
public DlnaProfileType Type { get; set; }
- public bool SupportsContainer(string container)
+ public bool SupportsContainer(string? container)
{
return ContainerProfile.ContainsContainer(Container, container);
}
- public bool SupportsVideoCodec(string codec)
+ public bool SupportsVideoCodec(string? codec)
{
return Type == DlnaProfileType.Video && ContainerProfile.ContainsContainer(VideoCodec, codec);
}
- public bool SupportsAudioCodec(string codec)
+ public bool SupportsAudioCodec(string? codec)
{
return (Type == DlnaProfileType.Audio || Type == DlnaProfileType.Video) && ContainerProfile.ContainsContainer(AudioCodec, codec);
}
diff --git a/MediaBrowser.Model/Dlna/ITranscoderSupport.cs b/MediaBrowser.Model/Dlna/ITranscoderSupport.cs
index a70ce44cc..d7397399d 100644
--- a/MediaBrowser.Model/Dlna/ITranscoderSupport.cs
+++ b/MediaBrowser.Model/Dlna/ITranscoderSupport.cs
@@ -10,22 +10,4 @@ namespace MediaBrowser.Model.Dlna
bool CanExtractSubtitles(string codec);
}
-
- public class FullTranscoderSupport : ITranscoderSupport
- {
- public bool CanEncodeToAudioCodec(string codec)
- {
- return true;
- }
-
- public bool CanEncodeToSubtitleCodec(string codec)
- {
- return true;
- }
-
- public bool CanExtractSubtitles(string codec)
- {
- return true;
- }
- }
}
diff --git a/MediaBrowser.Model/Dlna/MediaOptions.cs b/MediaBrowser.Model/Dlna/MediaOptions.cs
index 29aecf97f..7ec0dd473 100644
--- a/MediaBrowser.Model/Dlna/MediaOptions.cs
+++ b/MediaBrowser.Model/Dlna/MediaOptions.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using MediaBrowser.Model.Dto;
@@ -59,22 +57,22 @@ namespace MediaBrowser.Model.Dlna
/// <summary>
/// Gets or sets the media sources.
/// </summary>
- public MediaSourceInfo[] MediaSources { get; set; }
+ public MediaSourceInfo[] MediaSources { get; set; } = Array.Empty<MediaSourceInfo>();
/// <summary>
/// Gets or sets the device profile.
/// </summary>
- public DeviceProfile Profile { get; set; }
+ required public DeviceProfile Profile { get; set; }
/// <summary>
/// Gets or sets a media source id. Optional. Only needed if a specific AudioStreamIndex or SubtitleStreamIndex are requested.
/// </summary>
- public string MediaSourceId { get; set; }
+ public string? MediaSourceId { get; set; }
/// <summary>
/// Gets or sets the device id.
/// </summary>
- public string DeviceId { get; set; }
+ public string? DeviceId { get; set; }
/// <summary>
/// Gets or sets an override of supported number of audio channels
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs
index 21e581801..db892a22c 100644
--- a/MediaBrowser.Model/Dlna/StreamBuilder.cs
+++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -41,53 +39,36 @@ namespace MediaBrowser.Model.Dlna
}
/// <summary>
- /// Initializes a new instance of the <see cref="StreamBuilder"/> class.
- /// </summary>
- /// <param name="logger">The <see cref="ILogger"/> object.</param>
- public StreamBuilder(ILogger<StreamBuilder> logger)
- : this(new FullTranscoderSupport(), logger)
- {
- }
-
- /// <summary>
/// Gets the optimal audio stream.
/// </summary>
/// <param name="options">The <see cref="MediaOptions"/> object to get the audio stream from.</param>
/// <returns>The <see cref="StreamInfo"/> of the optimal audio stream.</returns>
- public StreamInfo GetOptimalAudioStream(MediaOptions options)
+ public StreamInfo? GetOptimalAudioStream(MediaOptions options)
{
ValidateMediaOptions(options, false);
- var mediaSources = new List<MediaSourceInfo>();
+ var streams = new List<StreamInfo>();
foreach (var mediaSource in options.MediaSources)
{
- if (string.IsNullOrEmpty(options.MediaSourceId) ||
- string.Equals(mediaSource.Id, options.MediaSourceId, StringComparison.OrdinalIgnoreCase))
+ if (!(string.IsNullOrEmpty(options.MediaSourceId)
+ || string.Equals(mediaSource.Id, options.MediaSourceId, StringComparison.OrdinalIgnoreCase)))
{
- mediaSources.Add(mediaSource);
+ continue;
}
- }
- var streams = new List<StreamInfo>();
- foreach (var mediaSourceInfo in mediaSources)
- {
- StreamInfo streamInfo = GetOptimalAudioStream(mediaSourceInfo, options);
+ StreamInfo? streamInfo = GetOptimalAudioStream(mediaSource, options);
if (streamInfo is not null)
{
+ streamInfo.DeviceId = options.DeviceId;
+ streamInfo.DeviceProfileId = options.Profile.Id;
streams.Add(streamInfo);
}
}
- foreach (var stream in streams)
- {
- stream.DeviceId = options.DeviceId;
- stream.DeviceProfileId = options.Profile.Id;
- }
-
return GetOptimalStream(streams, options.GetMaxBitrate(true) ?? 0);
}
- private StreamInfo GetOptimalAudioStream(MediaSourceInfo item, MediaOptions options)
+ private StreamInfo? GetOptimalAudioStream(MediaSourceInfo item, MediaOptions options)
{
var playlistItem = new StreamInfo
{
@@ -141,7 +122,7 @@ namespace MediaBrowser.Model.Dlna
}
}
- TranscodingProfile transcodingProfile = null;
+ TranscodingProfile? transcodingProfile = null;
foreach (var tcProfile in options.Profile.TranscodingProfiles)
{
if (tcProfile.Type == playlistItem.MediaType
@@ -193,15 +174,15 @@ namespace MediaBrowser.Model.Dlna
/// </summary>
/// <param name="options">The <see cref="MediaOptions"/> object to get the video stream from.</param>
/// <returns>The <see cref="StreamInfo"/> of the optimal video stream.</returns>
- public StreamInfo GetOptimalVideoStream(MediaOptions options)
+ public StreamInfo? GetOptimalVideoStream(MediaOptions options)
{
ValidateMediaOptions(options, true);
var mediaSources = new List<MediaSourceInfo>();
foreach (var mediaSourceInfo in options.MediaSources)
{
- if (string.IsNullOrEmpty(options.MediaSourceId) ||
- string.Equals(mediaSourceInfo.Id, options.MediaSourceId, StringComparison.OrdinalIgnoreCase))
+ if (string.IsNullOrEmpty(options.MediaSourceId)
+ || string.Equals(mediaSourceInfo.Id, options.MediaSourceId, StringComparison.OrdinalIgnoreCase))
{
mediaSources.Add(mediaSourceInfo);
}
@@ -226,7 +207,7 @@ namespace MediaBrowser.Model.Dlna
return GetOptimalStream(streams, options.GetMaxBitrate(false) ?? 0);
}
- private static StreamInfo GetOptimalStream(List<StreamInfo> streams, long maxBitrate)
+ private static StreamInfo? GetOptimalStream(List<StreamInfo> streams, long maxBitrate)
=> SortMediaSources(streams, maxBitrate).FirstOrDefault();
private static IOrderedEnumerable<StreamInfo> SortMediaSources(List<StreamInfo> streams, long maxBitrate)
@@ -369,7 +350,7 @@ namespace MediaBrowser.Model.Dlna
/// <param name="type">The <see cref="DlnaProfileType"/>.</param>
/// <param name="playProfile">The <see cref="DirectPlayProfile"/> object to get the video stream from.</param>
/// <returns>The the normalized input container.</returns>
- public static string NormalizeMediaSourceFormatIntoSingleContainer(string inputContainer, DeviceProfile profile, DlnaProfileType type, DirectPlayProfile playProfile = null)
+ public static string? NormalizeMediaSourceFormatIntoSingleContainer(string inputContainer, DeviceProfile? profile, DlnaProfileType type, DirectPlayProfile? playProfile = null)
{
if (string.IsNullOrEmpty(inputContainer))
{
@@ -397,7 +378,7 @@ namespace MediaBrowser.Model.Dlna
return formats[0];
}
- private (DirectPlayProfile Profile, PlayMethod? PlayMethod, TranscodeReason TranscodeReasons) GetAudioDirectPlayProfile(MediaSourceInfo item, MediaStream audioStream, MediaOptions options)
+ private (DirectPlayProfile? Profile, PlayMethod? PlayMethod, TranscodeReason TranscodeReasons) GetAudioDirectPlayProfile(MediaSourceInfo item, MediaStream audioStream, MediaOptions options)
{
var directPlayProfile = options.Profile.DirectPlayProfiles
.FirstOrDefault(x => x.Type == DlnaProfileType.Audio && IsAudioDirectPlaySupported(x, item, audioStream));
@@ -413,7 +394,6 @@ namespace MediaBrowser.Model.Dlna
return (null, null, GetTranscodeReasonsFromDirectPlayProfile(item, null, audioStream, options.Profile.DirectPlayProfiles));
}
- var playMethods = new List<PlayMethod>();
TranscodeReason transcodeReasons = 0;
// The profile describes what the device supports
@@ -452,7 +432,7 @@ namespace MediaBrowser.Model.Dlna
return (directPlayProfile, null, transcodeReasons);
}
- private static TranscodeReason GetTranscodeReasonsFromDirectPlayProfile(MediaSourceInfo item, MediaStream videoStream, MediaStream audioStream, IEnumerable<DirectPlayProfile> directPlayProfiles)
+ private static TranscodeReason GetTranscodeReasonsFromDirectPlayProfile(MediaSourceInfo item, MediaStream? videoStream, MediaStream audioStream, IEnumerable<DirectPlayProfile> directPlayProfiles)
{
var mediaType = videoStream is null ? DlnaProfileType.Audio : DlnaProfileType.Video;
@@ -578,7 +558,7 @@ namespace MediaBrowser.Model.Dlna
}
}
- private static void SetStreamInfoOptionsFromDirectPlayProfile(MediaOptions options, MediaSourceInfo item, StreamInfo playlistItem, DirectPlayProfile directPlayProfile)
+ private static void SetStreamInfoOptionsFromDirectPlayProfile(MediaOptions options, MediaSourceInfo item, StreamInfo playlistItem, DirectPlayProfile? directPlayProfile)
{
var container = NormalizeMediaSourceFormatIntoSingleContainer(item.Container, options.Profile, DlnaProfileType.Video, directPlayProfile);
var protocol = "http";
@@ -590,7 +570,7 @@ namespace MediaBrowser.Model.Dlna
playlistItem.SubProtocol = protocol;
playlistItem.VideoCodecs = new[] { item.VideoStream.Codec };
- playlistItem.AudioCodecs = ContainerProfile.SplitValue(directPlayProfile.AudioCodec);
+ playlistItem.AudioCodecs = ContainerProfile.SplitValue(directPlayProfile?.AudioCodec);
}
private StreamInfo BuildVideoItem(MediaSourceInfo item, MediaOptions options)
@@ -637,6 +617,12 @@ namespace MediaBrowser.Model.Dlna
var isEligibleForDirectStream = options.EnableDirectStream && (options.ForceDirectStream || !bitrateLimitExceeded);
TranscodeReason transcodeReasons = 0;
+ // Force transcode or remux for BD/DVD folders
+ if (item.VideoType == VideoType.Dvd || item.VideoType == VideoType.BluRay)
+ {
+ isEligibleForDirectPlay = false;
+ }
+
if (bitrateLimitExceeded)
{
transcodeReasons = TranscodeReason.ContainerBitrateExceedsLimit;
@@ -649,7 +635,7 @@ namespace MediaBrowser.Model.Dlna
isEligibleForDirectPlay,
isEligibleForDirectStream);
- DirectPlayProfile directPlayProfile = null;
+ DirectPlayProfile? directPlayProfile = null;
if (isEligibleForDirectPlay || isEligibleForDirectStream)
{
// See if it can be direct played
@@ -680,16 +666,16 @@ namespace MediaBrowser.Model.Dlna
playlistItem.AudioStreamIndex = audioStream?.Index;
if (audioStream is not null)
{
- playlistItem.AudioCodecs = ContainerProfile.SplitValue(directPlayProfile.AudioCodec);
+ playlistItem.AudioCodecs = ContainerProfile.SplitValue(directPlayProfile?.AudioCodec);
}
SetStreamInfoOptionsFromDirectPlayProfile(options, item, playlistItem, directPlayProfile);
- BuildStreamVideoItem(playlistItem, options, item, videoStream, audioStream, candidateAudioStreams, directPlayProfile.Container, directPlayProfile.VideoCodec, directPlayProfile.AudioCodec);
+ BuildStreamVideoItem(playlistItem, options, item, videoStream, audioStream, candidateAudioStreams, directPlayProfile?.Container, directPlayProfile?.VideoCodec, directPlayProfile?.AudioCodec);
}
if (subtitleStream is not null)
{
- var subtitleProfile = GetSubtitleProfile(item, subtitleStream, options.Profile.SubtitleProfiles, directPlay.Value, _transcoderSupport, directPlayProfile.Container, null);
+ var subtitleProfile = GetSubtitleProfile(item, subtitleStream, options.Profile.SubtitleProfiles, directPlay.Value, _transcoderSupport, directPlayProfile?.Container, null);
playlistItem.SubtitleDeliveryMethod = subtitleProfile.Method;
playlistItem.SubtitleFormat = subtitleProfile.Format;
@@ -751,7 +737,14 @@ namespace MediaBrowser.Model.Dlna
return playlistItem;
}
- private TranscodingProfile GetVideoTranscodeProfile(MediaSourceInfo item, MediaOptions options, MediaStream videoStream, MediaStream audioStream, IEnumerable<MediaStream> candidateAudioStreams, MediaStream subtitleStream, StreamInfo playlistItem)
+ private TranscodingProfile? GetVideoTranscodeProfile(
+ MediaSourceInfo item,
+ MediaOptions options,
+ MediaStream? videoStream,
+ MediaStream? audioStream,
+ IEnumerable<MediaStream> candidateAudioStreams,
+ MediaStream? subtitleStream,
+ StreamInfo playlistItem)
{
if (!(item.SupportsTranscoding || item.SupportsDirectStream))
{
@@ -798,7 +791,16 @@ namespace MediaBrowser.Model.Dlna
return transcodingProfiles.FirstOrDefault();
}
- private void BuildStreamVideoItem(StreamInfo playlistItem, MediaOptions options, MediaSourceInfo item, MediaStream videoStream, MediaStream audioStream, IEnumerable<MediaStream> candidateAudioStreams, string container, string videoCodec, string audioCodec)
+ private void BuildStreamVideoItem(
+ StreamInfo playlistItem,
+ MediaOptions options,
+ MediaSourceInfo item,
+ MediaStream? videoStream,
+ MediaStream? audioStream,
+ IEnumerable<MediaStream> candidateAudioStreams,
+ string? container,
+ string? videoCodec,
+ string? audioCodec)
{
// Prefer matching video codecs
var videoCodecs = ContainerProfile.SplitValue(videoCodec);
@@ -886,12 +888,12 @@ namespace MediaBrowser.Model.Dlna
int? bitDepth = videoStream?.BitDepth;
int? videoBitrate = videoStream?.BitRate;
double? videoLevel = videoStream?.Level;
- string videoProfile = videoStream?.Profile;
- string videoRangeType = videoStream?.VideoRangeType;
+ string? videoProfile = videoStream?.Profile;
+ string? videoRangeType = videoStream?.VideoRangeType;
float videoFramerate = videoStream is null ? 0 : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate ?? 0;
bool? isAnamorphic = videoStream?.IsAnamorphic;
bool? isInterlaced = videoStream?.IsInterlaced;
- string videoCodecTag = videoStream?.CodecTag;
+ string? videoCodecTag = videoStream?.CodecTag;
bool? isAvc = videoStream?.IsAVC;
TransportStreamTimestamp? timestamp = videoStream is null ? TransportStreamTimestamp.None : item.Timestamp;
@@ -927,11 +929,11 @@ namespace MediaBrowser.Model.Dlna
playlistItem.AudioBitrate = Math.Min(playlistItem.AudioBitrate ?? audioBitrate, audioBitrate);
bool? isSecondaryAudio = audioStream is null ? null : item.IsSecondaryAudio(audioStream);
- int? inputAudioBitrate = audioStream is null ? null : audioStream.BitRate;
- int? audioChannels = audioStream is null ? null : audioStream.Channels;
- string audioProfile = audioStream is null ? null : audioStream.Profile;
- int? inputAudioSampleRate = audioStream is null ? null : audioStream.SampleRate;
- int? inputAudioBitDepth = audioStream is null ? null : audioStream.BitDepth;
+ int? inputAudioBitrate = audioStream?.BitRate;
+ int? audioChannels = audioStream?.Channels;
+ string? audioProfile = audioStream?.Profile;
+ int? inputAudioSampleRate = audioStream?.SampleRate;
+ int? inputAudioBitDepth = audioStream?.BitDepth;
var appliedAudioConditions = options.Profile.CodecProfiles
.Where(i => i.Type == CodecType.VideoAudio &&
@@ -979,7 +981,7 @@ namespace MediaBrowser.Model.Dlna
playlistItem?.TranscodeReasons);
}
- private static int GetDefaultAudioBitrate(string audioCodec, int? audioChannels)
+ private static int GetDefaultAudioBitrate(string? audioCodec, int? audioChannels)
{
if (!string.IsNullOrEmpty(audioCodec))
{
@@ -1012,9 +1014,9 @@ namespace MediaBrowser.Model.Dlna
return 192000;
}
- private static int GetAudioBitrate(long maxTotalBitrate, string[] targetAudioCodecs, MediaStream audioStream, StreamInfo item)
+ private static int GetAudioBitrate(long maxTotalBitrate, string[] targetAudioCodecs, MediaStream? audioStream, StreamInfo item)
{
- string targetAudioCodec = targetAudioCodecs.Length == 0 ? null : targetAudioCodecs[0];
+ string? targetAudioCodec = targetAudioCodecs.Length == 0 ? null : targetAudioCodecs[0];
int? targetAudioChannels = item.GetTargetAudioChannels(targetAudioCodec);
@@ -1105,13 +1107,13 @@ namespace MediaBrowser.Model.Dlna
return 7168000;
}
- private (DirectPlayProfile Profile, PlayMethod? PlayMethod, int? AudioStreamIndex, TranscodeReason TranscodeReasons) GetVideoDirectPlayProfile(
+ private (DirectPlayProfile? Profile, PlayMethod? PlayMethod, int? AudioStreamIndex, TranscodeReason TranscodeReasons) GetVideoDirectPlayProfile(
MediaOptions options,
MediaSourceInfo mediaSource,
- MediaStream videoStream,
- MediaStream audioStream,
+ MediaStream? videoStream,
+ MediaStream? audioStream,
ICollection<MediaStream> candidateAudioStreams,
- MediaStream subtitleStream,
+ MediaStream? subtitleStream,
bool isEligibleForDirectPlay,
bool isEligibleForDirectStream)
{
@@ -1134,12 +1136,12 @@ namespace MediaBrowser.Model.Dlna
int? bitDepth = videoStream?.BitDepth;
int? videoBitrate = videoStream?.BitRate;
double? videoLevel = videoStream?.Level;
- string videoProfile = videoStream?.Profile;
- string videoRangeType = videoStream?.VideoRangeType;
+ string? videoProfile = videoStream?.Profile;
+ string? videoRangeType = videoStream?.VideoRangeType;
float videoFramerate = videoStream is null ? 0 : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate ?? 0;
bool? isAnamorphic = videoStream?.IsAnamorphic;
bool? isInterlaced = videoStream?.IsInterlaced;
- string videoCodecTag = videoStream?.CodecTag;
+ string? videoCodecTag = videoStream?.CodecTag;
bool? isAvc = videoStream?.IsAVC;
TransportStreamTimestamp? timestamp = videoStream is null ? TransportStreamTimestamp.None : mediaSource.Timestamp;
@@ -1227,14 +1229,14 @@ namespace MediaBrowser.Model.Dlna
}
// Check video codec
- string videoCodec = videoStream?.Codec;
+ string? videoCodec = videoStream?.Codec;
if (!directPlayProfile.SupportsVideoCodec(videoCodec))
{
directPlayProfileReasons |= TranscodeReason.VideoCodecNotSupported;
}
// Check audio codec
- MediaStream selectedAudioStream = null;
+ MediaStream? selectedAudioStream = null;
if (candidateAudioStreams.Any())
{
selectedAudioStream = candidateAudioStreams.FirstOrDefault(audioStream => directPlayProfile.SupportsAudioCodec(audioStream.Codec));
@@ -1355,8 +1357,8 @@ namespace MediaBrowser.Model.Dlna
SubtitleProfile[] subtitleProfiles,
PlayMethod playMethod,
ITranscoderSupport transcoderSupport,
- string outputContainer,
- string transcodingSubProtocol)
+ string? outputContainer,
+ string? transcodingSubProtocol)
{
if (!subtitleStream.IsExternal && (playMethod != PlayMethod.Transcode || !string.Equals(transcodingSubProtocol, "hls", StringComparison.OrdinalIgnoreCase)))
{
@@ -1429,7 +1431,7 @@ namespace MediaBrowser.Model.Dlna
};
}
- private static bool IsSubtitleEmbedSupported(string transcodingContainer)
+ private static bool IsSubtitleEmbedSupported(string? transcodingContainer)
{
if (!string.IsNullOrEmpty(transcodingContainer))
{
@@ -1451,7 +1453,7 @@ namespace MediaBrowser.Model.Dlna
return false;
}
- private static SubtitleProfile GetExternalSubtitleProfile(MediaSourceInfo mediaSource, MediaStream subtitleStream, SubtitleProfile[] subtitleProfiles, PlayMethod playMethod, ITranscoderSupport transcoderSupport, bool allowConversion)
+ private static SubtitleProfile? GetExternalSubtitleProfile(MediaSourceInfo mediaSource, MediaStream subtitleStream, SubtitleProfile[] subtitleProfiles, PlayMethod playMethod, ITranscoderSupport transcoderSupport, bool allowConversion)
{
foreach (var profile in subtitleProfiles)
{
@@ -1584,7 +1586,7 @@ namespace MediaBrowser.Model.Dlna
private static IEnumerable<ProfileCondition> GetProfileConditionsForAudio(
IEnumerable<CodecProfile> codecProfiles,
string container,
- string codec,
+ string? codec,
int? audioChannels,
int? audioBitrate,
int? audioSampleRate,
@@ -1604,7 +1606,7 @@ namespace MediaBrowser.Model.Dlna
return conditions.Where(condition => !ConditionProcessor.IsAudioConditionSatisfied(condition, audioChannels, audioBitrate, audioSampleRate, audioBitDepth));
}
- 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)
{
@@ -2080,7 +2082,7 @@ namespace MediaBrowser.Model.Dlna
}
// Check audio codec
- string audioCodec = audioStream?.Codec;
+ string? audioCodec = audioStream?.Codec;
if (!profile.SupportsAudioCodec(audioCodec))
{
return false;
diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs
index 93ace43df..886b64a24 100644
--- a/MediaBrowser.Model/Dlna/StreamInfo.cs
+++ b/MediaBrowser.Model/Dlna/StreamInfo.cs
@@ -107,9 +107,8 @@ namespace MediaBrowser.Model.Dlna
public string MediaSourceId => MediaSource?.Id;
- public bool IsDirectStream =>
- PlayMethod == PlayMethod.DirectStream ||
- PlayMethod == PlayMethod.DirectPlay;
+ public bool IsDirectStream => MediaSource?.VideoType is not (VideoType.Dvd or VideoType.BluRay)
+ && PlayMethod is PlayMethod.DirectStream or PlayMethod.DirectPlay;
/// <summary>
/// Gets the audio stream that will be used.
diff --git a/MediaBrowser.Model/Globalization/ILocalizationManager.cs b/MediaBrowser.Model/Globalization/ILocalizationManager.cs
index e00157dce..02a29e7fa 100644
--- a/MediaBrowser.Model/Globalization/ILocalizationManager.cs
+++ b/MediaBrowser.Model/Globalization/ILocalizationManager.cs
@@ -30,8 +30,9 @@ namespace MediaBrowser.Model.Globalization
/// Gets the rating level.
/// </summary>
/// <param name="rating">The rating.</param>
+ /// <param name="countryCode">The optional two letter ISO language string.</param>
/// <returns><see cref="int" /> or <c>null</c>.</returns>
- int? GetRatingLevel(string rating);
+ int? GetRatingLevel(string rating, string? countryCode = null);
/// <summary>
/// Gets the localized string.
diff --git a/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs b/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs
new file mode 100644
index 000000000..d546ffccd
--- /dev/null
+++ b/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs
@@ -0,0 +1,41 @@
+#nullable disable
+
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Model.MediaInfo;
+
+/// <summary>
+/// Represents the result of BDInfo output.
+/// </summary>
+public class BlurayDiscInfo
+{
+ /// <summary>
+ /// Gets or sets the media streams.
+ /// </summary>
+ /// <value>The media streams.</value>
+ public MediaStream[] MediaStreams { get; set; }
+
+ /// <summary>
+ /// Gets or sets the run time ticks.
+ /// </summary>
+ /// <value>The run time ticks.</value>
+ public long? RunTimeTicks { get; set; }
+
+ /// <summary>
+ /// Gets or sets the files.
+ /// </summary>
+ /// <value>The files.</value>
+ public string[] Files { get; set; }
+
+ /// <summary>
+ /// Gets or sets the playlist name.
+ /// </summary>
+ /// <value>The playlist name.</value>
+ public string PlaylistName { get; set; }
+
+ /// <summary>
+ /// Gets or sets the chapters.
+ /// </summary>
+ /// <value>The chapters.</value>
+ public double[] Chapters { get; set; }
+}
diff --git a/MediaBrowser.Model/MediaInfo/IBlurayExaminer.cs b/MediaBrowser.Model/MediaInfo/IBlurayExaminer.cs
new file mode 100644
index 000000000..d39725301
--- /dev/null
+++ b/MediaBrowser.Model/MediaInfo/IBlurayExaminer.cs
@@ -0,0 +1,14 @@
+namespace MediaBrowser.Model.MediaInfo;
+
+/// <summary>
+/// Interface IBlurayExaminer.
+/// </summary>
+public interface IBlurayExaminer
+{
+ /// <summary>
+ /// Gets the disc info.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns>BlurayDiscInfo.</returns>
+ BlurayDiscInfo GetDiscInfo(string path);
+}