2
0

Dvd.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.IO;
  6. using System.Diagnostics;
  7. using MediaBrowser.Model.IO;
  8. namespace DvdLib.Ifo
  9. {
  10. public class Dvd
  11. {
  12. private readonly ushort _titleSetCount;
  13. public readonly List<Title> Titles;
  14. private ushort _titleCount;
  15. public readonly Dictionary<ushort, string> VTSPaths = new Dictionary<ushort, string>();
  16. private readonly IFileSystem _fileSystem;
  17. public Dvd(string path, IFileSystem fileSystem)
  18. {
  19. _fileSystem = fileSystem;
  20. Titles = new List<Title>();
  21. var allFiles = _fileSystem.GetFiles(path, true).ToList();
  22. var vmgPath = allFiles.FirstOrDefault(i => string.Equals(i.Name, "VIDEO_TS.IFO", StringComparison.OrdinalIgnoreCase)) ??
  23. allFiles.FirstOrDefault(i => string.Equals(i.Name, "VIDEO_TS.BUP", StringComparison.OrdinalIgnoreCase));
  24. if (vmgPath == null)
  25. {
  26. var allIfos = allFiles.Where(i => string.Equals(i.Extension, ".ifo", StringComparison.OrdinalIgnoreCase));
  27. foreach (var ifo in allIfos)
  28. {
  29. var num = ifo.Name.Split('_').ElementAtOrDefault(1);
  30. ushort ifoNumber;
  31. var numbersRead = new List<ushort>();
  32. if (!string.IsNullOrEmpty(num) && ushort.TryParse(num, out ifoNumber) && !numbersRead.Contains(ifoNumber))
  33. {
  34. ReadVTS(ifoNumber, ifo.FullName);
  35. numbersRead.Add(ifoNumber);
  36. }
  37. }
  38. }
  39. else
  40. {
  41. using (var vmgFs = _fileSystem.GetFileStream(vmgPath.FullName, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read))
  42. {
  43. using (BigEndianBinaryReader vmgRead = new BigEndianBinaryReader(vmgFs))
  44. {
  45. vmgFs.Seek(0x3E, SeekOrigin.Begin);
  46. _titleSetCount = vmgRead.ReadUInt16();
  47. // read address of TT_SRPT
  48. vmgFs.Seek(0xC4, SeekOrigin.Begin);
  49. uint ttSectorPtr = vmgRead.ReadUInt32();
  50. vmgFs.Seek(ttSectorPtr * 2048, SeekOrigin.Begin);
  51. ReadTT_SRPT(vmgRead);
  52. }
  53. }
  54. for (ushort titleSetNum = 1; titleSetNum <= _titleSetCount; titleSetNum++)
  55. {
  56. ReadVTS(titleSetNum, allFiles);
  57. }
  58. }
  59. }
  60. private void ReadTT_SRPT(BinaryReader read)
  61. {
  62. _titleCount = read.ReadUInt16();
  63. read.BaseStream.Seek(6, SeekOrigin.Current);
  64. for (uint titleNum = 1; titleNum <= _titleCount; titleNum++)
  65. {
  66. Title t = new Title(titleNum);
  67. t.ParseTT_SRPT(read);
  68. Titles.Add(t);
  69. }
  70. }
  71. private void ReadVTS(ushort vtsNum, List<FileSystemMetadata> allFiles)
  72. {
  73. var filename = String.Format("VTS_{0:00}_0.IFO", vtsNum);
  74. var vtsPath = allFiles.FirstOrDefault(i => string.Equals(i.Name, filename, StringComparison.OrdinalIgnoreCase)) ??
  75. allFiles.FirstOrDefault(i => string.Equals(i.Name, Path.ChangeExtension(filename, ".bup"), StringComparison.OrdinalIgnoreCase));
  76. if (vtsPath == null)
  77. {
  78. throw new FileNotFoundException("Unable to find VTS IFO file");
  79. }
  80. ReadVTS(vtsNum, vtsPath.FullName);
  81. }
  82. private void ReadVTS(ushort vtsNum, string vtsPath)
  83. {
  84. VTSPaths[vtsNum] = vtsPath;
  85. using (var vtsFs = _fileSystem.GetFileStream(vtsPath, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read))
  86. {
  87. using (BigEndianBinaryReader vtsRead = new BigEndianBinaryReader(vtsFs))
  88. {
  89. // Read VTS_PTT_SRPT
  90. vtsFs.Seek(0xC8, SeekOrigin.Begin);
  91. uint vtsPttSrptSecPtr = vtsRead.ReadUInt32();
  92. uint baseAddr = (vtsPttSrptSecPtr * 2048);
  93. vtsFs.Seek(baseAddr, SeekOrigin.Begin);
  94. ushort numTitles = vtsRead.ReadUInt16();
  95. vtsRead.ReadUInt16();
  96. uint endaddr = vtsRead.ReadUInt32();
  97. uint[] offsets = new uint[numTitles];
  98. for (ushort titleNum = 0; titleNum < numTitles; titleNum++)
  99. {
  100. offsets[titleNum] = vtsRead.ReadUInt32();
  101. }
  102. for (uint titleNum = 0; titleNum < numTitles; titleNum++)
  103. {
  104. uint chapNum = 1;
  105. vtsFs.Seek(baseAddr + offsets[titleNum], SeekOrigin.Begin);
  106. Title t = Titles.FirstOrDefault(vtst => vtst.IsVTSTitle(vtsNum, titleNum + 1));
  107. if (t == null) continue;
  108. do
  109. {
  110. t.Chapters.Add(new Chapter(vtsRead.ReadUInt16(), vtsRead.ReadUInt16(), chapNum));
  111. if (titleNum + 1 < numTitles && vtsFs.Position == (baseAddr + offsets[titleNum + 1])) break;
  112. chapNum++;
  113. }
  114. while (vtsFs.Position < (baseAddr + endaddr));
  115. }
  116. // Read VTS_PGCI
  117. vtsFs.Seek(0xCC, SeekOrigin.Begin);
  118. uint vtsPgciSecPtr = vtsRead.ReadUInt32();
  119. vtsFs.Seek(vtsPgciSecPtr * 2048, SeekOrigin.Begin);
  120. long startByte = vtsFs.Position;
  121. ushort numPgcs = vtsRead.ReadUInt16();
  122. vtsFs.Seek(6, SeekOrigin.Current);
  123. for (ushort pgcNum = 1; pgcNum <= numPgcs; pgcNum++)
  124. {
  125. byte pgcCat = vtsRead.ReadByte();
  126. bool entryPgc = (pgcCat & 0x80) != 0;
  127. uint titleNum = (uint)(pgcCat & 0x7F);
  128. vtsFs.Seek(3, SeekOrigin.Current);
  129. uint vtsPgcOffset = vtsRead.ReadUInt32();
  130. Title t = Titles.FirstOrDefault(vtst => vtst.IsVTSTitle(vtsNum, titleNum));
  131. if (t != null) t.AddPgc(vtsRead, startByte + vtsPgcOffset, entryPgc, pgcNum);
  132. }
  133. }
  134. }
  135. }
  136. }
  137. }