From 847518701d544fd75780d8d77f98bb5238b45245 Mon Sep 17 00:00:00 2001 From: Dmitry Lyzo Date: Fri, 1 Apr 2022 23:40:15 +0300 Subject: [PATCH 1/3] fix: Fix codec conditions `ApplyConditions` is used to determine the applicability of the current codec (`Conditions`). `Conditions` is the actual conditions for the stream. `CodecType.VideoAudio` (not `CodecType.Video`) must be used for the audio tracks in the video. --- MediaBrowser.Model/Dlna/StreamBuilder.cs | 30 +-- .../Dlna/StreamBuilderTests.cs | 45 +++- .../DeviceProfile-AndroidTVExoPlayer.json | 216 ++++++++++++++++++ 3 files changed, 261 insertions(+), 30 deletions(-) create mode 100644 tests/Jellyfin.Model.Tests/Test Data/DeviceProfile-AndroidTVExoPlayer.json diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index bc34a98669..3fc7ff0a3b 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -750,10 +750,13 @@ namespace MediaBrowser.Model.Dlna var container = transcodingProfile.Container; var appliedVideoConditions = options.Profile.CodecProfiles .Where(i => i.Type == CodecType.Video && - i.ContainsAnyCodec(videoCodec, container)) + i.ContainsAnyCodec(videoCodec, container) && + i.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoConditionSatisfied(applyCondition, videoStream?.Width, videoStream?.Height, videoStream?.BitDepth, videoStream?.BitRate, videoStream?.Profile, videoStream?.Level, videoFramerate, videoStream?.PacketLength, timestamp, videoStream?.IsAnamorphic, videoStream?.IsInterlaced, videoStream?.RefFrames, numVideoStreams, numAudioStreams, videoStream?.CodecTag, videoStream?.IsAVC))) .Select(i => - i.ApplyConditions.Any(applyCondition => ConditionProcessor.IsVideoConditionSatisfied(applyCondition, videoStream?.Width, videoStream?.Height, videoStream?.BitDepth, videoStream?.BitRate, videoStream?.Profile, videoStream?.Level, videoFramerate, videoStream?.PacketLength, timestamp, videoStream?.IsAnamorphic, videoStream?.IsInterlaced, videoStream?.RefFrames, numVideoStreams, numAudioStreams, videoStream?.CodecTag, videoStream?.IsAVC))); - var conditionsSatisfied = !appliedVideoConditions.Any() || !appliedVideoConditions.Any(satisfied => !satisfied); + i.Conditions.All(condition => ConditionProcessor.IsVideoConditionSatisfied(condition, videoStream?.Width, videoStream?.Height, videoStream?.BitDepth, videoStream?.BitRate, videoStream?.Profile, videoStream?.Level, videoFramerate, videoStream?.PacketLength, timestamp, videoStream?.IsAnamorphic, videoStream?.IsInterlaced, videoStream?.RefFrames, numVideoStreams, numAudioStreams, videoStream?.CodecTag, videoStream?.IsAVC))); + + // An empty appliedVideoConditions means that the codec has no conditions for the current video stream + var conditionsSatisfied = appliedVideoConditions.All(satisfied => satisfied); return conditionsSatisfied ? 1 : 2; } @@ -843,7 +846,7 @@ namespace MediaBrowser.Model.Dlna var appliedVideoConditions = options.Profile.CodecProfiles .Where(i => i.Type == CodecType.Video && i.ContainsAnyCodec(videoCodec, container) && - i.ApplyConditions.Any(applyCondition => ConditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))); + i.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))); var isFirstAppliedCodecProfile = true; foreach (var i in appliedVideoConditions) { @@ -873,9 +876,9 @@ namespace MediaBrowser.Model.Dlna int? inputAudioBitDepth = audioStream == null ? null : audioStream.BitDepth; var appliedAudioConditions = options.Profile.CodecProfiles - .Where(i => i.Type == CodecType.Video && + .Where(i => i.Type == CodecType.VideoAudio && i.ContainsAnyCodec(audioCodec, container) && - i.ApplyConditions.Any(applyCondition => ConditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth, audioProfile, isSecondaryAudio))); + i.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth, audioProfile, isSecondaryAudio))); isFirstAppliedCodecProfile = true; foreach (var i in appliedAudioConditions) { @@ -1108,18 +1111,9 @@ namespace MediaBrowser.Model.Dlna profile, "VideoCodecProfile", profile.CodecProfiles - .Where(codecProfile => codecProfile.Type == CodecType.Video && codecProfile.ContainsAnyCodec(videoStream?.Codec, container)) - .SelectMany(codecProfile => - { - var failedApplyConditions = checkVideoConditions(codecProfile.ApplyConditions); - if (!failedApplyConditions.Any()) - { - return Array.Empty(); - } - - var failedConditions = checkVideoConditions(codecProfile.Conditions); - return failedApplyConditions.Concat(failedConditions); - })); + .Where(codecProfile => codecProfile.Type == CodecType.Video && codecProfile.ContainsAnyCodec(videoStream?.Codec, container) && + !checkVideoConditions(codecProfile.ApplyConditions).Any()) + .SelectMany(codecProfile => checkVideoConditions(codecProfile.Conditions))); // Check audiocandidates profile conditions var audioStreamMatches = candidateAudioStreams.ToDictionary(s => s, audioStream => CheckVideoAudioStreamDirectPlay(options, mediaSource, container, audioStream, defaultLanguage, defaultMarked)); diff --git a/tests/Jellyfin.Model.Tests/Dlna/StreamBuilderTests.cs b/tests/Jellyfin.Model.Tests/Dlna/StreamBuilderTests.cs index a56874bc06..484eb63e1f 100644 --- a/tests/Jellyfin.Model.Tests/Dlna/StreamBuilderTests.cs +++ b/tests/Jellyfin.Model.Tests/Dlna/StreamBuilderTests.cs @@ -25,8 +25,8 @@ namespace Jellyfin.Model.Tests [InlineData("Chrome", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectPlay)] // #6450 [InlineData("Chrome", "mp4-h264-ac3-aacExt-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioIsExternal)] // #6450 [InlineData("Chrome", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 - [InlineData("Chrome", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")] - [InlineData("Chrome", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")] + [InlineData("Chrome", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode")] + [InlineData("Chrome", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode")] [InlineData("Chrome", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Chrome", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Chrome", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] // #6450 @@ -36,8 +36,8 @@ namespace Jellyfin.Model.Tests [InlineData("Firefox", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectPlay)] // #6450 [InlineData("Firefox", "mp4-h264-ac3-aacExt-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioIsExternal)] // #6450 [InlineData("Firefox", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 - [InlineData("Firefox", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")] - [InlineData("Firefox", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")] + [InlineData("Firefox", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode")] + [InlineData("Firefox", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode")] [InlineData("Firefox", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Firefox", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Firefox", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] // #6450 @@ -87,8 +87,8 @@ namespace Jellyfin.Model.Tests [InlineData("Chrome-NoHLS", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectPlay)] // #6450 [InlineData("Chrome-NoHLS", "mp4-h264-ac3-aacExt-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioIsExternal)] // #6450 [InlineData("Chrome-NoHLS", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 - [InlineData("Chrome-NoHLS", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode", "http")] - [InlineData("Chrome-NoHLS", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode", "http")] + [InlineData("Chrome-NoHLS", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode", "http")] + [InlineData("Chrome-NoHLS", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode", "http")] [InlineData("Chrome-NoHLS", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Chrome-NoHLS", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Chrome-NoHLS", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] // #6450 @@ -131,6 +131,15 @@ namespace Jellyfin.Model.Tests [InlineData("Null", "mkv-vp9-aac-srt-2600k", null, TranscodeReason.ContainerBitrateExceedsLimit)] [InlineData("Null", "mkv-vp9-ac3-srt-2600k", null, TranscodeReason.ContainerBitrateExceedsLimit)] [InlineData("Null", "mkv-vp9-vorbis-vtt-2600k", null, TranscodeReason.ContainerBitrateExceedsLimit)] + // AndroidTV + [InlineData("AndroidTVExoPlayer", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectPlay)] + [InlineData("AndroidTVExoPlayer", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("AndroidTVExoPlayer", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("AndroidTVExoPlayer", "mp4-hevc-aac-srt-15200k", PlayMethod.DirectPlay)] + [InlineData("AndroidTVExoPlayer", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectPlay)] + [InlineData("AndroidTVExoPlayer", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("AndroidTVExoPlayer", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("AndroidTVExoPlayer", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] public async Task BuildVideoItemSimple(string deviceName, string mediaSource, PlayMethod? playMethod, TranscodeReason why = (TranscodeReason)0, string transcodeMode = "DirectStream", string transcodeProtocol = "") { var options = await GetVideoOptions(deviceName, mediaSource); @@ -144,8 +153,8 @@ namespace Jellyfin.Model.Tests [InlineData("Chrome", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Chrome", "mp4-h264-ac3-aacExt-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Chrome", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 - [InlineData("Chrome", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")] - [InlineData("Chrome", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")] + [InlineData("Chrome", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode")] + [InlineData("Chrome", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode")] [InlineData("Chrome", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Chrome", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Chrome", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] // #6450 @@ -154,8 +163,8 @@ namespace Jellyfin.Model.Tests [InlineData("Firefox", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Firefox", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Firefox", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 - [InlineData("Firefox", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")] - [InlineData("Firefox", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")] + [InlineData("Firefox", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode")] + [InlineData("Firefox", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode")] [InlineData("Firefox", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Firefox", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Firefox", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] // #6450 @@ -198,6 +207,15 @@ namespace Jellyfin.Model.Tests [InlineData("JellyfinMediaPlayer", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectPlay)] // #6450 [InlineData("JellyfinMediaPlayer", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectPlay)] // #6450 [InlineData("JellyfinMediaPlayer", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectPlay)] // #6450 + // AndroidTV + [InlineData("AndroidTVExoPlayer", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectPlay)] + [InlineData("AndroidTVExoPlayer", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("AndroidTVExoPlayer", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("AndroidTVExoPlayer", "mp4-hevc-aac-srt-15200k", PlayMethod.DirectPlay)] + [InlineData("AndroidTVExoPlayer", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectPlay)] + [InlineData("AndroidTVExoPlayer", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("AndroidTVExoPlayer", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("AndroidTVExoPlayer", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] public async Task BuildVideoItemWithFirstExplicitStream(string deviceName, string mediaSource, PlayMethod? playMethod, TranscodeReason why = (TranscodeReason)0, string transcodeMode = "DirectStream", string transcodeProtocol = "") { var options = await GetVideoOptions(deviceName, mediaSource); @@ -213,10 +231,10 @@ namespace Jellyfin.Model.Tests // Chrome [InlineData("Chrome", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay)] // #6450 [InlineData("Chrome", "mp4-h264-ac3-aacExt-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioIsExternal)] // #6450 - [InlineData("Chrome", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")] + [InlineData("Chrome", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode")] // Firefox [InlineData("Firefox", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay)] // #6450 - [InlineData("Firefox", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")] + [InlineData("Firefox", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode")] // Yatse [InlineData("Yatse", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] // #6450 [InlineData("Yatse", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] // #6450 @@ -225,6 +243,9 @@ namespace Jellyfin.Model.Tests [InlineData("RokuSSPlus", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] // #6450 // no streams [InlineData("Chrome", "no-streams", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")] // #6450 + // AndroidTV + [InlineData("AndroidTVExoPlayer", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] + [InlineData("AndroidTVExoPlayer", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] public async Task BuildVideoItemWithDirectPlayExplicitStreams(string deviceName, string mediaSource, PlayMethod? playMethod, TranscodeReason why = (TranscodeReason)0, string transcodeMode = "DirectStream", string transcodeProtocol = "") { var options = await GetVideoOptions(deviceName, mediaSource); diff --git a/tests/Jellyfin.Model.Tests/Test Data/DeviceProfile-AndroidTVExoPlayer.json b/tests/Jellyfin.Model.Tests/Test Data/DeviceProfile-AndroidTVExoPlayer.json new file mode 100644 index 0000000000..3d3968268f --- /dev/null +++ b/tests/Jellyfin.Model.Tests/Test Data/DeviceProfile-AndroidTVExoPlayer.json @@ -0,0 +1,216 @@ +{ + "Name": "Jellyfin AndroidTV-ExoPlayer", + "EnableAlbumArtInDidl": false, + "EnableSingleAlbumArtLimit": false, + "EnableSingleSubtitleLimit": false, + "SupportedMediaTypes": "Audio,Photo,Video", + "MaxAlbumArtWidth": 0, + "MaxAlbumArtHeight": 0, + "MaxStreamingBitrate": 120000000, + "MaxStaticBitrate": 100000000, + "MusicStreamingTranscodingBitrate": 192000, + "TimelineOffsetSeconds": 0, + "RequiresPlainVideoItems": false, + "RequiresPlainFolders": false, + "EnableMSMediaReceiverRegistrar": false, + "IgnoreTranscodeByteRangeRequests": false, + "DirectPlayProfiles": [ + { + "Container": "m4v,mov,xvid,vob,mkv,wmv,asf,ogm,ogv,mp4,webm", + "AudioCodec": "aac,mp3,mp2,aac_latm,alac,ac3,eac3,dca,dts,mlp,truehd,pcm_alaw,pcm_mulaw", + "VideoCodec": "h264,hevc,vp8,vp9,mpeg,mpeg2video", + "Type": "Video", + "$type": "DirectPlayProfile" + }, + { + "Container": "aac,mp3,mp2,aac_latm,alac,ac3,eac3,dca,dts,mlp,truehd,pcm_alaw,pcm_mulaw,,pa,flac,wav,wma,ogg,oga,webma,ape,opus", + "Type": "Audio", + "$type": "DirectPlayProfile" + }, + { + "Container": "jpg,jpeg,png,gif,web", + "Type": "Photo", + "$type": "DirectPlayProfile" + } + ], + "CodecProfiles": [ + { + "Type": "Video", + "Conditions": [ + { + "Condition": "EqualsAny", + "Property": "VideoProfile", + "Value": "high|main|baseline|constrained baseline", + "IsRequired": false, + "$type": "ProfileCondition" + }, + { + "Condition": "LessThanEqual", + "Property": "VideoLevel", + "Value": "51", + "IsRequired": false, + "$type": "ProfileCondition" + } + ], + "Codec": "h264", + "$type": "CodecProfile" + }, + { + "Type": "Video", + "Conditions": [ + { + "Condition": "LessThanEqual", + "Property": "RefFrames", + "Value": "12", + "IsRequired": false, + "$type": "ProfileCondition" + } + ], + "ApplyConditions": [ + { + "Condition": "GreaterThanEqual", + "Property": "Width", + "Value": "1200", + "IsRequired": false, + "$type": "ProfileCondition" + } + ], + "Codec": "h264", + "$type": "CodecProfile" + }, + { + "Type": "Video", + "Conditions": [ + { + "Condition": "LessThanEqual", + "Property": "RefFrames", + "Value": "4", + "IsRequired": false, + "$type": "ProfileCondition" + } + ], + "ApplyConditions": [ + { + "Condition": "GreaterThanEqual", + "Property": "Width", + "Value": "1900", + "IsRequired": false, + "$type": "ProfileCondition" + } + ], + "Codec": "h264", + "$type": "CodecProfile" + }, + { + "Type": "VideoAudio", + "Conditions": [ + { + "Condition": "LessThanEqual", + "Property": "AudioChannels", + "Value": "6", + "IsRequired": false, + "$type": "ProfileCondition" + } + ], + "$type": "CodecProfile" + } + ], + "TranscodingProfiles": [ + { + "Container": "ts", + "Type": "Video", + "VideoCodec": "h264", + "AudioCodec": "aac,mp3", + "Protocol": "hls", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Streaming", + "EnableSubtitlesInManifest": false, + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "$type": "TranscodingProfile" + }, + { + "Container": "mp3", + "Type": "Audio", + "AudioCodec": "mp3", + "Protocol": "http", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Streaming", + "EnableSubtitlesInManifest": false, + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "$type": "TranscodingProfile" + } + ], + "SubtitleProfiles": [ + { + "Format": "srt", + "Method": "Embed", + "$type": "SubtitleProfile" + }, + { + "Format": "srt", + "Method": "External", + "$type": "SubtitleProfile" + }, + { + "Format": "subrip", + "Method": "Embed", + "$type": "SubtitleProfile" + }, + { + "Format": "subrip", + "Method": "External", + "$type": "SubtitleProfile" + }, + { + "Format": "ass", + "Method": "Encode", + "$type": "SubtitleProfile" + }, + { + "Format": "ssa", + "Method": "Encode", + "$type": "SubtitleProfile" + }, + { + "Format": "pgs", + "Method": "Encode", + "$type": "SubtitleProfile" + }, + { + "Format": "pgssub", + "Method": "Encode", + "$type": "SubtitleProfile" + }, + { + "Format": "dvdsub", + "Method": "Encode", + "$type": "SubtitleProfile" + }, + { + "Format": "vtt", + "Method": "Embed", + "$type": "SubtitleProfile" + }, + { + "Format": "sub", + "Method": "Embed", + "$type": "SubtitleProfile" + }, + { + "Format": "idx", + "Method": "Embed", + "$type": "SubtitleProfile" + } + ], + "$type": "DeviceProfile" +} From d5434988d7e637fe81b329d27ba9786c2f3fd349 Mon Sep 17 00:00:00 2001 From: Dmitry Lyzo Date: Sun, 3 Apr 2022 22:33:20 +0300 Subject: [PATCH 2/3] test: Add tests for Tizen 3/4 --- .../Dlna/StreamBuilderTests.cs | 50 ++ .../DeviceProfile-Tizen3-stereo.json | 526 ++++++++++++++++++ .../DeviceProfile-Tizen4-4K-5.1.json | 499 +++++++++++++++++ ...ediaSourceInfo-mp4-h264-dts-srt-2600k.json | 70 +++ ...SourceInfo-mp4-hevc-truehd-srt-15200k.json | 74 +++ 5 files changed, 1219 insertions(+) create mode 100644 tests/Jellyfin.Model.Tests/Test Data/DeviceProfile-Tizen3-stereo.json create mode 100644 tests/Jellyfin.Model.Tests/Test Data/DeviceProfile-Tizen4-4K-5.1.json create mode 100644 tests/Jellyfin.Model.Tests/Test Data/MediaSourceInfo-mp4-h264-dts-srt-2600k.json create mode 100644 tests/Jellyfin.Model.Tests/Test Data/MediaSourceInfo-mp4-hevc-truehd-srt-15200k.json diff --git a/tests/Jellyfin.Model.Tests/Dlna/StreamBuilderTests.cs b/tests/Jellyfin.Model.Tests/Dlna/StreamBuilderTests.cs index 484eb63e1f..013fffef03 100644 --- a/tests/Jellyfin.Model.Tests/Dlna/StreamBuilderTests.cs +++ b/tests/Jellyfin.Model.Tests/Dlna/StreamBuilderTests.cs @@ -140,6 +140,28 @@ namespace Jellyfin.Model.Tests [InlineData("AndroidTVExoPlayer", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectPlay)] [InlineData("AndroidTVExoPlayer", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectPlay)] [InlineData("AndroidTVExoPlayer", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] + // Tizen 3 Stereo + [InlineData("Tizen3-stereo", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectPlay)] + [InlineData("Tizen3-stereo", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("Tizen3-stereo", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("Tizen3-stereo", "mp4-h264-dts-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("Tizen3-stereo", "mp4-hevc-aac-srt-15200k", PlayMethod.DirectPlay)] + [InlineData("Tizen3-stereo", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectPlay)] + [InlineData("Tizen3-stereo", "mp4-hevc-truehd-srt-15200k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] + [InlineData("Tizen3-stereo", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("Tizen3-stereo", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("Tizen3-stereo", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectPlay)] + // Tizen 4 4K 5.1 + [InlineData("Tizen4-4K-5.1", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectPlay)] + [InlineData("Tizen4-4K-5.1", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("Tizen4-4K-5.1", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("Tizen4-4K-5.1", "mp4-h264-dts-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] + [InlineData("Tizen4-4K-5.1", "mp4-hevc-aac-srt-15200k", PlayMethod.DirectPlay)] + [InlineData("Tizen4-4K-5.1", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectPlay)] + [InlineData("Tizen4-4K-5.1", "mp4-hevc-truehd-srt-15200k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] + [InlineData("Tizen4-4K-5.1", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("Tizen4-4K-5.1", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("Tizen4-4K-5.1", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectPlay)] public async Task BuildVideoItemSimple(string deviceName, string mediaSource, PlayMethod? playMethod, TranscodeReason why = (TranscodeReason)0, string transcodeMode = "DirectStream", string transcodeProtocol = "") { var options = await GetVideoOptions(deviceName, mediaSource); @@ -216,6 +238,28 @@ namespace Jellyfin.Model.Tests [InlineData("AndroidTVExoPlayer", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectPlay)] [InlineData("AndroidTVExoPlayer", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectPlay)] [InlineData("AndroidTVExoPlayer", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] + // Tizen 3 Stereo + [InlineData("Tizen3-stereo", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectPlay)] + [InlineData("Tizen3-stereo", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("Tizen3-stereo", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("Tizen3-stereo", "mp4-h264-dts-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("Tizen3-stereo", "mp4-hevc-aac-srt-15200k", PlayMethod.DirectPlay)] + [InlineData("Tizen3-stereo", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectPlay)] + [InlineData("Tizen3-stereo", "mp4-hevc-truehd-srt-15200k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] + [InlineData("Tizen3-stereo", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("Tizen3-stereo", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("Tizen3-stereo", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectPlay)] + // Tizen 4 4K 5.1 + [InlineData("Tizen4-4K-5.1", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectPlay)] + [InlineData("Tizen4-4K-5.1", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("Tizen4-4K-5.1", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("Tizen4-4K-5.1", "mp4-h264-dts-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] + [InlineData("Tizen4-4K-5.1", "mp4-hevc-aac-srt-15200k", PlayMethod.DirectPlay)] + [InlineData("Tizen4-4K-5.1", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectPlay)] + [InlineData("Tizen4-4K-5.1", "mp4-hevc-truehd-srt-15200k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] + [InlineData("Tizen4-4K-5.1", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("Tizen4-4K-5.1", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectPlay)] + [InlineData("Tizen4-4K-5.1", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectPlay)] public async Task BuildVideoItemWithFirstExplicitStream(string deviceName, string mediaSource, PlayMethod? playMethod, TranscodeReason why = (TranscodeReason)0, string transcodeMode = "DirectStream", string transcodeProtocol = "") { var options = await GetVideoOptions(deviceName, mediaSource); @@ -246,6 +290,12 @@ namespace Jellyfin.Model.Tests // AndroidTV [InlineData("AndroidTVExoPlayer", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] [InlineData("AndroidTVExoPlayer", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] + // Tizen 3 Stereo + [InlineData("Tizen3-stereo", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] + [InlineData("Tizen3-stereo", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] + // Tizen 4 4K 5.1 + [InlineData("Tizen4-4K-5.1", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] + [InlineData("Tizen4-4K-5.1", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] public async Task BuildVideoItemWithDirectPlayExplicitStreams(string deviceName, string mediaSource, PlayMethod? playMethod, TranscodeReason why = (TranscodeReason)0, string transcodeMode = "DirectStream", string transcodeProtocol = "") { var options = await GetVideoOptions(deviceName, mediaSource); diff --git a/tests/Jellyfin.Model.Tests/Test Data/DeviceProfile-Tizen3-stereo.json b/tests/Jellyfin.Model.Tests/Test Data/DeviceProfile-Tizen3-stereo.json new file mode 100644 index 0000000000..719f553ce8 --- /dev/null +++ b/tests/Jellyfin.Model.Tests/Test Data/DeviceProfile-Tizen3-stereo.json @@ -0,0 +1,526 @@ +{ + "Name": "Jellyfin Tizen 3 Stereo", + "EnableAlbumArtInDidl": false, + "EnableSingleAlbumArtLimit": false, + "EnableSingleSubtitleLimit": false, + "SupportedMediaTypes": "Audio,Photo,Video", + "MaxAlbumArtWidth": 0, + "MaxAlbumArtHeight": 0, + "MaxStreamingBitrate": 120000000, + "MaxStaticBitrate": 100000000, + "MusicStreamingTranscodingBitrate": 384000, + "TimelineOffsetSeconds": 0, + "RequiresPlainVideoItems": false, + "RequiresPlainFolders": false, + "EnableMSMediaReceiverRegistrar": false, + "IgnoreTranscodeByteRangeRequests": false, + "DirectPlayProfiles": [ + { + "Container": "webm", + "AudioCodec": "vorbis,opus", + "VideoCodec": "vp8,vp9", + "Type": "Video", + "$type": "DirectPlayProfile" + }, + { + "Container": "mp4,m4v", + "AudioCodec": "aac,mp3,ac3,eac3,mp2,dca,dts,pcm_s16le,pcm_s24le,aac_latm,opus,flac,vorbis", + "VideoCodec": "h264,hevc,mpeg2video,vc1,msmpeg4v2,vp8,vp9", + "Type": "Video", + "$type": "DirectPlayProfile" + }, + { + "Container": "mkv", + "AudioCodec": "aac,mp3,ac3,eac3,mp2,dca,dts,pcm_s16le,pcm_s24le,aac_latm,opus,flac,vorbis", + "VideoCodec": "h264,hevc,mpeg2video,vc1,msmpeg4v2,vp8,vp9", + "Type": "Video", + "$type": "DirectPlayProfile" + }, + { + "Container": "m2ts", + "AudioCodec": "aac,mp3,ac3,eac3,mp2,dca,dts,pcm_s16le,pcm_s24le,aac_latm,opus,flac,vorbis", + "VideoCodec": "h264,vc1,mpeg2video", + "Type": "Video", + "$type": "DirectPlayProfile" + }, + { + "Container": "wmv", + "AudioCodec": "", + "VideoCodec": "", + "Type": "Video", + "$type": "DirectPlayProfile" + }, + { + "Container": "ts,mpegts", + "AudioCodec": "aac,mp3,ac3,eac3,mp2,dca,dts,pcm_s16le,pcm_s24le,aac_latm,opus,flac,vorbis", + "VideoCodec": "h264,hevc,vc1,mpeg2video", + "Type": "Video", + "$type": "DirectPlayProfile" + }, + { + "Container": "asf", + "AudioCodec": "", + "VideoCodec": "", + "Type": "Video", + "$type": "DirectPlayProfile" + }, + { + "Container": "avi", + "AudioCodec": "aac,mp3,ac3,eac3,mp2,dca,dts,pcm_s16le,pcm_s24le,aac_latm,opus,flac,vorbis", + "VideoCodec": "", + "Type": "Video", + "$type": "DirectPlayProfile" + }, + { + "Container": "mpg,mpeg,flv,3gp,mts,trp,vob,vro", + "AudioCodec": "aac,mp3,ac3,eac3,mp2,dca,dts,pcm_s16le,pcm_s24le,aac_latm,opus,flac,vorbis", + "VideoCodec": "", + "Type": "Video", + "$type": "DirectPlayProfile" + }, + { + "Container": "mov", + "AudioCodec": "aac,mp3,ac3,eac3,mp2,dca,dts,pcm_s16le,pcm_s24le,aac_latm,opus,flac,vorbis", + "VideoCodec": "h264", + "Type": "Video", + "$type": "DirectPlayProfile" + }, + { + "Container": "opus", + "Type": "Audio", + "$type": "DirectPlayProfile" + }, + { + "Container": "webm", + "AudioCodec": "opus", + "Type": "Audio", + "$type": "DirectPlayProfile" + }, + { + "Container": "mp3", + "Type": "Audio", + "$type": "DirectPlayProfile" + }, + { + "Container": "aac", + "Type": "Audio", + "$type": "DirectPlayProfile" + }, + { + "Container": "m4a", + "AudioCodec": "aac", + "Type": "Audio", + "$type": "DirectPlayProfile" + }, + { + "Container": "m4b", + "AudioCodec": "aac", + "Type": "Audio", + "$type": "DirectPlayProfile" + }, + { + "Container": "flac", + "Type": "Audio", + "$type": "DirectPlayProfile" + }, + { + "Container": "webma", + "Type": "Audio", + "$type": "DirectPlayProfile" + }, + { + "Container": "webm", + "AudioCodec": "webma", + "Type": "Audio", + "$type": "DirectPlayProfile" + }, + { + "Container": "wma", + "Type": "Audio", + "$type": "DirectPlayProfile" + }, + { + "Container": "wav", + "Type": "Audio", + "$type": "DirectPlayProfile" + }, + { + "Container": "ogg", + "Type": "Audio", + "$type": "DirectPlayProfile" + } + ], + "TranscodingProfiles": [ + { + "Container": "aac", + "Type": "Audio", + "AudioCodec": "aac", + "Protocol": "hls", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Streaming", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "2", + "MinSegments": 1, + "SegmentLength": 0, + "BreakOnNonKeyFrames": true, + "$type": "TranscodingProfile" + }, + { + "Container": "aac", + "Type": "Audio", + "AudioCodec": "aac", + "Protocol": "http", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Streaming", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "2", + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "$type": "TranscodingProfile" + }, + { + "Container": "mp3", + "Type": "Audio", + "AudioCodec": "mp3", + "Protocol": "http", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Streaming", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "2", + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "$type": "TranscodingProfile" + }, + { + "Container": "opus", + "Type": "Audio", + "AudioCodec": "opus", + "Protocol": "http", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Streaming", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "2", + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "$type": "TranscodingProfile" + }, + { + "Container": "wav", + "Type": "Audio", + "AudioCodec": "wav", + "Protocol": "http", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Streaming", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "2", + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "$type": "TranscodingProfile" + }, + { + "Container": "opus", + "Type": "Audio", + "AudioCodec": "opus", + "Protocol": "http", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Static", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "2", + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "$type": "TranscodingProfile" + }, + { + "Container": "mp3", + "Type": "Audio", + "AudioCodec": "mp3", + "Protocol": "http", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Static", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "2", + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "$type": "TranscodingProfile" + }, + { + "Container": "aac", + "Type": "Audio", + "AudioCodec": "aac", + "Protocol": "http", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Static", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "2", + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "$type": "TranscodingProfile" + }, + { + "Container": "wav", + "Type": "Audio", + "AudioCodec": "wav", + "Protocol": "http", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Static", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "2", + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "$type": "TranscodingProfile" + }, + { + "Container": "mkv", + "Type": "Video", + "VideoCodec": "h264,hevc,mpeg2video,vc1,msmpeg4v2,vp8,vp9", + "AudioCodec": "aac,mp3,ac3,eac3,mp2,dca,dts,pcm_s16le,pcm_s24le,aac_latm,opus,flac,vorbis", + "Protocol": "", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": true, + "Context": "Static", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "2", + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "Conditions": [ + { + "Condition": "LessThanEqual", + "Property": "Width", + "Value": "1920", + "IsRequired": false, + "$type": "ProfileCondition" + } + ], + "$type": "TranscodingProfile" + }, + { + "Container": "ts", + "Type": "Video", + "VideoCodec": "h264,hevc", + "AudioCodec": "aac,mp3,ac3,eac3,opus", + "Protocol": "hls", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Streaming", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "2", + "MinSegments": 1, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "Conditions": [ + { + "Condition": "LessThanEqual", + "Property": "Width", + "Value": "1920", + "IsRequired": false, + "$type": "ProfileCondition" + } + ], + "$type": "TranscodingProfile" + }, + { + "Container": "webm", + "Type": "Video", + "VideoCodec": "vp8,vp9,vpx", + "AudioCodec": "vorbis,opus", + "Protocol": "http", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Streaming", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "2", + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "Conditions": [ + { + "Condition": "LessThanEqual", + "Property": "Width", + "Value": "1920", + "IsRequired": false, + "$type": "ProfileCondition" + } + ], + "$type": "TranscodingProfile" + }, + { + "Container": "mp4", + "Type": "Video", + "VideoCodec": "h264", + "AudioCodec": "aac,mp3,ac3,eac3,mp2,dca,dts,pcm_s16le,pcm_s24le,aac_latm,opus,flac,vorbis", + "Protocol": "http", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Static", + "EnableSubtitlesInManifest": false, + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "Conditions": [ + { + "Condition": "LessThanEqual", + "Property": "Width", + "Value": "1920", + "IsRequired": false, + "$type": "ProfileCondition" + } + ], + "$type": "TranscodingProfile" + } + ], + "CodecProfiles": [ + { + "Type": "Video", + "Conditions": [ + { + "Condition": "NotEquals", + "Property": "IsAnamorphic", + "Value": "true", + "IsRequired": false, + "$type": "ProfileCondition" + }, + { + "Condition": "EqualsAny", + "Property": "VideoProfile", + "Value": "high|main|baseline|constrained baseline|high 10", + "IsRequired": false, + "$type": "ProfileCondition" + }, + { + "Condition": "LessThanEqual", + "Property": "VideoLevel", + "Value": "52", + "IsRequired": false, + "$type": "ProfileCondition" + }, + { + "Condition": "LessThanEqual", + "Property": "VideoBitrate", + "Value": "20000000", + "IsRequired": false, + "$type": "ProfileCondition" + } + ], + "Codec": "h264", + "$type": "CodecProfile" + }, + { + "Type": "Video", + "Conditions": [ + { + "Condition": "NotEquals", + "Property": "IsAnamorphic", + "Value": "true", + "IsRequired": false, + "$type": "ProfileCondition" + }, + { + "Condition": "EqualsAny", + "Property": "VideoProfile", + "Value": "main|main 10", + "IsRequired": false, + "$type": "ProfileCondition" + }, + { + "Condition": "LessThanEqual", + "Property": "VideoLevel", + "Value": "183", + "IsRequired": false, + "$type": "ProfileCondition" + }, + { + "Condition": "LessThanEqual", + "Property": "VideoBitrate", + "Value": "20000000", + "IsRequired": false, + "$type": "ProfileCondition" + } + ], + "Codec": "hevc", + "$type": "CodecProfile" + }, + { + "Type": "Video", + "Conditions": [ + { + "Condition": "LessThanEqual", + "Property": "VideoBitrate", + "Value": "20000000", + "IsRequired": false, + "$type": "ProfileCondition" + } + ], + "$type": "CodecProfile" + } + ], + "ResponseProfiles": [ + { + "Container": "m4v", + "Type": "Video", + "MimeType": "video/mp4", + "$type": "ResponseProfile" + } + ], + "SubtitleProfiles": [ + { + "Format": "vtt", + "Method": "External", + "$type": "SubtitleProfile" + }, + { + "Format": "ass", + "Method": "External", + "$type": "SubtitleProfile" + }, + { + "Format": "ssa", + "Method": "External", + "$type": "SubtitleProfile" + } + ], + "$type": "DeviceProfile" +} diff --git a/tests/Jellyfin.Model.Tests/Test Data/DeviceProfile-Tizen4-4K-5.1.json b/tests/Jellyfin.Model.Tests/Test Data/DeviceProfile-Tizen4-4K-5.1.json new file mode 100644 index 0000000000..79b1f4fdb1 --- /dev/null +++ b/tests/Jellyfin.Model.Tests/Test Data/DeviceProfile-Tizen4-4K-5.1.json @@ -0,0 +1,499 @@ +{ + "Name": "Jellyfin Tizen 4 4K 5.1", + "EnableAlbumArtInDidl": false, + "EnableSingleAlbumArtLimit": false, + "EnableSingleSubtitleLimit": false, + "SupportedMediaTypes": "Audio,Photo,Video", + "MaxAlbumArtWidth": 0, + "MaxAlbumArtHeight": 0, + "MaxStreamingBitrate": 120000000, + "MaxStaticBitrate": 100000000, + "MusicStreamingTranscodingBitrate": 384000, + "TimelineOffsetSeconds": 0, + "RequiresPlainVideoItems": false, + "RequiresPlainFolders": false, + "EnableMSMediaReceiverRegistrar": false, + "IgnoreTranscodeByteRangeRequests": false, + "DirectPlayProfiles": [ + { + "Container": "webm", + "AudioCodec": "vorbis,opus", + "VideoCodec": "vp8,vp9", + "Type": "Video", + "$type": "DirectPlayProfile" + }, + { + "Container": "mp4,m4v", + "AudioCodec": "aac,mp3,ac3,eac3,mp2,pcm_s16le,pcm_s24le,aac_latm,opus,flac,vorbis", + "VideoCodec": "h264,hevc,mpeg2video,vc1,msmpeg4v2,vp8,vp9", + "Type": "Video", + "$type": "DirectPlayProfile" + }, + { + "Container": "mkv", + "AudioCodec": "aac,mp3,ac3,eac3,mp2,pcm_s16le,pcm_s24le,aac_latm,opus,flac,vorbis", + "VideoCodec": "h264,hevc,mpeg2video,vc1,msmpeg4v2,vp8,vp9", + "Type": "Video", + "$type": "DirectPlayProfile" + }, + { + "Container": "m2ts", + "AudioCodec": "aac,mp3,ac3,eac3,mp2,pcm_s16le,pcm_s24le,aac_latm,opus,flac,vorbis", + "VideoCodec": "h264,vc1,mpeg2video", + "Type": "Video", + "$type": "DirectPlayProfile" + }, + { + "Container": "wmv", + "AudioCodec": "", + "VideoCodec": "", + "Type": "Video", + "$type": "DirectPlayProfile" + }, + { + "Container": "ts,mpegts", + "AudioCodec": "aac,mp3,ac3,eac3,mp2,pcm_s16le,pcm_s24le,aac_latm,opus,flac,vorbis", + "VideoCodec": "h264,hevc,vc1,mpeg2video", + "Type": "Video", + "$type": "DirectPlayProfile" + }, + { + "Container": "asf", + "AudioCodec": "", + "VideoCodec": "", + "Type": "Video", + "$type": "DirectPlayProfile" + }, + { + "Container": "avi", + "AudioCodec": "aac,mp3,ac3,eac3,mp2,pcm_s16le,pcm_s24le,aac_latm,opus,flac,vorbis", + "VideoCodec": "h264,hevc", + "Type": "Video", + "$type": "DirectPlayProfile" + }, + { + "Container": "mpg,mpeg,flv,3gp,mts,trp,vob,vro", + "AudioCodec": "aac,mp3,ac3,eac3,mp2,pcm_s16le,pcm_s24le,aac_latm,opus,flac,vorbis", + "VideoCodec": "", + "Type": "Video", + "$type": "DirectPlayProfile" + }, + { + "Container": "mov", + "AudioCodec": "aac,mp3,ac3,eac3,mp2,pcm_s16le,pcm_s24le,aac_latm,opus,flac,vorbis", + "VideoCodec": "h264", + "Type": "Video", + "$type": "DirectPlayProfile" + }, + { + "Container": "opus", + "Type": "Audio", + "$type": "DirectPlayProfile" + }, + { + "Container": "webm", + "AudioCodec": "opus", + "Type": "Audio", + "$type": "DirectPlayProfile" + }, + { + "Container": "mp3", + "Type": "Audio", + "$type": "DirectPlayProfile" + }, + { + "Container": "aac", + "Type": "Audio", + "$type": "DirectPlayProfile" + }, + { + "Container": "m4a", + "AudioCodec": "aac", + "Type": "Audio", + "$type": "DirectPlayProfile" + }, + { + "Container": "m4b", + "AudioCodec": "aac", + "Type": "Audio", + "$type": "DirectPlayProfile" + }, + { + "Container": "flac", + "Type": "Audio", + "$type": "DirectPlayProfile" + }, + { + "Container": "webma", + "Type": "Audio", + "$type": "DirectPlayProfile" + }, + { + "Container": "webm", + "AudioCodec": "webma", + "Type": "Audio", + "$type": "DirectPlayProfile" + }, + { + "Container": "wma", + "Type": "Audio", + "$type": "DirectPlayProfile" + }, + { + "Container": "wav", + "Type": "Audio", + "$type": "DirectPlayProfile" + }, + { + "Container": "ogg", + "Type": "Audio", + "$type": "DirectPlayProfile" + } + ], + "TranscodingProfiles": [ + { + "Container": "aac", + "Type": "Audio", + "AudioCodec": "aac", + "Protocol": "hls", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Streaming", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "6", + "MinSegments": 1, + "SegmentLength": 0, + "BreakOnNonKeyFrames": true, + "$type": "TranscodingProfile" + }, + { + "Container": "aac", + "Type": "Audio", + "AudioCodec": "aac", + "Protocol": "http", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Streaming", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "6", + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "$type": "TranscodingProfile" + }, + { + "Container": "mp3", + "Type": "Audio", + "AudioCodec": "mp3", + "Protocol": "http", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Streaming", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "6", + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "$type": "TranscodingProfile" + }, + { + "Container": "opus", + "Type": "Audio", + "AudioCodec": "opus", + "Protocol": "http", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Streaming", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "6", + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "$type": "TranscodingProfile" + }, + { + "Container": "wav", + "Type": "Audio", + "AudioCodec": "wav", + "Protocol": "http", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Streaming", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "6", + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "$type": "TranscodingProfile" + }, + { + "Container": "opus", + "Type": "Audio", + "AudioCodec": "opus", + "Protocol": "http", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Static", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "6", + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "$type": "TranscodingProfile" + }, + { + "Container": "mp3", + "Type": "Audio", + "AudioCodec": "mp3", + "Protocol": "http", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Static", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "6", + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "$type": "TranscodingProfile" + }, + { + "Container": "aac", + "Type": "Audio", + "AudioCodec": "aac", + "Protocol": "http", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Static", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "6", + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "$type": "TranscodingProfile" + }, + { + "Container": "wav", + "Type": "Audio", + "AudioCodec": "wav", + "Protocol": "http", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Static", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "6", + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "$type": "TranscodingProfile" + }, + { + "Container": "mkv", + "Type": "Video", + "VideoCodec": "h264,hevc,mpeg2video,vc1,msmpeg4v2,vp8,vp9", + "AudioCodec": "aac,mp3,ac3,eac3,mp2,pcm_s16le,pcm_s24le,aac_latm,opus,flac,vorbis", + "Protocol": "", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": true, + "Context": "Static", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "6", + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "Conditions": [ + { + "Condition": "LessThanEqual", + "Property": "Width", + "Value": "3840", + "IsRequired": false, + "$type": "ProfileCondition" + } + ], + "$type": "TranscodingProfile" + }, + { + "Container": "ts", + "Type": "Video", + "VideoCodec": "h264,hevc", + "AudioCodec": "aac,mp3,ac3,eac3,opus", + "Protocol": "hls", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Streaming", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "6", + "MinSegments": 1, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "Conditions": [ + { + "Condition": "LessThanEqual", + "Property": "Width", + "Value": "3840", + "IsRequired": false, + "$type": "ProfileCondition" + } + ], + "$type": "TranscodingProfile" + }, + { + "Container": "webm", + "Type": "Video", + "VideoCodec": "vp8,vp9,vpx", + "AudioCodec": "vorbis,opus", + "Protocol": "http", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Streaming", + "EnableSubtitlesInManifest": false, + "MaxAudioChannels": "6", + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "Conditions": [ + { + "Condition": "LessThanEqual", + "Property": "Width", + "Value": "3840", + "IsRequired": false, + "$type": "ProfileCondition" + } + ], + "$type": "TranscodingProfile" + }, + { + "Container": "mp4", + "Type": "Video", + "VideoCodec": "h264", + "AudioCodec": "aac,mp3,ac3,eac3,mp2,pcm_s16le,pcm_s24le,aac_latm,opus,flac,vorbis", + "Protocol": "http", + "EstimateContentLength": false, + "EnableMpegtsM2TsMode": false, + "TranscodeSeekInfo": "Auto", + "CopyTimestamps": false, + "Context": "Static", + "EnableSubtitlesInManifest": false, + "MinSegments": 0, + "SegmentLength": 0, + "BreakOnNonKeyFrames": false, + "Conditions": [ + { + "Condition": "LessThanEqual", + "Property": "Width", + "Value": "3840", + "IsRequired": false, + "$type": "ProfileCondition" + } + ], + "$type": "TranscodingProfile" + } + ], + "CodecProfiles": [ + { + "Type": "Video", + "Conditions": [ + { + "Condition": "NotEquals", + "Property": "IsAnamorphic", + "Value": "true", + "IsRequired": false, + "$type": "ProfileCondition" + }, + { + "Condition": "EqualsAny", + "Property": "VideoProfile", + "Value": "high|main|baseline|constrained baseline|high 10", + "IsRequired": false, + "$type": "ProfileCondition" + }, + { + "Condition": "LessThanEqual", + "Property": "VideoLevel", + "Value": "52", + "IsRequired": false, + "$type": "ProfileCondition" + } + ], + "Codec": "h264", + "$type": "CodecProfile" + }, + { + "Type": "Video", + "Conditions": [ + { + "Condition": "NotEquals", + "Property": "IsAnamorphic", + "Value": "true", + "IsRequired": false, + "$type": "ProfileCondition" + }, + { + "Condition": "EqualsAny", + "Property": "VideoProfile", + "Value": "main|main 10", + "IsRequired": false, + "$type": "ProfileCondition" + }, + { + "Condition": "LessThanEqual", + "Property": "VideoLevel", + "Value": "183", + "IsRequired": false, + "$type": "ProfileCondition" + } + ], + "Codec": "hevc", + "$type": "CodecProfile" + } + ], + "ResponseProfiles": [ + { + "Container": "m4v", + "Type": "Video", + "MimeType": "video/mp4", + "$type": "ResponseProfile" + } + ], + "SubtitleProfiles": [ + { + "Format": "vtt", + "Method": "External", + "$type": "SubtitleProfile" + }, + { + "Format": "ass", + "Method": "External", + "$type": "SubtitleProfile" + }, + { + "Format": "ssa", + "Method": "External", + "$type": "SubtitleProfile" + } + ], + "$type": "DeviceProfile" +} diff --git a/tests/Jellyfin.Model.Tests/Test Data/MediaSourceInfo-mp4-h264-dts-srt-2600k.json b/tests/Jellyfin.Model.Tests/Test Data/MediaSourceInfo-mp4-h264-dts-srt-2600k.json new file mode 100644 index 0000000000..224365df63 --- /dev/null +++ b/tests/Jellyfin.Model.Tests/Test Data/MediaSourceInfo-mp4-h264-dts-srt-2600k.json @@ -0,0 +1,70 @@ +{ + "Id": "a766d122b58e45d9492d17af77748bf5", + "Path": "/Media/MyVideo-720p.mp4", + "Container": "mov,mp4,m4a,3gp,3g2,mj2", + "Size": 835317696, + "Name": "MyVideo-720p", + "ETag": "579a34c6d5dfb21d81539a51220b6a23", + "RunTimeTicks": 25801230336, + "SupportsTranscoding": true, + "SupportsDirectStream": true, + "SupportsDirectPlay": true, + "SupportsProbing": true, + "MediaStreams": [ + { + "Codec": "h264", + "CodecTag": "avc1", + "Language": "eng", + "TimeBase": "1/11988", + "VideoRange": "SDR", + "DisplayTitle": "720p H264 SDR", + "NalLengthSize": "0", + "BitRate": 2032876, + "BitDepth": 8, + "RefFrames": 1, + "IsDefault": true, + "Height": 720, + "Width": 1280, + "AverageFrameRate": 23.976, + "RealFrameRate": 23.976, + "Profile": "High", + "Type": 1, + "AspectRatio": "16:9", + "PixelFormat": "yuv420p", + "Level": 41 + }, + { + "Codec": "dts", + "Language": "eng", + "TimeBase": "1/48000", + "DisplayTitle": "En - DTS - 5.1 - Default", + "ChannelLayout": "5.1", + "BitRate": 384000, + "Channels": 6, + "SampleRate": 48000, + "IsDefault": true, + "Index": 1, + "Score": 202 + }, + { + "Codec": "srt", + "Language": "eng", + "TimeBase": "1/1000000", + "localizedUndefined": "Undefined", + "localizedDefault": "Default", + "localizedForced": "Forced", + "DisplayTitle": "En - Default", + "BitRate": 92, + "IsDefault": true, + "Type": 2, + "Index": 2, + "Score": 6421, + "IsExternal": true, + "IsTextSubtitleStream": true, + "SupportsExternalStream": true + } + ], + "Bitrate": 2590008, + "DefaultAudioStreamIndex": 1, + "DefaultSubtitleStreamIndex": 2 +} diff --git a/tests/Jellyfin.Model.Tests/Test Data/MediaSourceInfo-mp4-hevc-truehd-srt-15200k.json b/tests/Jellyfin.Model.Tests/Test Data/MediaSourceInfo-mp4-hevc-truehd-srt-15200k.json new file mode 100644 index 0000000000..a5393966f4 --- /dev/null +++ b/tests/Jellyfin.Model.Tests/Test Data/MediaSourceInfo-mp4-hevc-truehd-srt-15200k.json @@ -0,0 +1,74 @@ +{ + "Id": "f6eab7118618ab26e61e495a1853481a", + "Path": "/Media/MyVideo-WEBDL-2160p.mp4", + "Container": "mov,mp4,m4a,3gp,3g2,mj2", + "Size": 6521110016, + "Name": "MyVideo WEBDL-2160p", + "ETag": "a2fb84b618ba2467fe377543f879e9bf", + "RunTimeTicks": 34318510080, + "SupportsTranscoding": true, + "SupportsDirectStream": true, + "SupportsDirectPlay": true, + "SupportsProbing": true, + "MediaStreams": [ + { + "Codec": "hevc", + "CodecTag": "hev1", + "Language": "eng", + "ColorSpace": "bt2020nc", + "ColorTransfer": "smpte2084", + "ColorPrimaries": "bt2020", + "TimeBase": "1/16000", + "VideoRange": "HDR", + "DisplayTitle": "4K HEVC HDR", + "BitRate": 14715079, + "BitDepth": 8, + "RefFrames": 1, + "IsDefault": true, + "Height": 2160, + "Width": 3840, + "AverageFrameRate": 23.976, + "RealFrameRate": 23.976, + "Profile": "Main 10", + "Type": 1, + "AspectRatio": "16:9", + "PixelFormat": "yuv420p10le", + "Level": 150 + }, + { + "Codec": "truehd", + "CodecTag": "AC-3", + "Language": "eng", + "TimeBase": "1/48000", + "DisplayTitle": "TRUEHD - 7.1", + "ChannelLayout": "7.1", + "BitRate": 384000, + "Channels": 8, + "SampleRate": 48000, + "IsDefault": true, + "Index": 1, + "Score": 203 + }, + { + "Codec": "srt", + "Language": "eng", + "TimeBase": "1/1000000", + "localizedUndefined": "Undefined", + "localizedDefault": "Default", + "localizedForced": "Forced", + "DisplayTitle": "En - Default", + "BitRate": 92, + "IsDefault": true, + "Type": 2, + "Index": 2, + "Score": 6421, + "IsExternal": true, + "IsTextSubtitleStream": true, + "SupportsExternalStream": true, + "Path": "/Media/MyVideo-WEBDL-2160p.default.eng.srt" + } + ], + "Bitrate": 15201382, + "DefaultAudioStreamIndex": 1, + "DefaultSubtitleStreamIndex": 2 +} From 0ff37413b084b28efa5963406b0ed42abb85e3ae Mon Sep 17 00:00:00 2001 From: Dmitry Lyzo Date: Tue, 5 Apr 2022 00:30:26 +0300 Subject: [PATCH 3/3] fix: Fix transcode reasons Don't add codec failure reasons if the codec isn't supported. --- MediaBrowser.Model/Dlna/StreamBuilder.cs | 13 +++++++++- .../Dlna/StreamBuilderTests.cs | 24 +++++++++---------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 3fc7ff0a3b..ee9cfeeca8 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -1183,7 +1183,18 @@ namespace MediaBrowser.Model.Dlna audioCodecProfileReasons = audioStreamMatches.GetValueOrDefault(selectedAudioStream); } - var failureReasons = directPlayProfileReasons | containerProfileReasons | videoCodecProfileReasons | audioCodecProfileReasons | subtitleProfileReasons; + var failureReasons = directPlayProfileReasons | containerProfileReasons | subtitleProfileReasons; + + if ((failureReasons & TranscodeReason.VideoCodecNotSupported) == 0) + { + failureReasons |= videoCodecProfileReasons; + } + + if ((failureReasons & TranscodeReason.AudioCodecNotSupported) == 0) + { + failureReasons |= audioCodecProfileReasons; + } + var directStreamFailureReasons = failureReasons & (~DirectStreamReasons); PlayMethod? playMethod = null; diff --git a/tests/Jellyfin.Model.Tests/Dlna/StreamBuilderTests.cs b/tests/Jellyfin.Model.Tests/Dlna/StreamBuilderTests.cs index 013fffef03..0035dc6653 100644 --- a/tests/Jellyfin.Model.Tests/Dlna/StreamBuilderTests.cs +++ b/tests/Jellyfin.Model.Tests/Dlna/StreamBuilderTests.cs @@ -25,8 +25,8 @@ namespace Jellyfin.Model.Tests [InlineData("Chrome", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectPlay)] // #6450 [InlineData("Chrome", "mp4-h264-ac3-aacExt-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioIsExternal)] // #6450 [InlineData("Chrome", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 - [InlineData("Chrome", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode")] - [InlineData("Chrome", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode")] + [InlineData("Chrome", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")] + [InlineData("Chrome", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")] [InlineData("Chrome", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Chrome", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Chrome", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] // #6450 @@ -36,8 +36,8 @@ namespace Jellyfin.Model.Tests [InlineData("Firefox", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectPlay)] // #6450 [InlineData("Firefox", "mp4-h264-ac3-aacExt-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioIsExternal)] // #6450 [InlineData("Firefox", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 - [InlineData("Firefox", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode")] - [InlineData("Firefox", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode")] + [InlineData("Firefox", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")] + [InlineData("Firefox", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")] [InlineData("Firefox", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Firefox", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Firefox", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] // #6450 @@ -87,8 +87,8 @@ namespace Jellyfin.Model.Tests [InlineData("Chrome-NoHLS", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectPlay)] // #6450 [InlineData("Chrome-NoHLS", "mp4-h264-ac3-aacExt-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioIsExternal)] // #6450 [InlineData("Chrome-NoHLS", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 - [InlineData("Chrome-NoHLS", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode", "http")] - [InlineData("Chrome-NoHLS", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode", "http")] + [InlineData("Chrome-NoHLS", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode", "http")] + [InlineData("Chrome-NoHLS", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode", "http")] [InlineData("Chrome-NoHLS", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Chrome-NoHLS", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Chrome-NoHLS", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] // #6450 @@ -175,8 +175,8 @@ namespace Jellyfin.Model.Tests [InlineData("Chrome", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Chrome", "mp4-h264-ac3-aacExt-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Chrome", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 - [InlineData("Chrome", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode")] - [InlineData("Chrome", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode")] + [InlineData("Chrome", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")] + [InlineData("Chrome", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")] [InlineData("Chrome", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Chrome", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Chrome", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] // #6450 @@ -185,8 +185,8 @@ namespace Jellyfin.Model.Tests [InlineData("Firefox", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Firefox", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Firefox", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 - [InlineData("Firefox", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode")] - [InlineData("Firefox", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode")] + [InlineData("Firefox", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")] + [InlineData("Firefox", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")] [InlineData("Firefox", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Firefox", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 [InlineData("Firefox", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] // #6450 @@ -275,10 +275,10 @@ namespace Jellyfin.Model.Tests // Chrome [InlineData("Chrome", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay)] // #6450 [InlineData("Chrome", "mp4-h264-ac3-aacExt-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioIsExternal)] // #6450 - [InlineData("Chrome", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode")] + [InlineData("Chrome", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")] // Firefox [InlineData("Firefox", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay)] // #6450 - [InlineData("Firefox", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoLevelNotSupported, "Transcode")] + [InlineData("Firefox", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")] // Yatse [InlineData("Yatse", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] // #6450 [InlineData("Yatse", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectPlay, (TranscodeReason)0, "Remux")] // #6450