diff options
Diffstat (limited to 'Jellyfin.Api/Helpers/DynamicHlsHelper.cs')
| -rw-r--r-- | Jellyfin.Api/Helpers/DynamicHlsHelper.cs | 66 |
1 files changed, 50 insertions, 16 deletions
diff --git a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs index 245239233..646bf6443 100644 --- a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs +++ b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs @@ -9,6 +9,8 @@ using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Extensions; using Jellyfin.Api.Models.StreamingDtos; +using Jellyfin.Data.Enums; +using Jellyfin.Extensions; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; @@ -209,9 +211,9 @@ public class DynamicHlsHelper // Provide SDR HEVC entrance for backward compatibility. if (encodingOptions.AllowHevcEncoding + && !encodingOptions.AllowAv1Encoding && EncodingHelper.IsCopyCodec(state.OutputVideoCodec) - && !string.IsNullOrEmpty(state.VideoStream.VideoRange) - && string.Equals(state.VideoStream.VideoRange, "HDR", StringComparison.OrdinalIgnoreCase) + && state.VideoStream.VideoRange == VideoRange.HDR && string.Equals(state.ActualOutputVideoCodec, "hevc", StringComparison.OrdinalIgnoreCase)) { var requestedVideoProfiles = state.GetRequestedProfiles("hevc"); @@ -223,9 +225,17 @@ public class DynamicHlsHelper sdrVideoUrl += "&AllowVideoStreamCopy=false"; var sdrOutputVideoBitrate = _encodingHelper.GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream, state.OutputVideoCodec); - var sdrOutputAudioBitrate = _encodingHelper.GetAudioBitrateParam(state.VideoRequest, state.AudioStream) ?? 0; - var sdrTotalBitrate = sdrOutputAudioBitrate + sdrOutputVideoBitrate; + var sdrOutputAudioBitrate = 0; + if (EncodingHelper.LosslessAudioCodecs.Contains(state.VideoRequest.AudioCodec, StringComparison.OrdinalIgnoreCase)) + { + sdrOutputAudioBitrate = state.AudioStream.BitRate ?? 0; + } + else + { + sdrOutputAudioBitrate = _encodingHelper.GetAudioBitrateParam(state.VideoRequest, state.AudioStream, state.OutputAudioChannels) ?? 0; + } + var sdrTotalBitrate = sdrOutputAudioBitrate + sdrOutputVideoBitrate; var sdrPlaylist = AppendPlaylist(builder, state, sdrVideoUrl, sdrTotalBitrate, subtitleGroup); // Provide a workaround for the case issue between flac and fLaC. @@ -243,11 +253,12 @@ public class DynamicHlsHelper // Provide Level 5.0 entrance for backward compatibility. // e.g. Apple A10 chips refuse the master playlist containing SDR HEVC Main Level 5.1 video, // but in fact it is capable of playing videos up to Level 6.1. - if (EncodingHelper.IsCopyCodec(state.OutputVideoCodec) + if (encodingOptions.AllowHevcEncoding + && !encodingOptions.AllowAv1Encoding + && EncodingHelper.IsCopyCodec(state.OutputVideoCodec) && state.VideoStream.Level.HasValue && state.VideoStream.Level > 150 - && !string.IsNullOrEmpty(state.VideoStream.VideoRange) - && string.Equals(state.VideoStream.VideoRange, "SDR", StringComparison.OrdinalIgnoreCase) + && state.VideoStream.VideoRange == VideoRange.SDR && string.Equals(state.ActualOutputVideoCodec, "hevc", StringComparison.OrdinalIgnoreCase)) { var playlistCodecsField = new StringBuilder(); @@ -331,17 +342,17 @@ public class DynamicHlsHelper /// <param name="state">StreamState of the current stream.</param> 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; if (EncodingHelper.IsCopyCodec(state.OutputVideoCodec)) { - if (string.Equals(videoRange, "SDR", StringComparison.OrdinalIgnoreCase)) + if (videoRange == VideoRange.SDR) { builder.Append(",VIDEO-RANGE=SDR"); } - if (string.Equals(videoRange, "HDR", StringComparison.OrdinalIgnoreCase)) + if (videoRange == VideoRange.HDR) { builder.Append(",VIDEO-RANGE=PQ"); } @@ -546,6 +557,12 @@ public class DynamicHlsHelper levelString = state.GetRequestedLevel("h265") ?? state.GetRequestedLevel("hevc") ?? "120"; levelString = EncodingHelper.NormalizeTranscodingLevel(state, levelString); } + + if (string.Equals(state.ActualOutputVideoCodec, "av1", StringComparison.OrdinalIgnoreCase)) + { + levelString = state.GetRequestedLevel("av1") ?? "19"; + levelString = EncodingHelper.NormalizeTranscodingLevel(state, levelString); + } } if (int.TryParse(levelString, NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedLevel)) @@ -557,11 +574,11 @@ public class DynamicHlsHelper } /// <summary> - /// Get the H.26X profile of the output video stream. + /// Get the profile of the output video stream. /// </summary> /// <param name="state">StreamState of the current stream.</param> /// <param name="codec">Video codec.</param> - /// <returns>H.26X profile of the output video stream.</returns> + /// <returns>Profile of the output video stream.</returns> private string GetOutputVideoCodecProfile(StreamState state, string codec) { string profileString = string.Empty; @@ -579,7 +596,8 @@ public class DynamicHlsHelper } if (string.Equals(state.ActualOutputVideoCodec, "h265", StringComparison.OrdinalIgnoreCase) - || string.Equals(state.ActualOutputVideoCodec, "hevc", StringComparison.OrdinalIgnoreCase)) + || string.Equals(state.ActualOutputVideoCodec, "hevc", StringComparison.OrdinalIgnoreCase) + || string.Equals(state.ActualOutputVideoCodec, "av1", StringComparison.OrdinalIgnoreCase)) { profileString ??= "main"; } @@ -649,9 +667,9 @@ public class DynamicHlsHelper { if (level == 0) { - // This is 0 when there's no requested H.26X level in the device profile - // and the source is not encoded in H.26X - _logger.LogError("Got invalid H.26X level when building CODECS field for HLS master playlist"); + // This is 0 when there's no requested level in the device profile + // and the source is not encoded in H.26X or AV1 + _logger.LogError("Got invalid level when building CODECS field for HLS master playlist"); return string.Empty; } @@ -668,6 +686,22 @@ public class DynamicHlsHelper return HlsCodecStringHelpers.GetH265String(profile, level); } + if (string.Equals(codec, "av1", StringComparison.OrdinalIgnoreCase)) + { + string profile = GetOutputVideoCodecProfile(state, "av1"); + + // Currently we only transcode to 8 bits AV1 + int bitDepth = 8; + if (EncodingHelper.IsCopyCodec(state.OutputVideoCodec) + && state.VideoStream != null + && state.VideoStream.BitDepth.HasValue) + { + bitDepth = state.VideoStream.BitDepth.Value; + } + + return HlsCodecStringHelpers.GetAv1String(profile, level, false, bitDepth); + } + return string.Empty; } |
