TSPlaylistFile.cs 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284
  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. #undef DEBUG
  20. using System;
  21. using System.Collections.Generic;
  22. using System.IO;
  23. using System.Text;
  24. namespace BDInfo
  25. {
  26. public class TSPlaylistFile
  27. {
  28. private FileInfo FileInfo = null;
  29. public string FileType = null;
  30. public bool IsInitialized = false;
  31. public string Name = null;
  32. public BDROM BDROM = null;
  33. public bool HasHiddenTracks = false;
  34. public bool HasLoops = false;
  35. public bool IsCustom = false;
  36. public List<double> Chapters = new List<double>();
  37. public Dictionary<ushort, TSStream> Streams =
  38. new Dictionary<ushort, TSStream>();
  39. public Dictionary<ushort, TSStream> PlaylistStreams =
  40. new Dictionary<ushort, TSStream>();
  41. public List<TSStreamClip> StreamClips =
  42. new List<TSStreamClip>();
  43. public List<Dictionary<ushort, TSStream>> AngleStreams =
  44. new List<Dictionary<ushort, TSStream>>();
  45. public List<Dictionary<double, TSStreamClip>> AngleClips =
  46. new List<Dictionary<double, TSStreamClip>>();
  47. public int AngleCount = 0;
  48. public List<TSStream> SortedStreams =
  49. new List<TSStream>();
  50. public List<TSVideoStream> VideoStreams =
  51. new List<TSVideoStream>();
  52. public List<TSAudioStream> AudioStreams =
  53. new List<TSAudioStream>();
  54. public List<TSTextStream> TextStreams =
  55. new List<TSTextStream>();
  56. public List<TSGraphicsStream> GraphicsStreams =
  57. new List<TSGraphicsStream>();
  58. public TSPlaylistFile(
  59. BDROM bdrom,
  60. FileInfo fileInfo)
  61. {
  62. BDROM = bdrom;
  63. FileInfo = fileInfo;
  64. Name = fileInfo.Name.ToUpper();
  65. }
  66. public TSPlaylistFile(
  67. BDROM bdrom,
  68. string name,
  69. List<TSStreamClip> clips)
  70. {
  71. BDROM = bdrom;
  72. Name = name;
  73. IsCustom = true;
  74. foreach (TSStreamClip clip in clips)
  75. {
  76. TSStreamClip newClip = new TSStreamClip(
  77. clip.StreamFile, clip.StreamClipFile);
  78. newClip.Name = clip.Name;
  79. newClip.TimeIn = clip.TimeIn;
  80. newClip.TimeOut = clip.TimeOut;
  81. newClip.Length = newClip.TimeOut - newClip.TimeIn;
  82. newClip.RelativeTimeIn = TotalLength;
  83. newClip.RelativeTimeOut = newClip.RelativeTimeIn + newClip.Length;
  84. newClip.AngleIndex = clip.AngleIndex;
  85. newClip.Chapters.Add(clip.TimeIn);
  86. StreamClips.Add(newClip);
  87. if (newClip.AngleIndex > AngleCount)
  88. {
  89. AngleCount = newClip.AngleIndex;
  90. }
  91. if (newClip.AngleIndex == 0)
  92. {
  93. Chapters.Add(newClip.RelativeTimeIn);
  94. }
  95. }
  96. LoadStreamClips();
  97. IsInitialized = true;
  98. }
  99. public override string ToString()
  100. {
  101. return Name;
  102. }
  103. public ulong InterleavedFileSize
  104. {
  105. get
  106. {
  107. ulong size = 0;
  108. foreach (TSStreamClip clip in StreamClips)
  109. {
  110. size += clip.InterleavedFileSize;
  111. }
  112. return size;
  113. }
  114. }
  115. public ulong FileSize
  116. {
  117. get
  118. {
  119. ulong size = 0;
  120. foreach (TSStreamClip clip in StreamClips)
  121. {
  122. size += clip.FileSize;
  123. }
  124. return size;
  125. }
  126. }
  127. public double TotalLength
  128. {
  129. get
  130. {
  131. double length = 0;
  132. foreach (TSStreamClip clip in StreamClips)
  133. {
  134. if (clip.AngleIndex == 0)
  135. {
  136. length += clip.Length;
  137. }
  138. }
  139. return length;
  140. }
  141. }
  142. public double TotalAngleLength
  143. {
  144. get
  145. {
  146. double length = 0;
  147. foreach (TSStreamClip clip in StreamClips)
  148. {
  149. length += clip.Length;
  150. }
  151. return length;
  152. }
  153. }
  154. public ulong TotalSize
  155. {
  156. get
  157. {
  158. ulong size = 0;
  159. foreach (TSStreamClip clip in StreamClips)
  160. {
  161. if (clip.AngleIndex == 0)
  162. {
  163. size += clip.PacketSize;
  164. }
  165. }
  166. return size;
  167. }
  168. }
  169. public ulong TotalAngleSize
  170. {
  171. get
  172. {
  173. ulong size = 0;
  174. foreach (TSStreamClip clip in StreamClips)
  175. {
  176. size += clip.PacketSize;
  177. }
  178. return size;
  179. }
  180. }
  181. public ulong TotalBitRate
  182. {
  183. get
  184. {
  185. if (TotalLength > 0)
  186. {
  187. return (ulong)Math.Round(((TotalSize * 8.0) / TotalLength));
  188. }
  189. return 0;
  190. }
  191. }
  192. public ulong TotalAngleBitRate
  193. {
  194. get
  195. {
  196. if (TotalAngleLength > 0)
  197. {
  198. return (ulong)Math.Round(((TotalAngleSize * 8.0) / TotalAngleLength));
  199. }
  200. return 0;
  201. }
  202. }
  203. public void Scan(
  204. Dictionary<string, TSStreamFile> streamFiles,
  205. Dictionary<string, TSStreamClipFile> streamClipFiles)
  206. {
  207. FileStream fileStream = null;
  208. BinaryReader fileReader = null;
  209. try
  210. {
  211. Streams.Clear();
  212. StreamClips.Clear();
  213. fileStream = File.OpenRead(FileInfo.FullName);
  214. fileReader = new BinaryReader(fileStream);
  215. byte[] data = new byte[fileStream.Length];
  216. int dataLength = fileReader.Read(data, 0, data.Length);
  217. int pos = 0;
  218. FileType = ReadString(data, 8, ref pos);
  219. if (FileType != "MPLS0100" && FileType != "MPLS0200")
  220. {
  221. throw new Exception(string.Format(
  222. "Playlist {0} has an unknown file type {1}.",
  223. FileInfo.Name, FileType));
  224. }
  225. int playlistOffset = ReadInt32(data, ref pos);
  226. int chaptersOffset = ReadInt32(data, ref pos);
  227. int extensionsOffset = ReadInt32(data, ref pos);
  228. pos = playlistOffset;
  229. int playlistLength = ReadInt32(data, ref pos);
  230. int playlistReserved = ReadInt16(data, ref pos);
  231. int itemCount = ReadInt16(data, ref pos);
  232. int subitemCount = ReadInt16(data, ref pos);
  233. List<TSStreamClip> chapterClips = new List<TSStreamClip>();
  234. for (int itemIndex = 0; itemIndex < itemCount; itemIndex++)
  235. {
  236. int itemStart = pos;
  237. int itemLength = ReadInt16(data, ref pos);
  238. string itemName = ReadString(data, 5, ref pos);
  239. string itemType = ReadString(data, 4, ref pos);
  240. TSStreamFile streamFile = null;
  241. string streamFileName = string.Format(
  242. "{0}.M2TS", itemName);
  243. if (streamFiles.ContainsKey(streamFileName))
  244. {
  245. streamFile = streamFiles[streamFileName];
  246. }
  247. if (streamFile == null)
  248. {
  249. // Error condition
  250. }
  251. TSStreamClipFile streamClipFile = null;
  252. string streamClipFileName = string.Format(
  253. "{0}.CLPI", itemName);
  254. if (streamClipFiles.ContainsKey(streamClipFileName))
  255. {
  256. streamClipFile = streamClipFiles[streamClipFileName];
  257. }
  258. if (streamClipFile == null)
  259. {
  260. throw new Exception(string.Format(
  261. "Playlist {0} referenced missing file {1}.",
  262. FileInfo.Name, streamFileName));
  263. }
  264. pos += 1;
  265. int multiangle = (data[pos] >> 4) & 0x01;
  266. int condition = data[pos] & 0x0F;
  267. pos += 2;
  268. int inTime = ReadInt32(data, ref pos);
  269. if (inTime < 0) inTime &= 0x7FFFFFFF;
  270. double timeIn = (double)inTime / 45000;
  271. int outTime = ReadInt32(data, ref pos);
  272. if (outTime < 0) outTime &= 0x7FFFFFFF;
  273. double timeOut = (double)outTime / 45000;
  274. TSStreamClip streamClip = new TSStreamClip(
  275. streamFile, streamClipFile);
  276. streamClip.Name = streamFileName; //TODO
  277. streamClip.TimeIn = timeIn;
  278. streamClip.TimeOut = timeOut;
  279. streamClip.Length = streamClip.TimeOut - streamClip.TimeIn;
  280. streamClip.RelativeTimeIn = TotalLength;
  281. streamClip.RelativeTimeOut = streamClip.RelativeTimeIn + streamClip.Length;
  282. StreamClips.Add(streamClip);
  283. chapterClips.Add(streamClip);
  284. pos += 12;
  285. if (multiangle > 0)
  286. {
  287. int angles = data[pos];
  288. pos += 2;
  289. for (int angle = 0; angle < angles - 1; angle++)
  290. {
  291. string angleName = ReadString(data, 5, ref pos);
  292. string angleType = ReadString(data, 4, ref pos);
  293. pos += 1;
  294. TSStreamFile angleFile = null;
  295. string angleFileName = string.Format(
  296. "{0}.M2TS", angleName);
  297. if (streamFiles.ContainsKey(angleFileName))
  298. {
  299. angleFile = streamFiles[angleFileName];
  300. }
  301. if (angleFile == null)
  302. {
  303. throw new Exception(string.Format(
  304. "Playlist {0} referenced missing angle file {1}.",
  305. FileInfo.Name, angleFileName));
  306. }
  307. TSStreamClipFile angleClipFile = null;
  308. string angleClipFileName = string.Format(
  309. "{0}.CLPI", angleName);
  310. if (streamClipFiles.ContainsKey(angleClipFileName))
  311. {
  312. angleClipFile = streamClipFiles[angleClipFileName];
  313. }
  314. if (angleClipFile == null)
  315. {
  316. throw new Exception(string.Format(
  317. "Playlist {0} referenced missing angle file {1}.",
  318. FileInfo.Name, angleClipFileName));
  319. }
  320. TSStreamClip angleClip =
  321. new TSStreamClip(angleFile, angleClipFile);
  322. angleClip.AngleIndex = angle + 1;
  323. angleClip.TimeIn = streamClip.TimeIn;
  324. angleClip.TimeOut = streamClip.TimeOut;
  325. angleClip.RelativeTimeIn = streamClip.RelativeTimeIn;
  326. angleClip.RelativeTimeOut = streamClip.RelativeTimeOut;
  327. angleClip.Length = streamClip.Length;
  328. StreamClips.Add(angleClip);
  329. }
  330. if (angles - 1 > AngleCount) AngleCount = angles - 1;
  331. }
  332. int streamInfoLength = ReadInt16(data, ref pos);
  333. pos += 2;
  334. int streamCountVideo = data[pos++];
  335. int streamCountAudio = data[pos++];
  336. int streamCountPG = data[pos++];
  337. int streamCountIG = data[pos++];
  338. int streamCountSecondaryAudio = data[pos++];
  339. int streamCountSecondaryVideo = data[pos++];
  340. int streamCountPIP = data[pos++];
  341. pos += 5;
  342. #if DEBUG
  343. Debug.WriteLine(string.Format(
  344. "{0} : {1} -> V:{2} A:{3} PG:{4} IG:{5} 2A:{6} 2V:{7} PIP:{8}",
  345. Name, streamFileName, streamCountVideo, streamCountAudio, streamCountPG, streamCountIG,
  346. streamCountSecondaryAudio, streamCountSecondaryVideo, streamCountPIP));
  347. #endif
  348. for (int i = 0; i < streamCountVideo; i++)
  349. {
  350. TSStream stream = CreatePlaylistStream(data, ref pos);
  351. if (stream != null) PlaylistStreams[stream.PID] = stream;
  352. }
  353. for (int i = 0; i < streamCountAudio; i++)
  354. {
  355. TSStream stream = CreatePlaylistStream(data, ref pos);
  356. if (stream != null) PlaylistStreams[stream.PID] = stream;
  357. }
  358. for (int i = 0; i < streamCountPG; i++)
  359. {
  360. TSStream stream = CreatePlaylistStream(data, ref pos);
  361. if (stream != null) PlaylistStreams[stream.PID] = stream;
  362. }
  363. for (int i = 0; i < streamCountIG; i++)
  364. {
  365. TSStream stream = CreatePlaylistStream(data, ref pos);
  366. if (stream != null) PlaylistStreams[stream.PID] = stream;
  367. }
  368. for (int i = 0; i < streamCountSecondaryAudio; i++)
  369. {
  370. TSStream stream = CreatePlaylistStream(data, ref pos);
  371. if (stream != null) PlaylistStreams[stream.PID] = stream;
  372. pos += 2;
  373. }
  374. for (int i = 0; i < streamCountSecondaryVideo; i++)
  375. {
  376. TSStream stream = CreatePlaylistStream(data, ref pos);
  377. if (stream != null) PlaylistStreams[stream.PID] = stream;
  378. pos += 6;
  379. }
  380. /*
  381. * TODO
  382. *
  383. for (int i = 0; i < streamCountPIP; i++)
  384. {
  385. TSStream stream = CreatePlaylistStream(data, ref pos);
  386. if (stream != null) PlaylistStreams[stream.PID] = stream;
  387. }
  388. */
  389. pos += itemLength - (pos - itemStart) + 2;
  390. }
  391. pos = chaptersOffset + 4;
  392. int chapterCount = ReadInt16(data, ref pos);
  393. for (int chapterIndex = 0;
  394. chapterIndex < chapterCount;
  395. chapterIndex++)
  396. {
  397. int chapterType = data[pos+1];
  398. if (chapterType == 1)
  399. {
  400. int streamFileIndex =
  401. ((int)data[pos + 2] << 8) + data[pos + 3];
  402. long chapterTime =
  403. ((long)data[pos + 4] << 24) +
  404. ((long)data[pos + 5] << 16) +
  405. ((long)data[pos + 6] << 8) +
  406. ((long)data[pos + 7]);
  407. TSStreamClip streamClip = chapterClips[streamFileIndex];
  408. double chapterSeconds = (double)chapterTime / 45000;
  409. double relativeSeconds =
  410. chapterSeconds -
  411. streamClip.TimeIn +
  412. streamClip.RelativeTimeIn;
  413. // TODO: Ignore short last chapter?
  414. if (TotalLength - relativeSeconds > 1.0)
  415. {
  416. streamClip.Chapters.Add(chapterSeconds);
  417. this.Chapters.Add(relativeSeconds);
  418. }
  419. }
  420. else
  421. {
  422. // TODO: Handle other chapter types?
  423. }
  424. pos += 14;
  425. }
  426. }
  427. finally
  428. {
  429. if (fileReader != null)
  430. {
  431. fileReader.Dispose();
  432. }
  433. if (fileStream != null)
  434. {
  435. fileStream.Dispose();
  436. }
  437. }
  438. }
  439. public void Initialize()
  440. {
  441. LoadStreamClips();
  442. Dictionary<string, List<double>> clipTimes = new Dictionary<string, List<double>>();
  443. foreach (TSStreamClip clip in StreamClips)
  444. {
  445. if (clip.AngleIndex == 0)
  446. {
  447. if (clipTimes.ContainsKey(clip.Name))
  448. {
  449. if (clipTimes[clip.Name].Contains(clip.TimeIn))
  450. {
  451. HasLoops = true;
  452. break;
  453. }
  454. else
  455. {
  456. clipTimes[clip.Name].Add(clip.TimeIn);
  457. }
  458. }
  459. else
  460. {
  461. clipTimes[clip.Name] = new List<double> { clip.TimeIn };
  462. }
  463. }
  464. }
  465. ClearBitrates();
  466. IsInitialized = true;
  467. }
  468. protected TSStream CreatePlaylistStream(byte[] data, ref int pos)
  469. {
  470. TSStream stream = null;
  471. int start = pos;
  472. int headerLength = data[pos++];
  473. int headerPos = pos;
  474. int headerType = data[pos++];
  475. int pid = 0;
  476. int subpathid = 0;
  477. int subclipid = 0;
  478. switch (headerType)
  479. {
  480. case 1:
  481. pid = ReadInt16(data, ref pos);
  482. break;
  483. case 2:
  484. subpathid = data[pos++];
  485. subclipid = data[pos++];
  486. pid = ReadInt16(data, ref pos);
  487. break;
  488. case 3:
  489. subpathid = data[pos++];
  490. pid = ReadInt16(data, ref pos);
  491. break;
  492. case 4:
  493. subpathid = data[pos++];
  494. subclipid = data[pos++];
  495. pid = ReadInt16(data, ref pos);
  496. break;
  497. default:
  498. break;
  499. }
  500. pos = headerPos + headerLength;
  501. int streamLength = data[pos++];
  502. int streamPos = pos;
  503. TSStreamType streamType = (TSStreamType)data[pos++];
  504. switch (streamType)
  505. {
  506. case TSStreamType.MVC_VIDEO:
  507. // TODO
  508. break;
  509. case TSStreamType.AVC_VIDEO:
  510. case TSStreamType.MPEG1_VIDEO:
  511. case TSStreamType.MPEG2_VIDEO:
  512. case TSStreamType.VC1_VIDEO:
  513. TSVideoFormat videoFormat = (TSVideoFormat)
  514. (data[pos] >> 4);
  515. TSFrameRate frameRate = (TSFrameRate)
  516. (data[pos] & 0xF);
  517. TSAspectRatio aspectRatio = (TSAspectRatio)
  518. (data[pos + 1] >> 4);
  519. stream = new TSVideoStream();
  520. ((TSVideoStream)stream).VideoFormat = videoFormat;
  521. ((TSVideoStream)stream).AspectRatio = aspectRatio;
  522. ((TSVideoStream)stream).FrameRate = frameRate;
  523. #if DEBUG
  524. Debug.WriteLine(string.Format(
  525. "\t{0} {1} {2} {3} {4}",
  526. pid,
  527. streamType,
  528. videoFormat,
  529. frameRate,
  530. aspectRatio));
  531. #endif
  532. break;
  533. case TSStreamType.AC3_AUDIO:
  534. case TSStreamType.AC3_PLUS_AUDIO:
  535. case TSStreamType.AC3_PLUS_SECONDARY_AUDIO:
  536. case TSStreamType.AC3_TRUE_HD_AUDIO:
  537. case TSStreamType.DTS_AUDIO:
  538. case TSStreamType.DTS_HD_AUDIO:
  539. case TSStreamType.DTS_HD_MASTER_AUDIO:
  540. case TSStreamType.DTS_HD_SECONDARY_AUDIO:
  541. case TSStreamType.LPCM_AUDIO:
  542. case TSStreamType.MPEG1_AUDIO:
  543. case TSStreamType.MPEG2_AUDIO:
  544. int audioFormat = ReadByte(data, ref pos);
  545. TSChannelLayout channelLayout = (TSChannelLayout)
  546. (audioFormat >> 4);
  547. TSSampleRate sampleRate = (TSSampleRate)
  548. (audioFormat & 0xF);
  549. string audioLanguage = ReadString(data, 3, ref pos);
  550. stream = new TSAudioStream();
  551. ((TSAudioStream)stream).ChannelLayout = channelLayout;
  552. ((TSAudioStream)stream).SampleRate = TSAudioStream.ConvertSampleRate(sampleRate);
  553. ((TSAudioStream)stream).LanguageCode = audioLanguage;
  554. #if DEBUG
  555. Debug.WriteLine(string.Format(
  556. "\t{0} {1} {2} {3} {4}",
  557. pid,
  558. streamType,
  559. audioLanguage,
  560. channelLayout,
  561. sampleRate));
  562. #endif
  563. break;
  564. case TSStreamType.INTERACTIVE_GRAPHICS:
  565. case TSStreamType.PRESENTATION_GRAPHICS:
  566. string graphicsLanguage = ReadString(data, 3, ref pos);
  567. stream = new TSGraphicsStream();
  568. ((TSGraphicsStream)stream).LanguageCode = graphicsLanguage;
  569. if (data[pos] != 0)
  570. {
  571. }
  572. #if DEBUG
  573. Debug.WriteLine(string.Format(
  574. "\t{0} {1} {2}",
  575. pid,
  576. streamType,
  577. graphicsLanguage));
  578. #endif
  579. break;
  580. case TSStreamType.SUBTITLE:
  581. int code = ReadByte(data, ref pos); // TODO
  582. string textLanguage = ReadString(data, 3, ref pos);
  583. stream = new TSTextStream();
  584. ((TSTextStream)stream).LanguageCode = textLanguage;
  585. #if DEBUG
  586. Debug.WriteLine(string.Format(
  587. "\t{0} {1} {2}",
  588. pid,
  589. streamType,
  590. textLanguage));
  591. #endif
  592. break;
  593. default:
  594. break;
  595. }
  596. pos = streamPos + streamLength;
  597. if (stream != null)
  598. {
  599. stream.PID = (ushort)pid;
  600. stream.StreamType = streamType;
  601. }
  602. return stream;
  603. }
  604. private void LoadStreamClips()
  605. {
  606. AngleClips.Clear();
  607. if (AngleCount > 0)
  608. {
  609. for (int angleIndex = 0; angleIndex < AngleCount; angleIndex++)
  610. {
  611. AngleClips.Add(new Dictionary<double, TSStreamClip>());
  612. }
  613. }
  614. TSStreamClip referenceClip = null;
  615. if (StreamClips.Count > 0)
  616. {
  617. referenceClip = StreamClips[0];
  618. }
  619. foreach (TSStreamClip clip in StreamClips)
  620. {
  621. if (clip.StreamClipFile.Streams.Count > referenceClip.StreamClipFile.Streams.Count)
  622. {
  623. referenceClip = clip;
  624. }
  625. else if (clip.Length > referenceClip.Length)
  626. {
  627. referenceClip = clip;
  628. }
  629. if (AngleCount > 0)
  630. {
  631. if (clip.AngleIndex == 0)
  632. {
  633. for (int angleIndex = 0; angleIndex < AngleCount; angleIndex++)
  634. {
  635. AngleClips[angleIndex][clip.RelativeTimeIn] = clip;
  636. }
  637. }
  638. else
  639. {
  640. AngleClips[clip.AngleIndex - 1][clip.RelativeTimeIn] = clip;
  641. }
  642. }
  643. }
  644. foreach (TSStream clipStream
  645. in referenceClip.StreamClipFile.Streams.Values)
  646. {
  647. if (!Streams.ContainsKey(clipStream.PID))
  648. {
  649. TSStream stream = clipStream.Clone();
  650. Streams[clipStream.PID] = stream;
  651. if (!IsCustom && !PlaylistStreams.ContainsKey(stream.PID))
  652. {
  653. stream.IsHidden = true;
  654. HasHiddenTracks = true;
  655. }
  656. if (stream.IsVideoStream)
  657. {
  658. VideoStreams.Add((TSVideoStream)stream);
  659. }
  660. else if (stream.IsAudioStream)
  661. {
  662. AudioStreams.Add((TSAudioStream)stream);
  663. }
  664. else if (stream.IsGraphicsStream)
  665. {
  666. GraphicsStreams.Add((TSGraphicsStream)stream);
  667. }
  668. else if (stream.IsTextStream)
  669. {
  670. TextStreams.Add((TSTextStream)stream);
  671. }
  672. }
  673. }
  674. if (referenceClip.StreamFile != null)
  675. {
  676. // TODO: Better way to add this in?
  677. if (BDInfoSettings.EnableSSIF &&
  678. referenceClip.StreamFile.InterleavedFile != null &&
  679. referenceClip.StreamFile.Streams.ContainsKey(4114) &&
  680. !Streams.ContainsKey(4114))
  681. {
  682. TSStream stream = referenceClip.StreamFile.Streams[4114].Clone();
  683. Streams[4114] = stream;
  684. if (stream.IsVideoStream)
  685. {
  686. VideoStreams.Add((TSVideoStream)stream);
  687. }
  688. }
  689. foreach (TSStream clipStream
  690. in referenceClip.StreamFile.Streams.Values)
  691. {
  692. if (Streams.ContainsKey(clipStream.PID))
  693. {
  694. TSStream stream = Streams[clipStream.PID];
  695. if (stream.StreamType != clipStream.StreamType) continue;
  696. if (clipStream.BitRate > stream.BitRate)
  697. {
  698. stream.BitRate = clipStream.BitRate;
  699. }
  700. stream.IsVBR = clipStream.IsVBR;
  701. if (stream.IsVideoStream &&
  702. clipStream.IsVideoStream)
  703. {
  704. ((TSVideoStream)stream).EncodingProfile =
  705. ((TSVideoStream)clipStream).EncodingProfile;
  706. }
  707. else if (stream.IsAudioStream &&
  708. clipStream.IsAudioStream)
  709. {
  710. TSAudioStream audioStream = (TSAudioStream)stream;
  711. TSAudioStream clipAudioStream = (TSAudioStream)clipStream;
  712. if (clipAudioStream.ChannelCount > audioStream.ChannelCount)
  713. {
  714. audioStream.ChannelCount = clipAudioStream.ChannelCount;
  715. }
  716. if (clipAudioStream.LFE > audioStream.LFE)
  717. {
  718. audioStream.LFE = clipAudioStream.LFE;
  719. }
  720. if (clipAudioStream.SampleRate > audioStream.SampleRate)
  721. {
  722. audioStream.SampleRate = clipAudioStream.SampleRate;
  723. }
  724. if (clipAudioStream.BitDepth > audioStream.BitDepth)
  725. {
  726. audioStream.BitDepth = clipAudioStream.BitDepth;
  727. }
  728. if (clipAudioStream.DialNorm < audioStream.DialNorm)
  729. {
  730. audioStream.DialNorm = clipAudioStream.DialNorm;
  731. }
  732. if (clipAudioStream.AudioMode != TSAudioMode.Unknown)
  733. {
  734. audioStream.AudioMode = clipAudioStream.AudioMode;
  735. }
  736. if (clipAudioStream.CoreStream != null &&
  737. audioStream.CoreStream == null)
  738. {
  739. audioStream.CoreStream = (TSAudioStream)
  740. clipAudioStream.CoreStream.Clone();
  741. }
  742. }
  743. }
  744. }
  745. }
  746. for (int i = 0; i < AngleCount; i++)
  747. {
  748. AngleStreams.Add(new Dictionary<ushort, TSStream>());
  749. }
  750. if (!BDInfoSettings.KeepStreamOrder)
  751. {
  752. VideoStreams.Sort(CompareVideoStreams);
  753. }
  754. foreach (TSStream stream in VideoStreams)
  755. {
  756. SortedStreams.Add(stream);
  757. for (int i = 0; i < AngleCount; i++)
  758. {
  759. TSStream angleStream = stream.Clone();
  760. angleStream.AngleIndex = i + 1;
  761. AngleStreams[i][angleStream.PID] = angleStream;
  762. SortedStreams.Add(angleStream);
  763. }
  764. }
  765. if (!BDInfoSettings.KeepStreamOrder)
  766. {
  767. AudioStreams.Sort(CompareAudioStreams);
  768. }
  769. foreach (TSStream stream in AudioStreams)
  770. {
  771. SortedStreams.Add(stream);
  772. }
  773. if (!BDInfoSettings.KeepStreamOrder)
  774. {
  775. GraphicsStreams.Sort(CompareGraphicsStreams);
  776. }
  777. foreach (TSStream stream in GraphicsStreams)
  778. {
  779. SortedStreams.Add(stream);
  780. }
  781. if (!BDInfoSettings.KeepStreamOrder)
  782. {
  783. TextStreams.Sort(CompareTextStreams);
  784. }
  785. foreach (TSStream stream in TextStreams)
  786. {
  787. SortedStreams.Add(stream);
  788. }
  789. }
  790. public void ClearBitrates()
  791. {
  792. foreach (TSStreamClip clip in StreamClips)
  793. {
  794. clip.PayloadBytes = 0;
  795. clip.PacketCount = 0;
  796. clip.PacketSeconds = 0;
  797. if (clip.StreamFile != null)
  798. {
  799. foreach (TSStream stream in clip.StreamFile.Streams.Values)
  800. {
  801. stream.PayloadBytes = 0;
  802. stream.PacketCount = 0;
  803. stream.PacketSeconds = 0;
  804. }
  805. if (clip.StreamFile != null &&
  806. clip.StreamFile.StreamDiagnostics != null)
  807. {
  808. clip.StreamFile.StreamDiagnostics.Clear();
  809. }
  810. }
  811. }
  812. foreach (TSStream stream in SortedStreams)
  813. {
  814. stream.PayloadBytes = 0;
  815. stream.PacketCount = 0;
  816. stream.PacketSeconds = 0;
  817. }
  818. }
  819. public bool IsValid
  820. {
  821. get
  822. {
  823. if (!IsInitialized) return false;
  824. if (BDInfoSettings.FilterShortPlaylists &&
  825. TotalLength < BDInfoSettings.FilterShortPlaylistsValue)
  826. {
  827. return false;
  828. }
  829. if (HasLoops &&
  830. BDInfoSettings.FilterLoopingPlaylists)
  831. {
  832. return false;
  833. }
  834. return true;
  835. }
  836. }
  837. public static int CompareVideoStreams(
  838. TSVideoStream x,
  839. TSVideoStream y)
  840. {
  841. if (x == null && y == null)
  842. {
  843. return 0;
  844. }
  845. else if (x == null && y != null)
  846. {
  847. return 1;
  848. }
  849. else if (x != null && y == null)
  850. {
  851. return -1;
  852. }
  853. else
  854. {
  855. if (x.Height > y.Height)
  856. {
  857. return -1;
  858. }
  859. else if (y.Height > x.Height)
  860. {
  861. return 1;
  862. }
  863. else if (x.PID > y.PID)
  864. {
  865. return 1;
  866. }
  867. else if (y.PID > x.PID)
  868. {
  869. return -1;
  870. }
  871. else
  872. {
  873. return 0;
  874. }
  875. }
  876. }
  877. public static int CompareAudioStreams(
  878. TSAudioStream x,
  879. TSAudioStream y)
  880. {
  881. if (x == y)
  882. {
  883. return 0;
  884. }
  885. else if (x == null && y == null)
  886. {
  887. return 0;
  888. }
  889. else if (x == null && y != null)
  890. {
  891. return -1;
  892. }
  893. else if (x != null && y == null)
  894. {
  895. return 1;
  896. }
  897. else
  898. {
  899. if (x.ChannelCount > y.ChannelCount)
  900. {
  901. return -1;
  902. }
  903. else if (y.ChannelCount > x.ChannelCount)
  904. {
  905. return 1;
  906. }
  907. else
  908. {
  909. int sortX = GetStreamTypeSortIndex(x.StreamType);
  910. int sortY = GetStreamTypeSortIndex(y.StreamType);
  911. if (sortX > sortY)
  912. {
  913. return -1;
  914. }
  915. else if (sortY > sortX)
  916. {
  917. return 1;
  918. }
  919. else
  920. {
  921. if (x.LanguageCode == "eng")
  922. {
  923. return -1;
  924. }
  925. else if (y.LanguageCode == "eng")
  926. {
  927. return 1;
  928. }
  929. else if (x.LanguageCode != y.LanguageCode)
  930. {
  931. return string.Compare(
  932. x.LanguageName, y.LanguageName);
  933. }
  934. else if (x.PID < y.PID)
  935. {
  936. return -1;
  937. }
  938. else if (y.PID < x.PID)
  939. {
  940. return 1;
  941. }
  942. return 0;
  943. }
  944. }
  945. }
  946. }
  947. public static int CompareTextStreams(
  948. TSTextStream x,
  949. TSTextStream y)
  950. {
  951. if (x == y)
  952. {
  953. return 0;
  954. }
  955. else if (x == null && y == null)
  956. {
  957. return 0;
  958. }
  959. else if (x == null && y != null)
  960. {
  961. return -1;
  962. }
  963. else if (x != null && y == null)
  964. {
  965. return 1;
  966. }
  967. else
  968. {
  969. if (x.LanguageCode == "eng")
  970. {
  971. return -1;
  972. }
  973. else if (y.LanguageCode == "eng")
  974. {
  975. return 1;
  976. }
  977. else
  978. {
  979. if (x.LanguageCode == y.LanguageCode)
  980. {
  981. if (x.PID > y.PID)
  982. {
  983. return 1;
  984. }
  985. else if (y.PID > x.PID)
  986. {
  987. return -1;
  988. }
  989. else
  990. {
  991. return 0;
  992. }
  993. }
  994. else
  995. {
  996. return string.Compare(
  997. x.LanguageName, y.LanguageName);
  998. }
  999. }
  1000. }
  1001. }
  1002. private static int CompareGraphicsStreams(
  1003. TSGraphicsStream x,
  1004. TSGraphicsStream y)
  1005. {
  1006. if (x == y)
  1007. {
  1008. return 0;
  1009. }
  1010. else if (x == null && y == null)
  1011. {
  1012. return 0;
  1013. }
  1014. else if (x == null && y != null)
  1015. {
  1016. return -1;
  1017. }
  1018. else if (x != null && y == null)
  1019. {
  1020. return 1;
  1021. }
  1022. else
  1023. {
  1024. int sortX = GetStreamTypeSortIndex(x.StreamType);
  1025. int sortY = GetStreamTypeSortIndex(y.StreamType);
  1026. if (sortX > sortY)
  1027. {
  1028. return -1;
  1029. }
  1030. else if (sortY > sortX)
  1031. {
  1032. return 1;
  1033. }
  1034. else if (x.LanguageCode == "eng")
  1035. {
  1036. return -1;
  1037. }
  1038. else if (y.LanguageCode == "eng")
  1039. {
  1040. return 1;
  1041. }
  1042. else
  1043. {
  1044. if (x.LanguageCode == y.LanguageCode)
  1045. {
  1046. if (x.PID > y.PID)
  1047. {
  1048. return 1;
  1049. }
  1050. else if (y.PID > x.PID)
  1051. {
  1052. return -1;
  1053. }
  1054. else
  1055. {
  1056. return 0;
  1057. }
  1058. }
  1059. else
  1060. {
  1061. return string.Compare(x.LanguageName, y.LanguageName);
  1062. }
  1063. }
  1064. }
  1065. }
  1066. private static int GetStreamTypeSortIndex(TSStreamType streamType)
  1067. {
  1068. switch (streamType)
  1069. {
  1070. case TSStreamType.Unknown:
  1071. return 0;
  1072. case TSStreamType.MPEG1_VIDEO:
  1073. return 1;
  1074. case TSStreamType.MPEG2_VIDEO:
  1075. return 2;
  1076. case TSStreamType.AVC_VIDEO:
  1077. return 3;
  1078. case TSStreamType.VC1_VIDEO:
  1079. return 4;
  1080. case TSStreamType.MVC_VIDEO:
  1081. return 5;
  1082. case TSStreamType.MPEG1_AUDIO:
  1083. return 1;
  1084. case TSStreamType.MPEG2_AUDIO:
  1085. return 2;
  1086. case TSStreamType.AC3_PLUS_SECONDARY_AUDIO:
  1087. return 3;
  1088. case TSStreamType.DTS_HD_SECONDARY_AUDIO:
  1089. return 4;
  1090. case TSStreamType.AC3_AUDIO:
  1091. return 5;
  1092. case TSStreamType.DTS_AUDIO:
  1093. return 6;
  1094. case TSStreamType.AC3_PLUS_AUDIO:
  1095. return 7;
  1096. case TSStreamType.DTS_HD_AUDIO:
  1097. return 8;
  1098. case TSStreamType.AC3_TRUE_HD_AUDIO:
  1099. return 9;
  1100. case TSStreamType.DTS_HD_MASTER_AUDIO:
  1101. return 10;
  1102. case TSStreamType.LPCM_AUDIO:
  1103. return 11;
  1104. case TSStreamType.SUBTITLE:
  1105. return 1;
  1106. case TSStreamType.INTERACTIVE_GRAPHICS:
  1107. return 2;
  1108. case TSStreamType.PRESENTATION_GRAPHICS:
  1109. return 3;
  1110. default:
  1111. return 0;
  1112. }
  1113. }
  1114. protected string ReadString(
  1115. byte[] data,
  1116. int count,
  1117. ref int pos)
  1118. {
  1119. string val =
  1120. ASCIIEncoding.ASCII.GetString(data, pos, count);
  1121. pos += count;
  1122. return val;
  1123. }
  1124. protected int ReadInt32(
  1125. byte[] data,
  1126. ref int pos)
  1127. {
  1128. int val =
  1129. ((int)data[pos] << 24) +
  1130. ((int)data[pos + 1] << 16) +
  1131. ((int)data[pos + 2] << 8) +
  1132. ((int)data[pos + 3]);
  1133. pos += 4;
  1134. return val;
  1135. }
  1136. protected int ReadInt16(
  1137. byte[] data,
  1138. ref int pos)
  1139. {
  1140. int val =
  1141. ((int)data[pos] << 8) +
  1142. ((int)data[pos + 1]);
  1143. pos += 2;
  1144. return val;
  1145. }
  1146. protected byte ReadByte(
  1147. byte[] data,
  1148. ref int pos)
  1149. {
  1150. return data[pos++];
  1151. }
  1152. }
  1153. }