|
@@ -108,7 +108,7 @@ namespace MediaBrowser.Model.Dlna
|
|
|
var inputAudioSampleRate = audioStream?.SampleRate;
|
|
|
var inputAudioBitDepth = audioStream?.BitDepth;
|
|
|
|
|
|
- if (directPlayMethod.HasValue)
|
|
|
+ if (directPlayMethod is PlayMethod.DirectPlay)
|
|
|
{
|
|
|
var profile = options.Profile;
|
|
|
var audioFailureConditions = GetProfileConditionsForAudio(profile.CodecProfiles, item.Container, audioStream?.Codec, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth, true);
|
|
@@ -124,6 +124,46 @@ namespace MediaBrowser.Model.Dlna
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (directPlayMethod is PlayMethod.DirectStream)
|
|
|
+ {
|
|
|
+ var remuxContainer = item.TranscodingContainer ?? "ts";
|
|
|
+ var supportedHlsContainers = new[] { "ts", "mp4" };
|
|
|
+ // If the container specified for the profile is an HLS supported container, use that container instead, overriding the preference
|
|
|
+ // The client should be responsible to ensure this container is compatible
|
|
|
+ remuxContainer = Array.Exists(supportedHlsContainers, element => string.Equals(element, directPlayInfo.Profile?.Container, StringComparison.OrdinalIgnoreCase)) ? directPlayInfo.Profile?.Container : remuxContainer;
|
|
|
+ bool codeIsSupported;
|
|
|
+ if (item.TranscodingSubProtocol == MediaStreamProtocol.hls)
|
|
|
+ {
|
|
|
+ // Enforce HLS audio codec restrictions
|
|
|
+ if (string.Equals(remuxContainer, "mp4", StringComparison.OrdinalIgnoreCase))
|
|
|
+ {
|
|
|
+ codeIsSupported = _supportedHlsAudioCodecsMp4.Contains(directPlayInfo.Profile?.AudioCodec ?? directPlayInfo.Profile?.Container);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ codeIsSupported = _supportedHlsAudioCodecsTs.Contains(directPlayInfo.Profile?.AudioCodec ?? directPlayInfo.Profile?.Container);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // Let's assume the client has given a correct container for http
|
|
|
+ codeIsSupported = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (codeIsSupported)
|
|
|
+ {
|
|
|
+ playlistItem.PlayMethod = directPlayMethod.Value;
|
|
|
+ playlistItem.Container = remuxContainer;
|
|
|
+ playlistItem.TranscodeReasons = transcodeReasons;
|
|
|
+ playlistItem.SubProtocol = item.TranscodingSubProtocol;
|
|
|
+ item.TranscodingContainer = remuxContainer;
|
|
|
+ return playlistItem;
|
|
|
+ }
|
|
|
+
|
|
|
+ transcodeReasons |= TranscodeReason.AudioCodecNotSupported;
|
|
|
+ playlistItem.TranscodeReasons = transcodeReasons;
|
|
|
+ }
|
|
|
+
|
|
|
TranscodingProfile? transcodingProfile = null;
|
|
|
foreach (var tcProfile in options.Profile.TranscodingProfiles)
|
|
|
{
|
|
@@ -379,6 +419,7 @@ namespace MediaBrowser.Model.Dlna
|
|
|
var directPlayProfile = options.Profile.DirectPlayProfiles
|
|
|
.FirstOrDefault(x => x.Type == DlnaProfileType.Audio && IsAudioDirectPlaySupported(x, item, audioStream));
|
|
|
|
|
|
+ TranscodeReason transcodeReasons = 0;
|
|
|
if (directPlayProfile is null)
|
|
|
{
|
|
|
_logger.LogDebug(
|
|
@@ -387,14 +428,25 @@ namespace MediaBrowser.Model.Dlna
|
|
|
item.Path ?? "Unknown path",
|
|
|
audioStream.Codec ?? "Unknown codec");
|
|
|
|
|
|
- return (null, null, GetTranscodeReasonsFromDirectPlayProfile(item, null, audioStream, options.Profile.DirectPlayProfiles));
|
|
|
- }
|
|
|
+ var directStreamProfile = options.Profile.DirectPlayProfiles
|
|
|
+ .FirstOrDefault(x => x.Type == DlnaProfileType.Audio && IsAudioDirectStreamSupported(x, item, audioStream));
|
|
|
|
|
|
- TranscodeReason transcodeReasons = 0;
|
|
|
+ if (directStreamProfile is not null)
|
|
|
+ {
|
|
|
+ directPlayProfile = directStreamProfile;
|
|
|
+ transcodeReasons |= TranscodeReason.ContainerNotSupported;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return (null, null, GetTranscodeReasonsFromDirectPlayProfile(item, null, audioStream, options.Profile.DirectPlayProfiles));
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
// The profile describes what the device supports
|
|
|
// If device requirements are satisfied then allow both direct stream and direct play
|
|
|
- if (item.SupportsDirectPlay)
|
|
|
+ // Note: As of 10.10 codebase, SupportsDirectPlay is always true because the MediaSourceInfo initializes this key as true
|
|
|
+ // Need to check additionally for current transcode reasons
|
|
|
+ if (item.SupportsDirectPlay && transcodeReasons == 0)
|
|
|
{
|
|
|
if (!IsBitrateLimitExceeded(item, options.GetMaxBitrate(true) ?? 0))
|
|
|
{
|
|
@@ -414,7 +466,10 @@ namespace MediaBrowser.Model.Dlna
|
|
|
{
|
|
|
if (!IsBitrateLimitExceeded(item, options.GetMaxBitrate(true) ?? 0))
|
|
|
{
|
|
|
- if (options.EnableDirectStream)
|
|
|
+ // Note: as of 10.10 codebase, the options.EnableDirectStream is always false due to
|
|
|
+ // "direct-stream http streaming is currently broken"
|
|
|
+ // Don't check that option for audio as we always assume that is supported
|
|
|
+ if (transcodeReasons == TranscodeReason.ContainerNotSupported)
|
|
|
{
|
|
|
return (directPlayProfile, PlayMethod.DirectStream, transcodeReasons);
|
|
|
}
|
|
@@ -2129,5 +2184,24 @@ namespace MediaBrowser.Model.Dlna
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
+
|
|
|
+ private static bool IsAudioDirectStreamSupported(DirectPlayProfile profile, MediaSourceInfo item, MediaStream audioStream)
|
|
|
+ {
|
|
|
+ // Check container type, this should NOT be supported
|
|
|
+ // If the container is supported, the file should be directly played
|
|
|
+ if (!profile.SupportsContainer(item.Container))
|
|
|
+ {
|
|
|
+ // Check audio codec, we cannot use the SupportsAudioCodec here
|
|
|
+ // Because that one assumes empty container supports all codec, which is just useless
|
|
|
+ string? audioCodec = audioStream?.Codec;
|
|
|
+ if (string.Equals(profile.AudioCodec, audioCodec, StringComparison.OrdinalIgnoreCase) ||
|
|
|
+ string.Equals(profile.Container, audioCodec, StringComparison.OrdinalIgnoreCase))
|
|
|
+ {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
}
|
|
|
}
|