From 003238ef5e5151c43738fedcc90f83fd5064580a Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sun, 11 Aug 2019 15:11:53 +0200 Subject: Update deps + document startup project * Fixed the release build * Documented all public/internal members of Jellyfin.Server * Enable TreatWarningsAsErrors for debug builds for Jellyfin.Server This will ensure that any new public/internal members of Jellyfin.Server are documented --- MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index c0f92ac4a..681a2e372 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -18,7 +18,7 @@ - + -- cgit v1.2.3 From 838e5d05d51c4c171c07d512f741304a6dc58f24 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sun, 11 Aug 2019 16:52:37 +0200 Subject: Document all public/internal members of Emby.Drawing Forces all new public/internal members to be documented. Enables TreatWarningsAsErrors for Emby.Drawing --- BDInfo/BDInfo.csproj | 1 + DvdLib/DvdLib.csproj | 1 + Emby.Dlna/Emby.Dlna.csproj | 1 + Emby.Drawing/Emby.Drawing.csproj | 2 + Emby.Drawing/ImageProcessor.cs | 159 ++++++++------------- Emby.Drawing/NullImageEncoder.cs | 34 +++-- Emby.IsoMounting/IsoMounter/IsoMounter.csproj | 1 + Emby.Notifications/Emby.Notifications.csproj | 1 + Emby.Photos/Emby.Photos.csproj | 1 + Emby.Server.Implementations/ApplicationHost.cs | 21 +-- Emby.Server.Implementations/Dto/DtoService.cs | 2 +- Emby.XmlTv/Emby.XmlTv/Emby.XmlTv.csproj | 1 + Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj | 1 + MediaBrowser.Api/Images/ImageService.cs | 8 +- MediaBrowser.Api/MediaBrowser.Api.csproj | 1 + MediaBrowser.Common/IApplicationHost.cs | 8 +- MediaBrowser.Common/MediaBrowser.Common.csproj | 1 + MediaBrowser.Controller/Drawing/IImageEncoder.cs | 21 +-- MediaBrowser.Controller/Drawing/IImageProcessor.cs | 30 ++-- .../Drawing/ImageProcessingOptions.cs | 5 +- .../MediaBrowser.Controller.csproj | 1 + .../MediaBrowser.LocalMetadata.csproj | 1 + .../MediaBrowser.MediaEncoding.csproj | 1 + MediaBrowser.Model/MediaBrowser.Model.csproj | 1 + .../MediaBrowser.Providers.csproj | 1 + .../MediaBrowser.WebDashboard.csproj | 1 + .../MediaBrowser.XbmcMetadata.csproj | 1 + 27 files changed, 141 insertions(+), 166 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/BDInfo/BDInfo.csproj b/BDInfo/BDInfo.csproj index b2c752d0c..9dbaa9e2f 100644 --- a/BDInfo/BDInfo.csproj +++ b/BDInfo/BDInfo.csproj @@ -11,6 +11,7 @@ netstandard2.0 false + true diff --git a/DvdLib/DvdLib.csproj b/DvdLib/DvdLib.csproj index b2c752d0c..9dbaa9e2f 100644 --- a/DvdLib/DvdLib.csproj +++ b/DvdLib/DvdLib.csproj @@ -11,6 +11,7 @@ netstandard2.0 false + true diff --git a/Emby.Dlna/Emby.Dlna.csproj b/Emby.Dlna/Emby.Dlna.csproj index 4c07087c5..34b49120b 100644 --- a/Emby.Dlna/Emby.Dlna.csproj +++ b/Emby.Dlna/Emby.Dlna.csproj @@ -14,6 +14,7 @@ netstandard2.0 false + true diff --git a/Emby.Drawing/Emby.Drawing.csproj b/Emby.Drawing/Emby.Drawing.csproj index 9f97baf77..716de059d 100644 --- a/Emby.Drawing/Emby.Drawing.csproj +++ b/Emby.Drawing/Emby.Drawing.csproj @@ -3,6 +3,8 @@ netstandard2.0 false + true + true diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index a7d95eb20..ce8089e59 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -22,42 +22,47 @@ using Microsoft.Extensions.Logging; namespace Emby.Drawing { /// - /// Class ImageProcessor + /// Class ImageProcessor. /// public class ImageProcessor : IImageProcessor, IDisposable { - /// - /// The us culture - /// - protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); + // Increment this when there's a change requiring caches to be invalidated + private const string Version = "3"; - /// - /// Gets the list of currently registered image processors - /// Image processors are specialized metadata providers that run after the normal ones - /// - /// The image enhancers. - public IImageEnhancer[] ImageEnhancers { get; private set; } + private static readonly HashSet _transparentImageTypes + = new HashSet(StringComparer.OrdinalIgnoreCase) { ".png", ".webp", ".gif" }; /// /// The _logger /// private readonly ILogger _logger; - private readonly IFileSystem _fileSystem; private readonly IServerApplicationPaths _appPaths; private IImageEncoder _imageEncoder; private readonly Func _libraryManager; private readonly Func _mediaEncoder; + private readonly Dictionary _locks = new Dictionary(); + private bool _disposed = false; + + /// + /// + /// + /// + /// + /// + /// + /// + /// public ImageProcessor( - ILoggerFactory loggerFactory, + ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem, IImageEncoder imageEncoder, Func libraryManager, Func mediaEncoder) { - _logger = loggerFactory.CreateLogger(nameof(ImageProcessor)); + _logger = logger; _fileSystem = fileSystem; _imageEncoder = imageEncoder; _libraryManager = libraryManager; @@ -69,20 +74,11 @@ namespace Emby.Drawing ImageHelper.ImageProcessor = this; } - public IImageEncoder ImageEncoder - { - get => _imageEncoder; - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } + private string ResizedImageCachePath => Path.Combine(_appPaths.ImageCachePath, "resized-images"); - _imageEncoder = value; - } - } + private string EnhancedImageCachePath => Path.Combine(_appPaths.ImageCachePath, "enhanced-images"); + /// public IReadOnlyCollection SupportedInputFormats => new HashSet(StringComparer.OrdinalIgnoreCase) { @@ -115,18 +111,20 @@ namespace Emby.Drawing "wbmp" }; + /// + public IReadOnlyCollection ImageEnhancers { get; set; } + /// public bool SupportsImageCollageCreation => _imageEncoder.SupportsImageCollageCreation; - private string ResizedImageCachePath => Path.Combine(_appPaths.ImageCachePath, "resized-images"); - - private string EnhancedImageCachePath => Path.Combine(_appPaths.ImageCachePath, "enhanced-images"); - - public void AddParts(IEnumerable enhancers) + /// + public IImageEncoder ImageEncoder { - ImageEnhancers = enhancers.ToArray(); + get => _imageEncoder; + set => _imageEncoder = value ?? throw new ArgumentNullException(nameof(value)); } + /// public async Task ProcessImage(ImageProcessingOptions options, Stream toStream) { var file = await ProcessImage(options).ConfigureAwait(false); @@ -137,15 +135,15 @@ namespace Emby.Drawing } } + /// public IReadOnlyCollection GetSupportedImageOutputFormats() => _imageEncoder.SupportedOutputFormats; - private static readonly HashSet TransparentImageTypes - = new HashSet(StringComparer.OrdinalIgnoreCase) { ".png", ".webp", ".gif" }; - + /// public bool SupportsTransparency(string path) - => TransparentImageTypes.Contains(Path.GetExtension(path)); + => _transparentImageTypes.Contains(Path.GetExtension(path)); + /// public async Task<(string path, string mimeType, DateTime dateModified)> ProcessImage(ImageProcessingOptions options) { if (options == null) @@ -187,9 +185,9 @@ namespace Emby.Drawing } dateModified = supportedImageInfo.dateModified; - bool requiresTransparency = TransparentImageTypes.Contains(Path.GetExtension(originalImagePath)); + bool requiresTransparency = _transparentImageTypes.Contains(Path.GetExtension(originalImagePath)); - if (options.Enhancers.Length > 0) + if (options.Enhancers.Count > 0) { if (item == null) { @@ -279,7 +277,7 @@ namespace Emby.Drawing } } - private ImageFormat GetOutputFormat(ImageFormat[] clientSupportedFormats, bool requiresTransparency) + private ImageFormat GetOutputFormat(IReadOnlyCollection clientSupportedFormats, bool requiresTransparency) { var serverFormats = GetSupportedImageOutputFormats(); @@ -320,11 +318,6 @@ namespace Emby.Drawing } } - /// - /// Increment this when there's a change requiring caches to be invalidated - /// - private const string Version = "3"; - /// /// Gets the cache file path based on a set of parameters /// @@ -372,9 +365,11 @@ namespace Emby.Drawing return GetCachePath(ResizedImageCachePath, filename, "." + format.ToString().ToLowerInvariant()); } + /// public ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info) => GetImageDimensions(item, info, true); + /// public ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info, bool updateItem) { int width = info.Width; @@ -400,26 +395,19 @@ namespace Emby.Drawing return size; } - /// - /// Gets the size of the image. - /// + /// public ImageDimensions GetImageDimensions(string path) => _imageEncoder.GetImageSize(path); - /// - /// Gets the image cache tag. - /// - /// The item. - /// The image. - /// Guid. - /// item + /// public string GetImageCacheTag(BaseItem item, ItemImageInfo image) { - var supportedEnhancers = GetSupportedEnhancers(item, image.Type); + var supportedEnhancers = GetSupportedEnhancers(item, image.Type).ToArray(); return GetImageCacheTag(item, image, supportedEnhancers); } + /// public string GetImageCacheTag(BaseItem item, ChapterInfo chapter) { try @@ -437,22 +425,15 @@ namespace Emby.Drawing } } - /// - /// Gets the image cache tag. - /// - /// The item. - /// The image. - /// The image enhancers. - /// Guid. - /// item - public string GetImageCacheTag(BaseItem item, ItemImageInfo image, IImageEnhancer[] imageEnhancers) + /// + public string GetImageCacheTag(BaseItem item, ItemImageInfo image, IReadOnlyCollection imageEnhancers) { string originalImagePath = image.Path; DateTime dateModified = image.DateModified; ImageType imageType = image.Type; // Optimization - if (imageEnhancers.Length == 0) + if (imageEnhancers.Count == 0) { return (originalImagePath + dateModified.Ticks).GetMD5().ToString("N", CultureInfo.InvariantCulture); } @@ -480,7 +461,7 @@ namespace Emby.Drawing { try { - string filename = (originalImagePath + dateModified.Ticks.ToString(UsCulture)).GetMD5().ToString("N", CultureInfo.InvariantCulture); + string filename = (originalImagePath + dateModified.Ticks.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("N", CultureInfo.InvariantCulture); string cacheExtension = _mediaEncoder().SupportsEncoder("libwebp") ? ".webp" : ".png"; var outputPath = Path.Combine(_appPaths.ImageCachePath, "converted-images", filename + cacheExtension); @@ -507,16 +488,10 @@ namespace Emby.Drawing return (originalImagePath, dateModified); } - /// - /// Gets the enhanced image. - /// - /// The item. - /// Type of the image. - /// Index of the image. - /// Task{System.String}. + /// public async Task GetEnhancedImage(BaseItem item, ImageType imageType, int imageIndex) { - var enhancers = GetSupportedEnhancers(item, imageType); + var enhancers = GetSupportedEnhancers(item, imageType).ToArray(); ItemImageInfo imageInfo = item.GetImageInfo(imageType, imageIndex); @@ -532,7 +507,7 @@ namespace Emby.Drawing bool inputImageSupportsTransparency, BaseItem item, int imageIndex, - IImageEnhancer[] enhancers, + IReadOnlyCollection enhancers, CancellationToken cancellationToken) { var originalImagePath = image.Path; @@ -573,6 +548,7 @@ namespace Emby.Drawing /// Index of the image. /// The supported enhancers. /// The cache unique identifier. + /// The cancellation token. /// Task<System.String>. /// /// originalImagePath @@ -584,9 +560,9 @@ namespace Emby.Drawing BaseItem item, ImageType imageType, int imageIndex, - IImageEnhancer[] supportedEnhancers, + IReadOnlyCollection supportedEnhancers, string cacheGuid, - CancellationToken cancellationToken) + CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(originalImagePath)) { @@ -680,6 +656,7 @@ namespace Emby.Drawing { throw new ArgumentNullException(nameof(path)); } + if (string.IsNullOrEmpty(uniqueName)) { throw new ArgumentNullException(nameof(uniqueName)); @@ -722,6 +699,7 @@ namespace Emby.Drawing return Path.Combine(path, prefix, filename); } + /// public void CreateImageCollage(ImageCollageOptions options) { _logger.LogInformation("Creating image collage and saving to {Path}", options.OutputPath); @@ -731,38 +709,25 @@ namespace Emby.Drawing _logger.LogInformation("Completed creation of image collage and saved to {Path}", options.OutputPath); } - public IImageEnhancer[] GetSupportedEnhancers(BaseItem item, ImageType imageType) + /// + public IEnumerable GetSupportedEnhancers(BaseItem item, ImageType imageType) { - List list = null; - foreach (var i in ImageEnhancers) { - try - { - if (i.Supports(item, imageType)) - { - if (list == null) - { - list = new List(); - } - list.Add(i); - } - } - catch (Exception ex) + if (i.Supports(item, imageType)) { - _logger.LogError(ex, "Error in image enhancer: {0}", i.GetType().Name); + yield return i; } } - - return list == null ? Array.Empty() : list.ToArray(); } - private Dictionary _locks = new Dictionary(); + private class LockInfo { public SemaphoreSlim Lock = new SemaphoreSlim(1, 1); public int Count = 1; } + private LockInfo GetLock(string key) { lock (_locks) @@ -795,7 +760,7 @@ namespace Emby.Drawing } } - private bool _disposed; + /// public void Dispose() { _disposed = true; diff --git a/Emby.Drawing/NullImageEncoder.cs b/Emby.Drawing/NullImageEncoder.cs index fc4a5af9f..5af7f1622 100644 --- a/Emby.Drawing/NullImageEncoder.cs +++ b/Emby.Drawing/NullImageEncoder.cs @@ -5,36 +5,40 @@ using MediaBrowser.Model.Drawing; namespace Emby.Drawing { + /// + /// A fallback implementation of . + /// public class NullImageEncoder : IImageEncoder { + /// public IReadOnlyCollection SupportedInputFormats => new HashSet(StringComparer.OrdinalIgnoreCase) { "png", "jpeg", "jpg" }; + /// public IReadOnlyCollection SupportedOutputFormats => new HashSet() { ImageFormat.Jpg, ImageFormat.Png }; - public void CropWhiteSpace(string inputPath, string outputPath) - { - throw new NotImplementedException(); - } - - public string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, ImageOrientation? orientation, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat) - { - throw new NotImplementedException(); - } - - public void CreateImageCollage(ImageCollageOptions options) - { - throw new NotImplementedException(); - } - + /// public string Name => "Null Image Encoder"; + /// public bool SupportsImageCollageCreation => false; + /// public bool SupportsImageEncoding => false; + /// public ImageDimensions GetImageSize(string path) + => throw new NotImplementedException(); + + /// + public string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, ImageOrientation? orientation, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat) + { + throw new NotImplementedException(); + } + + /// + public void CreateImageCollage(ImageCollageOptions options) { throw new NotImplementedException(); } diff --git a/Emby.IsoMounting/IsoMounter/IsoMounter.csproj b/Emby.IsoMounting/IsoMounter/IsoMounter.csproj index dafa51cd5..0778b987b 100644 --- a/Emby.IsoMounting/IsoMounter/IsoMounter.csproj +++ b/Emby.IsoMounting/IsoMounter/IsoMounter.csproj @@ -12,6 +12,7 @@ netstandard2.0 false + true diff --git a/Emby.Notifications/Emby.Notifications.csproj b/Emby.Notifications/Emby.Notifications.csproj index 5c68e48c8..cbd3bde4f 100644 --- a/Emby.Notifications/Emby.Notifications.csproj +++ b/Emby.Notifications/Emby.Notifications.csproj @@ -3,6 +3,7 @@ netstandard2.0 false + true diff --git a/Emby.Photos/Emby.Photos.csproj b/Emby.Photos/Emby.Photos.csproj index c9830abc5..39b97a3bf 100644 --- a/Emby.Photos/Emby.Photos.csproj +++ b/Emby.Photos/Emby.Photos.csproj @@ -16,6 +16,7 @@ netstandard2.0 false + true diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 09847b2f8..b620f6be2 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -510,13 +510,8 @@ namespace Emby.Server.Implementations return AllConcreteTypes.Where(i => currentType.IsAssignableFrom(i)); } - /// - /// Gets the exports. - /// - /// The type - /// if set to true [manage lifetime]. - /// IEnumerable{``0}. - public IEnumerable GetExports(bool manageLifetime = true) + /// + public IReadOnlyCollection GetExports(bool manageLifetime = true) { var parts = GetExportTypes() .Select(CreateInstanceSafe) @@ -538,6 +533,7 @@ namespace Emby.Server.Implementations /// /// Runs the startup tasks. /// + /// . public async Task RunStartupTasksAsync() { Logger.LogInformation("Running startup tasks"); @@ -550,7 +546,7 @@ namespace Emby.Server.Implementations Logger.LogInformation("ServerId: {0}", SystemId); - var entryPoints = GetExports().ToList(); + var entryPoints = GetExports(); var stopWatch = new Stopwatch(); stopWatch.Start(); @@ -801,7 +797,7 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(HttpServer); - ImageProcessor = GetImageProcessor(); + ImageProcessor = new ImageProcessor(LoggerFactory.CreateLogger(), ServerConfigurationManager.ApplicationPaths, FileSystemManager, ImageEncoder, () => LibraryManager, () => MediaEncoder); serviceCollection.AddSingleton(ImageProcessor); TVSeriesManager = new TVSeriesManager(UserManager, UserDataManager, LibraryManager, ServerConfigurationManager); @@ -953,11 +949,6 @@ namespace Emby.Server.Implementations } } - private IImageProcessor GetImageProcessor() - { - return new ImageProcessor(LoggerFactory, ServerConfigurationManager.ApplicationPaths, FileSystemManager, ImageEncoder, () => LibraryManager, () => MediaEncoder); - } - /// /// Gets the user repository. /// @@ -1087,7 +1078,7 @@ namespace Emby.Server.Implementations GetExports(), GetExports()); - ImageProcessor.AddParts(GetExports()); + ImageProcessor.ImageEnhancers = GetExports(); LiveTvManager.AddParts(GetExports(), GetExports(), GetExports()); diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 6e7aa1313..1a7f10634 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -1364,7 +1364,7 @@ namespace Emby.Server.Implementations.Dto return null; } - var supportedEnhancers = _imageProcessor.GetSupportedEnhancers(item, ImageType.Primary); + var supportedEnhancers = _imageProcessor.GetSupportedEnhancers(item, ImageType.Primary).ToArray(); ImageDimensions size; diff --git a/Emby.XmlTv/Emby.XmlTv/Emby.XmlTv.csproj b/Emby.XmlTv/Emby.XmlTv/Emby.XmlTv.csproj index 0225be2c2..04f558173 100644 --- a/Emby.XmlTv/Emby.XmlTv/Emby.XmlTv.csproj +++ b/Emby.XmlTv/Emby.XmlTv/Emby.XmlTv.csproj @@ -3,6 +3,7 @@ netstandard2.0 false + true diff --git a/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj b/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj index f023bc55d..396bdd4b7 100644 --- a/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj +++ b/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj @@ -3,6 +3,7 @@ netstandard2.0 false + true diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 23c7339d2..6d3037b24 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -550,14 +550,14 @@ namespace MediaBrowser.Api.Images } IImageEnhancer[] supportedImageEnhancers; - if (_imageProcessor.ImageEnhancers.Length > 0) + if (_imageProcessor.ImageEnhancers.Count > 0) { if (item == null) { item = _libraryManager.GetItemById(itemId); } - supportedImageEnhancers = request.EnableImageEnhancers ? _imageProcessor.GetSupportedEnhancers(item, request.Type) : Array.Empty(); + supportedImageEnhancers = request.EnableImageEnhancers ? _imageProcessor.GetSupportedEnhancers(item, request.Type).ToArray() : Array.Empty(); } else { @@ -606,8 +606,8 @@ namespace MediaBrowser.Api.Images ImageRequest request, ItemImageInfo image, bool cropwhitespace, - ImageFormat[] supportedFormats, - IImageEnhancer[] enhancers, + IReadOnlyCollection supportedFormats, + IReadOnlyCollection enhancers, TimeSpan? cacheDuration, IDictionary headers, bool isHeadRequest) diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index ba29c656b..f653270a6 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -12,6 +12,7 @@ netstandard2.0 false + true diff --git a/MediaBrowser.Common/IApplicationHost.cs b/MediaBrowser.Common/IApplicationHost.cs index cb7343440..2248e9c85 100644 --- a/MediaBrowser.Common/IApplicationHost.cs +++ b/MediaBrowser.Common/IApplicationHost.cs @@ -75,10 +75,10 @@ namespace MediaBrowser.Common /// /// Gets the exports. /// - /// - /// if set to true [manage liftime]. - /// IEnumerable{``0}. - IEnumerable GetExports(bool manageLifetime = true); + /// The type. + /// If set to true [manage lifetime]. + /// . + IReadOnlyCollection GetExports(bool manageLifetime = true); /// /// Resolves this instance. diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 05b48a2a1..1b753aa29 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -23,6 +23,7 @@ netstandard2.0 false + true diff --git a/MediaBrowser.Controller/Drawing/IImageEncoder.cs b/MediaBrowser.Controller/Drawing/IImageEncoder.cs index 4eaecd0a0..a0f9ae46e 100644 --- a/MediaBrowser.Controller/Drawing/IImageEncoder.cs +++ b/MediaBrowser.Controller/Drawing/IImageEncoder.cs @@ -17,16 +17,6 @@ namespace MediaBrowser.Controller.Drawing /// The supported output formats. IReadOnlyCollection SupportedOutputFormats { get; } - /// - /// Encodes the image. - /// - string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, ImageOrientation? orientation, int quality, ImageProcessingOptions options, ImageFormat outputFormat); - - /// - /// Creates the image collage. - /// - /// The options. - void CreateImageCollage(ImageCollageOptions options); /// /// Gets the name. /// @@ -46,5 +36,16 @@ namespace MediaBrowser.Controller.Drawing bool SupportsImageEncoding { get; } ImageDimensions GetImageSize(string path); + + /// + /// Encodes the image. + /// + string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, ImageOrientation? orientation, int quality, ImageProcessingOptions options, ImageFormat outputFormat); + + /// + /// Creates the image collage. + /// + /// The options. + void CreateImageCollage(ImageCollageOptions options); } } diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs index a11e2186f..a58a11bd1 100644 --- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs +++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs @@ -24,7 +24,15 @@ namespace MediaBrowser.Controller.Drawing /// Gets the image enhancers. /// /// The image enhancers. - IImageEnhancer[] ImageEnhancers { get; } + IReadOnlyCollection ImageEnhancers { get; set; } + + /// + /// Gets a value indicating whether [supports image collage creation]. + /// + /// true if [supports image collage creation]; otherwise, false. + bool SupportsImageCollageCreation { get; } + + IImageEncoder ImageEncoder { get; set; } /// /// Gets the dimensions of the image. @@ -50,19 +58,13 @@ namespace MediaBrowser.Controller.Drawing /// ImageDimensions ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info, bool updateItem); - /// - /// Adds the parts. - /// - /// The enhancers. - void AddParts(IEnumerable enhancers); - /// /// Gets the supported enhancers. /// /// The item. /// Type of the image. /// IEnumerable{IImageEnhancer}. - IImageEnhancer[] GetSupportedEnhancers(BaseItem item, ImageType imageType); + IEnumerable GetSupportedEnhancers(BaseItem item, ImageType imageType); /// /// Gets the image cache tag. @@ -80,7 +82,7 @@ namespace MediaBrowser.Controller.Drawing /// The image. /// The image enhancers. /// Guid. - string GetImageCacheTag(BaseItem item, ItemImageInfo image, IImageEnhancer[] imageEnhancers); + string GetImageCacheTag(BaseItem item, ItemImageInfo image, IReadOnlyCollection imageEnhancers); /// /// Processes the image. @@ -109,7 +111,7 @@ namespace MediaBrowser.Controller.Drawing /// /// Gets the supported image output formats. /// - /// IReadOnlyCollection{ImageOutput}. + /// . IReadOnlyCollection GetSupportedImageOutputFormats(); /// @@ -118,14 +120,6 @@ namespace MediaBrowser.Controller.Drawing /// The options. void CreateImageCollage(ImageCollageOptions options); - /// - /// Gets a value indicating whether [supports image collage creation]. - /// - /// true if [supports image collage creation]; otherwise, false. - bool SupportsImageCollageCreation { get; } - - IImageEncoder ImageEncoder { get; set; } - bool SupportsTransparency(string path); } } diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs index db432f500..29addf6e6 100644 --- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs +++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using MediaBrowser.Controller.Entities; @@ -33,9 +34,9 @@ namespace MediaBrowser.Controller.Drawing public int Quality { get; set; } - public IImageEnhancer[] Enhancers { get; set; } + public IReadOnlyCollection Enhancers { get; set; } - public ImageFormat[] SupportedOutputFormats { get; set; } + public IReadOnlyCollection SupportedOutputFormats { get; set; } public bool AddPlayedIndicator { get; set; } diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 01893f1b5..c6bca2518 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -19,6 +19,7 @@ netstandard2.0 false + true diff --git a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj index 867b82ede..a8f8da9b8 100644 --- a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj +++ b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj @@ -12,6 +12,7 @@ netstandard2.0 false + true diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index c0f92ac4a..05af9fd03 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -3,6 +3,7 @@ netstandard2.0 false + true diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 3de2cca2d..e9f43ea56 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -10,6 +10,7 @@ netstandard2.0 false + true diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 5941ed436..ab4759c61 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -21,6 +21,7 @@ netstandard2.0 false + true diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index c099e77d6..883986894 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -18,6 +18,7 @@ netstandard2.0 false + true diff --git a/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj b/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj index ba29c656b..f653270a6 100644 --- a/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj +++ b/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj @@ -12,6 +12,7 @@ netstandard2.0 false + true -- cgit v1.2.3 From 1616f24cee15095b22092c63b5627662bf47befc Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sun, 1 Sep 2019 18:39:23 +0200 Subject: Fix more warnings --- Emby.Photos/PhotoProvider.cs | 4 +- .../MediaEncoder/EncodingManager.cs | 2 +- .../MediaEncoding/EncodingHelper.cs | 775 ++++++++++++--------- .../MediaEncoding/MediaEncoderHelpers.cs | 17 +- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 2 +- .../MediaInfo/VideoImageProvider.cs | 2 +- MediaBrowser.XbmcMetadata/EntryPoint.cs | 16 +- MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs | 39 +- MediaBrowser.sln | 8 +- 9 files changed, 492 insertions(+), 373 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/Emby.Photos/PhotoProvider.cs b/Emby.Photos/PhotoProvider.cs index 99a635e60..1591609ab 100644 --- a/Emby.Photos/PhotoProvider.cs +++ b/Emby.Photos/PhotoProvider.cs @@ -170,8 +170,8 @@ namespace Emby.Photos } } - const ItemUpdateType result = ItemUpdateType.ImageUpdate | ItemUpdateType.MetadataImport; - return Task.FromResult(result); + const ItemUpdateType Result = ItemUpdateType.ImageUpdate | ItemUpdateType.MetadataImport; + return Task.FromResult(Result); } } } diff --git a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs index 52d07d784..840aca7a6 100644 --- a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs +++ b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs @@ -139,7 +139,7 @@ namespace Emby.Server.Implementations.MediaEncoder var protocol = MediaProtocol.File; - var inputPath = MediaEncoderHelpers.GetInputArgument(_fileSystem, video.Path, protocol, null, Array.Empty()); + var inputPath = MediaEncoderHelpers.GetInputArgument(_fileSystem, video.Path, null, Array.Empty()); Directory.CreateDirectory(Path.GetDirectoryName(path)); diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 5665e72cf..963091673 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Text; using System.Threading; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Configuration; @@ -22,8 +23,17 @@ namespace MediaBrowser.Controller.MediaEncoding private readonly IMediaEncoder _mediaEncoder; private readonly IFileSystem _fileSystem; private readonly ISubtitleEncoder _subtitleEncoder; - // private readonly IApplicationPaths _appPaths; - // private readonly IAssemblyInfo _assemblyInfo; + + private static readonly string[] _videoProfiles = new[] + { + "ConstrainedBaseline", + "Baseline", + "Extended", + "Main", + "High", + "ProgressiveHigh", + "ConstrainedHigh" + }; public EncodingHelper(IMediaEncoder mediaEncoder, IFileSystem fileSystem, ISubtitleEncoder subtitleEncoder) { @@ -33,14 +43,10 @@ namespace MediaBrowser.Controller.MediaEncoding } public string GetH264Encoder(EncodingJobInfo state, EncodingOptions encodingOptions) - { - return GetH264OrH265Encoder("libx264", "h264", state, encodingOptions); - } + => GetH264OrH265Encoder("libx264", "h264", state, encodingOptions); public string GetH265Encoder(EncodingJobInfo state, EncodingOptions encodingOptions) - { - return GetH264OrH265Encoder("libx265", "hevc", state, encodingOptions); - } + => GetH264OrH265Encoder("libx265", "hevc", state, encodingOptions); private string GetH264OrH265Encoder(string defaultEncoder, string hwEncoder, EncodingJobInfo state, EncodingOptions encodingOptions) { @@ -64,19 +70,17 @@ namespace MediaBrowser.Controller.MediaEncoding }; if (!string.IsNullOrEmpty(hwType) - && encodingOptions.EnableHardwareEncoding && codecMap.ContainsKey(hwType)) + && encodingOptions.EnableHardwareEncoding + && codecMap.ContainsKey(hwType) + && CheckVaapi(state, hwType, encodingOptions)) { - if (CheckVaapi(state, hwType, encodingOptions)) - { - var preferredEncoder = codecMap[hwType]; + var preferredEncoder = codecMap[hwType]; - if (_mediaEncoder.SupportsEncoder(preferredEncoder)) - { - return preferredEncoder; - } + if (_mediaEncoder.SupportsEncoder(preferredEncoder)) + { + return preferredEncoder; } } - } // Avoid performing a second attempt when the first one @@ -106,15 +110,13 @@ namespace MediaBrowser.Controller.MediaEncoding { var videoStream = state.VideoStream; - if (videoStream != null) + // vaapi will throw an error with this input + // [vaapi @ 0x7faed8000960] No VAAPI support for codec mpeg4 profile -99. + if (string.Equals(videoStream?.Codec, "mpeg4", StringComparison.OrdinalIgnoreCase)) { - // vaapi will throw an error with this input - // [vaapi @ 0x7faed8000960] No VAAPI support for codec mpeg4 profile -99. - if (string.Equals(videoStream.Codec, "mpeg4", StringComparison.OrdinalIgnoreCase)) - { - return false; - } + return false; } + return true; } @@ -127,23 +129,27 @@ namespace MediaBrowser.Controller.MediaEncoding if (!string.IsNullOrEmpty(codec)) { - if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase) || - string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase) + || string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)) { return GetH265Encoder(state, encodingOptions); } + if (string.Equals(codec, "h264", StringComparison.OrdinalIgnoreCase)) { return GetH264Encoder(state, encodingOptions); } + if (string.Equals(codec, "vpx", StringComparison.OrdinalIgnoreCase)) { return "libvpx"; } + if (string.Equals(codec, "wmv", StringComparison.OrdinalIgnoreCase)) { return "wmv2"; } + if (string.Equals(codec, "theora", StringComparison.OrdinalIgnoreCase)) { return "libtheora"; @@ -162,9 +168,7 @@ namespace MediaBrowser.Controller.MediaEncoding /// System.String. public string GetUserAgentParam(EncodingJobInfo state) { - string useragent = null; - - state.RemoteHttpHeaders.TryGetValue("User-Agent", out useragent); + state.RemoteHttpHeaders.TryGetValue("User-Agent", out string useragent); if (!string.IsNullOrEmpty(useragent)) { @@ -193,50 +197,62 @@ namespace MediaBrowser.Controller.MediaEncoding { return null; } + if (string.Equals(container, "wmv", StringComparison.OrdinalIgnoreCase)) { return null; } + if (string.Equals(container, "mts", StringComparison.OrdinalIgnoreCase)) { return null; } + if (string.Equals(container, "vob", StringComparison.OrdinalIgnoreCase)) { return null; } + if (string.Equals(container, "mpg", StringComparison.OrdinalIgnoreCase)) { return null; } + if (string.Equals(container, "mpeg", StringComparison.OrdinalIgnoreCase)) { return null; } + if (string.Equals(container, "rec", StringComparison.OrdinalIgnoreCase)) { return null; } + if (string.Equals(container, "dvr-ms", StringComparison.OrdinalIgnoreCase)) { return null; } + if (string.Equals(container, "ogm", StringComparison.OrdinalIgnoreCase)) { return null; } + if (string.Equals(container, "divx", StringComparison.OrdinalIgnoreCase)) { return null; } + if (string.Equals(container, "tp", StringComparison.OrdinalIgnoreCase)) { return null; } + if (string.Equals(container, "rmvb", StringComparison.OrdinalIgnoreCase)) { return null; } + if (string.Equals(container, "rtp", StringComparison.OrdinalIgnoreCase)) { return null; @@ -264,10 +280,12 @@ namespace MediaBrowser.Controller.MediaEncoding { return null; } + if (string.Equals(codec, "aac_latm", StringComparison.OrdinalIgnoreCase)) { return null; } + if (string.Equals(codec, "eac3", StringComparison.OrdinalIgnoreCase)) { return null; @@ -292,30 +310,37 @@ namespace MediaBrowser.Controller.MediaEncoding { return "mp3"; } + if (string.Equals(ext, ".aac", StringComparison.OrdinalIgnoreCase)) { return "aac"; } + if (string.Equals(ext, ".wma", StringComparison.OrdinalIgnoreCase)) { return "wma"; } + if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase)) { return "vorbis"; } + if (string.Equals(ext, ".oga", StringComparison.OrdinalIgnoreCase)) { return "vorbis"; } + if (string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase)) { return "vorbis"; } + if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase)) { return "vorbis"; } + if (string.Equals(ext, ".webma", StringComparison.OrdinalIgnoreCase)) { return "vorbis"; @@ -337,14 +362,17 @@ namespace MediaBrowser.Controller.MediaEncoding { return "wmv"; } + if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase)) { return "vpx"; } + if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase)) { return "theora"; } + if (string.Equals(ext, ".m3u8", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ts", StringComparison.OrdinalIgnoreCase)) { return "h264"; @@ -355,19 +383,9 @@ namespace MediaBrowser.Controller.MediaEncoding public int GetVideoProfileScore(string profile) { - var list = new[] - { - "ConstrainedBaseline", - "Baseline", - "Extended", - "Main", - "High", - "ProgressiveHigh", - "ConstrainedHigh" - }; - // strip spaces because they may be stripped out on the query string - return Array.FindIndex(list, t => string.Equals(t, profile.Replace(" ", ""), StringComparison.OrdinalIgnoreCase)); + profile = profile.Replace(" ", ""); + return Array.FindIndex(_videoProfiles, x => string.Equals(x, profile, StringComparison.OrdinalIgnoreCase)); } public string GetInputPathArgument(EncodingJobInfo state) @@ -375,14 +393,19 @@ namespace MediaBrowser.Controller.MediaEncoding var protocol = state.InputProtocol; var mediaPath = state.MediaPath ?? string.Empty; - var inputPath = new[] { mediaPath }; - - if (state.IsInputVideo) + string[] inputPath; + if (state.IsInputVideo + && !(state.VideoType == VideoType.Iso && state.IsoMount == null)) { - if (!(state.VideoType == VideoType.Iso && state.IsoMount == null)) - { - inputPath = MediaEncoderHelpers.GetInputArgument(_fileSystem, mediaPath, state.InputProtocol, state.IsoMount, state.PlayableStreamFileNames); - } + inputPath = MediaEncoderHelpers.GetInputArgument( + _fileSystem, + mediaPath, + state.IsoMount, + state.PlayableStreamFileNames); + } + else + { + inputPath = new[] { mediaPath }; } return _mediaEncoder.GetInputArgument(inputPath, protocol); @@ -401,18 +424,22 @@ namespace MediaBrowser.Controller.MediaEncoding { return "aac -strict experimental"; } + if (string.Equals(codec, "mp3", StringComparison.OrdinalIgnoreCase)) { return "libmp3lame"; } + if (string.Equals(codec, "vorbis", StringComparison.OrdinalIgnoreCase)) { return "libvorbis"; } + if (string.Equals(codec, "wma", StringComparison.OrdinalIgnoreCase)) { return "wmav2"; } + if (string.Equals(codec, "opus", StringComparison.OrdinalIgnoreCase)) { return "libopus"; @@ -426,54 +453,59 @@ namespace MediaBrowser.Controller.MediaEncoding /// public string GetInputArgument(EncodingJobInfo state, EncodingOptions encodingOptions) { - var request = state.BaseRequest; - - var arg = string.Format("-i {0}", GetInputPathArgument(state)); + var arg = new StringBuilder(); - if (state.SubtitleStream != null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode) + if (state.IsVideoRequest + && string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)) { - if (state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream) + var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; + var hwOutputFormat = "vaapi"; + + if (hasGraphicalSubs) { - if (state.VideoStream != null && state.VideoStream.Width.HasValue) - { - // This is hacky but not sure how to get the exact subtitle resolution - int height = Convert.ToInt32((double)state.VideoStream.Width.Value / 16.0 * 9.0); + hwOutputFormat = "yuv420p"; + } - arg += string.Format(" -canvas_size {0}:{1}", state.VideoStream.Width.Value.ToString(CultureInfo.InvariantCulture), height.ToString(CultureInfo.InvariantCulture)); - } + arg.Append("-hwaccel vaapi -hwaccel_output_format ") + .Append(hwOutputFormat) + .Append(" -vaapi_device ") + .Append(encodingOptions.VaapiDevice) + .Append(' '); + } - var subtitlePath = state.SubtitleStream.Path; + arg.Append("-i ") + .Append(GetInputPathArgument(state)); - if (string.Equals(Path.GetExtension(subtitlePath), ".sub", StringComparison.OrdinalIgnoreCase)) - { - var idxFile = Path.ChangeExtension(subtitlePath, ".idx"); - if (File.Exists(idxFile)) - { - subtitlePath = idxFile; - } - } + if (state.SubtitleStream != null + && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode + && state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream) + { + if (state.VideoStream != null && state.VideoStream.Width.HasValue) + { + // This is hacky but not sure how to get the exact subtitle resolution + int height = Convert.ToInt32(state.VideoStream.Width.Value / 16.0 * 9.0); - arg += " -i \"" + subtitlePath + "\""; + arg.Append(" -canvas_size ") + .Append(state.VideoStream.Width.Value.ToString(CultureInfo.InvariantCulture)) + .Append(':') + .Append(height.ToString(CultureInfo.InvariantCulture)); } - } - if (state.IsVideoRequest) - { - if (string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)) - { - var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; - var hwOutputFormat = "vaapi"; + var subtitlePath = state.SubtitleStream.Path; - if (hasGraphicalSubs) + if (string.Equals(Path.GetExtension(subtitlePath), ".sub", StringComparison.OrdinalIgnoreCase)) + { + var idxFile = Path.ChangeExtension(subtitlePath, ".idx"); + if (File.Exists(idxFile)) { - hwOutputFormat = "yuv420p"; + subtitlePath = idxFile; } - - arg = "-hwaccel vaapi -hwaccel_output_format " + hwOutputFormat + " -vaapi_device " + encodingOptions.VaapiDevice + " " + arg; } + + arg.Append(" -i \"").Append(subtitlePath).Append('\"'); } - return arg.Trim(); + return arg.ToString(); } /// @@ -485,16 +517,16 @@ namespace MediaBrowser.Controller.MediaEncoding { var codec = stream.Codec ?? string.Empty; - return codec.IndexOf("264", StringComparison.OrdinalIgnoreCase) != -1 || - codec.IndexOf("avc", StringComparison.OrdinalIgnoreCase) != -1; + return codec.IndexOf("264", StringComparison.OrdinalIgnoreCase) != -1 + || codec.IndexOf("avc", StringComparison.OrdinalIgnoreCase) != -1; } public bool IsH265(MediaStream stream) { var codec = stream.Codec ?? string.Empty; - return codec.IndexOf("265", StringComparison.OrdinalIgnoreCase) != -1 || - codec.IndexOf("hevc", StringComparison.OrdinalIgnoreCase) != -1; + return codec.IndexOf("265", StringComparison.OrdinalIgnoreCase) != -1 + || codec.IndexOf("hevc", StringComparison.OrdinalIgnoreCase) != -1; } public string GetBitStreamArgs(MediaStream stream) @@ -523,27 +555,38 @@ namespace MediaBrowser.Controller.MediaEncoding { // With vpx when crf is used, b:v becomes a max rate // https://trac.ffmpeg.org/wiki/vpxEncodingGuide. - return string.Format(" -maxrate:v {0} -bufsize:v {1} -b:v {0}", bitrate.Value.ToString(_usCulture), (bitrate.Value * 2).ToString(_usCulture)); + return string.Format( + CultureInfo.InvariantCulture, + " -maxrate:v {0} -bufsize:v {1} -b:v {0}", + bitrate.Value, + bitrate.Value * 2); } if (string.Equals(videoCodec, "msmpeg4", StringComparison.OrdinalIgnoreCase)) { - return string.Format(" -b:v {0}", bitrate.Value.ToString(_usCulture)); + return string.Format( + CultureInfo.InvariantCulture, + " -b:v {0}", + bitrate.Value); } if (string.Equals(videoCodec, "libx264", StringComparison.OrdinalIgnoreCase) || string.Equals(videoCodec, "libx265", StringComparison.OrdinalIgnoreCase)) { // h264 - return string.Format(" -maxrate {0} -bufsize {1}", - bitrate.Value.ToString(_usCulture), - (bitrate.Value * 2).ToString(_usCulture)); + return string.Format( + CultureInfo.InvariantCulture, + " -maxrate {0} -bufsize {1}", + bitrate.Value, + bitrate.Value * 2); } // h264 - return string.Format(" -b:v {0} -maxrate {0} -bufsize {1}", - bitrate.Value.ToString(_usCulture), - (bitrate.Value * 2).ToString(_usCulture)); + return string.Format( + CultureInfo.InvariantCulture, + " -b:v {0} -maxrate {0} -bufsize {1}", + bitrate.Value, + bitrate.Value * 2); } return string.Empty; @@ -576,7 +619,7 @@ namespace MediaBrowser.Controller.MediaEncoding // hls always copies timestamps var setPtsParam = state.CopyTimestamps || state.TranscodingType != TranscodingJobType.Progressive ? string.Empty - : string.Format(",setpts=PTS -{0}/TB", seconds.ToString(_usCulture)); + : string.Format(CultureInfo.InvariantCulture, ",setpts=PTS -{0}/TB", seconds); // TODO // var fallbackFontPath = Path.Combine(_appPaths.ProgramDataPath, "fonts", "DroidSansFallback.ttf"); @@ -684,6 +727,7 @@ namespace MediaBrowser.Controller.MediaEncoding { encodeCrf = encodingOptions.H265Crf; } + if (encodeCrf >= 0 && encodeCrf <= 51) { param += " -crf " + encodeCrf.ToString(CultureInfo.InvariantCulture); @@ -695,12 +739,11 @@ namespace MediaBrowser.Controller.MediaEncoding { defaultCrf = "28"; } + param += " -crf " + defaultCrf; } } - - // h264 (h264_qsv) - else if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase)) + else if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase)) // h264 (h264_qsv) { string[] valid_h264_qsv = { "veryslow", "slower", "slow", "medium", "fast", "faster", "veryfast" }; @@ -716,10 +759,8 @@ namespace MediaBrowser.Controller.MediaEncoding param += " -look_ahead 0"; } - - // h264 (h264_nvenc) - else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) || - string.Equals(videoEncoder, "hevc_nvenc", StringComparison.OrdinalIgnoreCase)) + else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) // h264 (h264_nvenc) + || string.Equals(videoEncoder, "hevc_nvenc", StringComparison.OrdinalIgnoreCase)) { switch (encodingOptions.EncoderPreset) { @@ -750,9 +791,7 @@ namespace MediaBrowser.Controller.MediaEncoding break; } } - - // webm - else if (string.Equals(videoEncoder, "libvpx", StringComparison.OrdinalIgnoreCase)) + else if (string.Equals(videoEncoder, "libvpx", StringComparison.OrdinalIgnoreCase)) // webm { // Values 0-3, 0 being highest quality but slower var profileScore = 0; @@ -778,18 +817,14 @@ namespace MediaBrowser.Controller.MediaEncoding qmin, qmax); } - else if (string.Equals(videoEncoder, "mpeg4", StringComparison.OrdinalIgnoreCase)) { param += "-mbd rd -flags +mv4+aic -trellis 2 -cmp 2 -subcmp 2 -bf 2"; } - - // asf/wmv - else if (string.Equals(videoEncoder, "wmv2", StringComparison.OrdinalIgnoreCase)) + else if (string.Equals(videoEncoder, "wmv2", StringComparison.OrdinalIgnoreCase)) // asf/wmv { param += "-qmin 2"; } - else if (string.Equals(videoEncoder, "msmpeg4", StringComparison.OrdinalIgnoreCase)) { param += "-mbd 2"; @@ -805,21 +840,21 @@ namespace MediaBrowser.Controller.MediaEncoding var targetVideoCodec = state.ActualOutputVideoCodec; - var request = state.BaseRequest; var profile = state.GetRequestedProfiles(targetVideoCodec).FirstOrDefault(); // vaapi does not support Baseline profile, force Constrained Baseline in this case, // which is compatible (and ugly) - if (string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) && - profile != null && profile.ToLowerInvariant().Contains("baseline")) + if (string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) + && profile != null + && profile.IndexOf("baseline", StringComparison.OrdinalIgnoreCase) != -1) { - profile = "constrained_baseline"; + profile = "constrained_baseline"; } if (!string.IsNullOrEmpty(profile)) { - if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) && - !string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase)) + if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) + && !string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase)) { // not supported by h264_omx param += " -profile:v " + profile; @@ -834,9 +869,9 @@ namespace MediaBrowser.Controller.MediaEncoding // h264_qsv and h264_nvenc expect levels to be expressed as a decimal. libx264 supports decimal and non-decimal format // also needed for libx264 due to https://trac.ffmpeg.org/ticket/3307 - if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) || - string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase) || - string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase)) { switch (level) { @@ -872,11 +907,11 @@ namespace MediaBrowser.Controller.MediaEncoding break; } } - // nvenc doesn't decode with param -level set ?! - else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) || - string.Equals(videoEncoder, "hevc_nvenc", StringComparison.OrdinalIgnoreCase)) + else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoEncoder, "hevc_nvenc", StringComparison.OrdinalIgnoreCase)) { - // todo param += ""; + // nvenc doesn't decode with param -level set ?! + // TODO: } else if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase)) { @@ -894,10 +929,10 @@ namespace MediaBrowser.Controller.MediaEncoding // todo } - if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) && - !string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) && - !string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) && - !string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase)) + if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) + && !string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) + && !string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) + && !string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase)) { param = "-pix_fmt yuv420p " + param; } @@ -919,12 +954,10 @@ namespace MediaBrowser.Controller.MediaEncoding return false; } - if (videoStream.IsInterlaced) + if (videoStream.IsInterlaced + && state.DeInterlace(videoStream.Codec, false)) { - if (state.DeInterlace(videoStream.Codec, false)) - { - return false; - } + return false; } if (videoStream.IsAnamorphic ?? false) @@ -936,24 +969,23 @@ namespace MediaBrowser.Controller.MediaEncoding } // Can't stream copy if we're burning in subtitles - if (request.SubtitleStreamIndex.HasValue) + if (request.SubtitleStreamIndex.HasValue + && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode) { - if (state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode) - { - return false; - } + return false; } - if (string.Equals("h264", videoStream.Codec, StringComparison.OrdinalIgnoreCase)) + if (string.Equals("h264", videoStream.Codec, StringComparison.OrdinalIgnoreCase) + && videoStream.IsAVC.HasValue + && !videoStream.IsAVC.Value + && request.RequireAvc) { - if (videoStream.IsAVC.HasValue && !videoStream.IsAVC.Value && request.RequireAvc) - { - return false; - } + return false; } // Source and target codecs must match - if (string.IsNullOrEmpty(videoStream.Codec) || !state.SupportedVideoCodecs.Contains(videoStream.Codec, StringComparer.OrdinalIgnoreCase)) + if (string.IsNullOrEmpty(videoStream.Codec) + || !state.SupportedVideoCodecs.Contains(videoStream.Codec, StringComparer.OrdinalIgnoreCase)) { return false; } @@ -983,21 +1015,17 @@ namespace MediaBrowser.Controller.MediaEncoding } // Video width must fall within requested value - if (request.MaxWidth.HasValue) + if (request.MaxWidth.HasValue + && (!videoStream.Width.HasValue || videoStream.Width.Value > request.MaxWidth.Value)) { - if (!videoStream.Width.HasValue || videoStream.Width.Value > request.MaxWidth.Value) - { - return false; - } + return false; } // Video height must fall within requested value - if (request.MaxHeight.HasValue) + if (request.MaxHeight.HasValue + && (!videoStream.Height.HasValue || videoStream.Height.Value > request.MaxHeight.Value)) { - if (!videoStream.Height.HasValue || videoStream.Height.Value > request.MaxHeight.Value) - { - return false; - } + return false; } // Video framerate must fall within requested value @@ -1013,12 +1041,10 @@ namespace MediaBrowser.Controller.MediaEncoding } // Video bitrate must fall within requested value - if (request.VideoBitRate.HasValue) + if (request.VideoBitRate.HasValue + && (!videoStream.BitRate.HasValue || videoStream.BitRate.Value > request.VideoBitRate.Value)) { - if (!videoStream.BitRate.HasValue || videoStream.BitRate.Value > request.VideoBitRate.Value) - { - return false; - } + return false; } var maxBitDepth = state.GetRequestedVideoBitDepth(videoStream.Codec); @@ -1031,35 +1057,31 @@ namespace MediaBrowser.Controller.MediaEncoding } var maxRefFrames = state.GetRequestedMaxRefFrames(videoStream.Codec); - if (maxRefFrames.HasValue) + if (maxRefFrames.HasValue + && videoStream.RefFrames.HasValue && videoStream.RefFrames.Value > maxRefFrames.Value) { - if (videoStream.RefFrames.HasValue && videoStream.RefFrames.Value > maxRefFrames.Value) - { - return false; - } + return false; } // If a specific level was requested, the source must match or be less than var level = state.GetRequestedLevel(videoStream.Codec); - if (!string.IsNullOrEmpty(level)) + if (!string.IsNullOrEmpty(level) + && double.TryParse(level, NumberStyles.Any, _usCulture, out var requestLevel)) { - if (double.TryParse(level, NumberStyles.Any, _usCulture, out var requestLevel)) + if (!videoStream.Level.HasValue) { - if (!videoStream.Level.HasValue) - { - //return false; - } + //return false; + } - if (videoStream.Level.HasValue && videoStream.Level.Value > requestLevel) - { - return false; - } + if (videoStream.Level.HasValue && videoStream.Level.Value > requestLevel) + { + return false; } } - if (string.Equals(state.InputContainer, "avi", StringComparison.OrdinalIgnoreCase) && - string.Equals(videoStream.Codec, "h264", StringComparison.OrdinalIgnoreCase) && - !(videoStream.IsAVC ?? false)) + if (string.Equals(state.InputContainer, "avi", StringComparison.OrdinalIgnoreCase) + && string.Equals(videoStream.Codec, "h264", StringComparison.OrdinalIgnoreCase) + && !(videoStream.IsAVC ?? false)) { // see Coach S01E01 - Kelly and the Professor(0).avi return false; @@ -1068,7 +1090,7 @@ namespace MediaBrowser.Controller.MediaEncoding return request.EnableAutoStreamCopy; } - public bool CanStreamCopyAudio(EncodingJobInfo state, MediaStream audioStream, string[] supportedAudioCodecs) + public bool CanStreamCopyAudio(EncodingJobInfo state, MediaStream audioStream, IEnumerable supportedAudioCodecs) { var request = state.BaseRequest; @@ -1078,16 +1100,16 @@ namespace MediaBrowser.Controller.MediaEncoding } var maxBitDepth = state.GetRequestedAudioBitDepth(audioStream.Codec); - if (maxBitDepth.HasValue) + if (maxBitDepth.HasValue + && audioStream.BitDepth.HasValue + && audioStream.BitDepth.Value > maxBitDepth.Value) { - if (audioStream.BitDepth.HasValue && audioStream.BitDepth.Value > maxBitDepth.Value) - { - return false; - } + return false; } // Source and target codecs must match - if (string.IsNullOrEmpty(audioStream.Codec) || !supportedAudioCodecs.Contains(audioStream.Codec, StringComparer.OrdinalIgnoreCase)) + if (string.IsNullOrEmpty(audioStream.Codec) + || !supportedAudioCodecs.Contains(audioStream.Codec, StringComparer.OrdinalIgnoreCase)) { return false; } @@ -1100,6 +1122,7 @@ namespace MediaBrowser.Controller.MediaEncoding { return false; } + if (audioStream.Channels.Value > channels.Value) { return false; @@ -1113,6 +1136,7 @@ namespace MediaBrowser.Controller.MediaEncoding { return false; } + if (audioStream.SampleRate.Value > request.AudioSampleRate.Value) { return false; @@ -1126,6 +1150,7 @@ namespace MediaBrowser.Controller.MediaEncoding { return false; } + if (audioStream.BitRate.Value > request.AudioBitRate.Value) { return false; @@ -1141,17 +1166,17 @@ namespace MediaBrowser.Controller.MediaEncoding if (videoStream != null) { - var isUpscaling = request.Height.HasValue && videoStream.Height.HasValue && - request.Height.Value > videoStream.Height.Value && request.Width.HasValue && videoStream.Width.HasValue && - request.Width.Value > videoStream.Width.Value; + var isUpscaling = request.Height.HasValue + && videoStream.Height.HasValue + && request.Height.Value > videoStream.Height.Value + && request.Width.HasValue + && videoStream.Width.HasValue + && request.Width.Value > videoStream.Width.Value; // Don't allow bitrate increases unless upscaling - if (!isUpscaling) + if (!isUpscaling && bitrate.HasValue && videoStream.BitRate.HasValue) { - if (bitrate.HasValue && videoStream.BitRate.HasValue) - { - bitrate = GetMinBitrate(videoStream.BitRate.Value, bitrate.Value); - } + bitrate = GetMinBitrate(videoStream.BitRate.Value, bitrate.Value); } } @@ -1179,7 +1204,7 @@ namespace MediaBrowser.Controller.MediaEncoding } else if (sourceBitrate <= 3000000) { - sourceBitrate = Convert.ToInt32(sourceBitrate * 2); + sourceBitrate *= 2; } var bitrate = Math.Min(sourceBitrate, requestedBitrate); @@ -1189,12 +1214,13 @@ namespace MediaBrowser.Controller.MediaEncoding private static double GetVideoBitrateScaleFactor(string codec) { - if (StringHelper.EqualsIgnoreCase(codec, "h265") || - StringHelper.EqualsIgnoreCase(codec, "hevc") || - StringHelper.EqualsIgnoreCase(codec, "vp9")) + if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase) + || string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase) + || string.Equals(codec, "vp9", StringComparison.OrdinalIgnoreCase)) { return .5; } + return 1; } @@ -1221,9 +1247,7 @@ namespace MediaBrowser.Controller.MediaEncoding scaleFactor = Math.Max(scaleFactor, 2); } - var newBitrate = scaleFactor * bitrate; - - return Convert.ToInt32(newBitrate); + return Convert.ToInt32(scaleFactor * bitrate); } public int? GetAudioBitrateParam(BaseEncodingJobOptions request, MediaStream audioStream) @@ -1235,7 +1259,6 @@ namespace MediaBrowser.Controller.MediaEncoding // Don't encode any higher than this return Math.Min(384000, request.AudioBitRate.Value); - //return Math.Min(currentBitrate, request.AudioBitRate.Value); } return null; @@ -1248,12 +1271,14 @@ namespace MediaBrowser.Controller.MediaEncoding var filters = new List(); // Boost volume to 200% when downsampling from 6ch to 2ch - if (channels.HasValue && channels.Value <= 2) + if (channels.HasValue + && channels.Value <= 2 + && state.AudioStream != null + && state.AudioStream.Channels.HasValue + && state.AudioStream.Channels.Value > 5 + && !encodingOptions.DownMixAudioBoost.Equals(1)) { - if (state.AudioStream != null && state.AudioStream.Channels.HasValue && state.AudioStream.Channels.Value > 5 && !encodingOptions.DownMixAudioBoost.Equals(1)) - { - filters.Add("volume=" + encodingOptions.DownMixAudioBoost.ToString(_usCulture)); - } + filters.Add("volume=" + encodingOptions.DownMixAudioBoost.ToString(_usCulture)); } var isCopyingTimestamps = state.CopyTimestamps || state.TranscodingType != TranscodingJobType.Progressive; @@ -1261,12 +1286,16 @@ namespace MediaBrowser.Controller.MediaEncoding { var seconds = TimeSpan.FromTicks(state.StartTimeTicks ?? 0).TotalSeconds; - filters.Add(string.Format("asetpts=PTS-{0}/TB", Math.Round(seconds).ToString(_usCulture))); + filters.Add( + string.Format( + CultureInfo.InvariantCulture, + "asetpts=PTS-{0}/TB", + Math.Round(seconds))); } if (filters.Count > 0) { - return "-af \"" + string.Join(",", filters.ToArray()) + "\""; + return "-af \"" + string.Join(",", filters) + "\""; } return string.Empty; @@ -1283,18 +1312,17 @@ namespace MediaBrowser.Controller.MediaEncoding { var request = state.BaseRequest; - var inputChannels = audioStream == null - ? null - : audioStream.Channels; + var inputChannels = audioStream?.Channels; if (inputChannels <= 0) { inputChannels = null; } - int? transcoderChannelLimit = null; var codec = outputAudioCodec ?? string.Empty; + + int? transcoderChannelLimit; if (codec.IndexOf("wma", StringComparison.OrdinalIgnoreCase) != -1) { // wmav2 currently only supports two channel output @@ -1343,6 +1371,7 @@ namespace MediaBrowser.Controller.MediaEncoding { return val2; } + if (!val2.HasValue) { return val1; @@ -1416,7 +1445,10 @@ namespace MediaBrowser.Controller.MediaEncoding if (state.VideoStream != null) { - args += string.Format("-map 0:{0}", state.VideoStream.Index); + args += string.Format( + CultureInfo.InvariantCulture, + "-map 0:{0}", + state.VideoStream.Index); } else { @@ -1426,7 +1458,10 @@ namespace MediaBrowser.Controller.MediaEncoding if (state.AudioStream != null) { - args += string.Format(" -map 0:{0}", state.AudioStream.Index); + args += string.Format( + CultureInfo.InvariantCulture, + " -map 0:{0}", + state.AudioStream.Index); } else @@ -1441,7 +1476,10 @@ namespace MediaBrowser.Controller.MediaEncoding } else if (subtitleMethod == SubtitleDeliveryMethod.Embed) { - args += string.Format(" -map 0:{0}", state.SubtitleStream.Index); + args += string.Format( + CultureInfo.InvariantCulture, + " -map 0:{0}", + state.SubtitleStream.Index); } else if (state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream) { @@ -1493,7 +1531,10 @@ namespace MediaBrowser.Controller.MediaEncoding var request = state.BaseRequest; // Add resolution params, if specified - if (request.Width.HasValue || request.Height.HasValue || request.MaxHeight.HasValue || request.MaxWidth.HasValue) + if (request.Width.HasValue + || request.Height.HasValue + || request.MaxHeight.HasValue + || request.MaxWidth.HasValue) { outputSizeParam = GetOutputSizeParam(state, options, outputVideoCodec).TrimEnd('"'); @@ -1515,12 +1556,15 @@ namespace MediaBrowser.Controller.MediaEncoding } } - if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase) && outputSizeParam.Length == 0) + if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase) + && outputSizeParam.Length == 0) { outputSizeParam = ",format=nv12|vaapi,hwupload"; // Add parameters to use VAAPI with burn-in subttiles (GH issue #642) - if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode) { + if (state.SubtitleStream != null + && state.SubtitleStream.IsTextSubtitleStream + && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode) { outputSizeParam += ",hwmap=mode=read+write+direct"; } } @@ -1529,7 +1573,11 @@ namespace MediaBrowser.Controller.MediaEncoding if (state.VideoStream != null && state.VideoStream.Width.HasValue && state.VideoStream.Height.HasValue) { - videoSizeParam = string.Format("scale={0}:{1}", state.VideoStream.Width.Value.ToString(_usCulture), state.VideoStream.Height.Value.ToString(_usCulture)); + videoSizeParam = string.Format( + CultureInfo.InvariantCulture, + "scale={0}:{1}", + state.VideoStream.Width.Value, + state.VideoStream.Height.Value); videoSizeParam += ":force_original_aspect_ratio=decrease"; } @@ -1542,15 +1590,18 @@ namespace MediaBrowser.Controller.MediaEncoding ? 0 : state.SubtitleStream.Index; - return string.Format(" -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay{3}\"", - mapPrefix.ToString(_usCulture), - subtitleStreamIndex.ToString(_usCulture), - state.VideoStream.Index.ToString(_usCulture), + return string.Format( + CultureInfo.InvariantCulture, + " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay{3}\"", + mapPrefix, + subtitleStreamIndex, + state.VideoStream.Index, outputSizeParam, videoSizeParam); } - private ValueTuple GetFixedOutputSize(int? videoWidth, + private (int? width, int? height) GetFixedOutputSize( + int? videoWidth, int? videoHeight, int? requestedWidth, int? requestedHeight, @@ -1559,11 +1610,11 @@ namespace MediaBrowser.Controller.MediaEncoding { if (!videoWidth.HasValue && !requestedWidth.HasValue) { - return new ValueTuple(null, null); + return (null, null); } if (!videoHeight.HasValue && !requestedHeight.HasValue) { - return new ValueTuple(null, null); + return (null, null); } decimal inputWidth = Convert.ToDecimal(videoWidth ?? requestedWidth); @@ -1583,7 +1634,7 @@ namespace MediaBrowser.Controller.MediaEncoding outputWidth = 2 * Math.Truncate(outputWidth / 2); outputHeight = 2 * Math.Truncate(outputHeight / 2); - return new ValueTuple(Convert.ToInt32(outputWidth), Convert.ToInt32(outputHeight)); + return (Convert.ToInt32(outputWidth), Convert.ToInt32(outputHeight)); } public List GetScalingFilters(int? videoWidth, @@ -1597,9 +1648,17 @@ namespace MediaBrowser.Controller.MediaEncoding int? requestedMaxHeight) { var filters = new List(); - var fixedOutputSize = GetFixedOutputSize(videoWidth, videoHeight, requestedWidth, requestedHeight, requestedMaxWidth, requestedMaxHeight); - - if (string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) && fixedOutputSize.Item1.HasValue && fixedOutputSize.Item2.HasValue) + var (width, height) = GetFixedOutputSize( + videoWidth, + videoHeight, + requestedWidth, + requestedHeight, + requestedMaxWidth, + requestedMaxHeight); + + if (string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) + && width.HasValue + && height.HasValue) { // Work around vaapi's reduced scaling features var scaler = "scale_vaapi"; @@ -1607,15 +1666,26 @@ namespace MediaBrowser.Controller.MediaEncoding // Given the input dimensions (inputWidth, inputHeight), determine the output dimensions // (outputWidth, outputHeight). The user may request precise output dimensions or maximum // output dimensions. Output dimensions are guaranteed to be even. - var outputWidth = fixedOutputSize.Item1.Value; - var outputHeight = fixedOutputSize.Item2.Value; + var outputWidth = width.Value; + var outputHeight = height.Value; - if (!videoWidth.HasValue || outputWidth != videoWidth.Value || !videoHeight.HasValue || outputHeight != videoHeight.Value) + if (!videoWidth.HasValue + || outputWidth != videoWidth.Value + || !videoHeight.HasValue + || outputHeight != videoHeight.Value) { - filters.Add(string.Format("{0}=w={1}:h={2}", scaler, outputWidth.ToString(_usCulture), outputHeight.ToString(_usCulture))); + filters.Add( + string.Format( + CultureInfo.InvariantCulture, + "{0}=w={1}:h={2}", + scaler, + outputWidth, + outputHeight)); } } - else if ((videoDecoder ?? string.Empty).IndexOf("_cuvid", StringComparison.OrdinalIgnoreCase) != -1 && fixedOutputSize.Item1.HasValue && fixedOutputSize.Item2.HasValue) + else if ((videoDecoder ?? string.Empty).IndexOf("_cuvid", StringComparison.OrdinalIgnoreCase) != -1 + && width.HasValue + && height.HasValue) { // Nothing to do, it's handled as an input resize filter } @@ -1631,7 +1701,12 @@ namespace MediaBrowser.Controller.MediaEncoding var widthParam = requestedWidth.Value.ToString(_usCulture); var heightParam = requestedHeight.Value.ToString(_usCulture); - filters.Add(string.Format("scale=trunc({0}/64)*64:trunc({1}/2)*2", widthParam, heightParam)); + filters.Add( + string.Format( + CultureInfo.InvariantCulture, + "scale=trunc({0}/64)*64:trunc({1}/2)*2", + widthParam, + heightParam)); } else { @@ -1647,11 +1722,21 @@ namespace MediaBrowser.Controller.MediaEncoding if (isExynosV4L2) { - filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,min({0}\\,{1}*dar))/64)*64:trunc(min(max(iw/dar\\,ih)\\,min({0}/dar\\,{1}))/2)*2", maxWidthParam, maxHeightParam)); + filters.Add( + string.Format( + CultureInfo.InvariantCulture, + "scale=trunc(min(max(iw\\,ih*dar)\\,min({0}\\,{1}*dar))/64)*64:trunc(min(max(iw/dar\\,ih)\\,min({0}/dar\\,{1}))/2)*2", + maxWidthParam, + maxHeightParam)); } else { - filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,min({0}\\,{1}*dar))/2)*2:trunc(min(max(iw/dar\\,ih)\\,min({0}/dar\\,{1}))/2)*2", maxWidthParam, maxHeightParam)); + filters.Add( + string.Format( + CultureInfo.InvariantCulture, + "scale=trunc(min(max(iw\\,ih*dar)\\,min({0}\\,{1}*dar))/2)*2:trunc(min(max(iw/dar\\,ih)\\,min({0}/dar\\,{1}))/2)*2", + maxWidthParam, + maxHeightParam)); } } @@ -1667,7 +1752,11 @@ namespace MediaBrowser.Controller.MediaEncoding { var widthParam = requestedWidth.Value.ToString(_usCulture); - filters.Add(string.Format("scale={0}:trunc(ow/a/2)*2", widthParam)); + filters.Add( + string.Format( + CultureInfo.InvariantCulture, + "scale={0}:trunc(ow/a/2)*2", + widthParam)); } } @@ -1678,11 +1767,19 @@ namespace MediaBrowser.Controller.MediaEncoding if (isExynosV4L2) { - filters.Add(string.Format("scale=trunc(oh*a/64)*64:{0}", heightParam)); + filters.Add( + string.Format( + CultureInfo.InvariantCulture, + "scale=trunc(oh*a/64)*64:{0}", + heightParam)); } else { - filters.Add(string.Format("scale=trunc(oh*a/2)*2:{0}", heightParam)); + filters.Add( + string.Format( + CultureInfo.InvariantCulture, + "scale=trunc(oh*a/2)*2:{0}", + heightParam)); } } @@ -1693,11 +1790,19 @@ namespace MediaBrowser.Controller.MediaEncoding if (isExynosV4L2) { - filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,{0})/64)*64:trunc(ow/dar/2)*2", maxWidthParam)); + filters.Add( + string.Format( + CultureInfo.InvariantCulture, + "scale=trunc(min(max(iw\\,ih*dar)\\,{0})/64)*64:trunc(ow/dar/2)*2", + maxWidthParam)); } else { - filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,{0})/2)*2:trunc(ow/dar/2)*2", maxWidthParam)); + filters.Add( + string.Format( + CultureInfo.InvariantCulture, + "scale=trunc(min(max(iw\\,ih*dar)\\,{0})/2)*2:trunc(ow/dar/2)*2", + maxWidthParam)); } } @@ -1708,11 +1813,19 @@ namespace MediaBrowser.Controller.MediaEncoding if (isExynosV4L2) { - filters.Add(string.Format("scale=trunc(oh*a/64)*64:min(max(iw/dar\\,ih)\\,{0})", maxHeightParam)); + filters.Add( + string.Format( + CultureInfo.InvariantCulture, + "scale=trunc(oh*a/64)*64:min(max(iw/dar\\,ih)\\,{0})", + maxHeightParam)); } else { - filters.Add(string.Format("scale=trunc(oh*a/2)*2:min(max(iw/dar\\,ih)\\,{0})", maxHeightParam)); + filters.Add( + string.Format( + CultureInfo.InvariantCulture, + "scale=trunc(oh*a/2)*2:min(max(iw/dar\\,ih)\\,{0})", + maxHeightParam)); } } } @@ -1722,8 +1835,8 @@ namespace MediaBrowser.Controller.MediaEncoding private string GetFixedSizeScalingFilter(Video3DFormat? threedFormat, int requestedWidth, int requestedHeight) { - var widthParam = requestedWidth.ToString(_usCulture); - var heightParam = requestedHeight.ToString(_usCulture); + var widthParam = requestedWidth.ToString(CultureInfo.InvariantCulture); + var heightParam = requestedHeight.ToString(CultureInfo.InvariantCulture); string filter = null; @@ -1765,13 +1878,14 @@ namespace MediaBrowser.Controller.MediaEncoding } } - return string.Format(filter, widthParam, heightParam); + return string.Format(CultureInfo.InvariantCulture, filter, widthParam, heightParam); } /// /// If we're going to put a fixed size on the command line, this will calculate it /// - public string GetOutputSizeParam(EncodingJobInfo state, + public string GetOutputSizeParam( + EncodingJobInfo state, EncodingOptions options, string outputVideoCodec, bool allowTimeStampCopy = true) @@ -1790,8 +1904,9 @@ namespace MediaBrowser.Controller.MediaEncoding filters.Add("hwdownload"); // If transcoding from 10 bit, transform colour spaces too - if ( !string.IsNullOrEmpty(videoStream.PixelFormat) && videoStream.PixelFormat.IndexOf( "p10", StringComparison.OrdinalIgnoreCase ) != -1 - && string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase ) ) + if (!string.IsNullOrEmpty(videoStream.PixelFormat) + && videoStream.PixelFormat.IndexOf("p10", StringComparison.OrdinalIgnoreCase) != -1 + && string.Equals(outputVideoCodec,"libx264", StringComparison.OrdinalIgnoreCase)) { filters.Add("format=p010le"); filters.Add("format=nv12"); @@ -1800,7 +1915,6 @@ namespace MediaBrowser.Controller.MediaEncoding { filters.Add("format=nv12"); } - } if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) @@ -1809,15 +1923,16 @@ namespace MediaBrowser.Controller.MediaEncoding filters.Add("hwupload"); } - if (state.DeInterlace("h264", true) && string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) + if (state.DeInterlace("h264", true) + && string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) { - filters.Add(string.Format("deinterlace_vaapi")); + filters.Add(string.Format(CultureInfo.InvariantCulture, "deinterlace_vaapi")); } - if ((state.DeInterlace("h264", true) || state.DeInterlace("h265", true) || state.DeInterlace("hevc", true)) && - !string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) + if ((state.DeInterlace("h264", true) || state.DeInterlace("h265", true) || state.DeInterlace("hevc", true)) + && !string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) { - var inputFramerate = videoStream == null ? null : videoStream.RealFrameRate; + var inputFramerate = videoStream?.RealFrameRate; // If it is already 60fps then it will create an output framerate that is much too high for roku and others to handle if (string.Equals(options.DeinterlaceMethod, "bobandweave", StringComparison.OrdinalIgnoreCase) && (inputFramerate ?? 60) <= 30) @@ -1830,11 +1945,11 @@ namespace MediaBrowser.Controller.MediaEncoding } } - var inputWidth = videoStream == null ? null : videoStream.Width; - var inputHeight = videoStream == null ? null : videoStream.Height; + var inputWidth = videoStream?.Width; + var inputHeight = videoStream?.Height; var threeDFormat = state.MediaSource.Video3DFormat; - var videoDecoder = this.GetHardwareAcceleratedVideoDecoder(state, options); + var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options); filters.AddRange(GetScalingFilters(inputWidth, inputHeight, threeDFormat, videoDecoder, outputVideoCodec, request.Width, request.Height, request.MaxWidth, request.MaxHeight)); @@ -1852,6 +1967,7 @@ namespace MediaBrowser.Controller.MediaEncoding { filters.Add("hwmap"); } + if (allowTimeStampCopy) { output += " -copyts"; @@ -1860,7 +1976,10 @@ namespace MediaBrowser.Controller.MediaEncoding if (filters.Count > 0) { - output += string.Format(" -vf \"{0}\"", string.Join(",", filters.ToArray())); + output += string.Format( + CultureInfo.InvariantCulture, + " -vf \"{0}\"", + string.Join(",", filters)); } return output; @@ -1908,7 +2027,8 @@ namespace MediaBrowser.Controller.MediaEncoding } } - if (state.AudioStream != null && CanStreamCopyAudio(state, state.AudioStream, state.SupportedAudioCodecs)) + if (state.AudioStream != null + && CanStreamCopyAudio(state, state.AudioStream, state.SupportedAudioCodecs)) { state.OutputAudioCodec = "copy"; } @@ -1925,14 +2045,10 @@ namespace MediaBrowser.Controller.MediaEncoding } public static string GetProbeSizeArgument(int numInputFiles) - { - return numInputFiles > 1 ? "-probesize 1G" : ""; - } + => numInputFiles > 1 ? "-probesize 1G" : ""; public static string GetAnalyzeDurationArgument(int numInputFiles) - { - return numInputFiles > 1 ? "-analyzeduration 200M" : ""; - } + => numInputFiles > 1 ? "-analyzeduration 200M" : ""; public string GetInputModifier(EncodingJobInfo state, EncodingOptions encodingOptions) { @@ -2000,18 +2116,22 @@ namespace MediaBrowser.Controller.MediaEncoding { flags.Add("+igndts"); } + if (state.IgnoreInputIndex) { flags.Add("+ignidx"); } + if (state.GenPtsInput || string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { flags.Add("+genpts"); } + if (state.DiscardCorruptFramesInput) { flags.Add("+discardcorrupt"); } + if (state.EnableFastSeekInput) { flags.Add("+fastseek"); @@ -2019,24 +2139,33 @@ namespace MediaBrowser.Controller.MediaEncoding if (flags.Count > 0) { - inputModifier += " -fflags " + string.Join("", flags.ToArray()); + inputModifier += " -fflags " + string.Join(string.Empty, flags); } - var videoDecoder = this.GetHardwareAcceleratedVideoDecoder(state, encodingOptions); + var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions); if (!string.IsNullOrEmpty(videoDecoder)) { inputModifier += " " + videoDecoder; - var videoStream = state.VideoStream; - var inputWidth = videoStream == null ? null : videoStream.Width; - var inputHeight = videoStream == null ? null : videoStream.Height; - var request = state.BaseRequest; + if ((videoDecoder ?? string.Empty).IndexOf("_cuvid", StringComparison.OrdinalIgnoreCase) != -1) + { + var videoStream = state.VideoStream; + var inputWidth = videoStream?.Width; + var inputHeight = videoStream?.Height; + var request = state.BaseRequest; - var fixedOutputSize = GetFixedOutputSize(inputWidth, inputHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight); + var (width, height) = GetFixedOutputSize(inputWidth, inputHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight); - if ((videoDecoder ?? string.Empty).IndexOf("_cuvid", StringComparison.OrdinalIgnoreCase) != -1 && fixedOutputSize.Item1.HasValue && fixedOutputSize.Item2.HasValue) - { - inputModifier += string.Format(" -resize {0}x{1}", fixedOutputSize.Item1.Value.ToString(_usCulture), fixedOutputSize.Item2.Value.ToString(_usCulture)); + if ((videoDecoder ?? string.Empty).IndexOf("_cuvid", StringComparison.OrdinalIgnoreCase) != -1 + && width.HasValue + && height.HasValue) + { + inputModifier += string.Format( + CultureInfo.InvariantCulture, + " -resize {0}x{1}", + width.Value, + height.Value); + } } } @@ -2045,9 +2174,9 @@ namespace MediaBrowser.Controller.MediaEncoding var outputVideoCodec = GetVideoEncoder(state, encodingOptions); // Important: If this is ever re-enabled, make sure not to use it with wtv because it breaks seeking - if (!string.Equals(state.InputContainer, "wtv", StringComparison.OrdinalIgnoreCase) && - state.TranscodingType != TranscodingJobType.Progressive && - state.EnableBreakOnNonKeyFrames(outputVideoCodec)) + if (!string.Equals(state.InputContainer, "wtv", StringComparison.OrdinalIgnoreCase) + && state.TranscodingType != TranscodingJobType.Progressive + && state.EnableBreakOnNonKeyFrames(outputVideoCodec)) { inputModifier += " -noaccurate_seek"; } @@ -2071,14 +2200,16 @@ namespace MediaBrowser.Controller.MediaEncoding } - public void AttachMediaSourceInfo(EncodingJobInfo state, - MediaSourceInfo mediaSource, - string requestedUrl) + public void AttachMediaSourceInfo( + EncodingJobInfo state, + MediaSourceInfo mediaSource, + string requestedUrl) { if (state == null) { throw new ArgumentNullException(nameof(state)); } + if (mediaSource == null) { throw new ArgumentNullException(nameof(mediaSource)); @@ -2136,15 +2267,16 @@ namespace MediaBrowser.Controller.MediaEncoding state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders; state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate; - if (state.ReadInputAtNativeFramerate || - mediaSource.Protocol == MediaProtocol.File && string.Equals(mediaSource.Container, "wtv", StringComparison.OrdinalIgnoreCase)) + if (state.ReadInputAtNativeFramerate + || mediaSource.Protocol == MediaProtocol.File + && string.Equals(mediaSource.Container, "wtv", StringComparison.OrdinalIgnoreCase)) { state.InputVideoSync = "-1"; state.InputAudioSync = "1"; } - if (string.Equals(mediaSource.Container, "wma", StringComparison.OrdinalIgnoreCase) || - string.Equals(mediaSource.Container, "asf", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(mediaSource.Container, "wma", StringComparison.OrdinalIgnoreCase) + || string.Equals(mediaSource.Container, "asf", StringComparison.OrdinalIgnoreCase)) { // Seeing some stuttering when transcoding wma to audio-only HLS state.InputAudioSync = "1"; @@ -2256,7 +2388,7 @@ namespace MediaBrowser.Controller.MediaEncoding return null; } - return this.GetHardwareAcceleratedVideoDecoder(state.MediaSource.VideoType ?? VideoType.VideoFile, state.VideoStream, encodingOptions); + return GetHardwareAcceleratedVideoDecoder(state.MediaSource.VideoType ?? VideoType.VideoFile, state.VideoStream, encodingOptions); } public string GetHardwareAcceleratedVideoDecoder(VideoType videoType, MediaStream videoStream, EncodingOptions encodingOptions) @@ -2269,9 +2401,9 @@ namespace MediaBrowser.Controller.MediaEncoding return null; } - if (videoStream != null && - !string.IsNullOrEmpty(videoStream.Codec) && - !string.IsNullOrEmpty(encodingOptions.HardwareAccelerationType)) + if (videoStream != null + && !string.IsNullOrEmpty(videoStream.Codec) + && !string.IsNullOrEmpty(encodingOptions.HardwareAccelerationType)) { if (string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) { @@ -2469,11 +2601,7 @@ namespace MediaBrowser.Controller.MediaEncoding codec = format; } - var args = " -codec:s:0 " + codec; - - args += " -disposition:s:0 default"; - - return args; + return " -codec:s:0 " + codec + " -disposition:s:0 default"; } public string GetProgressiveVideoFullCommandLine(EncodingJobInfo state, EncodingOptions encodingOptions, string outputPath, string defaultPreset) @@ -2484,8 +2612,8 @@ namespace MediaBrowser.Controller.MediaEncoding var format = string.Empty; var keyFrame = string.Empty; - if (string.Equals(Path.GetExtension(outputPath), ".mp4", StringComparison.OrdinalIgnoreCase) && - state.BaseRequest.Context == EncodingContext.Streaming) + if (string.Equals(Path.GetExtension(outputPath), ".mp4", StringComparison.OrdinalIgnoreCase) + && state.BaseRequest.Context == EncodingContext.Streaming) { // Comparison: https://github.com/jansmolders86/mediacenterjs/blob/master/lib/transcoding/desktop.js format = " -f mp4 -movflags frag_keyframe+empty_moov"; @@ -2495,7 +2623,9 @@ namespace MediaBrowser.Controller.MediaEncoding var inputModifier = GetInputModifier(state, encodingOptions); - return string.Format("{0} {1}{2} {3} {4} -map_metadata -1 -map_chapters -1 -threads {5} {6}{7}{8} -y \"{9}\"", + return string.Format( + CultureInfo.InvariantCulture, + "{0} {1}{2} {3} {4} -map_metadata -1 -map_chapters -1 -threads {5} {6}{7}{8} -y \"{9}\"", inputModifier, GetInputArgument(state, encodingOptions), keyFrame, @@ -2505,8 +2635,7 @@ namespace MediaBrowser.Controller.MediaEncoding GetProgressiveVideoAudioArguments(state, encodingOptions), GetSubtitleEmbedArguments(state), format, - outputPath - ).Trim(); + outputPath).Trim(); } public string GetOutputFFlags(EncodingJobInfo state) @@ -2519,7 +2648,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (flags.Count > 0) { - return " -fflags " + string.Join("", flags.ToArray()); + return " -fflags " + string.Join("", flags); } return string.Empty; @@ -2536,9 +2665,9 @@ namespace MediaBrowser.Controller.MediaEncoding if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { - if (state.VideoStream != null && - string.Equals(state.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) && - !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase)) + if (state.VideoStream != null + && string.Equals(state.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) + && !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase)) { string bitStreamArgs = GetBitStreamArgs(state.VideoStream); if (!string.IsNullOrEmpty(bitStreamArgs)) @@ -2559,8 +2688,10 @@ namespace MediaBrowser.Controller.MediaEncoding } else { - var keyFrameArg = string.Format(" -force_key_frames \"expr:gte(t,n_forced*{0})\"", - 5.ToString(_usCulture)); + var keyFrameArg = string.Format( + CultureInfo.InvariantCulture, + " -force_key_frames \"expr:gte(t,n_forced*{0})\"", + 5); args += keyFrameArg; @@ -2581,6 +2712,7 @@ namespace MediaBrowser.Controller.MediaEncoding { args += " -copyts"; } + args += " -avoid_negative_ts disabled -start_at_zero"; } @@ -2681,39 +2813,22 @@ namespace MediaBrowser.Controller.MediaEncoding } } - var albumCoverInput = string.Empty; - var mapArgs = string.Empty; - var metadata = string.Empty; - var vn = string.Empty; - - var hasArt = !string.IsNullOrEmpty(state.AlbumCoverPath); - hasArt = false; - - if (hasArt) - { - albumCoverInput = " -i \"" + state.AlbumCoverPath + "\""; - mapArgs = " -map 0:a -map 1:v -c:1:v copy"; - metadata = " -metadata:s:v title=\"Album cover\" -metadata:s:v comment=\"Cover(Front)\""; - } - else - { - vn = " -vn"; - } - var threads = GetNumberOfThreads(state, encodingOptions, null); var inputModifier = GetInputModifier(state, encodingOptions); - return string.Format("{0} {1}{7}{8} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1{6} -y \"{5}\"", + return string.Format( + CultureInfo.InvariantCulture, + "{0} {1}{7}{8} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1{6} -y \"{5}\"", inputModifier, GetInputArgument(state, encodingOptions), threads, - vn, - string.Join(" ", audioTranscodeParams.ToArray()), + " -vn", + string.Join(" ", audioTranscodeParams), outputPath, - metadata, - albumCoverInput, - mapArgs).Trim(); + string.Empty, + string.Empty, + string.Empty).Trim(); } } diff --git a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs index 7f842c1d0..5cedc3d57 100644 --- a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs +++ b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs @@ -1,8 +1,8 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using MediaBrowser.Model.IO; -using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.Controller.MediaEncoding { @@ -16,31 +16,26 @@ namespace MediaBrowser.Controller.MediaEncoding /// /// The file system. /// The video path. - /// The protocol. /// The iso mount. /// The playable stream file names. - /// System.String[][]. - public static string[] GetInputArgument(IFileSystem fileSystem, string videoPath, MediaProtocol protocol, IIsoMount isoMount, string[] playableStreamFileNames) + /// string[]. + public static string[] GetInputArgument(IFileSystem fileSystem, string videoPath, IIsoMount isoMount, IReadOnlyCollection playableStreamFileNames) { - if (playableStreamFileNames.Length > 0) + if (playableStreamFileNames.Count > 0) { if (isoMount == null) { return GetPlayableStreamFiles(fileSystem, videoPath, playableStreamFileNames); } + return GetPlayableStreamFiles(fileSystem, isoMount.MountedPath, playableStreamFileNames); } return new[] { videoPath }; } - private static string[] GetPlayableStreamFiles(IFileSystem fileSystem, string rootPath, string[] filenames) + private static string[] GetPlayableStreamFiles(IFileSystem fileSystem, string rootPath, IEnumerable filenames) { - if (filenames.Length == 0) - { - return new string[] { }; - } - var allFiles = fileSystem .GetFilePaths(rootPath, true) .ToArray(); diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index a8874b6d0..75bb960c3 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -303,7 +303,7 @@ namespace MediaBrowser.MediaEncoding.Encoder { var extractChapters = request.MediaType == DlnaProfileType.Video && request.ExtractChapters; - var inputFiles = MediaEncoderHelpers.GetInputArgument(FileSystem, request.MediaSource.Path, request.MediaSource.Protocol, request.MountedIso, request.PlayableStreamFileNames); + var inputFiles = MediaEncoderHelpers.GetInputArgument(FileSystem, request.MediaSource.Path, request.MountedIso, request.PlayableStreamFileNames); var probeSize = EncodingHelper.GetProbeSizeArgument(inputFiles.Length); string analyzeDuration; diff --git a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs index d80084acf..e0b23108f 100644 --- a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs @@ -62,7 +62,7 @@ namespace MediaBrowser.Providers.MediaInfo { var protocol = item.PathProtocol ?? MediaProtocol.File; - var inputPath = MediaEncoderHelpers.GetInputArgument(_fileSystem, item.Path, protocol, null, item.GetPlayableStreamFileNames(_mediaEncoder)); + var inputPath = MediaEncoderHelpers.GetInputArgument(_fileSystem, item.Path, null, item.GetPlayableStreamFileNames(_mediaEncoder)); var mediaStreams = item.GetMediaStreams(); diff --git a/MediaBrowser.XbmcMetadata/EntryPoint.cs b/MediaBrowser.XbmcMetadata/EntryPoint.cs index 992991a7e..fe4d50efa 100644 --- a/MediaBrowser.XbmcMetadata/EntryPoint.cs +++ b/MediaBrowser.XbmcMetadata/EntryPoint.cs @@ -16,27 +16,30 @@ namespace MediaBrowser.XbmcMetadata { private readonly IUserDataManager _userDataManager; private readonly ILogger _logger; - private readonly ILibraryManager _libraryManager; private readonly IProviderManager _providerManager; private readonly IConfigurationManager _config; - public EntryPoint(IUserDataManager userDataManager, ILibraryManager libraryManager, ILogger logger, IProviderManager providerManager, IConfigurationManager config) + public EntryPoint( + IUserDataManager userDataManager, + ILogger logger, + IProviderManager providerManager, + IConfigurationManager config) { _userDataManager = userDataManager; - _libraryManager = libraryManager; _logger = logger; _providerManager = providerManager; _config = config; } + /// public Task RunAsync() { - _userDataManager.UserDataSaved += _userDataManager_UserDataSaved; + _userDataManager.UserDataSaved += OnUserDataSaved; return Task.CompletedTask; } - void _userDataManager_UserDataSaved(object sender, UserDataSaveEventArgs e) + private void OnUserDataSaved(object sender, UserDataSaveEventArgs e) { if (e.SaveReason == UserDataSaveReason.PlaybackFinished || e.SaveReason == UserDataSaveReason.TogglePlayed || e.SaveReason == UserDataSaveReason.UpdateUserRating) { @@ -47,9 +50,10 @@ namespace MediaBrowser.XbmcMetadata } } + /// public void Dispose() { - _userDataManager.UserDataSaved -= _userDataManager_UserDataSaved; + _userDataManager.UserDataSaved -= OnUserDataSaved; } private void SaveMetadataForItem(BaseItem item, ItemUpdateType updateReason) diff --git a/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs index 430b93199..a1905bf26 100644 --- a/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs @@ -15,16 +15,30 @@ namespace MediaBrowser.XbmcMetadata.Savers { public class AlbumNfoSaver : BaseNfoSaver { + public AlbumNfoSaver( + IFileSystem fileSystem, + IServerConfigurationManager configurationManager, + ILibraryManager libraryManager, + IUserManager userManager, + IUserDataManager userDataManager, + ILogger logger) + : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger) + { + } + + /// protected override string GetLocalSavePath(BaseItem item) { return Path.Combine(item.Path, "album.nfo"); } + /// protected override string GetRootElementName(BaseItem item) { return "album"; } + /// public override bool IsEnabledFor(BaseItem item, ItemUpdateType updateType) { if (!item.SupportsLocalMetadata) @@ -35,6 +49,7 @@ namespace MediaBrowser.XbmcMetadata.Savers return item is MusicAlbum && updateType >= MinimumUpdateType; } + /// protected override void WriteCustomElements(BaseItem item, XmlWriter writer) { var album = (MusicAlbum)item; @@ -52,8 +67,6 @@ namespace MediaBrowser.XbmcMetadata.Savers AddTracks(album.Tracks, writer); } - private readonly CultureInfo UsCulture = new CultureInfo("en-US"); - private void AddTracks(IEnumerable tracks, XmlWriter writer) { foreach (var track in tracks.OrderBy(i => i.ParentIndexNumber ?? 0).ThenBy(i => i.IndexNumber ?? 0)) @@ -62,7 +75,7 @@ namespace MediaBrowser.XbmcMetadata.Savers if (track.IndexNumber.HasValue) { - writer.WriteElementString("position", track.IndexNumber.Value.ToString(UsCulture)); + writer.WriteElementString("position", track.IndexNumber.Value.ToString(CultureInfo.InvariantCulture)); } if (!string.IsNullOrEmpty(track.Name)) @@ -81,21 +94,19 @@ namespace MediaBrowser.XbmcMetadata.Savers } } + /// protected override List GetTagsUsed(BaseItem item) { var list = base.GetTagsUsed(item); - list.AddRange(new string[] - { - "track", - "artist", - "albumartist" - }); - return list; - } + list.AddRange( + new string[] + { + "track", + "artist", + "albumartist" + }); - public AlbumNfoSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger) - : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger) - { + return list; } } } diff --git a/MediaBrowser.sln b/MediaBrowser.sln index 3ed86d65c..39839e273 100644 --- a/MediaBrowser.sln +++ b/MediaBrowser.sln @@ -1,4 +1,4 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26730.3 @@ -41,8 +41,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Emby.Naming", "Emby.Naming\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Emby.XmlTv", "Emby.XmlTv\Emby.XmlTv\Emby.XmlTv.csproj", "{6EAFA7F0-8A82-49E6-B2FA-086C5CAEA95B}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IsoMounter", "Emby.IsoMounting\IsoMounter\IsoMounter.csproj", "{9BA471D2-6DB9-4DBF-B3A0-9FB3171F94A6}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MediaBrowser.MediaEncoding", "MediaBrowser.MediaEncoding\MediaBrowser.MediaEncoding.csproj", "{960295EE-4AF4-4440-A525-B4C295B01A61}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Server", "Jellyfin.Server\Jellyfin.Server.csproj", "{07E39F42-A2C6-4B32-AF8C-725F957A73FF}" @@ -141,10 +139,6 @@ Global {6EAFA7F0-8A82-49E6-B2FA-086C5CAEA95B}.Debug|Any CPU.Build.0 = Debug|Any CPU {6EAFA7F0-8A82-49E6-B2FA-086C5CAEA95B}.Release|Any CPU.ActiveCfg = Release|Any CPU {6EAFA7F0-8A82-49E6-B2FA-086C5CAEA95B}.Release|Any CPU.Build.0 = Release|Any CPU - {9BA471D2-6DB9-4DBF-B3A0-9FB3171F94A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9BA471D2-6DB9-4DBF-B3A0-9FB3171F94A6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9BA471D2-6DB9-4DBF-B3A0-9FB3171F94A6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9BA471D2-6DB9-4DBF-B3A0-9FB3171F94A6}.Release|Any CPU.Build.0 = Release|Any CPU {960295EE-4AF4-4440-A525-B4C295B01A61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {960295EE-4AF4-4440-A525-B4C295B01A61}.Debug|Any CPU.Build.0 = Debug|Any CPU {960295EE-4AF4-4440-A525-B4C295B01A61}.Release|Any CPU.ActiveCfg = Release|Any CPU -- cgit v1.2.3 From 2919cf28ead3fc7b80dec789477eef4d2688616b Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 11 Sep 2019 19:31:35 +0200 Subject: Update deps (#1735) --- Emby.Server.Implementations/Emby.Server.Implementations.csproj | 4 ++-- Jellyfin.Server/Jellyfin.Server.csproj | 4 ++-- Jellyfin.Server/Program.cs | 2 +- MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index b48193c58..2c71f0457 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -21,7 +21,7 @@ - + @@ -33,7 +33,7 @@ - + diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index 8c57ee453..35f0c84cb 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -37,13 +37,13 @@ - + - + diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 594441af0..716dd0fcd 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -22,7 +22,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Serilog; -using Serilog.AspNetCore; +using Serilog.Extensions.Logging; using SQLitePCL; using ILogger = Microsoft.Extensions.Logging.ILogger; diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index fdb20477f..264f31f3c 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -19,7 +19,7 @@ - + -- cgit v1.2.3 From c9820d30edf1cb8fa99a52ec72b6571d6d4506f7 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Fri, 20 Sep 2019 12:42:08 +0200 Subject: Fix multiple mistakes and warnings --- BDInfo/BDROM.cs | 9 +---- Emby.Server.Implementations/Dto/DtoService.cs | 10 ++--- .../HttpServer/Security/AuthService.cs | 2 +- .../Library/CoreResolutionIgnoreRule.cs | 1 - Emby.Server.Implementations/Library/UserManager.cs | 4 +- .../Library/UserViewManager.cs | 4 +- .../LiveTv/EmbyTV/EncodedRecorder.cs | 3 -- .../LiveTv/Listings/SchedulesDirect.cs | 37 ++++++++---------- .../LiveTv/LiveTvManager.cs | 45 ++++++++++------------ .../TunerHosts/HdHomerun/HdHomerunManager.cs | 4 +- .../Services/StringMapTypeDeserializer.cs | 2 +- Jellyfin.Server/Jellyfin.Server.csproj | 2 +- MediaBrowser.Api/UserLibrary/ItemsService.cs | 4 +- MediaBrowser.Common/Extensions/BaseExtensions.cs | 12 +++--- .../Extensions/CollectionExtensions.cs | 19 ++++++++- MediaBrowser.Controller/Entities/BaseItem.cs | 21 ++++++---- .../MediaEncoding/EncodingHelper.cs | 3 -- MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs | 2 - .../Subtitles/SubtitleEncoder.cs | 8 ++-- .../Savers/EpisodeNfoSaver.cs | 2 +- RSSDP/SsdpDevicePublisher.cs | 4 -- 21 files changed, 94 insertions(+), 104 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/BDInfo/BDROM.cs b/BDInfo/BDROM.cs index 6759ed55a..3a0c14ffd 100644 --- a/BDInfo/BDROM.cs +++ b/BDInfo/BDROM.cs @@ -212,7 +212,6 @@ namespace BDInfo public void Scan() { - var errorStreamClipFiles = new List(); foreach (var streamClipFile in StreamClipFiles.Values) { try @@ -221,7 +220,6 @@ namespace BDInfo } catch (Exception ex) { - errorStreamClipFiles.Add(streamClipFile); if (StreamClipFileScanError != null) { if (StreamClipFileScanError(streamClipFile, ex)) @@ -250,7 +248,6 @@ namespace BDInfo StreamFiles.Values.CopyTo(streamFiles, 0); Array.Sort(streamFiles, CompareStreamFiles); - var errorPlaylistFiles = new List(); foreach (var playlistFile in PlaylistFiles.Values) { try @@ -259,7 +256,6 @@ namespace BDInfo } catch (Exception ex) { - errorPlaylistFiles.Add(playlistFile); if (PlaylistFileScanError != null) { if (PlaylistFileScanError(playlistFile, ex)) @@ -275,7 +271,6 @@ namespace BDInfo } } - var errorStreamFiles = new List(); foreach (var streamFile in streamFiles) { try @@ -296,7 +291,6 @@ namespace BDInfo } catch (Exception ex) { - errorStreamFiles.Add(streamFile); if (StreamFileScanError != null) { if (StreamFileScanError(streamFile, ex)) @@ -431,7 +425,7 @@ namespace BDInfo { return 1; } - else if ((x != null || x.FileInfo != null) && (y == null || y.FileInfo == null)) + else if ((x != null && x.FileInfo != null) && (y == null || y.FileInfo == null)) { return -1; } @@ -451,6 +445,5 @@ namespace BDInfo } } } - } } diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 75192a8f1..a3201f0bc 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -218,14 +218,12 @@ namespace Emby.Server.Implementations.Dto AttachUserSpecificInfo(dto, item, user, options); } - if (item is IHasMediaSources hasMediaSources) + if (item is IHasMediaSources + && options.ContainsField(ItemFields.MediaSources)) { - if (options.ContainsField(ItemFields.MediaSources)) - { - dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(item, true, user).ToArray(); + dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(item, true, user).ToArray(); - NormalizeMediaSourceContainers(dto); - } + NormalizeMediaSourceContainers(dto); } if (options.ContainsField(ItemFields.Studios)) diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs index 3d3f67ca2..93a61fe67 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs @@ -51,7 +51,7 @@ namespace Emby.Server.Implementations.HttpServer.Security var user = auth.User; - if (user == null & !auth.UserId.Equals(Guid.Empty)) + if (user == null && auth.UserId != Guid.Empty) { throw new SecurityException("User with Id " + auth.UserId + " not found"); } diff --git a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs index f1ae2fc9c..8bdb38784 100644 --- a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs +++ b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs @@ -57,7 +57,6 @@ namespace Emby.Server.Implementations.Library } var filename = fileInfo.Name; - var path = fileInfo.FullName; // Ignore hidden files on UNIX if (Environment.OSVersion.Platform != PlatformID.Win32NT diff --git a/Emby.Server.Implementations/Library/UserManager.cs b/Emby.Server.Implementations/Library/UserManager.cs index ac6b4a209..52b2f56ff 100644 --- a/Emby.Server.Implementations/Library/UserManager.cs +++ b/Emby.Server.Implementations/Library/UserManager.cs @@ -273,14 +273,12 @@ namespace Emby.Server.Implementations.Library var user = Users.FirstOrDefault(i => string.Equals(username, i.Name, StringComparison.OrdinalIgnoreCase)); var success = false; - string updatedUsername = null; IAuthenticationProvider authenticationProvider = null; if (user != null) { var authResult = await AuthenticateLocalUser(username, password, hashedPassword, user, remoteEndPoint).ConfigureAwait(false); authenticationProvider = authResult.authenticationProvider; - updatedUsername = authResult.username; success = authResult.success; } else @@ -288,7 +286,7 @@ namespace Emby.Server.Implementations.Library // user is null var authResult = await AuthenticateLocalUser(username, password, hashedPassword, null, remoteEndPoint).ConfigureAwait(false); authenticationProvider = authResult.authenticationProvider; - updatedUsername = authResult.username; + string updatedUsername = authResult.username; success = authResult.success; if (success diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs index 4d79cae13..88e2a8fa6 100644 --- a/Emby.Server.Implementations/Library/UserViewManager.cs +++ b/Emby.Server.Implementations/Library/UserViewManager.cs @@ -236,7 +236,7 @@ namespace Emby.Server.Implementations.Library if (!parentId.Equals(Guid.Empty)) { var parentItem = _libraryManager.GetItemById(parentId); - if (parentItem is Channel parentItemChannel) + if (parentItem is Channel) { return _channelManager.GetLatestChannelItemsInternal( new InternalItemsQuery(user) @@ -248,7 +248,7 @@ namespace Emby.Server.Implementations.Library IncludeItemTypes = request.IncludeItemTypes, EnableTotalRecordCount = false }, - CancellationToken.None).Result.Items; + CancellationToken.None).GetAwaiter().GetResult().Items; } if (parentItem is Folder parent) diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index 3cc0541e7..cc9c8e5d2 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -208,9 +208,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV private static string GetAudioArgs(MediaSourceInfo mediaSource) { - var mediaStreams = mediaSource.MediaStreams ?? new List(); - var inputAudioCodec = mediaStreams.Where(i => i.Type == MediaStreamType.Audio).Select(i => i.Codec).FirstOrDefault() ?? string.Empty; - return "-codec:a:0 copy"; //var audioChannels = 2; diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index f5dffc22a..9a4c91d0b 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -17,7 +17,6 @@ using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Net; using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; -using Microsoft.Net.Http.Headers; namespace Emby.Server.Implementations.LiveTv.Listings { @@ -41,6 +40,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings private string UserAgent => _appHost.ApplicationUserAgent; + /// + public string Name => "Schedules Direct"; + + /// + public string Type => nameof(SchedulesDirect); + private static List GetScheduleRequestDates(DateTime startDateUtc, DateTime endDateUtc) { var dates = new List(); @@ -103,7 +108,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings httpOptions.RequestHeaders["token"] = token; using (var response = await Post(httpOptions, true, info).ConfigureAwait(false)) - using (var reader = new StreamReader(response.Content)) { var dailySchedules = await _jsonSerializer.DeserializeFromStreamAsync>(response.Content).ConfigureAwait(false); _logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules.Count, channelId); @@ -122,7 +126,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings httpOptions.RequestContent = "[\"" + string.Join("\", \"", programsID) + "\"]"; using (var innerResponse = await Post(httpOptions, true, info).ConfigureAwait(false)) - using (var innerReader = new StreamReader(innerResponse.Content)) { var programDetails = await _jsonSerializer.DeserializeFromStreamAsync>(innerResponse.Content).ConfigureAwait(false); var programDict = programDetails.ToDictionary(p => p.programID, y => y); @@ -152,14 +155,14 @@ namespace Emby.Server.Implementations.LiveTv.Listings var imagesWithText = allImages.Where(i => string.Equals(i.text, "yes", StringComparison.OrdinalIgnoreCase)); var imagesWithoutText = allImages.Where(i => string.Equals(i.text, "no", StringComparison.OrdinalIgnoreCase)); - const double desiredAspect = 0.666666667; + const double DesiredAspect = 2.0 / 3; - programEntry.primaryImage = GetProgramImage(ApiUrl, imagesWithText, true, desiredAspect) ?? - GetProgramImage(ApiUrl, allImages, true, desiredAspect); + programEntry.primaryImage = GetProgramImage(ApiUrl, imagesWithText, true, DesiredAspect) ?? + GetProgramImage(ApiUrl, allImages, true, DesiredAspect); - const double wideAspect = 1.77777778; + const double WideAspect = 16.0 / 9; - programEntry.thumbImage = GetProgramImage(ApiUrl, imagesWithText, true, wideAspect); + programEntry.thumbImage = GetProgramImage(ApiUrl, imagesWithText, true, WideAspect); // Don't supply the same image twice if (string.Equals(programEntry.primaryImage, programEntry.thumbImage, StringComparison.Ordinal)) @@ -167,7 +170,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings programEntry.thumbImage = null; } - programEntry.backdropImage = GetProgramImage(ApiUrl, imagesWithoutText, true, wideAspect); + programEntry.backdropImage = GetProgramImage(ApiUrl, imagesWithoutText, true, WideAspect); //programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ?? // GetProgramImage(ApiUrl, data, "Banner-L1", false) ?? @@ -178,6 +181,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings programsInfo.Add(GetProgram(channelId, schedule, programDict[schedule.programID])); } + return programsInfo; } } @@ -185,12 +189,10 @@ namespace Emby.Server.Implementations.LiveTv.Listings private static int GetSizeOrder(ScheduleDirect.ImageData image) { - if (!string.IsNullOrWhiteSpace(image.height)) + if (!string.IsNullOrWhiteSpace(image.height) + && int.TryParse(image.height, out int value)) { - if (int.TryParse(image.height, out int value)) - { - return value; - } + return value; } return 0; @@ -736,16 +738,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings httpOptions.RequestHeaders["token"] = token; - using (var response = await _httpClient.SendAsync(httpOptions, "PUT")) + using (await _httpClient.SendAsync(httpOptions, "PUT")) { } } - public string Name => "Schedules Direct"; - - public static string TypeName = "SchedulesDirect"; - public string Type => TypeName; - private async Task HasLineup(ListingsProviderInfo info, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(info.ListingsId)) diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index ee975e19a..89b92c999 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -60,16 +60,6 @@ namespace Emby.Server.Implementations.LiveTv private IListingsProvider[] _listingProviders = Array.Empty(); private readonly IFileSystem _fileSystem; - public event EventHandler> SeriesTimerCancelled; - public event EventHandler> TimerCancelled; - public event EventHandler> TimerCreated; - public event EventHandler> SeriesTimerCreated; - - public string GetEmbyTvActiveRecordingPath(string id) - { - return EmbyTV.EmbyTV.Current.GetActiveRecordingPath(id); - } - public LiveTvManager( IServerApplicationHost appHost, IServerConfigurationManager config, @@ -102,17 +92,34 @@ namespace Emby.Server.Implementations.LiveTv _tvDtoService = new LiveTvDtoService(dtoService, imageProcessor, loggerFactory, appHost, _libraryManager); } + public event EventHandler> SeriesTimerCancelled; + + public event EventHandler> TimerCancelled; + + public event EventHandler> TimerCreated; + + public event EventHandler> SeriesTimerCreated; + /// /// Gets the services. /// /// The services. public IReadOnlyList Services => _services; + public ITunerHost[] TunerHosts => _tunerHosts; + + public IListingsProvider[] ListingProviders => _listingProviders; + private LiveTvOptions GetConfiguration() { return _config.GetConfiguration("livetv"); } + public string GetEmbyTvActiveRecordingPath(string id) + { + return EmbyTV.EmbyTV.Current.GetActiveRecordingPath(id); + } + /// /// Adds the parts. /// @@ -130,13 +137,13 @@ namespace Emby.Server.Implementations.LiveTv { if (service is EmbyTV.EmbyTV embyTv) { - embyTv.TimerCreated += EmbyTv_TimerCreated; - embyTv.TimerCancelled += EmbyTv_TimerCancelled; + embyTv.TimerCreated += OnEmbyTvTimerCreated; + embyTv.TimerCancelled += OnEmbyTvTimerCancelled; } } } - private void EmbyTv_TimerCancelled(object sender, GenericEventArgs e) + private void OnEmbyTvTimerCancelled(object sender, GenericEventArgs e) { var timerId = e.Argument; @@ -149,10 +156,9 @@ namespace Emby.Server.Implementations.LiveTv }); } - private void EmbyTv_TimerCreated(object sender, GenericEventArgs e) + private void OnEmbyTvTimerCreated(object sender, GenericEventArgs e) { var timer = e.Argument; - var service = sender as ILiveTvService; TimerCreated?.Invoke(this, new GenericEventArgs { @@ -164,10 +170,6 @@ namespace Emby.Server.Implementations.LiveTv }); } - public ITunerHost[] TunerHosts => _tunerHosts; - - public IListingsProvider[] ListingProviders => _listingProviders; - public List GetTunerHostTypes() { return _tunerHosts.OrderBy(i => i.Name).Select(i => new NameIdPair @@ -966,9 +968,6 @@ namespace Emby.Server.Implementations.LiveTv private async Task AddRecordingInfo(IEnumerable> programs, CancellationToken cancellationToken) { - var timers = new Dictionary>(); - var seriesTimers = new Dictionary>(); - IReadOnlyList timerList = null; IReadOnlyList seriesTimerList = null; @@ -1601,8 +1600,6 @@ namespace Emby.Server.Implementations.LiveTv if (!string.IsNullOrEmpty(query.Id)) { - var guid = new Guid(query.Id); - timers = timers .Where(i => string.Equals(_tvDtoService.GetInternalTimerId(i.Item1.Id), query.Id, StringComparison.OrdinalIgnoreCase)); } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs index 3699b988c..9702392b2 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs @@ -424,14 +424,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun return false; } - var nameTag = buf[offset++]; + offset++; // Name Tag var nameLength = buf[offset++]; // skip the name field to get to value for return offset += nameLength; - var valueTag = buf[offset++]; + offset++; // Value Tag var valueLength = buf[offset++]; diff --git a/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs b/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs index c27eb7686..23e22afd5 100644 --- a/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs +++ b/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs @@ -15,7 +15,7 @@ namespace Emby.Server.Implementations.Services { PropertySetFn = propertySetFn; PropertyParseStringFn = propertyParseStringFn; - PropertyType = PropertyType; + PropertyType = propertyType; } public Action PropertySetFn { get; private set; } diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index 35f0c84cb..fa3e9cb35 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -22,7 +22,7 @@ - + diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index ada540ba6..b4a302648 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -455,9 +455,7 @@ namespace MediaBrowser.Api.UserLibrary IncludeItemTypes = new[] { typeof(MusicAlbum).Name }, Name = i, Limit = 1 - - }).Select(albumId => albumId); - + }); }).ToArray(); } diff --git a/MediaBrowser.Common/Extensions/BaseExtensions.cs b/MediaBrowser.Common/Extensions/BaseExtensions.cs index 40c16b957..33473c2be 100644 --- a/MediaBrowser.Common/Extensions/BaseExtensions.cs +++ b/MediaBrowser.Common/Extensions/BaseExtensions.cs @@ -14,20 +14,20 @@ namespace MediaBrowser.Common.Extensions /// Strips the HTML. /// /// The HTML string. - /// System.String. + /// . public static string StripHtml(this string htmlString) { // http://stackoverflow.com/questions/1349023/how-can-i-strip-html-from-text-in-net - const string pattern = @"<(.|\n)*?>"; + const string Pattern = @"<(.|\n)*?>"; - return Regex.Replace(htmlString, pattern, string.Empty).Trim(); + return Regex.Replace(htmlString, Pattern, string.Empty).Trim(); } /// - /// Gets the M d5. + /// Gets the Md5. /// - /// The STR. - /// Guid. + /// The string. + /// . public static Guid GetMD5(this string str) { using (var provider = MD5.Create()) diff --git a/MediaBrowser.Common/Extensions/CollectionExtensions.cs b/MediaBrowser.Common/Extensions/CollectionExtensions.cs index 3bc0295a0..75b9f59f8 100644 --- a/MediaBrowser.Common/Extensions/CollectionExtensions.cs +++ b/MediaBrowser.Common/Extensions/CollectionExtensions.cs @@ -5,13 +5,28 @@ namespace MediaBrowser.Common.Extensions // The MS CollectionExtensions are only available in netcoreapp public static class CollectionExtensions { - public static TValue GetValueOrDefault (this IReadOnlyDictionary dictionary, TKey key) + public static TValue GetValueOrDefault(this IReadOnlyDictionary dictionary, TKey key) { dictionary.TryGetValue(key, out var ret); return ret; } - // REVIEW: Inline? + /// + /// Copies all the elements of the current collection to the specified list + /// starting at the specified destination array index. The index is specified as a 32-bit integer. + /// + /// The current collection that is the source of the elements. + /// The list that is the destination of the elements copied from the current collection. + /// A 32-bit integer that represents the index in destination at which copying begins. + /// + public static void CopyTo(this IReadOnlyList source, IList destination, int index = 0) + { + for (int i = 0; i < source.Count; i++) + { + destination[index + i] = source[i]; + } + } + /// /// Copies all the elements of the current collection to the specified list /// starting at the specified destination array index. The index is specified as a 32-bit integer. diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 0e9f7ee44..369f63b13 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -2045,7 +2045,7 @@ namespace MediaBrowser.Controller.Entities if (itemByPath == null) { - //Logger.LogWarning("Unable to find linked item at path {0}", info.Path); + Logger.LogWarning("Unable to find linked item at path {0}", info.Path); } return itemByPath; @@ -2057,7 +2057,7 @@ namespace MediaBrowser.Controller.Entities if (item == null) { - //Logger.LogWarning("Unable to find linked item at path {0}", info.Path); + Logger.LogWarning("Unable to find linked item at path {0}", info.Path); } return item; @@ -2085,14 +2085,17 @@ namespace MediaBrowser.Controller.Entities if (!current.Contains(name, StringComparer.OrdinalIgnoreCase)) { - if (current.Length == 0) + int curLen = current.Length; + if (curLen == 0) { Studios = new[] { name }; } else { - var list = - Studios = current.Concat(new[] { name }).ToArray(); + var newArr = new string[curLen + 1]; + current.CopyTo(newArr, 0); + newArr[curLen] = name; + Studios = newArr; } } } @@ -2231,8 +2234,12 @@ namespace MediaBrowser.Controller.Entities else { - var currentCount = ImageInfos.Length; - ImageInfos = ImageInfos.Concat(new[] { image }).ToArray(); + var current = ImageInfos; + var currentCount = current.Length; + var newArr = new ItemImageInfo[currentCount + 1]; + current.CopyTo(newArr, 0); + current[currentCount] = image; + ImageInfos = current; } } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 841205d0c..eb3d2ab81 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1252,9 +1252,6 @@ namespace MediaBrowser.Controller.MediaEncoding { if (request.AudioBitRate.HasValue) { - // Make sure we don't request a bitrate higher than the source - var currentBitrate = audioStream == null ? request.AudioBitRate.Value : audioStream.BitRate ?? request.AudioBitRate.Value; - // Don't encode any higher than this return Math.Min(384000, request.AudioBitRate.Value); } diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs index 19009e577..bd727bcdf 100644 --- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs @@ -158,8 +158,6 @@ namespace MediaBrowser.LocalMetadata.Savers /// Task. public static void AddCommonNodes(BaseItem item, XmlWriter writer, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataRepo, IFileSystem fileSystem, IServerConfigurationManager config) { - var writtenProviderIds = new HashSet(StringComparer.OrdinalIgnoreCase); - if (!string.IsNullOrEmpty(item.OfficialRating)) { writer.WriteElementString("ContentRating", item.OfficialRating); diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 9ddfb9b01..d5fa76c3a 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -506,12 +506,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles if (failed) { - var msg = string.Format("ffmpeg subtitle conversion failed for {Path}", inputPath); + _logger.LogError("ffmpeg subtitle conversion failed for {Path}", inputPath); - _logger.LogError(msg); - - throw new Exception(msg); + throw new Exception( + string.Format(CultureInfo.InvariantCulture, "ffmpeg subtitle conversion failed for {0}", inputPath)); } + await SetAssFont(outputPath).ConfigureAwait(false); _logger.LogInformation("ffmpeg subtitle conversion succeeded for {Path}", inputPath); diff --git a/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs index aa28fded1..091c1957e 100644 --- a/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs @@ -31,7 +31,7 @@ namespace MediaBrowser.XbmcMetadata.Savers /// public override bool IsEnabledFor(BaseItem item, ItemUpdateType updateType) - => !item.SupportsLocalMetadata && item is Episode && updateType >= MinimumUpdateType; + => item.SupportsLocalMetadata && item is Episode && updateType >= MinimumUpdateType; /// protected override void WriteCustomElements(BaseItem item, XmlWriter writer) diff --git a/RSSDP/SsdpDevicePublisher.cs b/RSSDP/SsdpDevicePublisher.cs index 7f3e56394..53b740052 100644 --- a/RSSDP/SsdpDevicePublisher.cs +++ b/RSSDP/SsdpDevicePublisher.cs @@ -86,7 +86,6 @@ namespace Rssdp.Infrastructure ThrowIfDisposed(); - var minCacheTime = TimeSpan.Zero; bool wasAdded = false; lock (_Devices) { @@ -94,7 +93,6 @@ namespace Rssdp.Infrastructure { _Devices.Add(device); wasAdded = true; - minCacheTime = GetMinimumNonZeroCacheLifetime(); } } @@ -120,14 +118,12 @@ namespace Rssdp.Infrastructure if (device == null) throw new ArgumentNullException(nameof(device)); bool wasRemoved = false; - var minCacheTime = TimeSpan.Zero; lock (_Devices) { if (_Devices.Contains(device)) { _Devices.Remove(device); wasRemoved = true; - minCacheTime = GetMinimumNonZeroCacheLifetime(); } } -- cgit v1.2.3 From 1b01a6ece1c60ed5b767f825265de17f78a2770a Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sat, 28 Sep 2019 01:29:54 +0200 Subject: Add tests for EncoderValidator * Add support for ffmpeg 4.2 * Parse the complete ffmpeg version instead of only the first 2 digits * Make max and min version optional * Remove max limitation (for now) * Style improvements --- .../Encoder/EncoderValidator.cs | 299 ++++++++++----------- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 21 +- .../Properties/AssemblyInfo.cs | 2 + MediaBrowser.sln | 7 + .../Jellyfin.Common.Tests.csproj | 4 +- .../EncoderValidatorTests.cs | 39 +++ .../EncoderValidatorTestsData.cs | 31 +++ .../Jellyfin.MediaEncoding.Tests.csproj | 19 ++ 8 files changed, 246 insertions(+), 176 deletions(-) create mode 100644 tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs create mode 100644 tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs create mode 100644 tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index b00350875..da0b7693e 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -1,111 +1,154 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; +using System.Diagnostics; using System.Linq; +using System.Text; using System.Text.RegularExpressions; -using MediaBrowser.Model.Diagnostics; using Microsoft.Extensions.Logging; namespace MediaBrowser.MediaEncoding.Encoder { public class EncoderValidator { - private readonly ILogger _logger; - private readonly IProcessFactory _processFactory; + private const string DefaultEncoderPath = "ffmpeg"; - public EncoderValidator(ILogger logger, IProcessFactory processFactory) + private static readonly string[] requiredDecoders = new[] { - _logger = logger; - _processFactory = processFactory; - } + "mpeg2video", + "h264_qsv", + "hevc_qsv", + "mpeg2_qsv", + "vc1_qsv", + "h264_cuvid", + "hevc_cuvid", + "dts", + "ac3", + "aac", + "mp3", + "h264", + "hevc" + }; - public (IEnumerable decoders, IEnumerable encoders) GetAvailableCoders(string encoderPath) + private static readonly string[] requiredEncoders = new[] + { + "libx264", + "libx265", + "mpeg4", + "msmpeg4", + "libvpx", + "libvpx-vp9", + "aac", + "libmp3lame", + "libopus", + "libvorbis", + "srt", + "h264_nvenc", + "hevc_nvenc", + "h264_qsv", + "hevc_qsv", + "h264_omx", + "hevc_omx", + "h264_vaapi", + "hevc_vaapi", + "h264_v4l2m2m", + "ac3" + }; + + // Try and use the individual library versions to determine a FFmpeg version + // This lookup table is to be maintained with the following command line: + // $ ffmpeg -version | perl -ne ' print "$1=$2.$3," if /^(lib\w+)\s+(\d+)\.\s*(\d+)/' + private static readonly IReadOnlyDictionary _ffmpegVersionMap = new Dictionary { - _logger.LogInformation("Validating media encoder at {EncoderPath}", encoderPath); + { "libavutil=56.31,libavcodec=58.54,libavformat=58.29,libavdevice=58.8,libavfilter=7.57,libswscale=5.5,libswresample=3.5,libpostproc=55.5,", new Version(4, 2) }, + { "libavutil=56.22,libavcodec=58.35,libavformat=58.20,libavdevice=58.5,libavfilter=7.40,libswscale=5.3,libswresample=3.3,libpostproc=55.3,", new Version(4, 1) }, + { "libavutil=56.14,libavcodec=58.18,libavformat=58.12,libavdevice=58.3,libavfilter=7.16,libswscale=5.1,libswresample=3.1,libpostproc=55.1,", new Version(4, 0) }, + { "libavutil=55.78,libavcodec=57.107,libavformat=57.83,libavdevice=57.10,libavfilter=6.107,libswscale=4.8,libswresample=2.9,libpostproc=54.7,", new Version(3, 4) }, + { "libavutil=55.58,libavcodec=57.89,libavformat=57.71,libavdevice=57.6,libavfilter=6.82,libswscale=4.6,libswresample=2.7,libpostproc=54.5,", new Version(3, 3) }, + { "libavutil=55.34,libavcodec=57.64,libavformat=57.56,libavdevice=57.1,libavfilter=6.65,libswscale=4.2,libswresample=2.3,libpostproc=54.1,", new Version(3, 2) }, + { "libavutil=54.31,libavcodec=56.60,libavformat=56.40,libavdevice=56.4,libavfilter=5.40,libswscale=3.1,libswresample=1.2,libpostproc=53.3,", new Version(2, 8) } + }; - var decoders = GetCodecs(encoderPath, Codec.Decoder); - var encoders = GetCodecs(encoderPath, Codec.Encoder); + private readonly ILogger _logger; - _logger.LogInformation("Encoder validation complete"); + private readonly string _encoderPath; - return (decoders, encoders); + public EncoderValidator(ILogger logger, string encoderPath = DefaultEncoderPath) + { + _logger = logger; + _encoderPath = encoderPath; } - public bool ValidateVersion(string encoderAppPath, bool logOutput) + public static Version MinVersion { get; } = new Version(4, 0); + + public static Version MaxVersion { get; } = null; + + public bool ValidateVersion() { string output = null; try { - output = GetProcessOutput(encoderAppPath, "-version"); + output = GetProcessOutput(_encoderPath, "-version"); } catch (Exception ex) { - if (logOutput) - { - _logger.LogError(ex, "Error validating encoder"); - } + _logger.LogError(ex, "Error validating encoder"); } if (string.IsNullOrWhiteSpace(output)) { - if (logOutput) - { - _logger.LogError("FFmpeg validation: The process returned no result"); - } + _logger.LogError("FFmpeg validation: The process returned no result"); return false; } _logger.LogDebug("ffmpeg output: {Output}", output); - if (output.IndexOf("Libav developers", StringComparison.OrdinalIgnoreCase) != -1) + return ValidateVersionInternal(output); + } + + internal bool ValidateVersionInternal(string versionOutput) + { + if (versionOutput.IndexOf("Libav developers", StringComparison.OrdinalIgnoreCase) != -1) { - if (logOutput) - { - _logger.LogError("FFmpeg validation: avconv instead of ffmpeg is not supported"); - } + _logger.LogError("FFmpeg validation: avconv instead of ffmpeg is not supported"); return false; } - // The min and max FFmpeg versions required to run jellyfin successfully - var minRequired = new Version(4, 0); - var maxRequired = new Version(4, 0); - // Work out what the version under test is - var underTest = GetFFmpegVersion(output); + var version = GetFFmpegVersion(versionOutput); - if (logOutput) - { - _logger.LogInformation("FFmpeg validation: Found ffmpeg version {0}", underTest != null ? underTest.ToString() : "unknown"); + _logger.LogInformation("Found ffmpeg version {0}", version != null ? version.ToString() : "unknown"); - if (underTest == null) // Version is unknown - { - if (minRequired.Equals(maxRequired)) - { - _logger.LogWarning("FFmpeg validation: We recommend ffmpeg version {0}", minRequired.ToString()); - } - else - { - _logger.LogWarning("FFmpeg validation: We recommend a minimum of {0} and maximum of {1}", minRequired.ToString(), maxRequired.ToString()); - } - } - else if (underTest.CompareTo(minRequired) < 0) // Version is below what we recommend - { - _logger.LogWarning("FFmpeg validation: The minimum recommended ffmpeg version is {0}", minRequired.ToString()); - } - else if (underTest.CompareTo(maxRequired) > 0) // Version is above what we recommend + if (version == null && MinVersion != null && MaxVersion != null) // Version is unknown + { + if (MinVersion == MaxVersion) { - _logger.LogWarning("FFmpeg validation: The maximum recommended ffmpeg version is {0}", maxRequired.ToString()); + _logger.LogWarning("FFmpeg validation: We recommend ffmpeg version {0}", MinVersion); } - else // Version is ok + else { - _logger.LogInformation("FFmpeg validation: Found suitable ffmpeg version"); + _logger.LogWarning("FFmpeg validation: We recommend a minimum of {0} and maximum of {1}", MinVersion, MaxVersion); } + + return false; + } + else if (MinVersion != null && version < MinVersion) // Version is below what we recommend + { + _logger.LogWarning("FFmpeg validation: The minimum recommended ffmpeg version is {0}", MinVersion); + return false; + } + else if (MaxVersion != null && version > MaxVersion) // Version is above what we recommend + { + _logger.LogWarning("FFmpeg validation: The maximum recommended ffmpeg version is {0}", MaxVersion); + return false; } - // underTest shall be null if versions is unknown - return (underTest == null) ? false : (underTest.CompareTo(minRequired) >= 0 && underTest.CompareTo(maxRequired) <= 0); + return true; } + public IEnumerable GetDecoders() => GetCodecs(Codec.Decoder); + + public IEnumerable GetEncoders() => GetCodecs(Codec.Encoder); + /// /// Using the output from "ffmpeg -version" work out the FFmpeg version. /// For pre-built binaries the first line should contain a string like "ffmpeg version x.y", which is easy @@ -115,10 +158,10 @@ namespace MediaBrowser.MediaEncoding.Encoder /// /// /// - static private Version GetFFmpegVersion(string output) + internal static Version GetFFmpegVersion(string output) { // For pre-built binaries the FFmpeg version should be mentioned at the very start of the output - var match = Regex.Match(output, @"ffmpeg version (\d+\.\d+)"); + var match = Regex.Match(output, @"ffmpeg version ((?:\d+\.?)+)"); if (match.Success) { @@ -126,25 +169,11 @@ namespace MediaBrowser.MediaEncoding.Encoder } else { - // Try and use the individual library versions to determine a FFmpeg version - // This lookup table is to be maintained with the following command line: - // $ ./ffmpeg.exe -version | perl -ne ' print "$1=$2.$3," if /^(lib\w+)\s+(\d+)\.\s*(\d+)/' - var lut = new ReadOnlyDictionary - (new Dictionary - { - { new Version("4.1"), "libavutil=56.22,libavcodec=58.35,libavformat=58.20,libavdevice=58.5,libavfilter=7.40,libswscale=5.3,libswresample=3.3,libpostproc=55.3," }, - { new Version("4.0"), "libavutil=56.14,libavcodec=58.18,libavformat=58.12,libavdevice=58.3,libavfilter=7.16,libswscale=5.1,libswresample=3.1,libpostproc=55.1," }, - { new Version("3.4"), "libavutil=55.78,libavcodec=57.107,libavformat=57.83,libavdevice=57.10,libavfilter=6.107,libswscale=4.8,libswresample=2.9,libpostproc=54.7," }, - { new Version("3.3"), "libavutil=55.58,libavcodec=57.89,libavformat=57.71,libavdevice=57.6,libavfilter=6.82,libswscale=4.6,libswresample=2.7,libpostproc=54.5," }, - { new Version("3.2"), "libavutil=55.34,libavcodec=57.64,libavformat=57.56,libavdevice=57.1,libavfilter=6.65,libswscale=4.2,libswresample=2.3,libpostproc=54.1," }, - { new Version("2.8"), "libavutil=54.31,libavcodec=56.60,libavformat=56.40,libavdevice=56.4,libavfilter=5.40,libswscale=3.1,libswresample=1.2,libpostproc=53.3," } - }); - // Create a reduced version string and lookup key from dictionary - var reducedVersion = GetVersionString(output); + var reducedVersion = GetLibrariesVersionString(output); // Try to lookup the string and return Key, otherwise if not found returns null - return lut.FirstOrDefault(x => x.Value == reducedVersion).Key; + return _ffmpegVersionMap.TryGetValue(reducedVersion, out Version version) ? version : null; } } @@ -154,76 +183,38 @@ namespace MediaBrowser.MediaEncoding.Encoder /// /// /// - static private string GetVersionString(string output) + private static string GetLibrariesVersionString(string output) { - string pattern = @"((?lib\w+)\s+(?\d+)\.\s*(?\d+))"; - RegexOptions options = RegexOptions.Multiline; - - string rc = null; - - foreach (Match m in Regex.Matches(output, pattern, options)) + var rc = new StringBuilder(144); + foreach (Match m in Regex.Matches( + output, + @"((?lib\w+)\s+(?\d+)\.\s*(?\d+))", + RegexOptions.Multiline)) { - rc += string.Concat(m.Groups["name"], '=', m.Groups["major"], '.', m.Groups["minor"], ','); + rc.Append(m.Groups["name"]) + .Append('=') + .Append(m.Groups["major"]) + .Append('.') + .Append(m.Groups["minor"]) + .Append(','); } - return rc; + return rc.Length == 0 ? null : rc.ToString(); } - private static readonly string[] requiredDecoders = new[] - { - "mpeg2video", - "h264_qsv", - "hevc_qsv", - "mpeg2_qsv", - "vc1_qsv", - "h264_cuvid", - "hevc_cuvid", - "dts", - "ac3", - "aac", - "mp3", - "h264", - "hevc" - }; - - private static readonly string[] requiredEncoders = new[] - { - "libx264", - "libx265", - "mpeg4", - "msmpeg4", - "libvpx", - "libvpx-vp9", - "aac", - "libmp3lame", - "libopus", - "libvorbis", - "srt", - "h264_nvenc", - "hevc_nvenc", - "h264_qsv", - "hevc_qsv", - "h264_omx", - "hevc_omx", - "h264_vaapi", - "hevc_vaapi", - "h264_v4l2m2m", - "ac3" - }; - private enum Codec { Encoder, Decoder } - private IEnumerable GetCodecs(string encoderAppPath, Codec codec) + private IEnumerable GetCodecs(Codec codec) { string codecstr = codec == Codec.Encoder ? "encoders" : "decoders"; string output = null; try { - output = GetProcessOutput(encoderAppPath, "-" + codecstr); + output = GetProcessOutput(_encoderPath, "-" + codecstr); } catch (Exception ex) { @@ -250,45 +241,25 @@ namespace MediaBrowser.MediaEncoding.Encoder private string GetProcessOutput(string path, string arguments) { - IProcess process = _processFactory.Create(new ProcessOptions + using (var process = new Process() { - CreateNoWindow = true, - UseShellExecute = false, - FileName = path, - Arguments = arguments, - IsHidden = true, - ErrorDialog = false, - RedirectStandardOutput = true, - // ffmpeg uses stderr to log info, don't show this - RedirectStandardError = true - }); - - _logger.LogDebug("Running {Path} {Arguments}", path, arguments); - - using (process) + StartInfo = new ProcessStartInfo(path, arguments) + { + CreateNoWindow = true, + UseShellExecute = false, + WindowStyle = ProcessWindowStyle.Hidden, + ErrorDialog = false, + RedirectStandardOutput = true, + // ffmpeg uses stderr to log info, don't show this + RedirectStandardError = true + } + }) { + _logger.LogDebug("Running {Path} {Arguments}", path, arguments); + process.Start(); - try - { - return process.StandardOutput.ReadToEnd(); - } - catch - { - _logger.LogWarning("Killing process {Path} {Arguments}", path, arguments); - - // Hate having to do this - try - { - process.Kill(); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error killing process"); - } - - throw; - } + return process.StandardOutput.ReadToEnd(); } } } diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 75bb960c3..04ff66991 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -114,13 +114,13 @@ namespace MediaBrowser.MediaEncoding.Encoder FFprobePath = Regex.Replace(FFmpegPath, @"[^\/\\]+?(\.[^\/\\\n.]+)?$", @"ffprobe$1"); // Interrogate to understand what coders are supported - var result = new EncoderValidator(_logger, _processFactory).GetAvailableCoders(FFmpegPath); + var validator = new EncoderValidator(_logger, FFmpegPath); - SetAvailableDecoders(result.decoders); - SetAvailableEncoders(result.encoders); + SetAvailableDecoders(validator.GetDecoders()); + SetAvailableEncoders(validator.GetEncoders()); } - _logger.LogInformation("FFmpeg: {0}: {1}", EncoderLocation.ToString(), FFmpegPath ?? string.Empty); + _logger.LogInformation("FFmpeg: {0}: {1}", EncoderLocation, FFmpegPath ?? string.Empty); } /// @@ -183,11 +183,11 @@ namespace MediaBrowser.MediaEncoding.Encoder { if (File.Exists(path)) { - rc = new EncoderValidator(_logger, _processFactory).ValidateVersion(path, true); + rc = new EncoderValidator(_logger, path).ValidateVersion(); if (!rc) { - _logger.LogWarning("FFmpeg: {0}: Failed version check: {1}", location.ToString(), path); + _logger.LogWarning("FFmpeg: {0}: Failed version check: {1}", location, path); } // ToDo - Enable the ffmpeg validator. At the moment any version can be used. @@ -198,7 +198,7 @@ namespace MediaBrowser.MediaEncoding.Encoder } else { - _logger.LogWarning("FFmpeg: {0}: File not found: {1}", location.ToString(), path); + _logger.LogWarning("FFmpeg: {0}: File not found: {1}", location, path); } } @@ -228,9 +228,9 @@ namespace MediaBrowser.MediaEncoding.Encoder /// /// /// - private string ExistsOnSystemPath(string filename) + private string ExistsOnSystemPath(string fileName) { - string inJellyfinPath = GetEncoderPathFromDirectory(System.AppContext.BaseDirectory, filename); + string inJellyfinPath = GetEncoderPathFromDirectory(System.AppContext.BaseDirectory, fileName); if (!string.IsNullOrEmpty(inJellyfinPath)) { return inJellyfinPath; @@ -239,13 +239,14 @@ namespace MediaBrowser.MediaEncoding.Encoder foreach (var path in values.Split(Path.PathSeparator)) { - var candidatePath = GetEncoderPathFromDirectory(path, filename); + var candidatePath = GetEncoderPathFromDirectory(path, fileName); if (!string.IsNullOrEmpty(candidatePath)) { return candidatePath; } } + return null; } diff --git a/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs b/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs index a9491374b..7b74cfc89 100644 --- a/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs +++ b/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs @@ -1,5 +1,6 @@ using System.Reflection; using System.Resources; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following @@ -14,6 +15,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] +[assembly: InternalsVisibleTo("Jellyfin.MediaEncoding.Tests")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from diff --git a/MediaBrowser.sln b/MediaBrowser.sln index d23ca1cdb..dd4e9f8a6 100644 --- a/MediaBrowser.sln +++ b/MediaBrowser.sln @@ -57,6 +57,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{FBBB5129 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Common.Tests", "tests\Jellyfin.Common.Tests\Jellyfin.Common.Tests.csproj", "{DF194677-DFD3-42AF-9F75-D44D5A416478}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.MediaEncoding.Tests", "tests\Jellyfin.MediaEncoding.Tests\Jellyfin.MediaEncoding.Tests.csproj", "{28464062-0939-4AA7-9F7B-24DDDA61A7C0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -159,6 +161,10 @@ Global {DF194677-DFD3-42AF-9F75-D44D5A416478}.Debug|Any CPU.Build.0 = Debug|Any CPU {DF194677-DFD3-42AF-9F75-D44D5A416478}.Release|Any CPU.ActiveCfg = Release|Any CPU {DF194677-DFD3-42AF-9F75-D44D5A416478}.Release|Any CPU.Build.0 = Release|Any CPU + {28464062-0939-4AA7-9F7B-24DDDA61A7C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {28464062-0939-4AA7-9F7B-24DDDA61A7C0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {28464062-0939-4AA7-9F7B-24DDDA61A7C0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {28464062-0939-4AA7-9F7B-24DDDA61A7C0}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -186,5 +192,6 @@ Global EndGlobalSection GlobalSection(NestedProjects) = preSolution {DF194677-DFD3-42AF-9F75-D44D5A416478} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6} + {28464062-0939-4AA7-9F7B-24DDDA61A7C0} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6} EndGlobalSection EndGlobal diff --git a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj index 449aaa1a5..242d99381 100644 --- a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj +++ b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj @@ -2,14 +2,14 @@ netcoreapp2.2 - false - + + diff --git a/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs new file mode 100644 index 000000000..9fa1e4f7e --- /dev/null +++ b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using MediaBrowser.MediaEncoding.Encoder; +using Microsoft.Extensions.Logging.Abstractions; +using Xunit; + +namespace Jellyfin.MediaEncoding.Tests +{ + public class EncoderValidatorTests + { + private class GetFFmpegVersionTestData : IEnumerable + { + public IEnumerator GetEnumerator() + { + yield return new object[] { EncoderValidatorTestsData.FFmpegV42Output, new Version(4, 2) }; + yield return new object[] { EncoderValidatorTestsData.FFmpegV404Output, new Version(4, 0, 4) }; + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } + + [Theory] + [ClassData(typeof(GetFFmpegVersionTestData))] + public void GetFFmpegVersionTest(string versionOutput, Version version) + { + Assert.Equal(version, EncoderValidator.GetFFmpegVersion(versionOutput)); + } + + [Theory] + [InlineData(EncoderValidatorTestsData.FFmpegV42Output, true)] + [InlineData(EncoderValidatorTestsData.FFmpegV404Output, true)] + public void ValidateVersionInternalTest(string versionOutput, bool valid) + { + var val = new EncoderValidator(new NullLogger()); + Assert.Equal(valid, val.ValidateVersionInternal(versionOutput)); + } + } +} diff --git a/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs new file mode 100644 index 000000000..d2a2e4358 --- /dev/null +++ b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs @@ -0,0 +1,31 @@ +namespace Jellyfin.MediaEncoding.Tests +{ + internal static class EncoderValidatorTestsData + { + public const string FFmpegV42Output = @"ffmpeg version n4.2 Copyright (c) 2000-2019 the FFmpeg developers +built with gcc 9.1.0 (GCC) +configuration: --prefix=/usr --disable-debug --disable-static --disable-stripping --enable-fontconfig --enable-gmp --enable-gnutls --enable-gpl --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libdav1d --enable-libdrm --enable-libfreetype --enable-libfribidi --enable-libgsm --enable-libiec61883 --enable-libjack --enable-libmodplug --enable-libmp3lame --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxcb --enable-libxml2 --enable-libxvid --enable-nvdec --enable-nvenc --enable-omx --enable-shared --enable-version3 +libavutil 56. 31.100 / 56. 31.100 +libavcodec 58. 54.100 / 58. 54.100 +libavformat 58. 29.100 / 58. 29.100 +libavdevice 58. 8.100 / 58. 8.100 +libavfilter 7. 57.100 / 7. 57.100 +libswscale 5. 5.100 / 5. 5.100 +libswresample 3. 5.100 / 3. 5.100 +libpostproc 55. 5.100 / 55. 5.100 +"; + + public const string FFmpegV404Output = @"ffmpeg version 4.0.4 Copyright (c) 2000-2019 the FFmpeg developers +built with gcc 8 (Debian 8.3.0-6) +configuration: --toolchain=hardened --prefix=/usr --target-os=linux --enable-cross-compile --extra-cflags=--static --enable-gpl --enable-static --disable-doc --disable-ffplay --disable-shared --disable-libxcb --disable-sdl2 --disable-xlib --enable-libfontconfig --enable-fontconfig --enable-gmp --enable-gnutls --enable-libass --enable-libbluray --enable-libdrm --enable-libfreetype --enable-libfribidi --enable-libmp3lame --enable-libopus --enable-libtheora --enable-libvorbis --enable-libwebp --enable-libx264 --enable-libx265 --enable-libzvbi --enable-omx --enable-omx-rpi --enable-version3 --enable-vaapi --enable-vdpau --arch=amd64 --enable-nvenc --enable-nvdec +libavutil 56. 14.100 / 56. 14.100 +libavcodec 58. 18.100 / 58. 18.100 +libavformat 58. 12.100 / 58. 12.100 +libavdevice 58. 3.100 / 58. 3.100 +libavfilter 7. 16.100 / 7. 16.100 +libswscale 5. 1.100 / 5. 1.100 +libswresample 3. 1.100 / 3. 1.100 +libpostproc 55. 1.100 / 55. 1.100 +"; + } +} diff --git a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj new file mode 100644 index 000000000..beb03d563 --- /dev/null +++ b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj @@ -0,0 +1,19 @@ + + + + netcoreapp2.2 + false + + + + + + + + + + + + + + -- cgit v1.2.3 From 3e1aab6b29621db741ecfb469189322c907b673f Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sun, 29 Sep 2019 13:41:24 +0200 Subject: Fix ffmpeg version check for unknown versions --- .../Encoder/EncoderValidator.cs | 19 +++++++------ .../EncoderValidatorTests.cs | 4 +++ .../EncoderValidatorTestsData.cs | 32 ++++++++++++++++++---- 3 files changed, 41 insertions(+), 14 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index da0b7693e..3620abfee 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -118,15 +118,18 @@ namespace MediaBrowser.MediaEncoding.Encoder _logger.LogInformation("Found ffmpeg version {0}", version != null ? version.ToString() : "unknown"); - if (version == null && MinVersion != null && MaxVersion != null) // Version is unknown + if (version == null) { - if (MinVersion == MaxVersion) + if (MinVersion != null && MaxVersion != null) // Version is unknown { - _logger.LogWarning("FFmpeg validation: We recommend ffmpeg version {0}", MinVersion); - } - else - { - _logger.LogWarning("FFmpeg validation: We recommend a minimum of {0} and maximum of {1}", MinVersion, MaxVersion); + if (MinVersion == MaxVersion) + { + _logger.LogWarning("FFmpeg validation: We recommend ffmpeg version {0}", MinVersion); + } + else + { + _logger.LogWarning("FFmpeg validation: We recommend a minimum of {0} and maximum of {1}", MinVersion, MaxVersion); + } } return false; @@ -161,7 +164,7 @@ namespace MediaBrowser.MediaEncoding.Encoder internal static Version GetFFmpegVersion(string output) { // For pre-built binaries the FFmpeg version should be mentioned at the very start of the output - var match = Regex.Match(output, @"ffmpeg version ((?:\d+\.?)+)"); + var match = Regex.Match(output, @"^ffmpeg version n?((?:\d+\.?)+)"); if (match.Success) { diff --git a/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs index 5a759bcb2..a7848316e 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs @@ -13,9 +13,11 @@ namespace Jellyfin.MediaEncoding.Tests { public IEnumerator GetEnumerator() { + yield return new object[] { EncoderValidatorTestsData.FFmpegV421Output, new Version(4, 2, 1) }; yield return new object[] { EncoderValidatorTestsData.FFmpegV42Output, new Version(4, 2) }; yield return new object[] { EncoderValidatorTestsData.FFmpegV414Output, new Version(4, 1, 4) }; yield return new object[] { EncoderValidatorTestsData.FFmpegV404Output, new Version(4, 0, 4) }; + yield return new object[] { EncoderValidatorTestsData.FFmpegGitUnknownOutput, null }; } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); @@ -29,9 +31,11 @@ namespace Jellyfin.MediaEncoding.Tests } [Theory] + [InlineData(EncoderValidatorTestsData.FFmpegV421Output, true)] [InlineData(EncoderValidatorTestsData.FFmpegV42Output, true)] [InlineData(EncoderValidatorTestsData.FFmpegV414Output, true)] [InlineData(EncoderValidatorTestsData.FFmpegV404Output, true)] + [InlineData(EncoderValidatorTestsData.FFmpegGitUnknownOutput, false)] public void ValidateVersionInternalTest(string versionOutput, bool valid) { var val = new EncoderValidator(new NullLogger()); diff --git a/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs index 1d444e2b3..12fde0770 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs @@ -2,6 +2,18 @@ namespace Jellyfin.MediaEncoding.Tests { internal static class EncoderValidatorTestsData { + public const string FFmpegV421Output = @"ffmpeg version 4.2.1 Copyright (c) 2000-2019 the FFmpeg developers +built with gcc 9.1.1 (GCC) 20190807 +configuration: --enable-gpl --enable-version3 --enable-sdl2 --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libdav1d --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex --enable-libxvid --enable-libaom --enable-libmfx --enable-amf --enable-ffnvcodec --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth --enable-libopenmpt +libavutil 56. 31.100 / 56. 31.100 +libavcodec 58. 54.100 / 58. 54.100 +libavformat 58. 29.100 / 58. 29.100 +libavdevice 58. 8.100 / 58. 8.100 +libavfilter 7. 57.100 / 7. 57.100 +libswscale 5. 5.100 / 5. 5.100 +libswresample 3. 5.100 / 3. 5.100 +libpostproc 55. 5.100 / 55. 5.100"; + public const string FFmpegV42Output = @"ffmpeg version n4.2 Copyright (c) 2000-2019 the FFmpeg developers built with gcc 9.1.0 (GCC) configuration: --prefix=/usr --disable-debug --disable-static --disable-stripping --enable-fontconfig --enable-gmp --enable-gnutls --enable-gpl --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libdav1d --enable-libdrm --enable-libfreetype --enable-libfribidi --enable-libgsm --enable-libiec61883 --enable-libjack --enable-libmodplug --enable-libmp3lame --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxcb --enable-libxml2 --enable-libxvid --enable-nvdec --enable-nvenc --enable-omx --enable-shared --enable-version3 @@ -12,8 +24,7 @@ libavdevice 58. 8.100 / 58. 8.100 libavfilter 7. 57.100 / 7. 57.100 libswscale 5. 5.100 / 5. 5.100 libswresample 3. 5.100 / 3. 5.100 -libpostproc 55. 5.100 / 55. 5.100 -"; +libpostproc 55. 5.100 / 55. 5.100"; public const string FFmpegV414Output = @"ffmpeg version 4.1.4-1~deb10u1 Copyright (c) 2000-2019 the FFmpeg developers built with gcc 8 (Raspbian 8.3.0-6+rpi1) @@ -26,8 +37,7 @@ libavfilter 7. 40.101 / 7. 40.101 libavresample 4. 0. 0 / 4. 0. 0 libswscale 5. 3.100 / 5. 3.100 libswresample 3. 3.100 / 3. 3.100 -libpostproc 55. 3.100 / 55. 3.100 -"; +libpostproc 55. 3.100 / 55. 3.100"; public const string FFmpegV404Output = @"ffmpeg version 4.0.4 Copyright (c) 2000-2019 the FFmpeg developers built with gcc 8 (Debian 8.3.0-6) @@ -39,8 +49,18 @@ libavdevice 58. 3.100 / 58. 3.100 libavfilter 7. 16.100 / 7. 16.100 libswscale 5. 1.100 / 5. 1.100 libswresample 3. 1.100 / 3. 1.100 -libpostproc 55. 1.100 / 55. 1.100 -"; +libpostproc 55. 1.100 / 55. 1.100"; + public const string FFmpegGitUnknownOutput = @"ffmpeg version N-94303-g7cb4f8c962 Copyright (c) 2000-2019 the FFmpeg developers +built with gcc 9.1.1 (GCC) 20190716 +configuration: --enable-gpl --enable-version3 --enable-sdl2 --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libdav1d --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex --enable-libxvid --enable-libaom --enable-libmfx --enable-amf --enable-ffnvcodec --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth --enable-libopenmpt +libavutil 56. 30.100 / 56. 30.100 +libavcodec 58. 53.101 / 58. 53.101 +libavformat 58. 28.102 / 58. 28.102 +libavdevice 58. 7.100 / 58. 7.100 +libavfilter 7. 56.101 / 7. 56.101 +libswscale 5. 4.101 / 5. 4.101 +libswresample 3. 4.100 / 3. 4.100 +libpostproc 55. 4.100 / 55. 4.100"; } } -- cgit v1.2.3