From 3bbb57eb833f2ae0ada312da03ac0e15b6bb1f59 Mon Sep 17 00:00:00 2001 From: vedant <12881174+viktory36@users.noreply.github.com> Date: Sat, 23 Mar 2024 16:39:49 +0300 Subject: [PATCH] Add new VideoRangeTypes to fully support DoVi on webOS (#10469) --- CONTRIBUTORS.md | 4 +- .../Controllers/DynamicHlsController.cs | 14 ++++-- Jellyfin.Data/Enums/VideoRangeType.cs | 17 ++++++- .../MediaEncoding/EncodingHelper.cs | 24 +++++++--- MediaBrowser.Model/Entities/MediaStream.cs | 44 ++++++++++++------- 5 files changed, 76 insertions(+), 27 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index e9c0fb2ad7..8550222a16 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -177,10 +177,12 @@ - [Chris-Codes-It](https://github.com/Chris-Codes-It) - [Pithaya](https://github.com/Pithaya) - [Çağrı Sakaoğlu](https://github.com/ilovepilav) - _ [Barasingha](https://github.com/MaVdbussche) + - [Barasingha](https://github.com/MaVdbussche) - [Gauvino](https://github.com/Gauvino) - [felix920506](https://github.com/felix920506) - [btopherjohnson](https://github.com/btopherjohnson) + - [GeorgeH005](https://github.com/GeorgeH005) + - [Vedant](https://github.com/viktory36/) # Emby Contributors diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index 1bdda8ad2f..312028cac1 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -1775,11 +1775,17 @@ public class DynamicHlsController : BaseJellyfinApiController || string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase) || string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)) { + var requestedRange = state.GetRequestedRangeTypes(codec); + var requestHasDOVI = requestedRange.Contains(VideoRangeType.DOVI.ToString(), StringComparison.OrdinalIgnoreCase); + var requestHasDOVIWithHDR10 = requestedRange.Contains(VideoRangeType.DOVIWithHDR10.ToString(), StringComparison.OrdinalIgnoreCase); + var requestHasDOVIWithHLG = requestedRange.Contains(VideoRangeType.DOVIWithHLG.ToString(), StringComparison.OrdinalIgnoreCase); + var requestHasDOVIWithSDR = requestedRange.Contains(VideoRangeType.DOVIWithSDR.ToString(), StringComparison.OrdinalIgnoreCase); + if (EncodingHelper.IsCopyCodec(codec) - && (state.VideoStream.VideoRangeType == VideoRangeType.DOVI - || string.Equals(state.VideoStream.CodecTag, "dovi", StringComparison.OrdinalIgnoreCase) - || string.Equals(state.VideoStream.CodecTag, "dvh1", StringComparison.OrdinalIgnoreCase) - || string.Equals(state.VideoStream.CodecTag, "dvhe", StringComparison.OrdinalIgnoreCase))) + && ((state.VideoStream.VideoRangeType == VideoRangeType.DOVI && requestHasDOVI) + || (state.VideoStream.VideoRangeType == VideoRangeType.DOVIWithHDR10 && requestHasDOVIWithHDR10) + || (state.VideoStream.VideoRangeType == VideoRangeType.DOVIWithHLG && requestHasDOVIWithHLG) + || (state.VideoStream.VideoRangeType == VideoRangeType.DOVIWithSDR && requestHasDOVIWithSDR))) { // Prefer dvh1 to dvhe args += " -tag:v:0 dvh1 -strict -2"; diff --git a/Jellyfin.Data/Enums/VideoRangeType.cs b/Jellyfin.Data/Enums/VideoRangeType.cs index 7ac7bc20a3..853c2c73db 100644 --- a/Jellyfin.Data/Enums/VideoRangeType.cs +++ b/Jellyfin.Data/Enums/VideoRangeType.cs @@ -26,10 +26,25 @@ public enum VideoRangeType HLG, /// - /// Dolby Vision video range type (12bit). + /// Dolby Vision video range type (10bit encoded / 12bit remapped). /// DOVI, + /// + /// Dolby Vision with HDR10 video range fallback (10bit). + /// + DOVIWithHDR10, + + /// + /// Dolby Vision with HLG video range fallback (10bit). + /// + DOVIWithHLG, + + /// + /// Dolby Vision with SDR video range fallback (8bit / 10bit). + /// + DOVIWithSDR, + /// /// HDR10+ video range type (10bit to 16bit). /// diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index cdaa6a6cd2..acf4f76a51 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -287,7 +287,9 @@ namespace MediaBrowser.Controller.MediaEncoding return state.VideoStream.VideoRange == VideoRange.HDR && (state.VideoStream.VideoRangeType == VideoRangeType.HDR10 - || state.VideoStream.VideoRangeType == VideoRangeType.HLG); + || state.VideoStream.VideoRangeType == VideoRangeType.HLG + || state.VideoStream.VideoRangeType == VideoRangeType.DOVIWithHDR10 + || state.VideoStream.VideoRangeType == VideoRangeType.DOVIWithHLG); } private bool IsVulkanHwTonemapAvailable(EncodingJobInfo state, EncodingOptions options) @@ -315,7 +317,8 @@ namespace MediaBrowser.Controller.MediaEncoding // Native VPP tonemapping may come to QSV in the future. return state.VideoStream.VideoRange == VideoRange.HDR - && state.VideoStream.VideoRangeType == VideoRangeType.HDR10; + && (state.VideoStream.VideoRangeType == VideoRangeType.HDR10 + || state.VideoStream.VideoRangeType == VideoRangeType.DOVIWithHDR10); } private bool IsVideoToolboxTonemapAvailable(EncodingJobInfo state, EncodingOptions options) @@ -330,7 +333,7 @@ namespace MediaBrowser.Controller.MediaEncoding // Certain DV profile 5 video works in Safari with direct playing, but the VideoToolBox does not produce correct mapping results with transcoding. // All other HDR formats working. return state.VideoStream.VideoRange == VideoRange.HDR - && state.VideoStream.VideoRangeType is VideoRangeType.HDR10 or VideoRangeType.HLG or VideoRangeType.HDR10Plus; + && state.VideoStream.VideoRangeType is VideoRangeType.HDR10 or VideoRangeType.HLG or VideoRangeType.HDR10Plus or VideoRangeType.DOVIWithHDR10 or VideoRangeType.DOVIWithHLG; } /// @@ -2206,7 +2209,16 @@ namespace MediaBrowser.Controller.MediaEncoding return false; } - if (!requestedRangeTypes.Contains(videoStream.VideoRangeType.ToString(), StringComparison.OrdinalIgnoreCase)) + // DOVIWithHDR10 should be compatible with HDR10 supporting players. Same goes with HLG and of course SDR. So allow copy of those formats + + var requestHasHDR10 = requestedRangeTypes.Contains(VideoRangeType.HDR10.ToString(), StringComparison.OrdinalIgnoreCase); + var requestHasHLG = requestedRangeTypes.Contains(VideoRangeType.HLG.ToString(), StringComparison.OrdinalIgnoreCase); + var requestHasSDR = requestedRangeTypes.Contains(VideoRangeType.SDR.ToString(), StringComparison.OrdinalIgnoreCase); + + if (!requestedRangeTypes.Contains(videoStream.VideoRangeType.ToString(), StringComparison.OrdinalIgnoreCase) + && !((requestHasHDR10 && videoStream.VideoRangeType == VideoRangeType.DOVIWithHDR10) + || (requestHasHLG && videoStream.VideoRangeType == VideoRangeType.DOVIWithHLG) + || (requestHasSDR && videoStream.VideoRangeType == VideoRangeType.DOVIWithSDR))) { return false; } @@ -6119,7 +6131,9 @@ namespace MediaBrowser.Controller.MediaEncoding && state.VideoStream.VideoRange == VideoRange.HDR && (state.VideoStream.VideoRangeType == VideoRangeType.HDR10 || state.VideoStream.VideoRangeType == VideoRangeType.HLG - || (state.VideoStream.VideoRangeType == VideoRangeType.DOVI + || ((state.VideoStream.VideoRangeType == VideoRangeType.DOVI + || state.VideoStream.VideoRangeType == VideoRangeType.DOVIWithHDR10 + || state.VideoStream.VideoRangeType == VideoRangeType.DOVIWithHLG) && string.Equals(state.VideoStream.Codec, "hevc", StringComparison.OrdinalIgnoreCase))); var useHwSurface = useOclToneMapping && IsVideoToolboxFullSupported() && _mediaEncoder.SupportsFilter("alphasrc"); diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index ae4a008bb3..a620bc9b54 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -707,34 +707,46 @@ namespace MediaBrowser.Model.Entities return (VideoRange.Unknown, VideoRangeType.Unknown); } - var colorTransfer = ColorTransfer; - - if (string.Equals(colorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase)) - { - return (VideoRange.HDR, VideoRangeType.HDR10); - } - - if (string.Equals(colorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase)) - { - return (VideoRange.HDR, VideoRangeType.HLG); - } - var codecTag = CodecTag; var dvProfile = DvProfile; var rpuPresentFlag = RpuPresentFlag == 1; var blPresentFlag = BlPresentFlag == 1; var dvBlCompatId = DvBlSignalCompatibilityId; - var isDoViHDRProfile = dvProfile == 5 || dvProfile == 7 || dvProfile == 8; - var isDoViHDRFlag = rpuPresentFlag && blPresentFlag && (dvBlCompatId == 0 || dvBlCompatId == 1 || dvBlCompatId == 4); + var isDoViProfile = dvProfile == 5 || dvProfile == 7 || dvProfile == 8; + var isDoViFlag = rpuPresentFlag && blPresentFlag && (dvBlCompatId == 0 || dvBlCompatId == 1 || dvBlCompatId == 4 || dvBlCompatId == 2 || dvBlCompatId == 6); - if ((isDoViHDRProfile && isDoViHDRFlag) + if ((isDoViProfile && isDoViFlag) || string.Equals(codecTag, "dovi", StringComparison.OrdinalIgnoreCase) || string.Equals(codecTag, "dvh1", StringComparison.OrdinalIgnoreCase) || string.Equals(codecTag, "dvhe", StringComparison.OrdinalIgnoreCase) || string.Equals(codecTag, "dav1", StringComparison.OrdinalIgnoreCase)) { - return (VideoRange.HDR, VideoRangeType.DOVI); + return dvProfile switch + { + 5 => (VideoRange.HDR, VideoRangeType.DOVI), + 8 => dvBlCompatId switch + { + 1 => (VideoRange.HDR, VideoRangeType.DOVIWithHDR10), + 4 => (VideoRange.HDR, VideoRangeType.DOVIWithHLG), + 2 => (VideoRange.SDR, VideoRangeType.DOVIWithSDR), + // There is no other case to handle here as per Dolby Spec. Default case included for completeness and linting purposes + _ => (VideoRange.SDR, VideoRangeType.SDR) + }, + 7 => (VideoRange.HDR, VideoRangeType.HDR10), + _ => (VideoRange.SDR, VideoRangeType.SDR) + }; + } + + var colorTransfer = ColorTransfer; + + if (string.Equals(colorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase)) + { + return (VideoRange.HDR, VideoRangeType.HDR10); + } + else if (string.Equals(colorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase)) + { + return (VideoRange.HDR, VideoRangeType.HLG); } return (VideoRange.SDR, VideoRangeType.SDR);