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> /// </summary>
/// <value>The chapter image resolution.</value> /// <value>The chapter image resolution.</value>
public ImageResolution ChapterImageResolution { get; set; } = ImageResolution.MatchSource; 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.Linq;
using System.Net.Mime; using System.Net.Mime;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Jellyfin.Data.Entities; using Jellyfin.Data.Entities;
using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.MediaEncoding;
@ -38,6 +40,8 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
private readonly IImageEncoder _imageEncoder; private readonly IImageEncoder _imageEncoder;
private readonly IMediaEncoder _mediaEncoder; private readonly IMediaEncoder _mediaEncoder;
private readonly SemaphoreSlim _parallelEncodingLimit;
private bool _disposed; private bool _disposed;
/// <summary> /// <summary>
@ -48,18 +52,28 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
/// <param name="fileSystem">The filesystem.</param> /// <param name="fileSystem">The filesystem.</param>
/// <param name="imageEncoder">The image encoder.</param> /// <param name="imageEncoder">The image encoder.</param>
/// <param name="mediaEncoder">The media encoder.</param> /// <param name="mediaEncoder">The media encoder.</param>
/// <param name="config">The configuration.</param>
public ImageProcessor( public ImageProcessor(
ILogger<ImageProcessor> logger, ILogger<ImageProcessor> logger,
IServerApplicationPaths appPaths, IServerApplicationPaths appPaths,
IFileSystem fileSystem, IFileSystem fileSystem,
IImageEncoder imageEncoder, IImageEncoder imageEncoder,
IMediaEncoder mediaEncoder) IMediaEncoder mediaEncoder,
IServerConfigurationManager config)
{ {
_logger = logger; _logger = logger;
_fileSystem = fileSystem; _fileSystem = fileSystem;
_imageEncoder = imageEncoder; _imageEncoder = imageEncoder;
_mediaEncoder = mediaEncoder; _mediaEncoder = mediaEncoder;
_appPaths = appPaths; _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"); private string ResizedImageCachePath => Path.Combine(_appPaths.ImageCachePath, "resized-images");
@ -199,7 +213,18 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
{ {
if (!File.Exists(cacheFilePath)) 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)) if (string.Equals(resultPath, originalImagePath, StringComparison.OrdinalIgnoreCase))
{ {
@ -563,6 +588,8 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable
disposable.Dispose(); disposable.Dispose();
} }
_parallelEncodingLimit?.Dispose();
_disposed = true; _disposed = true;
} }
} }