Skip to content
Permalink
Browse files
Merged jellyfin#5951
  • Loading branch information
BaronGreenback committed May 2, 2021
2 parents 9c5e2f4 + e10f8dc commit cf9ae8206f31152c1fa51fc08fe9d680bdc16b31
@@ -1628,7 +1628,7 @@ private bool FileExists(string path, string timerId)

private IRecorder GetRecorder(MediaSourceInfo mediaSource)
{
if (mediaSource.RequiresLooping || !(mediaSource.Container ?? string.Empty).EndsWith("ts", StringComparison.OrdinalIgnoreCase) || (mediaSource.Protocol != MediaProtocol.File && mediaSource.Protocol != MediaProtocol.Http))
if (mediaSource.RequiresLooping || !mediaSource.Container.EndsWith("ts", StringComparison.OrdinalIgnoreCase) || (mediaSource.Protocol != MediaProtocol.File && mediaSource.Protocol != MediaProtocol.Http))
{
return new EncodedRecorder(_logger, _mediaEncoder, _config.ApplicationPaths, _config);
}
@@ -247,6 +247,7 @@ public AudioController(AudioHelper audioHelper)
/// <param name="videoStreamIndex">Optional. The index of the video stream to use. If omitted the first video stream will be used.</param>
/// <param name="context">Optional. The <see cref="EncodingContext"/>.</param>
/// <param name="streamOptions">Optional. The streaming options.</param>
/// <param name="ext">Optional. The original stream extension.</param>
/// <response code="200">Audio stream returned.</response>
/// <returns>A <see cref="FileResult"/> containing the audio file.</returns>
[HttpGet("{itemId}/stream.{container}", Name = "GetAudioStreamByContainer")]
@@ -302,7 +303,8 @@ public AudioController(AudioHelper audioHelper)
[FromQuery] int? audioStreamIndex,
[FromQuery] int? videoStreamIndex,
[FromQuery] EncodingContext? context,
[FromQuery] Dictionary<string, string>? streamOptions)
[FromQuery] Dictionary<string, string>? streamOptions,
[FromQuery] string? ext)
{
StreamingRequestDto streamingRequest = new StreamingRequestDto
{
@@ -354,7 +356,8 @@ public AudioController(AudioHelper audioHelper)
AudioStreamIndex = audioStreamIndex,
VideoStreamIndex = videoStreamIndex,
Context = context ?? EncodingContext.Static,
StreamOptions = streamOptions
StreamOptions = streamOptions,
OriginalExtension = ext
};

return await _audioHelper.GetAudioStream(_transcodingJobType, streamingRequest).ConfigureAwait(false);
@@ -311,6 +311,7 @@ public async Task<ActionResult> MergeVersions([FromQuery, Required, ModelBinder(
/// <param name="videoStreamIndex">Optional. The index of the video stream to use. If omitted the first video stream will be used.</param>
/// <param name="context">Optional. The <see cref="EncodingContext"/>.</param>
/// <param name="streamOptions">Optional. The streaming options.</param>
/// <param name="ext">Optional. The stream's original extension.</param>
/// <response code="200">Video stream returned.</response>
/// <returns>A <see cref="FileResult"/> containing the audio file.</returns>
[HttpGet("{itemId}/stream")]
@@ -366,7 +367,8 @@ public async Task<ActionResult> MergeVersions([FromQuery, Required, ModelBinder(
[FromQuery] int? audioStreamIndex,
[FromQuery] int? videoStreamIndex,
[FromQuery] EncodingContext? context,
[FromQuery] Dictionary<string, string> streamOptions)
[FromQuery] Dictionary<string, string> streamOptions,
[FromQuery] string? ext)
{
var isHeadRequest = Request.Method == System.Net.WebRequestMethods.Http.Head;
var cancellationTokenSource = new CancellationTokenSource();
@@ -420,7 +422,8 @@ public async Task<ActionResult> MergeVersions([FromQuery, Required, ModelBinder(
AudioStreamIndex = audioStreamIndex,
VideoStreamIndex = videoStreamIndex,
Context = context ?? EncodingContext.Streaming,
StreamOptions = streamOptions
StreamOptions = streamOptions,
OriginalExtension = ext
};

using var state = await StreamingHelpers.GetStreamingState(
@@ -590,6 +593,7 @@ public async Task<ActionResult> MergeVersions([FromQuery, Required, ModelBinder(
/// <param name="videoStreamIndex">Optional. The index of the video stream to use. If omitted the first video stream will be used.</param>
/// <param name="context">Optional. The <see cref="EncodingContext"/>.</param>
/// <param name="streamOptions">Optional. The streaming options.</param>
/// <param name="ext">Optional. The stream's original extension.</param>
/// <response code="200">Video stream returned.</response>
/// <returns>A <see cref="FileResult"/> containing the audio file.</returns>
[HttpGet("{itemId}/{stream=stream}.{container}")]
@@ -645,7 +649,8 @@ public async Task<ActionResult> MergeVersions([FromQuery, Required, ModelBinder(
[FromQuery] int? audioStreamIndex,
[FromQuery] int? videoStreamIndex,
[FromQuery] EncodingContext? context,
[FromQuery] Dictionary<string, string> streamOptions)
[FromQuery] Dictionary<string, string> streamOptions,
[FromQuery] string? ext)
{
return GetVideoStream(
itemId,
@@ -696,7 +701,8 @@ public async Task<ActionResult> MergeVersions([FromQuery, Required, ModelBinder(
audioStreamIndex,
videoStreamIndex,
context,
streamOptions);
streamOptions,
ext);
}
}
}
@@ -348,7 +348,7 @@ public class MediaInfoHelper
{
streamInfo.PlaySessionId = playSessionId;
streamInfo.StartPositionTicks = startTimeTicks;
mediaSource.TranscodingUrl = streamInfo.ToUrl("-", auth.Token).TrimStart('-');
mediaSource.TranscodingUrl = streamInfo.ToUrl(null, auth.Token);
mediaSource.TranscodingUrl += "&allowVideoStreamCopy=false";
mediaSource.TranscodingUrl += "&allowAudioStreamCopy=false";
mediaSource.TranscodingContainer = streamInfo.Container;
@@ -368,7 +368,7 @@ public class MediaInfoHelper
if (streamInfo.PlayMethod == PlayMethod.Transcode)
{
streamInfo.StartPositionTicks = startTimeTicks;
mediaSource.TranscodingUrl = streamInfo.ToUrl("-", auth.Token).TrimStart('-');
mediaSource.TranscodingUrl = streamInfo.ToUrl(null, auth.Token);

if (!allowVideoStreamCopy)
{
@@ -83,7 +83,7 @@ public static class StreamingHelpers
throw new ResourceNotFoundException(nameof(httpRequest.Path));
}

var url = httpRequest.Path.Value.Split('.')[^1];
var url = streamingRequest.OriginalExtension ?? httpRequest.Path.Value.Split('.')[^1];

if (string.IsNullOrEmpty(streamingRequest.AudioCodec))
{
@@ -93,8 +93,8 @@ public static class StreamingHelpers
var state = new StreamState(mediaSourceManager, transcodingJobType, transcodingJobHelper)
{
Request = streamingRequest,
RequestedUrl = httpRequest.Path,
UserAgent = httpRequest.Headers[HeaderNames.UserAgent]
UserAgent = httpRequest.Headers[HeaderNames.UserAgent],
Extension = url
};

var auth = authorizationContext.GetAuthorizationInfo(httpRequest);
@@ -162,9 +162,9 @@ public static class StreamingHelpers

var encodingOptions = serverConfigurationManager.GetEncodingOptions();

encodingHelper.AttachMediaSourceInfo(state, encodingOptions, mediaSource, url);
encodingHelper.AttachMediaSourceInfo(state, encodingOptions, mediaSource, state.Extension);

string? containerInternal = Path.GetExtension(state.RequestedUrl);
string? containerInternal = state.Extension;

if (!string.IsNullOrEmpty(streamingRequest.Container))
{
@@ -281,11 +281,9 @@ public static class StreamingHelpers
/// <returns>System.String.</returns>
private static string? GetOutputFileExtension(StreamState state)
{
var ext = Path.GetExtension(state.RequestedUrl);

if (!string.IsNullOrEmpty(ext))
if (!string.IsNullOrEmpty(state.Extension))
{
return ext;
return state.Extension;
}

// Try to infer based on the desired video codec
@@ -763,7 +763,7 @@ private async Task AcquireResources(StreamState state, CancellationTokenSource c
.ConfigureAwait(false);
var encodingOptions = _serverConfigurationManager.GetEncodingOptions();

_encodingHelper.AttachMediaSourceInfo(state, encodingOptions, liveStreamResponse.MediaSource, state.RequestedUrl);
_encodingHelper.AttachMediaSourceInfo(state, encodingOptions, liveStreamResponse.MediaSource, state.Extension);

if (state.VideoRequest != null)
{
@@ -29,11 +29,6 @@ public StreamState(IMediaSourceManager mediaSourceManager, TranscodingJobType tr
_transcodingJobHelper = transcodingJobHelper;
}

/// <summary>
/// Gets or sets the requested url.
/// </summary>
public string? RequestedUrl { get; set; }

/// <summary>
/// Gets or sets the request.
/// </summary>
@@ -125,6 +120,11 @@ public int MinSegments
}
}

/// <summary>
/// Gets or sets the stream's extension.
/// </summary>
public string? Extension { get; set; }

/// <summary>
/// Gets or sets the user agent.
/// </summary>
@@ -1,4 +1,4 @@
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.MediaEncoding;

namespace Jellyfin.Api.Models.StreamingDtos
{
@@ -41,5 +41,10 @@ public class StreamingRequestDto : BaseEncodingJobOptions
/// Gets or sets the min segments.
/// </summary>
public int? MinSegments { get; set; }

/// <summary>
/// Gets or sets the original file extension.
/// </summary>
public string? OriginalExtension { get; set; }
}
}
@@ -393,12 +393,10 @@ public string InferAudioCodec(string container)
/// <summary>
/// Infers the video codec.
/// </summary>
/// <param name="url">The URL.</param>
/// <param name="ext">The file extensive.</param>
/// <returns>System.Nullable{VideoCodecs}.</returns>
public string InferVideoCodec(string url)
public string InferVideoCodec(string ext)
{
var ext = Path.GetExtension(url);

if (string.Equals(ext, ".asf", StringComparison.OrdinalIgnoreCase))
{
return "wmv";
@@ -696,19 +694,16 @@ public static string GetBitStreamArgs(MediaStream stream)

public static string GetAudioBitStreamArguments(EncodingJobInfo state, string segmentContainer, string mediaSourceContainer)
{
var bitStreamArgs = string.Empty;
var segmentFormat = GetSegmentFileExtension(segmentContainer).TrimStart('.');

// Apply aac_adtstoasc bitstream filter when media source is in mpegts.
if (string.Equals(segmentFormat, "mp4", StringComparison.OrdinalIgnoreCase)
if (string.Equals(segmentContainer, "mp4", StringComparison.OrdinalIgnoreCase)
&& (string.Equals(mediaSourceContainer, "mpegts", StringComparison.OrdinalIgnoreCase)
|| string.Equals(mediaSourceContainer, "hls", StringComparison.OrdinalIgnoreCase)))
{
bitStreamArgs = GetBitStreamArgs(state.AudioStream);
bitStreamArgs = string.IsNullOrEmpty(bitStreamArgs) ? string.Empty : " " + bitStreamArgs;
var bitStreamArgs = GetBitStreamArgs(state.AudioStream);
return string.IsNullOrEmpty(bitStreamArgs) ? string.Empty : " " + bitStreamArgs;
}

return bitStreamArgs;
return string.Empty;
}

public static string GetSegmentFileExtension(string segmentContainer)
@@ -3133,7 +3128,7 @@ public string GetInputModifier(EncodingJobInfo state, EncodingOptions encodingOp
EncodingJobInfo state,
EncodingOptions encodingOptions,
MediaSourceInfo mediaSource,
string requestedUrl)
string extension)
{
if (state == null)
{
@@ -3172,8 +3167,8 @@ public string GetInputModifier(EncodingJobInfo state, EncodingOptions encodingOp
state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate;

if (state.ReadInputAtNativeFramerate
|| mediaSource.Protocol == MediaProtocol.File
&& string.Equals(mediaSource.Container, "wtv", StringComparison.OrdinalIgnoreCase))
|| (mediaSource.Protocol == MediaProtocol.File
&& string.Equals(mediaSource.Container, "wtv", StringComparison.OrdinalIgnoreCase)))
{
state.InputVideoSync = "-1";
state.InputAudioSync = "1";
@@ -3194,12 +3189,7 @@ public string GetInputModifier(EncodingJobInfo state, EncodingOptions encodingOp

if (string.IsNullOrEmpty(videoRequest.VideoCodec))
{
if (string.IsNullOrEmpty(requestedUrl))
{
requestedUrl = "test." + videoRequest.Container;
}

videoRequest.VideoCodec = InferVideoCodec(requestedUrl);
videoRequest.VideoCodec = InferVideoCodec(extension);
}

state.VideoStream = GetMediaStream(mediaStreams, videoRequest.VideoStreamIndex, MediaStreamType.Video);
@@ -604,11 +604,6 @@ public string ToUrl(string baseUrl, string accessToken)
return MediaSource.Path;
}

if (string.IsNullOrEmpty(baseUrl))
{
throw new ArgumentNullException(nameof(baseUrl));
}

var list = new List<string>();
foreach (NameValuePair pair in BuildParams(this, accessToken))
{
@@ -648,14 +643,7 @@ public string ToUrl(string baseUrl, string accessToken)

private string GetUrl(string baseUrl, string queryString)
{
if (string.IsNullOrEmpty(baseUrl))
{
throw new ArgumentNullException(nameof(baseUrl));
}

string extension = string.IsNullOrEmpty(Container) ? string.Empty : "." + Container;

baseUrl = baseUrl.TrimEnd('/');
baseUrl = baseUrl?.TrimEnd('/') ?? string.Empty;

if (MediaType == DlnaProfileType.Audio)
{
@@ -664,15 +652,27 @@ private string GetUrl(string baseUrl, string queryString)
return string.Format(CultureInfo.InvariantCulture, "{0}/audio/{1}/master.m3u8?{2}", baseUrl, ItemId, queryString);
}

return string.Format(CultureInfo.InvariantCulture, "{0}/audio/{1}/stream{2}?{3}", baseUrl, ItemId, extension, queryString);
// Store the original container name, and fake response a .ts so media will show up.
if (!string.IsNullOrEmpty(Container))
{
queryString += "&ext=." + Container;
}

return string.Format(CultureInfo.InvariantCulture, "{0}/audio/{1}/stream.ts?{2}", baseUrl, ItemId, queryString);
}

if (string.Equals(SubProtocol, "hls", StringComparison.OrdinalIgnoreCase))
{
return string.Format(CultureInfo.InvariantCulture, "{0}/videos/{1}/master.m3u8?{2}", baseUrl, ItemId, queryString);
}

return string.Format(CultureInfo.InvariantCulture, "{0}/videos/{1}/stream{2}?{3}", baseUrl, ItemId, extension, queryString);
// Store the original container name, and fake response a .ts so media will show up.
if (!string.IsNullOrEmpty(Container))
{
queryString += "&ext=." + Container;
}

return string.Format(CultureInfo.InvariantCulture, "{0}/videos/{1}/stream.ts?{2}", baseUrl, ItemId, queryString);
}

private static List<NameValuePair> BuildParams(StreamInfo item, string accessToken)

0 comments on commit cf9ae82

Please sign in to comment.