Procházet zdrojové kódy

Backport pull request #8213 from jellyfin/release-10.8.z

Fix high single thread usage in throttler

Original-merge: ba026716c1609941ec50a26e50ef5e68cc84d0c0

Merged-by: Claus Vium <cvium@users.noreply.github.com>

Backported-by: Joshua M. Boniface <joshua@boniface.me>
nyanmisaka před 2 roky
rodič
revize
0309c5622e

+ 1 - 1
Jellyfin.Api/Helpers/TranscodingJobHelper.cs

@@ -654,7 +654,7 @@ namespace Jellyfin.Api.Helpers
         {
             if (EnableThrottling(state))
             {
-                transcodingJob.TranscodingThrottler = new TranscodingThrottler(transcodingJob, new Logger<TranscodingThrottler>(new LoggerFactory()), _serverConfigurationManager, _fileSystem);
+                transcodingJob.TranscodingThrottler = new TranscodingThrottler(transcodingJob, new Logger<TranscodingThrottler>(new LoggerFactory()), _serverConfigurationManager, _fileSystem, _mediaEncoder);
                 transcodingJob.TranscodingThrottler.Start();
             }
         }

+ 11 - 4
Jellyfin.Api/Models/PlaybackDtos/TranscodingThrottler.cs

@@ -2,6 +2,7 @@
 using System.Threading;
 using System.Threading.Tasks;
 using MediaBrowser.Common.Configuration;
+using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.IO;
 using Microsoft.Extensions.Logging;
@@ -17,6 +18,7 @@ namespace Jellyfin.Api.Models.PlaybackDtos
         private readonly ILogger<TranscodingThrottler> _logger;
         private readonly IConfigurationManager _config;
         private readonly IFileSystem _fileSystem;
+        private readonly IMediaEncoder _mediaEncoder;
         private Timer? _timer;
         private bool _isPaused;
 
@@ -27,12 +29,14 @@ namespace Jellyfin.Api.Models.PlaybackDtos
         /// <param name="logger">Instance of the <see cref="ILogger{TranscodingThrottler}"/> interface.</param>
         /// <param name="config">Instance of the <see cref="IConfigurationManager"/> interface.</param>
         /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
-        public TranscodingThrottler(TranscodingJobDto job, ILogger<TranscodingThrottler> logger, IConfigurationManager config, IFileSystem fileSystem)
+        /// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param>
+        public TranscodingThrottler(TranscodingJobDto job, ILogger<TranscodingThrottler> logger, IConfigurationManager config, IFileSystem fileSystem, IMediaEncoder mediaEncoder)
         {
             _job = job;
             _logger = logger;
             _config = config;
             _fileSystem = fileSystem;
+            _mediaEncoder = mediaEncoder;
         }
 
         /// <summary>
@@ -55,7 +59,8 @@ namespace Jellyfin.Api.Models.PlaybackDtos
 
                 try
                 {
-                    await _job.Process!.StandardInput.WriteLineAsync().ConfigureAwait(false);
+                    var resumeKey = _mediaEncoder.IsPkeyPauseSupported ? "u" : Environment.NewLine;
+                    await _job.Process!.StandardInput.WriteAsync(resumeKey).ConfigureAwait(false);
                     _isPaused = false;
                 }
                 catch (Exception ex)
@@ -125,11 +130,13 @@ namespace Jellyfin.Api.Models.PlaybackDtos
         {
             if (!_isPaused)
             {
-                _logger.LogDebug("Sending pause command to ffmpeg");
+                var pauseKey = _mediaEncoder.IsPkeyPauseSupported ? "p" : "c";
+
+                _logger.LogDebug("Sending pause command [{Key}] to ffmpeg", pauseKey);
 
                 try
                 {
-                    await _job.Process!.StandardInput.WriteAsync("c").ConfigureAwait(false);
+                    await _job.Process!.StandardInput.WriteAsync(pauseKey).ConfigureAwait(false);
                     _isPaused = true;
                 }
                 catch (Exception ex)

+ 6 - 0
MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs

@@ -37,6 +37,12 @@ namespace MediaBrowser.Controller.MediaEncoding
         /// <returns>The version of encoder.</returns>
         Version EncoderVersion { get; }
 
+        /// <summary>
+        /// Whether p key pausing is supported.
+        /// </summary>
+        /// <value><c>true</c> if p key pausing is supported, <c>false</c> otherwise.</value>
+        bool IsPkeyPauseSupported { get; }
+
         /// <summary>
         /// Gets a value indicating whether the configured Vaapi device is from AMD(radeonsi/r600 Mesa driver).
         /// </summary>

+ 35 - 8
MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs

@@ -153,7 +153,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
             string output;
             try
             {
-                output = GetProcessOutput(_encoderPath, "-version", false);
+                output = GetProcessOutput(_encoderPath, "-version", false, null);
             }
             catch (Exception ex)
             {
@@ -234,7 +234,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
             string output;
             try
             {
-                output = GetProcessOutput(_encoderPath, "-version", false);
+                output = GetProcessOutput(_encoderPath, "-version", false, null);
             }
             catch (Exception ex)
             {
@@ -341,7 +341,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
             try
             {
-                var output = GetProcessOutput(_encoderPath, "-v verbose -hide_banner -init_hw_device vaapi=va:" + renderNodePath, true);
+                var output = GetProcessOutput(_encoderPath, "-v verbose -hide_banner -init_hw_device vaapi=va:" + renderNodePath, true, null);
                 return output.Contains(driverName, StringComparison.Ordinal);
             }
             catch (Exception ex)
@@ -356,7 +356,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
             string? output = null;
             try
             {
-                output = GetProcessOutput(_encoderPath, "-hwaccels", false);
+                output = GetProcessOutput(_encoderPath, "-hwaccels", false, null);
             }
             catch (Exception ex)
             {
@@ -384,7 +384,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
             string output;
             try
             {
-                output = GetProcessOutput(_encoderPath, "-h filter=" + filter, false);
+                output = GetProcessOutput(_encoderPath, "-h filter=" + filter, false, null);
             }
             catch (Exception ex)
             {
@@ -402,13 +402,34 @@ namespace MediaBrowser.MediaEncoding.Encoder
             return false;
         }
 
+        public bool CheckSupportedRuntimeKey(string keyDesc)
+        {
+            if (string.IsNullOrEmpty(keyDesc))
+            {
+                return false;
+            }
+
+            string output;
+            try
+            {
+                output = GetProcessOutput(_encoderPath, "-hide_banner -f lavfi -i nullsrc=s=1x1:d=500 -f null -", true, "?");
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError(ex, "Error checking supported runtime key");
+                return false;
+            }
+
+            return output.Contains(keyDesc, StringComparison.Ordinal);
+        }
+
         private IEnumerable<string> GetCodecs(Codec codec)
         {
             string codecstr = codec == Codec.Encoder ? "encoders" : "decoders";
             string output;
             try
             {
-                output = GetProcessOutput(_encoderPath, "-" + codecstr, false);
+                output = GetProcessOutput(_encoderPath, "-" + codecstr, false, null);
             }
             catch (Exception ex)
             {
@@ -439,7 +460,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
             string output;
             try
             {
-                output = GetProcessOutput(_encoderPath, "-filters", false);
+                output = GetProcessOutput(_encoderPath, "-filters", false, null);
             }
             catch (Exception ex)
             {
@@ -477,7 +498,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
             return dict;
         }
 
-        private string GetProcessOutput(string path, string arguments, bool readStdErr)
+        private string GetProcessOutput(string path, string arguments, bool readStdErr, string? testKey)
         {
             using (var process = new Process()
             {
@@ -487,6 +508,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
                     UseShellExecute = false,
                     WindowStyle = ProcessWindowStyle.Hidden,
                     ErrorDialog = false,
+                    RedirectStandardInput = !string.IsNullOrEmpty(testKey),
                     RedirectStandardOutput = true,
                     RedirectStandardError = true
                 }
@@ -496,6 +518,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
                 process.Start();
 
+                if (!string.IsNullOrEmpty(testKey))
+                {
+                    process.StandardInput.Write(testKey);
+                }
+
                 return readStdErr ? process.StandardError.ReadToEnd() : process.StandardOutput.ReadToEnd();
             }
         }

+ 6 - 0
MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs

@@ -67,6 +67,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
         private List<string> _filters = new List<string>();
         private IDictionary<int, bool> _filtersWithOption = new Dictionary<int, bool>();
 
+        private bool _isPkeyPauseSupported = false;
+
         private bool _isVaapiDeviceAmd = false;
         private bool _isVaapiDeviceInteliHD = false;
         private bool _isVaapiDeviceInteli965 = false;
@@ -100,6 +102,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
         public Version EncoderVersion => _ffmpegVersion;
 
+        public bool IsPkeyPauseSupported => _isPkeyPauseSupported;
+
         public bool IsVaapiDeviceAmd => _isVaapiDeviceAmd;
 
         public bool IsVaapiDeviceInteliHD => _isVaapiDeviceInteliHD;
@@ -154,6 +158,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
                 _threads = EncodingHelper.GetNumberOfThreads(null, options, null);
 
+                _isPkeyPauseSupported = validator.CheckSupportedRuntimeKey("p      pause transcoding");
+
                 // Check the Vaapi device vendor
                 if (OperatingSystem.IsLinux()
                     && SupportsHwaccel("vaapi")