Sfoglia il codice sorgente

Merge pull request #9882 from nyanmisaka/fix-sync-amd-va-vk

Bond-009 2 anni fa
parent
commit
d874262bf9
1 ha cambiato i file con 196 aggiunte e 127 eliminazioni
  1. 196 127
      MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs

+ 196 - 127
MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs

@@ -163,7 +163,8 @@ namespace MediaBrowser.Controller.MediaEncoding
 
         private bool IsVaapiFullSupported()
         {
-            return _mediaEncoder.SupportsHwaccel("vaapi")
+            return _mediaEncoder.SupportsHwaccel("drm")
+                   && _mediaEncoder.SupportsHwaccel("vaapi")
                    && _mediaEncoder.SupportsFilter("scale_vaapi")
                    && _mediaEncoder.SupportsFilter("deinterlace_vaapi")
                    && _mediaEncoder.SupportsFilter("tonemap_vaapi")
@@ -713,28 +714,43 @@ namespace MediaBrowser.Controller.MediaEncoding
                 options);
         }
 
-        private string GetVaapiDeviceArgs(string renderNodePath, string driver, string kernelDriver, string alias)
+        private string GetVaapiDeviceArgs(string renderNodePath, string driver, string kernelDriver, string srcDeviceAlias, string alias)
         {
             alias ??= VaapiAlias;
             renderNodePath = renderNodePath ?? "/dev/dri/renderD128";
-            var options = string.IsNullOrEmpty(driver)
-                ? renderNodePath
-                : ",driver=" + driver + (string.IsNullOrEmpty(kernelDriver) ? string.Empty : ",kernel_driver=" + kernelDriver);
+            var driverOpts = string.IsNullOrEmpty(driver)
+                ? ":" + renderNodePath
+                : ":,driver=" + driver + (string.IsNullOrEmpty(kernelDriver) ? string.Empty : ",kernel_driver=" + kernelDriver);
+            var options = string.IsNullOrEmpty(srcDeviceAlias)
+                ? driverOpts
+                : "@" + srcDeviceAlias;
 
             return string.Format(
                 CultureInfo.InvariantCulture,
-                " -init_hw_device vaapi={0}:{1}",
+                " -init_hw_device vaapi={0}{1}",
                 alias,
                 options);
         }
 
+        private string GetDrmDeviceArgs(string renderNodePath, string alias)
+        {
+            alias ??= DrmAlias;
+            renderNodePath = renderNodePath ?? "/dev/dri/renderD128";
+
+            return string.Format(
+                CultureInfo.InvariantCulture,
+                " -init_hw_device drm={0}:{1}",
+                alias,
+                renderNodePath);
+        }
+
         private string GetQsvDeviceArgs(string alias)
         {
             var arg = " -init_hw_device qsv=" + (alias ?? QsvAlias);
             if (OperatingSystem.IsLinux())
             {
                 // derive qsv from vaapi device
-                return GetVaapiDeviceArgs(null, "iHD", "i915", VaapiAlias) + arg + "@" + VaapiAlias;
+                return GetVaapiDeviceArgs(null, "iHD", "i915", null, VaapiAlias) + arg + "@" + VaapiAlias;
             }
 
             if (OperatingSystem.IsWindows())
@@ -828,21 +844,17 @@ namespace MediaBrowser.Controller.MediaEncoding
 
                 if (_mediaEncoder.IsVaapiDeviceInteliHD)
                 {
-                    args.Append(GetVaapiDeviceArgs(null, "iHD", null, VaapiAlias));
+                    args.Append(GetVaapiDeviceArgs(null, "iHD", null, null, VaapiAlias));
                 }
                 else if (_mediaEncoder.IsVaapiDeviceInteli965)
                 {
                     // Only override i965 since it has lower priority than iHD in libva lookup.
                     Environment.SetEnvironmentVariable("LIBVA_DRIVER_NAME", "i965");
                     Environment.SetEnvironmentVariable("LIBVA_DRIVER_NAME_JELLYFIN", "i965");
-                    args.Append(GetVaapiDeviceArgs(null, "i965", null, VaapiAlias));
-                }
-                else
-                {
-                    args.Append(GetVaapiDeviceArgs(options.VaapiDevice, null, null, VaapiAlias));
+                    args.Append(GetVaapiDeviceArgs(null, "i965", null, null, VaapiAlias));
                 }
 
-                var filterDevArgs = GetFilterHwDeviceArgs(VaapiAlias);
+                var filterDevArgs = string.Empty;
                 var doOclTonemap = isHwTonemapAvailable && IsOpenclFullSupported();
 
                 if (_mediaEncoder.IsVaapiDeviceInteliHD || _mediaEncoder.IsVaapiDeviceInteli965)
@@ -859,15 +871,24 @@ namespace MediaBrowser.Controller.MediaEncoding
                         && _mediaEncoder.IsVaapiDeviceSupportVulkanFmtModifier
                         && Environment.OSVersion.Version >= _minKernelVersionAmdVkFmtModifier)
                     {
+                        args.Append(GetDrmDeviceArgs(options.VaapiDevice, DrmAlias));
+                        args.Append(GetVaapiDeviceArgs(null, null, null, DrmAlias, VaapiAlias));
+                        args.Append(GetVulkanDeviceArgs(0, null, DrmAlias, VulkanAlias));
+
                         // libplacebo wants an explicitly set vulkan filter device.
-                        args.Append(GetVulkanDeviceArgs(0, null, VaapiAlias, VulkanAlias));
                         filterDevArgs = GetFilterHwDeviceArgs(VulkanAlias);
                     }
-                    else if (doOclTonemap)
+                    else
                     {
-                        // ROCm/ROCr OpenCL runtime
-                        args.Append(GetOpenclDeviceArgs(0, "Advanced Micro Devices", null, OpenclAlias));
-                        filterDevArgs = GetFilterHwDeviceArgs(OpenclAlias);
+                        args.Append(GetVaapiDeviceArgs(options.VaapiDevice, null, null, null, VaapiAlias));
+                        filterDevArgs = GetFilterHwDeviceArgs(VaapiAlias);
+
+                        if (doOclTonemap)
+                        {
+                            // ROCm/ROCr OpenCL runtime
+                            args.Append(GetOpenclDeviceArgs(0, "Advanced Micro Devices", null, OpenclAlias));
+                            filterDevArgs = GetFilterHwDeviceArgs(OpenclAlias);
+                        }
                     }
                 }
                 else if (doOclTonemap)
@@ -3011,6 +3032,75 @@ namespace MediaBrowser.Controller.MediaEncoding
                     options.TonemappingRange);
         }
 
+        public string GetLibplaceboFilter(
+            EncodingOptions options,
+            string videoFormat,
+            bool doTonemap,
+            int? videoWidth,
+            int? videoHeight,
+            int? requestedWidth,
+            int? requestedHeight,
+            int? requestedMaxWidth,
+            int? requestedMaxHeight)
+        {
+            var (outWidth, outHeight) = GetFixedOutputSize(
+                videoWidth,
+                videoHeight,
+                requestedWidth,
+                requestedHeight,
+                requestedMaxWidth,
+                requestedMaxHeight);
+
+            var isFormatFixed = !string.IsNullOrEmpty(videoFormat);
+            var isSizeFixed = !videoWidth.HasValue
+                || outWidth.Value != videoWidth.Value
+                || !videoHeight.HasValue
+                || outHeight.Value != videoHeight.Value;
+
+            var sizeArg = isSizeFixed ? (":w=" + outWidth.Value + ":h=" + outHeight.Value) : string.Empty;
+            var formatArg = isFormatFixed ? (":format=" + videoFormat) : string.Empty;
+            var tonemapArg = string.Empty;
+
+            if (doTonemap)
+            {
+                var algorithm = options.TonemappingAlgorithm;
+                var mode = options.TonemappingMode;
+                var range = options.TonemappingRange;
+
+                if (string.Equals(algorithm, "bt2390", StringComparison.OrdinalIgnoreCase))
+                {
+                    algorithm = "bt.2390";
+                }
+                else if (string.Equals(algorithm, "none", StringComparison.OrdinalIgnoreCase))
+                {
+                    algorithm = "clip";
+                }
+
+                tonemapArg = ":tonemapping=" + algorithm;
+
+                if (string.Equals(mode, "max", StringComparison.OrdinalIgnoreCase)
+                    || string.Equals(mode, "rgb", StringComparison.OrdinalIgnoreCase))
+                {
+                    tonemapArg += ":tonemapping_mode=" + mode;
+                }
+
+                tonemapArg += ":peak_detect=0:color_primaries=bt709:color_trc=bt709:colorspace=bt709";
+
+                if (string.Equals(range, "tv", StringComparison.OrdinalIgnoreCase)
+                    || string.Equals(range, "pc", StringComparison.OrdinalIgnoreCase))
+                {
+                    tonemapArg += ":range=" + range;
+                }
+            }
+
+            return string.Format(
+                CultureInfo.InvariantCulture,
+                "libplacebo=upscaler=none:downscaler=none{0}{1}{2}",
+                sizeArg,
+                formatArg,
+                tonemapArg);
+        }
+
         /// <summary>
         /// Gets the parameter of software filter chain.
         /// </summary>
@@ -4240,7 +4330,6 @@ namespace MediaBrowser.Controller.MediaEncoding
             var isVaapiEncoder = vidEncoder.Contains("vaapi", StringComparison.OrdinalIgnoreCase);
             var isSwDecoder = string.IsNullOrEmpty(vidDecoder);
             var isSwEncoder = !isVaapiEncoder;
-            var isVaInVaOut = isVaapiDecoder && isVaapiEncoder;
 
             var doDeintH264 = state.DeInterlace("h264", true) || state.DeInterlace("avc", true);
             var doDeintHevc = state.DeInterlace("h265", true) || state.DeInterlace("hevc", true);
@@ -4269,99 +4358,81 @@ namespace MediaBrowser.Controller.MediaEncoding
                     mainFilters.Add(swDeintFilter);
                 }
 
-                var outFormat = doVkTonemap ? "yuv420p10le" : "nv12";
-                var swScaleFilter = GetSwScaleFilter(state, options, vidEncoder, inW, inH, threeDFormat, reqW, reqH, reqMaxW, reqMaxH);
-                // sw scale
-                mainFilters.Add(swScaleFilter);
-                mainFilters.Add("format=" + outFormat);
-
-                // keep video at memory except vk tonemap,
-                // since the overhead caused by hwupload >>> using sw filter.
-                // sw => hw
-                if (doVkTonemap)
+                if (doVkTonemap || hasSubs)
                 {
-                    mainFilters.Add("hwupload=derive_device=vaapi");
-                    mainFilters.Add("format=vaapi");
-                    mainFilters.Add("hwmap=derive_device=vulkan");
+                    // sw => hw
+                    mainFilters.Add("hwupload=derive_device=vulkan");
                     mainFilters.Add("format=vulkan");
                 }
+                else
+                {
+                    // sw scale
+                    var swScaleFilter = GetSwScaleFilter(state, options, vidEncoder, inW, inH, threeDFormat, reqW, reqH, reqMaxW, reqMaxH);
+                    mainFilters.Add(swScaleFilter);
+                    mainFilters.Add("format=nv12");
+                }
             }
             else if (isVaapiDecoder)
             {
                 // INPUT vaapi surface(vram)
-                // hw deint
-                if (doDeintH2645)
+                if (doVkTonemap || hasSubs)
                 {
-                    var deintFilter = GetHwDeinterlaceFilter(state, options, "vaapi");
-                    mainFilters.Add(deintFilter);
+                    // map from vaapi to vulkan/drm via interop (Vega/gfx9+).
+                    mainFilters.Add("hwmap=derive_device=vulkan");
+                    mainFilters.Add("format=vulkan");
                 }
-
-                var outFormat = doVkTonemap ? string.Empty : (hasSubs && isVaInVaOut ? "bgra" : "nv12");
-                var hwScaleFilter = GetHwScaleFilter("vaapi", outFormat, inW, inH, reqW, reqH, reqMaxW, reqMaxH);
-
-                // allocate extra pool sizes for overlay_vulkan
-                if (!string.IsNullOrEmpty(hwScaleFilter) && isVaInVaOut && hasSubs)
+                else
                 {
-                    hwScaleFilter += ":extra_hw_frames=32";
-                }
-
-                // hw scale
-                mainFilters.Add(hwScaleFilter);
-            }
+                    // hw deint
+                    if (doDeintH2645)
+                    {
+                        var deintFilter = GetHwDeinterlaceFilter(state, options, "vaapi");
+                        mainFilters.Add(deintFilter);
+                    }
 
-            if ((isVaapiDecoder && doVkTonemap) || (isVaInVaOut && (doVkTonemap || hasSubs)))
-            {
-                // map from vaapi to vulkan via vaapi-vulkan interop (Vega/gfx9+).
-                mainFilters.Add("hwmap=derive_device=vulkan");
-                mainFilters.Add("format=vulkan");
+                    // hw scale
+                    var hwScaleFilter = GetHwScaleFilter("vaapi", "nv12", inW, inH, reqW, reqH, reqMaxW, reqMaxH);
+                    mainFilters.Add(hwScaleFilter);
+                }
             }
 
-            // vk tonemap
-            if (doVkTonemap)
+            // vk libplacebo
+            if (doVkTonemap || hasSubs)
             {
-                var outFormat = isVaInVaOut && hasSubs ? "bgra" : "nv12";
-                var tonemapFilter = GetHwTonemapFilter(options, "vulkan", outFormat);
-                mainFilters.Add(tonemapFilter);
+                var libplaceboFilter = GetLibplaceboFilter(options, "bgra", doVkTonemap, inW, inH, reqW, reqH, reqMaxW, reqMaxH);
+                mainFilters.Add(libplaceboFilter);
             }
 
-            if (doVkTonemap && isVaInVaOut && !hasSubs)
+            if (doVkTonemap && !hasSubs)
             {
-                // OUTPUT vaapi(nv12/bgra) surface(vram)
-                // reverse-mapping via vaapi-vulkan interop.
-                mainFilters.Add("hwmap=derive_device=vaapi:reverse=1");
+                // OUTPUT vaapi(nv12) surface(vram)
+                // map from vulkan/drm to vaapi via interop (Vega/gfx9+).
+                mainFilters.Add("hwmap=derive_device=drm");
+                mainFilters.Add("format=drm_prime");
+                mainFilters.Add("hwmap=derive_device=vaapi");
                 mainFilters.Add("format=vaapi");
-            }
 
-            var memoryOutput = false;
-            var isUploadForVkTonemap = isSwDecoder && doVkTonemap;
-            if ((isVaapiDecoder && isSwEncoder) || isUploadForVkTonemap)
-            {
-                memoryOutput = true;
+                // clear the surf->meta_offset and output nv12
+                mainFilters.Add("scale_vaapi=format=nv12");
 
-                // OUTPUT nv12 surface(memory)
-                mainFilters.Add("hwdownload");
-                mainFilters.Add("format=nv12");
-            }
-
-            // OUTPUT nv12 surface(memory)
-            if (isSwDecoder && isVaapiEncoder)
-            {
-                memoryOutput = true;
+                // hw deint
+                if (doDeintH2645)
+                {
+                    var deintFilter = GetHwDeinterlaceFilter(state, options, "vaapi");
+                    mainFilters.Add(deintFilter);
+                }
             }
 
-            if (memoryOutput)
+            if (!hasSubs)
             {
-                // text subtitles
-                if (hasTextSubs)
+                // OUTPUT nv12 surface(memory)
+                if (isSwEncoder && (doVkTonemap || isVaapiDecoder))
                 {
-                    var textSubtitlesFilter = GetTextSubtitlesFilter(state, false, false);
-                    mainFilters.Add(textSubtitlesFilter);
+                    mainFilters.Add("hwdownload");
+                    mainFilters.Add("format=nv12");
                 }
-            }
 
-            if (memoryOutput && isVaapiEncoder)
-            {
-                if (!hasGraphicalSubs)
+                if (isSwDecoder && isVaapiEncoder && !doVkTonemap)
                 {
                     mainFilters.Add("hwupload_vaapi");
                 }
@@ -4370,55 +4441,53 @@ namespace MediaBrowser.Controller.MediaEncoding
             /* Make sub and overlay filters for subtitle stream */
             var subFilters = new List<string>();
             var overlayFilters = new List<string>();
-            if (isVaInVaOut)
+            if (hasSubs)
             {
-                if (hasSubs)
+                if (hasGraphicalSubs)
                 {
-                    if (hasGraphicalSubs)
-                    {
-                        // scale=s=1280x720,format=bgra,hwupload
-                        var subSwScaleFilter = GetCustomSwScaleFilter(inW, inH, reqW, reqH, reqMaxW, reqMaxH);
-                        subFilters.Add(subSwScaleFilter);
-                        subFilters.Add("format=bgra");
-                    }
-                    else if (hasTextSubs)
-                    {
-                        var alphaSrcFilter = GetAlphaSrcFilter(state, inW, inH, reqW, reqH, reqMaxW, reqMaxH, hasAssSubs ? 10 : 5);
-                        var subTextSubtitlesFilter = GetTextSubtitlesFilter(state, true, true);
-                        subFilters.Add(alphaSrcFilter);
-                        subFilters.Add("format=bgra");
-                        subFilters.Add(subTextSubtitlesFilter);
-                    }
-
-                    // prefer vaapi hwupload to vulkan hwupload,
-                    // Mesa RADV does not support a dedicated transfer queue.
-                    subFilters.Add("hwupload=derive_device=vaapi");
-                    subFilters.Add("format=vaapi");
-                    subFilters.Add("hwmap=derive_device=vulkan");
-                    subFilters.Add("format=vulkan");
+                    // scale=s=1280x720,format=bgra,hwupload
+                    var subSwScaleFilter = GetCustomSwScaleFilter(inW, inH, reqW, reqH, reqMaxW, reqMaxH);
+                    subFilters.Add(subSwScaleFilter);
+                    subFilters.Add("format=bgra");
+                }
+                else if (hasTextSubs)
+                {
+                    var alphaSrcFilter = GetAlphaSrcFilter(state, inW, inH, reqW, reqH, reqMaxW, reqMaxH, hasAssSubs ? 10 : 5);
+                    var subTextSubtitlesFilter = GetTextSubtitlesFilter(state, true, true);
+                    subFilters.Add(alphaSrcFilter);
+                    subFilters.Add("format=bgra");
+                    subFilters.Add(subTextSubtitlesFilter);
+                }
 
-                    overlayFilters.Add("overlay_vulkan=eof_action=endall:shortest=1:repeatlast=0");
+                subFilters.Add("hwupload=derive_device=vulkan");
+                subFilters.Add("format=vulkan");
 
-                    // TODO: figure out why libplacebo can sync without vaSyncSurface VPP support in radeonsi.
-                    overlayFilters.Add("libplacebo=format=nv12:apply_filmgrain=0:apply_dolbyvision=0:upscaler=none:downscaler=none:dithering=none");
+                overlayFilters.Add("overlay_vulkan=eof_action=endall:shortest=1:repeatlast=0");
 
-                    // OUTPUT vaapi(nv12/bgra) surface(vram)
-                    // reverse-mapping via vaapi-vulkan interop.
-                    overlayFilters.Add("hwmap=derive_device=vaapi:reverse=1");
-                    overlayFilters.Add("format=vaapi");
+                if (isSwEncoder)
+                {
+                    // OUTPUT nv12 surface(memory)
+                    overlayFilters.Add("scale_vulkan=format=nv12");
+                    overlayFilters.Add("hwdownload");
+                    overlayFilters.Add("format=nv12");
                 }
-            }
-            else if (memoryOutput)
-            {
-                if (hasGraphicalSubs)
+                else if (isVaapiEncoder)
                 {
-                    var subSwScaleFilter = GetCustomSwScaleFilter(inW, inH, reqW, reqH, reqMaxW, reqMaxH);
-                    subFilters.Add(subSwScaleFilter);
-                    overlayFilters.Add("overlay=eof_action=pass:shortest=1:repeatlast=0");
+                    // OUTPUT vaapi(nv12) surface(vram)
+                    // map from vulkan/drm to vaapi via interop (Vega/gfx9+).
+                    overlayFilters.Add("hwmap=derive_device=drm");
+                    overlayFilters.Add("format=drm_prime");
+                    overlayFilters.Add("hwmap=derive_device=vaapi");
+                    overlayFilters.Add("format=vaapi");
 
-                    if (isVaapiEncoder)
+                    // clear the surf->meta_offset and output nv12
+                    overlayFilters.Add("scale_vaapi=format=nv12");
+
+                    // hw deint
+                    if (doDeintH2645)
                     {
-                        overlayFilters.Add("hwupload_vaapi");
+                        var deintFilter = GetHwDeinterlaceFilter(state, options, "vaapi");
+                        overlayFilters.Add(deintFilter);
                     }
                 }
             }