瀏覽代碼

update image encoding

Luke Pulverenti 8 年之前
父節點
當前提交
9cd2d793be

+ 11 - 7
Emby.Drawing.ImageMagick/ImageMagickEncoder.cs

@@ -130,7 +130,7 @@ namespace Emby.Drawing.ImageMagick
                 string.Equals(ext, ".webp", StringComparison.OrdinalIgnoreCase);
         }
 
-        public void EncodeImage(string inputPath, ImageSize? originalImageSize, string outputPath, bool autoOrient, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
+        public string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
         {
             // Even if the caller specified 100, don't use it because it takes forever
             quality = Math.Min(quality, 99);
@@ -144,9 +144,13 @@ namespace Emby.Drawing.ImageMagick
                         originalImage.CurrentImage.TrimImage(10);
                     }
 
-                    if (options.CropWhiteSpace || !originalImageSize.HasValue)
+                    var originalImageSize = new ImageSize(originalImage.CurrentImage.Width, originalImage.CurrentImage.Height);
+                    ImageHelper.SaveImageSize(inputPath, dateModified, originalImageSize);
+
+                    if (!options.CropWhiteSpace && options.HasDefaultOptions(inputPath, originalImageSize))
                     {
-                        originalImageSize = new ImageSize(originalImage.CurrentImage.Width, originalImage.CurrentImage.Height);
+                        // Just spit out the original file if all the options are default
+                        return inputPath;
                     }
 
                     var newImageSize = ImageHelper.GetNewImageSize(options, originalImageSize);
@@ -174,10 +178,8 @@ namespace Emby.Drawing.ImageMagick
             {
                 using (var originalImage = new MagickWand(inputPath))
                 {
-                    if (options.CropWhiteSpace || !originalImageSize.HasValue)
-                    {
-                        originalImageSize = new ImageSize(originalImage.CurrentImage.Width, originalImage.CurrentImage.Height);
-                    }
+                    var originalImageSize = new ImageSize(originalImage.CurrentImage.Width, originalImage.CurrentImage.Height);
+                    ImageHelper.SaveImageSize(inputPath, dateModified, originalImageSize);
 
                     var newImageSize = ImageHelper.GetNewImageSize(options, originalImageSize);
 
@@ -205,6 +207,8 @@ namespace Emby.Drawing.ImageMagick
                     }
                 }
             }
+
+            return outputPath;
         }
 
         private void AddForegroundLayer(MagickWand wand, ImageProcessingOptions options)

+ 31 - 8
Emby.Drawing.Skia/SkiaEncoder.cs

@@ -191,18 +191,18 @@ namespace Emby.Drawing.Skia
         }
 
         private string[] TransparentImageTypes = new string[] { ".png", ".gif", ".webp" };
-        private SKBitmap Decode(string path)
+        private SKBitmap Decode(string path, bool forceCleanBitmap = false)
         {
             var requiresTransparencyHack = TransparentImageTypes.Contains(Path.GetExtension(path) ?? string.Empty);
 
-            if (requiresTransparencyHack)
+            if (requiresTransparencyHack || forceCleanBitmap)
             {
                 using (var stream = new SKFileStream(path))
                 {
                     var codec = SKCodec.Create(stream);
 
                     // create the bitmap
-                    var bitmap = new SKBitmap(codec.Info.Width, codec.Info.Height);
+                    var bitmap = new SKBitmap(codec.Info.Width, codec.Info.Height, !requiresTransparencyHack);
                     // decode
                     codec.GetPixels(bitmap.Info, bitmap.GetPixels());
 
@@ -210,7 +210,18 @@ namespace Emby.Drawing.Skia
                 }
             }
 
-            return SKBitmap.Decode(path);
+            var resultBitmap = SKBitmap.Decode(path);
+
+            // If we have to resize these they often end up distorted
+            if (resultBitmap.ColorType == SKColorType.Gray8)
+            {
+                using (resultBitmap)
+                {
+                    return Decode(path, true);
+                }
+            }
+
+            return resultBitmap;
         }
 
         private SKBitmap GetBitmap(string path, bool cropWhitespace)
@@ -226,7 +237,7 @@ namespace Emby.Drawing.Skia
             return Decode(path);
         }
 
-        public void EncodeImage(string inputPath, ImageSize? originalImageSize, string outputPath, bool autoOrient, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
+        public string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
         {
             if (string.IsNullOrWhiteSpace(inputPath))
             {
@@ -246,9 +257,20 @@ namespace Emby.Drawing.Skia
 
             using (var bitmap = GetBitmap(inputPath, options.CropWhiteSpace))
             {
-                if (options.CropWhiteSpace || !originalImageSize.HasValue)
+                if (bitmap == null)
+                {
+                    throw new Exception(string.Format("Skia unable to read image {0}", inputPath));
+                }
+
+                //_logger.Info("Color type {0}", bitmap.Info.ColorType);
+
+                var originalImageSize = new ImageSize(bitmap.Width, bitmap.Height);
+                ImageHelper.SaveImageSize(inputPath, dateModified, originalImageSize);
+
+                if (!options.CropWhiteSpace && options.HasDefaultOptions(inputPath, originalImageSize))
                 {
-                    originalImageSize = new ImageSize(bitmap.Width, bitmap.Height);
+                    // Just spit out the original file if all the options are default
+                    return inputPath;
                 }
 
                 var newImageSize = ImageHelper.GetNewImageSize(options, originalImageSize);
@@ -269,7 +291,7 @@ namespace Emby.Drawing.Skia
                         using (var outputStream = new SKFileWStream(outputPath))
                         {
                             resizedBitmap.Encode(outputStream, skiaOutputFormat, quality);
-                            return;
+                            return outputPath;
                         }
                     }
 
@@ -326,6 +348,7 @@ namespace Emby.Drawing.Skia
                     }
                 }
             }
+            return outputPath;
         }
 
         public void CreateImageCollage(ImageCollageOptions options)

+ 65 - 19
Emby.Drawing/ImageProcessor.cs

@@ -75,6 +75,7 @@ namespace Emby.Drawing
 
             ImageEnhancers = new List<IImageEnhancer>();
             _saveImageSizeTimer = timerFactory.Create(SaveImageSizeCallback, null, Timeout.Infinite, Timeout.Infinite);
+            ImageHelper.ImageProcessor = this;
 
             Dictionary<Guid, ImageSize> sizeDictionary;
 
@@ -212,19 +213,12 @@ namespace Emby.Drawing
                 return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
             }
 
-            ImageSize? originalImageSize = null;
-            try
-            {
-                originalImageSize = GetImageSize(originalImagePath, dateModified, true);
-                if (options.HasDefaultOptions(originalImagePath, originalImageSize.Value))
-                {
-                    // Just spit out the original file if all the options are default
-                    return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
-                }
-            }
-            catch
+            ImageSize? originalImageSize = GetSavedImageSize(originalImagePath, dateModified);
+            if (originalImageSize.HasValue && options.HasDefaultOptions(originalImagePath, originalImageSize.Value))
             {
-                originalImageSize = null;
+                // Just spit out the original file if all the options are default
+                _logger.Info("Returning original image {0}", originalImagePath);
+                return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
             }
 
             var newSize = ImageHelper.GetNewImageSize(options, originalImageSize);
@@ -243,7 +237,13 @@ namespace Emby.Drawing
                     var tmpPath = Path.ChangeExtension(Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString("N")), Path.GetExtension(cacheFilePath));
                     _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(tmpPath));
 
-                    _imageEncoder.EncodeImage(originalImagePath, originalImageSize, tmpPath, AutoOrient(options.Item), quality, options, outputFormat);
+                    var resultPath =_imageEncoder.EncodeImage(originalImagePath, dateModified, tmpPath, AutoOrient(options.Item), quality, options, outputFormat);
+
+                    if (string.Equals(resultPath, originalImagePath, StringComparison.OrdinalIgnoreCase))
+                    {
+                        return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
+                    }
+
                     CopyFile(tmpPath, cacheFilePath);
 
                     return new Tuple<string, string, DateTime>(tmpPath, GetMimeType(outputFormat, cacheFilePath), _fileSystem.GetLastWriteTimeUtc(tmpPath));
@@ -422,24 +422,70 @@ namespace Emby.Drawing
                 throw new ArgumentNullException("path");
             }
 
-            var name = path + "datemodified=" + imageDateModified.Ticks;
-
             ImageSize size;
 
-            var cacheHash = name.GetMD5();
+            var cacheHash = GetImageSizeKey(path, imageDateModified);
 
             if (!_cachedImagedSizes.TryGetValue(cacheHash, out size))
             {
                 size = GetImageSizeInternal(path, allowSlowMethod);
 
-                if (size.Width > 0 && size.Height > 0)
+                SaveImageSize(size, cacheHash, false);
+            }
+
+            return size;
+        }
+
+        public void SaveImageSize(string path, DateTime imageDateModified, ImageSize size)
+        {
+            var cacheHash = GetImageSizeKey(path, imageDateModified);
+            SaveImageSize(size, cacheHash, true);
+        }
+
+        private void SaveImageSize(ImageSize size, Guid cacheHash, bool checkExists)
+        {
+            if (size.Width <= 0 || size.Height <= 0)
+            {
+                return;
+            }
+
+            if (checkExists && _cachedImagedSizes.ContainsKey(cacheHash))
+            {
+                return;
+            }
+
+            if (checkExists)
+            {
+                if (_cachedImagedSizes.TryAdd(cacheHash, size))
                 {
                     StartSaveImageSizeTimer();
-                    _cachedImagedSizes.AddOrUpdate(cacheHash, size, (keyName, oldValue) => size);
                 }
             }
+            else
+            {
+                StartSaveImageSizeTimer();
+                _cachedImagedSizes.AddOrUpdate(cacheHash, size, (keyName, oldValue) => size);
+            }
+        }
 
-            return size;
+        private Guid GetImageSizeKey(string path, DateTime imageDateModified)
+        {
+            var name = path + "datemodified=" + imageDateModified.Ticks;
+            return name.GetMD5();
+        }
+
+        public ImageSize? GetSavedImageSize(string path, DateTime imageDateModified)
+        {
+            ImageSize size;
+
+            var cacheHash = GetImageSizeKey(path, imageDateModified);
+
+            if (_cachedImagedSizes.TryGetValue(cacheHash, out size))
+            {
+                return size;
+            }
+
+            return null;
         }
 
         /// <summary>

+ 1 - 1
Emby.Drawing/NullImageEncoder.cs

@@ -32,7 +32,7 @@ namespace Emby.Drawing
             throw new NotImplementedException();
         }
 
-        public void EncodeImage(string inputPath, ImageSize? originalImageSize, string outputPath, bool autoOrient, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
+        public string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
         {
             throw new NotImplementedException();
         }

+ 5 - 3
Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs

@@ -167,10 +167,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings
                             {
                                 var programEntry = programDict[schedule.programID];
 
-                                var data = images[imageIndex].data ?? new List<ScheduleDirect.ImageData>();
-                                data = data.OrderByDescending(GetSizeOrder).ToList();
+                                var allImages = (images[imageIndex].data ?? new List<ScheduleDirect.ImageData>()).OrderByDescending(GetSizeOrder).ToList();
+                                var imagesWithText = allImages.Where(i => string.Equals(i.text, "yes", StringComparison.OrdinalIgnoreCase)).ToList();
+
+                                programEntry.primaryImage = GetProgramImage(ApiUrl, imagesWithText, "Logo", true, 600) ??
+                                    GetProgramImage(ApiUrl, allImages, "Logo", true, 600);
 
-                                programEntry.primaryImage = GetProgramImage(ApiUrl, data, "Logo", true, 600);
                                 //programEntry.thumbImage = GetProgramImage(ApiUrl, data, "Iconic", false);
                                 //programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ??
                                 //    GetProgramImage(ApiUrl, data, "Banner-L1", false) ??

+ 1 - 1
MediaBrowser.Controller/Drawing/IImageEncoder.cs

@@ -19,7 +19,7 @@ namespace MediaBrowser.Controller.Drawing
         /// <summary>
         /// Encodes the image.
         /// </summary>
-        void EncodeImage(string inputPath, ImageSize? originalImageSize, string outputPath, bool autoOrient, int quality, ImageProcessingOptions options, ImageFormat outputFormat);
+        string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, int quality, ImageProcessingOptions options, ImageFormat outputFormat);
 
         /// <summary>
         /// Creates the image collage.

+ 2 - 0
MediaBrowser.Controller/Drawing/IImageProcessor.cs

@@ -114,5 +114,7 @@ namespace MediaBrowser.Controller.Drawing
         bool SupportsImageCollageCreation { get; }
 
         IImageEncoder ImageEncoder { get; set; }
+
+        void SaveImageSize(string path, DateTime imageDateModified, ImageSize size);
     }
 }

+ 9 - 1
MediaBrowser.Controller/Drawing/ImageHelper.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Entities;
+using System;
+using MediaBrowser.Controller.Entities;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Entities;
 
@@ -18,6 +19,13 @@ namespace MediaBrowser.Controller.Drawing
             return GetSizeEstimate(options);
         }
 
+        public static IImageProcessor ImageProcessor { get; set; }
+
+        public static void SaveImageSize(string path, DateTime dateModified, ImageSize size)
+        {
+            ImageProcessor.SaveImageSize(path, dateModified, size);
+        }
+
         private static ImageSize GetSizeEstimate(ImageProcessingOptions options)
         {
             if (options.Width.HasValue && options.Height.HasValue)

+ 14 - 2
MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs

@@ -968,7 +968,7 @@ namespace MediaBrowser.Controller.MediaEncoding
                 {
                     if (bitrate.HasValue && videoStream.BitRate.HasValue)
                     {
-                        bitrate = Math.Min(bitrate.Value, videoStream.BitRate.Value);
+                        bitrate = GetMinBitrate(bitrate.Value, videoStream.BitRate.Value);
                     }
                 }
             }
@@ -981,13 +981,25 @@ namespace MediaBrowser.Controller.MediaEncoding
                 // If a max bitrate was requested, don't let the scaled bitrate exceed it
                 if (request.VideoBitRate.HasValue)
                 {
-                    bitrate = Math.Min(bitrate.Value, request.VideoBitRate.Value);
+                    bitrate = GetMinBitrate(bitrate.Value, request.VideoBitRate.Value);
                 }
             }
 
             return bitrate;
         }
 
+        private int GetMinBitrate(int sourceBitrate, int requestedBitrate)
+        {
+            if (sourceBitrate <= 2000000)
+            {
+                sourceBitrate *= 2;
+            }
+
+            var bitrate = Math.Min(sourceBitrate, requestedBitrate);
+
+            return bitrate;
+        }
+
         public int? GetAudioBitrateParam(BaseEncodingJobOptions request, MediaStream audioStream)
         {
             if (request.AudioBitRate.HasValue)