improve image processing performance

pull/1154/head
Luke Pulverenti 7 years ago
parent d7a1a87009
commit dec3b1bbb0

@ -430,7 +430,7 @@ namespace Emby.Dlna.PlayTo
return Task.FromResult(true); return Task.FromResult(true);
} }
public Task SendRestartRequiredNotification(SystemInfo info, CancellationToken cancellationToken) public Task SendRestartRequiredNotification(CancellationToken cancellationToken)
{ {
return Task.FromResult(true); return Task.FromResult(true);
} }

@ -173,6 +173,8 @@ namespace Emby.Drawing.ImageMagick
originalImage.CurrentImage.CompressionQuality = quality; originalImage.CurrentImage.CompressionQuality = quality;
originalImage.CurrentImage.StripImage(); originalImage.CurrentImage.StripImage();
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(outputPath));
originalImage.SaveImage(outputPath); originalImage.SaveImage(outputPath);
} }
} }

@ -528,6 +528,7 @@ namespace Emby.Drawing.Skia
// If all we're doing is resizing then we can stop now // If all we're doing is resizing then we can stop now
if (!hasBackgroundColor && !hasForegroundColor && blur == 0 && !hasIndicator) if (!hasBackgroundColor && !hasForegroundColor && blur == 0 && !hasIndicator)
{ {
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(outputPath));
using (var outputStream = new SKFileWStream(outputPath)) using (var outputStream = new SKFileWStream(outputPath))
{ {
resizedBitmap.Encode(outputStream, skiaOutputFormat, quality); resizedBitmap.Encode(outputStream, skiaOutputFormat, quality);
@ -580,6 +581,7 @@ namespace Emby.Drawing.Skia
DrawIndicator(canvas, width, height, options); DrawIndicator(canvas, width, height, options);
} }
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(outputPath));
using (var outputStream = new SKFileWStream(outputPath)) using (var outputStream = new SKFileWStream(outputPath))
{ {
saveBitmap.Encode(outputStream, skiaOutputFormat, quality); saveBitmap.Encode(outputStream, skiaOutputFormat, quality);

@ -220,7 +220,7 @@ namespace Emby.Drawing
Type = originalImage.Type, Type = originalImage.Type,
Path = originalImagePath Path = originalImagePath
}, requiresTransparency, item, options.ImageIndex, options.Enhancers).ConfigureAwait(false); }, requiresTransparency, item, options.ImageIndex, options.Enhancers, CancellationToken.None).ConfigureAwait(false);
originalImagePath = tuple.Item1; originalImagePath = tuple.Item1;
dateModified = tuple.Item2; dateModified = tuple.Item2;
@ -256,31 +256,29 @@ namespace Emby.Drawing
var outputFormat = GetOutputFormat(options.SupportedOutputFormats, requiresTransparency); var outputFormat = GetOutputFormat(options.SupportedOutputFormats, requiresTransparency);
var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.Blur, options.BackgroundColor, options.ForegroundLayer); var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.Blur, options.BackgroundColor, options.ForegroundLayer);
CheckDisposed();
var lockInfo = GetLock(cacheFilePath);
await lockInfo.Lock.WaitAsync().ConfigureAwait(false);
try try
{ {
CheckDisposed();
if (!_fileSystem.FileExists(cacheFilePath)) if (!_fileSystem.FileExists(cacheFilePath))
{ {
var tmpPath = Path.ChangeExtension(Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString("N")), Path.GetExtension(cacheFilePath));
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(tmpPath));
if (options.CropWhiteSpace && !SupportsTransparency(originalImagePath)) if (options.CropWhiteSpace && !SupportsTransparency(originalImagePath))
{ {
options.CropWhiteSpace = false; options.CropWhiteSpace = false;
} }
var resultPath = _imageEncoder.EncodeImage(originalImagePath, dateModified, tmpPath, autoOrient, orientation, quality, options, outputFormat); var resultPath = _imageEncoder.EncodeImage(originalImagePath, dateModified, cacheFilePath, autoOrient, orientation, quality, options, outputFormat);
if (string.Equals(resultPath, originalImagePath, StringComparison.OrdinalIgnoreCase)) if (string.Equals(resultPath, originalImagePath, StringComparison.OrdinalIgnoreCase))
{ {
return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified); return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
} }
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(cacheFilePath)); return new Tuple<string, string, DateTime>(cacheFilePath, GetMimeType(outputFormat, cacheFilePath), _fileSystem.GetLastWriteTimeUtc(cacheFilePath));
CopyFile(tmpPath, cacheFilePath);
return new Tuple<string, string, DateTime>(tmpPath, GetMimeType(outputFormat, cacheFilePath), _fileSystem.GetLastWriteTimeUtc(tmpPath));
} }
return new Tuple<string, string, DateTime>(cacheFilePath, GetMimeType(outputFormat, cacheFilePath), _fileSystem.GetLastWriteTimeUtc(cacheFilePath)); return new Tuple<string, string, DateTime>(cacheFilePath, GetMimeType(outputFormat, cacheFilePath), _fileSystem.GetLastWriteTimeUtc(cacheFilePath));
@ -302,6 +300,10 @@ namespace Emby.Drawing
// Just spit out the original file if all the options are default // Just spit out the original file if all the options are default
return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified); return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
} }
finally
{
ReleaseLock(cacheFilePath, lockInfo);
}
} }
private ImageFormat GetOutputFormat(ImageFormat[] clientSupportedFormats, bool requiresTransparency) private ImageFormat GetOutputFormat(ImageFormat[] clientSupportedFormats, bool requiresTransparency)
@ -667,7 +669,7 @@ namespace Emby.Drawing
var inputImageSupportsTransparency = SupportsTransparency(imageInfo.Path); var inputImageSupportsTransparency = SupportsTransparency(imageInfo.Path);
var result = await GetEnhancedImage(imageInfo, inputImageSupportsTransparency, item, imageIndex, enhancers); var result = await GetEnhancedImage(imageInfo, inputImageSupportsTransparency, item, imageIndex, enhancers, CancellationToken.None);
return result.Item1; return result.Item1;
} }
@ -676,7 +678,8 @@ namespace Emby.Drawing
bool inputImageSupportsTransparency, bool inputImageSupportsTransparency,
IHasMetadata item, IHasMetadata item,
int imageIndex, int imageIndex,
List<IImageEnhancer> enhancers) List<IImageEnhancer> enhancers,
CancellationToken cancellationToken)
{ {
var originalImagePath = image.Path; var originalImagePath = image.Path;
var dateModified = image.DateModified; var dateModified = image.DateModified;
@ -687,7 +690,7 @@ namespace Emby.Drawing
var cacheGuid = GetImageCacheTag(item, image, enhancers); var cacheGuid = GetImageCacheTag(item, image, enhancers);
// Enhance if we have enhancers // Enhance if we have enhancers
var ehnancedImageInfo = await GetEnhancedImageInternal(originalImagePath, item, imageType, imageIndex, enhancers, cacheGuid).ConfigureAwait(false); var ehnancedImageInfo = await GetEnhancedImageInternal(originalImagePath, item, imageType, imageIndex, enhancers, cacheGuid, cancellationToken).ConfigureAwait(false);
var ehnancedImagePath = ehnancedImageInfo.Item1; var ehnancedImagePath = ehnancedImageInfo.Item1;
@ -727,7 +730,8 @@ namespace Emby.Drawing
ImageType imageType, ImageType imageType,
int imageIndex, int imageIndex,
List<IImageEnhancer> supportedEnhancers, List<IImageEnhancer> supportedEnhancers,
string cacheGuid) string cacheGuid,
CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(originalImagePath)) if (string.IsNullOrEmpty(originalImagePath))
{ {
@ -755,29 +759,28 @@ namespace Emby.Drawing
var enhancedImagePath = GetCachePath(EnhancedImageCachePath, cacheGuid + cacheExtension); var enhancedImagePath = GetCachePath(EnhancedImageCachePath, cacheGuid + cacheExtension);
// Check again in case of contention var lockInfo = GetLock(enhancedImagePath);
if (_fileSystem.FileExists(enhancedImagePath))
{
return new Tuple<string, bool>(enhancedImagePath, treatmentRequiresTransparency);
}
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(enhancedImagePath)); await lockInfo.Lock.WaitAsync(cancellationToken).ConfigureAwait(false);
var tmpPath = Path.Combine(_appPaths.TempDirectory, Path.ChangeExtension(Guid.NewGuid().ToString(), Path.GetExtension(enhancedImagePath)));
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(tmpPath));
await ExecuteImageEnhancers(supportedEnhancers, originalImagePath, tmpPath, item, imageType, imageIndex).ConfigureAwait(false);
try try
{ {
_fileSystem.CopyFile(tmpPath, enhancedImagePath, true); // Check again in case of contention
if (_fileSystem.FileExists(enhancedImagePath))
{
return new Tuple<string, bool>(enhancedImagePath, treatmentRequiresTransparency);
}
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(enhancedImagePath));
await ExecuteImageEnhancers(supportedEnhancers, originalImagePath, enhancedImagePath, item, imageType, imageIndex).ConfigureAwait(false);
return new Tuple<string, bool>(enhancedImagePath, treatmentRequiresTransparency);
} }
catch finally
{ {
ReleaseLock(enhancedImagePath, lockInfo);
} }
return new Tuple<string, bool>(tmpPath, treatmentRequiresTransparency);
} }
/// <summary> /// <summary>
@ -896,6 +899,45 @@ namespace Emby.Drawing
return list; return list;
} }
private Dictionary<string, LockInfo> _locks = new Dictionary<string, LockInfo>();
private class LockInfo
{
public SemaphoreSlim Lock = new SemaphoreSlim(1, 1);
public int Count = 1;
}
private LockInfo GetLock(string key)
{
lock (_locks)
{
LockInfo info;
if (_locks.TryGetValue(key, out info))
{
info.Count++;
}
else
{
info = new LockInfo();
_locks[key] = info;
}
return info;
}
}
private void ReleaseLock(string key, LockInfo info)
{
info.Lock.Release();
lock (_locks)
{
info.Count--;
if (info.Count <= 0)
{
_locks.Remove(key);
info.Lock.Dispose();
}
}
}
private bool _disposed; private bool _disposed;
public void Dispose() public void Dispose()
{ {

@ -43,7 +43,7 @@ namespace Emby.Server.Implementations.Social
throw new ResourceNotFoundException(); throw new ResourceNotFoundException();
} }
var externalUrl = (await _appHost.GetSystemInfo(CancellationToken.None).ConfigureAwait(false)).WanAddress; var externalUrl = (await _appHost.GetPublicSystemInfo(CancellationToken.None).ConfigureAwait(false)).WanAddress;
if (string.IsNullOrWhiteSpace(externalUrl)) if (string.IsNullOrWhiteSpace(externalUrl))
{ {
@ -74,7 +74,7 @@ namespace Emby.Server.Implementations.Social
{ {
var info = _repository.GetShareInfo(id); var info = _repository.GetShareInfo(id);
AddShareInfo(info, _appHost.GetSystemInfo(CancellationToken.None).Result.WanAddress); AddShareInfo(info, _appHost.GetPublicSystemInfo(CancellationToken.None).Result.WanAddress);
return info; return info;
} }

Loading…
Cancel
Save