diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs
index 09cf7303e7..9f2088e36e 100644
--- a/Jellyfin.Api/Controllers/DynamicHlsController.cs
+++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs
@@ -1641,9 +1641,11 @@ public class DynamicHlsController : BaseJellyfinApiController
Path.GetFileNameWithoutExtension(outputPath));
}
+ var hlsArguments = GetHlsArguments(isEventPlaylist, state.SegmentLength);
+
return string.Format(
CultureInfo.InvariantCulture,
- "{0} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -copyts -avoid_negative_ts disabled -max_muxing_queue_size {6} -f hls -max_delay 5000000 -hls_time {7} -hls_segment_type {8} -start_number {9}{10} -hls_segment_filename \"{12}\" -hls_playlist_type {11} -hls_list_size 0 -y \"{13}\"",
+ "{0} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -copyts -avoid_negative_ts disabled -max_muxing_queue_size {6} -f hls -max_delay 5000000 -hls_time {7} -hls_segment_type {8} -start_number {9}{10} -hls_segment_filename \"{11}\" {12} -y \"{13}\"",
inputModifier,
_encodingHelper.GetInputArgument(state, _encodingOptions, segmentContainer),
threads,
@@ -1655,11 +1657,38 @@ public class DynamicHlsController : BaseJellyfinApiController
segmentFormat,
startNumber.ToString(CultureInfo.InvariantCulture),
baseUrlParam,
- isEventPlaylist ? "event" : "vod",
EncodingUtils.NormalizePath(outputTsArg),
+ hlsArguments,
EncodingUtils.NormalizePath(outputPath)).Trim();
}
+ ///
+ /// Gets the HLS arguments for transcoding.
+ ///
+ /// The command line arguments for HLS transcoding.
+ private string GetHlsArguments(bool isEventPlaylist, int segmentLength)
+ {
+ var enableThrottling = _encodingOptions.EnableThrottling;
+ var enableSegmentDeletion = _encodingOptions.EnableSegmentDeletion;
+
+ // Only enable segment deletion when throttling is enabled
+ if (enableThrottling && enableSegmentDeletion)
+ {
+ // Store enough segments for configured seconds of playback; this needs to be above throttling settings
+ var segmentCount = _encodingOptions.SegmentKeepSeconds / segmentLength;
+
+ _logger.LogDebug("Using throttling and segment deletion, keeping {0} segments", segmentCount);
+
+ return string.Format(CultureInfo.InvariantCulture, "-hls_list_size {0} -hls_flags delete_segments", segmentCount.ToString(CultureInfo.InvariantCulture));
+ }
+ else
+ {
+ _logger.LogDebug("Using normal playback, is event playlist? {0}", isEventPlaylist);
+
+ return string.Format(CultureInfo.InvariantCulture, "-hls_playlist_type {0} -hls_list_size 0", isEventPlaylist ? "event" : "vod");
+ }
+ }
+
///
/// Gets the audio arguments for transcoding.
///
diff --git a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs
index f25a718697..cee8e0f9be 100644
--- a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs
+++ b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs
@@ -660,7 +660,7 @@ public class TranscodingJobHelper : IDisposable
{
if (EnableThrottling(state))
{
- transcodingJob.TranscodingThrottler = new TranscodingThrottler(transcodingJob, new Logger(new LoggerFactory()), _serverConfigurationManager, _fileSystem, _mediaEncoder);
+ transcodingJob.TranscodingThrottler = new TranscodingThrottler(transcodingJob, _loggerFactory.CreateLogger(), _serverConfigurationManager, _fileSystem, _mediaEncoder);
transcodingJob.TranscodingThrottler.Start();
}
}
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index 26564740d8..b155d674de 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -1365,22 +1365,11 @@ namespace MediaBrowser.Controller.MediaEncoding
{
var args = string.Empty;
var gopArg = string.Empty;
- var keyFrameArg = string.Empty;
- if (isEventPlaylist)
- {
- keyFrameArg = string.Format(
- CultureInfo.InvariantCulture,
- " -force_key_frames:0 \"expr:gte(t,n_forced*{0})\"",
- segmentLength);
- }
- else if (startNumber.HasValue)
- {
- keyFrameArg = string.Format(
- CultureInfo.InvariantCulture,
- " -force_key_frames:0 \"expr:gte(t,{0}+n_forced*{1})\"",
- startNumber.Value * segmentLength,
- segmentLength);
- }
+
+ var keyFrameArg = string.Format(
+ CultureInfo.InvariantCulture,
+ " -force_key_frames:0 \"expr:gte(t,n_forced*{0})\"",
+ segmentLength);
var framerate = state.VideoStream?.RealFrameRate;
if (framerate.HasValue)
diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs
index ac2f1e71a3..a53be0fee7 100644
--- a/MediaBrowser.Model/Configuration/EncodingOptions.cs
+++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs
@@ -20,6 +20,8 @@ public class EncodingOptions
MaxMuxingQueueSize = 2048;
EnableThrottling = false;
ThrottleDelaySeconds = 180;
+ EnableSegmentDeletion = false;
+ SegmentKeepSeconds = 720;
EncodingThreadCount = -1;
// This is a DRM device that is almost guaranteed to be there on every intel platform,
// plus it's the default one in ffmpeg if you don't specify anything
@@ -102,6 +104,16 @@ public class EncodingOptions
///
public int ThrottleDelaySeconds { get; set; }
+ ///
+ /// Gets or sets a value indicating whether segment deletion is enabled.
+ ///
+ public bool EnableSegmentDeletion { get; set; }
+
+ ///
+ /// Gets or sets seconds for which segments should be kept before being deleted.
+ ///
+ public int SegmentKeepSeconds { get; set; }
+
///
/// Gets or sets the hardware acceleration type.
///