Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add control over multiple codec streaming to the device profile #9016

Draft
wants to merge 1 commit into
base: release-10.8.z
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 12 additions & 6 deletions Jellyfin.Api/Controllers/DynamicHlsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@ public class DynamicHlsController : BaseJellyfinApiController
/// <param name="context">Optional. The <see cref="EncodingContext"/>.</param>
/// <param name="streamOptions">Optional. The streaming options.</param>
/// <param name="enableAdaptiveBitrateStreaming">Enable adaptive bitrate streaming.</param>
/// <param name="enableMultipleCodecStreaming">Enable multiple codec streaming.</param>
/// <response code="200">Video stream returned.</response>
/// <returns>A <see cref="FileResult"/> containing the playlist file.</returns>
[HttpGet("Videos/{itemId}/master.m3u8")]
Expand Down Expand Up @@ -468,7 +469,8 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] int? videoStreamIndex,
[FromQuery] EncodingContext? context,
[FromQuery] Dictionary<string, string> streamOptions,
[FromQuery] bool enableAdaptiveBitrateStreaming = true)
[FromQuery] bool enableAdaptiveBitrateStreaming = true,
[FromQuery] bool enableMultipleCodecStreaming = true)
{
var streamingRequest = new HlsVideoRequestDto
{
Expand Down Expand Up @@ -522,10 +524,11 @@ public class DynamicHlsController : BaseJellyfinApiController
VideoStreamIndex = videoStreamIndex,
Context = context ?? EncodingContext.Streaming,
StreamOptions = streamOptions,
EnableAdaptiveBitrateStreaming = enableAdaptiveBitrateStreaming
EnableAdaptiveBitrateStreaming = enableAdaptiveBitrateStreaming,
EnableMultipleCodecStreaming = enableMultipleCodecStreaming
};

return await _dynamicHlsHelper.GetMasterHlsPlaylist(TranscodingJobType, streamingRequest, enableAdaptiveBitrateStreaming).ConfigureAwait(false);
return await _dynamicHlsHelper.GetMasterHlsPlaylist(TranscodingJobType, streamingRequest, enableAdaptiveBitrateStreaming, enableMultipleCodecStreaming).ConfigureAwait(false);
}

/// <summary>
Expand Down Expand Up @@ -581,6 +584,7 @@ public class DynamicHlsController : BaseJellyfinApiController
/// <param name="context">Optional. The <see cref="EncodingContext"/>.</param>
/// <param name="streamOptions">Optional. The streaming options.</param>
/// <param name="enableAdaptiveBitrateStreaming">Enable adaptive bitrate streaming.</param>
/// <param name="enableMultipleCodecStreaming">Enable multiple codec streaming.</param>
/// <response code="200">Audio stream returned.</response>
/// <returns>A <see cref="FileResult"/> containing the playlist file.</returns>
[HttpGet("Audio/{itemId}/master.m3u8")]
Expand Down Expand Up @@ -637,7 +641,8 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] int? videoStreamIndex,
[FromQuery] EncodingContext? context,
[FromQuery] Dictionary<string, string> streamOptions,
[FromQuery] bool enableAdaptiveBitrateStreaming = true)
[FromQuery] bool enableAdaptiveBitrateStreaming = true,
[FromQuery] bool enableMultipleCodecStreaming = true)
{
var streamingRequest = new HlsAudioRequestDto
{
Expand Down Expand Up @@ -689,10 +694,11 @@ public class DynamicHlsController : BaseJellyfinApiController
VideoStreamIndex = videoStreamIndex,
Context = context ?? EncodingContext.Streaming,
StreamOptions = streamOptions,
EnableAdaptiveBitrateStreaming = enableAdaptiveBitrateStreaming
EnableAdaptiveBitrateStreaming = enableAdaptiveBitrateStreaming,
EnableMultipleCodecStreaming = enableMultipleCodecStreaming
};

return await _dynamicHlsHelper.GetMasterHlsPlaylist(TranscodingJobType, streamingRequest, enableAdaptiveBitrateStreaming).ConfigureAwait(false);
return await _dynamicHlsHelper.GetMasterHlsPlaylist(TranscodingJobType, streamingRequest, enableAdaptiveBitrateStreaming, enableMultipleCodecStreaming).ConfigureAwait(false);
}

/// <summary>
Expand Down
5 changes: 3 additions & 2 deletions Jellyfin.Api/Controllers/UniversalAudioController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -233,10 +233,11 @@ public class UniversalAudioController : BaseJellyfinApiController
TranscodeReasons = mediaSource.TranscodeReasons == 0 ? null : mediaSource.TranscodeReasons.ToString(),
Context = EncodingContext.Static,
StreamOptions = new Dictionary<string, string>(),
EnableAdaptiveBitrateStreaming = true
EnableAdaptiveBitrateStreaming = true,
EnableMultipleCodecStreaming = true
};

return await _dynamicHlsHelper.GetMasterHlsPlaylist(TranscodingJobType.Hls, dynamicHlsRequestDto, true)
return await _dynamicHlsHelper.GetMasterHlsPlaylist(TranscodingJobType.Hls, dynamicHlsRequestDto, true, true)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The device profile is ignored here.

.ConfigureAwait(false);
}

Expand Down
8 changes: 6 additions & 2 deletions Jellyfin.Api/Helpers/DynamicHlsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,13 @@ public class DynamicHlsHelper
/// <param name="transcodingJobType">Transcoding job type.</param>
/// <param name="streamingRequest">Streaming request dto.</param>
/// <param name="enableAdaptiveBitrateStreaming">Enable adaptive bitrate streaming.</param>
/// <param name="enableMultipleCodecStreaming">Enable multiple codec streaming.</param>
/// <returns>A <see cref="Task"/> containing the resulting <see cref="ActionResult"/>.</returns>
public async Task<ActionResult> GetMasterHlsPlaylist(
TranscodingJobType transcodingJobType,
StreamingRequestDto streamingRequest,
bool enableAdaptiveBitrateStreaming)
bool enableAdaptiveBitrateStreaming,
bool enableMultipleCodecStreaming)
{
var isHeadRequest = _httpContextAccessor.HttpContext?.Request.Method == WebRequestMethods.Http.Head;
// CTS lifecycle is managed internally.
Expand All @@ -110,6 +112,7 @@ public class DynamicHlsHelper
streamingRequest,
isHeadRequest,
enableAdaptiveBitrateStreaming,
enableMultipleCodecStreaming,
transcodingJobType,
cancellationTokenSource).ConfigureAwait(false);
}
Expand All @@ -118,6 +121,7 @@ public class DynamicHlsHelper
StreamingRequestDto streamingRequest,
bool isHeadRequest,
bool enableAdaptiveBitrateStreaming,
bool enableMultipleCodecStreaming,
TranscodingJobType transcodingJobType,
CancellationTokenSource cancellationTokenSource)
{
Expand Down Expand Up @@ -200,7 +204,7 @@ public class DynamicHlsHelper

var basicPlaylist = AppendPlaylist(builder, state, playlistUrl, totalBitrate, subtitleGroup);

if (state.VideoStream != null && state.VideoRequest != null)
if (enableMultipleCodecStreaming && state.VideoStream != null && state.VideoRequest != null)
{
// Provide SDR HEVC entrance for backward compatibility.
if (EncodingHelper.IsCopyCodec(state.OutputVideoCodec)
Expand Down
5 changes: 5 additions & 0 deletions Jellyfin.Api/Models/StreamingDtos/HlsAudioRequestDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,10 @@ public class HlsAudioRequestDto : StreamingRequestDto
/// Gets or sets a value indicating whether enable adaptive bitrate streaming.
/// </summary>
public bool EnableAdaptiveBitrateStreaming { get; set; }

/// <summary>
/// Gets or sets a value indicating whether enable multiple codec streaming.
/// </summary>
public bool EnableMultipleCodecStreaming { get; set; }
}
}
5 changes: 5 additions & 0 deletions Jellyfin.Api/Models/StreamingDtos/HlsVideoRequestDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,10 @@ public class HlsVideoRequestDto : VideoRequestDto
/// Gets or sets a value indicating whether enable adaptive bitrate streaming.
/// </summary>
public bool EnableAdaptiveBitrateStreaming { get; set; }

/// <summary>
/// Gets or sets a value indicating whether enable multiple codec streaming.
/// </summary>
public bool EnableMultipleCodecStreaming { get; set; }
}
}
5 changes: 5 additions & 0 deletions MediaBrowser.Model/Dlna/DeviceProfile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ public class DeviceProfile
[DefaultValue(false)]
public bool EnableAlbumArtInDidl { get; set; }

/// <summary>
/// Gets or sets a value indicating whether enable multiple codec streaming.
/// </summary>
public bool? EnableMultipleCodecStreaming { get; set; }

/// <summary>
/// Gets or sets a value indicating whether EnableSingleAlbumArtLimit.
/// </summary>
Expand Down
10 changes: 10 additions & 0 deletions MediaBrowser.Model/Dlna/StreamBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,11 @@ private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options)

var longBitrate = Math.Min(transcodingBitrate, playlistItem.AudioBitrate ?? transcodingBitrate);
playlistItem.AudioBitrate = longBitrate > int.MaxValue ? int.MaxValue : Convert.ToInt32(longBitrate);

if (options.Profile.EnableMultipleCodecStreaming.HasValue)
{
playlistItem.EnableMultipleCodecStreaming = options.Profile.EnableMultipleCodecStreaming;
}
}

playlistItem.TranscodeReasons = transcodeReasons;
Expand Down Expand Up @@ -916,6 +921,11 @@ private void BuildStreamVideoItem(StreamInfo playlistItem, VideoOptions options,
playlistItem.VideoBitrate = Math.Max(Math.Min(availableBitrateForVideo, currentValue), 64_000);
}

if (options.Profile.EnableMultipleCodecStreaming.HasValue)
{
playlistItem.EnableMultipleCodecStreaming = options.Profile.EnableMultipleCodecStreaming;
}

_logger.LogDebug(
"Transcode Result for Profile: {Profile}, Path: {Path}, PlayMethod: {PlayMethod}, AudioStreamIndex: {AudioStreamIndex}, SubtitleStreamIndex: {SubtitleStreamIndex}, Reasons: {TranscodeReason}",
options.Profile?.Name ?? "Anonymous Profile",
Expand Down
7 changes: 7 additions & 0 deletions MediaBrowser.Model/Dlna/StreamInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,11 @@ public TransportStreamTimestamp TargetTimestamp
}
}

/// <summary>
/// Gets or sets a value indicating whether enable multiple codec streaming.
/// </summary>
public bool? EnableMultipleCodecStreaming { get; set; }

public void SetOption(string qualifier, string name, string value)
{
if (string.IsNullOrEmpty(qualifier))
Expand Down Expand Up @@ -741,6 +746,8 @@ private static IEnumerable<NameValuePair> BuildParams(StreamInfo item, string ac

list.Add(new NameValuePair("SubtitleMethod", item.SubtitleStreamIndex.HasValue && item.SubtitleDeliveryMethod != SubtitleDeliveryMethod.External ? item.SubtitleDeliveryMethod.ToString() : string.Empty));

list.Add(new NameValuePair("EnableMultipleCodecStreaming", item.EnableMultipleCodecStreaming.HasValue ? item.EnableMultipleCodecStreaming.Value.ToString(CultureInfo.InvariantCulture).ToLowerInvariant() : string.Empty));

if (!item.IsDirectStream)
{
if (item.RequireNonAnamorphic)
Expand Down