aboutsummaryrefslogtreecommitdiff
path: root/Jellyfin.Api/Controllers/DynamicHlsController.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Jellyfin.Api/Controllers/DynamicHlsController.cs')
-rw-r--r--Jellyfin.Api/Controllers/DynamicHlsController.cs102
1 files changed, 52 insertions, 50 deletions
diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs
index a641ec209..4cac8ed67 100644
--- a/Jellyfin.Api/Controllers/DynamicHlsController.cs
+++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs
@@ -166,18 +166,18 @@ public class DynamicHlsController : BaseJellyfinApiController
[ProducesPlaylistFile]
public async Task<ActionResult> GetLiveHlsStream(
[FromRoute, Required] Guid itemId,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? container,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? container,
[FromQuery] bool? @static,
[FromQuery] string? @params,
[FromQuery] string? tag,
[FromQuery, ParameterObsolete] string? deviceProfileId,
[FromQuery] string? playSessionId,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? segmentContainer,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? segmentContainer,
[FromQuery] int? segmentLength,
[FromQuery] int? minSegments,
[FromQuery] string? mediaSourceId,
[FromQuery] string? deviceId,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? audioCodec,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? audioCodec,
[FromQuery] bool? enableAutoStreamCopy,
[FromQuery] bool? allowVideoStreamCopy,
[FromQuery] bool? allowAudioStreamCopy,
@@ -188,7 +188,7 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] int? audioChannels,
[FromQuery] int? maxAudioChannels,
[FromQuery] string? profile,
- [FromQuery] string? level,
+ [FromQuery] [RegularExpression(EncodingHelper.LevelValidationRegex)] string? level,
[FromQuery] float? framerate,
[FromQuery] float? maxFramerate,
[FromQuery] bool? copyTimestamps,
@@ -207,8 +207,8 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] int? cpuCoreLimit,
[FromQuery] string? liveStreamId,
[FromQuery] bool? enableMpegtsM2TsMode,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? videoCodec,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? subtitleCodec,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? videoCodec,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? subtitleCodec,
[FromQuery] string? transcodeReasons,
[FromQuery] int? audioStreamIndex,
[FromQuery] int? videoStreamIndex,
@@ -415,12 +415,12 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] string? tag,
[FromQuery, ParameterObsolete] string? deviceProfileId,
[FromQuery] string? playSessionId,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? segmentContainer,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? segmentContainer,
[FromQuery] int? segmentLength,
[FromQuery] int? minSegments,
[FromQuery, Required] string mediaSourceId,
[FromQuery] string? deviceId,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? audioCodec,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? audioCodec,
[FromQuery] bool? enableAutoStreamCopy,
[FromQuery] bool? allowVideoStreamCopy,
[FromQuery] bool? allowAudioStreamCopy,
@@ -431,7 +431,7 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] int? audioChannels,
[FromQuery] int? maxAudioChannels,
[FromQuery] string? profile,
- [FromQuery] string? level,
+ [FromQuery] [RegularExpression(EncodingHelper.LevelValidationRegex)] string? level,
[FromQuery] float? framerate,
[FromQuery] float? maxFramerate,
[FromQuery] bool? copyTimestamps,
@@ -452,14 +452,14 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] int? cpuCoreLimit,
[FromQuery] string? liveStreamId,
[FromQuery] bool? enableMpegtsM2TsMode,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? videoCodec,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? subtitleCodec,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? videoCodec,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? subtitleCodec,
[FromQuery] string? transcodeReasons,
[FromQuery] int? audioStreamIndex,
[FromQuery] int? videoStreamIndex,
[FromQuery] EncodingContext? context,
[FromQuery] Dictionary<string, string> streamOptions,
- [FromQuery] bool enableAdaptiveBitrateStreaming = true,
+ [FromQuery] bool enableAdaptiveBitrateStreaming = false,
[FromQuery] bool enableTrickplay = true,
[FromQuery] bool enableAudioVbrEncoding = true,
[FromQuery] bool alwaysBurnInSubtitleWhenTranscoding = false)
@@ -591,12 +591,12 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] string? tag,
[FromQuery, ParameterObsolete] string? deviceProfileId,
[FromQuery] string? playSessionId,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? segmentContainer,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? segmentContainer,
[FromQuery] int? segmentLength,
[FromQuery] int? minSegments,
[FromQuery, Required] string mediaSourceId,
[FromQuery] string? deviceId,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? audioCodec,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? audioCodec,
[FromQuery] bool? enableAutoStreamCopy,
[FromQuery] bool? allowVideoStreamCopy,
[FromQuery] bool? allowAudioStreamCopy,
@@ -608,7 +608,7 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] int? audioChannels,
[FromQuery] int? maxAudioChannels,
[FromQuery] string? profile,
- [FromQuery] string? level,
+ [FromQuery] [RegularExpression(EncodingHelper.LevelValidationRegex)] string? level,
[FromQuery] float? framerate,
[FromQuery] float? maxFramerate,
[FromQuery] bool? copyTimestamps,
@@ -627,14 +627,14 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] int? cpuCoreLimit,
[FromQuery] string? liveStreamId,
[FromQuery] bool? enableMpegtsM2TsMode,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? videoCodec,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? subtitleCodec,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? videoCodec,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? subtitleCodec,
[FromQuery] string? transcodeReasons,
[FromQuery] int? audioStreamIndex,
[FromQuery] int? videoStreamIndex,
[FromQuery] EncodingContext? context,
[FromQuery] Dictionary<string, string> streamOptions,
- [FromQuery] bool enableAdaptiveBitrateStreaming = true,
+ [FromQuery] bool enableAdaptiveBitrateStreaming = false,
[FromQuery] bool enableAudioVbrEncoding = true)
{
var streamingRequest = new HlsAudioRequestDto
@@ -761,12 +761,12 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] string? tag,
[FromQuery, ParameterObsolete] string? deviceProfileId,
[FromQuery] string? playSessionId,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? segmentContainer,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? segmentContainer,
[FromQuery] int? segmentLength,
[FromQuery] int? minSegments,
[FromQuery] string? mediaSourceId,
[FromQuery] string? deviceId,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? audioCodec,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? audioCodec,
[FromQuery] bool? enableAutoStreamCopy,
[FromQuery] bool? allowVideoStreamCopy,
[FromQuery] bool? allowAudioStreamCopy,
@@ -777,7 +777,7 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] int? audioChannels,
[FromQuery] int? maxAudioChannels,
[FromQuery] string? profile,
- [FromQuery] string? level,
+ [FromQuery] [RegularExpression(EncodingHelper.LevelValidationRegex)] string? level,
[FromQuery] float? framerate,
[FromQuery] float? maxFramerate,
[FromQuery] bool? copyTimestamps,
@@ -798,8 +798,8 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] int? cpuCoreLimit,
[FromQuery] string? liveStreamId,
[FromQuery] bool? enableMpegtsM2TsMode,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? videoCodec,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? subtitleCodec,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? videoCodec,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? subtitleCodec,
[FromQuery] string? transcodeReasons,
[FromQuery] int? audioStreamIndex,
[FromQuery] int? videoStreamIndex,
@@ -933,12 +933,12 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] string? tag,
[FromQuery, ParameterObsolete] string? deviceProfileId,
[FromQuery] string? playSessionId,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? segmentContainer,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? segmentContainer,
[FromQuery] int? segmentLength,
[FromQuery] int? minSegments,
[FromQuery] string? mediaSourceId,
[FromQuery] string? deviceId,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? audioCodec,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? audioCodec,
[FromQuery] bool? enableAutoStreamCopy,
[FromQuery] bool? allowVideoStreamCopy,
[FromQuery] bool? allowAudioStreamCopy,
@@ -950,7 +950,7 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] int? audioChannels,
[FromQuery] int? maxAudioChannels,
[FromQuery] string? profile,
- [FromQuery] string? level,
+ [FromQuery] [RegularExpression(EncodingHelper.LevelValidationRegex)] string? level,
[FromQuery] float? framerate,
[FromQuery] float? maxFramerate,
[FromQuery] bool? copyTimestamps,
@@ -969,8 +969,8 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] int? cpuCoreLimit,
[FromQuery] string? liveStreamId,
[FromQuery] bool? enableMpegtsM2TsMode,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? videoCodec,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? subtitleCodec,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? videoCodec,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? subtitleCodec,
[FromQuery] string? transcodeReasons,
[FromQuery] int? audioStreamIndex,
[FromQuery] int? videoStreamIndex,
@@ -1106,7 +1106,7 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromRoute, Required] Guid itemId,
[FromRoute, Required] string playlistId,
[FromRoute, Required] int segmentId,
- [FromRoute, Required] string container,
+ [FromRoute, Required] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string container,
[FromQuery, Required] long runtimeTicks,
[FromQuery, Required] long actualSegmentLengthTicks,
[FromQuery] bool? @static,
@@ -1114,12 +1114,12 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] string? tag,
[FromQuery, ParameterObsolete] string? deviceProfileId,
[FromQuery] string? playSessionId,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? segmentContainer,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? segmentContainer,
[FromQuery] int? segmentLength,
[FromQuery] int? minSegments,
[FromQuery] string? mediaSourceId,
[FromQuery] string? deviceId,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? audioCodec,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? audioCodec,
[FromQuery] bool? enableAutoStreamCopy,
[FromQuery] bool? allowVideoStreamCopy,
[FromQuery] bool? allowAudioStreamCopy,
@@ -1130,7 +1130,7 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] int? audioChannels,
[FromQuery] int? maxAudioChannels,
[FromQuery] string? profile,
- [FromQuery] string? level,
+ [FromQuery] [RegularExpression(EncodingHelper.LevelValidationRegex)] string? level,
[FromQuery] float? framerate,
[FromQuery] float? maxFramerate,
[FromQuery] bool? copyTimestamps,
@@ -1151,8 +1151,8 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] int? cpuCoreLimit,
[FromQuery] string? liveStreamId,
[FromQuery] bool? enableMpegtsM2TsMode,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? videoCodec,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? subtitleCodec,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? videoCodec,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? subtitleCodec,
[FromQuery] string? transcodeReasons,
[FromQuery] int? audioStreamIndex,
[FromQuery] int? videoStreamIndex,
@@ -1291,7 +1291,7 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromRoute, Required] Guid itemId,
[FromRoute, Required] string playlistId,
[FromRoute, Required] int segmentId,
- [FromRoute, Required] string container,
+ [FromRoute, Required] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string container,
[FromQuery, Required] long runtimeTicks,
[FromQuery, Required] long actualSegmentLengthTicks,
[FromQuery] bool? @static,
@@ -1299,12 +1299,12 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] string? tag,
[FromQuery, ParameterObsolete] string? deviceProfileId,
[FromQuery] string? playSessionId,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? segmentContainer,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? segmentContainer,
[FromQuery] int? segmentLength,
[FromQuery] int? minSegments,
[FromQuery] string? mediaSourceId,
[FromQuery] string? deviceId,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? audioCodec,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? audioCodec,
[FromQuery] bool? enableAutoStreamCopy,
[FromQuery] bool? allowVideoStreamCopy,
[FromQuery] bool? allowAudioStreamCopy,
@@ -1316,7 +1316,7 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] int? audioChannels,
[FromQuery] int? maxAudioChannels,
[FromQuery] string? profile,
- [FromQuery] string? level,
+ [FromQuery] [RegularExpression(EncodingHelper.LevelValidationRegex)] string? level,
[FromQuery] float? framerate,
[FromQuery] float? maxFramerate,
[FromQuery] bool? copyTimestamps,
@@ -1335,8 +1335,8 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] int? cpuCoreLimit,
[FromQuery] string? liveStreamId,
[FromQuery] bool? enableMpegtsM2TsMode,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? videoCodec,
- [FromQuery] [RegularExpression(EncodingHelper.ValidationRegex)] string? subtitleCodec,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? videoCodec,
+ [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? subtitleCodec,
[FromQuery] string? transcodeReasons,
[FromQuery] int? audioStreamIndex,
[FromQuery] int? videoStreamIndex,
@@ -1419,8 +1419,9 @@ public class DynamicHlsController : BaseJellyfinApiController
TranscodingJobType,
cancellationTokenSource.Token)
.ConfigureAwait(false);
-
+ var mediaSourceId = state.BaseRequest.MediaSourceId;
var request = new CreateMainPlaylistRequest(
+ mediaSourceId is null ? null : Guid.Parse(mediaSourceId),
state.MediaPath,
state.SegmentLength * 1000,
state.RunTimeTicks ?? 0,
@@ -1675,7 +1676,7 @@ public class DynamicHlsController : BaseJellyfinApiController
}
var audioCodec = _encodingHelper.GetAudioEncoder(state);
- var bitStreamArgs = EncodingHelper.GetAudioBitStreamArguments(state, state.Request.SegmentContainer, state.MediaSource.Container);
+ var bitStreamArgs = _encodingHelper.GetAudioBitStreamArguments(state, state.Request.SegmentContainer, state.MediaSource.Container);
// opus, dts, truehd and flac (in FFmpeg 5 and older) are experimental in mp4 muxer
var strictArgs = string.Empty;
@@ -1753,7 +1754,7 @@ public class DynamicHlsController : BaseJellyfinApiController
if (channels.HasValue
&& (channels.Value != 2
- || (state.AudioStream?.Channels != null && !useDownMixAlgorithm)))
+ || (state.AudioStream?.Channels is not null && !useDownMixAlgorithm)))
{
args += " -ac " + channels.Value;
}
@@ -1778,7 +1779,7 @@ public class DynamicHlsController : BaseJellyfinApiController
}
else if (state.AudioStream?.CodecTag is not null && state.AudioStream.CodecTag.Equals("ac-4", StringComparison.Ordinal))
{
- // ac-4 audio tends to hava a super weird sample rate that will fail most encoders
+ // ac-4 audio tends to have a super weird sample rate that will fail most encoders
// force resample it to 48KHz
args += " -ar 48000";
}
@@ -1822,10 +1823,11 @@ public class DynamicHlsController : BaseJellyfinApiController
// Clients reporting Dolby Vision capabilities with fallbacks may only support the fallback layer.
// Only enable Dolby Vision remuxing if the client explicitly declares support for profiles without fallbacks.
var clientSupportsDoVi = requestedRange.Contains(VideoRangeType.DOVI.ToString(), StringComparison.OrdinalIgnoreCase);
- var videoIsDoVi = state.VideoStream.VideoRangeType is VideoRangeType.DOVI or VideoRangeType.DOVIWithHDR10 or VideoRangeType.DOVIWithHLG or VideoRangeType.DOVIWithSDR;
+ var videoIsDoVi = EncodingHelper.IsDovi(state.VideoStream);
if (EncodingHelper.IsCopyCodec(codec)
- && (videoIsDoVi && clientSupportsDoVi))
+ && (videoIsDoVi && clientSupportsDoVi)
+ && !_encodingHelper.IsDoviRemoved(state))
{
if (isActualOutputVideoCodecHevc)
{
@@ -1855,7 +1857,7 @@ public class DynamicHlsController : BaseJellyfinApiController
// If h264_mp4toannexb is ever added, do not use it for live tv.
if (state.VideoStream is not null && !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase))
{
- string bitStreamArgs = EncodingHelper.GetBitStreamArgs(state.VideoStream);
+ string bitStreamArgs = _encodingHelper.GetBitStreamArgs(state, MediaStreamType.Video);
if (!string.IsNullOrEmpty(bitStreamArgs))
{
args += " " + bitStreamArgs;
@@ -2056,16 +2058,16 @@ public class DynamicHlsController : BaseJellyfinApiController
}
}
- private Task DeleteLastFile(string playlistPath, string segmentExtension, int retryCount)
+ private async Task DeleteLastFile(string playlistPath, string segmentExtension, int retryCount)
{
var file = GetLastTranscodingFile(playlistPath, segmentExtension, _fileSystem);
if (file is null)
{
- return Task.CompletedTask;
+ return;
}
- return DeleteFile(file.FullName, retryCount);
+ await DeleteFile(file.FullName, retryCount).ConfigureAwait(false);
}
private async Task DeleteFile(string path, int retryCount)