mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-09-06 11:34:57 +02:00
Fix high single thread usage in throttler
this requires jellyfin-ffmpeg >= 5.0.1-8
This commit is contained in:
parent
5bcab0f0f8
commit
c53f6a2890
5 changed files with 59 additions and 13 deletions
|
@ -654,7 +654,7 @@ namespace Jellyfin.Api.Helpers
|
||||||
{
|
{
|
||||||
if (EnableThrottling(state))
|
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();
|
transcodingJob.TranscodingThrottler.Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
@ -17,6 +18,7 @@ namespace Jellyfin.Api.Models.PlaybackDtos
|
||||||
private readonly ILogger<TranscodingThrottler> _logger;
|
private readonly ILogger<TranscodingThrottler> _logger;
|
||||||
private readonly IConfigurationManager _config;
|
private readonly IConfigurationManager _config;
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
private Timer? _timer;
|
private Timer? _timer;
|
||||||
private bool _isPaused;
|
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="logger">Instance of the <see cref="ILogger{TranscodingThrottler}"/> interface.</param>
|
||||||
/// <param name="config">Instance of the <see cref="IConfigurationManager"/> interface.</param>
|
/// <param name="config">Instance of the <see cref="IConfigurationManager"/> interface.</param>
|
||||||
/// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> 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;
|
_job = job;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_config = config;
|
_config = config;
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
|
_mediaEncoder = mediaEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -55,7 +59,8 @@ namespace Jellyfin.Api.Models.PlaybackDtos
|
||||||
|
|
||||||
try
|
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;
|
_isPaused = false;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -125,11 +130,13 @@ namespace Jellyfin.Api.Models.PlaybackDtos
|
||||||
{
|
{
|
||||||
if (!_isPaused)
|
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
|
try
|
||||||
{
|
{
|
||||||
await _job.Process!.StandardInput.WriteAsync("c").ConfigureAwait(false);
|
await _job.Process!.StandardInput.WriteAsync(pauseKey).ConfigureAwait(false);
|
||||||
_isPaused = true;
|
_isPaused = true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
|
@ -37,6 +37,12 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
/// <returns>The version of encoder.</returns>
|
/// <returns>The version of encoder.</returns>
|
||||||
Version EncoderVersion { get; }
|
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>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the configured Vaapi device is from AMD(radeonsi/r600 Mesa driver).
|
/// Gets a value indicating whether the configured Vaapi device is from AMD(radeonsi/r600 Mesa driver).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -153,7 +153,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
string output;
|
string output;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
output = GetProcessOutput(_encoderPath, "-version", false);
|
output = GetProcessOutput(_encoderPath, "-version", false, null);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -234,7 +234,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
string output;
|
string output;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
output = GetProcessOutput(_encoderPath, "-version", false);
|
output = GetProcessOutput(_encoderPath, "-version", false, null);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -341,7 +341,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
try
|
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);
|
return output.Contains(driverName, StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -356,7 +356,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
string? output = null;
|
string? output = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
output = GetProcessOutput(_encoderPath, "-hwaccels", false);
|
output = GetProcessOutput(_encoderPath, "-hwaccels", false, null);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -384,7 +384,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
string output;
|
string output;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
output = GetProcessOutput(_encoderPath, "-h filter=" + filter, false);
|
output = GetProcessOutput(_encoderPath, "-h filter=" + filter, false, null);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -402,13 +402,34 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
return false;
|
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)
|
private IEnumerable<string> GetCodecs(Codec codec)
|
||||||
{
|
{
|
||||||
string codecstr = codec == Codec.Encoder ? "encoders" : "decoders";
|
string codecstr = codec == Codec.Encoder ? "encoders" : "decoders";
|
||||||
string output;
|
string output;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
output = GetProcessOutput(_encoderPath, "-" + codecstr, false);
|
output = GetProcessOutput(_encoderPath, "-" + codecstr, false, null);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -439,7 +460,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
string output;
|
string output;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
output = GetProcessOutput(_encoderPath, "-filters", false);
|
output = GetProcessOutput(_encoderPath, "-filters", false, null);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -477,7 +498,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
return dict;
|
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()
|
using (var process = new Process()
|
||||||
{
|
{
|
||||||
|
@ -487,6 +508,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
WindowStyle = ProcessWindowStyle.Hidden,
|
WindowStyle = ProcessWindowStyle.Hidden,
|
||||||
ErrorDialog = false,
|
ErrorDialog = false,
|
||||||
|
RedirectStandardInput = !string.IsNullOrEmpty(testKey),
|
||||||
RedirectStandardOutput = true,
|
RedirectStandardOutput = true,
|
||||||
RedirectStandardError = true
|
RedirectStandardError = true
|
||||||
}
|
}
|
||||||
|
@ -496,6 +518,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
process.Start();
|
process.Start();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(testKey))
|
||||||
|
{
|
||||||
|
process.StandardInput.Write(testKey);
|
||||||
|
}
|
||||||
|
|
||||||
return readStdErr ? process.StandardError.ReadToEnd() : process.StandardOutput.ReadToEnd();
|
return readStdErr ? process.StandardError.ReadToEnd() : process.StandardOutput.ReadToEnd();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
private List<string> _filters = new List<string>();
|
private List<string> _filters = new List<string>();
|
||||||
private IDictionary<int, bool> _filtersWithOption = new Dictionary<int, bool>();
|
private IDictionary<int, bool> _filtersWithOption = new Dictionary<int, bool>();
|
||||||
|
|
||||||
|
private bool _isPkeyPauseSupported = false;
|
||||||
|
|
||||||
private bool _isVaapiDeviceAmd = false;
|
private bool _isVaapiDeviceAmd = false;
|
||||||
private bool _isVaapiDeviceInteliHD = false;
|
private bool _isVaapiDeviceInteliHD = false;
|
||||||
private bool _isVaapiDeviceInteli965 = false;
|
private bool _isVaapiDeviceInteli965 = false;
|
||||||
|
@ -100,6 +102,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
public Version EncoderVersion => _ffmpegVersion;
|
public Version EncoderVersion => _ffmpegVersion;
|
||||||
|
|
||||||
|
public bool IsPkeyPauseSupported => _isPkeyPauseSupported;
|
||||||
|
|
||||||
public bool IsVaapiDeviceAmd => _isVaapiDeviceAmd;
|
public bool IsVaapiDeviceAmd => _isVaapiDeviceAmd;
|
||||||
|
|
||||||
public bool IsVaapiDeviceInteliHD => _isVaapiDeviceInteliHD;
|
public bool IsVaapiDeviceInteliHD => _isVaapiDeviceInteliHD;
|
||||||
|
@ -154,6 +158,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
_threads = EncodingHelper.GetNumberOfThreads(null, options, null);
|
_threads = EncodingHelper.GetNumberOfThreads(null, options, null);
|
||||||
|
|
||||||
|
_isPkeyPauseSupported = validator.CheckSupportedRuntimeKey("p pause transcoding");
|
||||||
|
|
||||||
// Check the Vaapi device vendor
|
// Check the Vaapi device vendor
|
||||||
if (OperatingSystem.IsLinux()
|
if (OperatingSystem.IsLinux()
|
||||||
&& SupportsHwaccel("vaapi")
|
&& SupportsHwaccel("vaapi")
|
||||||
|
|
Loading…
Reference in a new issue