control the number of simultaneous image operations

This commit is contained in:
Luke Pulverenti 2015-04-23 12:50:54 -04:00
parent 7ac8fd1c68
commit 6f01652520
7 changed files with 84 additions and 47 deletions

View File

@ -51,6 +51,7 @@ namespace Emby.Drawing
private readonly IJsonSerializer _jsonSerializer; private readonly IJsonSerializer _jsonSerializer;
private readonly IServerApplicationPaths _appPaths; private readonly IServerApplicationPaths _appPaths;
private readonly IImageEncoder _imageEncoder; private readonly IImageEncoder _imageEncoder;
private readonly SemaphoreSlim _imageProcessingSemaphore;
public ImageProcessor(ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem, IJsonSerializer jsonSerializer, IImageEncoder imageEncoder) public ImageProcessor(ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem, IJsonSerializer jsonSerializer, IImageEncoder imageEncoder)
{ {
@ -88,6 +89,8 @@ namespace Emby.Drawing
} }
_cachedImagedSizes = new ConcurrentDictionary<Guid, ImageSize>(sizeDictionary); _cachedImagedSizes = new ConcurrentDictionary<Guid, ImageSize>(sizeDictionary);
var count = Environment.ProcessorCount;
_imageProcessingSemaphore = new SemaphoreSlim(count, count);
} }
public string[] SupportedInputFormats public string[] SupportedInputFormats
@ -201,6 +204,8 @@ namespace Emby.Drawing
await semaphore.WaitAsync().ConfigureAwait(false); await semaphore.WaitAsync().ConfigureAwait(false);
var imageProcessingLockTaken = false;
try try
{ {
CheckDisposed(); CheckDisposed();
@ -212,11 +217,20 @@ namespace Emby.Drawing
Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath)); Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
await _imageProcessingSemaphore.WaitAsync().ConfigureAwait(false);
imageProcessingLockTaken = true;
_imageEncoder.EncodeImage(originalImagePath, cacheFilePath, newWidth, newHeight, quality, options); _imageEncoder.EncodeImage(originalImagePath, cacheFilePath, newWidth, newHeight, quality, options);
} }
} }
finally finally
{ {
if (imageProcessingLockTaken)
{
_imageProcessingSemaphore.Release();
}
semaphore.Release(); semaphore.Release();
} }
@ -254,10 +268,15 @@ namespace Emby.Drawing
return GetResult(croppedImagePath); return GetResult(croppedImagePath);
} }
var imageProcessingLockTaken = false;
try try
{ {
Directory.CreateDirectory(Path.GetDirectoryName(croppedImagePath)); Directory.CreateDirectory(Path.GetDirectoryName(croppedImagePath));
await _imageProcessingSemaphore.WaitAsync().ConfigureAwait(false);
imageProcessingLockTaken = true;
_imageEncoder.CropWhiteSpace(originalImagePath, croppedImagePath); _imageEncoder.CropWhiteSpace(originalImagePath, croppedImagePath);
} }
catch (Exception ex) catch (Exception ex)
@ -269,6 +288,11 @@ namespace Emby.Drawing
} }
finally finally
{ {
if (imageProcessingLockTaken)
{
_imageProcessingSemaphore.Release();
}
semaphore.Release(); semaphore.Release();
} }
@ -592,13 +616,25 @@ namespace Emby.Drawing
return enhancedImagePath; return enhancedImagePath;
} }
var imageProcessingLockTaken = false;
try try
{ {
Directory.CreateDirectory(Path.GetDirectoryName(enhancedImagePath)); Directory.CreateDirectory(Path.GetDirectoryName(enhancedImagePath));
await _imageProcessingSemaphore.WaitAsync().ConfigureAwait(false);
imageProcessingLockTaken = true;
await ExecuteImageEnhancers(supportedEnhancers, originalImagePath, enhancedImagePath, item, imageType, imageIndex).ConfigureAwait(false); await ExecuteImageEnhancers(supportedEnhancers, originalImagePath, enhancedImagePath, item, imageType, imageIndex).ConfigureAwait(false);
} }
finally finally
{ {
if (imageProcessingLockTaken)
{
_imageProcessingSemaphore.Release();
}
semaphore.Release(); semaphore.Release();
} }
@ -717,9 +753,18 @@ namespace Emby.Drawing
return Path.Combine(path, filename); return Path.Combine(path, filename);
} }
public void CreateImageCollage(ImageCollageOptions options) public async Task CreateImageCollage(ImageCollageOptions options)
{ {
_imageEncoder.CreateImageCollage(options); await _imageProcessingSemaphore.WaitAsync().ConfigureAwait(false);
try
{
_imageEncoder.CreateImageCollage(options);
}
finally
{
_imageProcessingSemaphore.Release();
}
} }
public IEnumerable<IImageEnhancer> GetSupportedEnhancers(IHasImages item, ImageType imageType) public IEnumerable<IImageEnhancer> GetSupportedEnhancers(IHasImages item, ImageType imageType)

View File

@ -104,6 +104,6 @@ namespace MediaBrowser.Controller.Drawing
/// Creates the image collage. /// Creates the image collage.
/// </summary> /// </summary>
/// <param name="options">The options.</param> /// <param name="options">The options.</param>
void CreateImageCollage(ImageCollageOptions options); Task CreateImageCollage(ImageCollageOptions options);
} }
} }

View File

@ -17,7 +17,7 @@ namespace MediaBrowser.Model.Configuration
DownMixAudioBoost = 2; DownMixAudioBoost = 2;
EncodingQuality = EncodingQuality.Auto; EncodingQuality = EncodingQuality.Auto;
EnableThrottling = true; EnableThrottling = true;
ThrottleThresholdSeconds = 90; ThrottleThresholdSeconds = 120;
} }
} }
} }

View File

@ -88,7 +88,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
NatUtility.UnhandledException += NatUtility_UnhandledException; NatUtility.UnhandledException += NatUtility_UnhandledException;
NatUtility.StartDiscovery(); NatUtility.StartDiscovery();
_timer = new Timer(s => _createdRules = new List<string>(), null, TimeSpan.FromMinutes(3), TimeSpan.FromMinutes(3)); _timer = new Timer(s => _createdRules = new List<string>(), null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
_lastConfigIdentifier = GetConfigIdentifier(); _lastConfigIdentifier = GetConfigIdentifier();
@ -97,17 +97,17 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
void NatUtility_UnhandledException(object sender, UnhandledExceptionEventArgs e) void NatUtility_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{ {
//var ex = e.ExceptionObject as Exception; var ex = e.ExceptionObject as Exception;
//if (ex == null) if (ex == null)
//{ {
// _logger.Error("Unidentified error reported by Mono.Nat"); //_logger.Error("Unidentified error reported by Mono.Nat");
//} }
//else else
//{ {
// // Seeing some blank exceptions coming through here // Seeing some blank exceptions coming through here
// _logger.ErrorException("Error reported by Mono.Nat: ", ex); _logger.ErrorException("Error reported by Mono.Nat: ", ex);
//} }
} }
void NatUtility_DeviceFound(object sender, DeviceEventArgs e) void NatUtility_DeviceFound(object sender, DeviceEventArgs e)

View File

@ -345,7 +345,7 @@ namespace MediaBrowser.Server.Implementations.Library
{ {
var name = MakeValidUsername(Environment.UserName); var name = MakeValidUsername(Environment.UserName);
var user = InstantiateNewUser(name, false); var user = InstantiateNewUser(name);
user.DateLastSaved = DateTime.UtcNow; user.DateLastSaved = DateTime.UtcNow;
@ -552,7 +552,7 @@ namespace MediaBrowser.Server.Implementations.Library
try try
{ {
var user = InstantiateNewUser(name, true); var user = InstantiateNewUser(name);
var list = Users.ToList(); var list = Users.ToList();
list.Add(user); list.Add(user);
@ -697,21 +697,13 @@ namespace MediaBrowser.Server.Implementations.Library
/// Instantiates the new user. /// Instantiates the new user.
/// </summary> /// </summary>
/// <param name="name">The name.</param> /// <param name="name">The name.</param>
/// <param name="checkId">if set to <c>true</c> [check identifier].</param>
/// <returns>User.</returns> /// <returns>User.</returns>
private User InstantiateNewUser(string name, bool checkId) private User InstantiateNewUser(string name)
{ {
var id = ("MBUser" + name).GetMD5();
if (checkId && Users.Select(i => i.Id).Contains(id))
{
id = Guid.NewGuid();
}
return new User return new User
{ {
Name = name, Name = name,
Id = id, Id = Guid.NewGuid(),
DateCreated = DateTime.UtcNow, DateCreated = DateTime.UtcNow,
DateModified = DateTime.UtcNow, DateModified = DateTime.UtcNow,
UsesIdForConfigurationPath = true UsesIdForConfigurationPath = true

View File

@ -80,7 +80,7 @@ namespace MediaBrowser.Server.Implementations.Photos
{ {
var outputPath = Path.Combine(ApplicationPaths.TempDirectory, Guid.NewGuid() + ".png"); var outputPath = Path.Combine(ApplicationPaths.TempDirectory, Guid.NewGuid() + ".png");
Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
var imageCreated = CreateImage(item, itemsWithImages, outputPath, imageType, 0); var imageCreated = await CreateImage(item, itemsWithImages, outputPath, imageType, 0).ConfigureAwait(false);
if (!imageCreated) if (!imageCreated)
{ {
@ -103,9 +103,9 @@ namespace MediaBrowser.Server.Implementations.Photos
return parts.GetMD5().ToString("N"); return parts.GetMD5().ToString("N");
} }
protected void CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, bool drawText) protected Task CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, bool drawText)
{ {
CreateCollage(primaryItem, items, outputPath, 960, 540, drawText, primaryItem.Name); return CreateCollage(primaryItem, items, outputPath, 960, 540, drawText, primaryItem.Name);
} }
protected virtual IEnumerable<string> GetStripCollageImagePaths(IHasImages primaryItem, IEnumerable<BaseItem> items) protected virtual IEnumerable<string> GetStripCollageImagePaths(IHasImages primaryItem, IEnumerable<BaseItem> items)
@ -115,22 +115,22 @@ namespace MediaBrowser.Server.Implementations.Photos
.Where(i => !string.IsNullOrWhiteSpace(i)); .Where(i => !string.IsNullOrWhiteSpace(i));
} }
protected void CreatePosterCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath) protected Task CreatePosterCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath)
{ {
CreateCollage(primaryItem, items, outputPath, 600, 900, true, primaryItem.Name); return CreateCollage(primaryItem, items, outputPath, 600, 900, true, primaryItem.Name);
} }
protected void CreateSquareCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, bool drawText) protected Task CreateSquareCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, bool drawText)
{ {
CreateCollage(primaryItem, items, outputPath, 800, 800, drawText, primaryItem.Name); return CreateCollage(primaryItem, items, outputPath, 800, 800, drawText, primaryItem.Name);
} }
protected void CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height, bool drawText, string text) protected Task CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height, bool drawText, string text)
{ {
CreateCollage(primaryItem, items, outputPath, width, height, drawText, text); return CreateCollage(primaryItem, items, outputPath, width, height, drawText, text);
} }
private void CreateCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height, bool drawText, string text) private Task CreateCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height, bool drawText, string text)
{ {
Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
@ -143,7 +143,7 @@ namespace MediaBrowser.Server.Implementations.Photos
InputPaths = GetStripCollageImagePaths(primaryItem, items).ToArray() InputPaths = GetStripCollageImagePaths(primaryItem, items).ToArray()
}; };
ImageProcessor.CreateImageCollage(options); return ImageProcessor.CreateImageCollage(options);
} }
public string Name public string Name
@ -151,7 +151,7 @@ namespace MediaBrowser.Server.Implementations.Photos
get { return "Dynamic Image Provider"; } get { return "Dynamic Image Provider"; }
} }
protected virtual bool CreateImage(IHasImages item, protected virtual async Task<bool> CreateImage(IHasImages item,
List<BaseItem> itemsWithImages, List<BaseItem> itemsWithImages,
string outputPath, string outputPath,
ImageType imageType, ImageType imageType,
@ -166,7 +166,7 @@ namespace MediaBrowser.Server.Implementations.Photos
if (imageType == ImageType.Thumb) if (imageType == ImageType.Thumb)
{ {
CreateThumbCollage(item, itemsWithImages, outputPath, drawText); await CreateThumbCollage(item, itemsWithImages, outputPath, drawText).ConfigureAwait(false);
return true; return true;
} }
@ -174,15 +174,15 @@ namespace MediaBrowser.Server.Implementations.Photos
{ {
if (item is UserView) if (item is UserView)
{ {
CreateSquareCollage(item, itemsWithImages, outputPath, drawText); await CreateSquareCollage(item, itemsWithImages, outputPath, drawText).ConfigureAwait(false);
} }
else if (item is PhotoAlbum || item is Playlist) else if (item is PhotoAlbum || item is Playlist)
{ {
CreateSquareCollage(item, itemsWithImages, outputPath, drawText); await CreateSquareCollage(item, itemsWithImages, outputPath, drawText).ConfigureAwait(false);
} }
else else
{ {
CreatePosterCollage(item, itemsWithImages, outputPath); await CreatePosterCollage(item, itemsWithImages, outputPath).ConfigureAwait(false);
} }
return true; return true;
@ -234,7 +234,7 @@ namespace MediaBrowser.Server.Implementations.Photos
protected virtual List<BaseItem> GetFinalItems(List<BaseItem> items, int limit) protected virtual List<BaseItem> GetFinalItems(List<BaseItem> items, int limit)
{ {
// Rotate the images once every x days // Rotate the images once every x days
var random = DateTime.Now.DayOfYear % 5; var random = DateTime.Now.DayOfYear % 7;
return items return items
.OrderBy(i => (random + "" + items.IndexOf(i)).GetMD5()) .OrderBy(i => (random + "" + items.IndexOf(i)).GetMD5())

View File

@ -216,7 +216,7 @@ namespace MediaBrowser.Server.Implementations.UserViews
return collectionStripViewTypes.Contains(view.ViewType ?? string.Empty); return collectionStripViewTypes.Contains(view.ViewType ?? string.Empty);
} }
protected override bool CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPath, ImageType imageType, int imageIndex) protected override async Task<bool> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPath, ImageType imageType, int imageIndex)
{ {
var view = (UserView)item; var view = (UserView)item;
if (imageType == ImageType.Primary && IsUsingCollectionStrip(view)) if (imageType == ImageType.Primary && IsUsingCollectionStrip(view))
@ -226,11 +226,11 @@ namespace MediaBrowser.Server.Implementations.UserViews
return false; return false;
} }
CreateThumbCollage(item, itemsWithImages, outputPath, 960, 540, false, item.Name); await CreateThumbCollage(item, itemsWithImages, outputPath, 960, 540, false, item.Name).ConfigureAwait(false);
return true; return true;
} }
return base.CreateImage(item, itemsWithImages, outputPath, imageType, imageIndex); return await base.CreateImage(item, itemsWithImages, outputPath, imageType, imageIndex).ConfigureAwait(false);
} }
protected override IEnumerable<String> GetStripCollageImagePaths(IHasImages primaryItem, IEnumerable<BaseItem> items) protected override IEnumerable<String> GetStripCollageImagePaths(IHasImages primaryItem, IEnumerable<BaseItem> items)