diff --git a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs
index a58da17d5..0e620e72a 100644
--- a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs
+++ b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs
@@ -304,6 +304,8 @@ public class DynamicHlsHelper
AppendPlaylistCodecsField(playlistBuilder, state);
+ AppendPlaylistSupplementalCodecsField(playlistBuilder, state);
+
AppendPlaylistResolutionField(playlistBuilder, state);
AppendPlaylistFramerateField(playlistBuilder, state);
@@ -406,6 +408,48 @@ public class DynamicHlsHelper
}
}
+ ///
+ /// Appends a SUPPLEMENTAL-CODECS field containing formatted strings of
+ /// the active streams output Dolby Vision Videos.
+ ///
+ ///
+ ///
+ /// StringBuilder to append the field to.
+ /// StreamState of the current stream.
+ private void AppendPlaylistSupplementalCodecsField(StringBuilder builder, StreamState state)
+ {
+ // Dolby Vision 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
+ {
+ VideoRangeType.DOVIWithHDR10 => "db1p",
+ VideoRangeType.DOVIWithHLG => "db4h",
+ _ => string.Empty
+ };
+
+ 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('"');
+ }
+
///
/// Appends a RESOLUTION field containing the resolution of the output stream.
///