From d944f415f3cc0e5433d94b11a16684ca3f0131ec Mon Sep 17 00:00:00 2001 From: gnattu Date: Sun, 22 Sep 2024 00:34:47 +0800 Subject: Let HLS Controller decide if subtitle should be burn in Previously, we predicted whether the subtitle should be burned in with transcode reasons, but that was not accurate because the actual transcoding codec is only determined after the client has requested the stream. This pass through the option to the `DynamicHlsController` to handle the subtitle burn-in during the actual transcoding process. Now the client should be responsible to conditionally load the subtitle when this option is enabled. --- Jellyfin.Api/Controllers/DynamicHlsController.cs | 63 ++++++++++++++++-------- 1 file changed, 42 insertions(+), 21 deletions(-) (limited to 'Jellyfin.Api/Controllers/DynamicHlsController.cs') diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index db1d86698..924f010e4 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -158,6 +158,7 @@ public class DynamicHlsController : BaseJellyfinApiController /// Optional. The max height. /// Optional. Whether to enable subtitles in the manifest. /// Optional. Whether to enable Audio Encoding. + /// Whether to always burn in subtitles when transcoding. /// Hls live stream retrieved. /// A containing the hls file. [HttpGet("Videos/{itemId}/live.m3u8")] @@ -216,7 +217,8 @@ public class DynamicHlsController : BaseJellyfinApiController [FromQuery] int? maxWidth, [FromQuery] int? maxHeight, [FromQuery] bool? enableSubtitlesInManifest, - [FromQuery] bool enableAudioVbrEncoding = true) + [FromQuery] bool enableAudioVbrEncoding = true, + [FromQuery] bool alwaysBurnInSubtitleWhenTranscoding = false) { VideoRequestDto streamingRequest = new VideoRequestDto { @@ -251,7 +253,7 @@ public class DynamicHlsController : BaseJellyfinApiController Height = height, VideoBitRate = videoBitRate, SubtitleStreamIndex = subtitleStreamIndex, - SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode, + SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.External, MaxRefFrames = maxRefFrames, MaxVideoBitDepth = maxVideoBitDepth, RequireAvc = requireAvc ?? false, @@ -271,7 +273,8 @@ public class DynamicHlsController : BaseJellyfinApiController MaxHeight = maxHeight, MaxWidth = maxWidth, EnableSubtitlesInManifest = enableSubtitlesInManifest ?? true, - EnableAudioVbrEncoding = enableAudioVbrEncoding + EnableAudioVbrEncoding = enableAudioVbrEncoding, + AlwaysBurnInSubtitleWhenTranscoding = alwaysBurnInSubtitleWhenTranscoding }; // CTS lifecycle is managed internally. @@ -398,6 +401,7 @@ public class DynamicHlsController : BaseJellyfinApiController /// Enable adaptive bitrate streaming. /// Enable trickplay image playlists being added to master playlist. /// Whether to enable Audio Encoding. + /// Whether to always burn in subtitles when transcoding. /// Video stream returned. /// A containing the playlist file. [HttpGet("Videos/{itemId}/master.m3u8")] @@ -457,7 +461,8 @@ public class DynamicHlsController : BaseJellyfinApiController [FromQuery] Dictionary streamOptions, [FromQuery] bool enableAdaptiveBitrateStreaming = true, [FromQuery] bool enableTrickplay = true, - [FromQuery] bool enableAudioVbrEncoding = true) + [FromQuery] bool enableAudioVbrEncoding = true, + [FromQuery] bool alwaysBurnInSubtitleWhenTranscoding = false) { var streamingRequest = new HlsVideoRequestDto { @@ -493,7 +498,7 @@ public class DynamicHlsController : BaseJellyfinApiController MaxHeight = maxHeight, VideoBitRate = videoBitRate, SubtitleStreamIndex = subtitleStreamIndex, - SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode, + SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.External, MaxRefFrames = maxRefFrames, MaxVideoBitDepth = maxVideoBitDepth, RequireAvc = requireAvc ?? false, @@ -512,7 +517,8 @@ public class DynamicHlsController : BaseJellyfinApiController StreamOptions = streamOptions, EnableAdaptiveBitrateStreaming = enableAdaptiveBitrateStreaming, EnableTrickplay = enableTrickplay, - EnableAudioVbrEncoding = enableAudioVbrEncoding + EnableAudioVbrEncoding = enableAudioVbrEncoding, + AlwaysBurnInSubtitleWhenTranscoding = alwaysBurnInSubtitleWhenTranscoding }; return await _dynamicHlsHelper.GetMasterHlsPlaylist(TranscodingJobType, streamingRequest, enableAdaptiveBitrateStreaming).ConfigureAwait(false); @@ -572,6 +578,7 @@ public class DynamicHlsController : BaseJellyfinApiController /// Optional. The streaming options. /// Enable adaptive bitrate streaming. /// Optional. Whether to enable Audio Encoding. + /// Whether to always burn in subtitles when transcoding. /// Audio stream returned. /// A containing the playlist file. [HttpGet("Audio/{itemId}/master.m3u8")] @@ -629,7 +636,8 @@ public class DynamicHlsController : BaseJellyfinApiController [FromQuery] EncodingContext? context, [FromQuery] Dictionary streamOptions, [FromQuery] bool enableAdaptiveBitrateStreaming = true, - [FromQuery] bool enableAudioVbrEncoding = true) + [FromQuery] bool enableAudioVbrEncoding = true, + [FromQuery] bool alwaysBurnInSubtitleWhenTranscoding = false) { var streamingRequest = new HlsAudioRequestDto { @@ -663,7 +671,7 @@ public class DynamicHlsController : BaseJellyfinApiController Height = height, VideoBitRate = videoBitRate, SubtitleStreamIndex = subtitleStreamIndex, - SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode, + SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.External, MaxRefFrames = maxRefFrames, MaxVideoBitDepth = maxVideoBitDepth, RequireAvc = requireAvc ?? false, @@ -681,7 +689,8 @@ public class DynamicHlsController : BaseJellyfinApiController Context = context ?? EncodingContext.Streaming, StreamOptions = streamOptions, EnableAdaptiveBitrateStreaming = enableAdaptiveBitrateStreaming, - EnableAudioVbrEncoding = enableAudioVbrEncoding + EnableAudioVbrEncoding = enableAudioVbrEncoding, + AlwaysBurnInSubtitleWhenTranscoding = alwaysBurnInSubtitleWhenTranscoding }; return await _dynamicHlsHelper.GetMasterHlsPlaylist(TranscodingJobType, streamingRequest, enableAdaptiveBitrateStreaming).ConfigureAwait(false); @@ -741,6 +750,7 @@ public class DynamicHlsController : BaseJellyfinApiController /// Optional. The . /// Optional. The streaming options. /// Optional. Whether to enable Audio Encoding. + /// Whether to always burn in subtitles when transcoding. /// Video stream returned. /// A containing the audio file. [HttpGet("Videos/{itemId}/main.m3u8")] @@ -797,7 +807,8 @@ public class DynamicHlsController : BaseJellyfinApiController [FromQuery] int? videoStreamIndex, [FromQuery] EncodingContext? context, [FromQuery] Dictionary streamOptions, - [FromQuery] bool enableAudioVbrEncoding = true) + [FromQuery] bool enableAudioVbrEncoding = true, + [FromQuery] bool alwaysBurnInSubtitleWhenTranscoding = false) { using var cancellationTokenSource = new CancellationTokenSource(); var streamingRequest = new VideoRequestDto @@ -834,7 +845,7 @@ public class DynamicHlsController : BaseJellyfinApiController MaxHeight = maxHeight, VideoBitRate = videoBitRate, SubtitleStreamIndex = subtitleStreamIndex, - SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode, + SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.External, MaxRefFrames = maxRefFrames, MaxVideoBitDepth = maxVideoBitDepth, RequireAvc = requireAvc ?? false, @@ -851,7 +862,8 @@ public class DynamicHlsController : BaseJellyfinApiController VideoStreamIndex = videoStreamIndex, Context = context ?? EncodingContext.Streaming, StreamOptions = streamOptions, - EnableAudioVbrEncoding = enableAudioVbrEncoding + EnableAudioVbrEncoding = enableAudioVbrEncoding, + AlwaysBurnInSubtitleWhenTranscoding = alwaysBurnInSubtitleWhenTranscoding }; return await GetVariantPlaylistInternal(streamingRequest, cancellationTokenSource) @@ -911,6 +923,7 @@ public class DynamicHlsController : BaseJellyfinApiController /// Optional. The . /// Optional. The streaming options. /// Optional. Whether to enable Audio Encoding. + /// Whether to always burn in subtitles when transcoding. /// Audio stream returned. /// A containing the audio file. [HttpGet("Audio/{itemId}/main.m3u8")] @@ -966,7 +979,8 @@ public class DynamicHlsController : BaseJellyfinApiController [FromQuery] int? videoStreamIndex, [FromQuery] EncodingContext? context, [FromQuery] Dictionary streamOptions, - [FromQuery] bool enableAudioVbrEncoding = true) + [FromQuery] bool enableAudioVbrEncoding = true, + [FromQuery] bool alwaysBurnInSubtitleWhenTranscoding = false) { using var cancellationTokenSource = new CancellationTokenSource(); var streamingRequest = new StreamingRequestDto @@ -1001,7 +1015,7 @@ public class DynamicHlsController : BaseJellyfinApiController Height = height, VideoBitRate = videoBitRate, SubtitleStreamIndex = subtitleStreamIndex, - SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode, + SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.External, MaxRefFrames = maxRefFrames, MaxVideoBitDepth = maxVideoBitDepth, RequireAvc = requireAvc ?? false, @@ -1018,7 +1032,8 @@ public class DynamicHlsController : BaseJellyfinApiController VideoStreamIndex = videoStreamIndex, Context = context ?? EncodingContext.Streaming, StreamOptions = streamOptions, - EnableAudioVbrEncoding = enableAudioVbrEncoding + EnableAudioVbrEncoding = enableAudioVbrEncoding, + AlwaysBurnInSubtitleWhenTranscoding = alwaysBurnInSubtitleWhenTranscoding }; return await GetVariantPlaylistInternal(streamingRequest, cancellationTokenSource) @@ -1084,6 +1099,7 @@ public class DynamicHlsController : BaseJellyfinApiController /// Optional. The . /// Optional. The streaming options. /// Optional. Whether to enable Audio Encoding. + /// Whether to always burn in subtitles when transcoding. /// Video stream returned. /// A containing the audio file. [HttpGet("Videos/{itemId}/hls1/{playlistId}/{segmentId}.{container}")] @@ -1146,7 +1162,8 @@ public class DynamicHlsController : BaseJellyfinApiController [FromQuery] int? videoStreamIndex, [FromQuery] EncodingContext? context, [FromQuery] Dictionary streamOptions, - [FromQuery] bool enableAudioVbrEncoding = true) + [FromQuery] bool enableAudioVbrEncoding = true, + [FromQuery] bool alwaysBurnInSubtitleWhenTranscoding = false) { var streamingRequest = new VideoRequestDto { @@ -1185,7 +1202,7 @@ public class DynamicHlsController : BaseJellyfinApiController MaxHeight = maxHeight, VideoBitRate = videoBitRate, SubtitleStreamIndex = subtitleStreamIndex, - SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode, + SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.External, MaxRefFrames = maxRefFrames, MaxVideoBitDepth = maxVideoBitDepth, RequireAvc = requireAvc ?? false, @@ -1202,7 +1219,8 @@ public class DynamicHlsController : BaseJellyfinApiController VideoStreamIndex = videoStreamIndex, Context = context ?? EncodingContext.Streaming, StreamOptions = streamOptions, - EnableAudioVbrEncoding = enableAudioVbrEncoding + EnableAudioVbrEncoding = enableAudioVbrEncoding, + AlwaysBurnInSubtitleWhenTranscoding = alwaysBurnInSubtitleWhenTranscoding }; return await GetDynamicSegment(streamingRequest, segmentId) @@ -1267,6 +1285,7 @@ public class DynamicHlsController : BaseJellyfinApiController /// Optional. The . /// Optional. The streaming options. /// Optional. Whether to enable Audio Encoding. + /// Whether to always burn in subtitles when transcoding. /// Video stream returned. /// A containing the audio file. [HttpGet("Audio/{itemId}/hls1/{playlistId}/{segmentId}.{container}")] @@ -1328,7 +1347,8 @@ public class DynamicHlsController : BaseJellyfinApiController [FromQuery] int? videoStreamIndex, [FromQuery] EncodingContext? context, [FromQuery] Dictionary streamOptions, - [FromQuery] bool enableAudioVbrEncoding = true) + [FromQuery] bool enableAudioVbrEncoding = true, + [FromQuery] bool alwaysBurnInSubtitleWhenTranscoding = false) { var streamingRequest = new StreamingRequestDto { @@ -1365,7 +1385,7 @@ public class DynamicHlsController : BaseJellyfinApiController Height = height, VideoBitRate = videoBitRate, SubtitleStreamIndex = subtitleStreamIndex, - SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode, + SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.External, MaxRefFrames = maxRefFrames, MaxVideoBitDepth = maxVideoBitDepth, RequireAvc = requireAvc ?? false, @@ -1382,7 +1402,8 @@ public class DynamicHlsController : BaseJellyfinApiController VideoStreamIndex = videoStreamIndex, Context = context ?? EncodingContext.Streaming, StreamOptions = streamOptions, - EnableAudioVbrEncoding = enableAudioVbrEncoding + EnableAudioVbrEncoding = enableAudioVbrEncoding, + AlwaysBurnInSubtitleWhenTranscoding = alwaysBurnInSubtitleWhenTranscoding }; return await GetDynamicSegment(streamingRequest, segmentId) -- cgit v1.2.3