aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs13
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs37
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs2
-rw-r--r--MediaBrowser.Providers/Trickplay/TrickplayImagesTask.cs12
-rw-r--r--MediaBrowser.Providers/Trickplay/TrickplayManager.cs49
-rw-r--r--MediaBrowser.Providers/Trickplay/TrickplayProvider.cs16
6 files changed, 89 insertions, 40 deletions
diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
index aa9faa936..f5e3d03cb 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
/// <param name="container">Video container type.</param>
/// <param name="mediaSource">Media source information.</param>
/// <param name="imageStream">Media stream information.</param>
- /// <param name="interval">The interval.</param>
/// <param name="maxWidth">The maximum width.</param>
+ /// <param name="interval">The interval.</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="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>
@@ -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 9b58f83b4..11f42c3f9 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<string> 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 78a310f0b..097eff295 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -264,5 +264,7 @@ namespace MediaBrowser.Model.Configuration
/// </summary>
/// <value>The limit for parallel image encoding.</value>
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 87ac145d7..a364926c0 100644
--- a/MediaBrowser.Providers/Trickplay/TrickplayImagesTask.cs
+++ b/MediaBrowser.Providers/Trickplay/TrickplayImagesTask.cs
@@ -22,7 +22,6 @@ namespace MediaBrowser.Providers.Trickplay
private readonly ILogger<TrickplayImagesTask> _logger;
private readonly ILibraryManager _libraryManager;
private readonly ILocalizationManager _localization;
- private readonly IServerConfigurationManager _configurationManager;
private readonly ITrickplayManager _trickplayManager;
/// <summary>
@@ -31,19 +30,16 @@ namespace MediaBrowser.Providers.Trickplay
/// <param name="logger">The logger.</param>
/// <param name="libraryManager">The library manager.</param>
/// <param name="localization">The localization manager.</param>
- /// <param name="configurationManager">The configuration manager.</param>
/// <param name="trickplayManager">The trickplay manager.</param>
public TrickplayImagesTask(
ILogger<TrickplayImagesTask> 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<double> 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 cb916dfdb..ed2c11281 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
/// <param name="fileSystem">The file systen.</param>
/// <param name="encodingHelper">The encoding helper.</param>
/// <param name="libraryManager">The library manager.</param>
+ /// <param name="config">The server configuration manager.</param>
public TrickplayManager(
ILogger<TrickplayManager> 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;
}
/// <inheritdoc />
@@ -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<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)
{
@@ -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 e4bd9e3c2..e29646725 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<TrickplayProvider> _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 <see cref="TrickplayProvider"/> class.
/// </summary>
/// <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="libraryManager">The library manager.</param>
public TrickplayProvider(
ILogger<TrickplayProvider> 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;