BDROM.cs 16 KB

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