Convert TranscodeReason to Flags
This commit is contained in:
parent
a3057afde8
commit
d871dded9f
|
@ -16,6 +16,7 @@ using MediaBrowser.Controller.MediaEncoding;
|
|||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
using MediaBrowser.Model.Session;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
@ -223,7 +224,7 @@ namespace Jellyfin.Api.Controllers
|
|||
DeInterlace = false,
|
||||
RequireNonAnamorphic = false,
|
||||
EnableMpegtsM2TsMode = false,
|
||||
TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(',', mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray()),
|
||||
TranscodeReasons = mediaSource.TranscodeReasons == MediaBrowser.Model.Session.TranscodeReason.None ? null : mediaSource.TranscodeReasons.Serialize(),
|
||||
Context = EncodingContext.Static,
|
||||
StreamOptions = new Dictionary<string, string>(),
|
||||
EnableAdaptiveBitrateStreaming = true
|
||||
|
@ -254,7 +255,7 @@ namespace Jellyfin.Api.Controllers
|
|||
CopyTimestamps = true,
|
||||
StartTimeTicks = startTimeTicks,
|
||||
SubtitleMethod = SubtitleDeliveryMethod.Embed,
|
||||
TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(',', mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray()),
|
||||
TranscodeReasons = mediaSource.TranscodeReasons == MediaBrowser.Model.Session.TranscodeReason.None ? null : mediaSource.TranscodeReasons.Serialize(),
|
||||
Context = EncodingContext.Static
|
||||
};
|
||||
|
||||
|
|
|
@ -479,7 +479,7 @@ namespace Jellyfin.Api.Helpers
|
|||
IsAudioDirect = EncodingHelper.IsCopyCodec(state.OutputAudioCodec),
|
||||
IsVideoDirect = EncodingHelper.IsCopyCodec(state.OutputVideoCodec),
|
||||
HardwareAccelerationType = hardwareAccelerationType,
|
||||
TranscodeReasons = state.TranscodeReasons
|
||||
TranscodeReason = state.TranscodeReason
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
using MediaBrowser.Model.Drawing;
|
||||
|
@ -23,7 +24,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||
public int? OutputAudioBitrate;
|
||||
public int? OutputAudioChannels;
|
||||
|
||||
private TranscodeReason[] _transcodeReasons = null;
|
||||
private TranscodeReason? _transcodeReasons = null;
|
||||
|
||||
public EncodingJobInfo(TranscodingJobType jobType)
|
||||
{
|
||||
|
@ -34,25 +35,27 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||
SupportedSubtitleCodecs = Array.Empty<string>();
|
||||
}
|
||||
|
||||
public TranscodeReason[] TranscodeReasons
|
||||
public TranscodeReason[] TranscodeReasons { get => TranscodeReason.ToArray(); }
|
||||
|
||||
[JsonIgnore]
|
||||
public TranscodeReason TranscodeReason
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_transcodeReasons == null)
|
||||
if (!_transcodeReasons.HasValue)
|
||||
{
|
||||
if (BaseRequest.TranscodeReasons == null)
|
||||
{
|
||||
return Array.Empty<TranscodeReason>();
|
||||
_transcodeReasons = TranscodeReason.None;
|
||||
return TranscodeReason.None;
|
||||
}
|
||||
|
||||
_transcodeReasons = BaseRequest.TranscodeReasons
|
||||
.Split(',')
|
||||
.Where(i => !string.IsNullOrEmpty(i))
|
||||
.Select(v => (TranscodeReason)Enum.Parse(typeof(TranscodeReason), v, true))
|
||||
.ToArray();
|
||||
TranscodeReason reason = TranscodeReason.None;
|
||||
Enum.TryParse<TranscodeReason>(BaseRequest.TranscodeReasons, out reason);
|
||||
_transcodeReasons = reason;
|
||||
}
|
||||
|
||||
return _transcodeReasons;
|
||||
return _transcodeReasons.Value;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
}).ThenBy(streams.IndexOf);
|
||||
}
|
||||
|
||||
private static TranscodeReason? GetTranscodeReasonForFailedCondition(ProfileCondition condition)
|
||||
private static TranscodeReason GetTranscodeReasonForFailedCondition(ProfileCondition condition)
|
||||
{
|
||||
switch (condition.Property)
|
||||
{
|
||||
|
@ -161,7 +161,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
|
||||
case ProfileConditionValue.Has64BitOffsets:
|
||||
// TODO
|
||||
return null;
|
||||
return TranscodeReason.None;
|
||||
|
||||
case ProfileConditionValue.Height:
|
||||
return TranscodeReason.VideoResolutionNotSupported;
|
||||
|
@ -171,7 +171,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
|
||||
case ProfileConditionValue.IsAvc:
|
||||
// TODO
|
||||
return null;
|
||||
return TranscodeReason.None;
|
||||
|
||||
case ProfileConditionValue.IsInterlaced:
|
||||
return TranscodeReason.InterlacedVideoNotSupported;
|
||||
|
@ -181,15 +181,15 @@ namespace MediaBrowser.Model.Dlna
|
|||
|
||||
case ProfileConditionValue.NumAudioStreams:
|
||||
// TODO
|
||||
return null;
|
||||
return TranscodeReason.None;
|
||||
|
||||
case ProfileConditionValue.NumVideoStreams:
|
||||
// TODO
|
||||
return null;
|
||||
return TranscodeReason.None;
|
||||
|
||||
case ProfileConditionValue.PacketLength:
|
||||
// TODO
|
||||
return null;
|
||||
return TranscodeReason.None;
|
||||
|
||||
case ProfileConditionValue.RefFrames:
|
||||
return TranscodeReason.RefFramesNotSupported;
|
||||
|
@ -217,13 +217,13 @@ namespace MediaBrowser.Model.Dlna
|
|||
|
||||
case ProfileConditionValue.VideoTimestamp:
|
||||
// TODO
|
||||
return null;
|
||||
return TranscodeReason.None;
|
||||
|
||||
case ProfileConditionValue.Width:
|
||||
return TranscodeReason.VideoResolutionNotSupported;
|
||||
|
||||
default:
|
||||
return null;
|
||||
return TranscodeReason.None;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -290,7 +290,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
var directPlayInfo = GetAudioDirectPlayMethods(item, audioStream, options);
|
||||
|
||||
var directPlayMethods = directPlayInfo.PlayMethods;
|
||||
var transcodeReasons = directPlayInfo.TranscodeReasons.ToList();
|
||||
var transcodeReasons = directPlayInfo.TranscodeReasons;
|
||||
|
||||
int? inputAudioChannels = audioStream?.Channels;
|
||||
int? inputAudioBitrate = audioStream?.BitDepth;
|
||||
|
@ -331,11 +331,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
if (!ConditionProcessor.IsAudioConditionSatisfied(c, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth))
|
||||
{
|
||||
LogConditionFailure(options.Profile, "AudioCodecProfile", c, item);
|
||||
var transcodeReason = GetTranscodeReasonForFailedCondition(c);
|
||||
if (transcodeReason.HasValue)
|
||||
{
|
||||
transcodeReasons.Add(transcodeReason.Value);
|
||||
}
|
||||
transcodeReasons |= GetTranscodeReasonForFailedCondition(c);
|
||||
|
||||
all = false;
|
||||
break;
|
||||
|
@ -434,7 +430,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
playlistItem.AudioBitrate = longBitrate > int.MaxValue ? int.MaxValue : Convert.ToInt32(longBitrate);
|
||||
}
|
||||
|
||||
playlistItem.TranscodeReasons = transcodeReasons.ToArray();
|
||||
playlistItem.TranscodeReasons = transcodeReasons;
|
||||
return playlistItem;
|
||||
}
|
||||
|
||||
|
@ -448,7 +444,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
return options.GetMaxBitrate(isAudio);
|
||||
}
|
||||
|
||||
private (IEnumerable<PlayMethod> PlayMethods, IEnumerable<TranscodeReason> TranscodeReasons) GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options)
|
||||
private (IEnumerable<PlayMethod> PlayMethods, TranscodeReason TranscodeReasons) GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options)
|
||||
{
|
||||
DirectPlayProfile directPlayProfile = options.Profile.DirectPlayProfiles
|
||||
.FirstOrDefault(x => x.Type == DlnaProfileType.Audio && IsAudioDirectPlaySupported(x, item, audioStream));
|
||||
|
@ -465,12 +461,12 @@ namespace MediaBrowser.Model.Dlna
|
|||
}
|
||||
|
||||
var playMethods = new List<PlayMethod>();
|
||||
var transcodeReasons = new List<TranscodeReason>();
|
||||
var transcodeReasons = TranscodeReason.None;
|
||||
|
||||
// While options takes the network and other factors into account. Only applies to direct stream
|
||||
if (item.SupportsDirectStream)
|
||||
{
|
||||
if (IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate(true) ?? 0, PlayMethod.DirectStream))
|
||||
if (IsItemBitrateEligibleForDirectPlay(item, options.GetMaxBitrate(true) ?? 0, PlayMethod.DirectStream))
|
||||
{
|
||||
if (options.EnableDirectStream)
|
||||
{
|
||||
|
@ -479,7 +475,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
}
|
||||
else
|
||||
{
|
||||
transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit);
|
||||
transcodeReasons |= TranscodeReason.ContainerBitrateExceedsLimit;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -487,7 +483,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
// If device requirements are satisfied then allow both direct stream and direct play
|
||||
if (item.SupportsDirectPlay)
|
||||
{
|
||||
if (IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true) ?? 0, PlayMethod.DirectPlay))
|
||||
if (IsItemBitrateEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true) ?? 0, PlayMethod.DirectPlay))
|
||||
{
|
||||
if (options.EnableDirectPlay)
|
||||
{
|
||||
|
@ -496,29 +492,26 @@ namespace MediaBrowser.Model.Dlna
|
|||
}
|
||||
else
|
||||
{
|
||||
transcodeReasons.Add(TranscodeReason.ContainerBitrateExceedsLimit);
|
||||
transcodeReasons |= TranscodeReason.ContainerBitrateExceedsLimit;
|
||||
}
|
||||
}
|
||||
|
||||
if (playMethods.Count > 0)
|
||||
{
|
||||
transcodeReasons.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
transcodeReasons = transcodeReasons.Distinct().ToList();
|
||||
transcodeReasons = TranscodeReason.None;
|
||||
}
|
||||
|
||||
return (playMethods, transcodeReasons);
|
||||
}
|
||||
|
||||
private static List<TranscodeReason> GetTranscodeReasonsFromDirectPlayProfile(MediaSourceInfo item, MediaStream videoStream, MediaStream audioStream, IEnumerable<DirectPlayProfile> directPlayProfiles)
|
||||
private static TranscodeReason GetTranscodeReasonsFromDirectPlayProfile(MediaSourceInfo item, MediaStream videoStream, MediaStream audioStream, IEnumerable<DirectPlayProfile> directPlayProfiles)
|
||||
{
|
||||
var mediaType = videoStream == null ? DlnaProfileType.Audio : DlnaProfileType.Video;
|
||||
|
||||
var containerSupported = false;
|
||||
var audioSupported = false;
|
||||
var videoSupported = false;
|
||||
var reasons = TranscodeReason.None;
|
||||
|
||||
foreach (var profile in directPlayProfiles)
|
||||
{
|
||||
|
@ -541,20 +534,20 @@ namespace MediaBrowser.Model.Dlna
|
|||
var list = new List<TranscodeReason>();
|
||||
if (!containerSupported)
|
||||
{
|
||||
list.Add(TranscodeReason.ContainerNotSupported);
|
||||
reasons |= TranscodeReason.ContainerNotSupported;
|
||||
}
|
||||
|
||||
if (videoStream != null && !videoSupported)
|
||||
{
|
||||
list.Add(TranscodeReason.VideoCodecNotSupported);
|
||||
reasons |= TranscodeReason.VideoCodecNotSupported;
|
||||
}
|
||||
|
||||
if (audioStream != null && !audioSupported)
|
||||
{
|
||||
list.Add(TranscodeReason.AudioCodecNotSupported);
|
||||
reasons |= TranscodeReason.AudioCodecNotSupported;
|
||||
}
|
||||
|
||||
return list;
|
||||
return reasons;
|
||||
}
|
||||
|
||||
private static int? GetDefaultSubtitleStreamIndex(MediaSourceInfo item, SubtitleProfile[] subtitleProfiles)
|
||||
|
@ -679,8 +672,9 @@ namespace MediaBrowser.Model.Dlna
|
|||
// TODO: This doesn't account for situations where the device is able to handle the media's bitrate, but the connection isn't fast enough
|
||||
var directPlayEligibilityResult = IsEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true) ?? 0, subtitleStream, audioStream, options, PlayMethod.DirectPlay);
|
||||
var directStreamEligibilityResult = IsEligibleForDirectPlay(item, options.GetMaxBitrate(false) ?? 0, subtitleStream, audioStream, options, PlayMethod.DirectStream);
|
||||
bool isEligibleForDirectPlay = options.EnableDirectPlay && (options.ForceDirectPlay || directPlayEligibilityResult.DirectPlay);
|
||||
bool isEligibleForDirectStream = options.EnableDirectStream && (options.ForceDirectStream || directStreamEligibilityResult.DirectPlay);
|
||||
bool isEligibleForDirectPlay = options.EnableDirectPlay && (options.ForceDirectPlay || directPlayEligibilityResult == TranscodeReason.None);
|
||||
bool isEligibleForDirectStream = options.EnableDirectStream && (options.ForceDirectStream || directPlayEligibilityResult == TranscodeReason.None);
|
||||
var transcodeReasons = directPlayEligibilityResult | directStreamEligibilityResult;
|
||||
|
||||
_logger.LogDebug(
|
||||
"Profile: {0}, Path: {1}, isEligibleForDirectPlay: {2}, isEligibleForDirectStream: {3}",
|
||||
|
@ -689,8 +683,6 @@ namespace MediaBrowser.Model.Dlna
|
|||
isEligibleForDirectPlay,
|
||||
isEligibleForDirectStream);
|
||||
|
||||
var transcodeReasons = new List<TranscodeReason>();
|
||||
|
||||
if (isEligibleForDirectPlay || isEligibleForDirectStream)
|
||||
{
|
||||
// See if it can be direct played
|
||||
|
@ -713,17 +705,13 @@ namespace MediaBrowser.Model.Dlna
|
|||
return playlistItem;
|
||||
}
|
||||
|
||||
transcodeReasons.AddRange(directPlayInfo.TranscodeReasons);
|
||||
transcodeReasons |= directPlayInfo.TranscodeReasons;
|
||||
}
|
||||
|
||||
if (directPlayEligibilityResult.Reason.HasValue)
|
||||
if (playlistItem.PlayMethod != PlayMethod.Transcode)
|
||||
{
|
||||
transcodeReasons.Add(directPlayEligibilityResult.Reason.Value);
|
||||
}
|
||||
|
||||
if (directStreamEligibilityResult.Reason.HasValue)
|
||||
{
|
||||
transcodeReasons.Add(directStreamEligibilityResult.Reason.Value);
|
||||
playlistItem.TranscodeReasons = transcodeReasons;
|
||||
return playlistItem;
|
||||
}
|
||||
|
||||
// Can't direct play, find the transcoding profile
|
||||
|
@ -869,7 +857,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
}
|
||||
}
|
||||
|
||||
playlistItem.TranscodeReasons = transcodeReasons.ToArray();
|
||||
playlistItem.TranscodeReasons = transcodeReasons;
|
||||
|
||||
return playlistItem;
|
||||
}
|
||||
|
@ -1000,7 +988,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
return 7168000;
|
||||
}
|
||||
|
||||
private (PlayMethod? PlayMethod, List<TranscodeReason> TranscodeReasons) GetVideoDirectPlayProfile(
|
||||
private (PlayMethod? PlayMethod, TranscodeReason TranscodeReasons) GetVideoDirectPlayProfile(
|
||||
VideoOptions options,
|
||||
MediaSourceInfo mediaSource,
|
||||
MediaStream videoStream,
|
||||
|
@ -1009,12 +997,12 @@ namespace MediaBrowser.Model.Dlna
|
|||
{
|
||||
if (options.ForceDirectPlay)
|
||||
{
|
||||
return (PlayMethod.DirectPlay, new List<TranscodeReason>());
|
||||
return (PlayMethod.DirectPlay, TranscodeReason.None);
|
||||
}
|
||||
|
||||
if (options.ForceDirectStream)
|
||||
{
|
||||
return (PlayMethod.DirectStream, new List<TranscodeReason>());
|
||||
return (PlayMethod.DirectStream, TranscodeReason.None);
|
||||
}
|
||||
|
||||
DeviceProfile profile = options.Profile;
|
||||
|
@ -1089,11 +1077,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
{
|
||||
LogConditionFailure(profile, "VideoContainerProfile", i, mediaSource);
|
||||
|
||||
var transcodeReason = GetTranscodeReasonForFailedCondition(i);
|
||||
var transcodeReasons = transcodeReason.HasValue
|
||||
? new List<TranscodeReason> { transcodeReason.Value }
|
||||
: new List<TranscodeReason>();
|
||||
|
||||
var transcodeReasons = GetTranscodeReasonForFailedCondition(i);
|
||||
return (null, transcodeReasons);
|
||||
}
|
||||
}
|
||||
|
@ -1133,11 +1117,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource);
|
||||
|
||||
var transcodeReason = GetTranscodeReasonForFailedCondition(i);
|
||||
var transcodeReasons = transcodeReason.HasValue
|
||||
? new List<TranscodeReason> { transcodeReason.Value }
|
||||
: new List<TranscodeReason>();
|
||||
|
||||
return (null, transcodeReasons);
|
||||
return (null, transcodeReason);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1178,11 +1158,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
{
|
||||
LogConditionFailure(profile, "VideoAudioCodecProfile", i, mediaSource);
|
||||
|
||||
var transcodeReason = GetTranscodeReasonForFailedCondition(i);
|
||||
var transcodeReasons = transcodeReason.HasValue
|
||||
? new List<TranscodeReason> { transcodeReason.Value }
|
||||
: new List<TranscodeReason>();
|
||||
|
||||
var transcodeReasons = GetTranscodeReasonForFailedCondition(i);
|
||||
return (null, transcodeReasons);
|
||||
}
|
||||
}
|
||||
|
@ -1190,10 +1166,10 @@ namespace MediaBrowser.Model.Dlna
|
|||
|
||||
if (isEligibleForDirectStream && mediaSource.SupportsDirectStream)
|
||||
{
|
||||
return (PlayMethod.DirectStream, new List<TranscodeReason>());
|
||||
return (PlayMethod.DirectStream, TranscodeReason.None);
|
||||
}
|
||||
|
||||
return (null, new List<TranscodeReason> { TranscodeReason.ContainerBitrateExceedsLimit });
|
||||
return (null, TranscodeReason.ContainerBitrateExceedsLimit);
|
||||
}
|
||||
|
||||
private void LogConditionFailure(DeviceProfile profile, string type, ProfileCondition condition, MediaSourceInfo mediaSource)
|
||||
|
@ -1209,7 +1185,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
mediaSource.Path ?? "Unknown path");
|
||||
}
|
||||
|
||||
private (bool DirectPlay, TranscodeReason? Reason) IsEligibleForDirectPlay(
|
||||
private TranscodeReason IsEligibleForDirectPlay(
|
||||
MediaSourceInfo item,
|
||||
long maxBitrate,
|
||||
MediaStream subtitleStream,
|
||||
|
@ -1217,6 +1193,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
VideoOptions options,
|
||||
PlayMethod playMethod)
|
||||
{
|
||||
var reason = TranscodeReason.None;
|
||||
if (subtitleStream != null)
|
||||
{
|
||||
var subtitleProfile = GetSubtitleProfile(item, subtitleStream, options.Profile.SubtitleProfiles, playMethod, _transcoderSupport, item.Container, null);
|
||||
|
@ -1226,22 +1203,23 @@ namespace MediaBrowser.Model.Dlna
|
|||
&& subtitleProfile.Method != SubtitleDeliveryMethod.Embed)
|
||||
{
|
||||
_logger.LogDebug("Not eligible for {0} due to unsupported subtitles", playMethod);
|
||||
return (false, TranscodeReason.SubtitleCodecNotSupported);
|
||||
reason |= TranscodeReason.SubtitleCodecNotSupported;
|
||||
}
|
||||
}
|
||||
|
||||
bool result = IsAudioEligibleForDirectPlay(item, maxBitrate, playMethod);
|
||||
bool result = IsItemBitrateEligibleForDirectPlay(item, maxBitrate, playMethod);
|
||||
if (!result)
|
||||
{
|
||||
return (false, TranscodeReason.ContainerBitrateExceedsLimit);
|
||||
reason |= TranscodeReason.ContainerBitrateExceedsLimit;
|
||||
}
|
||||
|
||||
// TODO:6450 support external audio in DirectStream?
|
||||
if (audioStream?.IsExternal == true)
|
||||
{
|
||||
return (false, TranscodeReason.AudioIsExternal);
|
||||
reason |= TranscodeReason.AudioIsExternal;
|
||||
}
|
||||
|
||||
return (true, null);
|
||||
return reason;
|
||||
}
|
||||
|
||||
public static SubtitleProfile GetSubtitleProfile(
|
||||
|
@ -1401,7 +1379,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
return null;
|
||||
}
|
||||
|
||||
private bool IsAudioEligibleForDirectPlay(MediaSourceInfo item, long maxBitrate, PlayMethod playMethod)
|
||||
private bool IsItemBitrateEligibleForDirectPlay(MediaSourceInfo item, long maxBitrate, PlayMethod playMethod)
|
||||
{
|
||||
// Don't restrict by bitrate if coming from an external domain
|
||||
if (item.IsRemote)
|
||||
|
|
|
@ -23,7 +23,6 @@ namespace MediaBrowser.Model.Dlna
|
|||
AudioCodecs = Array.Empty<string>();
|
||||
VideoCodecs = Array.Empty<string>();
|
||||
SubtitleCodecs = Array.Empty<string>();
|
||||
TranscodeReasons = Array.Empty<TranscodeReason>();
|
||||
StreamOptions = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
|
@ -103,7 +102,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
|
||||
public string PlaySessionId { get; set; }
|
||||
|
||||
public TranscodeReason[] TranscodeReasons { get; set; }
|
||||
public TranscodeReason TranscodeReasons { get; set; }
|
||||
|
||||
public Dictionary<string, string> StreamOptions { get; private set; }
|
||||
|
||||
|
@ -799,7 +798,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
|
||||
if (!item.IsDirectStream)
|
||||
{
|
||||
list.Add(new NameValuePair("TranscodeReasons", string.Join(',', item.TranscodeReasons.Distinct())));
|
||||
list.Add(new NameValuePair("TranscodeReasons", item.TranscodeReasons.Serialize()));
|
||||
}
|
||||
|
||||
return list;
|
||||
|
|
|
@ -109,7 +109,7 @@ namespace MediaBrowser.Model.Dto
|
|||
public int? AnalyzeDurationMs { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public TranscodeReason[] TranscodeReasons { get; set; }
|
||||
public TranscodeReason TranscodeReasons { get; set; }
|
||||
|
||||
public int? DefaultAudioStreamIndex { get; set; }
|
||||
|
||||
|
|
|
@ -1,32 +1,51 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
|
||||
namespace MediaBrowser.Model.Session
|
||||
{
|
||||
[Flags]
|
||||
public enum TranscodeReason
|
||||
{
|
||||
ContainerNotSupported = 0,
|
||||
VideoCodecNotSupported = 1,
|
||||
AudioCodecNotSupported = 2,
|
||||
ContainerBitrateExceedsLimit = 3,
|
||||
AudioBitrateNotSupported = 4,
|
||||
AudioChannelsNotSupported = 5,
|
||||
VideoResolutionNotSupported = 6,
|
||||
UnknownVideoStreamInfo = 7,
|
||||
UnknownAudioStreamInfo = 8,
|
||||
AudioProfileNotSupported = 9,
|
||||
AudioSampleRateNotSupported = 10,
|
||||
AnamorphicVideoNotSupported = 11,
|
||||
InterlacedVideoNotSupported = 12,
|
||||
SecondaryAudioNotSupported = 13,
|
||||
RefFramesNotSupported = 14,
|
||||
VideoBitDepthNotSupported = 15,
|
||||
VideoBitrateNotSupported = 16,
|
||||
VideoFramerateNotSupported = 17,
|
||||
VideoLevelNotSupported = 18,
|
||||
VideoProfileNotSupported = 19,
|
||||
AudioBitDepthNotSupported = 20,
|
||||
SubtitleCodecNotSupported = 21,
|
||||
DirectPlayError = 22,
|
||||
AudioIsExternal = 23
|
||||
None = 0,
|
||||
|
||||
// Primary
|
||||
ContainerNotSupported = 1 << 0,
|
||||
VideoCodecNotSupported = 1 << 1,
|
||||
AudioCodecNotSupported = 1 << 2,
|
||||
SubtitleCodecNotSupported = 1 << 3,
|
||||
AudioIsExternal = 1 << 4,
|
||||
SecondaryAudioNotSupported = 1 << 5,
|
||||
|
||||
// Video Constraints
|
||||
VideoProfileNotSupported = 1 << 6,
|
||||
VideoLevelNotSupported = 1 << 7,
|
||||
VideoResolutionNotSupported = 1 << 8,
|
||||
VideoBitDepthNotSupported = 1 << 9,
|
||||
VideoFramerateNotSupported = 1 << 10,
|
||||
RefFramesNotSupported = 1 << 11,
|
||||
AnamorphicVideoNotSupported = 1 << 12,
|
||||
InterlacedVideoNotSupported = 1 << 13,
|
||||
|
||||
// Audio Constraints
|
||||
AudioChannelsNotSupported = 1 << 14,
|
||||
AudioProfileNotSupported = 1 << 15,
|
||||
AudioSampleRateNotSupported = 1 << 16,
|
||||
AudioBitDepthNotSupported = 1 << 20,
|
||||
|
||||
// Bitrate Constraints
|
||||
ContainerBitrateExceedsLimit = 1 << 17,
|
||||
VideoBitrateNotSupported = 1 << 18,
|
||||
AudioBitrateNotSupported = 1 << 19,
|
||||
|
||||
// Errors
|
||||
UnknownVideoStreamInfo = 1 << 20,
|
||||
UnknownAudioStreamInfo = 1 << 21,
|
||||
DirectPlayError = 1 << 22,
|
||||
|
||||
// Aliases
|
||||
ContainerReasons = ContainerNotSupported | ContainerBitrateExceedsLimit,
|
||||
AudioReasons = AudioCodecNotSupported | AudioBitrateNotSupported | AudioChannelsNotSupported | AudioProfileNotSupported | AudioSampleRateNotSupported | SecondaryAudioNotSupported | AudioBitDepthNotSupported | AudioIsExternal,
|
||||
VideoReasons = VideoCodecNotSupported | VideoResolutionNotSupported | AnamorphicVideoNotSupported | InterlacedVideoNotSupported | VideoBitDepthNotSupported | VideoBitrateNotSupported | VideoFramerateNotSupported | VideoLevelNotSupported | RefFramesNotSupported,
|
||||
}
|
||||
}
|
||||
|
|
22
MediaBrowser.Model/Session/TranscodeReasonExtensions.cs
Normal file
22
MediaBrowser.Model/Session/TranscodeReasonExtensions.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.Model.Session
|
||||
{
|
||||
public static class TranscodeReasonExtensions
|
||||
{
|
||||
private static TranscodeReason[] values = Enum.GetValues<TranscodeReason>();
|
||||
|
||||
public static string Serialize(this MediaBrowser.Model.Session.TranscodeReason reasons, string sep = ",")
|
||||
{
|
||||
return string.Join(sep, reasons.ToArray());
|
||||
}
|
||||
|
||||
public static TranscodeReason[] ToArray(this MediaBrowser.Model.Session.TranscodeReason reasons)
|
||||
{
|
||||
return values.Where(r => r != 0 && reasons.HasFlag(r)).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +1,12 @@
|
|||
#nullable disable
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MediaBrowser.Model.Session
|
||||
{
|
||||
public class TranscodingInfo
|
||||
{
|
||||
public TranscodingInfo()
|
||||
{
|
||||
TranscodeReasons = Array.Empty<TranscodeReason>();
|
||||
}
|
||||
|
||||
public string AudioCodec { get; set; }
|
||||
|
||||
public string VideoCodec { get; set; }
|
||||
|
@ -36,6 +31,9 @@ namespace MediaBrowser.Model.Session
|
|||
|
||||
public HardwareEncodingType? HardwareAccelerationType { get; set; }
|
||||
|
||||
public TranscodeReason[] TranscodeReasons { get; set; }
|
||||
public TranscodeReason[] TranscodeReasons { get => TranscodeReason.ToArray(); }
|
||||
|
||||
[JsonIgnore]
|
||||
public TranscodeReason TranscodeReason { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
|
@ -19,21 +20,120 @@ namespace Jellyfin.MediaBrowser.Model.Tests
|
|||
[Theory]
|
||||
// Chrome
|
||||
[InlineData("Chrome", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("Chrome", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.Transcode)] // #6450 should be DirectPlay
|
||||
[InlineData("Chrome", "mp4-h264-ac3-srt-2600k", PlayMethod.Transcode)] // #6450 should be DirectStream
|
||||
[InlineData("Chrome", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, true)]
|
||||
[InlineData("Chrome", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, true)]
|
||||
[InlineData("Chrome", "mkv-vp9-aac-srt-2600k", PlayMethod.Transcode, true)] // #6450 should be 'false'
|
||||
[InlineData("Chrome", "mkv-vp9-ac3-srt-2600k", PlayMethod.Transcode, true)] // #6450 should be 'false'
|
||||
[InlineData("Chrome", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("Chrome", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.Transcode, TranscodeReason.SecondaryAudioNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("Chrome", "mp4-h264-ac3-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported)] // #6450 should be DirectStream
|
||||
[InlineData("Chrome", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")]
|
||||
[InlineData("Chrome", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.AudioCodecNotSupported, "Transcode")]
|
||||
[InlineData("Chrome", "mkv-vp9-aac-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported, "Transcode")] // #6450 should be 'false'
|
||||
[InlineData("Chrome", "mkv-vp9-ac3-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported, "Transcode")] // #6450 should be 'false'
|
||||
[InlineData("Chrome", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
// Firefox
|
||||
[InlineData("Firefox", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("Firefox", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.Transcode)] // #6450 should be DirectPlay
|
||||
[InlineData("Firefox", "mp4-h264-ac3-srt-2600k", PlayMethod.Transcode)] // #6450 should be DirectStream
|
||||
[InlineData("Firefox", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, true)]
|
||||
[InlineData("Firefox", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, true)]
|
||||
[InlineData("Firefox", "mkv-vp9-aac-srt-2600k", PlayMethod.Transcode, true)] // #6450 should be 'false'
|
||||
[InlineData("Firefox", "mkv-vp9-ac3-srt-2600k", PlayMethod.Transcode, true)] // #6450 should be 'false'
|
||||
[InlineData("Firefox", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("Firefox", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.Transcode, TranscodeReason.SecondaryAudioNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("Firefox", "mp4-h264-ac3-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported)] // #6450 should be DirectStream
|
||||
[InlineData("Firefox", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")]
|
||||
[InlineData("Firefox", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.AudioCodecNotSupported, "Transcode")]
|
||||
[InlineData("Firefox", "mkv-vp9-aac-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported, "Transcode")] // #6450 should be 'false'
|
||||
[InlineData("Firefox", "mkv-vp9-ac3-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported, "Transcode")] // #6450 should be 'false'
|
||||
[InlineData("Firefox", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
// Safari
|
||||
[InlineData("SafariNext", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("SafariNext", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("SafariNext", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("SafariNext", "mp4-hevc-aac-srt-15200k", PlayMethod.DirectStream)] // #6450 should probably be DirectPlay
|
||||
[InlineData("SafariNext", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectStream)] // #6450 should probably be DirectPlay
|
||||
// AndroidPixel
|
||||
[InlineData("AndroidPixel", "mp4-h264-aac-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("AndroidPixel", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("AndroidPixel", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("AndroidPixel", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit, "Transcode")]
|
||||
[InlineData("AndroidPixel", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit, "Transcode")]
|
||||
// Yatse
|
||||
[InlineData("Yatse", "mp4-h264-aac-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("Yatse", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("Yatse", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.Transcode, TranscodeReason.SecondaryAudioNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("Yatse", "mp4-h264-ac3-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported, "Transcode")]
|
||||
[InlineData("Yatse", "mp4-hevc-aac-srt-15200k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("Yatse", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported, "Transcode")] // #6450 should be DirectPlay
|
||||
// RokuSSPlus
|
||||
[InlineData("RokuSSPlus", "mp4-h264-aac-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("RokuSSPlus", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("RokuSSPlus", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("RokuSSPlus", "mp4-h264-ac3-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported)] // #6450 should be DirectStream
|
||||
[InlineData("RokuSSPlus", "mp4-hevc-aac-srt-15200k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("RokuSSPlus", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported, "Transcode")] // #6450 should be DirectPlay
|
||||
[InlineData("RokuSSPlus", "mp4-hevc-ac3-srt-15200k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported, "Transcode")] // #6450 should be DirectStream
|
||||
// JellyfinMediaPlayer
|
||||
[InlineData("JellyfinMediaPlayer", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("JellyfinMediaPlayer", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("JellyfinMediaPlayer", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("JellyfinMediaPlayer", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit)] // #6450 should be DirectPlay
|
||||
[InlineData("JellyfinMediaPlayer", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit)] // #6450 should be DirectPlay
|
||||
[InlineData("JellyfinMediaPlayer", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("JellyfinMediaPlayer", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("JellyfinMediaPlayer", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
// TranscodeMedia
|
||||
[InlineData("TranscodeMedia", "mp4-h264-aac-vtt-2600k", PlayMethod.Transcode, TranscodeReason.ContainerNotSupported | TranscodeReason.VideoCodecNotSupported | TranscodeReason.AudioCodecNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("TranscodeMedia", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.Transcode, TranscodeReason.ContainerNotSupported | TranscodeReason.VideoCodecNotSupported | TranscodeReason.AudioCodecNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("TranscodeMedia", "mp4-h264-ac3-srt-2600k", PlayMethod.Transcode, TranscodeReason.ContainerNotSupported | TranscodeReason.VideoCodecNotSupported | TranscodeReason.AudioCodecNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("TranscodeMedia", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.ContainerNotSupported | TranscodeReason.VideoCodecNotSupported | TranscodeReason.AudioCodecNotSupported, "Transcode")] // #6450 should be DirectPlay
|
||||
[InlineData("TranscodeMedia", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.ContainerNotSupported | TranscodeReason.VideoCodecNotSupported | TranscodeReason.AudioCodecNotSupported, "Transcode")] // #6450 should be DirectPlay
|
||||
[InlineData("TranscodeMedia", "mkv-vp9-aac-srt-2600k", PlayMethod.Transcode, TranscodeReason.ContainerNotSupported | TranscodeReason.VideoCodecNotSupported | TranscodeReason.AudioCodecNotSupported, "Transcode")] // #6450 should be DirectPlay
|
||||
[InlineData("TranscodeMedia", "mkv-vp9-ac3-srt-2600k", PlayMethod.Transcode, TranscodeReason.ContainerNotSupported | TranscodeReason.VideoCodecNotSupported | TranscodeReason.AudioCodecNotSupported, "Transcode")] // #6450 should be DirectPlay
|
||||
[InlineData("TranscodeMedia", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.Transcode, TranscodeReason.ContainerNotSupported | TranscodeReason.VideoCodecNotSupported | TranscodeReason.AudioCodecNotSupported, "Transcode")] // #6450 should be DirectPlay
|
||||
// DirectMedia
|
||||
[InlineData("DirectMedia", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("DirectMedia", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("DirectMedia", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("DirectMedia", "mp4-hevc-aac-srt-15200k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("DirectMedia", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("DirectMedia", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("DirectMedia", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("DirectMedia", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
// LowBandwidth
|
||||
[InlineData("LowBandwidth", "mp4-h264-aac-vtt-2600k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit)] // #6450 should be DirectPlay
|
||||
[InlineData("LowBandwidth", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit)] // #6450 should be DirectPlay
|
||||
[InlineData("LowBandwidth", "mp4-h264-ac3-srt-2600k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit)] // #6450 should be DirectPlay
|
||||
[InlineData("LowBandwidth", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit, "Transcode")] // #6450 should be DirectPlay
|
||||
[InlineData("LowBandwidth", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit, "Transcode")] // #6450 should be DirectPlay
|
||||
[InlineData("LowBandwidth", "mkv-vp9-aac-srt-2600k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit, "Transcode")] // #6450 should be DirectPlay
|
||||
[InlineData("LowBandwidth", "mkv-vp9-ac3-srt-2600k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit, "Transcode")] // #6450 should be DirectPlay
|
||||
[InlineData("LowBandwidth", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit, "Transcode")] // #6450 should be DirectPlay
|
||||
// Null
|
||||
[InlineData("Null", "mp4-h264-aac-vtt-2600k", null, TranscodeReason.ContainerBitrateExceedsLimit | TranscodeReason.SubtitleCodecNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("Null", "mp4-h264-ac3-aac-srt-2600k", null, TranscodeReason.ContainerBitrateExceedsLimit | TranscodeReason.SubtitleCodecNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("Null", "mp4-h264-ac3-srt-2600k", null, TranscodeReason.ContainerBitrateExceedsLimit | TranscodeReason.SubtitleCodecNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("Null", "mp4-hevc-aac-srt-15200k", null, TranscodeReason.ContainerBitrateExceedsLimit | TranscodeReason.SubtitleCodecNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("Null", "mp4-hevc-ac3-aac-srt-15200k", null, TranscodeReason.ContainerBitrateExceedsLimit | TranscodeReason.SubtitleCodecNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("Null", "mkv-vp9-aac-srt-2600k", null, TranscodeReason.ContainerBitrateExceedsLimit | TranscodeReason.SubtitleCodecNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("Null", "mkv-vp9-ac3-srt-2600k", null, TranscodeReason.ContainerBitrateExceedsLimit | TranscodeReason.SubtitleCodecNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("Null", "mkv-vp9-vorbis-vtt-2600k", null, TranscodeReason.ContainerBitrateExceedsLimit | TranscodeReason.SubtitleCodecNotSupported)] // #6450 should be DirectPlay
|
||||
public async Task BuildVideoItemSimple(string deviceName, string mediaSource, PlayMethod? playMethod, TranscodeReason why = TranscodeReason.None, string transcodeMode = "DirectStream", string transcodeProtocol = "")
|
||||
{
|
||||
var options = await GetVideoOptions(deviceName, mediaSource);
|
||||
BuildVideoItemSimpleTest(options, playMethod, why, transcodeMode, transcodeProtocol);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
// Chrome
|
||||
[InlineData("Chrome", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("Chrome", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("Chrome", "mp4-h264-ac3-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported)] // #6450 should be DirectStream
|
||||
[InlineData("Chrome", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")]
|
||||
[InlineData("Chrome", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.AudioCodecNotSupported, "Transcode")]
|
||||
[InlineData("Chrome", "mkv-vp9-aac-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported, "Transcode")] // #6450 should be 'false'
|
||||
[InlineData("Chrome", "mkv-vp9-ac3-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported, "Transcode")] // #6450 should be 'false'
|
||||
[InlineData("Chrome", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
// Firefox
|
||||
[InlineData("Firefox", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("Firefox", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("Firefox", "mp4-h264-ac3-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported)] // #6450 should be DirectStream
|
||||
[InlineData("Firefox", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")]
|
||||
[InlineData("Firefox", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.AudioCodecNotSupported, "Transcode")]
|
||||
[InlineData("Firefox", "mkv-vp9-aac-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported, "Transcode")] // #6450 should be 'false'
|
||||
[InlineData("Firefox", "mkv-vp9-ac3-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported, "Transcode")] // #6450 should be 'false'
|
||||
[InlineData("Firefox", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
// Safari
|
||||
[InlineData("SafariNext", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
|
@ -45,70 +145,68 @@ namespace Jellyfin.MediaBrowser.Model.Tests
|
|||
[InlineData("AndroidPixel", "mp4-h264-aac-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("AndroidPixel", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("AndroidPixel", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("AndroidPixel", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, true)]
|
||||
[InlineData("AndroidPixel", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, true)]
|
||||
[InlineData("AndroidPixel", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit, "Transcode")]
|
||||
[InlineData("AndroidPixel", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit, "Transcode")]
|
||||
// Yatse
|
||||
[InlineData("Yatse", "mp4-h264-aac-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("Yatse", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.Transcode)] // #6450 should be DirectPlay
|
||||
[InlineData("Yatse", "mp4-h264-ac3-srt-2600k", PlayMethod.Transcode, true)]
|
||||
[InlineData("Yatse", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("Yatse", "mp4-h264-ac3-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported, "Transcode")]
|
||||
[InlineData("Yatse", "mp4-hevc-aac-srt-15200k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("Yatse", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, true)] // #6450 should be DirectPlay
|
||||
[InlineData("Yatse", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported, "Transcode")] // #6450 should be DirectPlay
|
||||
// RokuSSPlus
|
||||
[InlineData("RokuSSPlus", "mp4-h264-aac-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("RokuSSPlus", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.Transcode)] // #6450 should be DirectPlay
|
||||
[InlineData("RokuSSPlus", "mp4-h264-ac3-srt-2600k", PlayMethod.Transcode)] // #6450 should be DirectStream
|
||||
[InlineData("RokuSSPlus", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("RokuSSPlus", "mp4-h264-ac3-srt-2600k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported)] // #6450 should be DirectStream
|
||||
[InlineData("RokuSSPlus", "mp4-hevc-aac-srt-15200k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("RokuSSPlus", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, true)] // #6450 should be DirectPlay
|
||||
[InlineData("RokuSSPlus", "mp4-hevc-ac3-srt-15200k", PlayMethod.Transcode, true)] // #6450 should be DirectStream
|
||||
[InlineData("RokuSSPlus", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported, "Transcode")] // #6450 should be DirectPlay
|
||||
[InlineData("RokuSSPlus", "mp4-hevc-ac3-srt-15200k", PlayMethod.Transcode, TranscodeReason.AudioCodecNotSupported, "Transcode")] // #6450 should be DirectStream
|
||||
// JellyfinMediaPlayer
|
||||
[InlineData("JellyfinMediaPlayer", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("JellyfinMediaPlayer", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("JellyfinMediaPlayer", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("JellyfinMediaPlayer", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode)] // #6450 should be DirectPlay
|
||||
[InlineData("JellyfinMediaPlayer", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode)] // #6450 should be DirectPlay
|
||||
[InlineData("JellyfinMediaPlayer", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit)] // #6450 should be DirectPlay
|
||||
[InlineData("JellyfinMediaPlayer", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit)] // #6450 should be DirectPlay
|
||||
[InlineData("JellyfinMediaPlayer", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("JellyfinMediaPlayer", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("JellyfinMediaPlayer", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
// TranscodeMedia
|
||||
[InlineData("TranscodeMedia", "mp4-h264-aac-vtt-2600k", PlayMethod.Transcode)] // #6450 should be DirectPlay
|
||||
[InlineData("TranscodeMedia", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.Transcode)] // #6450 should be DirectPlay
|
||||
[InlineData("TranscodeMedia", "mp4-h264-ac3-srt-2600k", PlayMethod.Transcode)] // #6450 should be DirectPlay
|
||||
[InlineData("TranscodeMedia", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, true)] // #6450 should be DirectPlay
|
||||
[InlineData("TranscodeMedia", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, true)] // #6450 should be DirectPlay
|
||||
[InlineData("TranscodeMedia", "mkv-vp9-aac-srt-2600k", PlayMethod.Transcode, true)] // #6450 should be DirectPlay
|
||||
[InlineData("TranscodeMedia", "mkv-vp9-ac3-srt-2600k", PlayMethod.Transcode, true)] // #6450 should be DirectPlay
|
||||
[InlineData("TranscodeMedia", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.Transcode, true)] // #6450 should be DirectPlay
|
||||
// DirectMedia
|
||||
[InlineData("DirectMedia", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("DirectMedia", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("DirectMedia", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("DirectMedia", "mp4-hevc-aac-srt-15200k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("DirectMedia", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("DirectMedia", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("DirectMedia", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("DirectMedia", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
// LowBandwidth
|
||||
[InlineData("LowBandwidth", "mp4-h264-aac-vtt-2600k", PlayMethod.Transcode)] // #6450 should be DirectPlay
|
||||
[InlineData("LowBandwidth", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.Transcode)] // #6450 should be DirectPlay
|
||||
[InlineData("LowBandwidth", "mp4-h264-ac3-srt-2600k", PlayMethod.Transcode)] // #6450 should be DirectPlay
|
||||
[InlineData("LowBandwidth", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, true)] // #6450 should be DirectPlay
|
||||
[InlineData("LowBandwidth", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, true)] // #6450 should be DirectPlay
|
||||
[InlineData("LowBandwidth", "mkv-vp9-aac-srt-2600k", PlayMethod.Transcode, true)] // #6450 should be DirectPlay
|
||||
[InlineData("LowBandwidth", "mkv-vp9-ac3-srt-2600k", PlayMethod.Transcode, true)] // #6450 should be DirectPlay
|
||||
[InlineData("LowBandwidth", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.Transcode, true)] // #6450 should be DirectPlay
|
||||
// Null
|
||||
[InlineData("Null", "mp4-h264-aac-vtt-2600k", null)] // #6450 should be DirectPlay
|
||||
[InlineData("Null", "mp4-h264-ac3-aac-srt-2600k", null)] // #6450 should be DirectPlay
|
||||
[InlineData("Null", "mp4-h264-ac3-srt-2600k", null)] // #6450 should be DirectPlay
|
||||
[InlineData("Null", "mp4-hevc-aac-srt-15200k", null)] // #6450 should be DirectPlay
|
||||
[InlineData("Null", "mp4-hevc-ac3-aac-srt-15200k", null)] // #6450 should be DirectPlay
|
||||
[InlineData("Null", "mkv-vp9-aac-srt-2600k", null)] // #6450 should be DirectPlay
|
||||
[InlineData("Null", "mkv-vp9-ac3-srt-2600k", null)] // #6450 should be DirectPlay
|
||||
[InlineData("Null", "mkv-vp9-vorbis-vtt-2600k", null)] // #6450 should be DirectPlay
|
||||
public async Task BuildVideoItemSimple(string deviceName, string mediaSource, PlayMethod? playMethod, bool fullTranscode = false)
|
||||
public async Task BuildVideoItemWithFirstExplicitStream(string deviceName, string mediaSource, PlayMethod?playMethod, TranscodeReason why = TranscodeReason.None, string transcodeMode = "DirectStream", string transcodeProtocol = "")
|
||||
{
|
||||
var builder = GetStreamBuilder();
|
||||
var options = await GetVideoOptions(deviceName, mediaSource);
|
||||
options.AudioStreamIndex = 1;
|
||||
options.SubtitleStreamIndex = options.MediaSources[0].MediaStreams.Count() - 1;
|
||||
BuildVideoItemSimpleTest(options, playMethod, why, transcodeMode, transcodeProtocol);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
// Chrome
|
||||
[InlineData("Chrome", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.Transcode, TranscodeReason.SecondaryAudioNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("Chrome", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")] // #6450 should have container & profile video reasons?
|
||||
// Firefox
|
||||
[InlineData("Firefox", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.Transcode, TranscodeReason.SecondaryAudioNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("Firefox", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")] // #6450 should have container & profile video reasons?
|
||||
// Yatse
|
||||
[InlineData("Yatse", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.Transcode, TranscodeReason.SecondaryAudioNotSupported)] // #6450 should be DirectPlay
|
||||
[InlineData("Yatse", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.SecondaryAudioNotSupported, "Transcode")] // #6450 should be DirectPlay
|
||||
// RokuSSPlus
|
||||
[InlineData("RokuSSPlus", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
[InlineData("RokuSSPlus", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectStream)] // #6450 should be DirectPlay
|
||||
public async Task BuildVideoItemWithDirectPlayExplicitStreams(string deviceName, string mediaSource, PlayMethod playMethod, TranscodeReason why = TranscodeReason.None, string transcodeMode = "DirectStream", string transcodeProtocol = "")
|
||||
{
|
||||
var options = await GetVideoOptions(deviceName, mediaSource);
|
||||
var streamCount = options.MediaSources[0].MediaStreams.Count();
|
||||
options.AudioStreamIndex = streamCount - 2;
|
||||
options.SubtitleStreamIndex = streamCount - 1;
|
||||
BuildVideoItemSimpleTest(options, playMethod, why, transcodeMode, transcodeProtocol);
|
||||
}
|
||||
|
||||
private void BuildVideoItemSimpleTest(VideoOptions options, PlayMethod? playMethod, TranscodeReason why, string transcodeMode, string transcodeProtocol)
|
||||
{
|
||||
if (string.IsNullOrEmpty(transcodeProtocol))
|
||||
{
|
||||
transcodeProtocol = playMethod == PlayMethod.DirectStream ? "http" : "hls";
|
||||
}
|
||||
|
||||
var builder = GetStreamBuilder();
|
||||
|
||||
var val = builder.BuildVideoItem(options);
|
||||
Assert.NotNull(val);
|
||||
|
@ -118,63 +216,130 @@ namespace Jellyfin.MediaBrowser.Model.Tests
|
|||
Assert.Equal(playMethod, val.PlayMethod);
|
||||
}
|
||||
|
||||
var videoStreams = options.MediaSources.SelectMany(source => source.MediaStreams).Where(stream => stream.Type == MediaStreamType.Video);
|
||||
var audioStreams = options.MediaSources.SelectMany(source => source.MediaStreams).Where(stream => stream.Type == MediaStreamType.Audio);
|
||||
Assert.Equal(why, val.TranscodeReasons);
|
||||
|
||||
var url = new UriBuilder(val.ToUrl("https://server/", "ACCESSTOKEN"));
|
||||
var query = System.Web.HttpUtility.ParseQueryString(url.Query);
|
||||
var audioStreamIndexInput = options.AudioStreamIndex;
|
||||
var targetVideoStream = val.TargetVideoStream;
|
||||
var targetAudioStream = val.TargetAudioStream;
|
||||
|
||||
var mediaSource = options.MediaSources.First(source => source.Id == val.MediaSourceId);
|
||||
Assert.NotNull(mediaSource);
|
||||
var videoStreams = mediaSource.MediaStreams.Where(stream => stream.Type == MediaStreamType.Video);
|
||||
var audioStreams = mediaSource.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio);
|
||||
// TODO: check AudioStreamIndex vs options.AudioStreamIndex
|
||||
var inputAudioStream = mediaSource.GetDefaultAudioStream(audioStreamIndexInput ?? mediaSource.DefaultAudioStreamIndex);
|
||||
|
||||
var uri = ParseUri(val);
|
||||
|
||||
if (playMethod == PlayMethod.DirectPlay)
|
||||
{
|
||||
// Assert.Contains(query.Get("VidoeCodec"), videoStreams.Select(stream => stream.Codec));
|
||||
// Assert.Contains(query.Get("AudioCodec"), audioStreams.Select(stream => stream.Codec));
|
||||
Assert.Contains(
|
||||
videoStreams,
|
||||
stream => val.TargetVideoCodec.Contains(stream.Codec));
|
||||
Assert.Contains(
|
||||
audioStreams,
|
||||
stream => val.TargetAudioCodec.Contains(stream.Codec));
|
||||
}
|
||||
// check expected container
|
||||
var containers = ContainerProfile.SplitValue(mediaSource.Container);
|
||||
Assert.Contains(uri.Extension, containers);
|
||||
|
||||
if (playMethod == PlayMethod.DirectStream)
|
||||
{
|
||||
Assert.Matches("stream[.][^.]+$", url.Path);
|
||||
}
|
||||
// check expected video codec (1)
|
||||
Assert.Contains(targetVideoStream.Codec, val.TargetVideoCodec);
|
||||
Assert.Single(val.TargetVideoCodec);
|
||||
|
||||
if (playMethod == PlayMethod.Transcode)
|
||||
// check expected audio codecs (1)
|
||||
Assert.Contains(targetAudioStream.Codec, val.TargetAudioCodec);
|
||||
Assert.Single(val.AudioCodecs);
|
||||
|
||||
// TODO: validate transcoding options as well
|
||||
}
|
||||
else if (playMethod == PlayMethod.DirectStream || playMethod == PlayMethod.Transcode)
|
||||
{
|
||||
if (fullTranscode)
|
||||
Assert.NotNull(val.Container);
|
||||
// Assert.NotEmpty(val.VideoCodecs);
|
||||
// Assert.NotEmpty(val.AudioCodecs);
|
||||
|
||||
// check expected container (todo: this could be a test param)
|
||||
if (transcodeProtocol == "http")
|
||||
{
|
||||
Assert.Equal("hls", val.SubProtocol);
|
||||
Assert.EndsWith("master.m3u8", url.Path, StringComparison.InvariantCulture);
|
||||
|
||||
// Assert.All(
|
||||
// videoStreams,
|
||||
// stream => Assert.DoesNotContain(stream.Codec, val.TargetVideoCodec));
|
||||
// Assert.Equal("webm", val.Container);
|
||||
Assert.Equal(val.Container, uri.Extension);
|
||||
Assert.Equal("stream", uri.Filename);
|
||||
// Assert.Equal("http", val.SubProtocol);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Equal("ts", val.Container);
|
||||
Assert.Equal("m3u8", uri.Extension);
|
||||
Assert.Equal("master", uri.Filename);
|
||||
Assert.Equal("hls", val.SubProtocol);
|
||||
Assert.EndsWith("master.m3u8", url.Path, StringComparison.InvariantCulture);
|
||||
}
|
||||
|
||||
Assert.Contains(
|
||||
videoStreams,
|
||||
stream => val.TargetVideoCodec.Contains(stream.Codec));
|
||||
// Assert.All(
|
||||
// audioStreams,
|
||||
// stream => Assert.DoesNotContain(stream.Codec, val.TargetAudioCodec));
|
||||
// Full transcode
|
||||
if (transcodeMode == "Transcode")
|
||||
{
|
||||
// TODO: what else to validate here
|
||||
if ((val.TranscodeReasons & TranscodeReason.ContainerReasons) == TranscodeReason.None)
|
||||
{
|
||||
// Assert.All(
|
||||
// videoStreams,
|
||||
// stream => Assert.DoesNotContain(stream.Codec, val.VideoCodecs));
|
||||
}
|
||||
|
||||
// todo: fill out tests here
|
||||
}
|
||||
|
||||
// DirectStream and Remux
|
||||
else
|
||||
{
|
||||
// check expected video codec (1)
|
||||
Assert.Contains(targetVideoStream.Codec, val.TargetVideoCodec);
|
||||
Assert.Single(val.TargetVideoCodec);
|
||||
|
||||
if (transcodeMode == "DirectStream")
|
||||
{
|
||||
if (!targetAudioStream.IsExternal)
|
||||
{
|
||||
// check expected audio codecs (1)
|
||||
// Assert.DoesNotContain(targetAudioStream.Codec, val.AudioCodecs);
|
||||
}
|
||||
}
|
||||
else if (transcodeMode == "Remux")
|
||||
{
|
||||
// check expected audio codecs (1)
|
||||
Assert.Contains(targetAudioStream.Codec, val.AudioCodecs);
|
||||
Assert.Single(val.AudioCodecs);
|
||||
}
|
||||
|
||||
// video details
|
||||
var videoStream = targetVideoStream;
|
||||
Assert.False(val.EstimateContentLength);
|
||||
Assert.Equal(TranscodeSeekInfo.Auto, val.TranscodeSeekInfo);
|
||||
// Assert.True(val.CopyTimestamps);
|
||||
|
||||
var videoStream = videoStreams.First(stream => val.TargetVideoCodec.Contains(stream.Codec));
|
||||
|
||||
Assert.Contains(videoStream.Codec, val.TargetVideoCodec);
|
||||
// Assert.Contains(videoStream.Profile.ToLowerInvariant(), val.TargetVideoProfile.Split(","));
|
||||
// Assert.Contains(videoStream.Profile?.ToLowerInvariant() ?? string.Empty, val.TargetVideoProfile?.Split(",").Select(s => s.ToLowerInvariant()) ?? new string[0]);
|
||||
// Assert.Equal(videoStream.Level, val.TargetVideoLevel);
|
||||
// Assert.Equal(videoStream.BitDepth, val.TargetVideoBitDepth);
|
||||
// Assert.Equal(videoStream.BitRate, val.VideoBitrate);
|
||||
// Assert.InRange(val.VideoBitrate.GetValueOrDefault(), videoStream.BitRate.GetValueOrDefault(), int.MaxValue);
|
||||
|
||||
// audio codec not supported
|
||||
if ((why & TranscodeReason.AudioCodecNotSupported) != TranscodeReason.None)
|
||||
{
|
||||
// audio stream specified
|
||||
if (options.AudioStreamIndex >= 0)
|
||||
{
|
||||
// TODO:fixme
|
||||
if (!targetAudioStream.IsExternal)
|
||||
{
|
||||
Assert.DoesNotContain(targetAudioStream.Codec, val.AudioCodecs);
|
||||
}
|
||||
}
|
||||
|
||||
// audio stream not specified
|
||||
else
|
||||
{
|
||||
// TODO:fixme
|
||||
Assert.All(audioStreams, stream =>
|
||||
{
|
||||
if (!stream.IsExternal)
|
||||
{
|
||||
// Assert.DoesNotContain(stream.Codec, val.AudioCodecs);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -182,7 +347,7 @@ namespace Jellyfin.MediaBrowser.Model.Tests
|
|||
{
|
||||
// what should the actual result be here?
|
||||
Assert.Null(val.SubProtocol);
|
||||
Assert.EndsWith("/stream", url.Path, StringComparison.InvariantCulture);
|
||||
Assert.EndsWith("/stream", uri.Path, StringComparison.InvariantCulture);
|
||||
|
||||
Assert.False(val.EstimateContentLength);
|
||||
Assert.Equal(TranscodeSeekInfo.Auto, val.TranscodeSeekInfo);
|
||||
|
@ -231,5 +396,23 @@ namespace Jellyfin.MediaBrowser.Model.Tests
|
|||
Profile = dp,
|
||||
};
|
||||
}
|
||||
|
||||
private static (string Path, NameValueCollection Query, string Filename, string Extension) ParseUri(StreamInfo val)
|
||||
{
|
||||
var href = val.ToUrl("media:", "ACCESSTOKEN").Split("?", 2);
|
||||
var path = href[0];
|
||||
|
||||
var queryString = href.ElementAtOrDefault(1);
|
||||
var query = string.IsNullOrEmpty(queryString) ? System.Web.HttpUtility.ParseQueryString(queryString ?? string.Empty) : new NameValueCollection();
|
||||
|
||||
var filename = System.IO.Path.GetFileNameWithoutExtension(path);
|
||||
var extension = System.IO.Path.GetExtension(path);
|
||||
if (extension.Length > 0)
|
||||
{
|
||||
extension = extension.Substring(1);
|
||||
}
|
||||
|
||||
return (path, query, filename, extension);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user