AdaptationField.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Linq;
  5. using System.Text;
  6. namespace MatrixIO.IO.MpegTs
  7. {
  8. public class AdaptationField
  9. {
  10. public byte Length { get; private set; }
  11. private byte _flags;
  12. public bool DiscontinuityIndicator
  13. {
  14. get { return (_flags & 0x80) > 0; }
  15. set { if (value) _flags |= 0x80; else _flags &= 0x7F; }
  16. }
  17. public bool RandomAccessIndicator
  18. {
  19. get { return (_flags & 0x40) > 0; }
  20. set { if (value) _flags |= 0x40; else _flags &= 0xBF; }
  21. }
  22. public bool ElementaryStreamPriorityIndicator
  23. {
  24. get { return (_flags & 0x20) > 0; }
  25. set { if (value) _flags |= 0x20; else _flags &= 0xDF; }
  26. }
  27. private bool HasProgramClockReference
  28. {
  29. get { return (_flags & 0x10) > 0; }
  30. set { if (value) _flags |= 0x10; else _flags &= 0xEF; }
  31. }
  32. private bool HasOriginalProgramClockReference
  33. {
  34. get { return (_flags & 0x08) > 0; }
  35. set { if (value) _flags |= 0x08; else _flags &= 0xF7; }
  36. }
  37. private bool HasSpliceCountdown
  38. {
  39. get { return (_flags & 0x04) > 0; }
  40. set { if (value) _flags |= 0x04; else _flags &= 0xFB; }
  41. }
  42. public bool HasPrivateData
  43. {
  44. get { return (_flags & 0x02) > 0; }
  45. set { if (value) _flags |= 0x02; else _flags &= 0xFD; }
  46. }
  47. public bool HasExtension
  48. {
  49. get { return (_flags & 0x01) > 0; }
  50. set { if (value) _flags |= 0x01; else _flags &= 0xFE; }
  51. }
  52. // Int48 with 33bit base, 6bit pad, 9bit extension
  53. private byte[] _programClockReference;
  54. public TimeSpan? ProgramClockReference
  55. {
  56. get
  57. {
  58. if (_programClockReference == null) return null;
  59. else return ProgramClockReferenceToTimeSpan(_programClockReference);
  60. }
  61. /*
  62. set
  63. {
  64. if (value == null)
  65. {
  66. _programClockReference = null;
  67. HasProgramClockReference = false;
  68. }
  69. else
  70. {
  71. }
  72. }
  73. */
  74. }
  75. // Int48 with 33bit base, 6bit pad, 9bit extension
  76. private byte[] _originalProgramClockReference;
  77. public TimeSpan? OriginalProgramClockReference
  78. {
  79. get
  80. {
  81. if (_originalProgramClockReference == null) return null;
  82. else return ProgramClockReferenceToTimeSpan(_originalProgramClockReference);
  83. }
  84. /*
  85. set
  86. {
  87. if (value == null)
  88. {
  89. _originalProgramClockReference = null;
  90. HasOriginalProgramClockReference = false;
  91. }
  92. else
  93. {
  94. }
  95. }
  96. */
  97. }
  98. private sbyte _spliceCountdown;
  99. public sbyte? SpliceCountdown
  100. {
  101. get { return HasSpliceCountdown ? _spliceCountdown : (sbyte?)null; }
  102. set
  103. {
  104. if (value.HasValue) _spliceCountdown = value.Value;
  105. HasSpliceCountdown = value.HasValue;
  106. }
  107. }
  108. private byte[] _privateData;
  109. public byte[] PrivateData
  110. {
  111. get { return HasPrivateData ? _privateData : null; }
  112. set { _privateData = value; HasPrivateData = (value != null); }
  113. }
  114. private AdaptationFieldExtension _extension;
  115. public AdaptationFieldExtension Extension
  116. {
  117. get { return HasExtension ? _extension : null; }
  118. set { _extension = value; HasExtension = (value != null); }
  119. }
  120. public byte[] Stuffing { get; set; }
  121. public AdaptationField() { }
  122. public AdaptationField(byte[] buffer, int offset = 4)
  123. {
  124. var position = offset;
  125. var length = Length = buffer[position++];
  126. if (length <= 0) return;
  127. _flags = buffer[position++];
  128. if (HasProgramClockReference)
  129. {
  130. _programClockReference = new byte[6];
  131. Buffer.BlockCopy(buffer, position, _programClockReference, 0, 6);
  132. position += 6;
  133. Debug.WriteLine("Has Program Clock Reference: " + ProgramClockReference);
  134. }
  135. if (HasOriginalProgramClockReference)
  136. {
  137. Debug.WriteLine("Has Original Program Clock Reference.");
  138. _originalProgramClockReference = new byte[6];
  139. Buffer.BlockCopy(buffer, position, _originalProgramClockReference, 0, 6);
  140. position += 6;
  141. }
  142. if (HasSpliceCountdown)
  143. {
  144. Debug.WriteLine("Has Splice Countdown.");
  145. SpliceCountdown = (sbyte) buffer[position++];
  146. }
  147. if (HasPrivateData)
  148. {
  149. byte privateDataLength = buffer[position++];
  150. Debug.WriteLine("Has " + privateDataLength + " byte of Private Data.");
  151. if (position > TsPacket.Length)
  152. {
  153. privateDataLength = 0;
  154. Debug.WriteLine("_position exceeds length by " + Math.Abs(buffer.Length - position) + " bytes.");
  155. throw new FormatException("Invalid private data length.");
  156. }
  157. else if (position + privateDataLength > TsPacket.Length)
  158. {
  159. Debug.WriteLine(" Private data exceeds length by " +
  160. Math.Abs(TsPacket.Length - position - privateDataLength) + " bytes!!!!!!!");
  161. privateDataLength = (byte)(TsPacket.Length - position);
  162. Debug.WriteLine("Reading " + privateDataLength + " bytes of Private Data.");
  163. }
  164. if (privateDataLength > 0)
  165. {
  166. var privateData = new byte[privateDataLength];
  167. Buffer.BlockCopy(buffer, position, privateData, 0, privateDataLength);
  168. PrivateData = privateData;
  169. position += privateDataLength;
  170. }
  171. }
  172. if (HasExtension)
  173. {
  174. Debug.WriteLine("Has Extension.");
  175. Extension = new AdaptationFieldExtension(buffer, position);
  176. position += Extension.Length;
  177. }
  178. int stuffingLength = length + 1 - (position - offset);
  179. if (stuffingLength > 0)
  180. {
  181. Debug.WriteLine("Has " + stuffingLength + " bytes of Adaptation Field stuffing.");
  182. Stuffing = new byte[stuffingLength];
  183. Buffer.BlockCopy(buffer, position, Stuffing, 0, stuffingLength);
  184. }
  185. }
  186. private TimeSpan ProgramClockReferenceToTimeSpan(byte[] pcr)
  187. {
  188. var longPCR = new long[] {pcr[0], pcr[1], pcr[2], pcr[3], pcr[4], pcr[5]};
  189. long pcrBase = longPCR[0] << 25 | longPCR[1] << 17 | longPCR[2] << 9 | longPCR[3] << 1 | (longPCR[4] & 0x80) >> 7;
  190. long pcrExtension = (longPCR[4] & 0x01) << 8 | longPCR[5];
  191. long pcrBaseTicks = (pcrBase * 1111111) / 10000; // Convert 90khz to Ticks (multiply by 111.1111)
  192. long pcrExtensionTicks = ((pcrExtension * 10) / 27) / 10; // Convert 27Mhz to Ticks (divide by 2.7)
  193. long pcrTicks = pcrBaseTicks + pcrExtensionTicks;
  194. Debug.WriteLine("PCR Ticks: " + pcrTicks);
  195. return new TimeSpan(pcrTicks);
  196. }
  197. }
  198. }