Allow limiting parallel image encodings to reduce memory usage (#8783)

This commit is contained in:
Hannes Braun 2023-01-16 18:06:44 +01:00 committed by GitHub
parent be206d4ff2
commit 66eff8b9ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 35 additions and 2 deletions

View File

@ -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;
}
}

View File

@ -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;
}
}