BDROM.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  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(Path.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.GetFiles(DirectoryBDJO.FullName).Any())
  119. {
  120. IsBDJava = true;
  121. }
  122. if (DirectorySNP != null &&
  123. GetFiles(DirectorySNP.FullName, ".mnv").Any())
  124. {
  125. IsPSP = true;
  126. }
  127. if (DirectorySSIF != null &&
  128. _fileSystem.GetFiles(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).Where(i => string.Equals(i.Extension, extension, StringComparison.OrdinalIgnoreCase));
  179. }
  180. public void Scan()
  181. {
  182. List<TSStreamClipFile> errorStreamClipFiles = new List<TSStreamClipFile>();
  183. foreach (TSStreamClipFile streamClipFile in StreamClipFiles.Values)
  184. {
  185. try
  186. {
  187. streamClipFile.Scan();
  188. }
  189. catch (Exception ex)
  190. {
  191. errorStreamClipFiles.Add(streamClipFile);
  192. if (StreamClipFileScanError != null)
  193. {
  194. if (StreamClipFileScanError(streamClipFile, ex))
  195. {
  196. continue;
  197. }
  198. else
  199. {
  200. break;
  201. }
  202. }
  203. else throw ex;
  204. }
  205. }
  206. foreach (TSStreamFile streamFile in StreamFiles.Values)
  207. {
  208. string ssifName = Path.GetFileNameWithoutExtension(streamFile.Name) + ".SSIF";
  209. if (InterleavedFiles.ContainsKey(ssifName))
  210. {
  211. streamFile.InterleavedFile = InterleavedFiles[ssifName];
  212. }
  213. }
  214. TSStreamFile[] streamFiles = new TSStreamFile[StreamFiles.Count];
  215. StreamFiles.Values.CopyTo(streamFiles, 0);
  216. Array.Sort(streamFiles, CompareStreamFiles);
  217. List<TSPlaylistFile> errorPlaylistFiles = new List<TSPlaylistFile>();
  218. foreach (TSPlaylistFile playlistFile in PlaylistFiles.Values)
  219. {
  220. try
  221. {
  222. playlistFile.Scan(StreamFiles, StreamClipFiles);
  223. }
  224. catch (Exception ex)
  225. {
  226. errorPlaylistFiles.Add(playlistFile);
  227. if (PlaylistFileScanError != null)
  228. {
  229. if (PlaylistFileScanError(playlistFile, ex))
  230. {
  231. continue;
  232. }
  233. else
  234. {
  235. break;
  236. }
  237. }
  238. else throw ex;
  239. }
  240. }
  241. List<TSStreamFile> errorStreamFiles = new List<TSStreamFile>();
  242. foreach (TSStreamFile streamFile in streamFiles)
  243. {
  244. try
  245. {
  246. List<TSPlaylistFile> playlists = new List<TSPlaylistFile>();
  247. foreach (TSPlaylistFile playlist in PlaylistFiles.Values)
  248. {
  249. foreach (TSStreamClip streamClip in playlist.StreamClips)
  250. {
  251. if (streamClip.Name == streamFile.Name)
  252. {
  253. playlists.Add(playlist);
  254. break;
  255. }
  256. }
  257. }
  258. streamFile.Scan(playlists, false);
  259. }
  260. catch (Exception ex)
  261. {
  262. errorStreamFiles.Add(streamFile);
  263. if (StreamFileScanError != null)
  264. {
  265. if (StreamFileScanError(streamFile, ex))
  266. {
  267. continue;
  268. }
  269. else
  270. {
  271. break;
  272. }
  273. }
  274. else throw ex;
  275. }
  276. }
  277. foreach (TSPlaylistFile playlistFile in PlaylistFiles.Values)
  278. {
  279. playlistFile.Initialize();
  280. if (!Is50Hz)
  281. {
  282. foreach (TSVideoStream videoStream in playlistFile.VideoStreams)
  283. {
  284. if (videoStream.FrameRate == TSFrameRate.FRAMERATE_25 ||
  285. videoStream.FrameRate == TSFrameRate.FRAMERATE_50)
  286. {
  287. Is50Hz = true;
  288. }
  289. }
  290. }
  291. }
  292. }
  293. private FileSystemMetadata GetDirectoryBDMV(
  294. string path)
  295. {
  296. if (string.IsNullOrWhiteSpace(path))
  297. {
  298. throw new ArgumentNullException("path");
  299. }
  300. FileSystemMetadata dir = _fileSystem.GetDirectoryInfo(path);
  301. while (dir != null)
  302. {
  303. if (string.Equals(dir.Name, "BDMV", StringComparison.OrdinalIgnoreCase))
  304. {
  305. return dir;
  306. }
  307. var parentFolder = Path.GetDirectoryName(dir.FullName);
  308. if (string.IsNullOrEmpty(parentFolder))
  309. {
  310. dir = null;
  311. }
  312. else
  313. {
  314. dir = _fileSystem.GetDirectoryInfo(parentFolder);
  315. }
  316. }
  317. return GetDirectory("BDMV", _fileSystem.GetDirectoryInfo(path), 0);
  318. }
  319. private FileSystemMetadata GetDirectory(
  320. string name,
  321. FileSystemMetadata dir,
  322. int searchDepth)
  323. {
  324. if (dir != null)
  325. {
  326. FileSystemMetadata[] children = _fileSystem.GetDirectories(dir.FullName).ToArray();
  327. foreach (FileSystemMetadata child in children)
  328. {
  329. if (string.Equals(child.Name, name, StringComparison.OrdinalIgnoreCase))
  330. {
  331. return child;
  332. }
  333. }
  334. if (searchDepth > 0)
  335. {
  336. foreach (FileSystemMetadata child in children)
  337. {
  338. GetDirectory(
  339. name, child, searchDepth - 1);
  340. }
  341. }
  342. }
  343. return null;
  344. }
  345. private long GetDirectorySize(FileSystemMetadata directoryInfo)
  346. {
  347. long size = 0;
  348. //if (!ExcludeDirs.Contains(directoryInfo.Name.ToUpper())) // TODO: Keep?
  349. {
  350. FileSystemMetadata[] pathFiles = _fileSystem.GetFiles(directoryInfo.FullName).ToArray();
  351. foreach (FileSystemMetadata pathFile in pathFiles)
  352. {
  353. if (pathFile.Extension.ToUpper() == ".SSIF")
  354. {
  355. continue;
  356. }
  357. size += pathFile.Length;
  358. }
  359. FileSystemMetadata[] pathChildren = _fileSystem.GetDirectories(directoryInfo.FullName).ToArray();
  360. foreach (FileSystemMetadata pathChild in pathChildren)
  361. {
  362. size += GetDirectorySize(pathChild);
  363. }
  364. }
  365. return size;
  366. }
  367. private string GetVolumeLabel(FileSystemMetadata dir)
  368. {
  369. return dir.Name;
  370. }
  371. public static int CompareStreamFiles(
  372. TSStreamFile x,
  373. TSStreamFile y)
  374. {
  375. // TODO: Use interleaved file sizes
  376. if ((x == null || x.FileInfo == null) && (y == null || y.FileInfo == null))
  377. {
  378. return 0;
  379. }
  380. else if ((x == null || x.FileInfo == null) && (y != null && y.FileInfo != null))
  381. {
  382. return 1;
  383. }
  384. else if ((x != null || x.FileInfo != null) && (y == null || y.FileInfo == null))
  385. {
  386. return -1;
  387. }
  388. else
  389. {
  390. if (x.FileInfo.Length > y.FileInfo.Length)
  391. {
  392. return 1;
  393. }
  394. else if (y.FileInfo.Length > x.FileInfo.Length)
  395. {
  396. return -1;
  397. }
  398. else
  399. {
  400. return 0;
  401. }
  402. }
  403. }
  404. }
  405. }