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

DLNA fix : Make media visible and playable #5951

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from 2 commits
Commits
File filter
Filter file types
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.

Always

Just for now

@@ -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);
}
@@ -248,6 +248,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")]
@@ -303,7 +304,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
{
@@ -355,7 +357,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);
@@ -315,6 +315,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")]
@@ -370,7 +371,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();
@@ -424,7 +426,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(
@@ -568,6 +571,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}")]
@@ -623,7 +627,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,
@@ -674,7 +679,8 @@ public async Task<ActionResult> MergeVersions([FromQuery, Required, ModelBinder(
audioStreamIndex,
videoStreamIndex,
context,
streamOptions);
streamOptions,
ext);
}
}
}
@@ -1,4 +1,4 @@
using System;
using System;
using System.Globalization;
using System.Linq;
using System.Net;
@@ -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))
{
@@ -96,9 +96,9 @@ public static class StreamingHelpers
var state = new StreamState(mediaSourceManager, transcodingJobType, transcodingJobHelper)
{
Request = streamingRequest,
RequestedUrl = url,
UserAgent = httpRequest.Headers[HeaderNames.UserAgent],
EnableDlnaHeaders = enableDlnaHeaders
EnableDlnaHeaders = enableDlnaHeaders,
Extension = url
};

var auth = authorizationContext.GetAuthorizationInfo(httpRequest);
@@ -166,9 +166,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))
{
@@ -419,11 +419,9 @@ private static void AddTimeSeekResponseHeaders(StreamState state, IHeaderDiction
/// <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>
This conversation was marked as resolved by BaronGreenback

This comment has been minimized.

@crobibero

crobibero May 2, 2021
Member Outdated

Suggested change
/// <param name="ext">The file extensive.</param>
/// <param name="ext">The file extension.</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)
ProTip! Use n and p to navigate between commits in a pull request.