From 68bfabbaba2fc6f7b5b6cd63b388f4669a476713 Mon Sep 17 00:00:00 2001 From: gnattu Date: Wed, 8 May 2024 13:50:03 +0800 Subject: [PATCH 1/4] Add option to extract keyframe only during trickplay image generation This would be significantly faster than decoding every frame, but it does have compatibility issues. Not all decoders support this mode, notably the VP9 decoder, CUVID decoders, and QSV decoders. Some videos with very long key-frame intervals may also perform poorly with this mode, as the image timing could become too inaccurate to reflect the actual frame. Signed-off-by: gnattu --- .../Trickplay/TrickplayManager.cs | 1 + MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs | 2 ++ MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 6 ++++++ MediaBrowser.Model/Configuration/TrickplayOptions.cs | 6 ++++++ 4 files changed, 15 insertions(+) diff --git a/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs b/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs index efdfc745f0..69c402f63b 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 d0d41c2d38..db4e21705a 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -807,6 +807,7 @@ namespace MediaBrowser.MediaEncoding.Encoder int? threads, int? qualityScale, ProcessPriorityClass? priority, + bool enableKeyFrameOnlyExtraction, EncodingHelper encodingHelper, CancellationToken cancellationToken) { @@ -862,6 +863,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. /// From 0340eccb523a33a7a777a3e06383df4900965895 Mon Sep 17 00:00:00 2001 From: gnattu Date: Wed, 17 Jul 2024 00:35:59 +0800 Subject: [PATCH 2/4] Force software decoding when hardware decoder does not support keyframe only mode but requested by user Signed-off-by: gnattu --- .../Encoder/MediaEncoder.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index db4e21705a..f101bbb148 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -814,6 +814,22 @@ namespace MediaBrowser.MediaEncoding.Encoder var options = allowHwAccel ? _configurationManager.GetEncodingOptions() : new EncodingOptions(); threads ??= _threads; + if (enableKeyFrameOnlyExtraction) + { + var supportsKeyFrameOnly = !allowHwAccel + || (string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && options.EnableEnhancedNvdecDecoder) + || (string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) && OperatingSystem.IsWindows() && options.PreferSystemNativeHwDecoder) + || (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) From b28d22545a59da010ce1b949c0aac76d19c61e95 Mon Sep 17 00:00:00 2001 From: gnattu Date: Wed, 17 Jul 2024 21:25:29 +0800 Subject: [PATCH 3/4] Simplify condition check Signed-off-by: gnattu --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index f101bbb148..fd6bef1ad7 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -814,10 +814,9 @@ namespace MediaBrowser.MediaEncoding.Encoder var options = allowHwAccel ? _configurationManager.GetEncodingOptions() : new EncodingOptions(); threads ??= _threads; - if (enableKeyFrameOnlyExtraction) + if (allowHwAccel && enableKeyFrameOnlyExtraction) { - var supportsKeyFrameOnly = !allowHwAccel - || (string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && options.EnableEnhancedNvdecDecoder) + var supportsKeyFrameOnly = (string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && options.EnableEnhancedNvdecDecoder) || (string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) && OperatingSystem.IsWindows() && options.PreferSystemNativeHwDecoder) || (string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && options.PreferSystemNativeHwDecoder) || string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) From e851bb869b0c9295372b6f9f47d78a4ea1401cea Mon Sep 17 00:00:00 2001 From: gnattu Date: Wed, 17 Jul 2024 22:25:28 +0800 Subject: [PATCH 4/4] Simply AMF Windows checking Co-authored-by: Nyanmisaka --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index fd6bef1ad7..390891fcf1 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -817,7 +817,7 @@ namespace MediaBrowser.MediaEncoding.Encoder if (allowHwAccel && enableKeyFrameOnlyExtraction) { var supportsKeyFrameOnly = (string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && options.EnableEnhancedNvdecDecoder) - || (string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) && OperatingSystem.IsWindows() && options.PreferSystemNativeHwDecoder) + || (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);