diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 8a3bd5bcd2..7129f7a166 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -259,6 +259,7 @@ namespace MediaBrowser.Controller.MediaEncoding return _mediaEncoder.SupportsHwaccel("videotoolbox") && _mediaEncoder.SupportsFilter("yadif_videotoolbox") && _mediaEncoder.SupportsFilter("overlay_videotoolbox") + && _mediaEncoder.SupportsFilter("tonemap_videotoolbox") && _mediaEncoder.SupportsFilter("scale_vt"); } @@ -1376,6 +1377,14 @@ namespace MediaBrowser.Controller.MediaEncoding return FormattableString.Invariant($" -rc_mode VBR -b:v {bitrate} -maxrate {bitrate} -bufsize {bufsize}"); } + if (string.Equals(videoCodec, "h264_videotoolbox", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoCodec, "hevc_videotoolbox", StringComparison.OrdinalIgnoreCase)) + { + // The `maxrate` and `bufsize` options can potentially lead to performance regression + // and even encoder hangs, especially when the value is very high. + return FormattableString.Invariant($" -b:v {bitrate}"); + } + return FormattableString.Invariant($" -b:v {bitrate} -maxrate {bitrate} -bufsize {bufsize}"); } @@ -5020,17 +5029,16 @@ namespace MediaBrowser.Controller.MediaEncoding var vidDecoder = GetHardwareVideoDecoder(state, options) ?? string.Empty; var isVtEncoder = vidEncoder.Contains("videotoolbox", StringComparison.OrdinalIgnoreCase); var isVtFullSupported = isMacOS && IsVideoToolboxFullSupported(); - var isVtOclSupported = isVtFullSupported && IsOpenclFullSupported(); // legacy videotoolbox pipeline (disable hw filters) if (!isVtEncoder - || !isVtOclSupported + || !isVtFullSupported || !_mediaEncoder.SupportsFilter("alphasrc")) { return GetSwVidFilterChain(state, options, vidEncoder); } - // preferred videotoolbox + vt/ocl filters pipeline + // preferred videotoolbox + metal filters pipeline return GetAppleVidFiltersPreferred(state, options, vidDecoder, vidEncoder); } @@ -5054,13 +5062,23 @@ namespace MediaBrowser.Controller.MediaEncoding var doDeintHevc = state.DeInterlace("h265", true) || state.DeInterlace("hevc", true); var doDeintH2645 = doDeintH264 || doDeintHevc; var doVtTonemap = IsVideoToolboxTonemapAvailable(state, options); - var doOclTonemap = !doVtTonemap && IsHwTonemapAvailable(state, options); + var doMetalTonemap = !doVtTonemap && IsHwTonemapAvailable(state, options); var scaleFormat = string.Empty; + // Use P010 for Metal tone mapping, otherwise force an 8bit output. if (!string.Equals(state.VideoStream.PixelFormat, "yuv420p", StringComparison.OrdinalIgnoreCase)) { - // Use P010 for OpenCL tone mapping, otherwise force an 8bit output. - scaleFormat = doOclTonemap ? "p010le" : "nv12"; + if (doMetalTonemap) + { + if (!string.Equals(state.VideoStream.PixelFormat, "yuv420p10le", StringComparison.OrdinalIgnoreCase)) + { + scaleFormat = "p010le"; + } + } + else + { + scaleFormat = "nv12"; + } } var hwScaleFilter = GetHwScaleFilter("vt", scaleFormat, inW, inH, reqW, reqH, reqMaxW, reqMaxH); @@ -5081,12 +5099,6 @@ namespace MediaBrowser.Controller.MediaEncoding /* Make main filters for video stream */ var mainFilters = new List(); - // Color override is only required for OpenCL where hardware surface is in use - if (doOclTonemap) - { - mainFilters.Add(GetOverwriteColorPropertiesParam(state, doOclTonemap)); - } - // INPUT videotoolbox/memory surface(vram/uma) // this will pass-through automatically if in/out format matches. mainFilters.Add("format=nv12|p010le|videotoolbox_vld"); @@ -5112,18 +5124,11 @@ namespace MediaBrowser.Controller.MediaEncoding // hw scale & vt tonemap mainFilters.Add(hwScaleFilter); - // ocl tonemap - if (doOclTonemap) + // Metal tonemap + if (doMetalTonemap) { - // map from videotoolbox to opencl via videotoolbox-opencl interop. - mainFilters.Add("hwmap=derive_device=opencl:mode=read"); - - var tonemapFilter = GetHwTonemapFilter(options, "opencl", "nv12"); + var tonemapFilter = GetHwTonemapFilter(options, "videotoolbox", "nv12"); mainFilters.Add(tonemapFilter); - - // OUTPUT videotoolbox(nv12) surface(vram/uma) - // reverse-mapping via videotoolbox-opencl interop. - mainFilters.Add("hwmap=derive_device=videotoolbox:mode=write:reverse=1"); } /* Make sub and overlay filters for subtitle stream */ @@ -6146,39 +6151,27 @@ namespace MediaBrowser.Controller.MediaEncoding || string.Equals("yuvj420p", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); var is8_10bitSwFormatsVt = is8bitSwFormatsVt || string.Equals("yuv420p10le", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); - // Hardware surface only make sense when interop with OpenCL // VideoToolbox's Hardware surface in ffmpeg is not only slower than hwupload, but also breaks HDR in many cases. // For example: https://trac.ffmpeg.org/ticket/10884 - var useOclToneMapping = !IsVideoToolboxTonemapAvailable(state, options) - && options.EnableTonemapping - && state.VideoStream is not null - && GetVideoColorBitDepth(state) == 10 - && state.VideoStream.VideoRange == VideoRange.HDR - && (state.VideoStream.VideoRangeType == VideoRangeType.HDR10 - || state.VideoStream.VideoRangeType == VideoRangeType.HLG - || ((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"); + // Disable it for now. + const bool UseHwSurface = false; if (is8bitSwFormatsVt) { if (string.Equals("avc", videoStream.Codec, StringComparison.OrdinalIgnoreCase) || string.Equals("h264", videoStream.Codec, StringComparison.OrdinalIgnoreCase)) { - return GetHwaccelType(state, options, "h264", bitDepth, useHwSurface); + return GetHwaccelType(state, options, "h264", bitDepth, UseHwSurface); } if (string.Equals("mpeg2video", videoStream.Codec, StringComparison.OrdinalIgnoreCase)) { - return GetHwaccelType(state, options, "mpeg2video", bitDepth, useHwSurface); + return GetHwaccelType(state, options, "mpeg2video", bitDepth, UseHwSurface); } if (string.Equals("mpeg4", videoStream.Codec, StringComparison.OrdinalIgnoreCase)) { - return GetHwaccelType(state, options, "mpeg4", bitDepth, useHwSurface); + return GetHwaccelType(state, options, "mpeg4", bitDepth, UseHwSurface); } } @@ -6187,12 +6180,12 @@ namespace MediaBrowser.Controller.MediaEncoding if (string.Equals("hevc", videoStream.Codec, StringComparison.OrdinalIgnoreCase) || string.Equals("h265", videoStream.Codec, StringComparison.OrdinalIgnoreCase)) { - return GetHwaccelType(state, options, "hevc", bitDepth, useHwSurface); + return GetHwaccelType(state, options, "hevc", bitDepth, UseHwSurface); } if (string.Equals("vp9", videoStream.Codec, StringComparison.OrdinalIgnoreCase)) { - return GetHwaccelType(state, options, "vp9", bitDepth, useHwSurface); + return GetHwaccelType(state, options, "vp9", bitDepth, UseHwSurface); } } diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index 6579f1abe5..ae0284e3ab 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -130,6 +130,7 @@ namespace MediaBrowser.MediaEncoding.Encoder "yadif_videotoolbox", "scale_vt", "overlay_videotoolbox", + "tonemap_videotoolbox", // rkrga "scale_rkrga", "vpp_rkrga",