Migrate VideoRange and VideoRangeType to Enum

This commit is contained in:
Shadowghost 2023-06-15 13:28:01 +02:00
parent d874262bf9
commit 20a4509991
12 changed files with 201 additions and 45 deletions

View File

@ -12,6 +12,7 @@ using Jellyfin.Api.Attributes;
using Jellyfin.Api.Helpers; using Jellyfin.Api.Helpers;
using Jellyfin.Api.Models.PlaybackDtos; using Jellyfin.Api.Models.PlaybackDtos;
using Jellyfin.Api.Models.StreamingDtos; using Jellyfin.Api.Models.StreamingDtos;
using Jellyfin.Data.Enums;
using Jellyfin.Extensions; using Jellyfin.Extensions;
using Jellyfin.MediaEncoding.Hls.Playlist; using Jellyfin.MediaEncoding.Hls.Playlist;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
@ -1809,7 +1810,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|| string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)) || string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase))
{ {
if (EncodingHelper.IsCopyCodec(codec) if (EncodingHelper.IsCopyCodec(codec)
&& (string.Equals(state.VideoStream.VideoRangeType, "DOVI", StringComparison.OrdinalIgnoreCase) && (state.VideoStream.VideoRangeType == VideoRangeType.DOVI
|| string.Equals(state.VideoStream.CodecTag, "dovi", StringComparison.OrdinalIgnoreCase) || string.Equals(state.VideoStream.CodecTag, "dovi", StringComparison.OrdinalIgnoreCase)
|| string.Equals(state.VideoStream.CodecTag, "dvh1", StringComparison.OrdinalIgnoreCase) || string.Equals(state.VideoStream.CodecTag, "dvh1", StringComparison.OrdinalIgnoreCase)
|| string.Equals(state.VideoStream.CodecTag, "dvhe", StringComparison.OrdinalIgnoreCase))) || string.Equals(state.VideoStream.CodecTag, "dvhe", StringComparison.OrdinalIgnoreCase)))

View File

@ -9,6 +9,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Jellyfin.Api.Extensions; using Jellyfin.Api.Extensions;
using Jellyfin.Api.Models.StreamingDtos; using Jellyfin.Api.Models.StreamingDtos;
using Jellyfin.Data.Enums;
using Jellyfin.Extensions; using Jellyfin.Extensions;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Extensions;
@ -211,8 +212,7 @@ public class DynamicHlsHelper
// Provide SDR HEVC entrance for backward compatibility. // Provide SDR HEVC entrance for backward compatibility.
if (encodingOptions.AllowHevcEncoding if (encodingOptions.AllowHevcEncoding
&& EncodingHelper.IsCopyCodec(state.OutputVideoCodec) && EncodingHelper.IsCopyCodec(state.OutputVideoCodec)
&& !string.IsNullOrEmpty(state.VideoStream.VideoRange) && state.VideoStream.VideoRange == VideoRange.HDR
&& string.Equals(state.VideoStream.VideoRange, "HDR", StringComparison.OrdinalIgnoreCase)
&& string.Equals(state.ActualOutputVideoCodec, "hevc", StringComparison.OrdinalIgnoreCase)) && string.Equals(state.ActualOutputVideoCodec, "hevc", StringComparison.OrdinalIgnoreCase))
{ {
var requestedVideoProfiles = state.GetRequestedProfiles("hevc"); var requestedVideoProfiles = state.GetRequestedProfiles("hevc");
@ -255,8 +255,7 @@ public class DynamicHlsHelper
if (EncodingHelper.IsCopyCodec(state.OutputVideoCodec) if (EncodingHelper.IsCopyCodec(state.OutputVideoCodec)
&& state.VideoStream.Level.HasValue && state.VideoStream.Level.HasValue
&& state.VideoStream.Level > 150 && state.VideoStream.Level > 150
&& !string.IsNullOrEmpty(state.VideoStream.VideoRange) && state.VideoStream.VideoRange == VideoRange.SDR
&& string.Equals(state.VideoStream.VideoRange, "SDR", StringComparison.OrdinalIgnoreCase)
&& string.Equals(state.ActualOutputVideoCodec, "hevc", StringComparison.OrdinalIgnoreCase)) && string.Equals(state.ActualOutputVideoCodec, "hevc", StringComparison.OrdinalIgnoreCase))
{ {
var playlistCodecsField = new StringBuilder(); var playlistCodecsField = new StringBuilder();
@ -340,17 +339,17 @@ public class DynamicHlsHelper
/// <param name="state">StreamState of the current stream.</param> /// <param name="state">StreamState of the current stream.</param>
private void AppendPlaylistVideoRangeField(StringBuilder builder, StreamState state) private void AppendPlaylistVideoRangeField(StringBuilder builder, StreamState state)
{ {
if (state.VideoStream is not null && !string.IsNullOrEmpty(state.VideoStream.VideoRange)) if (state.VideoStream is not null && state.VideoStream.VideoRange != VideoRange.Unknown)
{ {
var videoRange = state.VideoStream.VideoRange; var videoRange = state.VideoStream.VideoRange;
if (EncodingHelper.IsCopyCodec(state.OutputVideoCodec)) if (EncodingHelper.IsCopyCodec(state.OutputVideoCodec))
{ {
if (string.Equals(videoRange, "SDR", StringComparison.OrdinalIgnoreCase)) if (videoRange == VideoRange.SDR)
{ {
builder.Append(",VIDEO-RANGE=SDR"); builder.Append(",VIDEO-RANGE=SDR");
} }
if (string.Equals(videoRange, "HDR", StringComparison.OrdinalIgnoreCase)) if (videoRange == VideoRange.HDR)
{ {
builder.Append(",VIDEO-RANGE=PQ"); builder.Append(",VIDEO-RANGE=PQ");
} }

View File

@ -0,0 +1,22 @@
namespace Jellyfin.Data.Enums;
/// <summary>
/// An enum representing video ranges.
/// </summary>
public enum VideoRange
{
/// <summary>
/// Unknown video range.
/// </summary>
Unknown,
/// <summary>
/// SDR video range.
/// </summary>
SDR,
/// <summary>
/// HDR video range.
/// </summary>
HDR
}

View File

@ -0,0 +1,37 @@
namespace Jellyfin.Data.Enums;
/// <summary>
/// An enum representing types of video ranges.
/// </summary>
public enum VideoRangeType
{
/// <summary>
/// Unknown video range type.
/// </summary>
Unknown,
/// <summary>
/// SDR video range type (8bit).
/// </summary>
SDR,
/// <summary>
/// HDR10 video range type (10bit).
/// </summary>
HDR10,
/// <summary>
/// HLG video range type (10bit).
/// </summary>
HLG,
/// <summary>
/// Dolby Vision video range type (12bit).
/// </summary>
DOVI,
/// <summary>
/// HDR10+ video range type (10bit to 16bit).
/// </summary>
HDR10Plus
}

View File

@ -209,8 +209,8 @@ namespace MediaBrowser.Controller.MediaEncoding
} }
if (string.Equals(state.VideoStream.Codec, "hevc", StringComparison.OrdinalIgnoreCase) if (string.Equals(state.VideoStream.Codec, "hevc", StringComparison.OrdinalIgnoreCase)
&& string.Equals(state.VideoStream.VideoRange, "HDR", StringComparison.OrdinalIgnoreCase) && state.VideoStream.VideoRange == VideoRange.HDR
&& string.Equals(state.VideoStream.VideoRangeType, "DOVI", StringComparison.OrdinalIgnoreCase)) && state.VideoStream.VideoRangeType == VideoRangeType.DOVI)
{ {
// Only native SW decoder and HW accelerator can parse dovi rpu. // Only native SW decoder and HW accelerator can parse dovi rpu.
var vidDecoder = GetHardwareVideoDecoder(state, options) ?? string.Empty; var vidDecoder = GetHardwareVideoDecoder(state, options) ?? string.Empty;
@ -221,9 +221,9 @@ namespace MediaBrowser.Controller.MediaEncoding
return isSwDecoder || isNvdecDecoder || isVaapiDecoder || isD3d11vaDecoder; return isSwDecoder || isNvdecDecoder || isVaapiDecoder || isD3d11vaDecoder;
} }
return string.Equals(state.VideoStream.VideoRange, "HDR", StringComparison.OrdinalIgnoreCase) return state.VideoStream.VideoRange == VideoRange.HDR
&& (string.Equals(state.VideoStream.VideoRangeType, "HDR10", StringComparison.OrdinalIgnoreCase) && (state.VideoStream.VideoRangeType == VideoRangeType.HDR10
|| string.Equals(state.VideoStream.VideoRangeType, "HLG", StringComparison.OrdinalIgnoreCase)); || state.VideoStream.VideoRangeType == VideoRangeType.HLG);
} }
private bool IsVulkanHwTonemapAvailable(EncodingJobInfo state, EncodingOptions options) private bool IsVulkanHwTonemapAvailable(EncodingJobInfo state, EncodingOptions options)
@ -235,7 +235,7 @@ namespace MediaBrowser.Controller.MediaEncoding
// libplacebo has partial Dolby Vision to SDR tonemapping support. // libplacebo has partial Dolby Vision to SDR tonemapping support.
return options.EnableTonemapping return options.EnableTonemapping
&& string.Equals(state.VideoStream.VideoRange, "HDR", StringComparison.OrdinalIgnoreCase) && state.VideoStream.VideoRange == VideoRange.HDR
&& GetVideoColorBitDepth(state) == 10; && GetVideoColorBitDepth(state) == 10;
} }
@ -250,8 +250,8 @@ namespace MediaBrowser.Controller.MediaEncoding
// Native VPP tonemapping may come to QSV in the future. // Native VPP tonemapping may come to QSV in the future.
return string.Equals(state.VideoStream.VideoRange, "HDR", StringComparison.OrdinalIgnoreCase) return state.VideoStream.VideoRange == VideoRange.HDR
&& string.Equals(state.VideoStream.VideoRangeType, "HDR10", StringComparison.OrdinalIgnoreCase); && state.VideoStream.VideoRangeType == VideoRangeType.HDR10;
} }
/// <summary> /// <summary>
@ -1945,12 +1945,12 @@ namespace MediaBrowser.Controller.MediaEncoding
var requestedRangeTypes = state.GetRequestedRangeTypes(videoStream.Codec); var requestedRangeTypes = state.GetRequestedRangeTypes(videoStream.Codec);
if (requestedRangeTypes.Length > 0) if (requestedRangeTypes.Length > 0)
{ {
if (string.IsNullOrEmpty(videoStream.VideoRangeType)) if (videoStream.VideoRangeType == VideoRangeType.Unknown)
{ {
return false; return false;
} }
if (!requestedRangeTypes.Contains(videoStream.VideoRangeType, StringComparison.OrdinalIgnoreCase)) if (!requestedRangeTypes.Contains(videoStream.VideoRangeType.ToString(), StringComparison.OrdinalIgnoreCase))
{ {
return false; return false;
} }

View File

@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using Jellyfin.Data.Entities; using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
@ -367,22 +368,21 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <summary> /// <summary>
/// Gets the target video range type. /// Gets the target video range type.
/// </summary> /// </summary>
public string TargetVideoRangeType public VideoRangeType TargetVideoRangeType
{ {
get get
{ {
if (BaseRequest.Static || EncodingHelper.IsCopyCodec(OutputVideoCodec)) if (BaseRequest.Static || EncodingHelper.IsCopyCodec(OutputVideoCodec))
{ {
return VideoStream?.VideoRangeType; return VideoStream?.VideoRangeType ?? VideoRangeType.Unknown;
} }
var requestedRangeType = GetRequestedRangeTypes(ActualOutputVideoCodec).FirstOrDefault(); if (Enum.TryParse(GetRequestedRangeTypes(ActualOutputVideoCodec).FirstOrDefault() ?? "Unknown", true, out VideoRangeType requestedRangeType))
if (!string.IsNullOrEmpty(requestedRangeType))
{ {
return requestedRangeType; return requestedRangeType;
} }
return null; return VideoRangeType.Unknown;
} }
} }

View File

@ -1,14 +1,38 @@
#pragma warning disable CS1591
using System; using System;
using System.Globalization; using System.Globalization;
using Jellyfin.Data.Enums;
using Jellyfin.Extensions; using Jellyfin.Extensions;
using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.MediaInfo;
namespace MediaBrowser.Model.Dlna namespace MediaBrowser.Model.Dlna
{ {
/// <summary>
/// The condition processor.
/// </summary>
public static class ConditionProcessor public static class ConditionProcessor
{ {
/// <summary>
/// Checks if a video condition is satisfied.
/// </summary>
/// <param name="condition">The <see cref="ProfileCondition"/>.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="videoBitDepth">The bit depth.</param>
/// <param name="videoBitrate">The bitrate.</param>
/// <param name="videoProfile">The video profile.</param>
/// <param name="videoRangeType">The <see cref="VideoRangeType"/>.</param>
/// <param name="videoLevel">The video level.</param>
/// <param name="videoFramerate">The framerate.</param>
/// <param name="packetLength">The packet length.</param>
/// <param name="timestamp">The <see cref="TransportStreamTimestamp"/>.</param>
/// <param name="isAnamorphic">A value indicating whether tthe video is anamorphic.</param>
/// <param name="isInterlaced">A value indicating whether tthe video is interlaced.</param>
/// <param name="refFrames">The reference frames.</param>
/// <param name="numVideoStreams">The number of video streams.</param>
/// <param name="numAudioStreams">The number of audio streams.</param>
/// <param name="videoCodecTag">The video codec tag.</param>
/// <param name="isAvc">A value indicating whether the video is AVC.</param>
/// <returns><b>True</b> if the condition is satisfied.</returns>
public static bool IsVideoConditionSatisfied( public static bool IsVideoConditionSatisfied(
ProfileCondition condition, ProfileCondition condition,
int? width, int? width,
@ -16,7 +40,7 @@ namespace MediaBrowser.Model.Dlna
int? videoBitDepth, int? videoBitDepth,
int? videoBitrate, int? videoBitrate,
string? videoProfile, string? videoProfile,
string? videoRangeType, VideoRangeType? videoRangeType,
double? videoLevel, double? videoLevel,
float? videoFramerate, float? videoFramerate,
int? packetLength, int? packetLength,
@ -70,6 +94,13 @@ namespace MediaBrowser.Model.Dlna
} }
} }
/// <summary>
/// Checks if a image condition is satisfied.
/// </summary>
/// <param name="condition">The <see cref="ProfileCondition"/>.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <returns><b>True</b> if the condition is satisfied.</returns>
public static bool IsImageConditionSatisfied(ProfileCondition condition, int? width, int? height) public static bool IsImageConditionSatisfied(ProfileCondition condition, int? width, int? height)
{ {
switch (condition.Property) switch (condition.Property)
@ -83,6 +114,15 @@ namespace MediaBrowser.Model.Dlna
} }
} }
/// <summary>
/// Checks if an audio condition is satisfied.
/// </summary>
/// <param name="condition">The <see cref="ProfileCondition"/>.</param>
/// <param name="audioChannels">The channel count.</param>
/// <param name="audioBitrate">The bitrate.</param>
/// <param name="audioSampleRate">The sample rate.</param>
/// <param name="audioBitDepth">The bit depth.</param>
/// <returns><b>True</b> if the condition is satisfied.</returns>
public static bool IsAudioConditionSatisfied(ProfileCondition condition, int? audioChannels, int? audioBitrate, int? audioSampleRate, int? audioBitDepth) public static bool IsAudioConditionSatisfied(ProfileCondition condition, int? audioChannels, int? audioBitrate, int? audioSampleRate, int? audioBitDepth)
{ {
switch (condition.Property) switch (condition.Property)
@ -100,6 +140,17 @@ namespace MediaBrowser.Model.Dlna
} }
} }
/// <summary>
/// Checks if an audio condition is satisfied for a video.
/// </summary>
/// <param name="condition">The <see cref="ProfileCondition"/>.</param>
/// <param name="audioChannels">The channel count.</param>
/// <param name="audioBitrate">The bitrate.</param>
/// <param name="audioSampleRate">The sample rate.</param>
/// <param name="audioBitDepth">The bit depth.</param>
/// <param name="audioProfile">The profile.</param>
/// <param name="isSecondaryTrack">A value indicating whether the audio is a secondary track.</param>
/// <returns><b>True</b> if the condition is satisfied.</returns>
public static bool IsVideoAudioConditionSatisfied( public static bool IsVideoAudioConditionSatisfied(
ProfileCondition condition, ProfileCondition condition,
int? audioChannels, int? audioChannels,
@ -281,5 +332,41 @@ namespace MediaBrowser.Model.Dlna
throw new InvalidOperationException("Unexpected ProfileConditionType: " + condition.Condition); throw new InvalidOperationException("Unexpected ProfileConditionType: " + condition.Condition);
} }
} }
private static bool IsConditionSatisfied(ProfileCondition condition, VideoRangeType? currentValue)
{
if (!currentValue.HasValue || currentValue.Equals(VideoRangeType.Unknown))
{
// If the value is unknown, it satisfies if not marked as required
return !condition.IsRequired;
}
var conditionType = condition.Condition;
if (conditionType == ProfileConditionType.EqualsAny)
{
foreach (var singleConditionString in condition.Value.AsSpan().Split('|'))
{
if (Enum.TryParse(singleConditionString, true, out VideoRangeType conditionValue)
&& conditionValue.Equals(currentValue))
{
return true;
}
}
return false;
}
if (Enum.TryParse(condition.Value, true, out VideoRangeType expected))
{
return conditionType switch
{
ProfileConditionType.Equals => currentValue.Value == expected,
ProfileConditionType.NotEquals => currentValue.Value != expected,
_ => throw new InvalidOperationException("Unexpected ProfileConditionType: " + condition.Condition)
};
}
return false;
}
} }
} }

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using Jellyfin.Data.Enums;
using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.MediaInfo;
namespace MediaBrowser.Model.Dlna namespace MediaBrowser.Model.Dlna
@ -128,7 +129,7 @@ namespace MediaBrowser.Model.Dlna
bool isDirectStream, bool isDirectStream,
long? runtimeTicks, long? runtimeTicks,
string videoProfile, string videoProfile,
string videoRangeType, VideoRangeType videoRangeType,
double? videoLevel, double? videoLevel,
float? videoFramerate, float? videoFramerate,
int? packetLength, int? packetLength,

View File

@ -2,6 +2,7 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Xml.Serialization; using System.Xml.Serialization;
using Jellyfin.Data.Enums;
using Jellyfin.Extensions; using Jellyfin.Extensions;
using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.MediaInfo;
@ -445,7 +446,7 @@ namespace MediaBrowser.Model.Dlna
int? bitDepth, int? bitDepth,
int? videoBitrate, int? videoBitrate,
string videoProfile, string videoProfile,
string videoRangeType, VideoRangeType videoRangeType,
double? videoLevel, double? videoLevel,
float? videoFramerate, float? videoFramerate,
int? packetLength, int? packetLength,

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using Jellyfin.Data.Enums;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.MediaInfo;
@ -889,7 +890,7 @@ namespace MediaBrowser.Model.Dlna
int? videoBitrate = videoStream?.BitRate; int? videoBitrate = videoStream?.BitRate;
double? videoLevel = videoStream?.Level; double? videoLevel = videoStream?.Level;
string? videoProfile = videoStream?.Profile; string? videoProfile = videoStream?.Profile;
string? videoRangeType = videoStream?.VideoRangeType; VideoRangeType? videoRangeType = videoStream?.VideoRangeType;
float videoFramerate = videoStream is null ? 0 : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate ?? 0; float videoFramerate = videoStream is null ? 0 : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate ?? 0;
bool? isAnamorphic = videoStream?.IsAnamorphic; bool? isAnamorphic = videoStream?.IsAnamorphic;
bool? isInterlaced = videoStream?.IsInterlaced; bool? isInterlaced = videoStream?.IsInterlaced;
@ -1144,7 +1145,7 @@ namespace MediaBrowser.Model.Dlna
int? videoBitrate = videoStream?.BitRate; int? videoBitrate = videoStream?.BitRate;
double? videoLevel = videoStream?.Level; double? videoLevel = videoStream?.Level;
string? videoProfile = videoStream?.Profile; string? videoProfile = videoStream?.Profile;
string? videoRangeType = videoStream?.VideoRangeType; VideoRangeType? videoRangeType = videoStream?.VideoRangeType;
float videoFramerate = videoStream is null ? 0 : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate ?? 0; float videoFramerate = videoStream is null ? 0 : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate ?? 0;
bool? isAnamorphic = videoStream?.IsAnamorphic; bool? isAnamorphic = videoStream?.IsAnamorphic;
bool? isInterlaced = videoStream?.IsInterlaced; bool? isInterlaced = videoStream?.IsInterlaced;
@ -1932,6 +1933,10 @@ namespace MediaBrowser.Model.Dlna
{ {
item.SetOption(qualifier, "rangetype", string.Join(',', values)); item.SetOption(qualifier, "rangetype", string.Join(',', values));
} }
else if (condition.Condition == ProfileConditionType.NotEquals)
{
item.SetOption(qualifier, "rangetype", string.Join(',', Enum.GetNames(typeof(VideoRangeType)).Except(values)));
}
else if (condition.Condition == ProfileConditionType.EqualsAny) else if (condition.Condition == ProfileConditionType.EqualsAny)
{ {
var currentValue = item.GetOption(qualifier, "rangetype"); var currentValue = item.GetOption(qualifier, "rangetype");

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using Jellyfin.Data.Enums;
using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
@ -281,23 +282,24 @@ namespace MediaBrowser.Model.Dlna
/// <summary> /// <summary>
/// Gets the target video range type that will be in the output stream. /// Gets the target video range type that will be in the output stream.
/// </summary> /// </summary>
public string TargetVideoRangeType public VideoRangeType TargetVideoRangeType
{ {
get get
{ {
if (IsDirectStream) if (IsDirectStream)
{ {
return TargetVideoStream?.VideoRangeType; return TargetVideoStream?.VideoRangeType ?? VideoRangeType.Unknown;
} }
var targetVideoCodecs = TargetVideoCodec; var targetVideoCodecs = TargetVideoCodec;
var videoCodec = targetVideoCodecs.Length == 0 ? null : targetVideoCodecs[0]; var videoCodec = targetVideoCodecs.Length == 0 ? null : targetVideoCodecs[0];
if (!string.IsNullOrEmpty(videoCodec)) if (!string.IsNullOrEmpty(videoCodec)
&& Enum.TryParse(GetOption(videoCodec, "rangetype"), true, out VideoRangeType videoRangeType))
{ {
return GetOption(videoCodec, "rangetype"); return videoRangeType;
} }
return TargetVideoStream?.VideoRangeType; return TargetVideoStream?.VideoRangeType ?? VideoRangeType.Unknown;
} }
} }

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Jellyfin.Data.Enums;
using Jellyfin.Extensions; using Jellyfin.Extensions;
using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Extensions;
@ -148,7 +149,7 @@ namespace MediaBrowser.Model.Entities
/// Gets the video range. /// Gets the video range.
/// </summary> /// </summary>
/// <value>The video range.</value> /// <value>The video range.</value>
public string VideoRange public VideoRange VideoRange
{ {
get get
{ {
@ -162,7 +163,7 @@ namespace MediaBrowser.Model.Entities
/// Gets the video range type. /// Gets the video range type.
/// </summary> /// </summary>
/// <value>The video range type.</value> /// <value>The video range type.</value>
public string VideoRangeType public VideoRangeType VideoRangeType
{ {
get get
{ {
@ -306,9 +307,9 @@ namespace MediaBrowser.Model.Entities
attributes.Add(Codec.ToUpperInvariant()); attributes.Add(Codec.ToUpperInvariant());
} }
if (!string.IsNullOrEmpty(VideoRange)) if (VideoRange != VideoRange.Unknown)
{ {
attributes.Add(VideoRange.ToUpperInvariant()); attributes.Add(VideoRange.ToString());
} }
if (!string.IsNullOrEmpty(Title)) if (!string.IsNullOrEmpty(Title))
@ -677,23 +678,23 @@ namespace MediaBrowser.Model.Entities
return true; return true;
} }
public (string VideoRange, string VideoRangeType) GetVideoColorRange() public (VideoRange VideoRange, VideoRangeType VideoRangeType) GetVideoColorRange()
{ {
if (Type != MediaStreamType.Video) if (Type != MediaStreamType.Video)
{ {
return (null, null); return (VideoRange.Unknown, VideoRangeType.Unknown);
} }
var colorTransfer = ColorTransfer; var colorTransfer = ColorTransfer;
if (string.Equals(colorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase)) if (string.Equals(colorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase))
{ {
return ("HDR", "HDR10"); return (VideoRange.HDR, VideoRangeType.HDR10);
} }
if (string.Equals(colorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase)) if (string.Equals(colorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase))
{ {
return ("HDR", "HLG"); return (VideoRange.HDR, VideoRangeType.HLG);
} }
var codecTag = CodecTag; var codecTag = CodecTag;
@ -711,10 +712,10 @@ namespace MediaBrowser.Model.Entities
|| string.Equals(codecTag, "dvhe", StringComparison.OrdinalIgnoreCase) || string.Equals(codecTag, "dvhe", StringComparison.OrdinalIgnoreCase)
|| string.Equals(codecTag, "dav1", StringComparison.OrdinalIgnoreCase)) || string.Equals(codecTag, "dav1", StringComparison.OrdinalIgnoreCase))
{ {
return ("HDR", "DOVI"); return (VideoRange.HDR, VideoRangeType.DOVI);
} }
return ("SDR", "SDR"); return (VideoRange.SDR, VideoRangeType.SDR);
} }
} }
} }