From 6744e712d3a4fd6f800e5499c90b247787e48cb6 Mon Sep 17 00:00:00 2001 From: nicknsy <20588554+nicknsy@users.noreply.github.com> Date: Sat, 25 Feb 2023 15:59:46 -0800 Subject: [PATCH] Use config values --- .../MediaEncoding/IMediaEncoder.cs | 13 +++-- .../Encoder/MediaEncoder.cs | 37 +++++++++----- .../Configuration/ServerConfiguration.cs | 2 + .../Trickplay/TrickplayImagesTask.cs | 12 +++-- .../Trickplay/TrickplayManager.cs | 49 +++++++++++++------ .../Trickplay/TrickplayProvider.cs | 16 +++--- 6 files changed, 89 insertions(+), 40 deletions(-) diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index aa9faa9369..f5e3d03cbc 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.Configuration; @@ -145,10 +146,12 @@ namespace MediaBrowser.Controller.MediaEncoding /// Video container type. /// Media source information. /// Media stream information. - /// The interval. /// The maximum width. + /// The interval. /// Allow for hardware acceleration. - /// Allow for hardware encoding. allowHwAccel must also be true. + /// The input/output thread count for ffmpeg. + /// The qscale value for ffmpeg. + /// The process priority for the ffmpeg process. /// EncodingHelper instance. /// The cancellation token. /// Directory where images where extracted. A given image made before another will always be named with a lower number. @@ -157,10 +160,12 @@ namespace MediaBrowser.Controller.MediaEncoding string container, MediaSourceInfo mediaSource, MediaStream imageStream, - TimeSpan interval, int maxWidth, + TimeSpan interval, bool allowHwAccel, - bool allowHwEncode, + int? threads, + int? qualityScale, + ProcessPriorityClass? priority, EncodingHelper encodingHelper, CancellationToken cancellationToken); diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 9b58f83b48..11f42c3f96 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -783,14 +783,17 @@ namespace MediaBrowser.MediaEncoding.Encoder string container, MediaSourceInfo mediaSource, MediaStream imageStream, - TimeSpan interval, int maxWidth, + TimeSpan interval, bool allowHwAccel, - bool allowHwEncode, + int? threads, + int? qualityScale, + ProcessPriorityClass? priority, EncodingHelper encodingHelper, CancellationToken cancellationToken) { var options = allowHwAccel ? _configurationManager.GetEncodingOptions() : new EncodingOptions(); + threads = threads ?? _threads; // A new EncodingOptions instance must be used as to not disable HW acceleration for all of Jellyfin. // Additionally, we must set a few fields without defaults to prevent null pointer exceptions. @@ -822,7 +825,7 @@ namespace MediaBrowser.MediaEncoding.Encoder if (!allowHwAccel) { - inputArg = "-threads " + _threads + " " + inputArg; // HW accel args set a different input thread count, only set if disabled + inputArg = "-threads " + threads + " " + inputArg; // HW accel args set a different input thread count, only set if disabled } var filterParam = encodingHelper.GetVideoProcessingFilterParam(jobState, options, jobState.OutputVideoCodec).Trim(); @@ -831,7 +834,7 @@ namespace MediaBrowser.MediaEncoding.Encoder throw new InvalidOperationException("EncodingHelper returned empty or invalid filter parameters."); } - return ExtractVideoImagesOnIntervalInternal(inputArg, filterParam, interval, vidEncoder, _threads, cancellationToken); + return ExtractVideoImagesOnIntervalInternal(inputArg, filterParam, interval, vidEncoder, threads, qualityScale, priority, cancellationToken); } private async Task ExtractVideoImagesOnIntervalInternal( @@ -839,7 +842,9 @@ namespace MediaBrowser.MediaEncoding.Encoder string filterParam, TimeSpan interval, string vidEncoder, - int outputThreads, + int? outputThreads, + int? qualityScale, + ProcessPriorityClass? priority, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(inputArg)) @@ -857,10 +862,6 @@ namespace MediaBrowser.MediaEncoding.Encoder { filterParam = filterParam.Insert(filterParam.IndexOf("\"", StringComparison.Ordinal) + 1, fps + ","); } - else - { - filterParam += fps + ","; - } var targetDirectory = Path.Combine(_configurationManager.ApplicationPaths.TempDirectory, Guid.NewGuid().ToString("N")); Directory.CreateDirectory(targetDirectory); @@ -869,11 +870,12 @@ namespace MediaBrowser.MediaEncoding.Encoder // Final command arguments var args = string.Format( CultureInfo.InvariantCulture, - "-loglevel error {0} -an -sn {1} -threads {2} -c:v {3} -f {4} \"{5}\"", + "-loglevel error {0} -an -sn {1} -threads {2} -c:v {3} {4}-f {5} \"{6}\"", inputArg, filterParam, - outputThreads, + outputThreads.GetValueOrDefault(_threads), vidEncoder, + qualityScale.HasValue ? "-qscale:v " + qualityScale.Value.ToString(CultureInfo.InvariantCulture) + " " : string.Empty, "image2", outputPath); @@ -904,6 +906,19 @@ namespace MediaBrowser.MediaEncoding.Encoder { StartProcess(processWrapper); + // Set process priority + if (priority.HasValue) + { + try + { + processWrapper.Process.PriorityClass = priority.Value; + } + catch (Exception ex) + { + _logger.LogDebug(ex, "Unable to set process priority to {Priority} for {Description}", priority.Value, processDescription); + } + } + // Need to give ffmpeg enough time to make all the thumbnails, which could be a while, // but we still need to detect if the process hangs. // Making the assumption that as long as new jpegs are showing up, everything is good. diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 78a310f0b1..097eff295a 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -264,5 +264,7 @@ namespace MediaBrowser.Model.Configuration /// /// The limit for parallel image encoding. public int ParallelImageEncodingLimit { get; set; } + + public TrickplayOptions TrickplayOptions { get; set; } = new TrickplayOptions(); } } diff --git a/MediaBrowser.Providers/Trickplay/TrickplayImagesTask.cs b/MediaBrowser.Providers/Trickplay/TrickplayImagesTask.cs index 87ac145d75..a364926c01 100644 --- a/MediaBrowser.Providers/Trickplay/TrickplayImagesTask.cs +++ b/MediaBrowser.Providers/Trickplay/TrickplayImagesTask.cs @@ -22,7 +22,6 @@ namespace MediaBrowser.Providers.Trickplay private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; private readonly ILocalizationManager _localization; - private readonly IServerConfigurationManager _configurationManager; private readonly ITrickplayManager _trickplayManager; /// @@ -31,19 +30,16 @@ namespace MediaBrowser.Providers.Trickplay /// The logger. /// The library manager. /// The localization manager. - /// The configuration manager. /// The trickplay manager. public TrickplayImagesTask( ILogger logger, ILibraryManager libraryManager, ILocalizationManager localization, - IServerConfigurationManager configurationManager, ITrickplayManager trickplayManager) { _libraryManager = libraryManager; _logger = logger; _localization = localization; - _configurationManager = configurationManager; _trickplayManager = trickplayManager; } @@ -77,6 +73,14 @@ namespace MediaBrowser.Providers.Trickplay public async Task ExecuteAsync(IProgress progress, CancellationToken cancellationToken) { // TODO: libraryoptions dont run on libraries with trickplay disabled + /* will this still get all sub-items? should recursive be true? + * from chapterimagestask + * DtoOptions = new DtoOptions(false) + { + EnableImages = false + }, + SourceTypes = new SourceType[] { SourceType.Library }, + */ var items = _libraryManager.GetItemList(new InternalItemsQuery { MediaTypes = new[] { MediaType.Video }, diff --git a/MediaBrowser.Providers/Trickplay/TrickplayManager.cs b/MediaBrowser.Providers/Trickplay/TrickplayManager.cs index cb916dfdbf..ed2c11281e 100644 --- a/MediaBrowser.Providers/Trickplay/TrickplayManager.cs +++ b/MediaBrowser.Providers/Trickplay/TrickplayManager.cs @@ -5,11 +5,13 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Trickplay; +using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using Microsoft.Extensions.Logging; @@ -28,6 +30,7 @@ namespace MediaBrowser.Providers.Trickplay private readonly IFileSystem _fileSystem; private readonly EncodingHelper _encodingHelper; private readonly ILibraryManager _libraryManager; + private readonly IServerConfigurationManager _config; private static readonly SemaphoreSlim _resourcePool = new(1, 1); @@ -40,13 +43,15 @@ namespace MediaBrowser.Providers.Trickplay /// The file systen. /// The encoding helper. /// The library manager. + /// The server configuration manager. public TrickplayManager( ILogger logger, IItemRepository itemRepo, IMediaEncoder mediaEncoder, IFileSystem fileSystem, EncodingHelper encodingHelper, - ILibraryManager libraryManager) + ILibraryManager libraryManager, + IServerConfigurationManager config) { _logger = logger; _itemRepo = itemRepo; @@ -54,6 +59,7 @@ namespace MediaBrowser.Providers.Trickplay _fileSystem = fileSystem; _encodingHelper = encodingHelper; _libraryManager = libraryManager; + _config = config; } /// @@ -61,16 +67,27 @@ namespace MediaBrowser.Providers.Trickplay { _logger.LogDebug("Trickplay refresh for {ItemId} (replace existing: {Replace})", video.Id, replace); - foreach (var width in new int[] { 320 } /*todo conf*/) + var options = _config.Configuration.TrickplayOptions; + foreach (var width in options.WidthResolutions) { cancellationToken.ThrowIfCancellationRequested(); - await RefreshTrickplayData(video, replace, width, 10000/*todo conf*/, 10/*todo conf*/, 10/*todo conf*/, true/*todo conf*/, true/*todo conf*/, cancellationToken).ConfigureAwait(false); + await RefreshTrickplayDataInternal( + video, + replace, + width, + options, + cancellationToken).ConfigureAwait(false); } } - private async Task RefreshTrickplayData(Video video, bool replace, int width, int interval, int tileWidth, int tileHeight, bool doHwAccel, bool doHwEncode, CancellationToken cancellationToken) + private async Task RefreshTrickplayDataInternal( + Video video, + bool replace, + int width, + TrickplayOptions options, + CancellationToken cancellationToken) { - if (!CanGenerateTrickplay(video, interval)) + if (!CanGenerateTrickplay(video, options.Interval)) { return; } @@ -108,10 +125,12 @@ namespace MediaBrowser.Providers.Trickplay container, mediaSource, mediaStream, - TimeSpan.FromMilliseconds(interval), width, - doHwAccel, - doHwEncode, + TimeSpan.FromMilliseconds(options.Interval), + options.EnableHwAcceleration, + options.ProcessThreads, + options.Qscale, + options.ProcessPriority, _encodingHelper, cancellationToken).ConfigureAwait(false); @@ -127,7 +146,7 @@ namespace MediaBrowser.Providers.Trickplay // Create tiles var tilesTempDir = Path.Combine(imgTempDir, Guid.NewGuid().ToString("N")); - var tilesInfo = CreateTiles(images, width, interval, tileWidth, tileHeight, 100/* todo _config.JpegQuality*/, tilesTempDir, outputDir); + var tilesInfo = CreateTiles(images, width, options, tilesTempDir, outputDir); // Save tiles info try @@ -166,7 +185,7 @@ namespace MediaBrowser.Providers.Trickplay } } - private TrickplayTilesInfo CreateTiles(List images, int width, int interval, int tileWidth, int tileHeight, int quality, string workDir, string outputDir) + private TrickplayTilesInfo CreateTiles(List images, int width, TrickplayOptions options, string workDir, string outputDir) { if (images.Count == 0) { @@ -178,9 +197,9 @@ namespace MediaBrowser.Providers.Trickplay var tilesInfo = new TrickplayTilesInfo { Width = width, - Interval = interval, - TileWidth = tileWidth, - TileHeight = tileHeight, + Interval = options.Interval, + TileWidth = options.TileWidth, + TileHeight = options.TileHeight, TileCount = 0, Bandwidth = 0 }; @@ -244,7 +263,7 @@ namespace MediaBrowser.Providers.Trickplay var tileGridPath = Path.Combine(workDir, $"{imgNo}.jpg"); using (var stream = File.OpenWrite(tileGridPath)) { - tileGrid.Encode(stream, SKEncodedImageFormat.Jpeg, quality); + tileGrid.Encode(stream, SKEncodedImageFormat.Jpeg, options.JpegQuality); } var bitrate = (int)Math.Ceiling((decimal)new FileInfo(tileGridPath).Length * 8 / tilesInfo.TileWidth / tilesInfo.TileHeight / (tilesInfo.Interval / 1000)); @@ -351,7 +370,7 @@ namespace MediaBrowser.Providers.Trickplay { Directory.Move(source, destination); } - catch (System.IO.IOException) + catch (IOException) { // Cross device move requires a copy Directory.CreateDirectory(destination); diff --git a/MediaBrowser.Providers/Trickplay/TrickplayProvider.cs b/MediaBrowser.Providers/Trickplay/TrickplayProvider.cs index e4bd9e3c20..e296467253 100644 --- a/MediaBrowser.Providers/Trickplay/TrickplayProvider.cs +++ b/MediaBrowser.Providers/Trickplay/TrickplayProvider.cs @@ -7,6 +7,7 @@ using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Trickplay; +using MediaBrowser.Model.Configuration; using Microsoft.Extensions.Logging; namespace MediaBrowser.Providers.Trickplay @@ -25,7 +26,7 @@ namespace MediaBrowser.Providers.Trickplay IForcedProvider { private readonly ILogger _logger; - private readonly IServerConfigurationManager _configurationManager; + private readonly IServerConfigurationManager _config; private readonly ITrickplayManager _trickplayManager; private readonly ILibraryManager _libraryManager; @@ -33,17 +34,17 @@ namespace MediaBrowser.Providers.Trickplay /// Initializes a new instance of the class. /// /// The logger. - /// The configuration manager. + /// The configuration manager. /// The trickplay manager. /// The library manager. public TrickplayProvider( ILogger logger, - IServerConfigurationManager configurationManager, + IServerConfigurationManager config, ITrickplayManager trickplayManager, ILibraryManager libraryManager) { _logger = logger; - _configurationManager = configurationManager; + _config = config; _trickplayManager = trickplayManager; _libraryManager = libraryManager; } @@ -110,11 +111,14 @@ namespace MediaBrowser.Providers.Trickplay return ItemUpdateType.None; } - // TODO: this is always blocking for metadata collection, make non-blocking option - if (true) + if (_config.Configuration.TrickplayOptions.ScanBehavior == TrickplayScanBehavior.Blocking) { await _trickplayManager.RefreshTrickplayData(video, replace, cancellationToken).ConfigureAwait(false); } + else + { + _ = _trickplayManager.RefreshTrickplayData(video, replace, cancellationToken).ConfigureAwait(false); + } // The core doesn't need to trigger any save operations over this return ItemUpdateType.None;