diff --git a/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs b/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs
index c14be032e5..bb32b7c20e 100644
--- a/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs
+++ b/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs
@@ -168,6 +168,7 @@ public class TrickplayManager : ITrickplayManager
options.ProcessThreads,
options.Qscale,
options.ProcessPriority,
+ options.EnableKeyFrameOnlyExtraction,
_encodingHelper,
cancellationToken).ConfigureAwait(false);
diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
index 26c353a54f..038c6c7f69 100644
--- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
+++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
@@ -153,6 +153,7 @@ namespace MediaBrowser.Controller.MediaEncoding
/// The input/output thread count for ffmpeg.
/// The qscale value for ffmpeg.
/// The process priority for the ffmpeg process.
+ /// Whether to only extract key frames.
/// EncodingHelper instance.
/// The cancellation token.
/// Directory where images where extracted. A given image made before another will always be named with a lower number.
@@ -168,6 +169,7 @@ namespace MediaBrowser.Controller.MediaEncoding
int? threads,
int? qualityScale,
ProcessPriorityClass? priority,
+ bool enableKeyFrameOnlyExtraction,
EncodingHelper encodingHelper,
CancellationToken cancellationToken);
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index d2aaba9063..de1b654822 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -813,12 +813,28 @@ namespace MediaBrowser.MediaEncoding.Encoder
int? threads,
int? qualityScale,
ProcessPriorityClass? priority,
+ bool enableKeyFrameOnlyExtraction,
EncodingHelper encodingHelper,
CancellationToken cancellationToken)
{
var options = allowHwAccel ? _configurationManager.GetEncodingOptions() : new EncodingOptions();
threads ??= _threads;
+ if (allowHwAccel && enableKeyFrameOnlyExtraction)
+ {
+ var supportsKeyFrameOnly = (string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && options.EnableEnhancedNvdecDecoder)
+ || (string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) && OperatingSystem.IsWindows())
+ || (string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && options.PreferSystemNativeHwDecoder)
+ || string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(options.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase);
+ if (!supportsKeyFrameOnly)
+ {
+ // Disable hardware acceleration when the hardware decoder does not support keyframe only mode.
+ allowHwAccel = false;
+ options = new EncodingOptions();
+ }
+ }
+
// 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.
if (!allowHwAccel)
@@ -868,6 +884,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
inputArg = "-threads " + threads + " " + inputArg; // HW accel args set a different input thread count, only set if disabled
}
+ if (enableKeyFrameOnlyExtraction)
+ {
+ inputArg = "-skip_frame nokey " + inputArg;
+ }
+
var filterParam = encodingHelper.GetVideoProcessingFilterParam(jobState, options, vidEncoder).Trim();
if (string.IsNullOrWhiteSpace(filterParam))
{
diff --git a/MediaBrowser.Model/Configuration/TrickplayOptions.cs b/MediaBrowser.Model/Configuration/TrickplayOptions.cs
index a151d3429b..578bb306a0 100644
--- a/MediaBrowser.Model/Configuration/TrickplayOptions.cs
+++ b/MediaBrowser.Model/Configuration/TrickplayOptions.cs
@@ -18,6 +18,12 @@ public class TrickplayOptions
///
public bool EnableHwEncoding { get; set; } = false;
+ ///
+ /// Gets or sets a value indicating whether to only extract key frames.
+ /// Significantly faster, but is not compatible with all decoders and/or video files.
+ ///
+ public bool EnableKeyFrameOnlyExtraction { get; set; } = false;
+
///
/// Gets or sets the behavior used by trickplay provider on library scan/update.
///