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:
2026-02-20 16:26:53 -05:00
parent 44ab9e1d6d
commit af1152b001
1436 changed files with 36615 additions and 15508 deletions
+39 -32
View File
@@ -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);
}
}
+7 -9
View File
@@ -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,
}
+9 -10
View File
@@ -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;
}
}
}
+3 -3
View File
@@ -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;
+1 -1
View File
@@ -4,7 +4,7 @@
#pragma warning disable CA1819 // Properties should not return arrays
using System;
using global::System;
namespace MediaBrowser.Model.Dlna;
+3 -3
View File
@@ -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>
+9 -11
View File
@@ -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,
}
+6 -8
View File
@@ -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);
}
+118 -120
View File
@@ -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&lt;System.Int32&gt;.</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&lt;System.Int32&gt;.</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;
}
}
+7 -9
View File
@@ -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,
}
+28 -30
View File
@@ -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; }
}
+81 -72
View File
@@ -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);
}
}
+6 -8
View File
@@ -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; }
}
+41 -31
View File
@@ -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;
}
}
}
+9 -7
View File
@@ -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,
}
+3 -3
View File
@@ -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>
+13 -15
View File
@@ -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; }
}
+6 -8
View File
@@ -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.