diff --git a/.github/workflows/repo-stale.yaml b/.github/workflows/repo-stale.yaml index 897b7014ac..7f6fcffed5 100644 --- a/.github/workflows/repo-stale.yaml +++ b/.github/workflows/repo-stale.yaml @@ -19,6 +19,7 @@ jobs: days-before-pr-stale: -1 days-before-close: 21 days-before-pr-close: -1 + operations-per-run: 75 exempt-issue-labels: regression,security,roadmap,future,feature,enhancement,confirmed stale-issue-label: stale stale-issue-message: |- diff --git a/DvdLib/BigEndianBinaryReader.cs b/DvdLib/BigEndianBinaryReader.cs deleted file mode 100644 index b3aad85cec..0000000000 --- a/DvdLib/BigEndianBinaryReader.cs +++ /dev/null @@ -1,25 +0,0 @@ -#pragma warning disable CS1591 - -using System.Buffers.Binary; -using System.IO; - -namespace DvdLib -{ - public class BigEndianBinaryReader : BinaryReader - { - public BigEndianBinaryReader(Stream input) - : base(input) - { - } - - public override ushort ReadUInt16() - { - return BinaryPrimitives.ReadUInt16BigEndian(base.ReadBytes(2)); - } - - public override uint ReadUInt32() - { - return BinaryPrimitives.ReadUInt32BigEndian(base.ReadBytes(4)); - } - } -} diff --git a/DvdLib/DvdLib.csproj b/DvdLib/DvdLib.csproj deleted file mode 100644 index 1053c0089f..0000000000 --- a/DvdLib/DvdLib.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - {713F42B5-878E-499D-A878-E4C652B1D5E8} - - - - - - - - net7.0 - false - true - AllDisabledByDefault - disable - - - diff --git a/DvdLib/Ifo/Cell.cs b/DvdLib/Ifo/Cell.cs deleted file mode 100644 index ea0b50e430..0000000000 --- a/DvdLib/Ifo/Cell.cs +++ /dev/null @@ -1,23 +0,0 @@ -#pragma warning disable CS1591 - -using System.IO; - -namespace DvdLib.Ifo -{ - public class Cell - { - public CellPlaybackInfo PlaybackInfo { get; private set; } - - public CellPositionInfo PositionInfo { get; private set; } - - internal void ParsePlayback(BinaryReader br) - { - PlaybackInfo = new CellPlaybackInfo(br); - } - - internal void ParsePosition(BinaryReader br) - { - PositionInfo = new CellPositionInfo(br); - } - } -} diff --git a/DvdLib/Ifo/CellPlaybackInfo.cs b/DvdLib/Ifo/CellPlaybackInfo.cs deleted file mode 100644 index 6e33a0ec5a..0000000000 --- a/DvdLib/Ifo/CellPlaybackInfo.cs +++ /dev/null @@ -1,52 +0,0 @@ -#pragma warning disable CS1591 - -using System.IO; - -namespace DvdLib.Ifo -{ - public enum BlockMode - { - NotInBlock = 0, - FirstCell = 1, - InBlock = 2, - LastCell = 3, - } - - public enum BlockType - { - Normal = 0, - Angle = 1, - } - - public enum PlaybackMode - { - Normal = 0, - StillAfterEachVOBU = 1, - } - - public class CellPlaybackInfo - { - public readonly BlockMode Mode; - public readonly BlockType Type; - public readonly bool SeamlessPlay; - public readonly bool Interleaved; - public readonly bool STCDiscontinuity; - public readonly bool SeamlessAngle; - public readonly PlaybackMode PlaybackMode; - public readonly bool Restricted; - public readonly byte StillTime; - public readonly byte CommandNumber; - public readonly DvdTime PlaybackTime; - public readonly uint FirstSector; - public readonly uint FirstILVUEndSector; - public readonly uint LastVOBUStartSector; - public readonly uint LastSector; - - internal CellPlaybackInfo(BinaryReader br) - { - br.BaseStream.Seek(0x4, SeekOrigin.Current); - PlaybackTime = new DvdTime(br.ReadBytes(4)); - br.BaseStream.Seek(0x10, SeekOrigin.Current); - } - } -} diff --git a/DvdLib/Ifo/CellPositionInfo.cs b/DvdLib/Ifo/CellPositionInfo.cs deleted file mode 100644 index 216aa0f77a..0000000000 --- a/DvdLib/Ifo/CellPositionInfo.cs +++ /dev/null @@ -1,19 +0,0 @@ -#pragma warning disable CS1591 - -using System.IO; - -namespace DvdLib.Ifo -{ - public class CellPositionInfo - { - public readonly ushort VOBId; - public readonly byte CellId; - - internal CellPositionInfo(BinaryReader br) - { - VOBId = br.ReadUInt16(); - br.ReadByte(); - CellId = br.ReadByte(); - } - } -} diff --git a/DvdLib/Ifo/Chapter.cs b/DvdLib/Ifo/Chapter.cs deleted file mode 100644 index e786cb5536..0000000000 --- a/DvdLib/Ifo/Chapter.cs +++ /dev/null @@ -1,20 +0,0 @@ -#pragma warning disable CS1591 - -namespace DvdLib.Ifo -{ - public class Chapter - { - public ushort ProgramChainNumber { get; private set; } - - public ushort ProgramNumber { get; private set; } - - public uint ChapterNumber { get; private set; } - - public Chapter(ushort pgcNum, ushort programNum, uint chapterNum) - { - ProgramChainNumber = pgcNum; - ProgramNumber = programNum; - ChapterNumber = chapterNum; - } - } -} diff --git a/DvdLib/Ifo/Dvd.cs b/DvdLib/Ifo/Dvd.cs deleted file mode 100644 index 7f8ece47dc..0000000000 --- a/DvdLib/Ifo/Dvd.cs +++ /dev/null @@ -1,167 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; - -namespace DvdLib.Ifo -{ - public class Dvd - { - private readonly ushort _titleSetCount; - public readonly List Titles; - - private ushort _titleCount; - public readonly Dictionary<ushort, string> VTSPaths = new Dictionary<ushort, string>(); - public Dvd(string path) - { - Titles = new List<Title>(); - var allFiles = new DirectoryInfo(path).GetFiles(path, SearchOption.AllDirectories); - - var vmgPath = allFiles.FirstOrDefault(i => string.Equals(i.Name, "VIDEO_TS.IFO", StringComparison.OrdinalIgnoreCase)) ?? - allFiles.FirstOrDefault(i => string.Equals(i.Name, "VIDEO_TS.BUP", StringComparison.OrdinalIgnoreCase)); - - if (vmgPath == null) - { - foreach (var ifo in allFiles) - { - if (!string.Equals(ifo.Extension, ".ifo", StringComparison.OrdinalIgnoreCase)) - { - continue; - } - - var nums = ifo.Name.Split('_', StringSplitOptions.RemoveEmptyEntries); - if (nums.Length >= 2 && ushort.TryParse(nums[1], out var ifoNumber)) - { - ReadVTS(ifoNumber, ifo.FullName); - } - } - } - else - { - using (var vmgFs = new FileStream(vmgPath.FullName, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - using (var vmgRead = new BigEndianBinaryReader(vmgFs)) - { - vmgFs.Seek(0x3E, SeekOrigin.Begin); - _titleSetCount = vmgRead.ReadUInt16(); - - // read address of TT_SRPT - vmgFs.Seek(0xC4, SeekOrigin.Begin); - uint ttSectorPtr = vmgRead.ReadUInt32(); - vmgFs.Seek(ttSectorPtr * 2048, SeekOrigin.Begin); - ReadTT_SRPT(vmgRead); - } - } - - for (ushort titleSetNum = 1; titleSetNum <= _titleSetCount; titleSetNum++) - { - ReadVTS(titleSetNum, allFiles); - } - } - } - - private void ReadTT_SRPT(BinaryReader read) - { - _titleCount = read.ReadUInt16(); - read.BaseStream.Seek(6, SeekOrigin.Current); - for (uint titleNum = 1; titleNum <= _titleCount; titleNum++) - { - var t = new Title(titleNum); - t.ParseTT_SRPT(read); - Titles.Add(t); - } - } - - private void ReadVTS(ushort vtsNum, IReadOnlyList<FileInfo> allFiles) - { - var filename = string.Format(CultureInfo.InvariantCulture, "VTS_{0:00}_0.IFO", vtsNum); - - var vtsPath = allFiles.FirstOrDefault(i => string.Equals(i.Name, filename, StringComparison.OrdinalIgnoreCase)) ?? - allFiles.FirstOrDefault(i => string.Equals(i.Name, Path.ChangeExtension(filename, ".bup"), StringComparison.OrdinalIgnoreCase)); - - if (vtsPath == null) - { - throw new FileNotFoundException("Unable to find VTS IFO file"); - } - - ReadVTS(vtsNum, vtsPath.FullName); - } - - private void ReadVTS(ushort vtsNum, string vtsPath) - { - VTSPaths[vtsNum] = vtsPath; - - using (var vtsFs = new FileStream(vtsPath, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - using (var vtsRead = new BigEndianBinaryReader(vtsFs)) - { - // Read VTS_PTT_SRPT - vtsFs.Seek(0xC8, SeekOrigin.Begin); - uint vtsPttSrptSecPtr = vtsRead.ReadUInt32(); - uint baseAddr = (vtsPttSrptSecPtr * 2048); - vtsFs.Seek(baseAddr, SeekOrigin.Begin); - - ushort numTitles = vtsRead.ReadUInt16(); - vtsRead.ReadUInt16(); - uint endaddr = vtsRead.ReadUInt32(); - uint[] offsets = new uint[numTitles]; - for (ushort titleNum = 0; titleNum < numTitles; titleNum++) - { - offsets[titleNum] = vtsRead.ReadUInt32(); - } - - for (uint titleNum = 0; titleNum < numTitles; titleNum++) - { - uint chapNum = 1; - vtsFs.Seek(baseAddr + offsets[titleNum], SeekOrigin.Begin); - var t = Titles.FirstOrDefault(vtst => vtst.IsVTSTitle(vtsNum, titleNum + 1)); - if (t == null) - { - continue; - } - - do - { - t.Chapters.Add(new Chapter(vtsRead.ReadUInt16(), vtsRead.ReadUInt16(), chapNum)); - if (titleNum + 1 < numTitles && vtsFs.Position == (baseAddr + offsets[titleNum + 1])) - { - break; - } - - chapNum++; - } - while (vtsFs.Position < (baseAddr + endaddr)); - } - - // Read VTS_PGCI - vtsFs.Seek(0xCC, SeekOrigin.Begin); - uint vtsPgciSecPtr = vtsRead.ReadUInt32(); - vtsFs.Seek(vtsPgciSecPtr * 2048, SeekOrigin.Begin); - - long startByte = vtsFs.Position; - - ushort numPgcs = vtsRead.ReadUInt16(); - vtsFs.Seek(6, SeekOrigin.Current); - for (ushort pgcNum = 1; pgcNum <= numPgcs; pgcNum++) - { - byte pgcCat = vtsRead.ReadByte(); - bool entryPgc = (pgcCat & 0x80) != 0; - uint titleNum = (uint)(pgcCat & 0x7F); - - vtsFs.Seek(3, SeekOrigin.Current); - uint vtsPgcOffset = vtsRead.ReadUInt32(); - - var t = Titles.FirstOrDefault(vtst => vtst.IsVTSTitle(vtsNum, titleNum)); - if (t != null) - { - t.AddPgc(vtsRead, startByte + vtsPgcOffset, entryPgc, pgcNum); - } - } - } - } - } - } -} diff --git a/DvdLib/Ifo/DvdTime.cs b/DvdLib/Ifo/DvdTime.cs deleted file mode 100644 index d231406106..0000000000 --- a/DvdLib/Ifo/DvdTime.cs +++ /dev/null @@ -1,39 +0,0 @@ -#pragma warning disable CS1591 - -using System; - -namespace DvdLib.Ifo -{ - public class DvdTime - { - public readonly byte Hour, Minute, Second, Frames, FrameRate; - - public DvdTime(byte[] data) - { - Hour = GetBCDValue(data[0]); - Minute = GetBCDValue(data[1]); - Second = GetBCDValue(data[2]); - Frames = GetBCDValue((byte)(data[3] & 0x3F)); - - if ((data[3] & 0x80) != 0) - { - FrameRate = 30; - } - else if ((data[3] & 0x40) != 0) - { - FrameRate = 25; - } - } - - private static byte GetBCDValue(byte data) - { - return (byte)((((data & 0xF0) >> 4) * 10) + (data & 0x0F)); - } - - public static explicit operator TimeSpan(DvdTime time) - { - int ms = (int)(((1.0 / (double)time.FrameRate) * time.Frames) * 1000.0); - return new TimeSpan(0, time.Hour, time.Minute, time.Second, ms); - } - } -} diff --git a/DvdLib/Ifo/Program.cs b/DvdLib/Ifo/Program.cs deleted file mode 100644 index 3d94fa7dc1..0000000000 --- a/DvdLib/Ifo/Program.cs +++ /dev/null @@ -1,16 +0,0 @@ -#pragma warning disable CS1591 - -using System.Collections.Generic; - -namespace DvdLib.Ifo -{ - public class Program - { - public IReadOnlyList<Cell> Cells { get; } - - public Program(List<Cell> cells) - { - Cells = cells; - } - } -} diff --git a/DvdLib/Ifo/ProgramChain.cs b/DvdLib/Ifo/ProgramChain.cs deleted file mode 100644 index 83c0051b90..0000000000 --- a/DvdLib/Ifo/ProgramChain.cs +++ /dev/null @@ -1,121 +0,0 @@ -#pragma warning disable CS1591 - -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace DvdLib.Ifo -{ - public enum ProgramPlaybackMode - { - Sequential, - Random, - Shuffle - } - - public class ProgramChain - { - private byte _programCount; - public readonly List<Program> Programs; - - private byte _cellCount; - public readonly List<Cell> Cells; - - public DvdTime PlaybackTime { get; private set; } - - public UserOperation ProhibitedUserOperations { get; private set; } - - public byte[] AudioStreamControl { get; private set; } // 8*2 entries - public byte[] SubpictureStreamControl { get; private set; } // 32*4 entries - - private ushort _nextProgramNumber; - - private ushort _prevProgramNumber; - - private ushort _goupProgramNumber; - - public ProgramPlaybackMode PlaybackMode { get; private set; } - - public uint ProgramCount { get; private set; } - - public byte StillTime { get; private set; } - - public byte[] Palette { get; private set; } // 16*4 entries - - private ushort _commandTableOffset; - - private ushort _programMapOffset; - private ushort _cellPlaybackOffset; - private ushort _cellPositionOffset; - - public readonly uint VideoTitleSetIndex; - - internal ProgramChain(uint vtsPgcNum) - { - VideoTitleSetIndex = vtsPgcNum; - Cells = new List<Cell>(); - Programs = new List<Program>(); - } - - internal void ParseHeader(BinaryReader br) - { - long startPos = br.BaseStream.Position; - - br.ReadUInt16(); - _programCount = br.ReadByte(); - _cellCount = br.ReadByte(); - PlaybackTime = new DvdTime(br.ReadBytes(4)); - ProhibitedUserOperations = (UserOperation)br.ReadUInt32(); - AudioStreamControl = br.ReadBytes(16); - SubpictureStreamControl = br.ReadBytes(128); - - _nextProgramNumber = br.ReadUInt16(); - _prevProgramNumber = br.ReadUInt16(); - _goupProgramNumber = br.ReadUInt16(); - - StillTime = br.ReadByte(); - byte pbMode = br.ReadByte(); - if (pbMode == 0) - { - PlaybackMode = ProgramPlaybackMode.Sequential; - } - else - { - PlaybackMode = ((pbMode & 0x80) == 0) ? ProgramPlaybackMode.Random : ProgramPlaybackMode.Shuffle; - } - - ProgramCount = (uint)(pbMode & 0x7F); - - Palette = br.ReadBytes(64); - _commandTableOffset = br.ReadUInt16(); - _programMapOffset = br.ReadUInt16(); - _cellPlaybackOffset = br.ReadUInt16(); - _cellPositionOffset = br.ReadUInt16(); - - // read position info - br.BaseStream.Seek(startPos + _cellPositionOffset, SeekOrigin.Begin); - for (int cellNum = 0; cellNum < _cellCount; cellNum++) - { - var c = new Cell(); - c.ParsePosition(br); - Cells.Add(c); - } - - br.BaseStream.Seek(startPos + _cellPlaybackOffset, SeekOrigin.Begin); - for (int cellNum = 0; cellNum < _cellCount; cellNum++) - { - Cells[cellNum].ParsePlayback(br); - } - - br.BaseStream.Seek(startPos + _programMapOffset, SeekOrigin.Begin); - var cellNumbers = new List<int>(); - for (int progNum = 0; progNum < _programCount; progNum++) cellNumbers.Add(br.ReadByte() - 1); - - for (int i = 0; i < cellNumbers.Count; i++) - { - int max = (i + 1 == cellNumbers.Count) ? _cellCount : cellNumbers[i + 1]; - Programs.Add(new Program(Cells.Where((c, idx) => idx >= cellNumbers[i] && idx < max).ToList())); - } - } - } -} diff --git a/DvdLib/Ifo/Title.cs b/DvdLib/Ifo/Title.cs deleted file mode 100644 index 29a0b95c72..0000000000 --- a/DvdLib/Ifo/Title.cs +++ /dev/null @@ -1,70 +0,0 @@ -#pragma warning disable CS1591 - -using System.Collections.Generic; -using System.IO; - -namespace DvdLib.Ifo -{ - public class Title - { - public uint TitleNumber { get; private set; } - - public uint AngleCount { get; private set; } - - public ushort ChapterCount { get; private set; } - - public byte VideoTitleSetNumber { get; private set; } - - private ushort _parentalManagementMask; - private byte _titleNumberInVTS; - private uint _vtsStartSector; // relative to start of entire disk - - public ProgramChain EntryProgramChain { get; private set; } - - public readonly List<ProgramChain> ProgramChains; - - public readonly List<Chapter> Chapters; - - public Title(uint titleNum) - { - ProgramChains = new List<ProgramChain>(); - Chapters = new List<Chapter>(); - Chapters = new List<Chapter>(); - TitleNumber = titleNum; - } - - public bool IsVTSTitle(uint vtsNum, uint vtsTitleNum) - { - return (vtsNum == VideoTitleSetNumber && vtsTitleNum == _titleNumberInVTS); - } - - internal void ParseTT_SRPT(BinaryReader br) - { - byte titleType = br.ReadByte(); - // TODO parse Title Type - - AngleCount = br.ReadByte(); - ChapterCount = br.ReadUInt16(); - _parentalManagementMask = br.ReadUInt16(); - VideoTitleSetNumber = br.ReadByte(); - _titleNumberInVTS = br.ReadByte(); - _vtsStartSector = br.ReadUInt32(); - } - - internal void AddPgc(BinaryReader br, long startByte, bool entryPgc, uint pgcNum) - { - long curPos = br.BaseStream.Position; - br.BaseStream.Seek(startByte, SeekOrigin.Begin); - - var pgc = new ProgramChain(pgcNum); - pgc.ParseHeader(br); - ProgramChains.Add(pgc); - if (entryPgc) - { - EntryProgramChain = pgc; - } - - br.BaseStream.Seek(curPos, SeekOrigin.Begin); - } - } -} diff --git a/DvdLib/Ifo/UserOperation.cs b/DvdLib/Ifo/UserOperation.cs deleted file mode 100644 index 5d111ebc06..0000000000 --- a/DvdLib/Ifo/UserOperation.cs +++ /dev/null @@ -1,37 +0,0 @@ -#pragma warning disable CS1591 - -using System; - -namespace DvdLib.Ifo -{ - [Flags] - public enum UserOperation - { - None = 0, - TitleOrTimePlay = 1, - ChapterSearchOrPlay = 2, - TitlePlay = 4, - Stop = 8, - GoUp = 16, - TimeOrChapterSearch = 32, - PrevOrTopProgramSearch = 64, - NextProgramSearch = 128, - ForwardScan = 256, - BackwardScan = 512, - TitleMenuCall = 1024, - RootMenuCall = 2048, - SubpictureMenuCall = 4096, - AudioMenuCall = 8192, - AngleMenuCall = 16384, - ChapterMenuCall = 32768, - Resume = 65536, - ButtonSelectOrActive = 131072, - StillOff = 262144, - PauseOn = 524288, - AudioStreamChange = 1048576, - SubpictureStreamChange = 2097152, - AngleChange = 4194304, - KaraokeAudioPresentationModeChange = 8388608, - VideoPresentationModeChange = 16777216, - } -} diff --git a/DvdLib/Properties/AssemblyInfo.cs b/DvdLib/Properties/AssemblyInfo.cs deleted file mode 100644 index 6acd571d68..0000000000 --- a/DvdLib/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Reflection; -using System.Resources; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("DvdLib")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: NeutralResourcesLanguage("en")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index e1e83621b1..fc7d0242d7 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -83,13 +83,11 @@ using MediaBrowser.Controller.Subtitles; using MediaBrowser.Controller.SyncPlay; using MediaBrowser.Controller.TV; using MediaBrowser.LocalMetadata.Savers; -using MediaBrowser.MediaEncoding.BdInfo; using MediaBrowser.MediaEncoding.Subtitles; using MediaBrowser.Model.Cryptography; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; -using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Net; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.System; @@ -562,8 +560,6 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton<ILocalizationManager, LocalizationManager>(); - serviceCollection.AddSingleton<IBlurayExaminer, BdInfoExaminer>(); - serviceCollection.AddSingleton<IUserDataRepository, SqliteUserDataRepository>(); serviceCollection.AddSingleton<IUserDataManager, UserDataManager>(); diff --git a/Emby.Server.Implementations/Localization/Core/bg-BG.json b/Emby.Server.Implementations/Localization/Core/bg-BG.json index 64cb36fd82..13b99cc997 100644 --- a/Emby.Server.Implementations/Localization/Core/bg-BG.json +++ b/Emby.Server.Implementations/Localization/Core/bg-BG.json @@ -123,5 +123,6 @@ "TaskOptimizeDatabase": "Оптимизирай базата данни", "TaskKeyframeExtractorDescription": "Извличат се ключови кадри от видеофайловете ,за да се създаде по точен ХЛС списък . Задачата може да отнеме много време.", "TaskKeyframeExtractor": "Извличане на ключови кадри", - "External": "Външен" + "External": "Външен", + "HearingImpaired": "Увреден слух" } diff --git a/Jellyfin.sln b/Jellyfin.sln index c0d2ec0687..f3fb7efa98 100644 --- a/Jellyfin.sln +++ b/Jellyfin.sln @@ -21,8 +21,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Drawing", "src\Jel EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Emby.Photos", "Emby.Photos\Emby.Photos.csproj", "{89AB4548-770D-41FD-A891-8DAFF44F452C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DvdLib", "DvdLib\DvdLib.csproj", "{713F42B5-878E-499D-A878-E4C652B1D5E8}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Emby.Server.Implementations", "Emby.Server.Implementations\Emby.Server.Implementations.csproj", "{E383961B-9356-4D5D-8233-9A1079D03055}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RSSDP", "RSSDP\RSSDP.csproj", "{21002819-C39A-4D3E-BE83-2A276A77FB1F}" @@ -139,10 +137,6 @@ Global {89AB4548-770D-41FD-A891-8DAFF44F452C}.Debug|Any CPU.Build.0 = Debug|Any CPU {89AB4548-770D-41FD-A891-8DAFF44F452C}.Release|Any CPU.ActiveCfg = Release|Any CPU {89AB4548-770D-41FD-A891-8DAFF44F452C}.Release|Any CPU.Build.0 = Release|Any CPU - {713F42B5-878E-499D-A878-E4C652B1D5E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {713F42B5-878E-499D-A878-E4C652B1D5E8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {713F42B5-878E-499D-A878-E4C652B1D5E8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {713F42B5-878E-499D-A878-E4C652B1D5E8}.Release|Any CPU.Build.0 = Release|Any CPU {E383961B-9356-4D5D-8233-9A1079D03055}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E383961B-9356-4D5D-8233-9A1079D03055}.Debug|Any CPU.Build.0 = Debug|Any CPU {E383961B-9356-4D5D-8233-9A1079D03055}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index fe8e9063ee..bc6207ac51 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -187,13 +187,5 @@ namespace MediaBrowser.Controller.MediaEncoding /// <param name="path">The path.</param> /// <param name="pathType">The type of path.</param> void UpdateEncoderPath(string path, string pathType); - - /// <summary> - /// Gets the primary playlist of .vob files. - /// </summary> - /// <param name="path">The to the .vob files.</param> - /// <param name="titleNumber">The title number to start with.</param> - /// <returns>A playlist.</returns> - IEnumerable<string> GetPrimaryPlaylistVobFiles(string path, uint? titleNumber); } } diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs deleted file mode 100644 index 7e026b42e3..0000000000 --- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs +++ /dev/null @@ -1,83 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Linq; -using BDInfo.IO; -using MediaBrowser.Model.IO; - -namespace MediaBrowser.MediaEncoding.BdInfo -{ - public class BdInfoDirectoryInfo : IDirectoryInfo - { - private readonly IFileSystem _fileSystem; - - private readonly FileSystemMetadata _impl; - - public BdInfoDirectoryInfo(IFileSystem fileSystem, string path) - { - _fileSystem = fileSystem; - _impl = _fileSystem.GetDirectoryInfo(path); - } - - private BdInfoDirectoryInfo(IFileSystem fileSystem, FileSystemMetadata impl) - { - _fileSystem = fileSystem; - _impl = impl; - } - - public string Name => _impl.Name; - - public string FullName => _impl.FullName; - - public IDirectoryInfo? Parent - { - get - { - var parentFolder = System.IO.Path.GetDirectoryName(_impl.FullName); - if (parentFolder is not null) - { - return new BdInfoDirectoryInfo(_fileSystem, parentFolder); - } - - return null; - } - } - - public IDirectoryInfo[] GetDirectories() - { - return Array.ConvertAll( - _fileSystem.GetDirectories(_impl.FullName).ToArray(), - x => new BdInfoDirectoryInfo(_fileSystem, x)); - } - - public IFileInfo[] GetFiles() - { - return Array.ConvertAll( - _fileSystem.GetFiles(_impl.FullName).ToArray(), - x => new BdInfoFileInfo(x)); - } - - public IFileInfo[] GetFiles(string searchPattern) - { - return Array.ConvertAll( - _fileSystem.GetFiles(_impl.FullName, new[] { searchPattern }, false, false).ToArray(), - x => new BdInfoFileInfo(x)); - } - - public IFileInfo[] GetFiles(string searchPattern, System.IO.SearchOption searchOption) - { - return Array.ConvertAll( - _fileSystem.GetFiles( - _impl.FullName, - new[] { searchPattern }, - false, - (searchOption & System.IO.SearchOption.AllDirectories) == System.IO.SearchOption.AllDirectories).ToArray(), - x => new BdInfoFileInfo(x)); - } - - public static IDirectoryInfo FromFileSystemPath(IFileSystem fs, string path) - { - return new BdInfoDirectoryInfo(fs, path); - } - } -} diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs deleted file mode 100644 index 3e53cbf29f..0000000000 --- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs +++ /dev/null @@ -1,194 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using BDInfo; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.MediaInfo; - -namespace MediaBrowser.MediaEncoding.BdInfo -{ - /// <summary> - /// Class BdInfoExaminer. - /// </summary> - public class BdInfoExaminer : IBlurayExaminer - { - private readonly IFileSystem _fileSystem; - - /// <summary> - /// Initializes a new instance of the <see cref="BdInfoExaminer" /> class. - /// </summary> - /// <param name="fileSystem">The filesystem.</param> - public BdInfoExaminer(IFileSystem fileSystem) - { - _fileSystem = fileSystem; - } - - /// <summary> - /// Gets the disc info. - /// </summary> - /// <param name="path">The path.</param> - /// <returns>BlurayDiscInfo.</returns> - public BlurayDiscInfo GetDiscInfo(string path) - { - if (string.IsNullOrWhiteSpace(path)) - { - throw new ArgumentNullException(nameof(path)); - } - - var bdrom = new BDROM(BdInfoDirectoryInfo.FromFileSystemPath(_fileSystem, path)); - - bdrom.Scan(); - - // Get the longest playlist - var playlist = bdrom.PlaylistFiles.Values.OrderByDescending(p => p.TotalLength).FirstOrDefault(p => p.IsValid); - - var outputStream = new BlurayDiscInfo - { - MediaStreams = Array.Empty<MediaStream>() - }; - - if (playlist is null) - { - return outputStream; - } - - outputStream.Chapters = playlist.Chapters.ToArray(); - - outputStream.RunTimeTicks = TimeSpan.FromSeconds(playlist.TotalLength).Ticks; - - var mediaStreams = new List<MediaStream>(); - - foreach (var stream in playlist.SortedStreams) - { - if (stream is TSVideoStream videoStream) - { - AddVideoStream(mediaStreams, videoStream); - continue; - } - - if (stream is TSAudioStream audioStream) - { - AddAudioStream(mediaStreams, audioStream); - continue; - } - - if (stream is TSTextStream textStream) - { - AddSubtitleStream(mediaStreams, textStream); - continue; - } - - if (stream is TSGraphicsStream graphicsStream) - { - AddSubtitleStream(mediaStreams, graphicsStream); - } - } - - outputStream.MediaStreams = mediaStreams.ToArray(); - - outputStream.PlaylistName = playlist.Name; - - if (playlist.StreamClips is not null && playlist.StreamClips.Any()) - { - // Get the files in the playlist - outputStream.Files = playlist.StreamClips.Select(i => i.StreamFile.Name).ToArray(); - } - - return outputStream; - } - - /// <summary> - /// Adds the video stream. - /// </summary> - /// <param name="streams">The streams.</param> - /// <param name="videoStream">The video stream.</param> - private void AddVideoStream(List<MediaStream> streams, TSVideoStream videoStream) - { - var mediaStream = new MediaStream - { - BitRate = Convert.ToInt32(videoStream.BitRate), - Width = videoStream.Width, - Height = videoStream.Height, - Codec = videoStream.CodecShortName, - IsInterlaced = videoStream.IsInterlaced, - Type = MediaStreamType.Video, - Index = streams.Count - }; - - if (videoStream.FrameRateDenominator > 0) - { - float frameRateEnumerator = videoStream.FrameRateEnumerator; - float frameRateDenominator = videoStream.FrameRateDenominator; - - mediaStream.AverageFrameRate = mediaStream.RealFrameRate = frameRateEnumerator / frameRateDenominator; - } - - streams.Add(mediaStream); - } - - /// <summary> - /// Adds the audio stream. - /// </summary> - /// <param name="streams">The streams.</param> - /// <param name="audioStream">The audio stream.</param> - private void AddAudioStream(List<MediaStream> streams, TSAudioStream audioStream) - { - var stream = new MediaStream - { - Codec = audioStream.CodecShortName, - Language = audioStream.LanguageCode, - Channels = audioStream.ChannelCount, - SampleRate = audioStream.SampleRate, - Type = MediaStreamType.Audio, - Index = streams.Count - }; - - var bitrate = Convert.ToInt32(audioStream.BitRate); - - if (bitrate > 0) - { - stream.BitRate = bitrate; - } - - if (audioStream.LFE > 0) - { - stream.Channels = audioStream.ChannelCount + 1; - } - - streams.Add(stream); - } - - /// <summary> - /// Adds the subtitle stream. - /// </summary> - /// <param name="streams">The streams.</param> - /// <param name="textStream">The text stream.</param> - private void AddSubtitleStream(List<MediaStream> streams, TSTextStream textStream) - { - streams.Add(new MediaStream - { - Language = textStream.LanguageCode, - Codec = textStream.CodecShortName, - Type = MediaStreamType.Subtitle, - Index = streams.Count - }); - } - - /// <summary> - /// Adds the subtitle stream. - /// </summary> - /// <param name="streams">The streams.</param> - /// <param name="textStream">The text stream.</param> - private void AddSubtitleStream(List<MediaStream> streams, TSGraphicsStream textStream) - { - streams.Add(new MediaStream - { - Language = textStream.LanguageCode, - Codec = textStream.CodecShortName, - Type = MediaStreamType.Subtitle, - Index = streams.Count - }); - } - } -} diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs deleted file mode 100644 index d55688e3df..0000000000 --- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs +++ /dev/null @@ -1,41 +0,0 @@ -#pragma warning disable CS1591 - -using System.IO; -using MediaBrowser.Model.IO; - -namespace MediaBrowser.MediaEncoding.BdInfo -{ - public class BdInfoFileInfo : BDInfo.IO.IFileInfo - { - private FileSystemMetadata _impl; - - public BdInfoFileInfo(FileSystemMetadata impl) - { - _impl = impl; - } - - public string Name => _impl.Name; - - public string FullName => _impl.FullName; - - public string Extension => _impl.Extension; - - public long Length => _impl.Length; - - public bool IsDir => _impl.IsDirectory; - - public Stream OpenRead() - { - return new FileStream( - FullName, - FileMode.Open, - FileAccess.Read, - FileShare.Read); - } - - public StreamReader OpenText() - { - return new StreamReader(OpenRead()); - } - } -} diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index d95f894c52..d2240b5aff 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -862,85 +862,6 @@ namespace MediaBrowser.MediaEncoding.Encoder throw new NotImplementedException(); } - /// <inheritdoc /> - public IEnumerable<string> GetPrimaryPlaylistVobFiles(string path, uint? titleNumber) - { - // min size 300 mb - const long MinPlayableSize = 314572800; - - // Try to eliminate menus and intros by skipping all files at the front of the list that are less than the minimum size - // Once we reach a file that is at least the minimum, return all subsequent ones - var allVobs = _fileSystem.GetFiles(path, true) - .Where(file => string.Equals(file.Extension, ".vob", StringComparison.OrdinalIgnoreCase)) - .OrderBy(i => i.FullName) - .ToList(); - - // If we didn't find any satisfying the min length, just take them all - if (allVobs.Count == 0) - { - _logger.LogWarning("No vobs found in dvd structure."); - return Enumerable.Empty<string>(); - } - - if (titleNumber.HasValue) - { - var prefix = string.Format( - CultureInfo.InvariantCulture, - titleNumber.Value >= 10 ? "VTS_{0}_" : "VTS_0{0}_", - titleNumber.Value); - var vobs = allVobs.Where(i => i.Name.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)).ToList(); - - if (vobs.Count > 0) - { - var minSizeVobs = vobs - .SkipWhile(f => f.Length < MinPlayableSize) - .ToList(); - - return minSizeVobs.Count == 0 ? vobs.Select(i => i.FullName) : minSizeVobs.Select(i => i.FullName); - } - - _logger.LogWarning("Could not determine vob file list for {Path} using DvdLib. Will scan using file sizes.", path); - } - - var files = allVobs - .SkipWhile(f => f.Length < MinPlayableSize) - .ToList(); - - // If we didn't find any satisfying the min length, just take them all - if (files.Count == 0) - { - _logger.LogWarning("Vob size filter resulted in zero matches. Taking all vobs."); - files = allVobs; - } - - // Assuming they're named "vts_05_01", take all files whose second part matches that of the first file - if (files.Count > 0) - { - var parts = _fileSystem.GetFileNameWithoutExtension(files[0]).Split('_'); - - if (parts.Length == 3) - { - var title = parts[1]; - - files = files.TakeWhile(f => - { - var fileParts = _fileSystem.GetFileNameWithoutExtension(f).Split('_'); - - return fileParts.Length == 3 && string.Equals(title, fileParts[1], StringComparison.OrdinalIgnoreCase); - }).ToList(); - - // If this resulted in not getting any vobs, just take them all - if (files.Count == 0) - { - _logger.LogWarning("Vob filename filter resulted in zero matches. Taking all vobs."); - files = allVobs; - } - } - } - - return files.Select(i => i.FullName); - } - public bool CanExtractSubtitles(string codec) { // TODO is there ever a case when a subtitle can't be extracted?? diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index 1233fb1108..93177298f9 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -22,7 +22,6 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="BDInfo" Version="0.7.6.2" /> <PackageReference Include="libse" Version="3.6.10" /> <PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" /> <PackageReference Include="System.Text.Encoding.CodePages" Version="7.0.0" /> diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 18e248a1bd..04bdbdf59e 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -625,17 +625,6 @@ namespace MediaBrowser.MediaEncoding.Probing return attachment; } - /// <summary> - /// Determines whether a stream code time base is double the frame rate. - /// </summary> - /// <param name="averageFrameRate">average frame rate.</param> - /// <param name="codecTimeBase">codec time base string.</param> - /// <returns>true if the codec time base is double the frame rate.</returns> - internal static bool IsCodecTimeBaseDoubleTheFrameRate(float? averageFrameRate, string codecTimeBase) - { - return MathF.Abs(((averageFrameRate ?? 0) * (GetFrameRate(codecTimeBase) ?? 0)) - 0.5f) <= float.Epsilon; - } - /// <summary> /// Converts ffprobe stream info to our MediaStream class. /// </summary> @@ -748,22 +737,9 @@ namespace MediaBrowser.MediaEncoding.Probing stream.AverageFrameRate = GetFrameRate(streamInfo.AverageFrameRate); stream.RealFrameRate = GetFrameRate(streamInfo.RFrameRate); - bool videoInterlaced = !string.IsNullOrWhiteSpace(streamInfo.FieldOrder) + stream.IsInterlaced = !string.IsNullOrWhiteSpace(streamInfo.FieldOrder) && !string.Equals(streamInfo.FieldOrder, "progressive", StringComparison.OrdinalIgnoreCase); - // Some interlaced H.264 files in mp4 containers using MBAFF coding aren't flagged as being interlaced by FFprobe, - // so for H.264 files we also calculate the frame rate from the codec time base and check if it is double the reported - // frame rate to determine if the file is interlaced - - bool h264MbaffCoded = string.Equals(stream.Codec, "h264", StringComparison.OrdinalIgnoreCase) - && string.IsNullOrWhiteSpace(streamInfo.FieldOrder) - && IsCodecTimeBaseDoubleTheFrameRate(stream.AverageFrameRate, stream.CodecTimeBase); - - if (videoInterlaced || h264MbaffCoded) - { - stream.IsInterlaced = true; - } - if (isAudio || string.Equals(stream.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase) || string.Equals(stream.Codec, "gif", StringComparison.OrdinalIgnoreCase) diff --git a/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs b/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs deleted file mode 100644 index 83f982a5c8..0000000000 --- a/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs +++ /dev/null @@ -1,39 +0,0 @@ -#nullable disable -#pragma warning disable CS1591 - -using MediaBrowser.Model.Entities; - -namespace MediaBrowser.Model.MediaInfo -{ - /// <summary> - /// Represents the result of BDInfo output. - /// </summary> - public class BlurayDiscInfo - { - /// <summary> - /// Gets or sets the media streams. - /// </summary> - /// <value>The media streams.</value> - public MediaStream[] MediaStreams { get; set; } - - /// <summary> - /// Gets or sets the run time ticks. - /// </summary> - /// <value>The run time ticks.</value> - public long? RunTimeTicks { get; set; } - - /// <summary> - /// Gets or sets the files. - /// </summary> - /// <value>The files.</value> - public string[] Files { get; set; } - - public string PlaylistName { get; set; } - - /// <summary> - /// Gets or sets the chapters. - /// </summary> - /// <value>The chapters.</value> - public double[] Chapters { get; set; } - } -} diff --git a/MediaBrowser.Model/MediaInfo/IBlurayExaminer.cs b/MediaBrowser.Model/MediaInfo/IBlurayExaminer.cs deleted file mode 100644 index 5b7d1d03c3..0000000000 --- a/MediaBrowser.Model/MediaInfo/IBlurayExaminer.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace MediaBrowser.Model.MediaInfo -{ - /// <summary> - /// Interface IBlurayExaminer. - /// </summary> - public interface IBlurayExaminer - { - /// <summary> - /// Gets the disc info. - /// </summary> - /// <param name="path">The path.</param> - /// <returns>BlurayDiscInfo.</returns> - BlurayDiscInfo GetDiscInfo(string path); - } -} diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 13de86a929..9e238e9f3a 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -8,7 +8,6 @@ <ItemGroup> <ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" /> <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" /> - <ProjectReference Include="..\DvdLib\DvdLib.csproj" /> </ItemGroup> <ItemGroup> diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index 81434b8620..0f35c6a5ea 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -9,7 +9,6 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using DvdLib.Ifo; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Chapters; using MediaBrowser.Controller.Configuration; @@ -37,7 +36,6 @@ namespace MediaBrowser.Providers.MediaInfo private readonly ILogger<FFProbeVideoInfo> _logger; private readonly IMediaEncoder _mediaEncoder; private readonly IItemRepository _itemRepo; - private readonly IBlurayExaminer _blurayExaminer; private readonly ILocalizationManager _localization; private readonly IEncodingManager _encodingManager; private readonly IServerConfigurationManager _config; @@ -53,7 +51,6 @@ namespace MediaBrowser.Providers.MediaInfo IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, - IBlurayExaminer blurayExaminer, ILocalizationManager localization, IEncodingManager encodingManager, IServerConfigurationManager config, @@ -67,7 +64,6 @@ namespace MediaBrowser.Providers.MediaInfo _mediaSourceManager = mediaSourceManager; _mediaEncoder = mediaEncoder; _itemRepo = itemRepo; - _blurayExaminer = blurayExaminer; _localization = localization; _encodingManager = encodingManager; _config = config; @@ -84,47 +80,16 @@ namespace MediaBrowser.Providers.MediaInfo CancellationToken cancellationToken) where T : Video { - BlurayDiscInfo blurayDiscInfo = null; - Model.MediaInfo.MediaInfo mediaInfoResult = null; if (!item.IsShortcut || options.EnableRemoteContentProbe) { - string[] streamFileNames = null; - - if (item.VideoType == VideoType.Dvd) - { - streamFileNames = FetchFromDvdLib(item); - - if (streamFileNames.Length == 0) - { - _logger.LogError("No playable vobs found in dvd structure, skipping ffprobe."); - return ItemUpdateType.MetadataImport; - } - } - else if (item.VideoType == VideoType.BluRay) - { - var inputPath = item.Path; - - blurayDiscInfo = GetBDInfo(inputPath); - - streamFileNames = blurayDiscInfo.Files; - - if (streamFileNames.Length == 0) - { - _logger.LogError("No playable vobs found in bluray structure, skipping ffprobe."); - return ItemUpdateType.MetadataImport; - } - } - - streamFileNames ??= Array.Empty<string>(); - mediaInfoResult = await GetMediaInfo(item, cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); } - await Fetch(item, cancellationToken, mediaInfoResult, blurayDiscInfo, options).ConfigureAwait(false); + await Fetch(item, cancellationToken, mediaInfoResult, options).ConfigureAwait(false); return ItemUpdateType.MetadataImport; } @@ -164,7 +129,6 @@ namespace MediaBrowser.Providers.MediaInfo Video video, CancellationToken cancellationToken, Model.MediaInfo.MediaInfo mediaInfo, - BlurayDiscInfo blurayInfo, MetadataRefreshOptions options) { List<MediaStream> mediaStreams; @@ -218,10 +182,6 @@ namespace MediaBrowser.Providers.MediaInfo video.Container = mediaInfo.Container; chapters = mediaInfo.Chapters ?? Array.Empty<ChapterInfo>(); - if (blurayInfo is not null) - { - FetchBdInfo(video, ref chapters, mediaStreams, blurayInfo); - } } else { @@ -317,91 +277,6 @@ namespace MediaBrowser.Providers.MediaInfo } } - private void FetchBdInfo(BaseItem item, ref ChapterInfo[] chapters, List<MediaStream> mediaStreams, BlurayDiscInfo blurayInfo) - { - var video = (Video)item; - - // video.PlayableStreamFileNames = blurayInfo.Files.ToList(); - - // Use BD Info if it has multiple m2ts. Otherwise, treat it like a video file and rely more on ffprobe output - if (blurayInfo.Files.Length > 1) - { - int? currentHeight = null; - int? currentWidth = null; - int? currentBitRate = null; - - var videoStream = mediaStreams.FirstOrDefault(s => s.Type == MediaStreamType.Video); - - // Grab the values that ffprobe recorded - if (videoStream is not null) - { - currentBitRate = videoStream.BitRate; - currentWidth = videoStream.Width; - currentHeight = videoStream.Height; - } - - // Fill video properties from the BDInfo result - mediaStreams.Clear(); - mediaStreams.AddRange(blurayInfo.MediaStreams); - - if (blurayInfo.RunTimeTicks.HasValue && blurayInfo.RunTimeTicks.Value > 0) - { - video.RunTimeTicks = blurayInfo.RunTimeTicks; - } - - if (blurayInfo.Chapters is not null) - { - double[] brChapter = blurayInfo.Chapters; - chapters = new ChapterInfo[brChapter.Length]; - for (int i = 0; i < brChapter.Length; i++) - { - chapters[i] = new ChapterInfo - { - StartPositionTicks = TimeSpan.FromSeconds(brChapter[i]).Ticks - }; - } - } - - videoStream = mediaStreams.FirstOrDefault(s => s.Type == MediaStreamType.Video); - - // Use the ffprobe values if these are empty - if (videoStream is not null) - { - videoStream.BitRate = IsEmpty(videoStream.BitRate) ? currentBitRate : videoStream.BitRate; - videoStream.Width = IsEmpty(videoStream.Width) ? currentWidth : videoStream.Width; - videoStream.Height = IsEmpty(videoStream.Height) ? currentHeight : videoStream.Height; - } - } - } - - private bool IsEmpty(int? num) - { - return !num.HasValue || num.Value == 0; - } - - /// <summary> - /// Gets information about the longest playlist on a bdrom. - /// </summary> - /// <param name="path">The path.</param> - /// <returns>VideoStream.</returns> - private BlurayDiscInfo GetBDInfo(string path) - { - if (string.IsNullOrWhiteSpace(path)) - { - throw new ArgumentNullException(nameof(path)); - } - - try - { - return _blurayExaminer.GetDiscInfo(path); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error getting BDInfo"); - return null; - } - } - private void FetchEmbeddedInfo(Video video, Model.MediaInfo.MediaInfo data, MetadataRefreshOptions refreshOptions, LibraryOptions libraryOptions) { var replaceData = refreshOptions.ReplaceAllMetadata; @@ -683,33 +558,5 @@ namespace MediaBrowser.Providers.MediaInfo return chapters; } - - private string[] FetchFromDvdLib(Video item) - { - var path = item.Path; - var dvd = new Dvd(path); - - var primaryTitle = dvd.Titles.OrderByDescending(GetRuntime).FirstOrDefault(); - - byte? titleNumber = null; - - if (primaryTitle is not null) - { - titleNumber = primaryTitle.VideoTitleSetNumber; - item.RunTimeTicks = GetRuntime(primaryTitle); - } - - return _mediaEncoder.GetPrimaryPlaylistVobFiles(item.Path, titleNumber) - .Select(Path.GetFileName) - .ToArray(); - } - - private long GetRuntime(Title title) - { - return title.ProgramChains - .Select(i => (TimeSpan)i.PlaybackTime) - .Select(i => i.Ticks) - .Sum(); - } } } diff --git a/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs index 2800219552..31fa3da1ce 100644 --- a/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs @@ -53,7 +53,6 @@ namespace MediaBrowser.Providers.MediaInfo /// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param> /// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param> /// <param name="itemRepo">Instance of the <see cref="IItemRepository"/> interface.</param> - /// <param name="blurayExaminer">Instance of the <see cref="IBlurayExaminer"/> interface.</param> /// <param name="localization">Instance of the <see cref="ILocalizationManager"/> interface.</param> /// <param name="encodingManager">Instance of the <see cref="IEncodingManager"/> interface.</param> /// <param name="config">Instance of the <see cref="IServerConfigurationManager"/> interface.</param> @@ -67,7 +66,6 @@ namespace MediaBrowser.Providers.MediaInfo IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, - IBlurayExaminer blurayExaminer, ILocalizationManager localization, IEncodingManager encodingManager, IServerConfigurationManager config, @@ -87,7 +85,6 @@ namespace MediaBrowser.Providers.MediaInfo mediaSourceManager, mediaEncoder, itemRepo, - blurayExaminer, localization, encodingManager, config, diff --git a/debian/bin/restart.sh b/debian/bin/restart.sh deleted file mode 100755 index 4847b918be..0000000000 --- a/debian/bin/restart.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash - -# restart.sh - Jellyfin server restart script -# Part of the Jellyfin project (https://github.com/jellyfin) -# -# This script restarts the Jellyfin daemon on Linux when using -# the Restart button on the admin dashboard. It supports the -# systemctl, service, and traditional /etc/init.d (sysv) restart -# methods, chosen automatically by which one is found first (in -# that order). -# -# This script is used by the Debian/Ubuntu/Fedora/CentOS packages. - -# This is the Right Way(tm) to check if we are booted with -# systemd, according to sd_booted(3) -if [ -d /run/systemd/system ]; then - cmd=systemctl -else - # Everything else is really hard to figure out, so we just use - # service(8) if it's available - that works with most init - # systems/distributions I know of, including FreeBSD - if type service >/dev/null 2>&1; then - cmd=service - else - # If even service(8) isn't available, we just try /etc/init.d - # and hope for the best - if [ -d /etc/init.d ]; then - cmd=sysv - else - echo "Unable to detect a way to restart Jellyfin; bailing out" 1>&2 - echo "Please report this bug to https://github.com/jellyfin/jellyfin/issues" 1>&2 - exit 1 - fi - fi -fi - -if type sudo >/dev/null 2>&1; then - sudo_command=sudo -else - sudo_command= -fi - -echo "Detected service control platform '$cmd'; using it to restart Jellyfin..." -case $cmd in - 'systemctl') - # Without systemd-run here, `jellyfin.service`'s shutdown terminates this process too - $sudo_command systemd-run systemctl restart jellyfin - ;; - 'service') - echo "sleep 0.5; $sudo_command service jellyfin start" | at now - ;; - 'sysv') - echo "sleep 0.5; /usr/bin/sudo /etc/init.d/jellyfin start" | at now - ;; -esac -exit 0 diff --git a/debian/conf/jellyfin b/debian/conf/jellyfin index 2f0630a9ce..9129967559 100644 --- a/debian/conf/jellyfin +++ b/debian/conf/jellyfin @@ -21,9 +21,6 @@ JELLYFIN_CACHE_DIR="/var/cache/jellyfin" # web client path, installed by the jellyfin-web package JELLYFIN_WEB_OPT="--webdir=/usr/share/jellyfin/web" -# Restart script for in-app server control -JELLYFIN_RESTART_OPT="--restartpath=/usr/lib/jellyfin/restart.sh" - # ffmpeg binary paths, overriding the system values JELLYFIN_FFMPEG_OPT="--ffmpeg=/usr/lib/jellyfin-ffmpeg/ffmpeg" @@ -50,4 +47,4 @@ JELLYFIN_ADDITIONAL_OPTS="" # Application username JELLYFIN_USER="jellyfin" # Full application command -JELLYFIN_ARGS="$JELLYFIN_WEB_OPT $JELLYFIN_RESTART_OPT $JELLYFIN_FFMPEG_OPT $JELLYFIN_SERVICE_OPT $JELLYFIN_NOWEBAPP_OPT $JELLFIN_ADDITIONAL_OPTS" +JELLYFIN_ARGS="$JELLYFIN_WEB_OPT $JELLYFIN_FFMPEG_OPT $JELLYFIN_SERVICE_OPT $JELLYFIN_NOWEBAPP_OPT $JELLFIN_ADDITIONAL_OPTS" diff --git a/debian/install b/debian/install index 994322d141..593b13a7b3 100644 --- a/debian/install +++ b/debian/install @@ -3,4 +3,3 @@ debian/conf/jellyfin etc/default/ debian/conf/logging.json etc/jellyfin/ debian/conf/jellyfin.service.conf etc/systemd/system/jellyfin.service.d/ debian/conf/jellyfin-sudoers etc/sudoers.d/ -debian/bin/restart.sh usr/lib/jellyfin/ diff --git a/debian/jellyfin.service b/debian/jellyfin.service index 1150924a08..2cc49f7c4a 100644 --- a/debian/jellyfin.service +++ b/debian/jellyfin.service @@ -8,7 +8,7 @@ EnvironmentFile = /etc/default/jellyfin User = jellyfin Group = jellyfin WorkingDirectory = /var/lib/jellyfin -ExecStart = /usr/bin/jellyfin $JELLYFIN_WEB_OPT $JELLYFIN_RESTART_OPT $JELLYFIN_FFMPEG_OPT $JELLYFIN_SERVICE_OPT $JELLYFIN_NOWEBAPP_OPT $JELLYFIN_ADDITIONAL_OPTS +ExecStart = /usr/bin/jellyfin $JELLYFIN_WEB_OPT $JELLYFIN_FFMPEG_OPT $JELLYFIN_SERVICE_OPT $JELLYFIN_NOWEBAPP_OPT $JELLYFIN_ADDITIONAL_OPTS Restart = on-failure TimeoutSec = 15 SuccessExitStatus=0 143 diff --git a/debian/postinst b/debian/postinst index a15442c76e..947959aa7a 100644 --- a/debian/postinst +++ b/debian/postinst @@ -59,8 +59,6 @@ case "$1" in chgrp adm $PROGRAMDATA $CONFIGDATA $LOGDATA $CACHEDATA chmod 0750 $PROGRAMDATA $CONFIGDATA $LOGDATA $CACHEDATA - chmod +x /usr/lib/jellyfin/restart.sh > /dev/null 2>&1 || true - # Install jellyfin symlink into /usr/bin ln -sf /usr/lib/jellyfin/bin/jellyfin /usr/bin/jellyfin diff --git a/fedora/jellyfin.env b/fedora/jellyfin.env index 1ccd8196fd..1f79fac4f6 100644 --- a/fedora/jellyfin.env +++ b/fedora/jellyfin.env @@ -23,9 +23,6 @@ JELLYFIN_CACHE_DIR="/var/cache/jellyfin" # web client path, installed by the jellyfin-web package # JELLYFIN_WEB_OPT="--webdir=/usr/share/jellyfin-web" -# In-App service control -JELLYFIN_RESTART_OPT="--restartpath=/usr/libexec/jellyfin/restart.sh" - # [OPTIONAL] ffmpeg binary paths, overriding the UI-configured values #JELLYFIN_FFMPEG_OPT="--ffmpeg=/usr/bin/ffmpeg" diff --git a/fedora/jellyfin.service b/fedora/jellyfin.service index 2fb9f30e00..1b3f8032c6 100644 --- a/fedora/jellyfin.service +++ b/fedora/jellyfin.service @@ -8,7 +8,7 @@ EnvironmentFile = /etc/sysconfig/jellyfin User = jellyfin Group = jellyfin WorkingDirectory = /var/lib/jellyfin -ExecStart = /usr/bin/jellyfin $JELLYFIN_WEB_OPT $JELLYFIN_RESTART_OPT $JELLYFIN_FFMPEG_OPT $JELLYFIN_SERVICE_OPT $JELLYFIN_NOWEBAPP_OPT $JELLYFIN_ADDITIONAL_OPTS +ExecStart = /usr/bin/jellyfin $JELLYFIN_WEB_OPT $JELLYFIN_SERVICE_OPT $JELLYFIN_NOWEBAPP_OPT $JELLYFIN_ADDITIONAL_OPTS Restart = on-failure TimeoutSec = 15 SuccessExitStatus=0 143 diff --git a/fedora/jellyfin.spec b/fedora/jellyfin.spec index 08de715370..2456877890 100644 --- a/fedora/jellyfin.spec +++ b/fedora/jellyfin.spec @@ -17,10 +17,9 @@ Source0: jellyfin-server-%{version}.tar.gz Source11: jellyfin.service Source12: jellyfin.env Source13: jellyfin.sudoers -Source14: restart.sh -Source15: jellyfin.override.conf -Source16: jellyfin-firewalld.xml -Source17: jellyfin-server-lowports.conf +Source14: jellyfin.override.conf +Source15: jellyfin-firewalld.xml +Source16: jellyfin-server-lowports.conf %{?systemd_requires} BuildRequires: systemd @@ -76,16 +75,15 @@ dotnet publish --configuration Release --self-contained --runtime %{dotnet_runti %{__mkdir} -p %{buildroot}%{_libdir}/jellyfin %{buildroot}%{_bindir} %{__cp} -r Jellyfin.Server/bin/Release/net7.0/%{dotnet_runtime}/publish/* %{buildroot}%{_libdir}/jellyfin ln -srf %{_libdir}/jellyfin/jellyfin %{buildroot}%{_bindir}/jellyfin -%{__install} -D %{SOURCE14} %{buildroot}%{_libexecdir}/jellyfin/restart.sh # Jellyfin config %{__install} -D Jellyfin.Server/Resources/Configuration/logging.json %{buildroot}%{_sysconfdir}/jellyfin/logging.json %{__install} -D %{SOURCE12} %{buildroot}%{_sysconfdir}/sysconfig/jellyfin # system config -%{__install} -D %{SOURCE16} %{buildroot}%{_prefix}/lib/firewalld/services/jellyfin.xml +%{__install} -D %{SOURCE15} %{buildroot}%{_prefix}/lib/firewalld/services/jellyfin.xml %{__install} -D %{SOURCE13} %{buildroot}%{_sysconfdir}/sudoers.d/jellyfin-sudoers -%{__install} -D %{SOURCE15} %{buildroot}%{_sysconfdir}/systemd/system/jellyfin.service.d/override.conf +%{__install} -D %{SOURCE14} %{buildroot}%{_sysconfdir}/systemd/system/jellyfin.service.d/override.conf %{__install} -D %{SOURCE11} %{buildroot}%{_unitdir}/jellyfin.service # empty directories @@ -95,7 +93,7 @@ ln -srf %{_libdir}/jellyfin/jellyfin %{buildroot}%{_bindir}/jellyfin %{__mkdir} -p %{buildroot}%{_var}/log/jellyfin # jellyfin-server-lowports subpackage -%{__install} -D -m 0644 %{SOURCE17} %{buildroot}%{_unitdir}/jellyfin.service.d/jellyfin-server-lowports.conf +%{__install} -D -m 0644 %{SOURCE16} %{buildroot}%{_unitdir}/jellyfin.service.d/jellyfin-server-lowports.conf %files @@ -110,7 +108,6 @@ ln -srf %{_libdir}/jellyfin/jellyfin %{buildroot}%{_bindir}/jellyfin %attr(755,root,root) %{_libdir}/jellyfin/createdump %attr(755,root,root) %{_libdir}/jellyfin/jellyfin %{_libdir}/jellyfin/* -%attr(755,root,root) %{_libexecdir}/jellyfin/restart.sh # Jellyfin config %config(noreplace) %attr(644,jellyfin,jellyfin) %{_sysconfdir}/jellyfin/logging.json diff --git a/fedora/restart.sh b/fedora/restart.sh deleted file mode 100755 index 4847b918be..0000000000 --- a/fedora/restart.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash - -# restart.sh - Jellyfin server restart script -# Part of the Jellyfin project (https://github.com/jellyfin) -# -# This script restarts the Jellyfin daemon on Linux when using -# the Restart button on the admin dashboard. It supports the -# systemctl, service, and traditional /etc/init.d (sysv) restart -# methods, chosen automatically by which one is found first (in -# that order). -# -# This script is used by the Debian/Ubuntu/Fedora/CentOS packages. - -# This is the Right Way(tm) to check if we are booted with -# systemd, according to sd_booted(3) -if [ -d /run/systemd/system ]; then - cmd=systemctl -else - # Everything else is really hard to figure out, so we just use - # service(8) if it's available - that works with most init - # systems/distributions I know of, including FreeBSD - if type service >/dev/null 2>&1; then - cmd=service - else - # If even service(8) isn't available, we just try /etc/init.d - # and hope for the best - if [ -d /etc/init.d ]; then - cmd=sysv - else - echo "Unable to detect a way to restart Jellyfin; bailing out" 1>&2 - echo "Please report this bug to https://github.com/jellyfin/jellyfin/issues" 1>&2 - exit 1 - fi - fi -fi - -if type sudo >/dev/null 2>&1; then - sudo_command=sudo -else - sudo_command= -fi - -echo "Detected service control platform '$cmd'; using it to restart Jellyfin..." -case $cmd in - 'systemctl') - # Without systemd-run here, `jellyfin.service`'s shutdown terminates this process too - $sudo_command systemd-run systemctl restart jellyfin - ;; - 'service') - echo "sleep 0.5; $sudo_command service jellyfin start" | at now - ;; - 'sysv') - echo "sleep 0.5; /usr/bin/sudo /etc/init.d/jellyfin start" | at now - ;; -esac -exit 0 diff --git a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs index bbe1246ca7..a64604e99f 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs @@ -31,16 +31,6 @@ namespace Jellyfin.MediaEncoding.Tests.Probing public void GetFrameRate_Success(string value, float? expected) => Assert.Equal(expected, ProbeResultNormalizer.GetFrameRate(value)); - [Theory] - [InlineData(0.5f, "0/1", false)] - [InlineData(24.5f, "8/196", false)] - [InlineData(63.5f, "1/127", true)] - [InlineData(null, "1/60", false)] - [InlineData(30f, "2/120", true)] - [InlineData(59.999996f, "1563/187560", true)] - public void IsCodecTimeBaseDoubleTheFrameRate_Success(float? frameRate, string codecTimeBase, bool expected) - => Assert.Equal(expected, ProbeResultNormalizer.IsCodecTimeBaseDoubleTheFrameRate(frameRate, codecTimeBase)); - [Fact] public void GetMediaInfo_MetaData_Success() { @@ -158,6 +148,99 @@ namespace Jellyfin.MediaEncoding.Tests.Probing Assert.False(res.MediaStreams[5].IsHearingImpaired); } + [Fact] + public void GetMediaInfo_ProgressiveVideoNoFieldOrder_Success() + { + var bytes = File.ReadAllBytes("Test Data/Probing/video_progressive_no_field_order.json"); + + var internalMediaInfoResult = JsonSerializer.Deserialize<InternalMediaInfoResult>(bytes, _jsonOptions); + MediaInfo res = _probeResultNormalizer.GetMediaInfo(internalMediaInfoResult, VideoType.VideoFile, false, "Test Data/Probing/video_progressive_no_field_order.mp4", MediaProtocol.File); + + Assert.Equal(2, res.MediaStreams.Count); + + Assert.NotNull(res.VideoStream); + Assert.Equal(res.MediaStreams[0], res.VideoStream); + Assert.Equal(0, res.VideoStream.Index); + Assert.Equal("h264", res.VideoStream.Codec); + Assert.Equal("Main", res.VideoStream.Profile); + Assert.Equal(MediaStreamType.Video, res.VideoStream.Type); + Assert.Equal(1080, res.VideoStream.Height); + Assert.Equal(1920, res.VideoStream.Width); + Assert.False(res.VideoStream.IsInterlaced); + Assert.Equal("16:9", res.VideoStream.AspectRatio); + Assert.Equal("yuv420p", res.VideoStream.PixelFormat); + Assert.Equal(41d, res.VideoStream.Level); + Assert.Equal(1, res.VideoStream.RefFrames); + Assert.True(res.VideoStream.IsAVC); + Assert.Equal(23.9760246f, res.VideoStream.RealFrameRate); + Assert.Equal("1/24000", res.VideoStream.TimeBase); + Assert.Equal(3948341, res.VideoStream.BitRate); + Assert.Equal(8, res.VideoStream.BitDepth); + Assert.True(res.VideoStream.IsDefault); + } + + [Fact] + public void GetMediaInfo_ProgressiveVideoNoFieldOrder2_Success() + { + var bytes = File.ReadAllBytes("Test Data/Probing/video_progressive_no_field_order2.json"); + + var internalMediaInfoResult = JsonSerializer.Deserialize<InternalMediaInfoResult>(bytes, _jsonOptions); + MediaInfo res = _probeResultNormalizer.GetMediaInfo(internalMediaInfoResult, VideoType.VideoFile, false, "Test Data/Probing/video_progressive_no_field_order2.mp4", MediaProtocol.File); + + Assert.Single(res.MediaStreams); + + Assert.NotNull(res.VideoStream); + Assert.Equal(res.MediaStreams[0], res.VideoStream); + Assert.Equal(0, res.VideoStream.Index); + Assert.Equal("h264", res.VideoStream.Codec); + Assert.Equal("High", res.VideoStream.Profile); + Assert.Equal(MediaStreamType.Video, res.VideoStream.Type); + Assert.Equal(720, res.VideoStream.Height); + Assert.Equal(1280, res.VideoStream.Width); + Assert.False(res.VideoStream.IsInterlaced); + Assert.Equal("16:9", res.VideoStream.AspectRatio); + Assert.Equal("yuv420p", res.VideoStream.PixelFormat); + Assert.Equal(31d, res.VideoStream.Level); + Assert.Equal(1, res.VideoStream.RefFrames); + Assert.True(res.VideoStream.IsAVC); + Assert.Equal(25f, res.VideoStream.RealFrameRate); + Assert.Equal("1/12800", res.VideoStream.TimeBase); + Assert.Equal(53288, res.VideoStream.BitRate); + Assert.Equal(8, res.VideoStream.BitDepth); + Assert.True(res.VideoStream.IsDefault); + } + + [Fact] + public void GetMediaInfo_InterlacedVideo_Success() + { + var bytes = File.ReadAllBytes("Test Data/Probing/video_interlaced.json"); + + var internalMediaInfoResult = JsonSerializer.Deserialize<InternalMediaInfoResult>(bytes, _jsonOptions); + MediaInfo res = _probeResultNormalizer.GetMediaInfo(internalMediaInfoResult, VideoType.VideoFile, false, "Test Data/Probing/video_interlaced.mp4", MediaProtocol.File); + + Assert.Single(res.MediaStreams); + + Assert.NotNull(res.VideoStream); + Assert.Equal(res.MediaStreams[0], res.VideoStream); + Assert.Equal(0, res.VideoStream.Index); + Assert.Equal("h264", res.VideoStream.Codec); + Assert.Equal("High", res.VideoStream.Profile); + Assert.Equal(MediaStreamType.Video, res.VideoStream.Type); + Assert.Equal(720, res.VideoStream.Height); + Assert.Equal(1280, res.VideoStream.Width); + Assert.True(res.VideoStream.IsInterlaced); + Assert.Equal("16:9", res.VideoStream.AspectRatio); + Assert.Equal("yuv420p", res.VideoStream.PixelFormat); + Assert.Equal(40d, res.VideoStream.Level); + Assert.Equal(1, res.VideoStream.RefFrames); + Assert.True(res.VideoStream.IsAVC); + Assert.Equal(25f, res.VideoStream.RealFrameRate); + Assert.Equal("1/12800", res.VideoStream.TimeBase); + Assert.Equal(56945, res.VideoStream.BitRate); + Assert.Equal(8, res.VideoStream.BitDepth); + Assert.True(res.VideoStream.IsDefault); + } + [Fact] public void GetMediaInfo_MusicVideo_Success() { diff --git a/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_interlaced.json b/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_interlaced.json new file mode 100644 index 0000000000..8102449208 --- /dev/null +++ b/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_interlaced.json @@ -0,0 +1,81 @@ +{ + "streams": [ + { + "index": 0, + "codec_name": "h264", + "codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10", + "profile": "High", + "codec_type": "video", + "codec_tag_string": "avc1", + "codec_tag": "0x31637661", + "width": 1280, + "height": 720, + "coded_width": 1280, + "coded_height": 720, + "closed_captions": 0, + "film_grain": 0, + "has_b_frames": 2, + "pix_fmt": "yuv420p", + "level": 40, + "chroma_location": "left", + "field_order": "tt", + "refs": 1, + "is_avc": "true", + "nal_length_size": "4", + "id": "0x1", + "r_frame_rate": "25/1", + "avg_frame_rate": "25/1", + "time_base": "1/12800", + "start_pts": 0, + "start_time": "0.000000", + "duration_ts": 3840000, + "duration": "300.000000", + "bit_rate": "56945", + "bits_per_raw_sample": "8", + "nb_frames": "7500", + "extradata_size": 42, + "disposition": { + "default": 1, + "dub": 0, + "original": 0, + "comment": 0, + "lyrics": 0, + "karaoke": 0, + "forced": 0, + "hearing_impaired": 0, + "visual_impaired": 0, + "clean_effects": 0, + "attached_pic": 0, + "timed_thumbnails": 0, + "captions": 0, + "descriptions": 0, + "metadata": 0, + "dependent": 0, + "still_image": 0 + }, + "tags": { + "language": "und", + "handler_name": "VideoHandler", + "vendor_id": "[0][0][0][0]" + } + } + ], + "format": { + "filename": "test-gray.720i.mp4", + "nb_streams": 1, + "nb_programs": 0, + "format_name": "mov,mp4,m4a,3gp,3g2,mj2", + "format_long_name": "QuickTime / MOV", + "start_time": "0.000000", + "duration": "300.000000", + "size": "2223957", + "bit_rate": "59305", + "probe_score": 100, + "tags": { + "major_brand": "isom", + "minor_version": "512", + "compatible_brands": "isomiso2avc1mp41", + "encoder": "Lavf58.20.100" + } + } +} diff --git a/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_progressive_no_field_order.json b/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_progressive_no_field_order.json new file mode 100644 index 0000000000..897c5e3aba --- /dev/null +++ b/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_progressive_no_field_order.json @@ -0,0 +1,133 @@ +{ + "streams": [ + { + "index": 0, + "codec_name": "h264", + "codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10", + "profile": "Main", + "codec_type": "video", + "codec_time_base": "1001/48000", + "codec_tag_string": "avc1", + "codec_tag": "0x31637661", + "width": 1920, + "height": 1080, + "coded_width": 1920, + "coded_height": 1088, + "closed_captions": 0, + "has_b_frames": 1, + "sample_aspect_ratio": "1:1", + "display_aspect_ratio": "16:9", + "pix_fmt": "yuv420p", + "level": 41, + "chroma_location": "left", + "refs": 1, + "is_avc": "true", + "nal_length_size": "4", + "r_frame_rate": "24000/1001", + "avg_frame_rate": "24000/1001", + "time_base": "1/24000", + "start_pts": 1000, + "start_time": "0.041667", + "duration_ts": 29095066, + "duration": "1212.294417", + "bit_rate": "3948341", + "bits_per_raw_sample": "8", + "nb_frames": "29066", + "disposition": { + "default": 1, + "dub": 0, + "original": 0, + "comment": 0, + "lyrics": 0, + "karaoke": 0, + "forced": 0, + "hearing_impaired": 0, + "visual_impaired": 0, + "clean_effects": 0, + "attached_pic": 0, + "timed_thumbnails": 0 + }, + "tags": { + "creation_time": "2020-01-20T13:56:34.000000Z", + "language": "eng", + "handler_name": "\fVideoHandler", + "encoder": "h264" + } + }, + { + "index": 1, + "codec_name": "ac3", + "codec_long_name": "ATSC A/52A (AC-3)", + "codec_type": "audio", + "codec_time_base": "1/48000", + "codec_tag_string": "ac-3", + "codec_tag": "0x332d6361", + "sample_fmt": "fltp", + "sample_rate": "48000", + "channels": 2, + "channel_layout": "stereo", + "bits_per_sample": 0, + "dmix_mode": "-1", + "ltrt_cmixlev": "-1.000000", + "ltrt_surmixlev": "-1.000000", + "loro_cmixlev": "-1.000000", + "loro_surmixlev": "-1.000000", + "r_frame_rate": "0/0", + "avg_frame_rate": "0/0", + "time_base": "1/48000", + "start_pts": 0, + "start_time": "0.000000", + "duration_ts": 58232832, + "duration": "1213.184000", + "bit_rate": "224000", + "nb_frames": "37912", + "disposition": { + "default": 1, + "dub": 0, + "original": 0, + "comment": 0, + "lyrics": 0, + "karaoke": 0, + "forced": 0, + "hearing_impaired": 0, + "visual_impaired": 0, + "clean_effects": 0, + "attached_pic": 0, + "timed_thumbnails": 0 + }, + "tags": { + "creation_time": "2020-01-20T13:56:34.000000Z", + "language": "eng", + "handler_name": "\fSoundHandler" + }, + "side_data_list": [ + { + "side_data_type": "Audio Service Type" + } + ] + } + ], + "format": { + "filename": "The Big Bang Theory - S01E17.mp4", + "nb_streams": 2, + "nb_programs": 0, + "format_name": "mov,mp4,m4a,3gp,3g2,mj2", + "format_long_name": "QuickTime / MOV", + "start_time": "0.000000", + "duration": "1213.184000", + "size": "633084606", + "bit_rate": "4174698", + "probe_score": 100, + "tags": { + "major_brand": "mp42", + "minor_version": "512", + "compatible_brands": "mp42", + "creation_time": "2020-01-20T13:56:34.000000Z", + "media_type": "9", + "season_number": "0", + "episode_sort": "0", + "hd_video": "0", + "iTunMOVI": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"><plist version=\"1.0\"><dict><key>studio</key><string>studio</string><key>cast</key><array><dict><key>name</key><string></string></dict></array><key>directors</key><array><dict><key>name</key><string></string></dict></array><key>producers</key><array><dict><key>name</key><string></string></dict></array><key>codirectors</key><array><dict><key>name</key><string>codirector</string></dict></array><key>screenwriters</key><array><dict><key>name</key><string></string></dict></array></dict></plist>" + } + } +} diff --git a/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_progressive_no_field_order2.json b/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_progressive_no_field_order2.json new file mode 100644 index 0000000000..4a03e0d61c --- /dev/null +++ b/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_progressive_no_field_order2.json @@ -0,0 +1,72 @@ +{ + "streams": [ + { + "index": 0, + "codec_name": "h264", + "codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10", + "profile": "High", + "codec_type": "video", + "codec_time_base": "1/50", + "codec_tag_string": "avc1", + "codec_tag": "0x31637661", + "width": 1280, + "height": 720, + "coded_width": 1280, + "coded_height": 720, + "closed_captions": 0, + "has_b_frames": 2, + "pix_fmt": "yuv420p", + "level": 31, + "chroma_location": "left", + "refs": 1, + "is_avc": "true", + "nal_length_size": "4", + "r_frame_rate": "25/1", + "avg_frame_rate": "25/1", + "time_base": "1/12800", + "start_pts": 0, + "start_time": "0.000000", + "duration_ts": 3840000, + "duration": "300.000000", + "bit_rate": "53288", + "bits_per_raw_sample": "8", + "nb_frames": "7500", + "disposition": { + "default": 1, + "dub": 0, + "original": 0, + "comment": 0, + "lyrics": 0, + "karaoke": 0, + "forced": 0, + "hearing_impaired": 0, + "visual_impaired": 0, + "clean_effects": 0, + "attached_pic": 0, + "timed_thumbnails": 0 + }, + "tags": { + "language": "und", + "handler_name": "VideoHandler" + } + } + ], + "format": { + "filename": "test-gray.720p.mp4", + "nb_streams": 1, + "nb_programs": 0, + "format_name": "mov,mp4,m4a,3gp,3g2,mj2", + "format_long_name": "QuickTime / MOV", + "start_time": "0.000000", + "duration": "300.000000", + "size": "2086818", + "bit_rate": "55648", + "probe_score": 100, + "tags": { + "major_brand": "isom", + "minor_version": "512", + "compatible_brands": "isomiso2avc1mp41", + "encoder": "Lavf58.20.100" + } + } +}