Przeglądaj źródła

add vpp tonemapping for vaapi

nyanmisaka 4 lat temu
rodzic
commit
09b9fa3ce1

+ 66 - 26
MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs

@@ -127,6 +127,25 @@ namespace MediaBrowser.Controller.MediaEncoding
                    && videoStream.VideoRange.Contains("HDR", StringComparison.OrdinalIgnoreCase);
                    && videoStream.VideoRange.Contains("HDR", StringComparison.OrdinalIgnoreCase);
         }
         }
 
 
+        private bool IsVppTonemappingSupported(EncodingJobInfo state, EncodingOptions options)
+        {
+            var videoStream = state.VideoStream;
+            var codec = videoStream.Codec;
+            if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase))
+            {
+                // Limited to HEVC for now since the filter doesn't accept master data from VP9.
+                return IsColorDepth10(state)
+                       && string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
+                       && _mediaEncoder.SupportsHwaccel("vaapi")
+                       && options.EnableVppTonemapping
+                       && !string.IsNullOrEmpty(videoStream.ColorTransfer)
+                       && videoStream.ColorTransfer.Equals("smpte2084", StringComparison.OrdinalIgnoreCase);
+            }
+
+            // Vpp tonemapping may come to QSV in the future.
+            return false;
+        }
+
         /// <summary>
         /// <summary>
         /// Gets the name of the output video codec.
         /// Gets the name of the output video codec.
         /// </summary>
         /// </summary>
@@ -469,6 +488,7 @@ namespace MediaBrowser.Controller.MediaEncoding
             var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
             var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
             var isMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
             var isMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
             var isTonemappingSupported = IsTonemappingSupported(state, encodingOptions);
             var isTonemappingSupported = IsTonemappingSupported(state, encodingOptions);
+            var isVppTonemappingSupported = IsVppTonemappingSupported(state, encodingOptions);
 
 
             if (!IsCopyCodec(outputVideoCodec))
             if (!IsCopyCodec(outputVideoCodec))
             {
             {
@@ -478,7 +498,7 @@ namespace MediaBrowser.Controller.MediaEncoding
                 {
                 {
                     if (isVaapiDecoder)
                     if (isVaapiDecoder)
                     {
                     {
-                        if (isTonemappingSupported)
+                        if (isTonemappingSupported && !isVppTonemappingSupported)
                         {
                         {
                            arg.Append("-init_hw_device vaapi=va:")
                            arg.Append("-init_hw_device vaapi=va:")
                                 .Append(encodingOptions.VaapiDevice)
                                 .Append(encodingOptions.VaapiDevice)
@@ -938,7 +958,7 @@ namespace MediaBrowser.Controller.MediaEncoding
                 var videoStream = state.VideoStream;
                 var videoStream = state.VideoStream;
                 var isColorDepth10 = IsColorDepth10(state);
                 var isColorDepth10 = IsColorDepth10(state);
                 var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions) ?? string.Empty;
                 var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions) ?? string.Empty;
-                var isNvdecDecoder = videoDecoder.IndexOf("cuda", StringComparison.OrdinalIgnoreCase) != -1;
+                var isNvdecDecoder = videoDecoder.Contains("cuda", StringComparison.OrdinalIgnoreCase);
 
 
                 if (!isNvdecDecoder)
                 if (!isNvdecDecoder)
                 {
                 {
@@ -1932,14 +1952,15 @@ namespace MediaBrowser.Controller.MediaEncoding
             var isVaapiDecoder = videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1;
             var isVaapiDecoder = videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1;
             var isVaapiH264Encoder = outputVideoCodec.IndexOf("h264_vaapi", StringComparison.OrdinalIgnoreCase) != -1;
             var isVaapiH264Encoder = outputVideoCodec.IndexOf("h264_vaapi", StringComparison.OrdinalIgnoreCase) != -1;
             var isVaapiHevcEncoder = outputVideoCodec.IndexOf("hevc_vaapi", StringComparison.OrdinalIgnoreCase) != -1;
             var isVaapiHevcEncoder = outputVideoCodec.IndexOf("hevc_vaapi", StringComparison.OrdinalIgnoreCase) != -1;
-            var isNvdecDecoder = videoDecoder.IndexOf("cuda", StringComparison.OrdinalIgnoreCase) != -1;
-            var isNvencEncoder = outputVideoCodec.IndexOf("nvenc", StringComparison.OrdinalIgnoreCase) != -1;
+            var isNvdecDecoder = videoDecoder.Contains("cuda", StringComparison.OrdinalIgnoreCase);
+            var isNvencEncoder = outputVideoCodec.Contains("nvenc", StringComparison.OrdinalIgnoreCase);
             var isTonemappingSupported = IsTonemappingSupported(state, options);
             var isTonemappingSupported = IsTonemappingSupported(state, options);
+            var isVppTonemappingSupported = IsVppTonemappingSupported(state, options);
             var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder);
             var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder);
 
 
             // Tonemapping and burn-in graphical subtitles requires overlay_vaapi.
             // Tonemapping and burn-in graphical subtitles requires overlay_vaapi.
             // But it's still in ffmpeg mailing list. Disable it for now.
             // But it's still in ffmpeg mailing list. Disable it for now.
-            if (isTonemappingSupported && isTonemappingSupportedOnVaapi)
+            if (isTonemappingSupported && isTonemappingSupportedOnVaapi && !isVppTonemappingSupported)
             {
             {
                 return GetOutputSizeParam(state, options, outputVideoCodec);
                 return GetOutputSizeParam(state, options, outputVideoCodec);
             }
             }
@@ -2123,17 +2144,24 @@ namespace MediaBrowser.Controller.MediaEncoding
                     || state.DeInterlace("h265", true)
                     || state.DeInterlace("h265", true)
                     || state.DeInterlace("hevc", true);
                     || state.DeInterlace("hevc", true);
 
 
+                var isVaapiDecoder = videoDecoder.Contains("vaapi", StringComparison.OrdinalIgnoreCase);
+                var isVaapiH264Encoder = videoEncoder.Contains("h264_vaapi", StringComparison.OrdinalIgnoreCase);
+                var isVaapiHevcEncoder = videoEncoder.Contains("hevc_vaapi", StringComparison.OrdinalIgnoreCase);
                 var isTonemappingSupported = IsTonemappingSupported(state, options);
                 var isTonemappingSupported = IsTonemappingSupported(state, options);
-                var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && !qsv_or_vaapi;
+                var isVppTonemappingSupported = IsVppTonemappingSupported(state, options);
+                var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder);
 
 
-                var outputPixFmt = string.Empty;
-                if (isTonemappingSupported && isTonemappingSupportedOnVaapi)
-                {
-                    outputPixFmt = "format=p010:out_range=limited";
-                }
-                else
+                var outputPixFmt = "format=nv12";
+                if (isTonemappingSupportedOnVaapi)
                 {
                 {
-                    outputPixFmt = "format=nv12";
+                    if (isVppTonemappingSupported)
+                    {
+                        outputPixFmt = "format=p010";
+                    }
+                    else if (isTonemappingSupported)
+                    {
+                        outputPixFmt = "format=p010:out_range=limited";
+                    }
                 }
                 }
 
 
                 if (!videoWidth.HasValue
                 if (!videoWidth.HasValue
@@ -2164,7 +2192,7 @@ namespace MediaBrowser.Controller.MediaEncoding
                             (qsv_or_vaapi && isDeintEnabled) ? ":deinterlace=1" : string.Empty));
                             (qsv_or_vaapi && isDeintEnabled) ? ":deinterlace=1" : string.Empty));
                 }
                 }
             }
             }
-            else if ((videoDecoder ?? string.Empty).IndexOf("cuda", StringComparison.OrdinalIgnoreCase) != -1
+            else if ((videoDecoder ?? string.Empty).Contains("cuda", StringComparison.OrdinalIgnoreCase)
                 && width.HasValue
                 && width.HasValue
                 && height.HasValue)
                 && height.HasValue)
             {
             {
@@ -2418,15 +2446,16 @@ namespace MediaBrowser.Controller.MediaEncoding
             var isVaapiHevcEncoder = outputVideoCodec.IndexOf("hevc_vaapi", StringComparison.OrdinalIgnoreCase) != -1;
             var isVaapiHevcEncoder = outputVideoCodec.IndexOf("hevc_vaapi", StringComparison.OrdinalIgnoreCase) != -1;
             var isQsvH264Encoder = outputVideoCodec.IndexOf("h264_qsv", StringComparison.OrdinalIgnoreCase) != -1;
             var isQsvH264Encoder = outputVideoCodec.IndexOf("h264_qsv", StringComparison.OrdinalIgnoreCase) != -1;
             var isQsvHevcEncoder = outputVideoCodec.IndexOf("hevc_qsv", StringComparison.OrdinalIgnoreCase) != -1;
             var isQsvHevcEncoder = outputVideoCodec.IndexOf("hevc_qsv", StringComparison.OrdinalIgnoreCase) != -1;
-            var isNvdecDecoder = videoDecoder.IndexOf("cuda", StringComparison.OrdinalIgnoreCase) != -1;
-            var isNvencEncoder = outputVideoCodec.IndexOf("nvenc", StringComparison.OrdinalIgnoreCase) != -1;
-            var isCuvidH264Decoder = videoDecoder.IndexOf("h264_cuvid", StringComparison.OrdinalIgnoreCase) != -1;
-            var isCuvidHevcDecoder = videoDecoder.IndexOf("hevc_cuvid", StringComparison.OrdinalIgnoreCase) != -1;
+            var isNvdecDecoder = videoDecoder.Contains("cuda", StringComparison.OrdinalIgnoreCase);
+            var isNvencEncoder = outputVideoCodec.Contains("nvenc", StringComparison.OrdinalIgnoreCase);
+            var isCuvidH264Decoder = videoDecoder.Contains("h264_cuvid", StringComparison.OrdinalIgnoreCase);
+            var isCuvidHevcDecoder = videoDecoder.Contains("hevc_cuvid", StringComparison.OrdinalIgnoreCase);
             var isLibX264Encoder = outputVideoCodec.IndexOf("libx264", StringComparison.OrdinalIgnoreCase) != -1;
             var isLibX264Encoder = outputVideoCodec.IndexOf("libx264", StringComparison.OrdinalIgnoreCase) != -1;
             var isLibX265Encoder = outputVideoCodec.IndexOf("libx265", StringComparison.OrdinalIgnoreCase) != -1;
             var isLibX265Encoder = outputVideoCodec.IndexOf("libx265", StringComparison.OrdinalIgnoreCase) != -1;
             var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
             var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
             var isColorDepth10 = IsColorDepth10(state);
             var isColorDepth10 = IsColorDepth10(state);
             var isTonemappingSupported = IsTonemappingSupported(state, options);
             var isTonemappingSupported = IsTonemappingSupported(state, options);
+            var isVppTonemappingSupported = IsVppTonemappingSupported(state, options);
             var isTonemappingSupportedOnNvenc = string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && (isNvdecDecoder || isCuvidHevcDecoder || isSwDecoder);
             var isTonemappingSupportedOnNvenc = string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && (isNvdecDecoder || isCuvidHevcDecoder || isSwDecoder);
             var isTonemappingSupportedOnAmf = string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) && (isD3d11vaDecoder || isSwDecoder);
             var isTonemappingSupportedOnAmf = string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) && (isD3d11vaDecoder || isSwDecoder);
             var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder);
             var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder);
@@ -2444,7 +2473,8 @@ namespace MediaBrowser.Controller.MediaEncoding
             var isDeinterlaceH264 = state.DeInterlace("h264", true) || state.DeInterlace("avc", true);
             var isDeinterlaceH264 = state.DeInterlace("h264", true) || state.DeInterlace("avc", true);
             var isDeinterlaceHevc = state.DeInterlace("h265", true) || state.DeInterlace("hevc", true);
             var isDeinterlaceHevc = state.DeInterlace("h265", true) || state.DeInterlace("hevc", true);
 
 
-            if (isTonemappingSupportedOnNvenc || isTonemappingSupportedOnAmf || isTonemappingSupportedOnVaapi)
+            // Add OpenCL tonemapping filter for NVENC/AMF/VAAPI.
+            if (isTonemappingSupportedOnNvenc || isTonemappingSupportedOnAmf || (isTonemappingSupportedOnVaapi && !isVppTonemappingSupported))
             {
             {
                 // Currently only with the use of NVENC decoder can we get a decent performance.
                 // Currently only with the use of NVENC decoder can we get a decent performance.
                 // Currently only the HEVC/H265 format is supported with NVDEC decoder.
                 // Currently only the HEVC/H265 format is supported with NVDEC decoder.
@@ -2490,7 +2520,7 @@ namespace MediaBrowser.Controller.MediaEncoding
                         filters.Add(
                         filters.Add(
                             string.Format(
                             string.Format(
                                 CultureInfo.InvariantCulture,
                                 CultureInfo.InvariantCulture,
-                                "yadif={0}:-1:0",
+                                "yadif_cuda={0}:-1:0",
                                 doubleRateDeinterlace ? "1" : "0"));
                                 doubleRateDeinterlace ? "1" : "0"));
                     }
                     }
 
 
@@ -2563,7 +2593,10 @@ namespace MediaBrowser.Controller.MediaEncoding
             }
             }
 
 
             // When the input may or may not be hardware VAAPI decodable.
             // When the input may or may not be hardware VAAPI decodable.
-            if ((isVaapiH264Encoder || isVaapiHevcEncoder) && !isTonemappingSupported && !isTonemappingSupportedOnVaapi)
+            if ((isVaapiH264Encoder || isVaapiHevcEncoder)
+                && !isTonemappingSupported
+                && !isVppTonemappingSupported
+                && !isTonemappingSupportedOnVaapi)
             {
             {
                 filters.Add("format=nv12|vaapi");
                 filters.Add("format=nv12|vaapi");
                 filters.Add("hwupload");
                 filters.Add("hwupload");
@@ -2668,21 +2701,28 @@ namespace MediaBrowser.Controller.MediaEncoding
                         request.MaxHeight));
                         request.MaxHeight));
             }
             }
 
 
-            // Another case is using Nvenc decoder.
+            // Add Vpp tonemapping filter for VAAPI.
+            // Full hardware based video post processing, faster than OpenCL but lacks fine tuning options.
+            if (isTonemappingSupportedOnVaapi && isVppTonemappingSupported)
+            {
+                filters.Add("tonemap_vaapi=format=nv12:transfer=bt709:matrix=bt709:primaries=bt709");
+            }
+
+            // Another case is when using Nvenc decoder.
             if (isNvdecDecoder && !isTonemappingSupported)
             if (isNvdecDecoder && !isTonemappingSupported)
             {
             {
-                var codec = videoStream.Codec.ToLowerInvariant();
+                var codec = videoStream.Codec;
 
 
                 // Assert 10-bit hardware decodable
                 // Assert 10-bit hardware decodable
                 if (isColorDepth10 && (string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
                 if (isColorDepth10 && (string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
                     || string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase)
                     || string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase)
                     || string.Equals(codec, "vp9", StringComparison.OrdinalIgnoreCase)))
                     || string.Equals(codec, "vp9", StringComparison.OrdinalIgnoreCase)))
                 {
                 {
-                    // Download data from GPU to CPU as p010le format.
+                    // Download data from GPU to CPU as p010 format.
                     filters.Add("hwdownload");
                     filters.Add("hwdownload");
                     filters.Add("format=p010");
                     filters.Add("format=p010");
 
 
-                    // cuda lacks of a pixel format converter.
+                    // Cuda lacks of a pixel format converter.
                     if (isNvencEncoder)
                     if (isNvencEncoder)
                     {
                     {
                         isHwuploadCudaRequired = true;
                         isHwuploadCudaRequired = true;
@@ -2710,7 +2750,7 @@ namespace MediaBrowser.Controller.MediaEncoding
                 {
                 {
                     // Convert hw context from ocl to va.
                     // Convert hw context from ocl to va.
                     // For tonemapping and text subs burn-in.
                     // For tonemapping and text subs burn-in.
-                    if (isTonemappingSupported && isTonemappingSupportedOnVaapi)
+                    if (isTonemappingSupported && isTonemappingSupportedOnVaapi && !isVppTonemappingSupported)
                     {
                     {
                         filters.Add("scale_vaapi");
                         filters.Add("scale_vaapi");
                     }
                     }

+ 3 - 0
MediaBrowser.Model/Configuration/EncodingOptions.cs

@@ -39,6 +39,8 @@ namespace MediaBrowser.Model.Configuration
 
 
         public bool EnableTonemapping { get; set; }
         public bool EnableTonemapping { get; set; }
 
 
+        public bool EnableVppTonemapping { get; set; }
+
         public string TonemappingAlgorithm { get; set; }
         public string TonemappingAlgorithm { get; set; }
 
 
         public string TonemappingRange { get; set; }
         public string TonemappingRange { get; set; }
@@ -90,6 +92,7 @@ namespace MediaBrowser.Model.Configuration
             // The left side of the dot is the platform number, and the right side is the device number on the platform.
             // The left side of the dot is the platform number, and the right side is the device number on the platform.
             OpenclDevice = "0.0";
             OpenclDevice = "0.0";
             EnableTonemapping = false;
             EnableTonemapping = false;
+            EnableVppTonemapping = false;
             TonemappingAlgorithm = "hable";
             TonemappingAlgorithm = "hable";
             TonemappingRange = "auto";
             TonemappingRange = "auto";
             TonemappingDesat = 0;
             TonemappingDesat = 0;