BDROM.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  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. public delegate bool OnStreamClipFileScanError(
  55. TSStreamClipFile streamClipFile, Exception ex);
  56. public event OnStreamClipFileScanError StreamClipFileScanError;
  57. public delegate bool OnStreamFileScanError(
  58. TSStreamFile streamClipFile, Exception ex);
  59. public event OnStreamFileScanError StreamFileScanError;
  60. public delegate bool OnPlaylistFileScanError(
  61. TSPlaylistFile playlistFile, Exception ex);
  62. public event OnPlaylistFileScanError PlaylistFileScanError;
  63. public BDROM(
  64. string path, IFileSystem fileSystem, ITextEncoding textEncoding)
  65. {
  66. if (string.IsNullOrEmpty(path))
  67. {
  68. throw new ArgumentNullException("path");
  69. }
  70. _fileSystem = fileSystem;
  71. //
  72. // Locate BDMV directories.
  73. //
  74. DirectoryBDMV =
  75. GetDirectoryBDMV(path);
  76. if (DirectoryBDMV == null)
  77. {
  78. throw new Exception("Unable to locate BD structure.");
  79. }
  80. DirectoryRoot =
  81. _fileSystem.GetDirectoryInfo(_fileSystem.GetDirectoryName(DirectoryBDMV.FullName));
  82. DirectoryBDJO =
  83. GetDirectory("BDJO", DirectoryBDMV, 0);
  84. DirectoryCLIPINF =
  85. GetDirectory("CLIPINF", DirectoryBDMV, 0);
  86. DirectoryPLAYLIST =
  87. GetDirectory("PLAYLIST", DirectoryBDMV, 0);
  88. DirectorySNP =
  89. GetDirectory("SNP", DirectoryRoot, 0);
  90. DirectorySTREAM =
  91. GetDirectory("STREAM", DirectoryBDMV, 0);
  92. DirectorySSIF =
  93. GetDirectory("SSIF", DirectorySTREAM, 0);
  94. if (DirectoryCLIPINF == null
  95. || DirectoryPLAYLIST == null)
  96. {
  97. throw new Exception("Unable to locate BD structure.");
  98. }
  99. //
  100. // Initialize basic disc properties.
  101. //
  102. VolumeLabel = GetVolumeLabel(DirectoryRoot);
  103. Size = (ulong)GetDirectorySize(DirectoryRoot);
  104. if (null != GetDirectory("BDSVM", DirectoryRoot, 0))
  105. {
  106. IsBDPlus = true;
  107. }
  108. if (null != GetDirectory("SLYVM", DirectoryRoot, 0))
  109. {
  110. IsBDPlus = true;
  111. }
  112. if (null != GetDirectory("ANYVM", DirectoryRoot, 0))
  113. {
  114. IsBDPlus = true;
  115. }
  116. if (DirectoryBDJO != null &&
  117. _fileSystem.GetFilePaths(DirectoryBDJO.FullName).Any())
  118. {
  119. IsBDJava = true;
  120. }
  121. if (DirectorySNP != null &&
  122. GetFilePaths(DirectorySNP.FullName, ".mnv").Any())
  123. {
  124. IsPSP = true;
  125. }
  126. if (DirectorySSIF != null &&
  127. _fileSystem.GetFilePaths(DirectorySSIF.FullName).Any())
  128. {
  129. Is3D = true;
  130. }
  131. if (_fileSystem.FileExists(Path.Combine(DirectoryRoot.FullName, "FilmIndex.xml")))
  132. {
  133. IsDBOX = true;
  134. }
  135. //
  136. // Initialize file lists.
  137. //
  138. if (DirectoryPLAYLIST != null)
  139. {
  140. FileSystemMetadata[] files = GetFiles(DirectoryPLAYLIST.FullName, ".mpls").ToArray();
  141. foreach (FileSystemMetadata file in files)
  142. {
  143. PlaylistFiles.Add(
  144. file.Name.ToUpper(), new TSPlaylistFile(this, file, _fileSystem, textEncoding));
  145. }
  146. }
  147. if (DirectorySTREAM != null)
  148. {
  149. FileSystemMetadata[] files = GetFiles(DirectorySTREAM.FullName, ".m2ts").ToArray();
  150. foreach (FileSystemMetadata file in files)
  151. {
  152. StreamFiles.Add(
  153. file.Name.ToUpper(), new TSStreamFile(file, _fileSystem));
  154. }
  155. }
  156. if (DirectoryCLIPINF != null)
  157. {
  158. FileSystemMetadata[] files = GetFiles(DirectoryCLIPINF.FullName, ".clpi").ToArray();
  159. foreach (FileSystemMetadata file in files)
  160. {
  161. StreamClipFiles.Add(
  162. file.Name.ToUpper(), new TSStreamClipFile(file, _fileSystem, textEncoding));
  163. }
  164. }
  165. if (DirectorySSIF != null)
  166. {
  167. FileSystemMetadata[] files = GetFiles(DirectorySSIF.FullName, ".ssif").ToArray();
  168. foreach (FileSystemMetadata file in files)
  169. {
  170. InterleavedFiles.Add(
  171. file.Name.ToUpper(), new TSInterleavedFile(file));
  172. }
  173. }
  174. }
  175. private IEnumerable<FileSystemMetadata> GetFiles(string path, string extension)
  176. {
  177. return _fileSystem.GetFiles(path, new[] { extension }, false, false);
  178. }
  179. private IEnumerable<string> GetFilePaths(string path, string extension)
  180. {
  181. return _fileSystem.GetFilePaths(path, new[] { extension }, false, false);
  182. }
  183. public void Scan()
  184. {
  185. List<TSStreamClipFile> errorStreamClipFiles = new List<TSStreamClipFile>();
  186. foreach (TSStreamClipFile streamClipFile in StreamClipFiles.Values)
  187. {
  188. try
  189. {
  190. streamClipFile.Scan();
  191. }
  192. catch (Exception ex)
  193. {
  194. errorStreamClipFiles.Add(streamClipFile);
  195. if (StreamClipFileScanError != null)
  196. {
  197. if (StreamClipFileScanError(streamClipFile, ex))
  198. {
  199. continue;
  200. }
  201. else
  202. {
  203. break;
  204. }
  205. }
  206. else throw ex;
  207. }
  208. }
  209. foreach (TSStreamFile streamFile in StreamFiles.Values)
  210. {
  211. string ssifName = Path.GetFileNameWithoutExtension(streamFile.Name) + ".SSIF";
  212. if (InterleavedFiles.ContainsKey(ssifName))
  213. {
  214. streamFile.InterleavedFile = InterleavedFiles[ssifName];
  215. }
  216. }
  217. TSStreamFile[] streamFiles = new TSStreamFile[StreamFiles.Count];
  218. StreamFiles.Values.CopyTo(streamFiles, 0);
  219. Array.Sort(streamFiles, CompareStreamFiles);
  220. List<TSPlaylistFile> errorPlaylistFiles = new List<TSPlaylistFile>();
  221. foreach (TSPlaylistFile playlistFile in PlaylistFiles.Values)
  222. {
  223. try
  224. {
  225. playlistFile.Scan(StreamFiles, StreamClipFiles);
  226. }
  227. catch (Exception ex)
  228. {
  229. errorPlaylistFiles.Add(playlistFile);
  230. if (PlaylistFileScanError != null)
  231. {
  232. if (PlaylistFileScanError(playlistFile, ex))
  233. {
  234. continue;
  235. }
  236. else
  237. {
  238. break;
  239. }
  240. }
  241. else throw ex;
  242. }
  243. }
  244. List<TSStreamFile> errorStreamFiles = new List<TSStreamFile>();
  245. foreach (TSStreamFile streamFile in streamFiles)
  246. {
  247. try
  248. {
  249. List<TSPlaylistFile> playlists = new List<TSPlaylistFile>();
  250. foreach (TSPlaylistFile playlist in PlaylistFiles.Values)
  251. {
  252. foreach (TSStreamClip streamClip in playlist.StreamClips)
  253. {
  254. if (streamClip.Name == streamFile.Name)
  255. {
  256. playlists.Add(playlist);
  257. break;
  258. }
  259. }
  260. }
  261. streamFile.Scan(playlists, false);
  262. }
  263. catch (Exception ex)
  264. {
  265. errorStreamFiles.Add(streamFile);
  266. if (StreamFileScanError != null)
  267. {
  268. if (StreamFileScanError(streamFile, ex))
  269. {
  270. continue;
  271. }
  272. else
  273. {
  274. break;
  275. }
  276. }
  277. else throw ex;
  278. }
  279. }
  280. foreach (TSPlaylistFile playlistFile in PlaylistFiles.Values)
  281. {
  282. playlistFile.Initialize();
  283. if (!Is50Hz)
  284. {
  285. foreach (TSVideoStream videoStream in playlistFile.VideoStreams)
  286. {
  287. if (videoStream.FrameRate == TSFrameRate.FRAMERATE_25 ||
  288. videoStream.FrameRate == TSFrameRate.FRAMERATE_50)
  289. {
  290. Is50Hz = true;
  291. }
  292. }
  293. }
  294. }
  295. }
  296. private FileSystemMetadata GetDirectoryBDMV(
  297. string path)
  298. {
  299. if (string.IsNullOrEmpty(path))
  300. {
  301. throw new ArgumentNullException("path");
  302. }
  303. FileSystemMetadata dir = _fileSystem.GetDirectoryInfo(path);
  304. while (dir != null)
  305. {
  306. if (string.Equals(dir.Name, "BDMV", StringComparison.OrdinalIgnoreCase))
  307. {
  308. return dir;
  309. }
  310. var parentFolder = _fileSystem.GetDirectoryName(dir.FullName);
  311. if (string.IsNullOrEmpty(parentFolder))
  312. {
  313. dir = null;
  314. }
  315. else
  316. {
  317. dir = _fileSystem.GetDirectoryInfo(parentFolder);
  318. }
  319. }
  320. return GetDirectory("BDMV", _fileSystem.GetDirectoryInfo(path), 0);
  321. }
  322. private FileSystemMetadata GetDirectory(
  323. string name,
  324. FileSystemMetadata dir,
  325. int searchDepth)
  326. {
  327. if (dir != null)
  328. {
  329. FileSystemMetadata[] children = _fileSystem.GetDirectories(dir.FullName).ToArray();
  330. foreach (FileSystemMetadata child in children)
  331. {
  332. if (string.Equals(child.Name, name, StringComparison.OrdinalIgnoreCase))
  333. {
  334. return child;
  335. }
  336. }
  337. if (searchDepth > 0)
  338. {
  339. foreach (FileSystemMetadata child in children)
  340. {
  341. GetDirectory(
  342. name, child, searchDepth - 1);
  343. }
  344. }
  345. }
  346. return null;
  347. }
  348. private long GetDirectorySize(FileSystemMetadata directoryInfo)
  349. {
  350. long size = 0;
  351. //if (!ExcludeDirs.Contains(directoryInfo.Name.ToUpper())) // TODO: Keep?
  352. {
  353. FileSystemMetadata[] pathFiles = _fileSystem.GetFiles(directoryInfo.FullName).ToArray();
  354. foreach (FileSystemMetadata pathFile in pathFiles)
  355. {
  356. if (pathFile.Extension.ToUpper() == ".SSIF")
  357. {
  358. continue;
  359. }
  360. size += pathFile.Length;
  361. }
  362. FileSystemMetadata[] pathChildren = _fileSystem.GetDirectories(directoryInfo.FullName).ToArray();
  363. foreach (FileSystemMetadata pathChild in pathChildren)
  364. {
  365. size += GetDirectorySize(pathChild);
  366. }
  367. }
  368. return size;
  369. }
  370. private string GetVolumeLabel(FileSystemMetadata dir)
  371. {
  372. return dir.Name;
  373. }
  374. public int CompareStreamFiles(
  375. TSStreamFile x,
  376. TSStreamFile y)
  377. {
  378. // TODO: Use interleaved file sizes
  379. if ((x == null || x.FileInfo == null) && (y == null || y.FileInfo == null))
  380. {
  381. return 0;
  382. }
  383. else if ((x == null || x.FileInfo == null) && (y != null && y.FileInfo != null))
  384. {
  385. return 1;
  386. }
  387. else if ((x != null || x.FileInfo != null) && (y == null || y.FileInfo == null))
  388. {
  389. return -1;
  390. }
  391. else
  392. {
  393. if (x.FileInfo.Length > y.FileInfo.Length)
  394. {
  395. return 1;
  396. }
  397. else if (y.FileInfo.Length > x.FileInfo.Length)
  398. {
  399. return -1;
  400. }
  401. else
  402. {
  403. return 0;
  404. }
  405. }
  406. }
  407. }
  408. }