2022-01-10 02:53:15 +00:00
using System ;
2022-01-23 16:37:52 +00:00
using System.Collections.Specialized ;
2022-01-10 02:53:15 +00:00
using System.IO ;
using System.Linq ;
2022-01-23 23:49:14 +00:00
using System.Runtime.Serialization ;
2022-01-10 02:53:15 +00:00
using System.Text.Json ;
using System.Threading.Tasks ;
using Jellyfin.Extensions.Json ;
using MediaBrowser.Model.Dlna ;
using MediaBrowser.Model.Dto ;
using MediaBrowser.Model.Entities ;
using MediaBrowser.Model.Session ;
using Microsoft.Extensions.Logging.Abstractions ;
using Moq ;
using Xunit ;
namespace Jellyfin.MediaBrowser.Model.Tests
{
public class StreamBuilderTests
{
[Theory]
// Chrome
2022-01-23 23:49:14 +00:00
[InlineData("Chrome", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectPlay)] // #6450
[InlineData("Chrome", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay)] // #6450
[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
2022-01-23 16:37:52 +00:00
[InlineData("Chrome", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")]
2022-01-23 23:49:14 +00:00
[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.None, "Remux")] // #6450
2022-01-10 02:53:15 +00:00
// Firefox
2022-01-23 23:49:14 +00:00
[InlineData("Firefox", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectPlay)] // #6450
[InlineData("Firefox", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay)] // #6450
[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
2022-01-23 16:37:52 +00:00
[InlineData("Firefox", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")]
2022-01-23 23:49:14 +00:00
[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.None, "Remux")] // #6450
2022-01-10 02:53:15 +00:00
// Safari
2022-01-23 23:49:14 +00:00
[InlineData("SafariNext", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectPlay)] // #6450
[InlineData("SafariNext", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay)] // #6450
[InlineData("SafariNext", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectPlay)] // #6450
[InlineData("SafariNext", "mp4-h264-ac3-aacExt-srt-2600k", PlayMethod.DirectPlay)] // #6450
[InlineData("SafariNext", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectPlay)] // #6450
[InlineData("SafariNext", "mp4-hevc-aac-srt-15200k", PlayMethod.DirectPlay)] // #6450
[InlineData("SafariNext", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectPlay)] // #6450
[InlineData("SafariNext", "mp4-hevc-ac3-aacExt-srt-15200k", PlayMethod.DirectPlay)] // #6450
2022-01-10 02:53:15 +00:00
// AndroidPixel
2022-01-23 23:49:14 +00:00
[InlineData("AndroidPixel", "mp4-h264-aac-srt-2600k", PlayMethod.DirectPlay)] // #6450
[InlineData("AndroidPixel", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay)] // #6450
[InlineData("AndroidPixel", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectPlay)] // #6450
[InlineData("AndroidPixel", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectPlay)] // #6450
2022-01-23 16:37:52 +00:00
[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")]
2022-01-10 02:53:15 +00:00
// Yatse
2022-01-23 23:49:14 +00:00
[InlineData("Yatse", "mp4-h264-aac-srt-2600k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450
[InlineData("Yatse", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450
[InlineData("Yatse", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450
[InlineData("Yatse", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)]
[InlineData("Yatse", "mp4-hevc-aac-srt-15200k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450
[InlineData("Yatse", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450
2022-01-10 02:53:15 +00:00
// RokuSSPlus
2022-01-23 23:49:14 +00:00
[InlineData("RokuSSPlus", "mp4-h264-aac-srt-2600k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450
[InlineData("RokuSSPlus", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450 should be DirectPlay
[InlineData("RokuSSPlus", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450
[InlineData("RokuSSPlus", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
[InlineData("RokuSSPlus", "mp4-hevc-aac-srt-15200k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450
[InlineData("RokuSSPlus", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450
[InlineData("RokuSSPlus", "mp4-hevc-ac3-srt-15200k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
2022-01-10 02:53:15 +00:00
// JellyfinMediaPlayer
2022-01-23 23:49:14 +00:00
[InlineData("JellyfinMediaPlayer", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450
[InlineData("JellyfinMediaPlayer", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450
[InlineData("JellyfinMediaPlayer", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450
[InlineData("JellyfinMediaPlayer", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit, "Transcode")]
[InlineData("JellyfinMediaPlayer", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit, "Transcode")]
[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
// Chrome-NoHLS
[InlineData("Chrome-NoHLS", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectPlay)] // #6450
[InlineData("Chrome-NoHLS", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay)] // #6450
[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", "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.None, "Remux")] // #6450
2022-01-10 02:53:15 +00:00
// TranscodeMedia
2022-01-23 23:49:14 +00:00
[InlineData("TranscodeMedia", "mp4-h264-aac-vtt-2600k", PlayMethod.Transcode, TranscodeReason.DirectPlayError, "Transcode")]
[InlineData("TranscodeMedia", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.Transcode, TranscodeReason.DirectPlayError, "Transcode")]
[InlineData("TranscodeMedia", "mp4-h264-ac3-srt-2600k", PlayMethod.Transcode, TranscodeReason.DirectPlayError, "Transcode")]
[InlineData("TranscodeMedia", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.DirectPlayError, "Transcode")]
[InlineData("TranscodeMedia", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.DirectPlayError, "Transcode")]
[InlineData("TranscodeMedia", "mkv-vp9-aac-srt-2600k", PlayMethod.Transcode, TranscodeReason.DirectPlayError, "Transcode")]
[InlineData("TranscodeMedia", "mkv-vp9-ac3-srt-2600k", PlayMethod.Transcode, TranscodeReason.DirectPlayError, "Transcode")]
[InlineData("TranscodeMedia", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.Transcode, TranscodeReason.DirectPlayError, "Transcode")]
2022-01-10 02:53:15 +00:00
// DirectMedia
2022-01-23 23:49:14 +00:00
[InlineData("DirectMedia", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")]
[InlineData("DirectMedia", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")]
[InlineData("DirectMedia", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")]
[InlineData("DirectMedia", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")]
[InlineData("DirectMedia", "mp4-hevc-aac-srt-15200k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")]
[InlineData("DirectMedia", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")]
[InlineData("DirectMedia", "mkv-vp9-aac-srt-2600k", PlayMethod.DirectPlay)]
[InlineData("DirectMedia", "mkv-vp9-ac3-srt-2600k", PlayMethod.DirectPlay)]
[InlineData("DirectMedia", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.DirectPlay)]
2022-01-10 02:53:15 +00:00
// LowBandwidth
2022-01-23 23:49:14 +00:00
[InlineData("LowBandwidth", "mp4-h264-aac-vtt-2600k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit, "Transcode")]
[InlineData("LowBandwidth", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit, "Transcode")]
[InlineData("LowBandwidth", "mp4-h264-ac3-srt-2600k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit, "Transcode")]
[InlineData("LowBandwidth", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit, "Transcode")]
[InlineData("LowBandwidth", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit, "Transcode")]
[InlineData("LowBandwidth", "mkv-vp9-aac-srt-2600k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit, "Transcode")]
[InlineData("LowBandwidth", "mkv-vp9-ac3-srt-2600k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit, "Transcode")]
[InlineData("LowBandwidth", "mkv-vp9-vorbis-vtt-2600k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit, "Transcode")]
2022-01-10 02:53:15 +00:00
// Null
2022-01-23 23:49:14 +00:00
[InlineData("Null", "mp4-h264-aac-vtt-2600k", null, TranscodeReason.ContainerBitrateExceedsLimit)]
[InlineData("Null", "mp4-h264-ac3-aac-srt-2600k", null, TranscodeReason.ContainerBitrateExceedsLimit)]
[InlineData("Null", "mp4-h264-ac3-srt-2600k", null, TranscodeReason.ContainerBitrateExceedsLimit)]
[InlineData("Null", "mp4-hevc-aac-srt-15200k", null, TranscodeReason.ContainerBitrateExceedsLimit)]
[InlineData("Null", "mp4-hevc-ac3-aac-srt-15200k", null, TranscodeReason.ContainerBitrateExceedsLimit)]
[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)]
// [InlineData("Chrome", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported | TranscodeReason.AudioCodecNotSupported, "Transcode")]
2022-01-23 16:37:52 +00:00
public async Task BuildVideoItemSimple ( string deviceName , string mediaSource , PlayMethod ? playMethod , TranscodeReason why = TranscodeReason . None , string transcodeMode = "DirectStream" , string transcodeProtocol = "" )
2022-01-10 02:53:15 +00:00
{
var options = await GetVideoOptions ( deviceName , mediaSource ) ;
2022-01-23 16:37:52 +00:00
BuildVideoItemSimpleTest ( options , playMethod , why , transcodeMode , transcodeProtocol ) ;
}
[Theory]
// Chrome
2022-01-23 23:49:14 +00:00
[InlineData("Chrome", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectPlay)] // #6450
[InlineData("Chrome", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
[InlineData("Chrome", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 <BUG: this is direct played>
[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
2022-01-23 16:37:52 +00:00
[InlineData("Chrome", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")]
2022-01-23 23:49:14 +00:00
[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.None, "Remux")] // #6450
2022-01-23 16:37:52 +00:00
// Firefox
2022-01-23 23:49:14 +00:00
[InlineData("Firefox", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectPlay)] // #6450
[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
2022-01-23 16:37:52 +00:00
[InlineData("Firefox", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")]
2022-01-23 23:49:14 +00:00
[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.None, "Remux")] // #6450
2022-01-23 16:37:52 +00:00
// Safari
2022-01-23 23:49:14 +00:00
[InlineData("SafariNext", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectPlay)] // #6450
[InlineData("SafariNext", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay)] // #6450
[InlineData("SafariNext", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectPlay)] // #6450
[InlineData("SafariNext", "mp4-h264-ac3-aacExt-srt-2600k", PlayMethod.DirectPlay)] // #6450
[InlineData("SafariNext", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectPlay)] // #6450
[InlineData("SafariNext", "mp4-hevc-aac-srt-15200k", PlayMethod.DirectPlay)] // #6450
[InlineData("SafariNext", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectPlay)] // #6450
[InlineData("SafariNext", "mp4-hevc-ac3-aacExt-srt-15200k", PlayMethod.DirectPlay)] // #6450
2022-01-23 16:37:52 +00:00
// AndroidPixel
2022-01-23 23:49:14 +00:00
[InlineData("AndroidPixel", "mp4-h264-aac-srt-2600k", PlayMethod.DirectPlay)] // #6450
[InlineData("AndroidPixel", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectPlay)] // #6450
[InlineData("AndroidPixel", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectPlay)] // #6450
2022-01-23 16:37:52 +00:00
[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
2022-01-23 23:49:14 +00:00
[InlineData("Yatse", "mp4-h264-aac-srt-2600k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450
[InlineData("Yatse", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
[InlineData("Yatse", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
[InlineData("Yatse", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)]
[InlineData("Yatse", "mp4-hevc-aac-srt-15200k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450
[InlineData("Yatse", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
2022-01-23 16:37:52 +00:00
// RokuSSPlus
2022-01-23 23:49:14 +00:00
[InlineData("RokuSSPlus", "mp4-h264-aac-srt-2600k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450
[InlineData("RokuSSPlus", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450 should be DirectPlay
[InlineData("RokuSSPlus", "mp4-h264-ac3-aacDef-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
[InlineData("RokuSSPlus", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
[InlineData("RokuSSPlus", "mp4-hevc-aac-srt-15200k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450
[InlineData("RokuSSPlus", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
[InlineData("RokuSSPlus", "mp4-hevc-ac3-srt-15200k", PlayMethod.DirectStream, TranscodeReason.AudioCodecNotSupported)] // #6450
2022-01-23 16:37:52 +00:00
// JellyfinMediaPlayer
2022-01-23 23:49:14 +00:00
[InlineData("JellyfinMediaPlayer", "mp4-h264-aac-vtt-2600k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450
[InlineData("JellyfinMediaPlayer", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450
[InlineData("JellyfinMediaPlayer", "mp4-h264-ac3-srt-2600k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450
[InlineData("JellyfinMediaPlayer", "mp4-hevc-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit, "Transcode")] // #6450
[InlineData("JellyfinMediaPlayer", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.ContainerBitrateExceedsLimit, "Transcode")] // #6450
[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
public async Task BuildVideoItemWithFirstExplicitStream ( string deviceName , string mediaSource , PlayMethod ? playMethod , TranscodeReason why = TranscodeReason . None , string transcodeMode = "DirectStream" , string transcodeProtocol = "" )
2022-01-23 16:37:52 +00:00
{
var options = await GetVideoOptions ( deviceName , mediaSource ) ;
options . AudioStreamIndex = 1 ;
2022-01-23 23:49:14 +00:00
options . SubtitleStreamIndex = options . MediaSources [ 0 ] . MediaStreams . Count - 1 ;
var streamInfo = BuildVideoItemSimpleTest ( options , playMethod , why , transcodeMode , transcodeProtocol ) ;
Assert . Equal ( streamInfo ? . AudioStreamIndex , options . AudioStreamIndex ) ;
Assert . Equal ( streamInfo ? . SubtitleStreamIndex , options . SubtitleStreamIndex ) ;
2022-01-23 16:37:52 +00:00
}
[Theory]
// Chrome
2022-01-23 23:49:14 +00:00
[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")]
2022-01-23 16:37:52 +00:00
// Firefox
2022-01-23 23:49:14 +00:00
[InlineData("Firefox", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay)] // #6450
[InlineData("Firefox", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.Transcode, TranscodeReason.VideoCodecNotSupported, "Transcode")]
2022-01-23 16:37:52 +00:00
// Yatse
2022-01-23 23:49:14 +00:00
[InlineData("Yatse", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450
[InlineData("Yatse", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450
2022-01-23 16:37:52 +00:00
// RokuSSPlus
2022-01-23 23:49:14 +00:00
[InlineData("RokuSSPlus", "mp4-h264-ac3-aac-srt-2600k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450
[InlineData("RokuSSPlus", "mp4-hevc-ac3-aac-srt-15200k", PlayMethod.DirectPlay, TranscodeReason.None, "Remux")] // #6450
public async Task BuildVideoItemWithDirectPlayExplicitStreams ( string deviceName , string mediaSource , PlayMethod ? playMethod , TranscodeReason why = TranscodeReason . None , string transcodeMode = "DirectStream" , string transcodeProtocol = "" )
2022-01-23 16:37:52 +00:00
{
var options = await GetVideoOptions ( deviceName , mediaSource ) ;
2022-01-23 23:49:14 +00:00
var streamCount = options . MediaSources [ 0 ] . MediaStreams . Count ;
2022-01-23 16:37:52 +00:00
options . AudioStreamIndex = streamCount - 2 ;
options . SubtitleStreamIndex = streamCount - 1 ;
2022-01-23 23:49:14 +00:00
var streamInfo = BuildVideoItemSimpleTest ( options , playMethod , why , transcodeMode , transcodeProtocol ) ;
Assert . Equal ( streamInfo ? . AudioStreamIndex , options . AudioStreamIndex ) ;
Assert . Equal ( streamInfo ? . SubtitleStreamIndex , options . SubtitleStreamIndex ) ;
2022-01-23 16:37:52 +00:00
}
2022-01-23 23:49:14 +00:00
private StreamInfo ? BuildVideoItemSimpleTest ( VideoOptions options , PlayMethod ? playMethod , TranscodeReason why , string transcodeMode , string transcodeProtocol )
2022-01-23 16:37:52 +00:00
{
if ( string . IsNullOrEmpty ( transcodeProtocol ) )
{
transcodeProtocol = playMethod = = PlayMethod . DirectStream ? "http" : "hls" ;
}
var builder = GetStreamBuilder ( ) ;
2022-01-10 02:53:15 +00:00
var val = builder . BuildVideoItem ( options ) ;
Assert . NotNull ( val ) ;
if ( playMethod ! = null )
{
Assert . Equal ( playMethod , val . PlayMethod ) ;
}
2022-01-23 16:37:52 +00:00
Assert . Equal ( why , val . TranscodeReasons ) ;
var audioStreamIndexInput = options . AudioStreamIndex ;
var targetVideoStream = val . TargetVideoStream ;
var targetAudioStream = val . TargetAudioStream ;
2022-01-10 02:53:15 +00:00
2022-01-23 16:37:52 +00:00
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 ) ;
2022-01-10 02:53:15 +00:00
if ( playMethod = = PlayMethod . DirectPlay )
{
2022-01-23 16:37:52 +00:00
// check expected container
var containers = ContainerProfile . SplitValue ( mediaSource . Container ) ;
2022-01-23 23:49:14 +00:00
// TODO: test transcode too
// Assert.Contains(uri.Extension, containers);
2022-01-10 02:53:15 +00:00
2022-01-23 16:37:52 +00:00
// check expected video codec (1)
Assert . Contains ( targetVideoStream . Codec , val . TargetVideoCodec ) ;
Assert . Single ( val . TargetVideoCodec ) ;
// check expected audio codecs (1)
Assert . Contains ( targetAudioStream . Codec , val . TargetAudioCodec ) ;
2022-01-23 23:49:14 +00:00
Assert . Single ( val . TargetAudioCodec ) ;
// Assert.Single(val.AudioCodecs);
2022-01-10 02:53:15 +00:00
2022-01-23 23:49:14 +00:00
if ( transcodeMode = = "DirectStream" )
{
Assert . Equal ( val . Container , uri . Extension ) ;
}
2022-01-23 16:37:52 +00:00
}
else if ( playMethod = = PlayMethod . DirectStream | | playMethod = = PlayMethod . Transcode )
2022-01-10 02:53:15 +00:00
{
2022-01-23 16:37:52 +00:00
Assert . NotNull ( val . Container ) ;
2022-01-23 23:49:14 +00:00
Assert . NotEmpty ( val . VideoCodecs ) ;
Assert . NotEmpty ( val . AudioCodecs ) ;
2022-01-23 16:37:52 +00:00
// check expected container (todo: this could be a test param)
if ( transcodeProtocol = = "http" )
2022-01-10 02:53:15 +00:00
{
2022-01-23 16:37:52 +00:00
// Assert.Equal("webm", val.Container);
Assert . Equal ( val . Container , uri . Extension ) ;
Assert . Equal ( "stream" , uri . Filename ) ;
2022-01-23 23:49:14 +00:00
Assert . Equal ( "http" , val . SubProtocol ) ;
2022-01-23 16:37:52 +00:00
}
else
{
Assert . Equal ( "ts" , val . Container ) ;
Assert . Equal ( "m3u8" , uri . Extension ) ;
Assert . Equal ( "master" , uri . Filename ) ;
2022-01-10 02:53:15 +00:00
Assert . Equal ( "hls" , val . SubProtocol ) ;
2022-01-23 16:37:52 +00:00
}
// Full transcode
if ( transcodeMode = = "Transcode" )
{
2022-01-23 23:49:14 +00:00
if ( ( val . TranscodeReasons & ( StreamBuilder . ContainerReasons | TranscodeReason . DirectPlayError ) ) = = TranscodeReason . None )
2022-01-23 16:37:52 +00:00
{
2022-01-23 23:49:14 +00:00
Assert . All (
videoStreams ,
stream = > Assert . DoesNotContain ( stream . Codec , val . VideoCodecs ) ) ;
2022-01-23 16:37:52 +00:00
}
2022-01-10 02:53:15 +00:00
2022-01-23 16:37:52 +00:00
// todo: fill out tests here
2022-01-10 02:53:15 +00:00
}
2022-01-23 16:37:52 +00:00
// DirectStream and Remux
2022-01-10 02:53:15 +00:00
else
{
2022-01-23 16:37:52 +00:00
// check expected video codec (1)
Assert . Contains ( targetVideoStream . Codec , val . TargetVideoCodec ) ;
Assert . Single ( val . TargetVideoCodec ) ;
2022-01-10 02:53:15 +00:00
2022-01-23 16:37:52 +00:00
if ( transcodeMode = = "DirectStream" )
{
if ( ! targetAudioStream . IsExternal )
{
// check expected audio codecs (1)
2022-01-23 23:49:14 +00:00
Assert . DoesNotContain ( targetAudioStream . Codec , val . AudioCodecs ) ;
2022-01-23 16:37:52 +00:00
}
}
else if ( transcodeMode = = "Remux" )
{
// check expected audio codecs (1)
Assert . Contains ( targetAudioStream . Codec , val . AudioCodecs ) ;
Assert . Single ( val . AudioCodecs ) ;
}
2022-01-10 02:53:15 +00:00
2022-01-23 16:37:52 +00:00
// video details
var videoStream = targetVideoStream ;
2022-01-10 02:53:15 +00:00
Assert . False ( val . EstimateContentLength ) ;
Assert . Equal ( TranscodeSeekInfo . Auto , val . TranscodeSeekInfo ) ;
2022-01-23 23:49:14 +00:00
Assert . Contains ( videoStream . Profile ? . ToLowerInvariant ( ) ? ? string . Empty , val . TargetVideoProfile ? . Split ( "," ) . Select ( s = > s . ToLowerInvariant ( ) ) ? ? Array . Empty < string > ( ) ) ;
Assert . Equal ( videoStream . Level , val . TargetVideoLevel ) ;
Assert . Equal ( videoStream . BitDepth , val . TargetVideoBitDepth ) ;
Assert . InRange ( val . VideoBitrate . GetValueOrDefault ( ) , videoStream . BitRate . GetValueOrDefault ( ) , int . MaxValue ) ;
2022-01-23 16:37:52 +00:00
// 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 )
{
2022-01-23 23:49:14 +00:00
Assert . DoesNotContain ( stream . Codec , val . AudioCodecs ) ;
2022-01-23 16:37:52 +00:00
}
} ) ;
}
}
2022-01-10 02:53:15 +00:00
}
}
2022-01-23 23:49:14 +00:00
else if ( playMethod = = null )
2022-01-10 02:53:15 +00:00
{
Assert . Null ( val . SubProtocol ) ;
2022-01-23 23:49:14 +00:00
Assert . Equal ( "stream" , uri . Filename ) ;
2022-01-10 02:53:15 +00:00
Assert . False ( val . EstimateContentLength ) ;
Assert . Equal ( TranscodeSeekInfo . Auto , val . TranscodeSeekInfo ) ;
}
2022-01-23 23:49:14 +00:00
return val ;
2022-01-10 02:53:15 +00:00
}
private static async ValueTask < T > TestData < T > ( string name )
{
var path = Path . Join ( "Test Data" , typeof ( T ) . Name + "-" + name + ".json" ) ;
using ( var stream = File . OpenRead ( path ) )
{
var value = await JsonSerializer . DeserializeAsync < T > ( stream , JsonDefaults . Options ) ;
if ( value ! = null )
{
return value ;
}
2022-01-23 23:49:14 +00:00
throw new SerializationException ( "Invalid test data: " + name ) ;
2022-01-10 02:53:15 +00:00
}
}
private StreamBuilder GetStreamBuilder ( )
{
var transcodeSupport = new Mock < ITranscoderSupport > ( ) ;
var logger = new NullLogger < StreamBuilderTests > ( ) ;
return new StreamBuilder ( transcodeSupport . Object , logger ) ;
}
private static async ValueTask < VideoOptions > GetVideoOptions ( string deviceProfile , params string [ ] sources )
{
var mediaSources = sources . Select ( src = > TestData < MediaSourceInfo > ( src ) )
. Select ( val = > val . Result )
. ToArray ( ) ;
var mediaSourceId = mediaSources [ 0 ] ? . Id ;
var dp = await TestData < DeviceProfile > ( deviceProfile ) ;
return new VideoOptions ( )
{
ItemId = new Guid ( "11D229B7-2D48-4B95-9F9B-49F6AB75E613" ) ,
MediaSourceId = mediaSourceId ,
MediaSources = mediaSources ,
DeviceId = "test-deviceId" ,
Profile = dp ,
2022-01-23 23:49:14 +00:00
AllowAudioStreamCopy = true ,
AllowVideoStreamCopy = true ,
2022-01-10 02:53:15 +00:00
} ;
}
2022-01-23 16:37:52 +00:00
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 ) ;
}
2022-01-10 02:53:15 +00:00
}
}