mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-11-03 19:17:24 -05:00 
			
		
		
		
	Merge pull request #8213 from nyanmisaka/pause-cpu
Fix high single thread usage in throttler
This commit is contained in:
		
						commit
						ba026716c1
					
				@ -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();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -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)
 | 
			
		||||
 | 
			
		||||
@ -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>
 | 
			
		||||
 | 
			
		||||
@ -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();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -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")
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user