aboutsummaryrefslogtreecommitdiff
path: root/Jellyfin.Api/Helpers/DynamicHlsHelper.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Jellyfin.Api/Helpers/DynamicHlsHelper.cs')
-rw-r--r--Jellyfin.Api/Helpers/DynamicHlsHelper.cs99
1 files changed, 65 insertions, 34 deletions
diff --git a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs
index 0e620e72a..a38ad379c 100644
--- a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs
+++ b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs
@@ -8,8 +8,8 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Api.Extensions;
-using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Entities;
using Jellyfin.Extensions;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
@@ -267,7 +267,7 @@ public class DynamicHlsHelper
if (EnableAdaptiveBitrateStreaming(state, isLiveStream, enableAdaptiveBitrateStreaming, _httpContextAccessor.HttpContext.GetNormalizedRemoteIP()))
{
- var requestedVideoBitrate = state.VideoRequest is null ? 0 : state.VideoRequest.VideoBitRate ?? 0;
+ var requestedVideoBitrate = state.VideoRequest?.VideoBitRate ?? 0;
// By default, vary by just 200k
var variation = GetBitrateVariation(totalBitrate);
@@ -345,13 +345,15 @@ public class DynamicHlsHelper
if (videoRange == VideoRange.HDR)
{
- if (videoRangeType == VideoRangeType.HLG)
+ switch (videoRangeType)
{
- builder.Append(",VIDEO-RANGE=HLG");
- }
- else
- {
- builder.Append(",VIDEO-RANGE=PQ");
+ case VideoRangeType.HLG:
+ case VideoRangeType.DOVIWithHLG:
+ builder.Append(",VIDEO-RANGE=HLG");
+ break;
+ default:
+ builder.Append(",VIDEO-RANGE=PQ");
+ break;
}
}
}
@@ -418,36 +420,67 @@ public class DynamicHlsHelper
/// <param name="state">StreamState of the current stream.</param>
private void AppendPlaylistSupplementalCodecsField(StringBuilder builder, StreamState state)
{
- // Dolby Vision currently cannot exist when transcoding
+ // HDR dynamic metadata currently cannot exist when transcoding
if (!EncodingHelper.IsCopyCodec(state.OutputVideoCodec))
{
return;
}
- var dvProfile = state.VideoStream.DvProfile;
- var dvLevel = state.VideoStream.DvLevel;
- var dvRangeString = state.VideoStream.VideoRangeType switch
+ if (EncodingHelper.IsDovi(state.VideoStream) && !_encodingHelper.IsDoviRemoved(state))
{
- VideoRangeType.DOVIWithHDR10 => "db1p",
- VideoRangeType.DOVIWithHLG => "db4h",
- _ => string.Empty
- };
+ AppendDvString();
+ }
+ else if (EncodingHelper.IsHdr10Plus(state.VideoStream) && !_encodingHelper.IsHdr10PlusRemoved(state))
+ {
+ AppendHdr10PlusString();
+ }
- if (dvProfile is null || dvLevel is null || string.IsNullOrEmpty(dvRangeString))
+ return;
+
+ void AppendDvString()
{
- return;
+ var dvProfile = state.VideoStream.DvProfile;
+ var dvLevel = state.VideoStream.DvLevel;
+ var dvRangeString = state.VideoStream.VideoRangeType switch
+ {
+ VideoRangeType.DOVIWithHDR10 => "db1p",
+ VideoRangeType.DOVIWithHLG => "db4h",
+ VideoRangeType.DOVIWithHDR10Plus => "db1p", // The HDR10+ metadata would be removed if Dovi metadata is not removed
+ _ => string.Empty // Don't label Dovi with EL and SDR due to compatability issues, ignore invalid configurations
+ };
+
+ if (dvProfile is null || dvLevel is null || string.IsNullOrEmpty(dvRangeString))
+ {
+ return;
+ }
+
+ var dvFourCc = string.Equals(state.ActualOutputVideoCodec, "av1", StringComparison.OrdinalIgnoreCase) ? "dav1" : "dvh1";
+ builder.Append(",SUPPLEMENTAL-CODECS=\"")
+ .Append(dvFourCc)
+ .Append('.')
+ .Append(dvProfile.Value.ToString("D2", CultureInfo.InvariantCulture))
+ .Append('.')
+ .Append(dvLevel.Value.ToString("D2", CultureInfo.InvariantCulture))
+ .Append('/')
+ .Append(dvRangeString)
+ .Append('"');
}
- var dvFourCc = string.Equals(state.ActualOutputVideoCodec, "av1", StringComparison.OrdinalIgnoreCase) ? "dav1" : "dvh1";
- builder.Append(",SUPPLEMENTAL-CODECS=\"")
- .Append(dvFourCc)
- .Append('.')
- .Append(dvProfile.Value.ToString("D2", CultureInfo.InvariantCulture))
- .Append('.')
- .Append(dvLevel.Value.ToString("D2", CultureInfo.InvariantCulture))
- .Append('/')
- .Append(dvRangeString)
- .Append('"');
+ void AppendHdr10PlusString()
+ {
+ var videoCodecLevel = GetOutputVideoCodecLevel(state);
+ if (string.IsNullOrEmpty(state.ActualOutputVideoCodec) || videoCodecLevel is null)
+ {
+ return;
+ }
+
+ var videoCodecString = GetPlaylistVideoCodecs(state, state.ActualOutputVideoCodec, videoCodecLevel.Value);
+ builder.Append(",SUPPLEMENTAL-CODECS=\"")
+ .Append(videoCodecString)
+ .Append('/')
+ .Append("cdm4")
+ .Append('"');
+ }
}
/// <summary>
@@ -526,9 +559,7 @@ public class DynamicHlsHelper
return false;
}
- // Having problems in android
- return false;
- // return state.VideoRequest.VideoBitRate.HasValue;
+ return state.VideoRequest?.VideoBitRate.HasValue ?? false;
}
private void AddSubtitles(StreamState state, IEnumerable<MediaStream> subtitles, StringBuilder builder, ClaimsPrincipal user)
@@ -550,7 +581,7 @@ public class DynamicHlsHelper
var url = string.Format(
CultureInfo.InvariantCulture,
- "{0}/Subtitles/{1}/subtitles.m3u8?SegmentLength={2}&api_key={3}",
+ "{0}/Subtitles/{1}/subtitles.m3u8?SegmentLength={2}&ApiKey={3}",
state.Request.MediaSourceId,
stream.Index.ToString(CultureInfo.InvariantCulture),
30.ToString(CultureInfo.InvariantCulture),
@@ -587,7 +618,7 @@ public class DynamicHlsHelper
var url = string.Format(
CultureInfo.InvariantCulture,
- "Trickplay/{0}/tiles.m3u8?MediaSourceId={1}&api_key={2}",
+ "Trickplay/{0}/tiles.m3u8?MediaSourceId={1}&ApiKey={2}",
width.ToString(CultureInfo.InvariantCulture),
state.Request.MediaSourceId,
user.GetToken());
@@ -616,7 +647,7 @@ public class DynamicHlsHelper
&& state.VideoStream is not null
&& state.VideoStream.Level.HasValue)
{
- levelString = state.VideoStream.Level.Value.ToString(CultureInfo.InvariantCulture) ?? string.Empty;
+ levelString = state.VideoStream.Level.Value.ToString(CultureInfo.InvariantCulture);
}
else
{