diff options
Diffstat (limited to 'Jellyfin.Api/Helpers/StreamingHelpers.cs')
| -rw-r--r-- | Jellyfin.Api/Helpers/StreamingHelpers.cs | 239 |
1 files changed, 2 insertions, 237 deletions
diff --git a/Jellyfin.Api/Helpers/StreamingHelpers.cs b/Jellyfin.Api/Helpers/StreamingHelpers.cs index 7d9a38931..71c62b235 100644 --- a/Jellyfin.Api/Helpers/StreamingHelpers.cs +++ b/Jellyfin.Api/Helpers/StreamingHelpers.cs @@ -12,15 +12,12 @@ using Jellyfin.Extensions; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Devices; -using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Primitives; using Microsoft.Net.Http.Headers; namespace Jellyfin.Api.Helpers; @@ -41,8 +38,6 @@ public static class StreamingHelpers /// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param> /// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param> /// <param name="encodingHelper">Instance of <see cref="EncodingHelper"/>.</param> - /// <param name="dlnaManager">Instance of the <see cref="IDlnaManager"/> interface.</param> - /// <param name="deviceManager">Instance of the <see cref="IDeviceManager"/> interface.</param> /// <param name="transcodingJobHelper">Initialized <see cref="TranscodingJobHelper"/>.</param> /// <param name="transcodingJobType">The <see cref="TranscodingJobType"/>.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param> @@ -56,21 +51,11 @@ public static class StreamingHelpers IServerConfigurationManager serverConfigurationManager, IMediaEncoder mediaEncoder, EncodingHelper encodingHelper, - IDlnaManager dlnaManager, - IDeviceManager deviceManager, TranscodingJobHelper transcodingJobHelper, TranscodingJobType transcodingJobType, CancellationToken cancellationToken) { var httpRequest = httpContext.Request; - // Parse the DLNA time seek header - if (!streamingRequest.StartTimeTicks.HasValue) - { - var timeSeek = httpRequest.Headers["TimeSeekRange.dlna.org"]; - - streamingRequest.StartTimeTicks = ParseTimeSeekHeader(timeSeek.ToString()); - } - if (!string.IsNullOrWhiteSpace(streamingRequest.Params)) { ParseParams(streamingRequest); @@ -89,16 +74,11 @@ public static class StreamingHelpers streamingRequest.AudioCodec = encodingHelper.InferAudioCodec(url); } - var enableDlnaHeaders = !string.IsNullOrWhiteSpace(streamingRequest.Params) || - streamingRequest.StreamOptions.ContainsKey("dlnaheaders") || - string.Equals(httpRequest.Headers["GetContentFeatures.DLNA.ORG"], "1", StringComparison.OrdinalIgnoreCase); - var state = new StreamState(mediaSourceManager, transcodingJobType, transcodingJobHelper) { Request = streamingRequest, RequestedUrl = url, - UserAgent = httpRequest.Headers[HeaderNames.UserAgent], - EnableDlnaHeaders = enableDlnaHeaders + UserAgent = httpRequest.Headers[HeaderNames.UserAgent] }; var userId = httpContext.User.GetUserId(); @@ -243,8 +223,6 @@ public static class StreamingHelpers } } - ApplyDeviceProfileSettings(state, dlnaManager, deviceManager, httpRequest, streamingRequest.DeviceProfileId, streamingRequest.Static); - var ext = string.IsNullOrWhiteSpace(state.OutputContainer) ? GetOutputFileExtension(state, mediaSource) : ("." + state.OutputContainer); @@ -255,123 +233,6 @@ public static class StreamingHelpers } /// <summary> - /// Adds the dlna headers. - /// </summary> - /// <param name="state">The state.</param> - /// <param name="responseHeaders">The response headers.</param> - /// <param name="isStaticallyStreamed">if set to <c>true</c> [is statically streamed].</param> - /// <param name="startTimeTicks">The start time in ticks.</param> - /// <param name="request">The <see cref="HttpRequest"/>.</param> - /// <param name="dlnaManager">Instance of the <see cref="IDlnaManager"/> interface.</param> - public static void AddDlnaHeaders( - StreamState state, - IHeaderDictionary responseHeaders, - bool isStaticallyStreamed, - long? startTimeTicks, - HttpRequest request, - IDlnaManager dlnaManager) - { - if (!state.EnableDlnaHeaders) - { - return; - } - - var profile = state.DeviceProfile; - - StringValues transferMode = request.Headers["transferMode.dlna.org"]; - responseHeaders.Append("transferMode.dlna.org", string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode.ToString()); - responseHeaders.Append("realTimeInfo.dlna.org", "DLNA.ORG_TLAG=*"); - - if (state.RunTimeTicks.HasValue) - { - if (string.Equals(request.Headers["getMediaInfo.sec"], "1", StringComparison.OrdinalIgnoreCase)) - { - var ms = TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalMilliseconds; - responseHeaders.Append("MediaInfo.sec", string.Format( - CultureInfo.InvariantCulture, - "SEC_Duration={0};", - Convert.ToInt32(ms))); - } - - if (!isStaticallyStreamed && profile is not null) - { - AddTimeSeekResponseHeaders(state, responseHeaders, startTimeTicks); - } - } - - profile ??= dlnaManager.GetDefaultProfile(); - - var audioCodec = state.ActualOutputAudioCodec; - - if (!state.IsVideoRequest) - { - responseHeaders.Append("contentFeatures.dlna.org", ContentFeatureBuilder.BuildAudioHeader( - profile, - state.OutputContainer, - audioCodec, - state.OutputAudioBitrate, - state.OutputAudioSampleRate, - state.OutputAudioChannels, - state.OutputAudioBitDepth, - isStaticallyStreamed, - state.RunTimeTicks, - state.TranscodeSeekInfo)); - } - else - { - var videoCodec = state.ActualOutputVideoCodec; - - responseHeaders.Append( - "contentFeatures.dlna.org", - ContentFeatureBuilder.BuildVideoHeader(profile, state.OutputContainer, videoCodec, audioCodec, state.OutputWidth, state.OutputHeight, state.TargetVideoBitDepth, state.OutputVideoBitrate, state.TargetTimestamp, isStaticallyStreamed, state.RunTimeTicks, state.TargetVideoProfile, state.TargetVideoRangeType, state.TargetVideoLevel, state.TargetFramerate, state.TargetPacketLength, state.TranscodeSeekInfo, state.IsTargetAnamorphic, state.IsTargetInterlaced, state.TargetRefFrames, state.TargetVideoStreamCount, state.TargetAudioStreamCount, state.TargetVideoCodecTag, state.IsTargetAVC).FirstOrDefault() ?? string.Empty); - } - } - - /// <summary> - /// Parses the time seek header. - /// </summary> - /// <param name="value">The time seek header string.</param> - /// <returns>A nullable <see cref="long"/> representing the seek time in ticks.</returns> - private static long? ParseTimeSeekHeader(ReadOnlySpan<char> value) - { - if (value.IsEmpty) - { - return null; - } - - const string npt = "npt="; - if (!value.StartsWith(npt, StringComparison.OrdinalIgnoreCase)) - { - throw new ArgumentException("Invalid timeseek header"); - } - - var index = value.IndexOf('-'); - value = index == -1 - ? value.Slice(npt.Length) - : value.Slice(npt.Length, index - npt.Length); - if (!value.Contains(':')) - { - // Parses npt times in the format of '417.33' - if (double.TryParse(value, CultureInfo.InvariantCulture, out var seconds)) - { - return TimeSpan.FromSeconds(seconds).Ticks; - } - - throw new ArgumentException("Invalid timeseek header"); - } - - try - { - // Parses npt times in the format of '10:19:25.7' - return TimeSpan.Parse(value, CultureInfo.InvariantCulture).Ticks; - } - catch - { - throw new ArgumentException("Invalid timeseek header"); - } - } - - /// <summary> /// Parses query parameters as StreamOptions. /// </summary> /// <param name="queryString">The query string.</param> @@ -394,29 +255,6 @@ public static class StreamingHelpers } /// <summary> - /// Adds the dlna time seek headers to the response. - /// </summary> - /// <param name="state">The current <see cref="StreamState"/>.</param> - /// <param name="responseHeaders">The <see cref="IHeaderDictionary"/> of the response.</param> - /// <param name="startTimeTicks">The start time in ticks.</param> - private static void AddTimeSeekResponseHeaders(StreamState state, IHeaderDictionary responseHeaders, long? startTimeTicks) - { - var runtimeSeconds = TimeSpan.FromTicks(state.RunTimeTicks!.Value).TotalSeconds.ToString(CultureInfo.InvariantCulture); - var startSeconds = TimeSpan.FromTicks(startTimeTicks ?? 0).TotalSeconds.ToString(CultureInfo.InvariantCulture); - - responseHeaders.Append("TimeSeekRange.dlna.org", string.Format( - CultureInfo.InvariantCulture, - "npt={0}-{1}/{1}", - startSeconds, - runtimeSeconds)); - responseHeaders.Append("X-AvailableSeekRange", string.Format( - CultureInfo.InvariantCulture, - "1 npt={0}-{1}", - startSeconds, - runtimeSeconds)); - } - - /// <summary> /// Gets the output file extension. /// </summary> /// <param name="state">The state.</param> @@ -519,79 +357,6 @@ public static class StreamingHelpers return Path.Combine(folder, filename + ext); } - private static void ApplyDeviceProfileSettings(StreamState state, IDlnaManager dlnaManager, IDeviceManager deviceManager, HttpRequest request, string? deviceProfileId, bool? @static) - { - if (!string.IsNullOrWhiteSpace(deviceProfileId)) - { - state.DeviceProfile = dlnaManager.GetProfile(deviceProfileId); - - if (state.DeviceProfile is null) - { - var caps = deviceManager.GetCapabilities(deviceProfileId); - state.DeviceProfile = caps is null ? dlnaManager.GetProfile(request.Headers) : caps.DeviceProfile; - } - } - - var profile = state.DeviceProfile; - - if (profile is null) - { - // Don't use settings from the default profile. - // Only use a specific profile if it was requested. - return; - } - - var audioCodec = state.ActualOutputAudioCodec; - var videoCodec = state.ActualOutputVideoCodec; - - var mediaProfile = !state.IsVideoRequest - ? profile.GetAudioMediaProfile(state.OutputContainer, audioCodec, state.OutputAudioChannels, state.OutputAudioBitrate, state.OutputAudioSampleRate, state.OutputAudioBitDepth) - : profile.GetVideoMediaProfile( - state.OutputContainer, - audioCodec, - videoCodec, - state.OutputWidth, - state.OutputHeight, - state.TargetVideoBitDepth, - state.OutputVideoBitrate, - state.TargetVideoProfile, - state.TargetVideoRangeType, - state.TargetVideoLevel, - state.TargetFramerate, - state.TargetPacketLength, - state.TargetTimestamp, - state.IsTargetAnamorphic, - state.IsTargetInterlaced, - state.TargetRefFrames, - state.TargetVideoStreamCount, - state.TargetAudioStreamCount, - state.TargetVideoCodecTag, - state.IsTargetAVC); - - if (mediaProfile is not null) - { - state.MimeType = mediaProfile.MimeType; - } - - if (!(@static.HasValue && @static.Value)) - { - var transcodingProfile = !state.IsVideoRequest ? profile.GetAudioTranscodingProfile(state.OutputContainer, audioCodec) : profile.GetVideoTranscodingProfile(state.OutputContainer, audioCodec, videoCodec); - - if (transcodingProfile is not null) - { - state.EstimateContentLength = transcodingProfile.EstimateContentLength; - // state.EnableMpegtsM2TsMode = transcodingProfile.EnableMpegtsM2TsMode; - state.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; - - if (state.VideoRequest is not null) - { - state.VideoRequest.CopyTimestamps = transcodingProfile.CopyTimestamps; - state.VideoRequest.EnableSubtitlesInManifest = transcodingProfile.EnableSubtitlesInManifest; - } - } - } - } - /// <summary> /// Parses the parameters. /// </summary> @@ -619,7 +384,7 @@ public static class StreamingHelpers switch (i) { case 0: - request.DeviceProfileId = val; + // DeviceProfileId break; case 1: request.DeviceId = val; |
