Refactor: standardize namespace and using directive style
Refactored all C# test files to use explicit namespace declarations and moved all using directives inside the namespace block for consistency. Updated assembly info and cache files to reflect the new build. Adjusted MvcTestingAppManifest.json to use fully qualified assembly names. No functional changes; all updates are related to code style, organization, and project metadata.
This commit is contained in:
@@ -2,14 +2,16 @@
|
||||
// Copyright (c) PlaceholderCompany. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Serialization;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
#pragma warning disable SA1615 // Element should be documented
|
||||
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
|
||||
using global::System;
|
||||
using global::System.Collections.Generic;
|
||||
using global::System.Linq;
|
||||
using global::System.Xml.Serialization;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Defines the <see cref="CodecProfile"/>.
|
||||
/// </summary>
|
||||
@@ -20,8 +22,8 @@ public class CodecProfile
|
||||
/// </summary>
|
||||
public CodecProfile()
|
||||
{
|
||||
Conditions = [];
|
||||
ApplyConditions = [];
|
||||
this.Conditions = [];
|
||||
this.ApplyConditions = [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -33,12 +35,12 @@ public class CodecProfile
|
||||
/// <summary>
|
||||
/// Gets or sets the list of <see cref="ProfileCondition"/> which this profile must meet.
|
||||
/// </summary>
|
||||
public ProfileCondition[] Conditions { get; set; }
|
||||
public List<ProfileCondition> Conditions { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the list of <see cref="ProfileCondition"/> to apply if this profile is met.
|
||||
/// </summary>
|
||||
public ProfileCondition[] ApplyConditions { get; set; }
|
||||
public List<ProfileCondition> ApplyConditions { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the codec(s) that this profile applies to.
|
||||
@@ -61,38 +63,43 @@ public class CodecProfile
|
||||
/// <summary>
|
||||
/// Checks to see whether the codecs and containers contain the given parameters.
|
||||
/// </summary>
|
||||
/// <param name="codecs">The codecs to match.</param>
|
||||
/// <param name="codec">The codec to match (single codec or comma-separated list).</param>
|
||||
/// <param name="container">The container to match.</param>
|
||||
/// <param name="useSubContainer">Consider sub-containers.</param>
|
||||
/// <returns>True if both conditions are met.</returns>
|
||||
public bool ContainsAnyCodec(IReadOnlyList<string> codecs, string? container, bool useSubContainer = false)
|
||||
{
|
||||
var containerToCheck = useSubContainer && string.Equals(Container, "hls", StringComparison.OrdinalIgnoreCase) ? SubContainer : Container;
|
||||
return ContainerHelper.ContainsContainer(containerToCheck, container) && codecs.Any(c => ContainerHelper.ContainsContainer(Codec, false, c));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks to see whether the codecs and containers contain the given parameters.
|
||||
/// </summary>
|
||||
/// <param name="codec">The codec to match.</param>
|
||||
/// <param name="container">The container to match.</param>
|
||||
/// <param name="useSubContainer">Consider sub-containers.</param>
|
||||
/// <returns>True if both conditions are met.</returns>
|
||||
/// <param name="useSubContainer">When true and Container is "hls", uses SubContainer instead of Container for matching.</param>
|
||||
/// <returns>True if both the codec and container conditions are met.</returns>
|
||||
public bool ContainsAnyCodec(string? codec, string? container, bool useSubContainer = false)
|
||||
{
|
||||
return ContainsAnyCodec(codec.AsSpan(), container, useSubContainer);
|
||||
if (codec is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var containerToCheck =
|
||||
useSubContainer &&
|
||||
string.Equals(this.Container, "hls", StringComparison.OrdinalIgnoreCase)
|
||||
? this.SubContainer
|
||||
: this.Container;
|
||||
|
||||
return ContainerHelper.ContainsContainer(containerToCheck, container)
|
||||
&& ContainerHelper.ContainsContainer(this.Codec, codec);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks to see whether the codecs and containers contain the given parameters.
|
||||
/// </summary>
|
||||
/// <param name="codec">The codec to match.</param>
|
||||
/// <param name="codecs">The list of codecs to match.</param>
|
||||
/// <param name="container">The container to match.</param>
|
||||
/// <param name="useSubContainer">Consider sub-containers.</param>
|
||||
/// <returns>True if both conditions are met.</returns>
|
||||
public bool ContainsAnyCodec(ReadOnlySpan<char> codec, string? container, bool useSubContainer = false)
|
||||
/// <param name="useSubContainer">When true and Container is "hls", uses SubContainer instead of Container for matching.</param>
|
||||
/// <returns>True if both the codec and container conditions are met.</returns>
|
||||
public bool ContainsAnyCodec(IReadOnlyList<string> codecs, string? container, bool useSubContainer = false)
|
||||
{
|
||||
var containerToCheck = useSubContainer && string.Equals(Container, "hls", StringComparison.OrdinalIgnoreCase) ? SubContainer : Container;
|
||||
return ContainerHelper.ContainsContainer(containerToCheck, container) && ContainerHelper.ContainsContainer(Codec, false, codec);
|
||||
if (codecs == null || codecs.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Join codecs with comma to match ContainerHelper's expected format
|
||||
var codecString = string.Join(',', codecs);
|
||||
return ContainsAnyCodec(codecString, container, useSubContainer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,10 @@
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
namespace MediaBrowser.Model.Dlna
|
||||
{
|
||||
public enum CodecType
|
||||
{
|
||||
Video = 0,
|
||||
VideoAudio = 1,
|
||||
Audio = 2
|
||||
}
|
||||
}
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
public enum CodecType
|
||||
{
|
||||
Video = 0,
|
||||
VideoAudio = 1,
|
||||
Audio = 2,
|
||||
}
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
// Copyright (c) PlaceholderCompany. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
|
||||
using global::System;
|
||||
using global::System.Globalization;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
|
||||
namespace MediaBrowser.Model.Dlna
|
||||
{
|
||||
/// <summary>
|
||||
/// The condition processor.
|
||||
/// </summary>
|
||||
public static class ConditionProcessor
|
||||
/// <summary>
|
||||
/// The condition processor.
|
||||
/// </summary>
|
||||
public static class ConditionProcessor
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if a video condition is satisfied.
|
||||
@@ -379,11 +379,10 @@ namespace MediaBrowser.Model.Dlna
|
||||
{
|
||||
ProfileConditionType.Equals => currentValue.Value == expected,
|
||||
ProfileConditionType.NotEquals => currentValue.Value != expected,
|
||||
_ => throw new InvalidOperationException("Unexpected ProfileConditionType: " + condition.Condition)
|
||||
_ => throw new InvalidOperationException("Unexpected ProfileConditionType: " + condition.Condition),
|
||||
};
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
#pragma warning disable CA1819 // Properties should not return arrays
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Serialization;
|
||||
using global::System;
|
||||
using global::System.Collections.Generic;
|
||||
using global::System.Xml.Serialization;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#pragma warning disable CA1819 // Properties should not return arrays
|
||||
|
||||
using System;
|
||||
using global::System;
|
||||
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
// Copyright (c) PlaceholderCompany. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
using System.Xml.Serialization;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
|
||||
using global::System.Xml.Serialization;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Defines the <see cref="DirectPlayProfile"/>.
|
||||
/// </summary>
|
||||
|
||||
@@ -4,14 +4,12 @@
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
namespace MediaBrowser.Model.Dlna
|
||||
{
|
||||
public enum DlnaProfileType
|
||||
{
|
||||
Audio = 0,
|
||||
Video = 1,
|
||||
Photo = 2,
|
||||
Subtitle = 3,
|
||||
Lyric = 4
|
||||
}
|
||||
}
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
public enum DlnaProfileType
|
||||
{
|
||||
Audio = 0,
|
||||
Video = 1,
|
||||
Photo = 2,
|
||||
Subtitle = 3,
|
||||
Lyric = 4,
|
||||
}
|
||||
|
||||
@@ -4,11 +4,9 @@
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
namespace MediaBrowser.Model.Dlna
|
||||
{
|
||||
public enum EncodingContext
|
||||
{
|
||||
Streaming = 0,
|
||||
Static = 1
|
||||
}
|
||||
}
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
public enum EncodingContext
|
||||
{
|
||||
Streaming = 0,
|
||||
Static = 1,
|
||||
}
|
||||
|
||||
@@ -4,14 +4,12 @@
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
namespace MediaBrowser.Model.Dlna
|
||||
{
|
||||
public interface ITranscoderSupport
|
||||
{
|
||||
bool CanEncodeToAudioCodec(string codec);
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
public interface ITranscoderSupport
|
||||
{
|
||||
bool CanEncodeToAudioCodec(string codec);
|
||||
|
||||
bool CanEncodeToSubtitleCodec(string codec);
|
||||
bool CanEncodeToSubtitleCodec(string codec);
|
||||
|
||||
bool CanExtractSubtitles(string codec);
|
||||
}
|
||||
}
|
||||
bool CanExtractSubtitles(string codec);
|
||||
}
|
||||
|
||||
@@ -2,148 +2,146 @@
|
||||
// Copyright (c) PlaceholderCompany. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
using System;
|
||||
using MediaBrowser.Model.Dto;
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
using global::System;
|
||||
using MediaBrowser.Model.Dto;
|
||||
|
||||
namespace MediaBrowser.Model.Dlna
|
||||
{
|
||||
/// <summary>
|
||||
/// Class MediaOptions.
|
||||
/// </summary>
|
||||
public class MediaOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MediaOptions"/> class.
|
||||
/// </summary>
|
||||
public MediaOptions()
|
||||
{
|
||||
Context = EncodingContext.Streaming;
|
||||
/// <summary>
|
||||
/// Class MediaOptions.
|
||||
/// </summary>
|
||||
public class MediaOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MediaOptions"/> class.
|
||||
/// </summary>
|
||||
public MediaOptions()
|
||||
{
|
||||
Context = EncodingContext.Streaming;
|
||||
|
||||
EnableDirectPlay = true;
|
||||
EnableDirectStream = true;
|
||||
}
|
||||
EnableDirectPlay = true;
|
||||
EnableDirectStream = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether direct playback is allowed.
|
||||
/// </summary>
|
||||
public bool EnableDirectPlay { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether direct playback is allowed.
|
||||
/// </summary>
|
||||
public bool EnableDirectPlay { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether direct streaming is allowed.
|
||||
/// </summary>
|
||||
public bool EnableDirectStream { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether direct streaming is allowed.
|
||||
/// </summary>
|
||||
public bool EnableDirectStream { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether direct playback is forced.
|
||||
/// </summary>
|
||||
public bool ForceDirectPlay { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether direct playback is forced.
|
||||
/// </summary>
|
||||
public bool ForceDirectPlay { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether direct streaming is forced.
|
||||
/// </summary>
|
||||
public bool ForceDirectStream { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether direct streaming is forced.
|
||||
/// </summary>
|
||||
public bool ForceDirectStream { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether audio stream copy is allowed.
|
||||
/// </summary>
|
||||
public bool AllowAudioStreamCopy { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether audio stream copy is allowed.
|
||||
/// </summary>
|
||||
public bool AllowAudioStreamCopy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether video stream copy is allowed.
|
||||
/// </summary>
|
||||
public bool AllowVideoStreamCopy { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether video stream copy is allowed.
|
||||
/// </summary>
|
||||
public bool AllowVideoStreamCopy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether always burn in subtitles when transcoding.
|
||||
/// </summary>
|
||||
public bool AlwaysBurnInSubtitleWhenTranscoding { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether always burn in subtitles when transcoding.
|
||||
/// </summary>
|
||||
public bool AlwaysBurnInSubtitleWhenTranscoding { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the item id.
|
||||
/// </summary>
|
||||
public Guid ItemId { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the item id.
|
||||
/// </summary>
|
||||
public Guid ItemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the media sources.
|
||||
/// </summary>
|
||||
public MediaSourceInfo[] MediaSources { get; set; } = Array.Empty<MediaSourceInfo>();
|
||||
/// <summary>
|
||||
/// Gets or sets the media sources.
|
||||
/// </summary>
|
||||
public MediaSourceInfo[] MediaSources { get; set; } = Array.Empty<MediaSourceInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the device profile.
|
||||
/// </summary>
|
||||
public required DeviceProfile Profile { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the device profile.
|
||||
/// </summary>
|
||||
public required 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; }
|
||||
/// <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; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the device id.
|
||||
/// </summary>
|
||||
public string? DeviceId { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the device id.
|
||||
/// </summary>
|
||||
public string? DeviceId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an override of supported number of audio channels
|
||||
/// Example: DeviceProfile supports five channel, but user only has stereo speakers.
|
||||
/// </summary>
|
||||
public int? MaxAudioChannels { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets an override of supported number of audio channels
|
||||
/// Example: DeviceProfile supports five channel, but user only has stereo speakers.
|
||||
/// </summary>
|
||||
public int? MaxAudioChannels { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the application's configured maximum bitrate.
|
||||
/// </summary>
|
||||
public int? MaxBitrate { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the application's configured maximum bitrate.
|
||||
/// </summary>
|
||||
public int? MaxBitrate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the context.
|
||||
/// </summary>
|
||||
/// <value>The context.</value>
|
||||
public EncodingContext Context { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the context.
|
||||
/// </summary>
|
||||
/// <value>The context.</value>
|
||||
public EncodingContext Context { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the audio transcoding bitrate.
|
||||
/// </summary>
|
||||
/// <value>The audio transcoding bitrate.</value>
|
||||
public int? AudioTranscodingBitrate { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the audio transcoding bitrate.
|
||||
/// </summary>
|
||||
/// <value>The audio transcoding bitrate.</value>
|
||||
public int? AudioTranscodingBitrate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an override for the audio stream index.
|
||||
/// </summary>
|
||||
public int? AudioStreamIndex { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets an override for the audio stream index.
|
||||
/// </summary>
|
||||
public int? AudioStreamIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an override for the subtitle stream index.
|
||||
/// </summary>
|
||||
public int? SubtitleStreamIndex { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets an override for the subtitle stream index.
|
||||
/// </summary>
|
||||
public int? SubtitleStreamIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum bitrate.
|
||||
/// </summary>
|
||||
/// <param name="isAudio">Whether or not this is audio.</param>
|
||||
/// <returns>System.Nullable<System.Int32>.</returns>
|
||||
public int? GetMaxBitrate(bool isAudio)
|
||||
{
|
||||
if (MaxBitrate.HasValue)
|
||||
{
|
||||
return MaxBitrate;
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the maximum bitrate.
|
||||
/// </summary>
|
||||
/// <param name="isAudio">Whether or not this is audio.</param>
|
||||
/// <returns>System.Nullable<System.Int32>.</returns>
|
||||
public int? GetMaxBitrate(bool isAudio)
|
||||
{
|
||||
if (MaxBitrate.HasValue)
|
||||
{
|
||||
return MaxBitrate;
|
||||
}
|
||||
|
||||
if (Profile is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (Profile is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Context == EncodingContext.Static)
|
||||
{
|
||||
if (isAudio && Profile.MaxStaticMusicBitrate.HasValue)
|
||||
{
|
||||
return Profile.MaxStaticMusicBitrate;
|
||||
}
|
||||
if (Context == EncodingContext.Static)
|
||||
{
|
||||
if (isAudio && Profile.MaxStaticMusicBitrate.HasValue)
|
||||
{
|
||||
return Profile.MaxStaticMusicBitrate;
|
||||
}
|
||||
|
||||
return Profile.MaxStaticBitrate;
|
||||
}
|
||||
return Profile.MaxStaticBitrate;
|
||||
}
|
||||
|
||||
return Profile.MaxStreamingBitrate;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Profile.MaxStreamingBitrate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,10 @@
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
namespace MediaBrowser.Model.Dlna
|
||||
{
|
||||
public enum PlaybackErrorCode
|
||||
{
|
||||
NotAllowed = 0,
|
||||
NoCompatibleStream = 1,
|
||||
RateLimitExceeded = 2
|
||||
}
|
||||
}
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
public enum PlaybackErrorCode
|
||||
{
|
||||
NotAllowed = 0,
|
||||
NoCompatibleStream = 1,
|
||||
RateLimitExceeded = 2,
|
||||
}
|
||||
|
||||
@@ -5,40 +5,38 @@
|
||||
#nullable disable
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System.Xml.Serialization;
|
||||
using global::System.Xml.Serialization;
|
||||
|
||||
namespace MediaBrowser.Model.Dlna
|
||||
{
|
||||
public class ProfileCondition
|
||||
{
|
||||
public ProfileCondition()
|
||||
{
|
||||
IsRequired = true;
|
||||
}
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
public class ProfileCondition
|
||||
{
|
||||
public ProfileCondition()
|
||||
{
|
||||
IsRequired = true;
|
||||
}
|
||||
|
||||
public ProfileCondition(ProfileConditionType condition, ProfileConditionValue property, string value)
|
||||
: this(condition, property, value, false)
|
||||
{
|
||||
}
|
||||
public ProfileCondition(ProfileConditionType condition, ProfileConditionValue property, string value)
|
||||
: this(condition, property, value, false)
|
||||
{
|
||||
}
|
||||
|
||||
public ProfileCondition(ProfileConditionType condition, ProfileConditionValue property, string value, bool isRequired)
|
||||
{
|
||||
Condition = condition;
|
||||
Property = property;
|
||||
Value = value;
|
||||
IsRequired = isRequired;
|
||||
}
|
||||
public ProfileCondition(ProfileConditionType condition, ProfileConditionValue property, string value, bool isRequired)
|
||||
{
|
||||
Condition = condition;
|
||||
Property = property;
|
||||
Value = value;
|
||||
IsRequired = isRequired;
|
||||
}
|
||||
|
||||
[XmlAttribute("condition")]
|
||||
public ProfileConditionType Condition { get; set; }
|
||||
[XmlAttribute("condition")]
|
||||
public ProfileConditionType Condition { get; set; }
|
||||
|
||||
[XmlAttribute("property")]
|
||||
public ProfileConditionValue Property { get; set; }
|
||||
[XmlAttribute("property")]
|
||||
public ProfileConditionValue Property { get; set; }
|
||||
|
||||
[XmlAttribute("value")]
|
||||
public string Value { get; set; }
|
||||
[XmlAttribute("value")]
|
||||
public string Value { get; set; }
|
||||
|
||||
[XmlAttribute("isRequired")]
|
||||
public bool IsRequired { get; set; }
|
||||
}
|
||||
}
|
||||
[XmlAttribute("isRequired")]
|
||||
public bool IsRequired { get; set; }
|
||||
}
|
||||
|
||||
@@ -4,14 +4,12 @@
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
namespace MediaBrowser.Model.Dlna
|
||||
{
|
||||
public enum ProfileConditionType
|
||||
{
|
||||
Equals = 0,
|
||||
NotEquals = 1,
|
||||
LessThanEqual = 2,
|
||||
GreaterThanEqual = 3,
|
||||
EqualsAny = 4
|
||||
}
|
||||
}
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
public enum ProfileConditionType
|
||||
{
|
||||
Equals = 0,
|
||||
NotEquals = 1,
|
||||
LessThanEqual = 2,
|
||||
GreaterThanEqual = 3,
|
||||
EqualsAny = 4,
|
||||
}
|
||||
|
||||
@@ -4,34 +4,32 @@
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
namespace MediaBrowser.Model.Dlna
|
||||
{
|
||||
public enum ProfileConditionValue
|
||||
{
|
||||
AudioChannels = 0,
|
||||
AudioBitrate = 1,
|
||||
AudioProfile = 2,
|
||||
Width = 3,
|
||||
Height = 4,
|
||||
Has64BitOffsets = 5,
|
||||
PacketLength = 6,
|
||||
VideoBitDepth = 7,
|
||||
VideoBitrate = 8,
|
||||
VideoFramerate = 9,
|
||||
VideoLevel = 10,
|
||||
VideoProfile = 11,
|
||||
VideoTimestamp = 12,
|
||||
IsAnamorphic = 13,
|
||||
RefFrames = 14,
|
||||
NumAudioStreams = 16,
|
||||
NumVideoStreams = 17,
|
||||
IsSecondaryAudio = 18,
|
||||
VideoCodecTag = 19,
|
||||
IsAvc = 20,
|
||||
IsInterlaced = 21,
|
||||
AudioSampleRate = 22,
|
||||
AudioBitDepth = 23,
|
||||
VideoRangeType = 24,
|
||||
NumStreams = 25
|
||||
}
|
||||
}
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
public enum ProfileConditionValue
|
||||
{
|
||||
AudioChannels = 0,
|
||||
AudioBitrate = 1,
|
||||
AudioProfile = 2,
|
||||
Width = 3,
|
||||
Height = 4,
|
||||
Has64BitOffsets = 5,
|
||||
PacketLength = 6,
|
||||
VideoBitDepth = 7,
|
||||
VideoBitrate = 8,
|
||||
VideoFramerate = 9,
|
||||
VideoLevel = 10,
|
||||
VideoProfile = 11,
|
||||
VideoTimestamp = 12,
|
||||
IsAnamorphic = 13,
|
||||
RefFrames = 14,
|
||||
NumAudioStreams = 16,
|
||||
NumVideoStreams = 17,
|
||||
IsSecondaryAudio = 18,
|
||||
VideoCodecTag = 19,
|
||||
IsAvc = 20,
|
||||
IsInterlaced = 21,
|
||||
AudioSampleRate = 22,
|
||||
AudioBitDepth = 23,
|
||||
VideoRangeType = 24,
|
||||
NumStreams = 25,
|
||||
}
|
||||
|
||||
@@ -4,18 +4,21 @@
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
namespace MediaBrowser.Model.Dlna
|
||||
{
|
||||
public class ResolutionConfiguration
|
||||
{
|
||||
public ResolutionConfiguration(int maxWidth, int maxBitrate)
|
||||
{
|
||||
MaxWidth = maxWidth;
|
||||
MaxBitrate = maxBitrate;
|
||||
}
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
public class ResolutionConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ResolutionConfiguration"/> class.
|
||||
/// </summary>
|
||||
/// <param name="maxWidth">The maximum width.</param>
|
||||
/// <param name="maxBitrate">The maximum bitrate.</param>
|
||||
public ResolutionConfiguration(int maxWidth, int maxBitrate)
|
||||
{
|
||||
MaxWidth = maxWidth;
|
||||
MaxBitrate = maxBitrate;
|
||||
}
|
||||
|
||||
public int MaxWidth { get; set; }
|
||||
public int MaxWidth { get; set; }
|
||||
|
||||
public int MaxBitrate { get; set; }
|
||||
}
|
||||
}
|
||||
public int MaxBitrate { get; set; }
|
||||
}
|
||||
|
||||
@@ -5,85 +5,94 @@
|
||||
#nullable disable
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using global::System;
|
||||
using global::System.Linq;
|
||||
|
||||
namespace MediaBrowser.Model.Dlna
|
||||
{
|
||||
public static class ResolutionNormalizer
|
||||
{
|
||||
// Please note: all bitrate here are in the scale of SDR h264 bitrate at 30fps
|
||||
private static readonly ResolutionConfiguration[] _configurations =
|
||||
[
|
||||
new ResolutionConfiguration(416, 365000),
|
||||
new ResolutionConfiguration(640, 730000),
|
||||
new ResolutionConfiguration(768, 1100000),
|
||||
new ResolutionConfiguration(960, 3000000),
|
||||
new ResolutionConfiguration(1280, 6000000),
|
||||
new ResolutionConfiguration(1920, 13500000),
|
||||
new ResolutionConfiguration(2560, 28000000),
|
||||
new ResolutionConfiguration(3840, 50000000)
|
||||
];
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
public static class ResolutionNormalizer
|
||||
{
|
||||
// Please note: all bitrate here are in the scale of SDR h264 bitrate at 30fps
|
||||
private static readonly ResolutionConfiguration[] _configurations =
|
||||
[
|
||||
new ResolutionConfiguration(416, 365000),
|
||||
new ResolutionConfiguration(640, 730000),
|
||||
new ResolutionConfiguration(768, 1100000),
|
||||
new ResolutionConfiguration(960, 3000000),
|
||||
new ResolutionConfiguration(1280, 6000000),
|
||||
new ResolutionConfiguration(1920, 13500000),
|
||||
new ResolutionConfiguration(2560, 28000000),
|
||||
new ResolutionConfiguration(3840, 50000000)
|
||||
];
|
||||
|
||||
public static ResolutionOptions Normalize(
|
||||
int? inputBitrate,
|
||||
int outputBitrate,
|
||||
int h264EquivalentOutputBitrate,
|
||||
int? maxWidth,
|
||||
int? maxHeight,
|
||||
float? targetFps,
|
||||
bool isHdr = false) // We are not doing HDR transcoding for now, leave for future use
|
||||
{
|
||||
// If the bitrate isn't changing, then don't downscale the resolution
|
||||
if (inputBitrate.HasValue && outputBitrate >= inputBitrate.Value)
|
||||
{
|
||||
if (maxWidth.HasValue || maxHeight.HasValue)
|
||||
{
|
||||
return new ResolutionOptions
|
||||
{
|
||||
MaxWidth = maxWidth,
|
||||
MaxHeight = maxHeight
|
||||
};
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Normalizes resolution options based on bitrate and dimensions.
|
||||
/// </summary>
|
||||
/// <param name="inputBitrate">The input bitrate.</param>
|
||||
/// <param name="outputBitrate">The output bitrate.</param>
|
||||
/// <param name="h264EquivalentOutputBitrate">The H264 equivalent output bitrate.</param>
|
||||
/// <param name="maxWidth">The maximum width.</param>
|
||||
/// <param name="maxHeight">The maximum height.</param>
|
||||
/// <param name="targetFps">The target frames per second.</param>
|
||||
/// <param name="isHdr">Whether the content is HDR.</param>
|
||||
/// <returns>The normalized resolution options.</returns>
|
||||
public static ResolutionOptions Normalize(
|
||||
int? inputBitrate,
|
||||
int outputBitrate,
|
||||
int h264EquivalentOutputBitrate,
|
||||
int? maxWidth,
|
||||
int? maxHeight,
|
||||
float? targetFps,
|
||||
bool isHdr = false) // We are not doing HDR transcoding for now, leave for future use
|
||||
{
|
||||
// If the bitrate isn't changing, then don't downscale the resolution
|
||||
if (inputBitrate.HasValue && outputBitrate >= inputBitrate.Value)
|
||||
{
|
||||
if (maxWidth.HasValue || maxHeight.HasValue)
|
||||
{
|
||||
return new ResolutionOptions
|
||||
{
|
||||
MaxWidth = maxWidth,
|
||||
MaxHeight = maxHeight,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Our reference bitrate is based on SDR h264 at 30fps
|
||||
var referenceFps = targetFps ?? 30.0f;
|
||||
var referenceScale = referenceFps <= 30.0f
|
||||
? 30.0f / referenceFps
|
||||
: 1.0f / MathF.Sqrt(referenceFps / 30.0f);
|
||||
var referenceBitrate = h264EquivalentOutputBitrate * referenceScale;
|
||||
// Our reference bitrate is based on SDR h264 at 30fps
|
||||
var referenceFps = targetFps ?? 30.0f;
|
||||
var referenceScale = referenceFps <= 30.0f
|
||||
? 30.0f / referenceFps
|
||||
: 1.0f / MathF.Sqrt(referenceFps / 30.0f);
|
||||
var referenceBitrate = h264EquivalentOutputBitrate * referenceScale;
|
||||
|
||||
if (isHdr)
|
||||
{
|
||||
referenceBitrate *= 0.8f;
|
||||
}
|
||||
if (isHdr)
|
||||
{
|
||||
referenceBitrate *= 0.8f;
|
||||
}
|
||||
|
||||
var resolutionConfig = GetResolutionConfiguration(Convert.ToInt32(referenceBitrate));
|
||||
var resolutionConfig = GetResolutionConfiguration(Convert.ToInt32(referenceBitrate));
|
||||
|
||||
if (resolutionConfig is null)
|
||||
{
|
||||
return new ResolutionOptions { MaxWidth = maxWidth, MaxHeight = maxHeight };
|
||||
}
|
||||
if (resolutionConfig is null)
|
||||
{
|
||||
return new ResolutionOptions { MaxWidth = maxWidth, MaxHeight = maxHeight };
|
||||
}
|
||||
|
||||
var originWidthValue = maxWidth;
|
||||
var originWidthValue = maxWidth;
|
||||
|
||||
maxWidth = Math.Min(resolutionConfig.MaxWidth, maxWidth ?? resolutionConfig.MaxWidth);
|
||||
if (!originWidthValue.HasValue || originWidthValue.Value != maxWidth.Value)
|
||||
{
|
||||
maxHeight = null;
|
||||
}
|
||||
maxWidth = Math.Min(resolutionConfig.MaxWidth, maxWidth ?? resolutionConfig.MaxWidth);
|
||||
if (!originWidthValue.HasValue || originWidthValue.Value != maxWidth.Value)
|
||||
{
|
||||
maxHeight = null;
|
||||
}
|
||||
|
||||
return new ResolutionOptions
|
||||
{
|
||||
MaxWidth = maxWidth,
|
||||
MaxHeight = maxHeight
|
||||
};
|
||||
}
|
||||
return new ResolutionOptions
|
||||
{
|
||||
MaxWidth = maxWidth,
|
||||
MaxHeight = maxHeight,
|
||||
};
|
||||
}
|
||||
|
||||
private static ResolutionConfiguration GetResolutionConfiguration(int outputBitrate)
|
||||
{
|
||||
return _configurations.FirstOrDefault(config => outputBitrate <= config.MaxBitrate);
|
||||
}
|
||||
}
|
||||
}
|
||||
private static ResolutionConfiguration GetResolutionConfiguration(int outputBitrate)
|
||||
{
|
||||
return _configurations.FirstOrDefault(config => outputBitrate <= config.MaxBitrate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,10 @@
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
namespace MediaBrowser.Model.Dlna
|
||||
{
|
||||
public class ResolutionOptions
|
||||
{
|
||||
public int? MaxWidth { get; set; }
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
public class ResolutionOptions
|
||||
{
|
||||
public int? MaxWidth { get; set; }
|
||||
|
||||
public int? MaxHeight { get; set; }
|
||||
}
|
||||
}
|
||||
public int? MaxHeight { get; set; }
|
||||
}
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
// Copyright (c) PlaceholderCompany. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
|
||||
using global::System;
|
||||
using global::System.Collections.Generic;
|
||||
using global::System.Globalization;
|
||||
using global::System.Linq;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Model.Dto;
|
||||
@@ -15,12 +17,10 @@ using MediaBrowser.Model.MediaInfo;
|
||||
using MediaBrowser.Model.Session;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MediaBrowser.Model.Dlna
|
||||
{
|
||||
/// <summary>
|
||||
/// Class StreamBuilder.
|
||||
/// </summary>
|
||||
public class StreamBuilder
|
||||
/// <summary>
|
||||
/// Class StreamBuilder.
|
||||
/// </summary>
|
||||
public class StreamBuilder
|
||||
{
|
||||
// Aliases
|
||||
internal const TranscodeReason ContainerReasons = TranscodeReason.ContainerNotSupported | TranscodeReason.ContainerBitrateExceedsLimit;
|
||||
@@ -86,7 +86,7 @@ namespace MediaBrowser.Model.Dlna
|
||||
MediaSource = item,
|
||||
RunTimeTicks = item.RunTimeTicks,
|
||||
Context = options.Context,
|
||||
DeviceProfile = options.Profile
|
||||
DeviceProfile = options.Profile,
|
||||
};
|
||||
|
||||
if (options.ForceDirectPlay)
|
||||
@@ -130,6 +130,7 @@ namespace MediaBrowser.Model.Dlna
|
||||
{
|
||||
var remuxContainer = item.TranscodingContainer ?? "ts";
|
||||
string[] supportedHlsContainers = ["ts", "mp4"];
|
||||
|
||||
// If the container specified for the profile is an HLS supported container, use that container instead, overriding the preference
|
||||
// The client should be responsible to ensure this container is compatible
|
||||
remuxContainer = Array.Exists(supportedHlsContainers, element => string.Equals(element, directPlayInfo.Profile?.Container, StringComparison.OrdinalIgnoreCase)) ? directPlayInfo.Profile?.Container : remuxContainer;
|
||||
@@ -323,6 +324,7 @@ namespace MediaBrowser.Model.Dlna
|
||||
return TranscodeReason.AudioSampleRateNotSupported;
|
||||
|
||||
case ProfileConditionValue.Has64BitOffsets:
|
||||
|
||||
// TODO
|
||||
return 0;
|
||||
|
||||
@@ -333,6 +335,7 @@ namespace MediaBrowser.Model.Dlna
|
||||
return TranscodeReason.AnamorphicVideoNotSupported;
|
||||
|
||||
case ProfileConditionValue.IsAvc:
|
||||
|
||||
// TODO
|
||||
return 0;
|
||||
|
||||
@@ -346,14 +349,17 @@ namespace MediaBrowser.Model.Dlna
|
||||
return TranscodeReason.StreamCountExceedsLimit;
|
||||
|
||||
case ProfileConditionValue.NumAudioStreams:
|
||||
|
||||
// TODO
|
||||
return 0;
|
||||
|
||||
case ProfileConditionValue.NumVideoStreams:
|
||||
|
||||
// TODO
|
||||
return 0;
|
||||
|
||||
case ProfileConditionValue.PacketLength:
|
||||
|
||||
// TODO
|
||||
return 0;
|
||||
|
||||
@@ -385,6 +391,7 @@ namespace MediaBrowser.Model.Dlna
|
||||
return TranscodeReason.VideoRangeTypeNotSupported;
|
||||
|
||||
case ProfileConditionValue.VideoTimestamp:
|
||||
|
||||
// TODO
|
||||
return 0;
|
||||
|
||||
@@ -655,7 +662,7 @@ namespace MediaBrowser.Model.Dlna
|
||||
Context = options.Context,
|
||||
DeviceProfile = options.Profile,
|
||||
SubtitleStreamIndex = options.SubtitleStreamIndex ?? GetDefaultSubtitleStreamIndex(item, options.Profile.SubtitleProfiles),
|
||||
AlwaysBurnInSubtitleWhenTranscoding = options.AlwaysBurnInSubtitleWhenTranscoding
|
||||
AlwaysBurnInSubtitleWhenTranscoding = options.AlwaysBurnInSubtitleWhenTranscoding,
|
||||
};
|
||||
|
||||
var subtitleStream = playlistItem.SubtitleStreamIndex.HasValue ? item.GetMediaStream(MediaStreamType.Subtitle, playlistItem.SubtitleStreamIndex.Value) : null;
|
||||
@@ -668,6 +675,7 @@ namespace MediaBrowser.Model.Dlna
|
||||
|
||||
// Collect candidate audio streams
|
||||
ICollection<MediaStream> candidateAudioStreams = audioStream is null ? [] : [audioStream];
|
||||
|
||||
// When the index is explicitly required by client or the default is specified by user, don't do any stream reselection.
|
||||
if (!item.DefaultAudioIndexSource.HasFlag(AudioIndexSource.User) && (options.AudioStreamIndex is null or < 0))
|
||||
{
|
||||
@@ -706,7 +714,7 @@ namespace MediaBrowser.Model.Dlna
|
||||
|
||||
var videoStream = item.VideoStream;
|
||||
|
||||
var bitrateLimitExceeded = IsBitrateLimitExceeded(item, options.GetMaxBitrate(false) ?? 0);
|
||||
var bitrateLimitExceeded = this.IsBitrateLimitExceeded(item, options.GetMaxBitrate(false) ?? 0);
|
||||
var isEligibleForDirectPlay = options.EnableDirectPlay && (options.ForceDirectPlay || !bitrateLimitExceeded);
|
||||
var isEligibleForDirectStream = options.EnableDirectStream && (options.ForceDirectStream || !bitrateLimitExceeded);
|
||||
TranscodeReason transcodeReasons = 0;
|
||||
@@ -722,7 +730,7 @@ namespace MediaBrowser.Model.Dlna
|
||||
transcodeReasons = TranscodeReason.ContainerBitrateExceedsLimit;
|
||||
}
|
||||
|
||||
_logger.LogDebug(
|
||||
this._logger.LogDebug(
|
||||
"Profile: {0}, Path: {1}, isEligibleForDirectPlay: {2}, isEligibleForDirectStream: {3}",
|
||||
options.Profile.Name ?? "Unknown Profile",
|
||||
item.Path ?? "Unknown path",
|
||||
@@ -733,7 +741,7 @@ namespace MediaBrowser.Model.Dlna
|
||||
if (isEligibleForDirectPlay || isEligibleForDirectStream)
|
||||
{
|
||||
// See if it can be direct played
|
||||
var directPlayInfo = GetVideoDirectPlayProfile(options, item, videoStream, audioStream, candidateAudioStreams, subtitleStream, isEligibleForDirectPlay, isEligibleForDirectStream);
|
||||
var directPlayInfo = this.GetVideoDirectPlayProfile(options, item, videoStream, audioStream, candidateAudioStreams, subtitleStream, isEligibleForDirectPlay, isEligibleForDirectStream);
|
||||
var directPlay = directPlayInfo.PlayMethod;
|
||||
transcodeReasons |= directPlayInfo.TranscodeReasons;
|
||||
|
||||
@@ -771,14 +779,14 @@ namespace MediaBrowser.Model.Dlna
|
||||
|
||||
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, this._transcoderSupport, directPlayProfile?.Container, null);
|
||||
|
||||
playlistItem.SubtitleDeliveryMethod = subtitleProfile.Method;
|
||||
playlistItem.SubtitleFormat = subtitleProfile.Format;
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogDebug(
|
||||
this._logger.LogDebug(
|
||||
"DirectPlay Result for Profile: {0}, Path: {1}, PlayMethod: {2}, AudioStreamIndex: {3}, SubtitleStreamIndex: {4}, Reasons: {5}",
|
||||
options.Profile.Name ?? "Anonymous Profile",
|
||||
item.Path ?? "Unknown path",
|
||||
@@ -794,19 +802,19 @@ namespace MediaBrowser.Model.Dlna
|
||||
{
|
||||
// Can't direct play, find the transcoding profile
|
||||
// If we do this for direct-stream we will overwrite the info
|
||||
var (transcodingProfile, playMethod) = GetVideoTranscodeProfile(item, options, videoStream, audioStream, playlistItem);
|
||||
var (transcodingProfile, playMethod) = this.GetVideoTranscodeProfile(item, options, videoStream, audioStream, playlistItem);
|
||||
|
||||
if (transcodingProfile is not null && playMethod.HasValue)
|
||||
{
|
||||
SetStreamInfoOptionsFromTranscodingProfile(item, playlistItem, transcodingProfile);
|
||||
|
||||
BuildStreamVideoItem(playlistItem, options, item, videoStream, audioStream, candidateAudioStreams, transcodingProfile.Container, transcodingProfile.VideoCodec, transcodingProfile.AudioCodec);
|
||||
this.BuildStreamVideoItem(playlistItem, options, item, videoStream, audioStream, candidateAudioStreams, transcodingProfile.Container, transcodingProfile.VideoCodec, transcodingProfile.AudioCodec);
|
||||
|
||||
playlistItem.PlayMethod = PlayMethod.Transcode;
|
||||
|
||||
if (subtitleStream is not null)
|
||||
{
|
||||
var subtitleProfile = GetSubtitleProfile(item, subtitleStream, options.Profile.SubtitleProfiles, PlayMethod.Transcode, _transcoderSupport, transcodingProfile.Container, transcodingProfile.Protocol);
|
||||
var subtitleProfile = GetSubtitleProfile(item, subtitleStream, options.Profile.SubtitleProfiles, PlayMethod.Transcode, this._transcoderSupport, transcodingProfile.Container, transcodingProfile.Protocol);
|
||||
playlistItem.SubtitleDeliveryMethod = subtitleProfile.Method;
|
||||
playlistItem.SubtitleFormat = subtitleProfile.Format;
|
||||
playlistItem.SubtitleCodecs = [subtitleProfile.Format];
|
||||
@@ -814,12 +822,12 @@ namespace MediaBrowser.Model.Dlna
|
||||
|
||||
if ((playlistItem.TranscodeReasons & (VideoReasons | TranscodeReason.ContainerBitrateExceedsLimit)) != 0)
|
||||
{
|
||||
ApplyTranscodingConditions(playlistItem, transcodingProfile.Conditions, null, true, true);
|
||||
this.ApplyTranscodingConditions(playlistItem, transcodingProfile.Conditions, null, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogDebug(
|
||||
this._logger.LogDebug(
|
||||
"StreamBuilder.BuildVideoItem( Profile={0}, Path={1}, AudioStreamIndex={2}, SubtitleStreamIndex={3} ) => ( PlayMethod={4}, TranscodeReason={5} ) {6}",
|
||||
options.Profile.Name ?? "Anonymous Profile",
|
||||
item.Path ?? "Unknown path",
|
||||
@@ -1059,6 +1067,7 @@ namespace MediaBrowser.Model.Dlna
|
||||
.Where(i => i.Type == CodecType.Video &&
|
||||
i.ContainsAnyCodec(playlistItem.VideoCodecs, container, useSubContainer) &&
|
||||
i.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoRangeType, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numStreams, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)))
|
||||
|
||||
// Reverse codec profiles for backward compatibility - first codec profile has higher priority
|
||||
.Reverse();
|
||||
foreach (var condition in appliedVideoConditions)
|
||||
@@ -1090,6 +1099,7 @@ namespace MediaBrowser.Model.Dlna
|
||||
.Where(i => i.Type == CodecType.VideoAudio &&
|
||||
i.ContainsAnyCodec(playlistItem.AudioCodecs, container) &&
|
||||
i.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth, audioProfile, isSecondaryAudio)))
|
||||
|
||||
// Reverse codec profiles for backward compatibility - first codec profile has higher priority
|
||||
.Reverse();
|
||||
|
||||
@@ -1106,6 +1116,7 @@ namespace MediaBrowser.Model.Dlna
|
||||
}
|
||||
|
||||
var maxBitrateSetting = options.GetMaxBitrate(false);
|
||||
|
||||
// Honor max rate
|
||||
if (maxBitrateSetting.HasValue)
|
||||
{
|
||||
@@ -1518,7 +1529,7 @@ namespace MediaBrowser.Model.Dlna
|
||||
new SubtitleProfile
|
||||
{
|
||||
Method = SubtitleDeliveryMethod.Encode,
|
||||
Format = subtitleStream.Codec
|
||||
Format = subtitleStream.Codec,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2309,13 +2320,13 @@ namespace MediaBrowser.Model.Dlna
|
||||
{
|
||||
var profile = options.Profile;
|
||||
|
||||
var failures = AggregateFailureConditions(
|
||||
var failures = this.AggregateFailureConditions(
|
||||
mediaSource,
|
||||
profile,
|
||||
"VideoCodecProfile",
|
||||
profile.ContainerProfiles
|
||||
.Where(containerProfile => containerProfile.Type == DlnaProfileType.Video && containerProfile.ContainsContainer(container))
|
||||
.SelectMany(containerProfile => CheckVideoConditions(containerProfile.Conditions, mediaSource, videoStream)));
|
||||
.SelectMany(containerProfile => this.CheckVideoConditions(containerProfile.Conditions, mediaSource, videoStream)));
|
||||
|
||||
return failures;
|
||||
}
|
||||
@@ -2334,15 +2345,15 @@ namespace MediaBrowser.Model.Dlna
|
||||
|
||||
string videoCodec = videoStream.Codec;
|
||||
|
||||
var failures = AggregateFailureConditions(
|
||||
var failures = this.AggregateFailureConditions(
|
||||
mediaSource,
|
||||
profile,
|
||||
"VideoCodecProfile",
|
||||
profile.CodecProfiles
|
||||
.Where(codecProfile => codecProfile.Type == CodecType.Video &&
|
||||
codecProfile.ContainsAnyCodec(videoCodec, container) &&
|
||||
!CheckVideoConditions(codecProfile.ApplyConditions, mediaSource, videoStream).Any())
|
||||
.SelectMany(codecProfile => CheckVideoConditions(codecProfile.Conditions, mediaSource, videoStream)));
|
||||
!this.CheckVideoConditions(codecProfile.ApplyConditions.ToArray(), mediaSource, videoStream).Any())
|
||||
.SelectMany(codecProfile => this.CheckVideoConditions(codecProfile.Conditions.ToArray(), mediaSource, videoStream)));
|
||||
|
||||
return failures;
|
||||
}
|
||||
@@ -2373,7 +2384,7 @@ namespace MediaBrowser.Model.Dlna
|
||||
? GetProfileConditionsForVideoAudio(profile.CodecProfiles, container, audioCodec, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, isSecondaryAudio)
|
||||
: GetProfileConditionsForAudio(profile.CodecProfiles, container, audioCodec, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, true);
|
||||
|
||||
var failures = AggregateFailureConditions(mediaSource, profile, "AudioCodecProfile", audioFailureConditions);
|
||||
var failures = this.AggregateFailureConditions(mediaSource, profile, "AudioCodecProfile", audioFailureConditions);
|
||||
|
||||
return failures;
|
||||
}
|
||||
@@ -2390,7 +2401,7 @@ namespace MediaBrowser.Model.Dlna
|
||||
/// <returns>Transcode reasons if the audio stream is not fully compatible for direct playback.</returns>
|
||||
private TranscodeReason GetCompatibilityAudioCodecDirect(MediaOptions options, MediaSourceInfo mediaSource, string container, MediaStream audioStream, bool isVideo, bool isSecondaryAudio)
|
||||
{
|
||||
var failures = GetCompatibilityAudioCodec(options, mediaSource, container, audioStream, null, isVideo, isSecondaryAudio);
|
||||
var failures = this.GetCompatibilityAudioCodec(options, mediaSource, container, audioStream, null, isVideo, isSecondaryAudio);
|
||||
|
||||
if (audioStream.IsExternal)
|
||||
{
|
||||
@@ -2400,4 +2411,3 @@ namespace MediaBrowser.Model.Dlna
|
||||
return failures;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
|
||||
#pragma warning disable CA1819 // Properties should not return arrays
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using global::System;
|
||||
using global::System.Collections.Generic;
|
||||
using global::System.ComponentModel;
|
||||
using global::System.Globalization;
|
||||
using global::System.Linq;
|
||||
using global::System.Text;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Model.Drawing;
|
||||
@@ -618,8 +618,10 @@ public class StreamInfo
|
||||
int? totalBitrate = TargetTotalBitrate;
|
||||
|
||||
double totalSeconds = RunTimeTicks.Value;
|
||||
|
||||
// Convert to ms
|
||||
totalSeconds /= 10000;
|
||||
|
||||
// Convert to seconds
|
||||
totalSeconds /= 1000;
|
||||
|
||||
@@ -1241,7 +1243,7 @@ public class StreamInfo
|
||||
Format = subtitleProfile.Format,
|
||||
Index = stream.Index,
|
||||
DeliveryMethod = subtitleProfile.Method,
|
||||
DisplayTitle = stream.DisplayTitle
|
||||
DisplayTitle = stream.DisplayTitle,
|
||||
};
|
||||
|
||||
if (info.DeliveryMethod == SubtitleDeliveryMethod.External)
|
||||
|
||||
@@ -4,36 +4,34 @@
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
namespace MediaBrowser.Model.Dlna
|
||||
{
|
||||
/// <summary>
|
||||
/// Delivery method to use during playback of a specific subtitle format.
|
||||
/// </summary>
|
||||
public enum SubtitleDeliveryMethod
|
||||
{
|
||||
/// <summary>
|
||||
/// Burn the subtitles in the video track.
|
||||
/// </summary>
|
||||
Encode = 0,
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
/// <summary>
|
||||
/// Delivery method to use during playback of a specific subtitle format.
|
||||
/// </summary>
|
||||
public enum SubtitleDeliveryMethod
|
||||
{
|
||||
/// <summary>
|
||||
/// Burn the subtitles in the video track.
|
||||
/// </summary>
|
||||
Encode = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Embed the subtitles in the file or stream.
|
||||
/// </summary>
|
||||
Embed = 1,
|
||||
/// <summary>
|
||||
/// Embed the subtitles in the file or stream.
|
||||
/// </summary>
|
||||
Embed = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Serve the subtitles as an external file.
|
||||
/// </summary>
|
||||
External = 2,
|
||||
/// <summary>
|
||||
/// Serve the subtitles as an external file.
|
||||
/// </summary>
|
||||
External = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Serve the subtitles as a separate HLS stream.
|
||||
/// </summary>
|
||||
Hls = 3,
|
||||
/// <summary>
|
||||
/// Serve the subtitles as a separate HLS stream.
|
||||
/// </summary>
|
||||
Hls = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Drop the subtitle.
|
||||
/// </summary>
|
||||
Drop = 4
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Drop the subtitle.
|
||||
/// </summary>
|
||||
Drop = 4,
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
// Copyright (c) PlaceholderCompany. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System.Xml.Serialization;
|
||||
using global::System.Xml.Serialization;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
|
||||
/// <summary>
|
||||
/// A class for subtitle profile information.
|
||||
/// </summary>
|
||||
|
||||
@@ -5,26 +5,24 @@
|
||||
#nullable disable
|
||||
#pragma warning disable CS1591
|
||||
|
||||
namespace MediaBrowser.Model.Dlna
|
||||
{
|
||||
public class SubtitleStreamInfo
|
||||
{
|
||||
public string Url { get; set; }
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
public class SubtitleStreamInfo
|
||||
{
|
||||
public string Url { get; set; }
|
||||
|
||||
public string Language { get; set; }
|
||||
public string Language { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
public bool IsForced { get; set; }
|
||||
public bool IsForced { get; set; }
|
||||
|
||||
public string Format { get; set; }
|
||||
public string Format { get; set; }
|
||||
|
||||
public string DisplayTitle { get; set; }
|
||||
public string DisplayTitle { get; set; }
|
||||
|
||||
public int Index { get; set; }
|
||||
public int Index { get; set; }
|
||||
|
||||
public SubtitleDeliveryMethod DeliveryMethod { get; set; }
|
||||
public SubtitleDeliveryMethod DeliveryMethod { get; set; }
|
||||
|
||||
public bool IsExternalUrl { get; set; }
|
||||
}
|
||||
}
|
||||
public bool IsExternalUrl { get; set; }
|
||||
}
|
||||
|
||||
@@ -4,11 +4,9 @@
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
namespace MediaBrowser.Model.Dlna
|
||||
{
|
||||
public enum TranscodeSeekInfo
|
||||
{
|
||||
Auto = 0,
|
||||
Bytes = 1
|
||||
}
|
||||
}
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
public enum TranscodeSeekInfo
|
||||
{
|
||||
Auto = 0,
|
||||
Bytes = 1,
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
// Copyright (c) PlaceholderCompany. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Xml.Serialization;
|
||||
using Jellyfin.Data.Enums;
|
||||
|
||||
namespace MediaBrowser.Model.Dlna;
|
||||
|
||||
using global::System;
|
||||
using global::System.ComponentModel;
|
||||
using global::System.Xml.Serialization;
|
||||
using Jellyfin.Data.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// A class for transcoding profile information.
|
||||
/// Note for client developers: Conditions defined in <see cref="CodecProfile"/> has higher priority and can override values defined here.
|
||||
|
||||
Reference in New Issue
Block a user