aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs6
-rw-r--r--src/Jellyfin.Drawing/ImageProcessor.cs31
2 files changed, 35 insertions, 2 deletions
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index d3e042aba..c39162250 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -259,5 +259,11 @@ namespace MediaBrowser.Model.Configuration
/// </summary>
/// <value>The chapter image resolution.</value>
public ImageResolution ChapterImageResolution { get; set; } = ImageResolution.MatchSource;
+
+ /// <summary>
+ /// Gets or sets the limit for parallel image encoding.
+ /// </summary>
+ /// <value>The limit for parallel image encoding.</value>
+ public int ParallelImageEncodingLimit { get; set; } = 0;
}
}
diff --git a/src/Jellyfin.Drawing/ImageProcessor.cs b/src/Jellyfin.Drawing/ImageProcessor.cs
index b381c9ae7..353a27b25 100644
--- a/src/Jellyfin.Drawing/ImageProcessor.cs
+++ b/src/Jellyfin.Drawing/ImageProcessor.cs
@@ -5,10 +5,12 @@ using System.IO;
using System.Linq;
using System.Net.Mime;
using System.Text;
+using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Data.Entities;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller;
+using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.MediaEncoding;
@@ -38,6 +40,8 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
private readonly IImageEncoder _imageEncoder;
private readonly IMediaEncoder _mediaEncoder;
+ private readonly SemaphoreSlim _parallelEncodingLimit;
+
private bool _disposed;
/// <summary>
@@ -48,18 +52,28 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
/// <param name="fileSystem">The filesystem.</param>
/// <param name="imageEncoder">The image encoder.</param>
/// <param name="mediaEncoder">The media encoder.</param>
+ /// <param name="config">The configuration.</param>
public ImageProcessor(
ILogger<ImageProcessor> logger,
IServerApplicationPaths appPaths,
IFileSystem fileSystem,
IImageEncoder imageEncoder,
- IMediaEncoder mediaEncoder)
+ IMediaEncoder mediaEncoder,
+ IServerConfigurationManager config)
{
_logger = logger;
_fileSystem = fileSystem;
_imageEncoder = imageEncoder;
_mediaEncoder = mediaEncoder;
_appPaths = appPaths;
+
+ var semaphoreCount = config.Configuration.ParallelImageEncodingLimit;
+ if (semaphoreCount < 1)
+ {
+ semaphoreCount = 2 * Environment.ProcessorCount;
+ }
+
+ _parallelEncodingLimit = new(semaphoreCount, semaphoreCount);
}
private string ResizedImageCachePath => Path.Combine(_appPaths.ImageCachePath, "resized-images");
@@ -199,7 +213,18 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
{
if (!File.Exists(cacheFilePath))
{
- string resultPath = _imageEncoder.EncodeImage(originalImagePath, dateModified, cacheFilePath, autoOrient, orientation, quality, options, outputFormat);
+ // Limit number of parallel (more precisely: concurrent) image encodings to prevent a high memory usage
+ await _parallelEncodingLimit.WaitAsync().ConfigureAwait(false);
+
+ string resultPath;
+ try
+ {
+ resultPath = _imageEncoder.EncodeImage(originalImagePath, dateModified, cacheFilePath, autoOrient, orientation, quality, options, outputFormat);
+ }
+ finally
+ {
+ _parallelEncodingLimit.Release();
+ }
if (string.Equals(resultPath, originalImagePath, StringComparison.OrdinalIgnoreCase))
{
@@ -563,6 +588,8 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
disposable.Dispose();
}
+ _parallelEncodingLimit?.Dispose();
+
_disposed = true;
}
}