Use config values

This commit is contained in:
nicknsy 2023-02-25 15:59:46 -08:00 committed by Nick
parent d448cc18ea
commit 6744e712d3
6 changed files with 89 additions and 40 deletions

View file

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Configuration;
@ -145,10 +146,12 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <param name="container">Video container type.</param> /// <param name="container">Video container type.</param>
/// <param name="mediaSource">Media source information.</param> /// <param name="mediaSource">Media source information.</param>
/// <param name="imageStream">Media stream information.</param> /// <param name="imageStream">Media stream information.</param>
/// <param name="interval">The interval.</param>
/// <param name="maxWidth">The maximum width.</param> /// <param name="maxWidth">The maximum width.</param>
/// <param name="interval">The interval.</param>
/// <param name="allowHwAccel">Allow for hardware acceleration.</param> /// <param name="allowHwAccel">Allow for hardware acceleration.</param>
/// <param name="allowHwEncode">Allow for hardware encoding. allowHwAccel must also be true.</param> /// <param name="threads">The input/output thread count for ffmpeg.</param>
/// <param name="qualityScale">The qscale value for ffmpeg.</param>
/// <param name="priority">The process priority for the ffmpeg process.</param>
/// <param name="encodingHelper">EncodingHelper instance.</param> /// <param name="encodingHelper">EncodingHelper instance.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Directory where images where extracted. A given image made before another will always be named with a lower number.</returns> /// <returns>Directory where images where extracted. A given image made before another will always be named with a lower number.</returns>
@ -157,10 +160,12 @@ namespace MediaBrowser.Controller.MediaEncoding
string container, string container,
MediaSourceInfo mediaSource, MediaSourceInfo mediaSource,
MediaStream imageStream, MediaStream imageStream,
TimeSpan interval,
int maxWidth, int maxWidth,
TimeSpan interval,
bool allowHwAccel, bool allowHwAccel,
bool allowHwEncode, int? threads,
int? qualityScale,
ProcessPriorityClass? priority,
EncodingHelper encodingHelper, EncodingHelper encodingHelper,
CancellationToken cancellationToken); CancellationToken cancellationToken);

View file

@ -783,14 +783,17 @@ namespace MediaBrowser.MediaEncoding.Encoder
string container, string container,
MediaSourceInfo mediaSource, MediaSourceInfo mediaSource,
MediaStream imageStream, MediaStream imageStream,
TimeSpan interval,
int maxWidth, int maxWidth,
TimeSpan interval,
bool allowHwAccel, bool allowHwAccel,
bool allowHwEncode, int? threads,
int? qualityScale,
ProcessPriorityClass? priority,
EncodingHelper encodingHelper, EncodingHelper encodingHelper,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
var options = allowHwAccel ? _configurationManager.GetEncodingOptions() : new EncodingOptions(); 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. // 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. // Additionally, we must set a few fields without defaults to prevent null pointer exceptions.
@ -822,7 +825,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (!allowHwAccel) 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(); 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."); 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<string> ExtractVideoImagesOnIntervalInternal( private async Task<string> ExtractVideoImagesOnIntervalInternal(
@ -839,7 +842,9 @@ namespace MediaBrowser.MediaEncoding.Encoder
string filterParam, string filterParam,
TimeSpan interval, TimeSpan interval,
string vidEncoder, string vidEncoder,
int outputThreads, int? outputThreads,
int? qualityScale,
ProcessPriorityClass? priority,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
if (string.IsNullOrWhiteSpace(inputArg)) if (string.IsNullOrWhiteSpace(inputArg))
@ -857,10 +862,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
{ {
filterParam = filterParam.Insert(filterParam.IndexOf("\"", StringComparison.Ordinal) + 1, fps + ","); filterParam = filterParam.Insert(filterParam.IndexOf("\"", StringComparison.Ordinal) + 1, fps + ",");
} }
else
{
filterParam += fps + ",";
}
var targetDirectory = Path.Combine(_configurationManager.ApplicationPaths.TempDirectory, Guid.NewGuid().ToString("N")); var targetDirectory = Path.Combine(_configurationManager.ApplicationPaths.TempDirectory, Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(targetDirectory); Directory.CreateDirectory(targetDirectory);
@ -869,11 +870,12 @@ namespace MediaBrowser.MediaEncoding.Encoder
// Final command arguments // Final command arguments
var args = string.Format( var args = string.Format(
CultureInfo.InvariantCulture, 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, inputArg,
filterParam, filterParam,
outputThreads, outputThreads.GetValueOrDefault(_threads),
vidEncoder, vidEncoder,
qualityScale.HasValue ? "-qscale:v " + qualityScale.Value.ToString(CultureInfo.InvariantCulture) + " " : string.Empty,
"image2", "image2",
outputPath); outputPath);
@ -904,6 +906,19 @@ namespace MediaBrowser.MediaEncoding.Encoder
{ {
StartProcess(processWrapper); 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, // 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. // 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. // Making the assumption that as long as new jpegs are showing up, everything is good.

View file

@ -264,5 +264,7 @@ namespace MediaBrowser.Model.Configuration
/// </summary> /// </summary>
/// <value>The limit for parallel image encoding.</value> /// <value>The limit for parallel image encoding.</value>
public int ParallelImageEncodingLimit { get; set; } public int ParallelImageEncodingLimit { get; set; }
public TrickplayOptions TrickplayOptions { get; set; } = new TrickplayOptions();
} }
} }

View file

@ -22,7 +22,6 @@ namespace MediaBrowser.Providers.Trickplay
private readonly ILogger<TrickplayImagesTask> _logger; private readonly ILogger<TrickplayImagesTask> _logger;
private readonly ILibraryManager _libraryManager; private readonly ILibraryManager _libraryManager;
private readonly ILocalizationManager _localization; private readonly ILocalizationManager _localization;
private readonly IServerConfigurationManager _configurationManager;
private readonly ITrickplayManager _trickplayManager; private readonly ITrickplayManager _trickplayManager;
/// <summary> /// <summary>
@ -31,19 +30,16 @@ namespace MediaBrowser.Providers.Trickplay
/// <param name="logger">The logger.</param> /// <param name="logger">The logger.</param>
/// <param name="libraryManager">The library manager.</param> /// <param name="libraryManager">The library manager.</param>
/// <param name="localization">The localization manager.</param> /// <param name="localization">The localization manager.</param>
/// <param name="configurationManager">The configuration manager.</param>
/// <param name="trickplayManager">The trickplay manager.</param> /// <param name="trickplayManager">The trickplay manager.</param>
public TrickplayImagesTask( public TrickplayImagesTask(
ILogger<TrickplayImagesTask> logger, ILogger<TrickplayImagesTask> logger,
ILibraryManager libraryManager, ILibraryManager libraryManager,
ILocalizationManager localization, ILocalizationManager localization,
IServerConfigurationManager configurationManager,
ITrickplayManager trickplayManager) ITrickplayManager trickplayManager)
{ {
_libraryManager = libraryManager; _libraryManager = libraryManager;
_logger = logger; _logger = logger;
_localization = localization; _localization = localization;
_configurationManager = configurationManager;
_trickplayManager = trickplayManager; _trickplayManager = trickplayManager;
} }
@ -77,6 +73,14 @@ namespace MediaBrowser.Providers.Trickplay
public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken) public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{ {
// TODO: libraryoptions dont run on libraries with trickplay disabled // 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 var items = _libraryManager.GetItemList(new InternalItemsQuery
{ {
MediaTypes = new[] { MediaType.Video }, MediaTypes = new[] { MediaType.Video },

View file

@ -5,11 +5,13 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Trickplay; using MediaBrowser.Controller.Trickplay;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -28,6 +30,7 @@ namespace MediaBrowser.Providers.Trickplay
private readonly IFileSystem _fileSystem; private readonly IFileSystem _fileSystem;
private readonly EncodingHelper _encodingHelper; private readonly EncodingHelper _encodingHelper;
private readonly ILibraryManager _libraryManager; private readonly ILibraryManager _libraryManager;
private readonly IServerConfigurationManager _config;
private static readonly SemaphoreSlim _resourcePool = new(1, 1); private static readonly SemaphoreSlim _resourcePool = new(1, 1);
@ -40,13 +43,15 @@ namespace MediaBrowser.Providers.Trickplay
/// <param name="fileSystem">The file systen.</param> /// <param name="fileSystem">The file systen.</param>
/// <param name="encodingHelper">The encoding helper.</param> /// <param name="encodingHelper">The encoding helper.</param>
/// <param name="libraryManager">The library manager.</param> /// <param name="libraryManager">The library manager.</param>
/// <param name="config">The server configuration manager.</param>
public TrickplayManager( public TrickplayManager(
ILogger<TrickplayManager> logger, ILogger<TrickplayManager> logger,
IItemRepository itemRepo, IItemRepository itemRepo,
IMediaEncoder mediaEncoder, IMediaEncoder mediaEncoder,
IFileSystem fileSystem, IFileSystem fileSystem,
EncodingHelper encodingHelper, EncodingHelper encodingHelper,
ILibraryManager libraryManager) ILibraryManager libraryManager,
IServerConfigurationManager config)
{ {
_logger = logger; _logger = logger;
_itemRepo = itemRepo; _itemRepo = itemRepo;
@ -54,6 +59,7 @@ namespace MediaBrowser.Providers.Trickplay
_fileSystem = fileSystem; _fileSystem = fileSystem;
_encodingHelper = encodingHelper; _encodingHelper = encodingHelper;
_libraryManager = libraryManager; _libraryManager = libraryManager;
_config = config;
} }
/// <inheritdoc /> /// <inheritdoc />
@ -61,16 +67,27 @@ namespace MediaBrowser.Providers.Trickplay
{ {
_logger.LogDebug("Trickplay refresh for {ItemId} (replace existing: {Replace})", video.Id, replace); _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(); 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; return;
} }
@ -108,10 +125,12 @@ namespace MediaBrowser.Providers.Trickplay
container, container,
mediaSource, mediaSource,
mediaStream, mediaStream,
TimeSpan.FromMilliseconds(interval),
width, width,
doHwAccel, TimeSpan.FromMilliseconds(options.Interval),
doHwEncode, options.EnableHwAcceleration,
options.ProcessThreads,
options.Qscale,
options.ProcessPriority,
_encodingHelper, _encodingHelper,
cancellationToken).ConfigureAwait(false); cancellationToken).ConfigureAwait(false);
@ -127,7 +146,7 @@ namespace MediaBrowser.Providers.Trickplay
// Create tiles // Create tiles
var tilesTempDir = Path.Combine(imgTempDir, Guid.NewGuid().ToString("N")); 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 // Save tiles info
try try
@ -166,7 +185,7 @@ namespace MediaBrowser.Providers.Trickplay
} }
} }
private TrickplayTilesInfo CreateTiles(List<FileSystemMetadata> images, int width, int interval, int tileWidth, int tileHeight, int quality, string workDir, string outputDir) private TrickplayTilesInfo CreateTiles(List<FileSystemMetadata> images, int width, TrickplayOptions options, string workDir, string outputDir)
{ {
if (images.Count == 0) if (images.Count == 0)
{ {
@ -178,9 +197,9 @@ namespace MediaBrowser.Providers.Trickplay
var tilesInfo = new TrickplayTilesInfo var tilesInfo = new TrickplayTilesInfo
{ {
Width = width, Width = width,
Interval = interval, Interval = options.Interval,
TileWidth = tileWidth, TileWidth = options.TileWidth,
TileHeight = tileHeight, TileHeight = options.TileHeight,
TileCount = 0, TileCount = 0,
Bandwidth = 0 Bandwidth = 0
}; };
@ -244,7 +263,7 @@ namespace MediaBrowser.Providers.Trickplay
var tileGridPath = Path.Combine(workDir, $"{imgNo}.jpg"); var tileGridPath = Path.Combine(workDir, $"{imgNo}.jpg");
using (var stream = File.OpenWrite(tileGridPath)) 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)); 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); Directory.Move(source, destination);
} }
catch (System.IO.IOException) catch (IOException)
{ {
// Cross device move requires a copy // Cross device move requires a copy
Directory.CreateDirectory(destination); Directory.CreateDirectory(destination);

View file

@ -7,6 +7,7 @@ using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Trickplay; using MediaBrowser.Controller.Trickplay;
using MediaBrowser.Model.Configuration;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace MediaBrowser.Providers.Trickplay namespace MediaBrowser.Providers.Trickplay
@ -25,7 +26,7 @@ namespace MediaBrowser.Providers.Trickplay
IForcedProvider IForcedProvider
{ {
private readonly ILogger<TrickplayProvider> _logger; private readonly ILogger<TrickplayProvider> _logger;
private readonly IServerConfigurationManager _configurationManager; private readonly IServerConfigurationManager _config;
private readonly ITrickplayManager _trickplayManager; private readonly ITrickplayManager _trickplayManager;
private readonly ILibraryManager _libraryManager; private readonly ILibraryManager _libraryManager;
@ -33,17 +34,17 @@ namespace MediaBrowser.Providers.Trickplay
/// Initializes a new instance of the <see cref="TrickplayProvider"/> class. /// Initializes a new instance of the <see cref="TrickplayProvider"/> class.
/// </summary> /// </summary>
/// <param name="logger">The logger.</param> /// <param name="logger">The logger.</param>
/// <param name="configurationManager">The configuration manager.</param> /// <param name="config">The configuration manager.</param>
/// <param name="trickplayManager">The trickplay manager.</param> /// <param name="trickplayManager">The trickplay manager.</param>
/// <param name="libraryManager">The library manager.</param> /// <param name="libraryManager">The library manager.</param>
public TrickplayProvider( public TrickplayProvider(
ILogger<TrickplayProvider> logger, ILogger<TrickplayProvider> logger,
IServerConfigurationManager configurationManager, IServerConfigurationManager config,
ITrickplayManager trickplayManager, ITrickplayManager trickplayManager,
ILibraryManager libraryManager) ILibraryManager libraryManager)
{ {
_logger = logger; _logger = logger;
_configurationManager = configurationManager; _config = config;
_trickplayManager = trickplayManager; _trickplayManager = trickplayManager;
_libraryManager = libraryManager; _libraryManager = libraryManager;
} }
@ -110,11 +111,14 @@ namespace MediaBrowser.Providers.Trickplay
return ItemUpdateType.None; return ItemUpdateType.None;
} }
// TODO: this is always blocking for metadata collection, make non-blocking option if (_config.Configuration.TrickplayOptions.ScanBehavior == TrickplayScanBehavior.Blocking)
if (true)
{ {
await _trickplayManager.RefreshTrickplayData(video, replace, cancellationToken).ConfigureAwait(false); 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 // The core doesn't need to trigger any save operations over this
return ItemUpdateType.None; return ItemUpdateType.None;