From 12ec0e285ddf8a5360859b5c49bb4b7b916569d2 Mon Sep 17 00:00:00 2001 From: "Negulici-R. Barnabas" Date: Mon, 18 Jul 2022 17:50:52 +0300 Subject: Chapter Images: - chapter image extraction intervals, limit count and resolutions can be set by the user from the server general settings; --- .../Configuration/ServerConfiguration.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'MediaBrowser.Model/Configuration') diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index e61b896b9d..c37c167eb6 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -240,5 +240,23 @@ namespace MediaBrowser.Model.Configuration /// Gets or sets a value indicating whether clients should be allowed to upload logs. /// public bool AllowClientLogUpload { get; set; } = true; + + /// + /// Gets or sets the dummy chapters duration in seconds. + /// + /// The dummy chapters duration. + public int DummyChapterDuration { get; set; } = 300; + + /// + /// Gets or sets the dummy chapter count. + /// + /// The dummy chapter count. + public int DummyChapterCount { get; set; } = 100; + + /// + /// Gets or sets the chapter image resolution. + /// + /// The chapter image resolution. + public string ChapterImageResolution { get; set; } = "Match Source"; } } -- cgit v1.2.3 From 7db1813cc8358ac7d4c7a78022553e1e3215679e Mon Sep 17 00:00:00 2001 From: "Negulici-R. Barnabas" Date: Sun, 13 Nov 2022 16:23:21 +0200 Subject: changed ChapterImageResolution in model to enum type; added 144p to the ImageResolution enum; updated chapters limit comment inside FFProbeVideoInfo.cs; --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 51 ++++++++++++---------- .../Configuration/ServerConfiguration.cs | 3 +- MediaBrowser.Model/Drawing/ImageResolution.cs | 10 +++++ .../MediaInfo/FFProbeVideoInfo.cs | 2 +- 4 files changed, 40 insertions(+), 26 deletions(-) (limited to 'MediaBrowser.Model/Configuration') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index cc6b51f58e..b7c49ed99b 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -609,6 +609,32 @@ namespace MediaBrowser.MediaEncoding.Encoder return await ExtractImageInternal(inputArgument, container, videoStream, imageStreamIndex, threedFormat, offset, false, targetFormat, cancellationToken).ConfigureAwait(false); } + private string GetImageResolutionParameter() + { + string imageResolutionParameter; + + imageResolutionParameter = _serverConfig.Configuration.ChapterImageResolution switch + { + ImageResolution.P144 => "256x144", + ImageResolution.P240 => "426x240", + ImageResolution.P360 => "640x360", + ImageResolution.P480 => "854x480", + ImageResolution.P720 => "1280x720", + ImageResolution.P1080 => "1920x1080", + ImageResolution.P1440 => "2560x1440", + ImageResolution.P2160 => "3840x2160", + _ => string.Empty + }; + + if (!string.IsNullOrEmpty(imageResolutionParameter)) + { + imageResolutionParameter = " -s " + imageResolutionParameter; + } + + return imageResolutionParameter; + } + + private async Task ExtractImageInternal(string inputPath, string container, MediaStream videoStream, int? imageStreamIndex, Video3DFormat? threedFormat, TimeSpan? offset, bool useIFrame, ImageFormat? targetFormat, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(inputPath)) @@ -626,29 +652,6 @@ namespace MediaBrowser.MediaEncoding.Encoder _ => ".jpg" }; - bool enumConversionStatus = Enum.TryParse(_serverConfig.Configuration.ChapterImageResolution, out ImageResolution resolution); - var outputResolution = string.Empty; - - if (enumConversionStatus) - { - outputResolution = resolution switch - { - ImageResolution.P240 => "426x240", - ImageResolution.P360 => "640x360", - ImageResolution.P480 => "854x480", - ImageResolution.P720 => "1280x720", - ImageResolution.P1080 => "1920x1080", - ImageResolution.P1440 => "2560x1440", - ImageResolution.P2160 => "3840x2160", - _ => string.Empty - }; - - if (!string.IsNullOrEmpty(outputResolution)) - { - outputResolution = " -s " + outputResolution; - } - } - var tempExtractPath = Path.Combine(_configurationManager.ApplicationPaths.TempDirectory, Guid.NewGuid() + outputExtension); Directory.CreateDirectory(Path.GetDirectoryName(tempExtractPath)); @@ -702,7 +705,7 @@ namespace MediaBrowser.MediaEncoding.Encoder var vf = string.Join(',', filters); var mapArg = imageStreamIndex.HasValue ? (" -map 0:" + imageStreamIndex.Value.ToString(CultureInfo.InvariantCulture)) : string.Empty; - var args = string.Format(CultureInfo.InvariantCulture, "-i {0}{3} -threads {4} -v quiet -vframes 1 -vf {2}{5} -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, _threads, outputResolution); + var args = string.Format(CultureInfo.InvariantCulture, "-i {0}{3} -threads {4} -v quiet -vframes 1 -vf {2}{5} -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, _threads, GetImageResolutionParameter()); if (offset.HasValue) { diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index c37c167eb6..a07ab7121e 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Updates; @@ -257,6 +258,6 @@ namespace MediaBrowser.Model.Configuration /// Gets or sets the chapter image resolution. /// /// The chapter image resolution. - public string ChapterImageResolution { get; set; } = "Match Source"; + public ImageResolution ChapterImageResolution { get; set; } = ImageResolution.MatchSource; } } diff --git a/MediaBrowser.Model/Drawing/ImageResolution.cs b/MediaBrowser.Model/Drawing/ImageResolution.cs index 7e1c54f5a3..99967da45e 100644 --- a/MediaBrowser.Model/Drawing/ImageResolution.cs +++ b/MediaBrowser.Model/Drawing/ImageResolution.cs @@ -5,6 +5,16 @@ namespace MediaBrowser.Model.Drawing /// public enum ImageResolution { + /// + /// MatchSource. + /// + MatchSource, + + /// + /// 144p. + /// + P144, + /// /// 240p. /// diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index c8ff5de69a..686f68c5d7 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -666,7 +666,7 @@ namespace MediaBrowser.Providers.MediaInfo return Array.Empty(); } - // Limit to 100 chapters just in case there's some incorrect metadata here + // Limit the chapters just in case there's some incorrect metadata here int chapterCount = (int)Math.Min(runtime / dummyChapterDuration, _config.Configuration.DummyChapterCount); var chapters = new ChapterInfo[chapterCount]; -- cgit v1.2.3 From a74b8b99af6e4735367a5e7812db1c9e80bcc63b Mon Sep 17 00:00:00 2001 From: Joe Rogers <1337joe@gmail.com> Date: Tue, 17 May 2022 23:00:13 +0200 Subject: Add option to allow extras to use embedded titles --- MediaBrowser.Model/Configuration/LibraryOptions.cs | 2 ++ MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.Model/Configuration') diff --git a/MediaBrowser.Model/Configuration/LibraryOptions.cs b/MediaBrowser.Model/Configuration/LibraryOptions.cs index c4d313bdba..81f2f02bc5 100644 --- a/MediaBrowser.Model/Configuration/LibraryOptions.cs +++ b/MediaBrowser.Model/Configuration/LibraryOptions.cs @@ -45,6 +45,8 @@ namespace MediaBrowser.Model.Configuration public bool EnableEmbeddedTitles { get; set; } + public bool EnableEmbeddedExtrasTitles { get; set; } + public bool EnableEmbeddedEpisodeInfos { get; set; } public int AutomaticRefreshIntervalDays { get; set; } diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index 58b23a36df..751135a2c8 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -484,8 +484,8 @@ namespace MediaBrowser.Providers.MediaInfo { if (!string.IsNullOrWhiteSpace(data.Name) && libraryOptions.EnableEmbeddedTitles) { - // Don't use the embedded name for extras because it will often be the same name as the movie - if (!video.ExtraType.HasValue) + // Separate option to use the embedded name for extras because it will often be the same name as the movie + if (!video.ExtraType.HasValue || libraryOptions.EnableEmbeddedExtrasTitles) { video.Name = data.Name; } -- cgit v1.2.3 From 69a51c425acef65c229e95f2c361226bd81d64c5 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 4 Jan 2023 16:01:31 +0100 Subject: Fix all warnings in Jellyfin.Api (#9003) --- Jellyfin.Api/Attributes/AcceptsFileAttribute.cs | 2 +- Jellyfin.Api/Attributes/ProducesFileAttribute.cs | 2 +- Jellyfin.Api/BaseJellyfinApiController.cs | 18 --- Jellyfin.Api/Controllers/ApiKeyController.cs | 2 +- Jellyfin.Api/Controllers/ImageController.cs | 135 +++++++++++---------- Jellyfin.Api/Controllers/LiveTvController.cs | 3 +- Jellyfin.Api/Controllers/PackageController.cs | 4 +- Jellyfin.Api/Controllers/PluginsController.cs | 3 +- Jellyfin.Api/Controllers/SubtitleController.cs | 40 +++--- Jellyfin.Api/Controllers/SyncPlayController.cs | 3 +- Jellyfin.Api/Controllers/SystemController.cs | 3 +- Jellyfin.Api/Controllers/UserLibraryController.cs | 2 +- Jellyfin.Api/Jellyfin.Api.csproj | 4 - .../Models/LiveTvDtos/ChannelMappingOptionsDto.cs | 6 +- Jellyfin.Server/Filters/FileRequestFilter.cs | 2 +- Jellyfin.Server/Filters/FileResponseFilter.cs | 2 +- .../Routines/AddDefaultPluginRepository.cs | 2 +- .../Routines/ReaddDefaultPluginRepository.cs | 4 +- .../Configuration/ServerConfiguration.cs | 2 +- jellyfin.ruleset | 4 + 20 files changed, 120 insertions(+), 123 deletions(-) (limited to 'MediaBrowser.Model/Configuration') diff --git a/Jellyfin.Api/Attributes/AcceptsFileAttribute.cs b/Jellyfin.Api/Attributes/AcceptsFileAttribute.cs index 58552d847d..fbe68b6b97 100644 --- a/Jellyfin.Api/Attributes/AcceptsFileAttribute.cs +++ b/Jellyfin.Api/Attributes/AcceptsFileAttribute.cs @@ -25,6 +25,6 @@ namespace Jellyfin.Api.Attributes /// Gets the configured content types. /// /// the configured content types. - public string[] GetContentTypes() => _contentTypes; + public string[] ContentTypes => _contentTypes; } } diff --git a/Jellyfin.Api/Attributes/ProducesFileAttribute.cs b/Jellyfin.Api/Attributes/ProducesFileAttribute.cs index 2bf77d729a..d8e4141acb 100644 --- a/Jellyfin.Api/Attributes/ProducesFileAttribute.cs +++ b/Jellyfin.Api/Attributes/ProducesFileAttribute.cs @@ -25,6 +25,6 @@ namespace Jellyfin.Api.Attributes /// Gets the configured content types. /// /// the configured content types. - public string[] GetContentTypes() => _contentTypes; + public string[] ContentTypes => _contentTypes; } } diff --git a/Jellyfin.Api/BaseJellyfinApiController.cs b/Jellyfin.Api/BaseJellyfinApiController.cs index 0c63d24b70..e327831fe7 100644 --- a/Jellyfin.Api/BaseJellyfinApiController.cs +++ b/Jellyfin.Api/BaseJellyfinApiController.cs @@ -17,24 +17,6 @@ namespace Jellyfin.Api JsonDefaults.PascalCaseMediaType)] public class BaseJellyfinApiController : ControllerBase { - /// - /// Create a new . - /// - /// The value to return. - /// The type to return. - /// The . - protected ActionResult> Ok(List value) - => new OkResult>(value); - - /// - /// Create a new . - /// - /// The value to return. - /// The type to return. - /// The . - protected ActionResult> Ok(IReadOnlyList value) - => new OkResult>(value); - /// /// Create a new . /// diff --git a/Jellyfin.Api/Controllers/ApiKeyController.cs b/Jellyfin.Api/Controllers/ApiKeyController.cs index 593846adc9..024a15349e 100644 --- a/Jellyfin.Api/Controllers/ApiKeyController.cs +++ b/Jellyfin.Api/Controllers/ApiKeyController.cs @@ -36,7 +36,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public async Task>> GetKeys() { - var keys = await _authenticationManager.GetApiKeys(); + var keys = await _authenticationManager.GetApiKeys().ConfigureAwait(false); return new QueryResult(keys); } diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 49342ad5ce..534667c8c6 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -106,24 +106,26 @@ namespace Jellyfin.Api.Controllers } var user = _userManager.GetUserById(userId); - await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); - - // Handle image/png; charset=utf-8 - var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); - var userDataPath = Path.Combine(_serverConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username); - if (user.ProfileImage is not null) + var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); + await using (memoryStream.ConfigureAwait(false)) { - await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false); - } + // Handle image/png; charset=utf-8 + var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); + var userDataPath = Path.Combine(_serverConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username); + if (user.ProfileImage is not null) + { + await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false); + } - user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType ?? string.Empty))); + user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType ?? string.Empty))); - await _providerManager - .SaveImage(memoryStream, mimeType, user.ProfileImage.Path) - .ConfigureAwait(false); - await _userManager.UpdateUserAsync(user).ConfigureAwait(false); + await _providerManager + .SaveImage(memoryStream, mimeType, user.ProfileImage.Path) + .ConfigureAwait(false); + await _userManager.UpdateUserAsync(user).ConfigureAwait(false); - return NoContent(); + return NoContent(); + } } /// @@ -153,24 +155,26 @@ namespace Jellyfin.Api.Controllers } var user = _userManager.GetUserById(userId); - await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); - - // Handle image/png; charset=utf-8 - var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); - var userDataPath = Path.Combine(_serverConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username); - if (user.ProfileImage is not null) + var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); + await using (memoryStream.ConfigureAwait(false)) { - await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false); - } + // Handle image/png; charset=utf-8 + var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); + var userDataPath = Path.Combine(_serverConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username); + if (user.ProfileImage is not null) + { + await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false); + } - user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType ?? string.Empty))); + user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType ?? string.Empty))); - await _providerManager - .SaveImage(memoryStream, mimeType, user.ProfileImage.Path) - .ConfigureAwait(false); - await _userManager.UpdateUserAsync(user).ConfigureAwait(false); + await _providerManager + .SaveImage(memoryStream, mimeType, user.ProfileImage.Path) + .ConfigureAwait(false); + await _userManager.UpdateUserAsync(user).ConfigureAwait(false); - return NoContent(); + return NoContent(); + } } /// @@ -341,14 +345,16 @@ namespace Jellyfin.Api.Controllers return NotFound(); } - await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); - - // Handle image/png; charset=utf-8 - var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); - await _providerManager.SaveImage(item, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false); - await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); + var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); + await using (memoryStream.ConfigureAwait(false)) + { + // Handle image/png; charset=utf-8 + var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); + await _providerManager.SaveImage(item, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false); + await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); - return NoContent(); + return NoContent(); + } } /// @@ -377,14 +383,16 @@ namespace Jellyfin.Api.Controllers return NotFound(); } - await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); - - // Handle image/png; charset=utf-8 - var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); - await _providerManager.SaveImage(item, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false); - await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); + var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); + await using (memoryStream.ConfigureAwait(false)) + { + // Handle image/png; charset=utf-8 + var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); + await _providerManager.SaveImage(item, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false); + await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); - return NoContent(); + return NoContent(); + } } /// @@ -1788,32 +1796,35 @@ namespace Jellyfin.Api.Controllers [AcceptsImageFile] public async Task UploadCustomSplashscreen() { - await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); + var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); + await using (memoryStream.ConfigureAwait(false)) + { + var mimeType = MediaTypeHeaderValue.Parse(Request.ContentType).MediaType; - var mimeType = MediaTypeHeaderValue.Parse(Request.ContentType).MediaType; + if (!mimeType.HasValue) + { + return BadRequest("Error reading mimetype from uploaded image"); + } - if (!mimeType.HasValue) - { - return BadRequest("Error reading mimetype from uploaded image"); - } + var extension = MimeTypes.ToExtension(mimeType.Value); + if (string.IsNullOrEmpty(extension)) + { + return BadRequest("Error converting mimetype to an image extension"); + } - var extension = MimeTypes.ToExtension(mimeType.Value); - if (string.IsNullOrEmpty(extension)) - { - return BadRequest("Error converting mimetype to an image extension"); - } + var filePath = Path.Combine(_appPaths.DataPath, "splashscreen-upload" + extension); + var brandingOptions = _serverConfigurationManager.GetConfiguration("branding"); + brandingOptions.SplashscreenLocation = filePath; + _serverConfigurationManager.SaveConfiguration("branding", brandingOptions); - var filePath = Path.Combine(_appPaths.DataPath, "splashscreen-upload" + extension); - var brandingOptions = _serverConfigurationManager.GetConfiguration("branding"); - brandingOptions.SplashscreenLocation = filePath; - _serverConfigurationManager.SaveConfiguration("branding", brandingOptions); + var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); + await using (fs.ConfigureAwait(false)) + { + await memoryStream.CopyToAsync(fs, CancellationToken.None).ConfigureAwait(false); + } - await using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) - { - await memoryStream.CopyToAsync(fs, CancellationToken.None).ConfigureAwait(false); + return NoContent(); } - - return NoContent(); } /// diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs index 94710d78f2..5228e0babf 100644 --- a/Jellyfin.Api/Controllers/LiveTvController.cs +++ b/Jellyfin.Api/Controllers/LiveTvController.cs @@ -1011,10 +1011,9 @@ namespace Jellyfin.Api.Controllers { if (!string.IsNullOrEmpty(pw)) { - using var sha = SHA1.Create(); // TODO: remove ToLower when Convert.ToHexString supports lowercase // Schedules Direct requires the hex to be lowercase - listingsProviderInfo.Password = Convert.ToHexString(sha.ComputeHash(Encoding.UTF8.GetBytes(pw))).ToLowerInvariant(); + listingsProviderInfo.Password = Convert.ToHexString(SHA1.HashData(Encoding.UTF8.GetBytes(pw))).ToLowerInvariant(); } return await _liveTvManager.SaveListingProvider(listingsProviderInfo, validateLogin, validateListings).ConfigureAwait(false); diff --git a/Jellyfin.Api/Controllers/PackageController.cs b/Jellyfin.Api/Controllers/PackageController.cs index 0aa7c2ac9e..10f967dcde 100644 --- a/Jellyfin.Api/Controllers/PackageController.cs +++ b/Jellyfin.Api/Controllers/PackageController.cs @@ -145,7 +145,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetRepositories() { - return _serverConfigurationManager.Configuration.PluginRepositories; + return Ok(_serverConfigurationManager.Configuration.PluginRepositories.AsEnumerable()); } /// @@ -157,7 +157,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("Repositories")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] - public ActionResult SetRepositories([FromBody, Required] List repositoryInfos) + public ActionResult SetRepositories([FromBody, Required] RepositoryInfo[] repositoryInfos) { _serverConfigurationManager.Configuration.PluginRepositories = repositoryInfos; _serverConfigurationManager.SaveConfiguration(); diff --git a/Jellyfin.Api/Controllers/PluginsController.cs b/Jellyfin.Api/Controllers/PluginsController.cs index 6a729b2373..b8a09990a5 100644 --- a/Jellyfin.Api/Controllers/PluginsController.cs +++ b/Jellyfin.Api/Controllers/PluginsController.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Text.Json; @@ -143,7 +144,7 @@ namespace Jellyfin.Api.Controllers public ActionResult UninstallPlugin([FromRoute, Required] Guid pluginId) { // If no version is given, return the current instance. - var plugins = _pluginManager.Plugins.Where(p => p.Id.Equals(pluginId)); + var plugins = _pluginManager.Plugins.Where(p => p.Id.Equals(pluginId)).ToList(); // Select the un-instanced one first. var plugin = plugins.FirstOrDefault(p => p.Instance is null) ?? plugins.OrderBy(p => p.Manifest.Status).FirstOrDefault(); diff --git a/Jellyfin.Api/Controllers/SubtitleController.cs b/Jellyfin.Api/Controllers/SubtitleController.cs index ff9bd095b5..c3ce1868e2 100644 --- a/Jellyfin.Api/Controllers/SubtitleController.cs +++ b/Jellyfin.Api/Controllers/SubtitleController.cs @@ -236,14 +236,17 @@ namespace Jellyfin.Api.Controllers if (string.Equals(format, "vtt", StringComparison.OrdinalIgnoreCase) && addVttTimeMap) { - await using Stream stream = await EncodeSubtitles(itemId.Value, mediaSourceId, index.Value, format, startPositionTicks, endPositionTicks, copyTimestamps).ConfigureAwait(false); - using var reader = new StreamReader(stream); + Stream stream = await EncodeSubtitles(itemId.Value, mediaSourceId, index.Value, format, startPositionTicks, endPositionTicks, copyTimestamps).ConfigureAwait(false); + await using (stream.ConfigureAwait(false)) + { + using var reader = new StreamReader(stream); - var text = await reader.ReadToEndAsync().ConfigureAwait(false); + var text = await reader.ReadToEndAsync().ConfigureAwait(false); - text = text.Replace("WEBVTT", "WEBVTT\nX-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000", StringComparison.Ordinal); + text = text.Replace("WEBVTT", "WEBVTT\nX-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000", StringComparison.Ordinal); - return File(Encoding.UTF8.GetBytes(text), MimeTypes.GetMimeType("file." + format)); + return File(Encoding.UTF8.GetBytes(text), MimeTypes.GetMimeType("file." + format)); + } } return File( @@ -403,19 +406,22 @@ namespace Jellyfin.Api.Controllers { var video = (Video)_libraryManager.GetItemById(itemId); var data = Convert.FromBase64String(body.Data); - await using var memoryStream = new MemoryStream(data); - await _subtitleManager.UploadSubtitle( - video, - new SubtitleResponse - { - Format = body.Format, - Language = body.Language, - IsForced = body.IsForced, - Stream = memoryStream - }).ConfigureAwait(false); - _providerManager.QueueRefresh(video.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), RefreshPriority.High); + var memoryStream = new MemoryStream(data, 0, data.Length, false, true); + await using (memoryStream.ConfigureAwait(false)) + { + await _subtitleManager.UploadSubtitle( + video, + new SubtitleResponse + { + Format = body.Format, + Language = body.Language, + IsForced = body.IsForced, + Stream = memoryStream + }).ConfigureAwait(false); + _providerManager.QueueRefresh(video.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), RefreshPriority.High); - return NoContent(); + return NoContent(); + } } /// diff --git a/Jellyfin.Api/Controllers/SyncPlayController.cs b/Jellyfin.Api/Controllers/SyncPlayController.cs index e194fc556e..99347246e0 100644 --- a/Jellyfin.Api/Controllers/SyncPlayController.cs +++ b/Jellyfin.Api/Controllers/SyncPlayController.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Constants; @@ -107,7 +108,7 @@ namespace Jellyfin.Api.Controllers { var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(false); var syncPlayRequest = new ListGroupsRequest(); - return Ok(_syncPlayManager.ListGroups(currentSession, syncPlayRequest)); + return Ok(_syncPlayManager.ListGroups(currentSession, syncPlayRequest).AsEnumerable()); } /// diff --git a/Jellyfin.Api/Controllers/SystemController.cs b/Jellyfin.Api/Controllers/SystemController.cs index 411c987f39..2d594293e0 100644 --- a/Jellyfin.Api/Controllers/SystemController.cs +++ b/Jellyfin.Api/Controllers/SystemController.cs @@ -216,8 +216,7 @@ namespace Jellyfin.Api.Controllers public ActionResult> GetWakeOnLanInfo() { var result = _network.GetMacAddresses() - .Select(i => new WakeOnLanInfo(i)) - .ToList(); + .Select(i => new WakeOnLanInfo(i)); return Ok(result); } } diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs index c18fa29af6..cd21c5f6ff 100644 --- a/Jellyfin.Api/Controllers/UserLibraryController.cs +++ b/Jellyfin.Api/Controllers/UserLibraryController.cs @@ -211,7 +211,7 @@ namespace Jellyfin.Api.Controllers if (item is IHasTrailers hasTrailers) { var trailers = hasTrailers.LocalTrailers; - return Ok(_dtoService.GetBaseItemDtos(trailers, dtoOptions, user, item)); + return Ok(_dtoService.GetBaseItemDtos(trailers, dtoOptions, user, item).AsEnumerable()); } return Ok(item.GetExtras() diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index 889f7dc9ab..eca68c6dfa 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -12,10 +12,6 @@ AD0001 - - false - - diff --git a/Jellyfin.Api/Models/LiveTvDtos/ChannelMappingOptionsDto.cs b/Jellyfin.Api/Models/LiveTvDtos/ChannelMappingOptionsDto.cs index f43822da77..e293c461cf 100644 --- a/Jellyfin.Api/Models/LiveTvDtos/ChannelMappingOptionsDto.cs +++ b/Jellyfin.Api/Models/LiveTvDtos/ChannelMappingOptionsDto.cs @@ -14,14 +14,12 @@ namespace Jellyfin.Api.Models.LiveTvDtos /// /// Gets or sets list of tuner channels. /// - [SuppressMessage("Microsoft.Performance", "CA2227:ReadOnlyRemoveSetter", MessageId = "TunerChannels", Justification = "Imported from ServiceStack")] - public List TunerChannels { get; set; } = null!; + required public IReadOnlyList TunerChannels { get; set; } /// /// Gets or sets list of provider channels. /// - [SuppressMessage("Microsoft.Performance", "CA2227:ReadOnlyRemoveSetter", MessageId = "ProviderChannels", Justification = "Imported from ServiceStack")] - public List ProviderChannels { get; set; } = null!; + required public IReadOnlyList ProviderChannels { get; set; } /// /// Gets or sets list of mappings. diff --git a/Jellyfin.Server/Filters/FileRequestFilter.cs b/Jellyfin.Server/Filters/FileRequestFilter.cs index 69e10994f4..bb5d6a4123 100644 --- a/Jellyfin.Server/Filters/FileRequestFilter.cs +++ b/Jellyfin.Server/Filters/FileRequestFilter.cs @@ -15,7 +15,7 @@ namespace Jellyfin.Server.Filters { if (attribute is AcceptsFileAttribute acceptsFileAttribute) { - operation.RequestBody = GetRequestBody(acceptsFileAttribute.GetContentTypes()); + operation.RequestBody = GetRequestBody(acceptsFileAttribute.ContentTypes); break; } } diff --git a/Jellyfin.Server/Filters/FileResponseFilter.cs b/Jellyfin.Server/Filters/FileResponseFilter.cs index 544fdbfd63..1a4559d260 100644 --- a/Jellyfin.Server/Filters/FileResponseFilter.cs +++ b/Jellyfin.Server/Filters/FileResponseFilter.cs @@ -40,7 +40,7 @@ namespace Jellyfin.Server.Filters response.Value.Content.Clear(); // Add all content-types as file. - foreach (var contentType in producesFileAttribute.GetContentTypes()) + foreach (var contentType in producesFileAttribute.ContentTypes) { response.Value.Content.Add(contentType, _openApiMediaType); } diff --git a/Jellyfin.Server/Migrations/Routines/AddDefaultPluginRepository.cs b/Jellyfin.Server/Migrations/Routines/AddDefaultPluginRepository.cs index f6d8c9cc0d..9e12c2e6bd 100644 --- a/Jellyfin.Server/Migrations/Routines/AddDefaultPluginRepository.cs +++ b/Jellyfin.Server/Migrations/Routines/AddDefaultPluginRepository.cs @@ -38,7 +38,7 @@ namespace Jellyfin.Server.Migrations.Routines /// public void Perform() { - _serverConfigurationManager.Configuration.PluginRepositories.Add(_defaultRepositoryInfo); + _serverConfigurationManager.Configuration.PluginRepositories = new[] { _defaultRepositoryInfo }; _serverConfigurationManager.SaveConfiguration(); } } diff --git a/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs b/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs index 394f14d63c..9cfaec46f8 100644 --- a/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs +++ b/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs @@ -39,9 +39,9 @@ namespace Jellyfin.Server.Migrations.Routines public void Perform() { // Only add if repository list is empty - if (_serverConfigurationManager.Configuration.PluginRepositories.Count == 0) + if (_serverConfigurationManager.Configuration.PluginRepositories.Length == 0) { - _serverConfigurationManager.Configuration.PluginRepositories.Add(_defaultRepositoryInfo); + _serverConfigurationManager.Configuration.PluginRepositories = new[] { _defaultRepositoryInfo }; _serverConfigurationManager.SaveConfiguration(); } } diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index a07ab7121e..d3e042abaa 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -194,7 +194,7 @@ namespace MediaBrowser.Model.Configuration public string[] CodecsUsed { get; set; } = Array.Empty(); - public List PluginRepositories { get; set; } = new List(); + public RepositoryInfo[] PluginRepositories { get; set; } = Array.Empty(); public bool EnableExternalContentInSuggestions { get; set; } = true; diff --git a/jellyfin.ruleset b/jellyfin.ruleset index 71385cee2a..3fda774b8d 100644 --- a/jellyfin.ruleset +++ b/jellyfin.ruleset @@ -138,6 +138,10 @@ + + + + -- cgit v1.2.3 From 407c716f82da25fa5ffe30a819ea1adb5c6873ab Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Mon, 2 Jan 2023 22:26:54 +0100 Subject: Add stereo downmix algorithm selection. --- Jellyfin.Api/Controllers/DynamicHlsController.cs | 8 +- .../MediaEncoding/EncodingHelper.cs | 28 +- .../Configuration/EncodingOptions.cs | 363 ++++++++++++++------- .../Entities/DownMixStereoAlgorithms.cs | 23 ++ 4 files changed, 292 insertions(+), 130 deletions(-) create mode 100644 MediaBrowser.Model/Entities/DownMixStereoAlgorithms.cs (limited to 'MediaBrowser.Model/Configuration') diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index af43bb578e..e0c5bcc84b 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -22,6 +22,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dlna; +using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; using Microsoft.AspNetCore.Authorization; @@ -1731,7 +1732,12 @@ namespace Jellyfin.Api.Controllers var channels = state.OutputAudioChannels; - if (channels.HasValue) + if (channels.HasValue + && (channels.Value != 2 + || (state.AudioStream is not null + && state.AudioStream.Channels.HasValue + && state.AudioStream.Channels.Value > 5 + && _encodingOptions.DownMixStereoAlgorithm == DownMixStereoAlgorithms.None))) { args += " -ac " + channels.Value; } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index b40c224d5d..e94a04a7dc 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -2129,15 +2129,30 @@ namespace MediaBrowser.Controller.MediaEncoding var filters = new List(); - // Boost volume to 200% when downsampling from 6ch to 2ch if (channels.HasValue - && channels.Value <= 2 + && channels.Value == 2 && state.AudioStream is not null && state.AudioStream.Channels.HasValue - && state.AudioStream.Channels.Value > 5 - && !encodingOptions.DownMixAudioBoost.Equals(1)) + && state.AudioStream.Channels.Value > 5) { - filters.Add("volume=" + encodingOptions.DownMixAudioBoost.ToString(CultureInfo.InvariantCulture)); + switch (encodingOptions.DownMixStereoAlgorithm) + { + case DownMixStereoAlgorithms.Dave750: + filters.Add("volume=4.25"); + filters.Add("pan=stereo|c0=0.5*c2+0.707*c0+0.707*c4+0.5*c3|c1=0.5*c2+0.707*c1+0.707*c5+0.5*c3"); + break; + case DownMixStereoAlgorithms.NightmodeDialogue: + filters.Add("pan=stereo|c0=c2+0.30*c0+0.30*c4|c1=c2+0.30*c1+0.30*c5"); + break; + case DownMixStereoAlgorithms.None: + default: + if (!encodingOptions.DownMixAudioBoost.Equals(1)) + { + filters.Add("volume=" + encodingOptions.DownMixAudioBoost.ToString(CultureInfo.InvariantCulture)); + } + + break; + } } var isCopyingTimestamps = state.CopyTimestamps || state.TranscodingType != TranscodingJobType.Progressive; @@ -5711,10 +5726,9 @@ namespace MediaBrowser.Controller.MediaEncoding return args; } - // Add the number of audio channels var channels = state.OutputAudioChannels; - if (channels.HasValue) + if (channels.HasValue && ((channels.Value != 2 && state.AudioStream.Channels <= 5) || encodingOptions.DownMixStereoAlgorithm == DownMixStereoAlgorithms.None)) { args += " -ac " + channels.Value; } diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs index f4cd2f0065..0ff95a2e1f 100644 --- a/MediaBrowser.Model/Configuration/EncodingOptions.cs +++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs @@ -1,128 +1,247 @@ #nullable disable -#pragma warning disable CS1591 +using MediaBrowser.Model.Entities; -namespace MediaBrowser.Model.Configuration +namespace MediaBrowser.Model.Configuration; + +/// +/// Class EncodingOptions. +/// +public class EncodingOptions { - public class EncodingOptions + /// + /// Initializes a new instance of the class. + /// + public EncodingOptions() { - public EncodingOptions() - { - EnableFallbackFont = false; - DownMixAudioBoost = 2; - MaxMuxingQueueSize = 2048; - EnableThrottling = false; - ThrottleDelaySeconds = 180; - EncodingThreadCount = -1; - // This is a DRM device that is almost guaranteed to be there on every intel platform, - // plus it's the default one in ffmpeg if you don't specify anything - VaapiDevice = "/dev/dri/renderD128"; - EnableTonemapping = false; - EnableVppTonemapping = false; - TonemappingAlgorithm = "bt2390"; - TonemappingRange = "auto"; - TonemappingDesat = 0; - TonemappingThreshold = 0.8; - TonemappingPeak = 100; - TonemappingParam = 0; - VppTonemappingBrightness = 0; - VppTonemappingContrast = 1.2; - H264Crf = 23; - H265Crf = 28; - DeinterlaceDoubleRate = false; - DeinterlaceMethod = "yadif"; - EnableDecodingColorDepth10Hevc = true; - EnableDecodingColorDepth10Vp9 = true; - EnableEnhancedNvdecDecoder = false; - PreferSystemNativeHwDecoder = true; - EnableIntelLowPowerH264HwEncoder = false; - EnableIntelLowPowerHevcHwEncoder = false; - EnableHardwareEncoding = true; - AllowHevcEncoding = false; - EnableSubtitleExtraction = true; - AllowOnDemandMetadataBasedKeyframeExtractionForExtensions = new[] { "mkv" }; - HardwareDecodingCodecs = new string[] { "h264", "vc1" }; - } - - public int EncodingThreadCount { get; set; } - - public string TranscodingTempPath { get; set; } - - public string FallbackFontPath { get; set; } - - public bool EnableFallbackFont { get; set; } - - public double DownMixAudioBoost { get; set; } - - public int MaxMuxingQueueSize { get; set; } - - public bool EnableThrottling { get; set; } - - public int ThrottleDelaySeconds { get; set; } - - public string HardwareAccelerationType { get; set; } - - /// - /// Gets or sets the FFmpeg path as set by the user via the UI. - /// - public string EncoderAppPath { get; set; } - - /// - /// Gets or sets the current FFmpeg path being used by the system and displayed on the transcode page. - /// - public string EncoderAppPathDisplay { get; set; } - - public string VaapiDevice { get; set; } - - public bool EnableTonemapping { get; set; } - - public bool EnableVppTonemapping { get; set; } - - public string TonemappingAlgorithm { get; set; } - - public string TonemappingRange { get; set; } - - public double TonemappingDesat { get; set; } - - public double TonemappingThreshold { get; set; } - - public double TonemappingPeak { get; set; } - - public double TonemappingParam { get; set; } - - public double VppTonemappingBrightness { get; set; } - - public double VppTonemappingContrast { get; set; } - - public int H264Crf { get; set; } - - public int H265Crf { get; set; } - - public string EncoderPreset { get; set; } - - public bool DeinterlaceDoubleRate { get; set; } - - public string DeinterlaceMethod { get; set; } - - public bool EnableDecodingColorDepth10Hevc { get; set; } - - public bool EnableDecodingColorDepth10Vp9 { get; set; } - - public bool EnableEnhancedNvdecDecoder { get; set; } - - public bool PreferSystemNativeHwDecoder { get; set; } - - public bool EnableIntelLowPowerH264HwEncoder { get; set; } - - public bool EnableIntelLowPowerHevcHwEncoder { get; set; } - - public bool EnableHardwareEncoding { get; set; } - - public bool AllowHevcEncoding { get; set; } - - public bool EnableSubtitleExtraction { get; set; } - - public string[] HardwareDecodingCodecs { get; set; } - - public string[] AllowOnDemandMetadataBasedKeyframeExtractionForExtensions { get; set; } + EnableFallbackFont = false; + DownMixAudioBoost = 2; + DownMixStereoAlgorithm = DownMixStereoAlgorithms.None; + MaxMuxingQueueSize = 2048; + EnableThrottling = false; + ThrottleDelaySeconds = 180; + EncodingThreadCount = -1; + // This is a DRM device that is almost guaranteed to be there on every intel platform, + // plus it's the default one in ffmpeg if you don't specify anything + VaapiDevice = "/dev/dri/renderD128"; + EnableTonemapping = false; + EnableVppTonemapping = false; + TonemappingAlgorithm = "bt2390"; + TonemappingRange = "auto"; + TonemappingDesat = 0; + TonemappingThreshold = 0.8; + TonemappingPeak = 100; + TonemappingParam = 0; + VppTonemappingBrightness = 0; + VppTonemappingContrast = 1.2; + H264Crf = 23; + H265Crf = 28; + DeinterlaceDoubleRate = false; + DeinterlaceMethod = "yadif"; + EnableDecodingColorDepth10Hevc = true; + EnableDecodingColorDepth10Vp9 = true; + EnableEnhancedNvdecDecoder = false; + PreferSystemNativeHwDecoder = true; + EnableIntelLowPowerH264HwEncoder = false; + EnableIntelLowPowerHevcHwEncoder = false; + EnableHardwareEncoding = true; + AllowHevcEncoding = false; + EnableSubtitleExtraction = true; + AllowOnDemandMetadataBasedKeyframeExtractionForExtensions = new[] { "mkv" }; + HardwareDecodingCodecs = new string[] { "h264", "vc1" }; } + + /// + /// Gets or sets the thread count used for encoding. + /// + public int EncodingThreadCount { get; set; } + + /// + /// Gets or sets the temporary transcoding path. + /// + public string TranscodingTempPath { get; set; } + + /// + /// Gets or sets the path to the fallback font. + /// + public string FallbackFontPath { get; set; } + + /// + /// Gets or sets a value indicating whether to use the fallback font. + /// + public bool EnableFallbackFont { get; set; } + + /// + /// Gets or sets the audio boost applied when downmixing audio. + /// + public double DownMixAudioBoost { get; set; } + + /// + /// Gets or sets the algorithm used for downmixing audio to stereo. + /// + public DownMixStereoAlgorithms DownMixStereoAlgorithm { get; set; } + + /// + /// Gets or sets the maximum size of the muxing queue. + /// + public int MaxMuxingQueueSize { get; set; } + + /// + /// Gets or sets a value indicating whether throttling is enabled. + /// + public bool EnableThrottling { get; set; } + + /// + /// Gets or sets the delay after which throttling happens. + /// + public int ThrottleDelaySeconds { get; set; } + + /// + /// Gets or sets the hardware acceleration type. + /// + public string HardwareAccelerationType { get; set; } + + /// + /// Gets or sets the FFmpeg path as set by the user via the UI. + /// + public string EncoderAppPath { get; set; } + + /// + /// Gets or sets the current FFmpeg path being used by the system and displayed on the transcode page. + /// + public string EncoderAppPathDisplay { get; set; } + + /// + /// Gets or sets the VA-API device. + /// + public string VaapiDevice { get; set; } + + /// + /// Gets or sets a value indicating whether tonemapping is enabled. + /// + public bool EnableTonemapping { get; set; } + + /// + /// Gets or sets a value indicating whether VPP tonemapping is enabled. + /// + public bool EnableVppTonemapping { get; set; } + + /// + /// Gets or sets the tone-mapping algorithm. + /// + public string TonemappingAlgorithm { get; set; } + + /// + /// Gets or sets the tone-mapping range. + /// + public string TonemappingRange { get; set; } + + /// + /// Gets or sets the tone-mapping desaturation. + /// + public double TonemappingDesat { get; set; } + + /// + /// Gets or sets the tone-mapping threshold. + /// + public double TonemappingThreshold { get; set; } + + /// + /// Gets or sets the tone-mapping peak. + /// + public double TonemappingPeak { get; set; } + + /// + /// Gets or sets the tone-mapping parameters. + /// + public double TonemappingParam { get; set; } + + /// + /// Gets or sets the VPP tone-mapping brightness. + /// + public double VppTonemappingBrightness { get; set; } + + /// + /// Gets or sets the VPP tone-mapping contrast. + /// + public double VppTonemappingContrast { get; set; } + + /// + /// Gets or sets the H264 CRF. + /// + public int H264Crf { get; set; } + + /// + /// Gets or sets the H265 CRF. + /// + public int H265Crf { get; set; } + + /// + /// Gets or sets the encoder preset. + /// + public string EncoderPreset { get; set; } + + /// + /// Gets or sets a value indicating whether the framerate is doubled when deinterlacing. + /// + public bool DeinterlaceDoubleRate { get; set; } + + /// + /// Gets or sets the deinterlace method. + /// + public string DeinterlaceMethod { get; set; } + + /// + /// Gets or sets a value indicating whether 10bit HEVC decoding is enabled. + /// + public bool EnableDecodingColorDepth10Hevc { get; set; } + + /// + /// Gets or sets a value indicating whether 10bit VP9 decoding is enabled. + /// + public bool EnableDecodingColorDepth10Vp9 { get; set; } + + /// + /// Gets or sets a value indicating whether the enhanced NVDEC is enabled. + /// + public bool EnableEnhancedNvdecDecoder { get; set; } + + /// + /// Gets or sets a value indicating whether the system native hardware decoder should be used. + /// + public bool PreferSystemNativeHwDecoder { get; set; } + + /// + /// Gets or sets a value indicating whether the Intel H264 low-power hardware encoder should be used. + /// + public bool EnableIntelLowPowerH264HwEncoder { get; set; } + + /// + /// Gets or sets a value indicating whether the Intel HEVC low-power hardware encoder should be used. + /// + public bool EnableIntelLowPowerHevcHwEncoder { get; set; } + + /// + /// Gets or sets a value indicating whether hardware encoding is enabled. + /// + public bool EnableHardwareEncoding { get; set; } + + /// + /// Gets or sets a value indicating whether HEVC encoding is enabled. + /// + public bool AllowHevcEncoding { get; set; } + + /// + /// Gets or sets a value indicating whether subtitle extraction is enabled. + /// + public bool EnableSubtitleExtraction { get; set; } + + /// + /// Gets or sets the codecs hardware encoding is used for. + /// + public string[] HardwareDecodingCodecs { get; set; } + + /// + /// Gets or sets the file extensions on-demand metadata based keyframe extraction is enabled for. + /// + public string[] AllowOnDemandMetadataBasedKeyframeExtractionForExtensions { get; set; } } diff --git a/MediaBrowser.Model/Entities/DownMixStereoAlgorithms.cs b/MediaBrowser.Model/Entities/DownMixStereoAlgorithms.cs new file mode 100644 index 0000000000..385cd6a34e --- /dev/null +++ b/MediaBrowser.Model/Entities/DownMixStereoAlgorithms.cs @@ -0,0 +1,23 @@ +namespace MediaBrowser.Model.Entities; + +/// +/// An enum representing an algorithm to downmix 6ch+ to stereo. +/// Algorithms sourced from https://superuser.com/questions/852400/properly-downmix-5-1-to-stereo-using-ffmpeg/1410620#1410620. +/// +public enum DownMixStereoAlgorithms +{ + /// + /// No special algorithm. + /// + None = 0, + + /// + /// Algorithm by Dave_750. + /// + Dave750 = 1, + + /// + /// Nightmode Dialogue algorithm. + /// + NightmodeDialogue = 2 +} -- cgit v1.2.3 From 66eff8b9ca18ab1cde76196c145ad0a98d0eda99 Mon Sep 17 00:00:00 2001 From: Hannes Braun Date: Mon, 16 Jan 2023 18:06:44 +0100 Subject: Allow limiting parallel image encodings to reduce memory usage (#8783) --- .../Configuration/ServerConfiguration.cs | 6 +++++ src/Jellyfin.Drawing/ImageProcessor.cs | 31 ++++++++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.Model/Configuration') diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index d3e042abaa..c39162250a 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -259,5 +259,11 @@ namespace MediaBrowser.Model.Configuration /// /// The chapter image resolution. public ImageResolution ChapterImageResolution { get; set; } = ImageResolution.MatchSource; + + /// + /// Gets or sets the limit for parallel image encoding. + /// + /// The limit for parallel image encoding. + public int ParallelImageEncodingLimit { get; set; } = 0; } } diff --git a/src/Jellyfin.Drawing/ImageProcessor.cs b/src/Jellyfin.Drawing/ImageProcessor.cs index b381c9ae73..353a27b254 100644 --- a/src/Jellyfin.Drawing/ImageProcessor.cs +++ b/src/Jellyfin.Drawing/ImageProcessor.cs @@ -5,10 +5,12 @@ using System.IO; using System.Linq; using System.Net.Mime; using System.Text; +using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.MediaEncoding; @@ -38,6 +40,8 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable private readonly IImageEncoder _imageEncoder; private readonly IMediaEncoder _mediaEncoder; + private readonly SemaphoreSlim _parallelEncodingLimit; + private bool _disposed; /// @@ -48,18 +52,28 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable /// The filesystem. /// The image encoder. /// The media encoder. + /// The configuration. public ImageProcessor( ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem, IImageEncoder imageEncoder, - IMediaEncoder mediaEncoder) + IMediaEncoder mediaEncoder, + IServerConfigurationManager config) { _logger = logger; _fileSystem = fileSystem; _imageEncoder = imageEncoder; _mediaEncoder = mediaEncoder; _appPaths = appPaths; + + var semaphoreCount = config.Configuration.ParallelImageEncodingLimit; + if (semaphoreCount < 1) + { + semaphoreCount = 2 * Environment.ProcessorCount; + } + + _parallelEncodingLimit = new(semaphoreCount, semaphoreCount); } private string ResizedImageCachePath => Path.Combine(_appPaths.ImageCachePath, "resized-images"); @@ -199,7 +213,18 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable { if (!File.Exists(cacheFilePath)) { - string resultPath = _imageEncoder.EncodeImage(originalImagePath, dateModified, cacheFilePath, autoOrient, orientation, quality, options, outputFormat); + // Limit number of parallel (more precisely: concurrent) image encodings to prevent a high memory usage + await _parallelEncodingLimit.WaitAsync().ConfigureAwait(false); + + string resultPath; + try + { + resultPath = _imageEncoder.EncodeImage(originalImagePath, dateModified, cacheFilePath, autoOrient, orientation, quality, options, outputFormat); + } + finally + { + _parallelEncodingLimit.Release(); + } if (string.Equals(resultPath, originalImagePath, StringComparison.OrdinalIgnoreCase)) { @@ -563,6 +588,8 @@ public sealed class ImageProcessor : IImageProcessor, IDisposable disposable.Dispose(); } + _parallelEncodingLimit?.Dispose(); + _disposed = true; } } -- cgit v1.2.3 From aa99aaebc4e37ca1e16c11f72dd4a57038200179 Mon Sep 17 00:00:00 2001 From: knackebrot Date: Mon, 7 Nov 2022 00:15:04 +0100 Subject: Add audio vbr calculation --- Jellyfin.Api/Controllers/DynamicHlsController.cs | 29 ++++++++-- .../MediaEncoding/EncodingHelper.cs | 64 +++++++++++++++++++++- .../Configuration/EncodingOptions.cs | 6 ++ 3 files changed, 91 insertions(+), 8 deletions(-) (limited to 'MediaBrowser.Model/Configuration') diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index 4d8b4de24f..7b1830761c 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -1685,14 +1685,25 @@ public class DynamicHlsController : BaseJellyfinApiController audioTranscodeParams += "-acodec " + audioCodec; - if (state.OutputAudioBitrate.HasValue) + var audioBitrate = state.OutputAudioBitrate; + var audioChannels = state.OutputAudioChannels; + + if (audioBitrate.HasValue) { - audioTranscodeParams += " -ab " + state.OutputAudioBitrate.Value.ToString(CultureInfo.InvariantCulture); + string vbrParam; + if (_encodingOptions.EnableAudioVbr && (vbrParam = _encodingHelper.GetAudioVbrModeParam(state.OutputAudioCodec, audioBitrate.Value / audioChannels ?? 2)) != null) + { + audioTranscodeParams += vbrParam; + } + else + { + audioTranscodeParams += " -ab " + audioBitrate.Value.ToString(CultureInfo.InvariantCulture); + } } - if (state.OutputAudioChannels.HasValue) + if (audioChannels.HasValue) { - audioTranscodeParams += " -ac " + state.OutputAudioChannels.Value.ToString(CultureInfo.InvariantCulture); + audioTranscodeParams += " -ac " + audioChannels.Value.ToString(CultureInfo.InvariantCulture); } if (state.OutputAudioSampleRate.HasValue) @@ -1747,7 +1758,15 @@ public class DynamicHlsController : BaseJellyfinApiController if (bitrate.HasValue) { - args += " -ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture); + string vbrParam; + if (_encodingOptions.EnableAudioVbr && (vbrParam = _encodingHelper.GetAudioVbrModeParam(state.OutputAudioCodec, bitrate.Value / channels ?? 2)) != null) + { + args += vbrParam; + } + else + { + args += " -ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture); + } } if (state.OutputAudioSampleRate.HasValue) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 648358b598..551160934d 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -2160,6 +2160,47 @@ namespace MediaBrowser.Controller.MediaEncoding return 128000; } + public string GetAudioVbrModeParam(string encoder, int bitratePerChannel) + { + if (encoder == "libfdk_aac") + { + return " -vbr:a " + bitratePerChannel switch + { + < 32000 => "1", + < 48000 => "2", + < 64000 => "3", + < 96000 => "4", + _ => "5" + }; + } + + if (encoder == "libmp3lame") + { + return " -qscale:a " + bitratePerChannel switch + { + < 48000 => "8", + < 64000 => "6", + < 88000 => "4", + < 112000 => "2", + _ => "0" + }; + } + + if (encoder == "libvorbis") + { + return " -qscale:a " + bitratePerChannel switch + { + < 40000 => "0", + < 56000 => "2", + < 80000 => "4", + < 112000 => "6", + _ => "8" + }; + } + + return null; + } + public string GetAudioFilterParam(EncodingJobInfo state, EncodingOptions encodingOptions) { var channels = state.OutputAudioChannels; @@ -5801,7 +5842,15 @@ namespace MediaBrowser.Controller.MediaEncoding if (bitrate.HasValue) { - args += " -ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture); + string vbrParam; + if (encodingOptions.EnableAudioVbr && (vbrParam = GetAudioVbrModeParam(codec, bitrate.Value / channels ?? 2)) != null) + { + args += vbrParam; + } + else + { + args += " -ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture); + } } if (state.OutputAudioSampleRate.HasValue) @@ -5819,13 +5868,22 @@ namespace MediaBrowser.Controller.MediaEncoding var audioTranscodeParams = new List(); var bitrate = state.OutputAudioBitrate; + var channels = state.OutputAudioChannels; if (bitrate.HasValue) { - audioTranscodeParams.Add("-ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture)); + string vbrParam; + if (encodingOptions.EnableAudioVbr && (vbrParam = GetAudioVbrModeParam(state.OutputAudioCodec, bitrate.Value / channels ?? 2)) != null) + { + audioTranscodeParams.Add(vbrParam); + } + else + { + audioTranscodeParams.Add("-ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture)); + } } - if (state.OutputAudioChannels.HasValue) + if (channels.HasValue) { audioTranscodeParams.Add("-ac " + state.OutputAudioChannels.Value.ToString(CultureInfo.InvariantCulture)); } diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs index 0ff95a2e1f..b43e0f024b 100644 --- a/MediaBrowser.Model/Configuration/EncodingOptions.cs +++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs @@ -14,6 +14,7 @@ public class EncodingOptions public EncodingOptions() { EnableFallbackFont = false; + EnableAudioVbr = false; DownMixAudioBoost = 2; DownMixStereoAlgorithm = DownMixStereoAlgorithms.None; MaxMuxingQueueSize = 2048; @@ -70,6 +71,11 @@ public class EncodingOptions /// public bool EnableFallbackFont { get; set; } + /// + /// Gets or sets a value indicating whether audio VBR is enabled. + /// + public bool EnableAudioVbr { get; set; } + /// /// Gets or sets the audio boost applied when downmixing audio. /// -- cgit v1.2.3 From 638bda629ba2fdceb58b0732f9c2cf4684edc115 Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Thu, 9 Mar 2023 19:35:54 -0500 Subject: Backport pull request #9391 from jellyfin/release-10.8.z Fix H.264 baseline hwaccel and enable enhanced Nvdec by default Original-merge: 22a8283a9e3425da0496c28e6737dfadf9c67b33 Merged-by: Bond-009 Backported-by: crobibero --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 17 +++++++++++++---- MediaBrowser.Model/Configuration/EncodingOptions.cs | 3 ++- 2 files changed, 15 insertions(+), 5 deletions(-) (limited to 'MediaBrowser.Model/Configuration') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index f07ac07513..0f3912e283 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -4909,6 +4909,10 @@ namespace MediaBrowser.Controller.MediaEncoding // Set the av1 codec explicitly to trigger hw accelerator, otherwise libdav1d will be used. var isAv1 = string.Equals(videoCodec, "av1", StringComparison.OrdinalIgnoreCase); + // Allow profile mismatch if decoding H.264 baseline with d3d11va and vaapi hwaccels. + var profileMismatch = string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase) + && string.Equals(state.VideoStream?.Profile, "baseline", StringComparison.OrdinalIgnoreCase); + if (bitDepth == 10 && isCodecAvailable) { if (string.Equals(videoCodec, "hevc", StringComparison.OrdinalIgnoreCase) @@ -4933,14 +4937,16 @@ namespace MediaBrowser.Controller.MediaEncoding { if (isVaapiSupported && isCodecAvailable) { - return " -hwaccel vaapi" + (outputHwSurface ? " -hwaccel_output_format vaapi" : string.Empty) + (isAv1 ? " -c:v av1" : string.Empty); + return " -hwaccel vaapi" + (outputHwSurface ? " -hwaccel_output_format vaapi" : string.Empty) + + (profileMismatch ? " -hwaccel_flags +allow_profile_mismatch" : string.Empty) + (isAv1 ? " -c:v av1" : string.Empty); } if (isD3d11Supported && isCodecAvailable) { // set -threads 3 to intel d3d11va decoder explicitly. Lower threads may result in dead lock. // on newer devices such as Xe, the larger the init_pool_size, the longer the initialization time for opencl to derive from d3d11. - return " -hwaccel d3d11va" + (outputHwSurface ? " -hwaccel_output_format d3d11" : string.Empty) + " -threads 3" + (isAv1 ? " -c:v av1" : string.Empty); + return " -hwaccel d3d11va" + (outputHwSurface ? " -hwaccel_output_format d3d11" : string.Empty) + + (profileMismatch ? " -hwaccel_flags +allow_profile_mismatch" : string.Empty) + " -threads 3" + (isAv1 ? " -c:v av1" : string.Empty); } } else @@ -4975,7 +4981,8 @@ namespace MediaBrowser.Controller.MediaEncoding { if (isD3d11Supported && isCodecAvailable) { - return " -hwaccel d3d11va" + (outputHwSurface ? " -hwaccel_output_format d3d11" : string.Empty) + (isAv1 ? " -c:v av1" : string.Empty); + return " -hwaccel d3d11va" + (outputHwSurface ? " -hwaccel_output_format d3d11" : string.Empty) + + (profileMismatch ? " -hwaccel_flags +allow_profile_mismatch" : string.Empty) + (isAv1 ? " -c:v av1" : string.Empty); } } @@ -4984,9 +4991,11 @@ namespace MediaBrowser.Controller.MediaEncoding && isVaapiSupported && isCodecAvailable) { - return " -hwaccel vaapi" + (outputHwSurface ? " -hwaccel_output_format vaapi" : string.Empty) + (isAv1 ? " -c:v av1" : string.Empty); + return " -hwaccel vaapi" + (outputHwSurface ? " -hwaccel_output_format vaapi" : string.Empty) + + (profileMismatch ? " -hwaccel_flags +allow_profile_mismatch" : string.Empty) + (isAv1 ? " -c:v av1" : string.Empty); } + // Apple videotoolbox if (string.Equals(options.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase) && isVideotoolboxSupported && isCodecAvailable) diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs index 0ff95a2e1f..f348d8417b 100644 --- a/MediaBrowser.Model/Configuration/EncodingOptions.cs +++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs @@ -39,7 +39,8 @@ public class EncodingOptions DeinterlaceMethod = "yadif"; EnableDecodingColorDepth10Hevc = true; EnableDecodingColorDepth10Vp9 = true; - EnableEnhancedNvdecDecoder = false; + // Enhanced Nvdec or system native decoder is required for DoVi to SDR tone-mapping. + EnableEnhancedNvdecDecoder = true; PreferSystemNativeHwDecoder = true; EnableIntelLowPowerH264HwEncoder = false; EnableIntelLowPowerHevcHwEncoder = false; -- cgit v1.2.3 From 21dcf775bee6459707435cc64bc3864f9e0eb0fe Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Tue, 14 Mar 2023 23:20:12 +0100 Subject: Add config option to disable dummy chapter generation (#9410) --- .../Configuration/ServerConfiguration.cs | 10 ++---- .../MediaInfo/FFProbeVideoInfo.cs | 40 +++++++++++----------- 2 files changed, 22 insertions(+), 28 deletions(-) (limited to 'MediaBrowser.Model/Configuration') diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index c39162250a..7cb07a2f7a 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -243,16 +243,10 @@ namespace MediaBrowser.Model.Configuration public bool AllowClientLogUpload { get; set; } = true; /// - /// Gets or sets the dummy chapters duration in seconds. + /// Gets or sets the dummy chapter duration in seconds, use 0 (zero) or less to disable generation alltogether. /// /// The dummy chapters duration. - public int DummyChapterDuration { get; set; } = 300; - - /// - /// Gets or sets the dummy chapter count. - /// - /// The dummy chapter count. - public int DummyChapterCount { get; set; } = 100; + public int DummyChapterDuration { get; set; } = 0; /// /// Gets or sets the chapter image resolution. diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index e199db7f2a..213639371a 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -298,7 +298,7 @@ namespace MediaBrowser.Providers.MediaInfo if (options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || options.MetadataRefreshMode == MetadataRefreshMode.Default) { - if (chapters.Length == 0 && mediaStreams.Any(i => i.Type == MediaStreamType.Video)) + if (_config.Configuration.DummyChapterDuration > 0 && chapters.Length == 0 && mediaStreams.Any(i => i.Type == MediaStreamType.Video)) { chapters = CreateDummyChapters(video); } @@ -662,39 +662,39 @@ namespace MediaBrowser.Providers.MediaInfo private ChapterInfo[] CreateDummyChapters(Video video) { var runtime = video.RunTimeTicks ?? 0; - long dummyChapterDuration = TimeSpan.FromSeconds(_config.Configuration.DummyChapterDuration).Ticks; - if (runtime < 0) + // Only process files with a runtime higher than 0 and lower than 12h. The latter are likely corrupted. + if (runtime < 0 || runtime > TimeSpan.FromHours(12).Ticks) { throw new ArgumentException( string.Format( CultureInfo.InvariantCulture, - "{0} has invalid runtime of {1}", + "{0} has an invalid runtime of {1} minutes", video.Name, - runtime)); + TimeSpan.FromTicks(runtime).Minutes)); } - if (runtime < dummyChapterDuration) + long dummyChapterDuration = TimeSpan.FromSeconds(_config.Configuration.DummyChapterDuration).Ticks; + if (runtime > dummyChapterDuration) { - return Array.Empty(); - } + int chapterCount = (int)(runtime / dummyChapterDuration); + var chapters = new ChapterInfo[chapterCount]; - // Limit the chapters just in case there's some incorrect metadata here - int chapterCount = (int)Math.Min(runtime / dummyChapterDuration, _config.Configuration.DummyChapterCount); - var chapters = new ChapterInfo[chapterCount]; - - long currentChapterTicks = 0; - for (int i = 0; i < chapterCount; i++) - { - chapters[i] = new ChapterInfo + long currentChapterTicks = 0; + for (int i = 0; i < chapterCount; i++) { - StartPositionTicks = currentChapterTicks - }; + chapters[i] = new ChapterInfo + { + StartPositionTicks = currentChapterTicks + }; + + currentChapterTicks += dummyChapterDuration; + } - currentChapterTicks += dummyChapterDuration; + return chapters; } - return chapters; + return Array.Empty(); } } } -- cgit v1.2.3 From 26958162d01ea9557d80f384face93012f70b821 Mon Sep 17 00:00:00 2001 From: Stepan Goremykin Date: Thu, 6 Apr 2023 18:41:25 +0200 Subject: Remove unused using directives --- Emby.Dlna/Main/DlnaEntryPoint.cs | 1 - Emby.Server.Implementations/Dto/DtoService.cs | 1 - Jellyfin.Api/Controllers/FilterController.cs | 1 - Jellyfin.Api/Controllers/QuickConnectController.cs | 2 -- Jellyfin.Api/Controllers/SearchController.cs | 1 - Jellyfin.Api/Controllers/UniversalAudioController.cs | 1 - Jellyfin.Server.Implementations/Security/AuthorizationContext.cs | 1 - Jellyfin.Server/CoreAppHost.cs | 1 - Jellyfin.Server/Startup.cs | 1 - MediaBrowser.Controller/Lyrics/LyricMetadata.cs | 2 -- MediaBrowser.Controller/Session/ISessionManager.cs | 1 - MediaBrowser.Controller/Subtitles/ISubtitleManager.cs | 1 - MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs | 1 - MediaBrowser.Model/Configuration/ServerConfiguration.cs | 1 - MediaBrowser.Providers/Lyric/TxtLyricProvider.cs | 1 - src/Jellyfin.Extensions/Json/Converters/JsonBoolStringConverter.cs | 1 - src/Jellyfin.Extensions/StringExtensions.cs | 2 -- .../Auth/FirstTimeSetupPolicy/FirstTimeSetupHandlerTests.cs | 1 - tests/Jellyfin.Api.Tests/Controllers/ImageControllerTests.cs | 1 - 19 files changed, 22 deletions(-) (limited to 'MediaBrowser.Model/Configuration') diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs index aab475153b..39cfc2d1d4 100644 --- a/Emby.Dlna/Main/DlnaEntryPoint.cs +++ b/Emby.Dlna/Main/DlnaEntryPoint.cs @@ -7,7 +7,6 @@ using System.Globalization; using System.Linq; using System.Net.Http; using System.Net.Sockets; -using System.Runtime.InteropServices; using System.Threading.Tasks; using Emby.Dlna.PlayTo; using Emby.Dlna.Ssdp; diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 8b66829032..c725839fba 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -7,7 +7,6 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; -using Jellyfin.Api.Helpers; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Extensions; diff --git a/Jellyfin.Api/Controllers/FilterController.cs b/Jellyfin.Api/Controllers/FilterController.cs index dac07429ff..d51a5325f5 100644 --- a/Jellyfin.Api/Controllers/FilterController.cs +++ b/Jellyfin.Api/Controllers/FilterController.cs @@ -1,6 +1,5 @@ using System; using System.Linq; -using Jellyfin.Api.Constants; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Enums; diff --git a/Jellyfin.Api/Controllers/QuickConnectController.cs b/Jellyfin.Api/Controllers/QuickConnectController.cs index d7e54b5b6a..14f5265aa7 100644 --- a/Jellyfin.Api/Controllers/QuickConnectController.cs +++ b/Jellyfin.Api/Controllers/QuickConnectController.cs @@ -1,8 +1,6 @@ using System; using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; -using Jellyfin.Api.Constants; -using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Authentication; diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs index f638c31c39..387b3ea5a6 100644 --- a/Jellyfin.Api/Controllers/SearchController.cs +++ b/Jellyfin.Api/Controllers/SearchController.cs @@ -3,7 +3,6 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Globalization; using System.Linq; -using Jellyfin.Api.Constants; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Enums; diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index 12d033ae63..2e9035d24f 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -5,7 +5,6 @@ using System.Globalization; using System.Linq; using System.Threading.Tasks; using Jellyfin.Api.Attributes; -using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Api.Models.StreamingDtos; diff --git a/Jellyfin.Server.Implementations/Security/AuthorizationContext.cs b/Jellyfin.Server.Implementations/Security/AuthorizationContext.cs index 63d3e8a04c..700e639700 100644 --- a/Jellyfin.Server.Implementations/Security/AuthorizationContext.cs +++ b/Jellyfin.Server.Implementations/Security/AuthorizationContext.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Net; using System.Threading.Tasks; -using EFCoreSecondLevelCacheInterceptor; using MediaBrowser.Controller; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs index 40cd5a0446..939376dd8d 100644 --- a/Jellyfin.Server/CoreAppHost.cs +++ b/Jellyfin.Server/CoreAppHost.cs @@ -22,7 +22,6 @@ using MediaBrowser.Controller.Lyrics; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Security; using MediaBrowser.Model.Activity; -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; diff --git a/Jellyfin.Server/Startup.cs b/Jellyfin.Server/Startup.cs index 155f9fc8c1..56f5c4796e 100644 --- a/Jellyfin.Server/Startup.cs +++ b/Jellyfin.Server/Startup.cs @@ -4,7 +4,6 @@ using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Net.Mime; -using System.Runtime.InteropServices; using System.Text; using Jellyfin.Api.Middleware; using Jellyfin.MediaEncoding.Hls.Extensions; diff --git a/MediaBrowser.Controller/Lyrics/LyricMetadata.cs b/MediaBrowser.Controller/Lyrics/LyricMetadata.cs index 6091ede52a..c4f0334892 100644 --- a/MediaBrowser.Controller/Lyrics/LyricMetadata.cs +++ b/MediaBrowser.Controller/Lyrics/LyricMetadata.cs @@ -1,5 +1,3 @@ -using System; - namespace MediaBrowser.Controller.Lyrics; /// diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index eefc5d222e..0c4719a0e5 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -7,7 +7,6 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities.Security; -using Jellyfin.Data.Events; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Session; diff --git a/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs b/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs index b86e482435..fcfc18a644 100644 --- a/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs +++ b/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs @@ -1,7 +1,6 @@ #pragma warning disable CS1591 using System; -using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Entities; diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs index ea520b1d6b..55480253dd 100644 --- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs +++ b/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs @@ -1,4 +1,3 @@ -using System; using System.IO; using System.Linq; using BDInfo.IO; diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 7cb07a2f7a..07f02d1879 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -2,7 +2,6 @@ #pragma warning disable CA1819 using System; -using System.Collections.Generic; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Updates; diff --git a/MediaBrowser.Providers/Lyric/TxtLyricProvider.cs b/MediaBrowser.Providers/Lyric/TxtLyricProvider.cs index 96a9e9dcf3..a9099d1927 100644 --- a/MediaBrowser.Providers/Lyric/TxtLyricProvider.cs +++ b/MediaBrowser.Providers/Lyric/TxtLyricProvider.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.IO; -using System.Linq; using System.Threading.Tasks; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Lyrics; diff --git a/src/Jellyfin.Extensions/Json/Converters/JsonBoolStringConverter.cs b/src/Jellyfin.Extensions/Json/Converters/JsonBoolStringConverter.cs index 2936fe4d6d..6895eadb86 100644 --- a/src/Jellyfin.Extensions/Json/Converters/JsonBoolStringConverter.cs +++ b/src/Jellyfin.Extensions/Json/Converters/JsonBoolStringConverter.cs @@ -1,7 +1,6 @@ using System; using System.Buffers; using System.Buffers.Text; -using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; diff --git a/src/Jellyfin.Extensions/StringExtensions.cs b/src/Jellyfin.Extensions/StringExtensions.cs index 7c61248757..b22eb7c4ea 100644 --- a/src/Jellyfin.Extensions/StringExtensions.cs +++ b/src/Jellyfin.Extensions/StringExtensions.cs @@ -1,6 +1,4 @@ using System; -using System.Globalization; -using System.Text; using System.Text.RegularExpressions; namespace Jellyfin.Extensions diff --git a/tests/Jellyfin.Api.Tests/Auth/FirstTimeSetupPolicy/FirstTimeSetupHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/FirstTimeSetupPolicy/FirstTimeSetupHandlerTests.cs index 6669a6689c..1ea1797ba1 100644 --- a/tests/Jellyfin.Api.Tests/Auth/FirstTimeSetupPolicy/FirstTimeSetupHandlerTests.cs +++ b/tests/Jellyfin.Api.Tests/Auth/FirstTimeSetupPolicy/FirstTimeSetupHandlerTests.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Threading.Tasks; using AutoFixture; using AutoFixture.AutoMoq; -using Jellyfin.Api.Auth.DefaultAuthorizationPolicy; using Jellyfin.Api.Auth.FirstTimeSetupPolicy; using Jellyfin.Api.Constants; using MediaBrowser.Common.Configuration; diff --git a/tests/Jellyfin.Api.Tests/Controllers/ImageControllerTests.cs b/tests/Jellyfin.Api.Tests/Controllers/ImageControllerTests.cs index d6428fb2cd..0254a1ec6e 100644 --- a/tests/Jellyfin.Api.Tests/Controllers/ImageControllerTests.cs +++ b/tests/Jellyfin.Api.Tests/Controllers/ImageControllerTests.cs @@ -1,4 +1,3 @@ -using System; using Jellyfin.Api.Controllers; using Xunit; -- cgit v1.2.3 From 603fce59df780626c3269eaa94d95504e823b2f6 Mon Sep 17 00:00:00 2001 From: TelepathicWalrus <48514138+TelepathicWalrus@users.noreply.github.com> Date: Mon, 15 May 2023 12:12:24 +0100 Subject: Audio normalization (#9222) Co-authored-by: Joe Rogers <1337joe@users.noreply.github.com> Co-authored-by: Bond-009 --- CONTRIBUTORS.md | 1 + .../Data/SqliteItemRepository.cs | 12 ++++- Emby.Server.Implementations/Dto/DtoService.cs | 1 + MediaBrowser.Controller/Entities/BaseItem.cs | 7 +++ MediaBrowser.Model/Configuration/LibraryOptions.cs | 2 + MediaBrowser.Model/Dto/BaseItemDto.cs | 6 +++ .../MediaInfo/AudioFileProber.cs | 60 ++++++++++++++++++++++ MediaBrowser.Providers/MediaInfo/ProbeProvider.cs | 2 +- 8 files changed, 88 insertions(+), 3 deletions(-) (limited to 'MediaBrowser.Model/Configuration') diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index c9430b235f..0b322685d1 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -126,6 +126,7 @@ - [SuperSandro2000](https://github.com/SuperSandro2000) - [tbraeutigam](https://github.com/tbraeutigam) - [teacupx](https://github.com/teacupx) + - [TelepathicWalrus](https://github.com/TelepathicWalrus) - [Terror-Gene](https://github.com/Terror-Gene) - [ThatNerdyPikachu](https://github.com/ThatNerdyPikachu) - [ThibaultNocchi](https://github.com/ThibaultNocchi) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 22d485d335..c32e7c75ad 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -49,8 +49,8 @@ namespace Emby.Server.Implementations.Data private const string SaveItemCommandText = @"replace into TypedBaseItems - (guid,type,data,Path,StartDate,EndDate,ChannelId,IsMovie,IsSeries,EpisodeTitle,IsRepeat,CommunityRating,CustomRating,IndexNumber,IsLocked,Name,OfficialRating,MediaType,Overview,ParentIndexNumber,PremiereDate,ProductionYear,ParentId,Genres,InheritedParentalRatingValue,SortName,ForcedSortName,RunTimeTicks,Size,DateCreated,DateModified,PreferredMetadataLanguage,PreferredMetadataCountryCode,Width,Height,DateLastRefreshed,DateLastSaved,IsInMixedFolder,LockedFields,Studios,Audio,ExternalServiceId,Tags,IsFolder,UnratedType,TopParentId,TrailerTypes,CriticRating,CleanName,PresentationUniqueKey,OriginalTitle,PrimaryVersionId,DateLastMediaAdded,Album,IsVirtualItem,SeriesName,UserDataKey,SeasonName,SeasonId,SeriesId,ExternalSeriesId,Tagline,ProviderIds,Images,ProductionLocations,ExtraIds,TotalBitrate,ExtraType,Artists,AlbumArtists,ExternalId,SeriesPresentationUniqueKey,ShowId,OwnerId) - values (@guid,@type,@data,@Path,@StartDate,@EndDate,@ChannelId,@IsMovie,@IsSeries,@EpisodeTitle,@IsRepeat,@CommunityRating,@CustomRating,@IndexNumber,@IsLocked,@Name,@OfficialRating,@MediaType,@Overview,@ParentIndexNumber,@PremiereDate,@ProductionYear,@ParentId,@Genres,@InheritedParentalRatingValue,@SortName,@ForcedSortName,@RunTimeTicks,@Size,@DateCreated,@DateModified,@PreferredMetadataLanguage,@PreferredMetadataCountryCode,@Width,@Height,@DateLastRefreshed,@DateLastSaved,@IsInMixedFolder,@LockedFields,@Studios,@Audio,@ExternalServiceId,@Tags,@IsFolder,@UnratedType,@TopParentId,@TrailerTypes,@CriticRating,@CleanName,@PresentationUniqueKey,@OriginalTitle,@PrimaryVersionId,@DateLastMediaAdded,@Album,@IsVirtualItem,@SeriesName,@UserDataKey,@SeasonName,@SeasonId,@SeriesId,@ExternalSeriesId,@Tagline,@ProviderIds,@Images,@ProductionLocations,@ExtraIds,@TotalBitrate,@ExtraType,@Artists,@AlbumArtists,@ExternalId,@SeriesPresentationUniqueKey,@ShowId,@OwnerId)"; + (guid,type,data,Path,StartDate,EndDate,ChannelId,IsMovie,IsSeries,EpisodeTitle,IsRepeat,CommunityRating,CustomRating,IndexNumber,IsLocked,Name,OfficialRating,MediaType,Overview,ParentIndexNumber,PremiereDate,ProductionYear,ParentId,Genres,InheritedParentalRatingValue,SortName,ForcedSortName,RunTimeTicks,Size,DateCreated,DateModified,PreferredMetadataLanguage,PreferredMetadataCountryCode,Width,Height,DateLastRefreshed,DateLastSaved,IsInMixedFolder,LockedFields,Studios,Audio,ExternalServiceId,Tags,IsFolder,UnratedType,TopParentId,TrailerTypes,CriticRating,CleanName,PresentationUniqueKey,OriginalTitle,PrimaryVersionId,DateLastMediaAdded,Album,LUFS,IsVirtualItem,SeriesName,UserDataKey,SeasonName,SeasonId,SeriesId,ExternalSeriesId,Tagline,ProviderIds,Images,ProductionLocations,ExtraIds,TotalBitrate,ExtraType,Artists,AlbumArtists,ExternalId,SeriesPresentationUniqueKey,ShowId,OwnerId) + values (@guid,@type,@data,@Path,@StartDate,@EndDate,@ChannelId,@IsMovie,@IsSeries,@EpisodeTitle,@IsRepeat,@CommunityRating,@CustomRating,@IndexNumber,@IsLocked,@Name,@OfficialRating,@MediaType,@Overview,@ParentIndexNumber,@PremiereDate,@ProductionYear,@ParentId,@Genres,@InheritedParentalRatingValue,@SortName,@ForcedSortName,@RunTimeTicks,@Size,@DateCreated,@DateModified,@PreferredMetadataLanguage,@PreferredMetadataCountryCode,@Width,@Height,@DateLastRefreshed,@DateLastSaved,@IsInMixedFolder,@LockedFields,@Studios,@Audio,@ExternalServiceId,@Tags,@IsFolder,@UnratedType,@TopParentId,@TrailerTypes,@CriticRating,@CleanName,@PresentationUniqueKey,@OriginalTitle,@PrimaryVersionId,@DateLastMediaAdded,@Album,@LUFS,@IsVirtualItem,@SeriesName,@UserDataKey,@SeasonName,@SeasonId,@SeriesId,@ExternalSeriesId,@Tagline,@ProviderIds,@Images,@ProductionLocations,@ExtraIds,@TotalBitrate,@ExtraType,@Artists,@AlbumArtists,@ExternalId,@SeriesPresentationUniqueKey,@ShowId,@OwnerId)"; private readonly IServerConfigurationManager _config; private readonly IServerApplicationHost _appHost; @@ -110,6 +110,7 @@ namespace Emby.Server.Implementations.Data "PrimaryVersionId", "DateLastMediaAdded", "Album", + "LUFS", "CriticRating", "IsVirtualItem", "SeriesName", @@ -489,6 +490,7 @@ namespace Emby.Server.Implementations.Data AddColumn(db, "TypedBaseItems", "PrimaryVersionId", "Text", existingColumnNames); AddColumn(db, "TypedBaseItems", "DateLastMediaAdded", "DATETIME", existingColumnNames); AddColumn(db, "TypedBaseItems", "Album", "Text", existingColumnNames); + AddColumn(db, "TypedBaseItems", "LUFS", "Float", existingColumnNames); AddColumn(db, "TypedBaseItems", "IsVirtualItem", "BIT", existingColumnNames); AddColumn(db, "TypedBaseItems", "SeriesName", "Text", existingColumnNames); AddColumn(db, "TypedBaseItems", "UserDataKey", "Text", existingColumnNames); @@ -906,6 +908,7 @@ namespace Emby.Server.Implementations.Data } saveItemStatement.TryBind("@Album", item.Album); + saveItemStatement.TryBind("@LUFS", item.LUFS); saveItemStatement.TryBind("@IsVirtualItem", item.IsVirtualItem); if (item is IHasSeries hasSeriesName) @@ -1756,6 +1759,11 @@ namespace Emby.Server.Implementations.Data item.Album = album; } + if (reader.TryGetSingle(index++, out var lUFS)) + { + item.LUFS = lUFS; + } + if (reader.TryGetSingle(index++, out var criticRating)) { item.CriticRating = criticRating; diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 8fa2f05662..7a6ed2cb80 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -906,6 +906,7 @@ namespace Emby.Server.Implementations.Dto // Add audio info if (item is Audio audio) { + dto.LUFS = audio.LUFS; dto.Album = audio.Album; if (audio.ExtraType.HasValue) { diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index adc7b2f953..1e868194e6 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -128,6 +128,13 @@ namespace MediaBrowser.Controller.Entities [JsonIgnore] public string Album { get; set; } + /// + /// Gets or sets the LUFS value. + /// + /// The LUFS Value. + [JsonIgnore] + public float LUFS { get; set; } + /// /// Gets or sets the channel identifier. /// diff --git a/MediaBrowser.Model/Configuration/LibraryOptions.cs b/MediaBrowser.Model/Configuration/LibraryOptions.cs index 81f2f02bc5..df68299465 100644 --- a/MediaBrowser.Model/Configuration/LibraryOptions.cs +++ b/MediaBrowser.Model/Configuration/LibraryOptions.cs @@ -30,6 +30,8 @@ namespace MediaBrowser.Model.Configuration public bool EnableRealtimeMonitor { get; set; } + public bool EnableLUFSScan { get; set; } + public bool EnableChapterImageExtraction { get; set; } public bool ExtractChapterImagesDuringLibraryScan { get; set; } diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index 2a86fded22..27154c2978 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -779,6 +779,12 @@ namespace MediaBrowser.Model.Dto /// The timer identifier. public string TimerId { get; set; } + /// + /// Gets or sets the LUFS value. + /// + /// The LUFS Value. + public float LUFS { get; set; } + /// /// Gets or sets the current program. /// diff --git a/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs b/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs index b8578c46f8..e1dcbc9939 100644 --- a/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs +++ b/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs @@ -1,6 +1,9 @@ using System; using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; using System.Linq; +using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Enums; @@ -14,6 +17,7 @@ using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.MediaInfo; +using Microsoft.Extensions.Logging; using TagLib; namespace MediaBrowser.Providers.MediaInfo @@ -23,6 +27,10 @@ namespace MediaBrowser.Providers.MediaInfo /// public class AudioFileProber { + // Default LUFS value for use with the web interface, at -18db gain will be 1(no db gain). + private const float DefaultLUFSValue = -18; + + private readonly ILogger _logger; private readonly IMediaEncoder _mediaEncoder; private readonly IItemRepository _itemRepo; private readonly ILibraryManager _libraryManager; @@ -31,16 +39,19 @@ namespace MediaBrowser.Providers.MediaInfo /// /// Initializes a new instance of the class. /// + /// Instance of the interface. /// Instance of the interface. /// Instance of the interface. /// Instance of the interface. /// Instance of the interface. public AudioFileProber( + ILogger logger, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, ILibraryManager libraryManager) { + _logger = logger; _mediaEncoder = mediaEncoder; _itemRepo = itemRepo; _libraryManager = libraryManager; @@ -89,6 +100,54 @@ namespace MediaBrowser.Providers.MediaInfo Fetch(item, result, cancellationToken); } + var libraryOptions = _libraryManager.GetLibraryOptions(item); + + if (libraryOptions.EnableLUFSScan) + { + string output; + using (var process = new Process() + { + StartInfo = new ProcessStartInfo + { + FileName = _mediaEncoder.EncoderPath, + Arguments = $"-hide_banner -i \"{path}\" -af ebur128=framelog=verbose -f null -", + RedirectStandardOutput = false, + RedirectStandardError = true + }, + }) + { + try + { + process.Start(); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error starting ffmpeg"); + + throw; + } + + output = await process.StandardError.ReadToEndAsync(cancellationToken).ConfigureAwait(false); + cancellationToken.ThrowIfCancellationRequested(); + MatchCollection split = Regex.Matches(output, @"I:\s+(.*?)\s+LUFS"); + + if (split.Count != 0) + { + item.LUFS = float.Parse(split[0].Groups[1].ValueSpan, CultureInfo.InvariantCulture.NumberFormat); + } + else + { + item.LUFS = DefaultLUFSValue; + } + } + } + else + { + item.LUFS = DefaultLUFSValue; + } + + _logger.LogDebug("LUFS for {ItemName} is {LUFS}.", item.Name, item.LUFS); + return ItemUpdateType.MetadataImport; } @@ -196,6 +255,7 @@ namespace MediaBrowser.Providers.MediaInfo audio.Album = tags.Album; audio.IndexNumber = Convert.ToInt32(tags.Track); audio.ParentIndexNumber = Convert.ToInt32(tags.Disc); + if (tags.Year != 0) { var year = Convert.ToInt32(tags.Year); diff --git a/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs index 2800219552..114a929753 100644 --- a/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs @@ -79,7 +79,7 @@ namespace MediaBrowser.Providers.MediaInfo NamingOptions namingOptions) { _logger = loggerFactory.CreateLogger(); - _audioProber = new AudioFileProber(mediaSourceManager, mediaEncoder, itemRepo, libraryManager); + _audioProber = new AudioFileProber(loggerFactory.CreateLogger(), mediaSourceManager, mediaEncoder, itemRepo, libraryManager); _audioResolver = new AudioResolver(loggerFactory.CreateLogger(), localization, mediaEncoder, fileSystem, namingOptions); _subtitleResolver = new SubtitleResolver(loggerFactory.CreateLogger(), localization, mediaEncoder, fileSystem, namingOptions); _videoProber = new FFProbeVideoInfo( -- cgit v1.2.3 From 4c8d3827658342b630472cc4dc1601ae56ffe39c Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Tue, 13 Jun 2023 10:53:35 -0400 Subject: Backport pull request #9642 from jellyfin/release-10.8.z Fix the brightness of VPP tonemap and add the tonemap mode Original-merge: d5a8419bc52ba06c070012849ba166dd2fbff8b0 Merged-by: Cody Robibero Backported-by: Bond_009 --- .../MediaEncoding/EncodingHelper.cs | 23 +++++++++++++++++----- .../Configuration/EncodingOptions.cs | 16 +++++++-------- 2 files changed, 26 insertions(+), 13 deletions(-) (limited to 'MediaBrowser.Model/Configuration') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 906a04a610..b6fa49fcd3 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -45,6 +45,7 @@ namespace MediaBrowser.Controller.MediaEncoding private readonly Version _minFFmpegImplictHwaccel = new Version(6, 0); private readonly Version _minFFmpegHwaUnsafeOutput = new Version(6, 0); + private readonly Version _minFFmpegOclCuTonemapMode = new Version(5, 1, 3); private static readonly string[] _videoProfilesH264 = new[] { @@ -2929,7 +2930,7 @@ namespace MediaBrowser.Controller.MediaEncoding return string.Empty; } - public static string GetHwTonemapFilter(EncodingOptions options, string hwTonemapSuffix, string videoFormat) + public string GetHwTonemapFilter(EncodingOptions options, string hwTonemapSuffix, string videoFormat) { if (string.IsNullOrEmpty(hwTonemapSuffix)) { @@ -2941,7 +2942,8 @@ namespace MediaBrowser.Controller.MediaEncoding if (string.Equals(hwTonemapSuffix, "vaapi", StringComparison.OrdinalIgnoreCase)) { - args = "tonemap_vaapi=format={0}:p=bt709:t=bt709:m=bt709,procamp_vaapi=b={1}:c={2}:extra_hw_frames=16"; + args = "procamp_vaapi=b={2}:c={3}," + args + ":extra_hw_frames=32"; + return string.Format( CultureInfo.InvariantCulture, args, @@ -2972,14 +2974,24 @@ namespace MediaBrowser.Controller.MediaEncoding { args = "tonemap_{0}=format={1}:p=bt709:t=bt709:m=bt709:tonemap={2}:peak={3}:desat={4}"; + if (string.Equals(options.TonemappingMode, "max", StringComparison.OrdinalIgnoreCase) + || string.Equals(options.TonemappingMode, "rgb", StringComparison.OrdinalIgnoreCase)) + { + if (_mediaEncoder.EncoderVersion >= _minFFmpegOclCuTonemapMode) + { + args += ":tonemap_mode={5}"; + } + } + if (options.TonemappingParam != 0) { - args += ":param={5}"; + args += ":param={6}"; } - if (!string.Equals(options.TonemappingRange, "auto", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(options.TonemappingRange, "tv", StringComparison.OrdinalIgnoreCase) + || string.Equals(options.TonemappingRange, "pc", StringComparison.OrdinalIgnoreCase)) { - args += ":range={6}"; + args += ":range={7}"; } } @@ -2991,6 +3003,7 @@ namespace MediaBrowser.Controller.MediaEncoding algorithm, options.TonemappingPeak, options.TonemappingDesat, + options.TonemappingMode, options.TonemappingParam, options.TonemappingRange); } diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs index f9f63f751a..ac2f1e71a3 100644 --- a/MediaBrowser.Model/Configuration/EncodingOptions.cs +++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs @@ -27,13 +27,13 @@ public class EncodingOptions EnableTonemapping = false; EnableVppTonemapping = false; TonemappingAlgorithm = "bt2390"; + TonemappingMode = "auto"; TonemappingRange = "auto"; TonemappingDesat = 0; - TonemappingThreshold = 0.8; TonemappingPeak = 100; TonemappingParam = 0; - VppTonemappingBrightness = 0; - VppTonemappingContrast = 1.2; + VppTonemappingBrightness = 16; + VppTonemappingContrast = 1; H264Crf = 23; H265Crf = 28; DeinterlaceDoubleRate = false; @@ -137,6 +137,11 @@ public class EncodingOptions /// public string TonemappingAlgorithm { get; set; } + /// + /// Gets or sets the tone-mapping mode. + /// + public string TonemappingMode { get; set; } + /// /// Gets or sets the tone-mapping range. /// @@ -147,11 +152,6 @@ public class EncodingOptions /// public double TonemappingDesat { get; set; } - /// - /// Gets or sets the tone-mapping threshold. - /// - public double TonemappingThreshold { get; set; } - /// /// Gets or sets the tone-mapping peak. /// -- cgit v1.2.3