BDROM.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. //============================================================================
  2. // BDInfo - Blu-ray Video and Audio Analysis Tool
  3. // Copyright © 2010 Cinema Squid
  4. //
  5. // This library is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU Lesser General Public
  7. // License as published by the Free Software Foundation; either
  8. // version 2.1 of the License, or (at your option) any later version.
  9. //
  10. // This library is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. // Lesser General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU Lesser General Public
  16. // License along with this library; if not, write to the Free Software
  17. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. //=============================================================================
  19. using System;
  20. using System.Collections.Generic;
  21. using System.IO;
  22. using System.Linq;
  23. using MediaBrowser.Model.IO;
  24. using MediaBrowser.Model.Text;
  25. namespace BDInfo
  26. {
  27. public class BDROM
  28. {
  29. public FileSystemMetadata DirectoryRoot = null;
  30. public FileSystemMetadata DirectoryBDMV = null;
  31. public FileSystemMetadata DirectoryBDJO = null;
  32. public FileSystemMetadata DirectoryCLIPINF = null;
  33. public FileSystemMetadata DirectoryPLAYLIST = null;
  34. public FileSystemMetadata DirectorySNP = null;
  35. public FileSystemMetadata DirectorySSIF = null;
  36. public FileSystemMetadata DirectorySTREAM = null;
  37. public string VolumeLabel = null;
  38. public ulong Size = 0;
  39. public bool IsBDPlus = false;
  40. public bool IsBDJava = false;
  41. public bool IsDBOX = false;
  42. public bool IsPSP = false;
  43. public bool Is3D = false;
  44. public bool Is50Hz = false;
  45. private readonly IFileSystem _fileSystem;
  46. public Dictionary<string, TSPlaylistFile> PlaylistFiles =
  47. new Dictionary<string, TSPlaylistFile>();
  48. public Dictionary<string, TSStreamClipFile> StreamClipFiles =
  49. new Dictionary<string, TSStreamClipFile>();
  50. public Dictionary<string, TSStreamFile> StreamFiles =
  51. new Dictionary<string, TSStreamFile>();
  52. public Dictionary<string, TSInterleavedFile> InterleavedFiles =
  53. new Dictionary<string, TSInterleavedFile>();
  54. private static List<string> ExcludeDirs = new List<string> { "ANY!", "AACS", "BDSVM", "ANYVM", "SLYVM" };
  55. public delegate bool OnStreamClipFileScanError(
  56. TSStreamClipFile streamClipFile, Exception ex);
  57. public event OnStreamClipFileScanError StreamClipFileScanError;
  58. public delegate bool OnStreamFileScanError(
  59. TSStreamFile streamClipFile, Exception ex);
  60. public event OnStreamFileScanError StreamFileScanError;
  61. public delegate bool OnPlaylistFileScanError(
  62. TSPlaylistFile playlistFile, Exception ex);
  63. public event OnPlaylistFileScanError PlaylistFileScanError;
  64. public BDROM(
  65. string path, IFileSystem fileSystem, ITextEncoding textEncoding)
  66. {
  67. if (string.IsNullOrWhiteSpace(path))
  68. {
  69. throw new ArgumentNullException("path");
  70. }
  71. _fileSystem = fileSystem;
  72. //
  73. // Locate BDMV directories.
  74. //
  75. DirectoryBDMV =
  76. GetDirectoryBDMV(path);
  77. if (DirectoryBDMV == null)
  78. {
  79. throw new Exception("Unable to locate BD structure.");
  80. }
  81. DirectoryRoot =
  82. _fileSystem.GetDirectoryInfo(_fileSystem.GetDirectoryName(DirectoryBDMV.FullName));
  83. DirectoryBDJO =
  84. GetDirectory("BDJO", DirectoryBDMV, 0);
  85. DirectoryCLIPINF =
  86. GetDirectory("CLIPINF", DirectoryBDMV, 0);
  87. DirectoryPLAYLIST =
  88. GetDirectory("PLAYLIST", DirectoryBDMV, 0);
  89. DirectorySNP =
  90. GetDirectory("SNP", DirectoryRoot, 0);
  91. DirectorySTREAM =
  92. GetDirectory("STREAM", DirectoryBDMV, 0);
  93. DirectorySSIF =
  94. GetDirectory("SSIF", DirectorySTREAM, 0);
  95. if (DirectoryCLIPINF == null
  96. || DirectoryPLAYLIST == null)
  97. {
  98. throw new Exception("Unable to locate BD structure.");
  99. }
  100. //
  101. // Initialize basic disc properties.
  102. //
  103. VolumeLabel = GetVolumeLabel(DirectoryRoot);
  104. Size = (ulong)GetDirectorySize(DirectoryRoot);
  105. if (null != GetDirectory("BDSVM", DirectoryRoot, 0))
  106. {
  107. IsBDPlus = true;
  108. }
  109. if (null != GetDirectory("SLYVM", DirectoryRoot, 0))
  110. {
  111. IsBDPlus = true;
  112. }
  113. if (null != GetDirectory("ANYVM", DirectoryRoot, 0))
  114. {
  115. IsBDPlus = true;
  116. }
  117. if (DirectoryBDJO != null &&
  118. _fileSystem.GetFilePaths(DirectoryBDJO.FullName).Any())
  119. {
  120. IsBDJava = true;
  121. }
  122. if (DirectorySNP != null &&
  123. GetFilePaths(DirectorySNP.FullName, ".mnv").Any())
  124. {
  125. IsPSP = true;
  126. }
  127. if (DirectorySSIF != null &&
  128. _fileSystem.GetFilePaths(DirectorySSIF.FullName).Any())
  129. {
  130. Is3D = true;
  131. }
  132. if (_fileSystem.FileExists(Path.Combine(DirectoryRoot.FullName, "FilmIndex.xml")))
  133. {
  134. IsDBOX = true;
  135. }
  136. //
  137. // Initialize file lists.
  138. //
  139. if (DirectoryPLAYLIST != null)
  140. {
  141. FileSystemMetadata[] files = GetFiles(DirectoryPLAYLIST.FullName, ".mpls").ToArray();
  142. foreach (FileSystemMetadata file in files)
  143. {
  144. PlaylistFiles.Add(
  145. file.Name.ToUpper(), new TSPlaylistFile(this, file, _fileSystem, textEncoding));
  146. }
  147. }
  148. if (DirectorySTREAM != null)
  149. {
  150. FileSystemMetadata[] files = GetFiles(DirectorySTREAM.FullName, ".m2ts").ToArray();
  151. foreach (FileSystemMetadata file in files)
  152. {
  153. StreamFiles.Add(
  154. file.Name.ToUpper(), new TSStreamFile(file, _fileSystem));
  155. }
  156. }
  157. if (DirectoryCLIPINF != null)
  158. {
  159. FileSystemMetadata[] files = GetFiles(DirectoryCLIPINF.FullName, ".clpi").ToArray();
  160. foreach (FileSystemMetadata file in files)
  161. {
  162. StreamClipFiles.Add(
  163. file.Name.ToUpper(), new TSStreamClipFile(file, _fileSystem, textEncoding));
  164. }
  165. }
  166. if (DirectorySSIF != null)
  167. {
  168. FileSystemMetadata[] files = GetFiles(DirectorySSIF.FullName, ".ssif").ToArray();
  169. foreach (FileSystemMetadata file in files)
  170. {
  171. InterleavedFiles.Add(
  172. file.Name.ToUpper(), new TSInterleavedFile(file));
  173. }
  174. }
  175. }
  176. private IEnumerable<FileSystemMetadata> GetFiles(string path, string extension)
  177. {
  178. return _fileSystem.GetFiles(path, new[] { extension }, false, false);
  179. }
  180. private IEnumerable<string> GetFilePaths(string path, string extension)
  181. {
  182. return _fileSystem.GetFilePaths(path, new[] { extension }, false, false);
  183. }
  184. public void Scan()
  185. {
  186. List<TSStreamClipFile> errorStreamClipFiles = new List<TSStreamClipFile>();
  187. foreach (TSStreamClipFile streamClipFile in StreamClipFiles.Values)
  188. {
  189. try
  190. {
  191. streamClipFile.Scan();
  192. }
  193. catch (Exception ex)
  194. {
  195. errorStreamClipFiles.Add(streamClipFile);
  196. if (StreamClipFileScanError != null)
  197. {
  198. if (StreamClipFileScanError(streamClipFile, ex))
  199. {
  200. continue;
  201. }
  202. else
  203. {
  204. break;
  205. }
  206. }
  207. else throw ex;
  208. }
  209. }
  210. foreach (TSStreamFile streamFile in StreamFiles.Values)
  211. {
  212. string ssifName = Path.GetFileNameWithoutExtension(streamFile.Name) + ".SSIF";
  213. if (InterleavedFiles.ContainsKey(ssifName))
  214. {
  215. streamFile.InterleavedFile = InterleavedFiles[ssifName];
  216. }
  217. }
  218. TSStreamFile[] streamFiles = new TSStreamFile[StreamFiles.Count];
  219. StreamFiles.Values.CopyTo(streamFiles, 0);
  220. Array.Sort(streamFiles, CompareStreamFiles);
  221. List<TSPlaylistFile> errorPlaylistFiles = new List<TSPlaylistFile>();
  222. foreach (TSPlaylistFile playlistFile in PlaylistFiles.Values)
  223. {
  224. try
  225. {
  226. playlistFile.Scan(StreamFiles, StreamClipFiles);
  227. }
  228. catch (Exception ex)
  229. {
  230. errorPlaylistFiles.Add(playlistFile);
  231. if (PlaylistFileScanError != null)
  232. {
  233. if (PlaylistFileScanError(playlistFile, ex))
  234. {
  235. continue;
  236. }
  237. else
  238. {
  239. break;
  240. }
  241. }
  242. else throw ex;
  243. }
  244. }
  245. List<TSStreamFile> errorStreamFiles = new List<TSStreamFile>();
  246. foreach (TSStreamFile streamFile in streamFiles)
  247. {
  248. try
  249. {
  250. List<TSPlaylistFile> playlists = new List<TSPlaylistFile>();
  251. foreach (TSPlaylistFile playlist in PlaylistFiles.Values)
  252. {
  253. foreach (TSStreamClip streamClip in playlist.StreamClips)
  254. {
  255. if (streamClip.Name == streamFile.Name)
  256. {
  257. playlists.Add(playlist);
  258. break;
  259. }
  260. }
  261. }
  262. streamFile.Scan(playlists, false);
  263. }
  264. catch (Exception ex)
  265. {
  266. errorStreamFiles.Add(streamFile);
  267. if (StreamFileScanError != null)
  268. {
  269. if (StreamFileScanError(streamFile, ex))
  270. {
  271. continue;
  272. }
  273. else
  274. {
  275. break;
  276. }
  277. }
  278. else throw ex;
  279. }
  280. }
  281. foreach (TSPlaylistFile playlistFile in PlaylistFiles.Values)
  282. {
  283. playlistFile.Initialize();
  284. if (!Is50Hz)
  285. {
  286. foreach (TSVideoStream videoStream in playlistFile.VideoStreams)
  287. {
  288. if (videoStream.FrameRate == TSFrameRate.FRAMERATE_25 ||
  289. videoStream.FrameRate == TSFrameRate.FRAMERATE_50)
  290. {
  291. Is50Hz = true;
  292. }
  293. }
  294. }
  295. }
  296. }
  297. private FileSystemMetadata GetDirectoryBDMV(
  298. string path)
  299. {
  300. if (string.IsNullOrWhiteSpace(path))
  301. {
  302. throw new ArgumentNullException("path");
  303. }
  304. FileSystemMetadata dir = _fileSystem.GetDirectoryInfo(path);
  305. while (dir != null)
  306. {
  307. if (string.Equals(dir.Name, "BDMV", StringComparison.OrdinalIgnoreCase))
  308. {
  309. return dir;
  310. }
  311. var parentFolder = _fileSystem.GetDirectoryName(dir.FullName);
  312. if (string.IsNullOrEmpty(parentFolder))
  313. {
  314. dir = null;
  315. }
  316. else
  317. {
  318. dir = _fileSystem.GetDirectoryInfo(parentFolder);
  319. }
  320. }
  321. return GetDirectory("BDMV", _fileSystem.GetDirectoryInfo(path), 0);
  322. }
  323. private FileSystemMetadata GetDirectory(
  324. string name,
  325. FileSystemMetadata dir,
  326. int searchDepth)
  327. {
  328. if (dir != null)
  329. {
  330. FileSystemMetadata[] children = _fileSystem.GetDirectories(dir.FullName).ToArray();
  331. foreach (FileSystemMetadata child in children)
  332. {
  333. if (string.Equals(child.Name, name, StringComparison.OrdinalIgnoreCase))
  334. {
  335. return child;
  336. }
  337. }
  338. if (searchDepth > 0)
  339. {
  340. foreach (FileSystemMetadata child in children)
  341. {
  342. GetDirectory(
  343. name, child, searchDepth - 1);
  344. }
  345. }
  346. }
  347. return null;
  348. }
  349. private long GetDirectorySize(FileSystemMetadata directoryInfo)
  350. {
  351. long size = 0;
  352. //if (!ExcludeDirs.Contains(directoryInfo.Name.ToUpper())) // TODO: Keep?
  353. {
  354. FileSystemMetadata[] pathFiles = _fileSystem.GetFiles(directoryInfo.FullName).ToArray();
  355. foreach (FileSystemMetadata pathFile in pathFiles)
  356. {
  357. if (pathFile.Extension.ToUpper() == ".SSIF")
  358. {
  359. continue;
  360. }
  361. size += pathFile.Length;
  362. }
  363. FileSystemMetadata[] pathChildren = _fileSystem.GetDirectories(directoryInfo.FullName).ToArray();
  364. foreach (FileSystemMetadata pathChild in pathChildren)
  365. {
  366. size += GetDirectorySize(pathChild);
  367. }
  368. }
  369. return size;
  370. }
  371. private string GetVolumeLabel(FileSystemMetadata dir)
  372. {
  373. return dir.Name;
  374. }
  375. public static int CompareStreamFiles(
  376. TSStreamFile x,
  377. TSStreamFile y)
  378. {
  379. // TODO: Use interleaved file sizes
  380. if ((x == null || x.FileInfo == null) && (y == null || y.FileInfo == null))
  381. {
  382. return 0;
  383. }
  384. else if ((x == null || x.FileInfo == null) && (y != null && y.FileInfo != null))
  385. {
  386. return 1;
  387. }
  388. else if ((x != null || x.FileInfo != null) && (y == null || y.FileInfo == null))
  389. {
  390. return -1;
  391. }
  392. else
  393. {
  394. if (x.FileInfo.Length > y.FileInfo.Length)
  395. {
  396. return 1;
  397. }
  398. else if (y.FileInfo.Length > x.FileInfo.Length)
  399. {
  400. return -1;
  401. }
  402. else
  403. {
  404. return 0;
  405. }
  406. }
  407. }
  408. }
  409. }