aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Controller
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Controller')
-rw-r--r--MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs1
-rw-r--r--MediaBrowser.Controller/BaseItemManager/IBaseItemManager.cs1
-rw-r--r--MediaBrowser.Controller/Drawing/IImageProcessor.cs2
-rw-r--r--MediaBrowser.Controller/Drawing/ImageHelper.cs69
-rw-r--r--MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs12
-rw-r--r--MediaBrowser.Controller/Entities/AggregateFolder.cs3
-rw-r--r--MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs12
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs11
-rw-r--r--MediaBrowser.Controller/Entities/BaseItemExtensions.cs20
-rw-r--r--MediaBrowser.Controller/Entities/CollectionFolder.cs5
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs10
-rw-r--r--MediaBrowser.Controller/Entities/TV/Episode.cs10
-rw-r--r--MediaBrowser.Controller/Entities/TV/Season.cs11
-rw-r--r--MediaBrowser.Controller/Entities/TV/Series.cs16
-rw-r--r--MediaBrowser.Controller/Entities/UserViewBuilder.cs10
-rw-r--r--MediaBrowser.Controller/Events/Updates/PluginUninstalledEventArgs.cs1
-rw-r--r--MediaBrowser.Controller/IDisplayPreferencesManager.cs2
-rw-r--r--MediaBrowser.Controller/IServerApplicationHost.cs8
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs11
-rw-r--r--MediaBrowser.Controller/Library/ItemResolveArgs.cs4
-rw-r--r--MediaBrowser.Controller/Library/MetadataConfigurationExtensions.cs15
-rw-r--r--MediaBrowser.Controller/Library/MetadataConfigurationStore.cs12
-rw-r--r--MediaBrowser.Controller/Library/NameExtensions.cs8
-rw-r--r--MediaBrowser.Controller/LiveTv/ChannelInfo.cs6
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj9
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs749
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs1
-rw-r--r--MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs9
-rw-r--r--MediaBrowser.Controller/MediaEncoding/JobLogger.cs1
-rw-r--r--MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs5
-rw-r--r--MediaBrowser.Controller/Persistence/IItemRepository.cs3
-rw-r--r--MediaBrowser.Controller/Playlists/Playlist.cs9
-rw-r--r--MediaBrowser.Controller/Plugins/IPluginConfigurationPage.cs51
-rw-r--r--MediaBrowser.Controller/Providers/DirectoryService.cs6
-rw-r--r--MediaBrowser.Controller/Providers/ILocalImageProvider.cs2
-rw-r--r--MediaBrowser.Controller/Providers/IProviderManager.cs25
-rw-r--r--MediaBrowser.Controller/Providers/IRemoteImageProvider.cs1
-rw-r--r--MediaBrowser.Controller/Providers/IRemoteSearchProvider.cs1
-rw-r--r--MediaBrowser.Controller/Providers/MetadataResult.cs12
-rw-r--r--MediaBrowser.Controller/Resolvers/BaseItemResolver.cs2
-rw-r--r--MediaBrowser.Controller/Session/AuthenticationRequest.cs1
-rw-r--r--MediaBrowser.Controller/Subtitles/ISubtitleManager.cs1
42 files changed, 627 insertions, 521 deletions
diff --git a/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs b/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs
index 31dd95402..a233c358e 100644
--- a/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs
+++ b/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs
@@ -1,7 +1,6 @@
using System;
using System.Linq;
using System.Threading;
-using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
diff --git a/MediaBrowser.Controller/BaseItemManager/IBaseItemManager.cs b/MediaBrowser.Controller/BaseItemManager/IBaseItemManager.cs
index e1f5d05a6..8a8736427 100644
--- a/MediaBrowser.Controller/BaseItemManager/IBaseItemManager.cs
+++ b/MediaBrowser.Controller/BaseItemManager/IBaseItemManager.cs
@@ -1,4 +1,3 @@
-using System;
using System.Threading;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Configuration;
diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
index 935a79031..142cebd0c 100644
--- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs
+++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
@@ -61,7 +61,7 @@ namespace MediaBrowser.Controller.Drawing
string GetImageCacheTag(BaseItem item, ChapterInfo info);
- string GetImageCacheTag(User user);
+ string? GetImageCacheTag(User user);
/// <summary>
/// Processes the image.
diff --git a/MediaBrowser.Controller/Drawing/ImageHelper.cs b/MediaBrowser.Controller/Drawing/ImageHelper.cs
index 87c28d577..596fcbc8c 100644
--- a/MediaBrowser.Controller/Drawing/ImageHelper.cs
+++ b/MediaBrowser.Controller/Drawing/ImageHelper.cs
@@ -1,75 +1,18 @@
#pragma warning disable CS1591
+#nullable enable
-using System;
-using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Drawing;
-using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Drawing
{
public static class ImageHelper
{
- public static ImageDimensions GetNewImageSize(ImageProcessingOptions options, ImageDimensions? originalImageSize)
+ public static ImageDimensions GetNewImageSize(ImageProcessingOptions options, ImageDimensions originalImageSize)
{
- if (originalImageSize.HasValue)
- {
- // Determine the output size based on incoming parameters
- var newSize = DrawingUtils.Resize(originalImageSize.Value, options.Width ?? 0, options.Height ?? 0, options.MaxWidth ?? 0, options.MaxHeight ?? 0);
-
- return newSize;
- }
-
- return GetSizeEstimate(options);
- }
-
- private static ImageDimensions GetSizeEstimate(ImageProcessingOptions options)
- {
- if (options.Width.HasValue && options.Height.HasValue)
- {
- return new ImageDimensions(options.Width.Value, options.Height.Value);
- }
-
- double aspect = GetEstimatedAspectRatio(options.Image.Type, options.Item);
-
- int? width = options.Width ?? options.MaxWidth;
-
- if (width.HasValue)
- {
- int heightValue = Convert.ToInt32((double)width.Value / aspect);
- return new ImageDimensions(width.Value, heightValue);
- }
-
- var height = options.Height ?? options.MaxHeight ?? 200;
- int widthValue = Convert.ToInt32(aspect * height);
- return new ImageDimensions(widthValue, height);
- }
-
- private static double GetEstimatedAspectRatio(ImageType type, BaseItem item)
- {
- switch (type)
- {
- case ImageType.Art:
- case ImageType.Backdrop:
- case ImageType.Chapter:
- case ImageType.Screenshot:
- case ImageType.Thumb:
- return 1.78;
- case ImageType.Banner:
- return 5.4;
- case ImageType.Box:
- case ImageType.BoxRear:
- case ImageType.Disc:
- case ImageType.Menu:
- case ImageType.Profile:
- return 1;
- case ImageType.Logo:
- return 2.58;
- case ImageType.Primary:
- double defaultPrimaryImageAspectRatio = item.GetDefaultPrimaryImageAspectRatio();
- return defaultPrimaryImageAspectRatio > 0 ? defaultPrimaryImageAspectRatio : 2.0 / 3;
- default:
- return 1;
- }
+ // Determine the output size based on incoming parameters
+ var newSize = DrawingUtils.Resize(originalImageSize, options.Width ?? 0, options.Height ?? 0, options.MaxWidth ?? 0, options.MaxHeight ?? 0);
+ newSize = DrawingUtils.ResizeFill(newSize, options.FillWidth, options.FillHeight);
+ return newSize;
}
}
}
diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
index 22105b7d7..230a0af60 100644
--- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
+++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
@@ -24,8 +24,6 @@ namespace MediaBrowser.Controller.Drawing
public int ImageIndex { get; set; }
- public bool CropWhiteSpace { get; set; }
-
public int? Width { get; set; }
public int? Height { get; set; }
@@ -34,6 +32,10 @@ namespace MediaBrowser.Controller.Drawing
public int? MaxHeight { get; set; }
+ public int? FillWidth { get; set; }
+
+ public int? FillHeight { get; set; }
+
public int Quality { get; set; }
public IReadOnlyCollection<ImageFormat> SupportedOutputFormats { get; set; }
@@ -95,6 +97,11 @@ namespace MediaBrowser.Controller.Drawing
return false;
}
+ if (sizeValue.Width > FillWidth || sizeValue.Height > FillHeight)
+ {
+ return false;
+ }
+
return true;
}
@@ -106,7 +113,6 @@ namespace MediaBrowser.Controller.Drawing
PercentPlayed.Equals(0) &&
!UnplayedCount.HasValue &&
!Blur.HasValue &&
- !CropWhiteSpace &&
string.IsNullOrEmpty(BackgroundColor) &&
string.IsNullOrEmpty(ForegroundLayer);
}
diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs
index 6ebea5f44..6a92200dd 100644
--- a/MediaBrowser.Controller/Entities/AggregateFolder.cs
+++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs
@@ -120,8 +120,7 @@ namespace MediaBrowser.Controller.Entities
var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, directoryService)
{
- FileInfo = FileSystem.GetDirectoryInfo(path),
- Path = path
+ FileInfo = FileSystem.GetDirectoryInfo(path)
};
// Gather child folder and files
diff --git a/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs b/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs
index f6d3cd6cc..20fad4cb0 100644
--- a/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs
@@ -1,6 +1,8 @@
#pragma warning disable CS1591
using System.Collections.Generic;
+using System.Linq;
+using MediaBrowser.Controller.Library;
namespace MediaBrowser.Controller.Entities.Audio
{
@@ -23,15 +25,7 @@ namespace MediaBrowser.Controller.Entities.Audio
public static IEnumerable<string> GetAllArtists<T>(this T item)
where T : IHasArtist, IHasAlbumArtist
{
- foreach (var i in item.AlbumArtists)
- {
- yield return i;
- }
-
- foreach (var i in item.Artists)
- {
- yield return i;
- }
+ return item.AlbumArtists.Concat(item.Artists).DistinctNames();
}
}
}
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index cbb02aabd..1b69c6646 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -1243,7 +1243,7 @@ namespace MediaBrowser.Controller.Entities
}
}
- return string.Join("/", terms.ToArray());
+ return string.Join('/', terms.ToArray());
}
/// <summary>
@@ -1998,6 +1998,11 @@ namespace MediaBrowser.Controller.Entities
return GetType().Name;
}
+ public BaseItemKind GetBaseItemKind()
+ {
+ return Enum.Parse<BaseItemKind>(GetClientTypeName());
+ }
+
/// <summary>
/// Gets the linked child.
/// </summary>
@@ -2319,7 +2324,7 @@ namespace MediaBrowser.Controller.Entities
.Where(i => i.IsLocalFile)
.Select(i => System.IO.Path.GetDirectoryName(i.Path))
.Distinct(StringComparer.OrdinalIgnoreCase)
- .SelectMany(i => directoryService.GetFilePaths(i))
+ .SelectMany(directoryService.GetFilePaths)
.ToList();
var deletedImages = ImageInfos
@@ -2790,7 +2795,7 @@ namespace MediaBrowser.Controller.Entities
{
var list = GetEtagValues(user);
- return string.Join("|", list).GetMD5().ToString("N", CultureInfo.InvariantCulture);
+ return string.Join('|', list).GetMD5().ToString("N", CultureInfo.InvariantCulture);
}
protected virtual List<string> GetEtagValues(User user)
diff --git a/MediaBrowser.Controller/Entities/BaseItemExtensions.cs b/MediaBrowser.Controller/Entities/BaseItemExtensions.cs
index c65477d39..157ed8332 100644
--- a/MediaBrowser.Controller/Entities/BaseItemExtensions.cs
+++ b/MediaBrowser.Controller/Entities/BaseItemExtensions.cs
@@ -1,5 +1,7 @@
+#nullable enable
#pragma warning disable CS1591
+using System;
using System.Linq;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
@@ -64,9 +66,19 @@ namespace MediaBrowser.Controller.Entities
/// <param name="source">The source object.</param>
/// <param name="dest">The destination object.</param>
public static void DeepCopy<T, TU>(this T source, TU dest)
- where T : BaseItem
- where TU : BaseItem
+ where T : BaseItem
+ where TU : BaseItem
{
+ if (source == null)
+ {
+ throw new ArgumentNullException(nameof(source));
+ }
+
+ if (dest == null)
+ {
+ throw new ArgumentNullException(nameof(dest));
+ }
+
var destProps = typeof(TU).GetProperties().Where(x => x.CanWrite).ToList();
foreach (var sourceProp in typeof(T).GetProperties())
@@ -99,8 +111,8 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <param name="source">The source object.</param>
public static TU DeepCopy<T, TU>(this T source)
- where T : BaseItem
- where TU : BaseItem, new()
+ where T : BaseItem
+ where TU : BaseItem, new()
{
var dest = new TU();
source.DeepCopy(dest);
diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs
index c3b6af76e..16a2c77e9 100644
--- a/MediaBrowser.Controller/Entities/CollectionFolder.cs
+++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs
@@ -26,7 +26,7 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public class CollectionFolder : Folder, ICollectionFolder
{
- private static readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions();
+ private static readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
public static IXmlSerializer XmlSerializer { get; set; }
public static IServerApplicationHost ApplicationHost { get; set; }
@@ -123,7 +123,7 @@ namespace MediaBrowser.Controller.Entities
{
LibraryOptions[path] = options;
- var clone = JsonSerializer.Deserialize<LibraryOptions>(JsonSerializer.Serialize(options, _jsonOptions), _jsonOptions);
+ var clone = JsonSerializer.Deserialize<LibraryOptions>(JsonSerializer.SerializeToUtf8Bytes(options, _jsonOptions), _jsonOptions);
foreach (var mediaPath in clone.PathInfos)
{
if (!string.IsNullOrEmpty(mediaPath.Path))
@@ -271,7 +271,6 @@ namespace MediaBrowser.Controller.Entities
var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, directoryService)
{
FileInfo = FileSystem.GetDirectoryInfo(path),
- Path = path,
Parent = GetParent() as Folder,
CollectionType = CollectionType
};
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index cac5026f7..d45f8758c 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -2,7 +2,6 @@
using System;
using System.Collections.Generic;
-using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.Json.Serialization;
@@ -1434,9 +1433,14 @@ namespace MediaBrowser.Controller.Entities
var linkedChildren = LinkedChildren;
foreach (var i in linkedChildren)
{
- if (i.ItemId.HasValue && i.ItemId.Value == itemId)
+ if (i.ItemId.HasValue)
{
- return true;
+ if (i.ItemId.Value == itemId)
+ {
+ return true;
+ }
+
+ continue;
}
var child = GetLinkedChild(i);
diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs
index dc12fbbea..70663ef47 100644
--- a/MediaBrowser.Controller/Entities/TV/Episode.cs
+++ b/MediaBrowser.Controller/Entities/TV/Episode.cs
@@ -99,7 +99,15 @@ namespace MediaBrowser.Controller.Entities.TV
take--;
}
- list.InsertRange(0, seriesUserDataKeys.Take(take).Select(i => i + ParentIndexNumber.Value.ToString("000") + IndexNumber.Value.ToString("000")));
+ var newList = seriesUserDataKeys.GetRange(0, take);
+ var suffix = ParentIndexNumber.Value.ToString("000", CultureInfo.InvariantCulture) + IndexNumber.Value.ToString("000", CultureInfo.InvariantCulture);
+ for (int i = 0; i < take; i++)
+ {
+ newList[i] = newList[i] + suffix;
+ }
+
+ newList.AddRange(list);
+ list = newList;
}
return list;
diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs
index 93bdd6e70..5b8168d3d 100644
--- a/MediaBrowser.Controller/Entities/TV/Season.cs
+++ b/MediaBrowser.Controller/Entities/TV/Season.cs
@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using System.Text.Json.Serialization;
using Jellyfin.Data.Entities;
@@ -56,7 +57,15 @@ namespace MediaBrowser.Controller.Entities.TV
var series = Series;
if (series != null)
{
- list.InsertRange(0, series.GetUserDataKeys().Select(i => i + (IndexNumber ?? 0).ToString("000")));
+ var newList = series.GetUserDataKeys();
+ var suffix = (IndexNumber ?? 0).ToString("000", CultureInfo.InvariantCulture);
+ for (int i = 0; i < newList.Count; i++)
+ {
+ newList[i] = newList[i] + suffix;
+ }
+
+ newList.AddRange(list);
+ list = newList;
}
return list;
diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs
index 1a379074d..9f9a2ad50 100644
--- a/MediaBrowser.Controller/Entities/TV/Series.cs
+++ b/MediaBrowser.Controller/Entities/TV/Series.cs
@@ -107,7 +107,7 @@ namespace MediaBrowser.Controller.Entities.TV
return key;
}
- return key + "-" + string.Join("-", folders);
+ return key + "-" + string.Join('-', folders);
}
private static string GetUniqueSeriesKey(BaseItem series)
@@ -169,14 +169,12 @@ namespace MediaBrowser.Controller.Entities.TV
{
var list = base.GetUserDataKeys();
- var key = this.GetProviderId(MetadataProvider.Imdb);
- if (!string.IsNullOrEmpty(key))
+ if (this.TryGetProviderId(MetadataProvider.Imdb, out var key))
{
list.Insert(0, key);
}
- key = this.GetProviderId(MetadataProvider.Tvdb);
- if (!string.IsNullOrEmpty(key))
+ if (this.TryGetProviderId(MetadataProvider.Tvdb, out key))
{
list.Insert(0, key);
}
@@ -208,7 +206,7 @@ namespace MediaBrowser.Controller.Entities.TV
query.AncestorWithPresentationUniqueKey = null;
query.SeriesPresentationUniqueKey = seriesKey;
query.IncludeItemTypes = new[] { nameof(Season) };
- query.OrderBy = new[] { ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray();
+ query.OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) };
if (user != null && !user.DisplayMissingEpisodes)
{
@@ -228,7 +226,7 @@ namespace MediaBrowser.Controller.Entities.TV
query.SeriesPresentationUniqueKey = seriesKey;
if (query.OrderBy.Count == 0)
{
- query.OrderBy = new[] { ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray();
+ query.OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) };
}
if (query.IncludeItemTypes.Length == 0)
@@ -254,7 +252,7 @@ namespace MediaBrowser.Controller.Entities.TV
AncestorWithPresentationUniqueKey = null,
SeriesPresentationUniqueKey = seriesKey,
IncludeItemTypes = new[] { nameof(Episode), nameof(Season) },
- OrderBy = new[] { ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray(),
+ OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) },
DtoOptions = options
};
@@ -365,7 +363,7 @@ namespace MediaBrowser.Controller.Entities.TV
AncestorWithPresentationUniqueKey = queryFromSeries ? null : seriesKey,
SeriesPresentationUniqueKey = queryFromSeries ? seriesKey : null,
IncludeItemTypes = new[] { nameof(Episode) },
- OrderBy = new[] { ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray(),
+ OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) },
DtoOptions = options
};
if (user != null)
diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
index 4e33a6bbd..78a64d8c9 100644
--- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs
+++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
@@ -217,8 +217,7 @@ namespace MediaBrowser.Controller.Entities
private QueryResult<BaseItem> GetMovieLatest(Folder parent, User user, InternalItemsQuery query)
{
- query.OrderBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray();
-
+ query.OrderBy = new[] { (ItemSortBy.DateCreated, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Descending) };
query.Recursive = true;
query.Parent = parent;
query.SetUser(user);
@@ -230,7 +229,7 @@ namespace MediaBrowser.Controller.Entities
private QueryResult<BaseItem> GetMovieResume(Folder parent, User user, InternalItemsQuery query)
{
- query.OrderBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray();
+ query.OrderBy = new[] { (ItemSortBy.DatePlayed, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Descending) };
query.IsResumable = true;
query.Recursive = true;
query.Parent = parent;
@@ -327,8 +326,7 @@ namespace MediaBrowser.Controller.Entities
private QueryResult<BaseItem> GetTvLatest(Folder parent, User user, InternalItemsQuery query)
{
- query.OrderBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray();
-
+ query.OrderBy = new[] { (ItemSortBy.DateCreated, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Descending) };
query.Recursive = true;
query.Parent = parent;
query.SetUser(user);
@@ -356,7 +354,7 @@ namespace MediaBrowser.Controller.Entities
private QueryResult<BaseItem> GetTvResume(Folder parent, User user, InternalItemsQuery query)
{
- query.OrderBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray();
+ query.OrderBy = new[] { (ItemSortBy.DatePlayed, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Descending) };
query.IsResumable = true;
query.Recursive = true;
query.Parent = parent;
diff --git a/MediaBrowser.Controller/Events/Updates/PluginUninstalledEventArgs.cs b/MediaBrowser.Controller/Events/Updates/PluginUninstalledEventArgs.cs
index a111e6d82..0f27be9bb 100644
--- a/MediaBrowser.Controller/Events/Updates/PluginUninstalledEventArgs.cs
+++ b/MediaBrowser.Controller/Events/Updates/PluginUninstalledEventArgs.cs
@@ -1,5 +1,4 @@
using Jellyfin.Data.Events;
-using MediaBrowser.Common.Plugins;
using MediaBrowser.Model.Plugins;
namespace MediaBrowser.Controller.Events.Updates
diff --git a/MediaBrowser.Controller/IDisplayPreferencesManager.cs b/MediaBrowser.Controller/IDisplayPreferencesManager.cs
index 041eeea62..be1d974a4 100644
--- a/MediaBrowser.Controller/IDisplayPreferencesManager.cs
+++ b/MediaBrowser.Controller/IDisplayPreferencesManager.cs
@@ -48,7 +48,7 @@ namespace MediaBrowser.Controller
/// <param name="itemId">The item id.</param>
/// <param name="client">The client string.</param>
/// <returns>The dictionary of custom item display preferences.</returns>
- IDictionary<string, string> ListCustomItemDisplayPreferences(Guid userId, Guid itemId, string client);
+ Dictionary<string, string> ListCustomItemDisplayPreferences(Guid userId, Guid itemId, string client);
/// <summary>
/// Sets the custom item display preference for the user and client.
diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs
index 92b2d43ce..6a65a8e47 100644
--- a/MediaBrowser.Controller/IServerApplicationHost.cs
+++ b/MediaBrowser.Controller/IServerApplicationHost.cs
@@ -3,10 +3,7 @@
using System;
using System.Collections.Generic;
using System.Net;
-using System.Threading;
-using System.Threading.Tasks;
using MediaBrowser.Common;
-using MediaBrowser.Common.Plugins;
using MediaBrowser.Model.System;
using Microsoft.AspNetCore.Http;
@@ -53,6 +50,11 @@ namespace MediaBrowser.Controller
string FriendlyName { get; }
/// <summary>
+ /// Gets the configured published server url.
+ /// </summary>
+ string PublishedServerUrl { get; }
+
+ /// <summary>
/// Gets the system info.
/// </summary>
/// <param name="source">The originator of the request.</param>
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index 6700761fc..6d9b568da 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -467,6 +467,15 @@ namespace MediaBrowser.Controller.Library
void UpdatePeople(BaseItem item, List<PersonInfo> people);
/// <summary>
+ /// Asynchronously updates the people.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="people">The people.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>The async task.</returns>
+ Task UpdatePeopleAsync(BaseItem item, List<PersonInfo> people, CancellationToken cancellationToken);
+
+ /// <summary>
/// Gets the item ids.
/// </summary>
/// <param name="query">The query.</param>
@@ -542,7 +551,7 @@ namespace MediaBrowser.Controller.Library
Guid GetMusicGenreId(string name);
- Task AddVirtualFolder(string name, string collectionType, LibraryOptions options, bool refreshLibrary);
+ Task AddVirtualFolder(string name, CollectionTypeOptions? collectionType, LibraryOptions options, bool refreshLibrary);
Task RemoveVirtualFolder(string name, bool refreshLibrary);
diff --git a/MediaBrowser.Controller/Library/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs
index 12a311dc3..f86f7df25 100644
--- a/MediaBrowser.Controller/Library/ItemResolveArgs.cs
+++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs
@@ -60,10 +60,10 @@ namespace MediaBrowser.Controller.Library
public FileSystemMetadata FileInfo { get; set; }
/// <summary>
- /// Gets or sets the path.
+ /// Gets the path.
/// </summary>
/// <value>The path.</value>
- public string Path { get; set; }
+ public string Path => FileInfo.FullName;
/// <summary>
/// Gets a value indicating whether this instance is directory.
diff --git a/MediaBrowser.Controller/Library/MetadataConfigurationExtensions.cs b/MediaBrowser.Controller/Library/MetadataConfigurationExtensions.cs
new file mode 100644
index 000000000..884f9e773
--- /dev/null
+++ b/MediaBrowser.Controller/Library/MetadataConfigurationExtensions.cs
@@ -0,0 +1,15 @@
+#pragma warning disable CS1591
+
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Model.Configuration;
+
+namespace MediaBrowser.Controller.Library
+{
+ public static class MetadataConfigurationExtensions
+ {
+ public static MetadataConfiguration GetMetadataConfiguration(this IConfigurationManager config)
+ {
+ return config.GetConfiguration<MetadataConfiguration>("metadata");
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/Library/MetadataConfigurationStore.cs b/MediaBrowser.Controller/Library/MetadataConfigurationStore.cs
index f16304db0..a6be6c0d3 100644
--- a/MediaBrowser.Controller/Library/MetadataConfigurationStore.cs
+++ b/MediaBrowser.Controller/Library/MetadataConfigurationStore.cs
@@ -14,18 +14,10 @@ namespace MediaBrowser.Controller.Library
{
new ConfigurationStore
{
- Key = "metadata",
- ConfigurationType = typeof(MetadataConfiguration)
+ Key = "metadata",
+ ConfigurationType = typeof(MetadataConfiguration)
}
};
}
}
-
- public static class MetadataConfigurationExtensions
- {
- public static MetadataConfiguration GetMetadataConfiguration(this IConfigurationManager config)
- {
- return config.GetConfiguration<MetadataConfiguration>("metadata");
- }
- }
}
diff --git a/MediaBrowser.Controller/Library/NameExtensions.cs b/MediaBrowser.Controller/Library/NameExtensions.cs
index 1c90bb4e0..6e79dc8dd 100644
--- a/MediaBrowser.Controller/Library/NameExtensions.cs
+++ b/MediaBrowser.Controller/Library/NameExtensions.cs
@@ -10,6 +10,10 @@ namespace MediaBrowser.Controller.Library
{
public static class NameExtensions
{
+ public static IEnumerable<string> DistinctNames(this IEnumerable<string> names)
+ => names.GroupBy(RemoveDiacritics, StringComparer.OrdinalIgnoreCase)
+ .Select(x => x.First());
+
private static string RemoveDiacritics(string? name)
{
if (name == null)
@@ -19,9 +23,5 @@ namespace MediaBrowser.Controller.Library
return name.RemoveDiacritics();
}
-
- public static IEnumerable<string> DistinctNames(this IEnumerable<string> names)
- => names.GroupBy(RemoveDiacritics, StringComparer.OrdinalIgnoreCase)
- .Select(x => x.First());
}
}
diff --git a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs
index 44bd38b54..166c4d77c 100644
--- a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs
+++ b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs
@@ -46,6 +46,12 @@ namespace MediaBrowser.Controller.LiveTv
public ChannelType ChannelType { get; set; }
/// <summary>
+ /// Gets or sets the group of the channel.
+ /// </summary>
+ /// <value>The group of the channel.</value>
+ public string ChannelGroup { get; set; }
+
+ /// <summary>
/// Supply the image path if it can be accessed directly from the file system.
/// </summary>
/// <value>The image path.</value>
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 5f75df54e..8c68b47dd 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -8,7 +8,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Controller</PackageId>
- <VersionPrefix>10.7.0</VersionPrefix>
+ <VersionPrefix>10.8.0</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>
@@ -34,6 +34,8 @@
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release' ">true</TreatWarningsAsErrors>
+ <AnalysisMode Condition=" '$(Configuration)' == 'Debug' ">AllEnabledByDefault</AnalysisMode>
+ <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<IncludeSymbols>true</IncludeSymbols>
@@ -47,14 +49,9 @@
<!-- Code Analyzers-->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
- <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>
- <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
- <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
- </PropertyGroup>
-
</Project>
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index efab87a38..2b5364775 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -10,8 +10,6 @@ using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using Jellyfin.Data.Enums;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Extensions;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
@@ -27,9 +25,7 @@ namespace MediaBrowser.Controller.MediaEncoding
private static readonly CultureInfo _usCulture = new CultureInfo("en-US");
private readonly IMediaEncoder _mediaEncoder;
- private readonly IFileSystem _fileSystem;
private readonly ISubtitleEncoder _subtitleEncoder;
- private readonly IConfiguration _configuration;
private static readonly string[] _videoProfiles = new[]
{
@@ -44,14 +40,10 @@ namespace MediaBrowser.Controller.MediaEncoding
public EncodingHelper(
IMediaEncoder mediaEncoder,
- IFileSystem fileSystem,
- ISubtitleEncoder subtitleEncoder,
- IConfiguration configuration)
+ ISubtitleEncoder subtitleEncoder)
{
_mediaEncoder = mediaEncoder;
- _fileSystem = fileSystem;
_subtitleEncoder = subtitleEncoder;
- _configuration = configuration;
}
public string GetH264Encoder(EncodingJobInfo state, EncodingOptions encodingOptions)
@@ -112,14 +104,57 @@ namespace MediaBrowser.Controller.MediaEncoding
return _mediaEncoder.SupportsHwaccel("vaapi");
}
+ private bool IsCudaSupported()
+ {
+ return _mediaEncoder.SupportsHwaccel("cuda")
+ && _mediaEncoder.SupportsFilter("scale_cuda", null)
+ && _mediaEncoder.SupportsFilter("yadif_cuda", null);
+ }
+
private bool IsTonemappingSupported(EncodingJobInfo state, EncodingOptions options)
{
var videoStream = state.VideoStream;
return IsColorDepth10(state)
&& _mediaEncoder.SupportsHwaccel("opencl")
&& options.EnableTonemapping
- && !string.IsNullOrEmpty(videoStream.VideoRange)
- && videoStream.VideoRange.Contains("HDR", StringComparison.OrdinalIgnoreCase);
+ && string.Equals(videoStream.VideoRange, "HDR", StringComparison.OrdinalIgnoreCase);
+ }
+
+ private bool IsVppTonemappingSupported(EncodingJobInfo state, EncodingOptions options)
+ {
+ var videoStream = state.VideoStream;
+ if (videoStream == null)
+ {
+ // Remote stream doesn't have media info, disable vpp tonemapping.
+ return false;
+ }
+
+ var codec = videoStream.Codec;
+ if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase))
+ {
+ // Limited to HEVC for now since the filter doesn't accept master data from VP9.
+ return IsColorDepth10(state)
+ && string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
+ && _mediaEncoder.SupportsHwaccel("vaapi")
+ && options.EnableVppTonemapping
+ && string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase);
+ }
+
+ // Hybrid VPP tonemapping for QSV with VAAPI
+ var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
+ if (isLinux && string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
+ {
+ // Limited to HEVC for now since the filter doesn't accept master data from VP9.
+ return IsColorDepth10(state)
+ && string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
+ && _mediaEncoder.SupportsHwaccel("vaapi")
+ && _mediaEncoder.SupportsHwaccel("qsv")
+ && options.EnableVppTonemapping
+ && string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase);
+ }
+
+ // Native VPP tonemapping may come to QSV in the future.
+ return false;
}
/// <summary>
@@ -270,6 +305,12 @@ namespace MediaBrowser.Controller.MediaEncoding
return null;
}
+ // ISO files don't have an ffmpeg format
+ if (string.Equals(container, "iso", StringComparison.OrdinalIgnoreCase))
+ {
+ return null;
+ }
+
return container;
}
@@ -458,11 +499,13 @@ namespace MediaBrowser.Controller.MediaEncoding
var isVaapiEncoder = outputVideoCodec.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1;
var isQsvDecoder = videoDecoder.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1;
var isQsvEncoder = outputVideoCodec.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1;
- var isNvdecHevcDecoder = videoDecoder.IndexOf("hevc_cuvid", StringComparison.OrdinalIgnoreCase) != -1;
+ var isNvdecDecoder = videoDecoder.Contains("cuda", StringComparison.OrdinalIgnoreCase);
+ var isCuvidHevcDecoder = videoDecoder.Contains("hevc_cuvid", StringComparison.OrdinalIgnoreCase);
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
var isMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
var isTonemappingSupported = IsTonemappingSupported(state, encodingOptions);
+ var isVppTonemappingSupported = IsVppTonemappingSupported(state, encodingOptions);
if (!IsCopyCodec(outputVideoCodec))
{
@@ -472,7 +515,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if (isVaapiDecoder)
{
- if (isTonemappingSupported)
+ if (isTonemappingSupported && !isVppTonemappingSupported)
{
arg.Append("-init_hw_device vaapi=va:")
.Append(encodingOptions.VaapiDevice)
@@ -496,6 +539,8 @@ namespace MediaBrowser.Controller.MediaEncoding
.Append(encodingOptions.VaapiDevice)
.Append(' ');
}
+
+ arg.Append("-autorotate 0 ");
}
if (state.IsVideoRequest
@@ -526,16 +571,37 @@ namespace MediaBrowser.Controller.MediaEncoding
}
// While using SW decoder
- else
+ else if (isSwDecoder)
{
arg.Append("-init_hw_device qsv=hw -filter_hw_device hw ");
}
+
+ // Hybrid VPP tonemapping with VAAPI
+ else if (isVaapiDecoder && isVppTonemappingSupported)
+ {
+ arg.Append("-init_hw_device vaapi=va:")
+ .Append(encodingOptions.VaapiDevice)
+ .Append(' ')
+ .Append("-init_hw_device qsv@va ")
+ .Append("-hwaccel_output_format vaapi ");
+ }
+
+ arg.Append("-autorotate 0 ");
}
}
if (state.IsVideoRequest
- && (string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && isNvdecHevcDecoder || isSwDecoder)
- || (string.Equals(encodingOptions.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) && isD3d11vaDecoder || isSwDecoder))
+ && string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase)
+ && isNvdecDecoder)
+ {
+ arg.Append("-hwaccel_output_format cuda -autorotate 0 ");
+ }
+
+ if (state.IsVideoRequest
+ && ((string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase)
+ && (isNvdecDecoder || isCuvidHevcDecoder || isSwDecoder))
+ || (string.Equals(encodingOptions.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase)
+ && (isD3d11vaDecoder || isSwDecoder))))
{
if (isTonemappingSupported)
{
@@ -922,18 +988,23 @@ namespace MediaBrowser.Controller.MediaEncoding
{
var videoStream = state.VideoStream;
var isColorDepth10 = IsColorDepth10(state);
+ var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions) ?? string.Empty;
+ var isNvdecDecoder = videoDecoder.Contains("cuda", StringComparison.OrdinalIgnoreCase);
- if (isColorDepth10
- && _mediaEncoder.SupportsHwaccel("opencl")
- && encodingOptions.EnableTonemapping
- && !string.IsNullOrEmpty(videoStream.VideoRange)
- && videoStream.VideoRange.Contains("HDR", StringComparison.OrdinalIgnoreCase))
- {
- param += " -pix_fmt nv12";
- }
- else
+ if (!isNvdecDecoder)
{
- param += " -pix_fmt yuv420p";
+ if (isColorDepth10
+ && _mediaEncoder.SupportsHwaccel("opencl")
+ && encodingOptions.EnableTonemapping
+ && !string.IsNullOrEmpty(videoStream.VideoRange)
+ && videoStream.VideoRange.Contains("HDR", StringComparison.OrdinalIgnoreCase))
+ {
+ param += " -pix_fmt nv12";
+ }
+ else
+ {
+ param += " -pix_fmt yuv420p";
+ }
}
}
@@ -1318,7 +1389,8 @@ namespace MediaBrowser.Controller.MediaEncoding
var requestedProfile = requestedProfiles[0];
// strip spaces because they may be stripped out on the query string as well
- if (!string.IsNullOrEmpty(videoStream.Profile) && !requestedProfiles.Contains(videoStream.Profile.Replace(" ", ""), StringComparer.OrdinalIgnoreCase))
+ if (!string.IsNullOrEmpty(videoStream.Profile)
+ && !requestedProfiles.Contains(videoStream.Profile.Replace(" ", "", StringComparison.Ordinal), StringComparer.OrdinalIgnoreCase))
{
var currentScore = GetVideoProfileScore(videoStream.Profile);
var requestedScore = GetVideoProfileScore(requestedProfile);
@@ -1647,7 +1719,7 @@ namespace MediaBrowser.Controller.MediaEncoding
if (filters.Count > 0)
{
- return " -af \"" + string.Join(",", filters) + "\"";
+ return " -af \"" + string.Join(',', filters) + "\"";
}
return string.Empty;
@@ -1912,12 +1984,18 @@ namespace MediaBrowser.Controller.MediaEncoding
var isVaapiDecoder = videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1;
var isVaapiH264Encoder = outputVideoCodec.IndexOf("h264_vaapi", StringComparison.OrdinalIgnoreCase) != -1;
var isVaapiHevcEncoder = outputVideoCodec.IndexOf("hevc_vaapi", StringComparison.OrdinalIgnoreCase) != -1;
+ var isQsvH264Encoder = outputVideoCodec.Contains("h264_qsv", StringComparison.OrdinalIgnoreCase);
+ var isQsvHevcEncoder = outputVideoCodec.Contains("hevc_qsv", StringComparison.OrdinalIgnoreCase);
+ var isNvdecDecoder = videoDecoder.Contains("cuda", StringComparison.OrdinalIgnoreCase);
+ var isNvencEncoder = outputVideoCodec.Contains("nvenc", StringComparison.OrdinalIgnoreCase);
var isTonemappingSupported = IsTonemappingSupported(state, options);
+ var isVppTonemappingSupported = IsVppTonemappingSupported(state, options);
var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder);
+ var isTonemappingSupportedOnQsv = string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isQsvH264Encoder || isQsvHevcEncoder);
// Tonemapping and burn-in graphical subtitles requires overlay_vaapi.
// But it's still in ffmpeg mailing list. Disable it for now.
- if (isTonemappingSupported && isTonemappingSupportedOnVaapi)
+ if (isTonemappingSupportedOnVaapi && isTonemappingSupported && !isVppTonemappingSupported)
{
return GetOutputSizeParam(state, options, outputVideoCodec);
}
@@ -1940,11 +2018,15 @@ namespace MediaBrowser.Controller.MediaEncoding
height.Value);
}
- // For QSV, feed it into hardware encoder now
- if (isLinux && (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)
- || string.Equals(outputVideoCodec, "hevc_qsv", StringComparison.OrdinalIgnoreCase)))
+ if (!string.IsNullOrEmpty(videoSizeParam)
+ && !(isTonemappingSupportedOnQsv && isVppTonemappingSupported))
{
- videoSizeParam += ",hwupload=extra_hw_frames=64";
+ // For QSV, feed it into hardware encoder now
+ if (isLinux && (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(outputVideoCodec, "hevc_qsv", StringComparison.OrdinalIgnoreCase)))
+ {
+ videoSizeParam += ",hwupload=extra_hw_frames=64";
+ }
}
}
@@ -1971,7 +2053,9 @@ namespace MediaBrowser.Controller.MediaEncoding
[sub]: SW scaling subtitle to FixedOutputSize
[base][sub]: SW overlay
*/
- retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3},hwdownload[base];[base][sub]overlay,format=nv12,hwupload\"";
+ retStr = !outputSizeParam.IsEmpty
+ ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3},hwdownload[base];[base][sub]overlay,format=nv12,hwupload\""
+ : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]hwdownload[base];[base][sub]overlay,format=nv12,hwupload\"";
}
// If we're hardware VAAPI decoding and software encoding, download frames from the decoder first
@@ -1984,7 +2068,9 @@ namespace MediaBrowser.Controller.MediaEncoding
[sub]: SW scaling subtitle to FixedOutputSize
[base][sub]: SW overlay
*/
- retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay\"";
+ retStr = !outputSizeParam.IsEmpty
+ ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay\""
+ : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay\"";
}
else if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)
|| string.Equals(outputVideoCodec, "hevc_qsv", StringComparison.OrdinalIgnoreCase))
@@ -1995,13 +2081,23 @@ namespace MediaBrowser.Controller.MediaEncoding
with fixed frame size.
Currently only supports linux.
*/
- if (isLinux)
+ if (isTonemappingSupportedOnQsv && isVppTonemappingSupported)
+ {
+ retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3},hwdownload,format=nv12[base];[base][sub]overlay\"";
+ }
+ else if (isLinux)
{
retStr = !outputSizeParam.IsEmpty
? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay_qsv\""
: " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay_qsv\"";
}
}
+ else if (isNvdecDecoder && isNvencEncoder)
+ {
+ retStr = !outputSizeParam.IsEmpty
+ ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay,format=nv12|yuv420p,hwupload_cuda\""
+ : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay,format=nv12|yuv420p,hwupload_cuda\"";
+ }
return string.Format(
CultureInfo.InvariantCulture,
@@ -2092,17 +2188,28 @@ namespace MediaBrowser.Controller.MediaEncoding
|| state.DeInterlace("h265", true)
|| state.DeInterlace("hevc", true);
+ var isVaapiDecoder = videoDecoder.Contains("vaapi", StringComparison.OrdinalIgnoreCase);
+ var isVaapiH264Encoder = videoEncoder.Contains("h264_vaapi", StringComparison.OrdinalIgnoreCase);
+ var isVaapiHevcEncoder = videoEncoder.Contains("hevc_vaapi", StringComparison.OrdinalIgnoreCase);
+ var isQsvH264Encoder = videoEncoder.Contains("h264_qsv", StringComparison.OrdinalIgnoreCase);
+ var isQsvHevcEncoder = videoEncoder.Contains("hevc_qsv", StringComparison.OrdinalIgnoreCase);
var isTonemappingSupported = IsTonemappingSupported(state, options);
- var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && !qsv_or_vaapi;
+ var isVppTonemappingSupported = IsVppTonemappingSupported(state, options);
+ var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)&& isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder);
+ var isTonemappingSupportedOnQsv = string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isQsvH264Encoder || isQsvHevcEncoder);
+ var isP010PixFmtRequired = (isTonemappingSupportedOnVaapi && (isTonemappingSupported || isVppTonemappingSupported))
+ || (isTonemappingSupportedOnQsv && isVppTonemappingSupported);
- var outputPixFmt = string.Empty;
- if (isTonemappingSupported && isTonemappingSupportedOnVaapi)
+
+ var outputPixFmt = "format=nv12";
+ if (isP010PixFmtRequired)
{
- outputPixFmt = "format=p010:out_range=limited";
+ outputPixFmt = "format=p010";
}
- else
+
+ if (isTonemappingSupportedOnQsv && isVppTonemappingSupported)
{
- outputPixFmt = "format=nv12";
+ qsv_or_vaapi = false;
}
if (!videoWidth.HasValue
@@ -2122,7 +2229,9 @@ namespace MediaBrowser.Controller.MediaEncoding
":" + outputPixFmt,
(qsv_or_vaapi && isDeintEnabled) ? ":deinterlace=1" : string.Empty));
}
- else
+
+ // Assert 10-bit is P010 so as we can avoid the extra scaler to get a bit more fps on high res HDR videos.
+ else if (!isP010PixFmtRequired)
{
filters.Add(
string.Format(
@@ -2133,6 +2242,49 @@ namespace MediaBrowser.Controller.MediaEncoding
(qsv_or_vaapi && isDeintEnabled) ? ":deinterlace=1" : string.Empty));
}
}
+ else if ((videoDecoder ?? string.Empty).Contains("cuda", StringComparison.OrdinalIgnoreCase)
+ && width.HasValue
+ && height.HasValue)
+ {
+ var outputWidth = width.Value;
+ var outputHeight = height.Value;
+
+ var isTonemappingSupported = IsTonemappingSupported(state, options);
+ var isTonemappingSupportedOnNvenc = string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase);
+ var isCudaFormatConversionSupported = _mediaEncoder.SupportsFilter("scale_cuda", "Output format (default \"same\")");
+
+ var outputPixFmt = string.Empty;
+ if (isCudaFormatConversionSupported)
+ {
+ outputPixFmt = "format=nv12";
+ if (isTonemappingSupported && isTonemappingSupportedOnNvenc)
+ {
+ outputPixFmt = "format=p010";
+ }
+ }
+
+ if (!videoWidth.HasValue
+ || outputWidth != videoWidth.Value
+ || !videoHeight.HasValue
+ || outputHeight != videoHeight.Value)
+ {
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "scale_cuda=w={0}:h={1}{2}",
+ outputWidth,
+ outputHeight,
+ isCudaFormatConversionSupported ? (":" + outputPixFmt) : string.Empty));
+ }
+ else if (isCudaFormatConversionSupported)
+ {
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "scale_cuda={0}",
+ outputPixFmt));
+ }
+ }
else if ((videoDecoder ?? string.Empty).IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1
&& width.HasValue
&& height.HasValue)
@@ -2367,28 +2519,36 @@ namespace MediaBrowser.Controller.MediaEncoding
var isVaapiHevcEncoder = outputVideoCodec.IndexOf("hevc_vaapi", StringComparison.OrdinalIgnoreCase) != -1;
var isQsvH264Encoder = outputVideoCodec.IndexOf("h264_qsv", StringComparison.OrdinalIgnoreCase) != -1;
var isQsvHevcEncoder = outputVideoCodec.IndexOf("hevc_qsv", StringComparison.OrdinalIgnoreCase) != -1;
- var isNvdecH264Decoder = videoDecoder.IndexOf("h264_cuvid", StringComparison.OrdinalIgnoreCase) != -1;
- var isNvdecHevcDecoder = videoDecoder.IndexOf("hevc_cuvid", StringComparison.OrdinalIgnoreCase) != -1;
+ var isNvdecDecoder = videoDecoder.Contains("cuda", StringComparison.OrdinalIgnoreCase);
+ var isNvencEncoder = outputVideoCodec.Contains("nvenc", StringComparison.OrdinalIgnoreCase);
+ var isCuvidH264Decoder = videoDecoder.Contains("h264_cuvid", StringComparison.OrdinalIgnoreCase);
+ var isCuvidHevcDecoder = videoDecoder.Contains("hevc_cuvid", StringComparison.OrdinalIgnoreCase);
var isLibX264Encoder = outputVideoCodec.IndexOf("libx264", StringComparison.OrdinalIgnoreCase) != -1;
var isLibX265Encoder = outputVideoCodec.IndexOf("libx265", StringComparison.OrdinalIgnoreCase) != -1;
var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
var isColorDepth10 = IsColorDepth10(state);
var isTonemappingSupported = IsTonemappingSupported(state, options);
- var isTonemappingSupportedOnNvenc = string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && isNvdecHevcDecoder || isSwDecoder;
- var isTonemappingSupportedOnAmf = string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) && isD3d11vaDecoder || isSwDecoder;
+ var isVppTonemappingSupported = IsVppTonemappingSupported(state, options);
+ var isTonemappingSupportedOnNvenc = string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && (isNvdecDecoder || isCuvidHevcDecoder || isSwDecoder);
+ var isTonemappingSupportedOnAmf = string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) && (isD3d11vaDecoder || isSwDecoder);
var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder);
+ var isTonemappingSupportedOnQsv = string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isQsvH264Encoder || isQsvHevcEncoder);
+ var hasSubs = state.SubtitleStream != null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
// If double rate deinterlacing is enabled and the input framerate is 30fps or below, otherwise the output framerate will be too high for many devices
- var doubleRateDeinterlace = options.DeinterlaceDoubleRate && (videoStream?.RealFrameRate ?? 60) <= 30;
+ var doubleRateDeinterlace = options.DeinterlaceDoubleRate && (videoStream?.AverageFrameRate ?? 60) <= 30;
var isScalingInAdvance = false;
+ var isCudaDeintInAdvance = false;
+ var isHwuploadCudaRequired = false;
var isDeinterlaceH264 = state.DeInterlace("h264", true) || state.DeInterlace("avc", true);
var isDeinterlaceHevc = state.DeInterlace("h265", true) || state.DeInterlace("hevc", true);
- if (isTonemappingSupportedOnNvenc || isTonemappingSupportedOnAmf || isTonemappingSupportedOnVaapi)
+ // Add OpenCL tonemapping filter for NVENC/AMF/VAAPI.
+ if (isTonemappingSupportedOnNvenc || isTonemappingSupportedOnAmf || (isTonemappingSupportedOnVaapi && !isVppTonemappingSupported))
{
// Currently only with the use of NVENC decoder can we get a decent performance.
// Currently only the HEVC/H265 format is supported with NVDEC decoder.
@@ -2428,15 +2588,17 @@ namespace MediaBrowser.Controller.MediaEncoding
filters.Add("format=p010");
}
- if (isNvdecHevcDecoder || isSwDecoder || isD3d11vaDecoder)
+ if ((isDeinterlaceH264 || isDeinterlaceHevc) && isNvdecDecoder)
{
- // Upload the HDR10 or HLG data to the OpenCL device,
- // use tonemap_opencl filter for tone mapping,
- // and then download the SDR data to memory.
- filters.Add("hwupload");
+ isCudaDeintInAdvance = true;
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "yadif_cuda={0}:-1:0",
+ doubleRateDeinterlace ? "1" : "0"));
}
- if (isVaapiDecoder)
+ if (isVaapiDecoder || isNvdecDecoder)
{
isScalingInAdvance = true;
filters.AddRange(
@@ -2452,11 +2614,28 @@ namespace MediaBrowser.Controller.MediaEncoding
request.Height,
request.MaxWidth,
request.MaxHeight));
+ }
- // hwmap the HDR data to opencl device by cl-va p010 interop.
+ // hwmap the HDR data to opencl device by cl-va p010 interop.
+ if (isVaapiDecoder)
+ {
filters.Add("hwmap");
}
+ // convert cuda device data to p010 host data.
+ if (isNvdecDecoder)
+ {
+ filters.Add("hwdownload,format=p010");
+ }
+
+ if (isNvdecDecoder || isCuvidHevcDecoder || isSwDecoder || isD3d11vaDecoder)
+ {
+ // Upload the HDR10 or HLG data to the OpenCL device,
+ // use tonemap_opencl filter for tone mapping,
+ // and then download the SDR data to memory.
+ filters.Add("hwupload");
+ }
+
filters.Add(
string.Format(
CultureInfo.InvariantCulture,
@@ -2468,21 +2647,15 @@ namespace MediaBrowser.Controller.MediaEncoding
options.TonemappingParam,
options.TonemappingRange));
- if (isNvdecHevcDecoder || isSwDecoder || isD3d11vaDecoder)
+ if (isNvdecDecoder || isCuvidHevcDecoder || isSwDecoder || isD3d11vaDecoder)
{
filters.Add("hwdownload");
+ filters.Add("format=nv12");
}
- if (isSwDecoder || isD3d11vaDecoder)
+ if (isNvdecDecoder && isNvencEncoder)
{
- if (isLibX264Encoder
- || isLibX265Encoder
- || hasGraphicalSubs
- || (isNvdecHevcDecoder && isDeinterlaceHevc)
- || (!isNvdecHevcDecoder && isDeinterlaceH264 || isDeinterlaceHevc))
- {
- filters.Add("format=nv12");
- }
+ isHwuploadCudaRequired = true;
}
if (isVaapiDecoder)
@@ -2494,22 +2667,25 @@ namespace MediaBrowser.Controller.MediaEncoding
}
// When the input may or may not be hardware VAAPI decodable.
- if ((isVaapiH264Encoder || isVaapiHevcEncoder) && !isTonemappingSupported && !isTonemappingSupportedOnVaapi)
+ if ((isVaapiH264Encoder || isVaapiHevcEncoder)
+ && !(isTonemappingSupportedOnVaapi && (isTonemappingSupported || isVppTonemappingSupported)))
{
filters.Add("format=nv12|vaapi");
filters.Add("hwupload");
}
// When burning in graphical subtitles using overlay_qsv, upload videostream to the same qsv context.
- else if (isLinux && hasGraphicalSubs && (isQsvH264Encoder || isQsvHevcEncoder))
+ else if (isLinux && hasGraphicalSubs && (isQsvH264Encoder || isQsvHevcEncoder)
+ && !(isTonemappingSupportedOnQsv && isVppTonemappingSupported))
{
filters.Add("hwupload=extra_hw_frames=64");
}
// If we're hardware VAAPI decoding and software encoding, download frames from the decoder first.
- else if (IsVaapiSupported(state) && isVaapiDecoder && (isLibX264Encoder || isLibX265Encoder))
+ else if ((IsVaapiSupported(state) && isVaapiDecoder) && (isLibX264Encoder || isLibX265Encoder)
+ && !(isTonemappingSupportedOnQsv && isVppTonemappingSupported))
{
- var codec = videoStream.Codec.ToLowerInvariant();
+ var codec = videoStream.Codec;
// Assert 10-bit hardware VAAPI decodable
if (isColorDepth10 && (string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
@@ -2534,9 +2710,10 @@ namespace MediaBrowser.Controller.MediaEncoding
}
// Add hardware deinterlace filter before scaling filter.
- if (isDeinterlaceH264)
+ if (isDeinterlaceH264 || isDeinterlaceHevc)
{
- if (isVaapiH264Encoder)
+ if (isVaapiEncoder
+ || (isTonemappingSupportedOnQsv && isVppTonemappingSupported))
{
filters.Add(
string.Format(
@@ -2544,6 +2721,14 @@ namespace MediaBrowser.Controller.MediaEncoding
"deinterlace_vaapi=rate={0}",
doubleRateDeinterlace ? "field" : "frame"));
}
+ else if (isNvdecDecoder && !isCudaDeintInAdvance)
+ {
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "yadif_cuda={0}:-1:0",
+ doubleRateDeinterlace ? "1" : "0"));
+ }
}
// Add software deinterlace filter before scaling filter.
@@ -2552,7 +2737,8 @@ namespace MediaBrowser.Controller.MediaEncoding
&& !isVaapiHevcEncoder
&& !isQsvH264Encoder
&& !isQsvHevcEncoder
- && !isNvdecH264Decoder)
+ && !isNvdecDecoder
+ && !isCuvidH264Decoder)
{
if (string.Equals(options.DeinterlaceMethod, "bwdif", StringComparison.OrdinalIgnoreCase))
{
@@ -2590,14 +2776,76 @@ namespace MediaBrowser.Controller.MediaEncoding
request.MaxHeight));
}
+ // Add VPP tonemapping filter for VAAPI.
+ // Full hardware based video post processing, faster than OpenCL but lacks fine tuning options.
+ if ((isTonemappingSupportedOnVaapi || isTonemappingSupportedOnQsv)
+ && isVppTonemappingSupported)
+ {
+ filters.Add("tonemap_vaapi=format=nv12:transfer=bt709:matrix=bt709:primaries=bt709");
+ }
+
+ // Another case is when using Nvenc decoder.
+ if (isNvdecDecoder && !isTonemappingSupported)
+ {
+ var codec = videoStream.Codec;
+ var isCudaFormatConversionSupported = _mediaEncoder.SupportsFilter("scale_cuda", "Output format (default \"same\")");
+
+ // Assert 10-bit hardware decodable
+ if (isColorDepth10 && (string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(codec, "vp9", StringComparison.OrdinalIgnoreCase)))
+ {
+ if (isCudaFormatConversionSupported)
+ {
+ if (isLibX264Encoder || isLibX265Encoder || hasSubs)
+ {
+ if (isNvencEncoder)
+ {
+ isHwuploadCudaRequired = true;
+ }
+
+ filters.Add("hwdownload");
+ filters.Add("format=nv12");
+ }
+ }
+ else
+ {
+ // Download data from GPU to CPU as p010 format.
+ filters.Add("hwdownload");
+ filters.Add("format=p010");
+
+ // Cuda lacks of a pixel format converter.
+ if (isNvencEncoder)
+ {
+ isHwuploadCudaRequired = true;
+ filters.Add("format=yuv420p");
+ }
+ }
+ }
+
+ // Assert 8-bit hardware decodable
+ else if (!isColorDepth10 && (isLibX264Encoder || isLibX265Encoder || hasSubs))
+ {
+ if (isNvencEncoder)
+ {
+ isHwuploadCudaRequired = true;
+ }
+
+ filters.Add("hwdownload");
+ filters.Add("format=nv12");
+ }
+ }
+
// Add parameters to use VAAPI with burn-in text subtitles (GH issue #642)
- if (isVaapiH264Encoder || isVaapiHevcEncoder)
+ if (isVaapiH264Encoder
+ || isVaapiHevcEncoder
+ || (isTonemappingSupportedOnQsv && isVppTonemappingSupported))
{
if (hasTextSubs)
{
// Convert hw context from ocl to va.
// For tonemapping and text subs burn-in.
- if (isTonemappingSupported && isTonemappingSupportedOnVaapi)
+ if (isTonemappingSupportedOnVaapi && isTonemappingSupported && !isVppTonemappingSupported)
{
filters.Add("scale_vaapi");
}
@@ -2608,8 +2856,6 @@ namespace MediaBrowser.Controller.MediaEncoding
}
}
- var output = string.Empty;
-
if (hasTextSubs)
{
var subParam = GetTextSubtitleParam(state);
@@ -2618,18 +2864,40 @@ namespace MediaBrowser.Controller.MediaEncoding
// Ensure proper filters are passed to ffmpeg in case of hardware acceleration via VA-API
// Reference: https://trac.ffmpeg.org/wiki/Hardware/VAAPI
- if (isVaapiH264Encoder)
+ if (isVaapiH264Encoder || isVaapiHevcEncoder)
{
filters.Add("hwmap");
}
+
+ if (isTonemappingSupportedOnQsv && isVppTonemappingSupported)
+ {
+ filters.Add("hwmap,format=vaapi");
+ }
+
+ if (isNvdecDecoder && isNvencEncoder)
+ {
+ isHwuploadCudaRequired = true;
+ }
}
+ // Interop the VAAPI data to QSV for hybrid tonemapping
+ if (isTonemappingSupportedOnQsv && isVppTonemappingSupported && !hasGraphicalSubs)
+ {
+ filters.Add("hwmap=derive_device=qsv,scale_qsv");
+ }
+
+ if (isHwuploadCudaRequired && !hasGraphicalSubs)
+ {
+ filters.Add("hwupload_cuda");
+ }
+
+ var output = string.Empty;
if (filters.Count > 0)
{
output += string.Format(
CultureInfo.InvariantCulture,
"{0}",
- string.Join(",", filters));
+ string.Join(',', filters));
}
return output;
@@ -2655,7 +2923,7 @@ namespace MediaBrowser.Controller.MediaEncoding
if (threads <= 0)
{
return 0;
- }
+ }
else if (threads >= Environment.ProcessorCount)
{
return Environment.ProcessorCount;
@@ -2821,7 +3089,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
inputModifier += " -deint 1";
- if (!encodingOptions.DeinterlaceDoubleRate || (videoStream?.RealFrameRate ?? 60) > 30)
+ if (!encodingOptions.DeinterlaceDoubleRate || (videoStream?.AverageFrameRate ?? 60) > 30)
{
inputModifier += " -drop_second_field 1";
}
@@ -3096,63 +3364,32 @@ namespace MediaBrowser.Controller.MediaEncoding
return null;
}
+ // Hybrid VPP tonemapping with VAAPI
+ if (string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)
+ && IsVppTonemappingSupported(state, encodingOptions))
+ {
+ // Since tonemap_vaapi only support HEVC for now, no need to check the codec again.
+ return GetHwaccelType(state, encodingOptions, "hevc", isColorDepth10);
+ }
+
if (string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
{
switch (videoStream.Codec.ToLowerInvariant())
{
case "avc":
case "h264":
- if (_mediaEncoder.SupportsDecoder("h264_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase))
- {
- // qsv decoder does not support 10-bit input
- if ((videoStream.BitDepth ?? 8) > 8)
- {
- encodingOptions.HardwareDecodingCodecs = Array.Empty<string>();
- return null;
- }
-
- return "-c:v h264_qsv";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "h264_qsv", "h264", isColorDepth10);
case "hevc":
case "h265":
- if (_mediaEncoder.SupportsDecoder("hevc_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase))
- {
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Hevc) ? null : "-c:v hevc_qsv";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "hevc_qsv", "hevc", isColorDepth10);
case "mpeg2video":
- if (_mediaEncoder.SupportsDecoder("mpeg2_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg2video", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v mpeg2_qsv";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "mpeg2_qsv", "mpeg2video", isColorDepth10);
case "vc1":
- if (_mediaEncoder.SupportsDecoder("vc1_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v vc1_qsv";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "vc1_qsv", "vc1", isColorDepth10);
case "vp8":
- if (_mediaEncoder.SupportsDecoder("vp8_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("vp8", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v vp8_qsv";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "vp8_qsv", "vp8", isColorDepth10);
case "vp9":
- if (_mediaEncoder.SupportsDecoder("vp9_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase))
- {
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Vp9) ? null : "-c:v vp9_qsv";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "vp9_qsv", "vp9", isColorDepth10);
}
}
else if (string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase))
@@ -3161,57 +3398,34 @@ namespace MediaBrowser.Controller.MediaEncoding
{
case "avc":
case "h264":
- if (_mediaEncoder.SupportsDecoder("h264_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v h264_cuvid";
- }
-
- break;
+ return encodingOptions.EnableEnhancedNvdecDecoder && IsCudaSupported()
+ ? GetHwaccelType(state, encodingOptions, "h264", isColorDepth10)
+ : GetHwDecoderName(encodingOptions, "h264_cuvid", "h264", isColorDepth10);
case "hevc":
case "h265":
- if (_mediaEncoder.SupportsDecoder("hevc_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase))
- {
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Hevc) ? null : "-c:v hevc_cuvid";
- }
-
- break;
+ return encodingOptions.EnableEnhancedNvdecDecoder && IsCudaSupported()
+ ? GetHwaccelType(state, encodingOptions, "hevc", isColorDepth10)
+ : GetHwDecoderName(encodingOptions, "hevc_cuvid", "hevc", isColorDepth10);
case "mpeg2video":
- if (_mediaEncoder.SupportsDecoder("mpeg2_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg2video", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v mpeg2_cuvid";
- }
-
- break;
+ return encodingOptions.EnableEnhancedNvdecDecoder && IsCudaSupported()
+ ? GetHwaccelType(state, encodingOptions, "mpeg2video", isColorDepth10)
+ : GetHwDecoderName(encodingOptions, "mpeg2_cuvid", "mpeg2video", isColorDepth10);
case "vc1":
- if (_mediaEncoder.SupportsDecoder("vc1_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v vc1_cuvid";
- }
-
- break;
+ return encodingOptions.EnableEnhancedNvdecDecoder && IsCudaSupported()
+ ? GetHwaccelType(state, encodingOptions, "vc1", isColorDepth10)
+ : GetHwDecoderName(encodingOptions, "vc1_cuvid", "vc1", isColorDepth10);
case "mpeg4":
- if (_mediaEncoder.SupportsDecoder("mpeg4_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg4", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v mpeg4_cuvid";
- }
-
- break;
+ return encodingOptions.EnableEnhancedNvdecDecoder && IsCudaSupported()
+ ? GetHwaccelType(state, encodingOptions, "mpeg4", isColorDepth10)
+ : GetHwDecoderName(encodingOptions, "mpeg4_cuvid", "mpeg4", isColorDepth10);
case "vp8":
- if (_mediaEncoder.SupportsDecoder("vp8_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("vp8", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v vp8_cuvid";
- }
-
- break;
+ return encodingOptions.EnableEnhancedNvdecDecoder && IsCudaSupported()
+ ? GetHwaccelType(state, encodingOptions, "vp8", isColorDepth10)
+ : GetHwDecoderName(encodingOptions, "vp8_cuvid", "vp8", isColorDepth10);
case "vp9":
- if (_mediaEncoder.SupportsDecoder("vp9_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase))
- {
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Vp9) ? null : "-c:v vp9_cuvid";
- }
-
- break;
+ return encodingOptions.EnableEnhancedNvdecDecoder && IsCudaSupported()
+ ? GetHwaccelType(state, encodingOptions, "vp9", isColorDepth10)
+ : GetHwDecoderName(encodingOptions, "vp9_cuvid", "vp9", isColorDepth10);
}
}
else if (string.Equals(encodingOptions.HardwareAccelerationType, "mediacodec", StringComparison.OrdinalIgnoreCase))
@@ -3220,50 +3434,18 @@ namespace MediaBrowser.Controller.MediaEncoding
{
case "avc":
case "h264":
- if (_mediaEncoder.SupportsDecoder("h264_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v h264_mediacodec";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "h264_mediacodec", "h264", isColorDepth10);
case "hevc":
case "h265":
- if (_mediaEncoder.SupportsDecoder("hevc_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase))
- {
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Hevc) ? null : "-c:v hevc_mediacodec";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "hevc_mediacodec", "hevc", isColorDepth10);
case "mpeg2video":
- if (_mediaEncoder.SupportsDecoder("mpeg2_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg2video", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v mpeg2_mediacodec";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "mpeg2_mediacodec", "mpeg2video", isColorDepth10);
case "mpeg4":
- if (_mediaEncoder.SupportsDecoder("mpeg4_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg4", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v mpeg4_mediacodec";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "mpeg4_mediacodec", "mpeg4", isColorDepth10);
case "vp8":
- if (_mediaEncoder.SupportsDecoder("vp8_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("vp8", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v vp8_mediacodec";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "vp8_mediacodec", "vp8", isColorDepth10);
case "vp9":
- if (_mediaEncoder.SupportsDecoder("vp9_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase))
- {
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Vp9) ? null : "-c:v vp9_mediacodec";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "vp9_mediacodec", "vp9", isColorDepth10);
}
}
else if (string.Equals(encodingOptions.HardwareAccelerationType, "omx", StringComparison.OrdinalIgnoreCase))
@@ -3272,33 +3454,13 @@ namespace MediaBrowser.Controller.MediaEncoding
{
case "avc":
case "h264":
- if (_mediaEncoder.SupportsDecoder("h264_mmal") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v h264_mmal";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "h264_mmal", "h264", isColorDepth10);
case "mpeg2video":
- if (_mediaEncoder.SupportsDecoder("mpeg2_mmal") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg2video", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v mpeg2_mmal";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "mpeg2_mmal", "mpeg2video", isColorDepth10);
case "mpeg4":
- if (_mediaEncoder.SupportsDecoder("mpeg4_mmal") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg4", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v mpeg4_mmal";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "mpeg4_mmal", "mpeg4", isColorDepth10);
case "vc1":
- if (_mediaEncoder.SupportsDecoder("vc1_mmal") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v vc1_mmal";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "vc1_mmal", "vc1", isColorDepth10);
}
}
else if (string.Equals(encodingOptions.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase))
@@ -3307,20 +3469,18 @@ namespace MediaBrowser.Controller.MediaEncoding
{
case "avc":
case "h264":
- return GetHwaccelType(state, encodingOptions, "h264");
+ return GetHwaccelType(state, encodingOptions, "h264", isColorDepth10);
case "hevc":
case "h265":
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Hevc) ? null : GetHwaccelType(state, encodingOptions, "hevc");
+ return GetHwaccelType(state, encodingOptions, "hevc", isColorDepth10);
case "mpeg2video":
- return GetHwaccelType(state, encodingOptions, "mpeg2video");
+ return GetHwaccelType(state, encodingOptions, "mpeg2video", isColorDepth10);
case "vc1":
- return GetHwaccelType(state, encodingOptions, "vc1");
+ return GetHwaccelType(state, encodingOptions, "vc1", isColorDepth10);
case "mpeg4":
- return GetHwaccelType(state, encodingOptions, "mpeg4");
+ return GetHwaccelType(state, encodingOptions, "mpeg4", isColorDepth10);
case "vp9":
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Vp9) ? null : GetHwaccelType(state, encodingOptions, "vp9");
+ return GetHwaccelType(state, encodingOptions, "vp9", isColorDepth10);
}
}
else if (string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase))
@@ -3329,20 +3489,18 @@ namespace MediaBrowser.Controller.MediaEncoding
{
case "avc":
case "h264":
- return GetHwaccelType(state, encodingOptions, "h264");
+ return GetHwaccelType(state, encodingOptions, "h264", isColorDepth10);
case "hevc":
case "h265":
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Hevc) ? null : GetHwaccelType(state, encodingOptions, "hevc");
+ return GetHwaccelType(state, encodingOptions, "hevc", isColorDepth10);
case "mpeg2video":
- return GetHwaccelType(state, encodingOptions, "mpeg2video");
+ return GetHwaccelType(state, encodingOptions, "mpeg2video", isColorDepth10);
case "vc1":
- return GetHwaccelType(state, encodingOptions, "vc1");
+ return GetHwaccelType(state, encodingOptions, "vc1", isColorDepth10);
case "vp8":
- return GetHwaccelType(state, encodingOptions, "vp8");
+ return GetHwaccelType(state, encodingOptions, "vp8", isColorDepth10);
case "vp9":
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Vp9) ? null : GetHwaccelType(state, encodingOptions, "vp9");
+ return GetHwaccelType(state, encodingOptions, "vp9", isColorDepth10);
}
}
else if (string.Equals(encodingOptions.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase))
@@ -3351,57 +3509,20 @@ namespace MediaBrowser.Controller.MediaEncoding
{
case "avc":
case "h264":
- if (_mediaEncoder.SupportsDecoder("h264_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v h264_opencl";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "h264_opencl", "h264", isColorDepth10);
case "hevc":
case "h265":
- if (_mediaEncoder.SupportsDecoder("hevc_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase))
- {
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Hevc) ? null : "-c:v hevc_opencl";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "hevc_opencl", "hevc", isColorDepth10);
case "mpeg2video":
- if (_mediaEncoder.SupportsDecoder("mpeg2_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg2video", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v mpeg2_opencl";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "mpeg2_opencl", "mpeg2video", isColorDepth10);
case "mpeg4":
- if (_mediaEncoder.SupportsDecoder("mpeg4_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg4", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v mpeg4_opencl";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "mpeg4_opencl", "mpeg4", isColorDepth10);
case "vc1":
- if (_mediaEncoder.SupportsDecoder("vc1_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v vc1_opencl";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "vc1_opencl", "vc1", isColorDepth10);
case "vp8":
- if (_mediaEncoder.SupportsDecoder("vp8_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase))
- {
- return "-c:v vp8_opencl";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "vp8_opencl", "vp8", isColorDepth10);
case "vp9":
- if (_mediaEncoder.SupportsDecoder("vp9_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase))
- {
- return (isColorDepth10 &&
- !encodingOptions.EnableDecodingColorDepth10Vp9) ? null : "-c:v vp9_opencl";
- }
-
- break;
+ return GetHwDecoderName(encodingOptions, "vp9_opencl", "vp9", isColorDepth10);
}
}
}
@@ -3425,14 +3546,42 @@ namespace MediaBrowser.Controller.MediaEncoding
}
/// <summary>
+ /// Gets a hw decoder name
+ /// </summary>
+ public string GetHwDecoderName(EncodingOptions options, string decoder, string videoCodec, bool isColorDepth10)
+ {
+ var isCodecAvailable = _mediaEncoder.SupportsDecoder(decoder) && options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase);
+ if (isColorDepth10 && isCodecAvailable)
+ {
+ if ((options.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase) && !options.EnableDecodingColorDepth10Hevc)
+ || (options.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase) && !options.EnableDecodingColorDepth10Vp9))
+ {
+ return null;
+ }
+ }
+
+ return isCodecAvailable ? ("-c:v " + decoder) : null;
+ }
+
+ /// <summary>
/// Gets a hwaccel type to use as a hardware decoder(dxva/vaapi) depending on the system
/// </summary>
- public string GetHwaccelType(EncodingJobInfo state, EncodingOptions options, string videoCodec)
+ public string GetHwaccelType(EncodingJobInfo state, EncodingOptions options, string videoCodec, bool isColorDepth10)
{
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
var isWindows8orLater = Environment.OSVersion.Version.Major > 6 || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor > 1);
var isDxvaSupported = _mediaEncoder.SupportsHwaccel("dxva2") || _mediaEncoder.SupportsHwaccel("d3d11va");
+ var isCodecAvailable = options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase);
+
+ if (isColorDepth10 && isCodecAvailable)
+ {
+ if ((options.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase) && !options.EnableDecodingColorDepth10Hevc)
+ || (options.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase) && !options.EnableDecodingColorDepth10Vp9))
+ {
+ return null;
+ }
+ }
if (string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase))
{
@@ -3451,7 +3600,9 @@ namespace MediaBrowser.Controller.MediaEncoding
}
}
- if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)
+ || (string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)
+ && IsVppTonemappingSupported(state, options)))
{
if (IsVaapiSupported(state) && options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase))
{
@@ -3462,6 +3613,14 @@ namespace MediaBrowser.Controller.MediaEncoding
}
}
+ if (string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase))
+ {
+ if (options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase))
+ {
+ return "-hwaccel cuda";
+ }
+ }
+
return null;
}
@@ -3714,7 +3873,7 @@ namespace MediaBrowser.Controller.MediaEncoding
GetInputArgument(state, encodingOptions),
threads,
" -vn",
- string.Join(" ", audioTranscodeParams),
+ string.Join(' ', audioTranscodeParams),
outputPath,
string.Empty,
string.Empty,
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
index dacd6dea6..d47a689f4 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
@@ -9,7 +9,6 @@ using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Session;
diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
index 34fe895cc..05dd1a69b 100644
--- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
+++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
@@ -7,7 +7,6 @@ using System.Threading.Tasks;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.System;
@@ -51,6 +50,14 @@ namespace MediaBrowser.Controller.MediaEncoding
bool SupportsHwaccel(string hwaccel);
/// <summary>
+ /// Whether given filter is supported.
+ /// </summary>
+ /// <param name="filter">The filter.</param>
+ /// <param name="option">The option.</param>
+ /// <returns><c>true</c> if the filter is supported, <c>false</c> otherwise.</returns>
+ bool SupportsFilter(string filter, string option);
+
+ /// <summary>
/// Extracts the audio image.
/// </summary>
/// <param name="path">The path.</param>
diff --git a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs
index cc8820f39..227c5f258 100644
--- a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs
+++ b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs
@@ -3,7 +3,6 @@
using System;
using System.Globalization;
using System.IO;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
diff --git a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
index 281d50372..89e01c08b 100644
--- a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
+++ b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
@@ -1,10 +1,5 @@
#pragma warning disable CS1591
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using MediaBrowser.Model.IO;
namespace MediaBrowser.Controller.MediaEncoding
{
diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs
index 45c6805f0..ed473c749 100644
--- a/MediaBrowser.Controller/Persistence/IItemRepository.cs
+++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs
@@ -153,8 +153,7 @@ namespace MediaBrowser.Controller.Persistence
/// <summary>
/// Updates the inherited values.
/// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- void UpdateInheritedValues(CancellationToken cancellationToken);
+ void UpdateInheritedValues();
int GetCount(InternalItemsQuery query);
diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs
index e8b7be7e2..c9c168c4c 100644
--- a/MediaBrowser.Controller/Playlists/Playlist.cs
+++ b/MediaBrowser.Controller/Playlists/Playlist.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
+using System.IO;
using System.Linq;
using System.Text.Json.Serialization;
using System.Threading;
@@ -13,7 +14,6 @@ using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Controller.Playlists
@@ -43,7 +43,8 @@ namespace MediaBrowser.Controller.Playlists
public static bool IsPlaylistFile(string path)
{
- return System.IO.Path.HasExtension(path);
+ // The path will sometimes be a directory and "Path.HasExtension" returns true if the name contains a '.' (dot).
+ return System.IO.Path.HasExtension(path) && !Directory.Exists(path);
}
[JsonIgnore]
@@ -162,7 +163,7 @@ namespace MediaBrowser.Controller.Playlists
Recursive = true,
IncludeItemTypes = new[] { nameof(Audio) },
GenreIds = new[] { musicGenre.Id },
- OrderBy = new[] { ItemSortBy.AlbumArtist, ItemSortBy.Album, ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray(),
+ OrderBy = new[] { (ItemSortBy.AlbumArtist, SortOrder.Ascending), (ItemSortBy.Album, SortOrder.Ascending), (ItemSortBy.SortName, SortOrder.Ascending) },
DtoOptions = options
});
}
@@ -174,7 +175,7 @@ namespace MediaBrowser.Controller.Playlists
Recursive = true,
IncludeItemTypes = new[] { nameof(Audio) },
ArtistIds = new[] { musicArtist.Id },
- OrderBy = new[] { ItemSortBy.AlbumArtist, ItemSortBy.Album, ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray(),
+ OrderBy = new[] { (ItemSortBy.AlbumArtist, SortOrder.Ascending), (ItemSortBy.Album, SortOrder.Ascending), (ItemSortBy.SortName, SortOrder.Ascending) },
DtoOptions = options
});
}
diff --git a/MediaBrowser.Controller/Plugins/IPluginConfigurationPage.cs b/MediaBrowser.Controller/Plugins/IPluginConfigurationPage.cs
deleted file mode 100644
index 93eab42cc..000000000
--- a/MediaBrowser.Controller/Plugins/IPluginConfigurationPage.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-using System.IO;
-using MediaBrowser.Common.Plugins;
-
-namespace MediaBrowser.Controller.Plugins
-{
- /// <summary>
- /// Interface IConfigurationPage.
- /// </summary>
- public interface IPluginConfigurationPage
- {
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- string Name { get; }
-
- /// <summary>
- /// Gets the type of the configuration page.
- /// </summary>
- /// <value>The type of the configuration page.</value>
- ConfigurationPageType ConfigurationPageType { get; }
-
- /// <summary>
- /// Gets the plugin.
- /// </summary>
- /// <value>The plugin.</value>
- IPlugin Plugin { get; }
-
- /// <summary>
- /// Gets the HTML stream.
- /// </summary>
- /// <returns>Stream.</returns>
- Stream GetHtmlStream();
- }
-
- /// <summary>
- /// Enum ConfigurationPageType.
- /// </summary>
- public enum ConfigurationPageType
- {
- /// <summary>
- /// The plugin configuration.
- /// </summary>
- PluginConfiguration,
-
- /// <summary>
- /// The none.
- /// </summary>
- None
- }
-}
diff --git a/MediaBrowser.Controller/Providers/DirectoryService.cs b/MediaBrowser.Controller/Providers/DirectoryService.cs
index 16fd1d42b..5c92069b4 100644
--- a/MediaBrowser.Controller/Providers/DirectoryService.cs
+++ b/MediaBrowser.Controller/Providers/DirectoryService.cs
@@ -12,11 +12,11 @@ namespace MediaBrowser.Controller.Providers
{
private readonly IFileSystem _fileSystem;
- private readonly ConcurrentDictionary<string, FileSystemMetadata[]> _cache = new ConcurrentDictionary<string, FileSystemMetadata[]>(StringComparer.OrdinalIgnoreCase);
+ private readonly ConcurrentDictionary<string, FileSystemMetadata[]> _cache = new (StringComparer.Ordinal);
- private readonly ConcurrentDictionary<string, FileSystemMetadata> _fileCache = new ConcurrentDictionary<string, FileSystemMetadata>(StringComparer.OrdinalIgnoreCase);
+ private readonly ConcurrentDictionary<string, FileSystemMetadata> _fileCache = new (StringComparer.Ordinal);
- private readonly ConcurrentDictionary<string, List<string>> _filePathCache = new ConcurrentDictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
+ private readonly ConcurrentDictionary<string, List<string>> _filePathCache = new (StringComparer.Ordinal);
public DirectoryService(IFileSystem fileSystem)
{
diff --git a/MediaBrowser.Controller/Providers/ILocalImageProvider.cs b/MediaBrowser.Controller/Providers/ILocalImageProvider.cs
index c129eddb3..f78bd6ddf 100644
--- a/MediaBrowser.Controller/Providers/ILocalImageProvider.cs
+++ b/MediaBrowser.Controller/Providers/ILocalImageProvider.cs
@@ -10,6 +10,6 @@ namespace MediaBrowser.Controller.Providers
/// </summary>
public interface ILocalImageProvider : IImageProvider
{
- List<LocalImageInfo> GetImages(BaseItem item, IDirectoryService directoryService);
+ IEnumerable<LocalImageInfo> GetImages(BaseItem item, IDirectoryService directoryService);
}
}
diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs
index 0a4967223..7bc56c82a 100644
--- a/MediaBrowser.Controller/Providers/IProviderManager.cs
+++ b/MediaBrowser.Controller/Providers/IProviderManager.cs
@@ -6,9 +6,7 @@ using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
-using Jellyfin.Data.Entities;
using Jellyfin.Data.Events;
-using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Configuration;
@@ -22,6 +20,12 @@ namespace MediaBrowser.Controller.Providers
/// </summary>
public interface IProviderManager
{
+ event EventHandler<GenericEventArgs<BaseItem>> RefreshStarted;
+
+ event EventHandler<GenericEventArgs<BaseItem>> RefreshCompleted;
+
+ event EventHandler<GenericEventArgs<Tuple<BaseItem, double>>> RefreshProgress;
+
/// <summary>
/// Queues the refresh.
/// </summary>
@@ -87,8 +91,11 @@ namespace MediaBrowser.Controller.Providers
/// <summary>
/// Adds the metadata providers.
/// </summary>
- void AddParts(IEnumerable<IImageProvider> imageProviders, IEnumerable<IMetadataService> metadataServices, IEnumerable<IMetadataProvider> metadataProviders,
- IEnumerable<IMetadataSaver> savers,
+ void AddParts(
+ IEnumerable<IImageProvider> imageProviders,
+ IEnumerable<IMetadataService> metadataServices,
+ IEnumerable<IMetadataProvider> metadataProviders,
+ IEnumerable<IMetadataSaver> metadataSavers,
IEnumerable<IExternalId> externalIds);
/// <summary>
@@ -132,12 +139,14 @@ namespace MediaBrowser.Controller.Providers
/// </summary>
/// <param name="item">The item.</param>
/// <param name="updateType">Type of the update.</param>
- /// <returns>Task.</returns>
void SaveMetadata(BaseItem item, ItemUpdateType updateType);
/// <summary>
/// Saves the metadata.
/// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="updateType">Type of the update.</param>
+ /// <param name="savers">The metadata savers.</param>
void SaveMetadata(BaseItem item, ItemUpdateType updateType, IEnumerable<string> savers);
/// <summary>
@@ -179,12 +188,6 @@ namespace MediaBrowser.Controller.Providers
void OnRefreshComplete(BaseItem item);
double? GetRefreshProgress(Guid id);
-
- event EventHandler<GenericEventArgs<BaseItem>> RefreshStarted;
-
- event EventHandler<GenericEventArgs<BaseItem>> RefreshCompleted;
-
- event EventHandler<GenericEventArgs<Tuple<BaseItem, double>>> RefreshProgress;
}
public enum RefreshPriority
diff --git a/MediaBrowser.Controller/Providers/IRemoteImageProvider.cs b/MediaBrowser.Controller/Providers/IRemoteImageProvider.cs
index ee8f5b860..de1631dcf 100644
--- a/MediaBrowser.Controller/Providers/IRemoteImageProvider.cs
+++ b/MediaBrowser.Controller/Providers/IRemoteImageProvider.cs
@@ -2,7 +2,6 @@ using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
diff --git a/MediaBrowser.Controller/Providers/IRemoteSearchProvider.cs b/MediaBrowser.Controller/Providers/IRemoteSearchProvider.cs
index 9592baa7c..e401ed211 100644
--- a/MediaBrowser.Controller/Providers/IRemoteSearchProvider.cs
+++ b/MediaBrowser.Controller/Providers/IRemoteSearchProvider.cs
@@ -3,7 +3,6 @@
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.Net;
namespace MediaBrowser.Controller.Providers
{
diff --git a/MediaBrowser.Controller/Providers/MetadataResult.cs b/MediaBrowser.Controller/Providers/MetadataResult.cs
index 1c695cafa..864cb3050 100644
--- a/MediaBrowser.Controller/Providers/MetadataResult.cs
+++ b/MediaBrowser.Controller/Providers/MetadataResult.cs
@@ -4,21 +4,25 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Providers
{
public class MetadataResult<T>
{
- public List<LocalImageInfo> Images { get; set; }
-
- public List<UserItemData> UserDataList { get; set; }
-
public MetadataResult()
{
Images = new List<LocalImageInfo>();
+ RemoteImages = new List<(string url, ImageType type)>();
ResultLanguage = "en";
}
+ public List<LocalImageInfo> Images { get; set; }
+
+ public List<(string url, ImageType type)> RemoteImages { get; set; }
+
+ public List<UserItemData> UserDataList { get; set; }
+
public List<PersonInfo> People { get; set; }
public bool HasMetadata { get; set; }
diff --git a/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs b/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs
index 67acdd9a3..25128a5cd 100644
--- a/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs
+++ b/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs
@@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Resolvers
/// </summary>
/// <param name="args">The args.</param>
/// <returns>`0.</returns>
- protected virtual T Resolve(ItemResolveArgs args)
+ public virtual T Resolve(ItemResolveArgs args)
{
return null;
}
diff --git a/MediaBrowser.Controller/Session/AuthenticationRequest.cs b/MediaBrowser.Controller/Session/AuthenticationRequest.cs
index cc321fd22..8c3ac58f2 100644
--- a/MediaBrowser.Controller/Session/AuthenticationRequest.cs
+++ b/MediaBrowser.Controller/Session/AuthenticationRequest.cs
@@ -12,6 +12,7 @@ namespace MediaBrowser.Controller.Session
public string Password { get; set; }
+ [Obsolete("Send full password in Password field")]
public string PasswordSha1 { get; set; }
public string App { get; set; }
diff --git a/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs b/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs
index feb26bc10..6d63286ef 100644
--- a/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs
+++ b/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs
@@ -2,7 +2,6 @@
using System;
using System.Collections.Generic;
-using System.IO;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Entities;