TrackFragmentRandomAccessBox.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.IO;
  6. using System.Collections;
  7. namespace MatrixIO.IO.Bmff.Boxes
  8. {
  9. /// <summary>
  10. /// Track Fragment Random Access Box ("tfra")
  11. /// </summary>
  12. [Box("tfra", "Track Fragment Random Access Box")]
  13. public class TrackFragmentRandomAccessBox : FullBox, ITableBox<TrackFragmentRandomAccessBox.TrackFragmentEntry>
  14. {
  15. public TrackFragmentRandomAccessBox() : base() { }
  16. public TrackFragmentRandomAccessBox(Stream stream) : base(stream) { }
  17. internal override ulong CalculateSize()
  18. {
  19. ulong entries = (ulong)Entries.Count;
  20. return base.CalculateSize()
  21. + 4 + 4 + 4
  22. + (entries * (ulong)(Version == 0x01 ? 16 : 8))
  23. + (entries * (ulong)SizeOfTrafNumber)
  24. + (entries * (ulong)SizeOfTrunNumber)
  25. + (entries * (ulong)SizeOfSampleNumber);
  26. }
  27. protected override void LoadFromStream(Stream stream)
  28. {
  29. base.LoadFromStream(stream);
  30. TrackID = stream.ReadBEUInt32();
  31. Reserved = stream.ReadBytes(3);
  32. _SizeOf = stream.ReadOneByte();
  33. uint NumberOfEntries = stream.ReadBEUInt32();
  34. for (uint i = 0; i < NumberOfEntries; i++)
  35. {
  36. TrackFragmentEntry entry = new TrackFragmentEntry();
  37. if (Version == 0x01)
  38. {
  39. entry.Time = stream.ReadBEUInt64();
  40. entry.MoofOffset = stream.ReadBEUInt64();
  41. }
  42. else
  43. {
  44. entry.Time = stream.ReadBEUInt32();
  45. entry.MoofOffset = stream.ReadBEUInt32();
  46. }
  47. if (SizeOfTrafNumber == 1) entry.TrafNumber = stream.ReadOneByte();
  48. else if (SizeOfTrafNumber == 2) entry.TrafNumber = stream.ReadBEUInt16();
  49. else if (SizeOfTrafNumber == 3) entry.TrafNumber = stream.ReadBEUInt24();
  50. else entry.TrafNumber = stream.ReadBEUInt32();
  51. if (SizeOfTrunNumber == 1) entry.TrunNumber = stream.ReadOneByte();
  52. else if (SizeOfTrunNumber == 2) entry.TrunNumber = stream.ReadBEUInt16();
  53. else if (SizeOfTrunNumber == 3) entry.TrunNumber = stream.ReadBEUInt24();
  54. else entry.TrunNumber = stream.ReadBEUInt32();
  55. if (SizeOfSampleNumber == 1) entry.SampleNumber = stream.ReadOneByte();
  56. else if (SizeOfSampleNumber == 2) entry.SampleNumber = stream.ReadBEUInt16();
  57. else if (SizeOfSampleNumber == 3) entry.SampleNumber = stream.ReadBEUInt24();
  58. else entry.SampleNumber = stream.ReadBEUInt32();
  59. _Entries.Add(entry);
  60. }
  61. }
  62. protected override void SaveToStream(Stream stream)
  63. {
  64. if ((from entry in _Entries select Math.Max(entry.Time, entry.MoofOffset)).Max() > UInt32.MaxValue) Version = 1;
  65. else Version = 0;
  66. uint MaxTrafNumber = (from entry in _Entries select entry.TrafNumber).Max();
  67. if (MaxTrafNumber > 16777215) SizeOfTrafNumber = 4;
  68. else if (MaxTrafNumber > UInt16.MaxValue) SizeOfTrafNumber = 3;
  69. else if (MaxTrafNumber > Byte.MaxValue) SizeOfTrafNumber = 2;
  70. else SizeOfTrafNumber = 1;
  71. uint MaxTrunNumber = (from entry in _Entries select entry.TrunNumber).Max();
  72. if (MaxTrunNumber > 16777215) SizeOfTrunNumber = 4;
  73. else if (MaxTrunNumber > UInt16.MaxValue) SizeOfTrunNumber = 3;
  74. else if (MaxTrunNumber > Byte.MaxValue) SizeOfTrunNumber = 2;
  75. else SizeOfTrunNumber = 1;
  76. uint MaxSampleNumber = (from entry in _Entries select entry.SampleNumber).Max();
  77. if (MaxSampleNumber > 16777215) SizeOfSampleNumber = 4;
  78. else if (MaxSampleNumber > UInt16.MaxValue) SizeOfSampleNumber = 3;
  79. else if (MaxSampleNumber > Byte.MaxValue) SizeOfSampleNumber = 2;
  80. else SizeOfSampleNumber = 1;
  81. base.SaveToStream(stream);
  82. stream.WriteBEUInt32(TrackID);
  83. stream.Write(Reserved, 0, 3);
  84. stream.WriteOneByte(_SizeOf);
  85. stream.WriteBEUInt32((uint)_Entries.Count);
  86. foreach(var entry in _Entries)
  87. {
  88. if (Version == 0x01)
  89. {
  90. stream.WriteBEUInt64(entry.Time);
  91. stream.WriteBEUInt64(entry.MoofOffset);
  92. }
  93. else
  94. {
  95. stream.WriteBEUInt32((uint)entry.Time);
  96. stream.WriteBEUInt32((uint)entry.MoofOffset);
  97. }
  98. if (SizeOfTrafNumber == 1) stream.WriteOneByte((byte)entry.TrafNumber);
  99. else if (SizeOfTrafNumber == 2) stream.WriteBEUInt16((ushort)entry.TrafNumber);
  100. else if (SizeOfTrafNumber == 3) stream.WriteBEUInt24((uint)entry.TrafNumber);
  101. else stream.WriteBEUInt32((uint)entry.TrafNumber);
  102. if (SizeOfTrunNumber == 1) stream.WriteOneByte((byte)entry.TrunNumber);
  103. else if (SizeOfTrunNumber == 2) stream.WriteBEUInt16((ushort)entry.TrunNumber);
  104. else if (SizeOfTrunNumber == 3) stream.WriteBEUInt24((uint)entry.TrunNumber);
  105. else stream.WriteBEUInt32((uint)entry.TrunNumber);
  106. if (SizeOfSampleNumber == 1) stream.WriteOneByte((byte)entry.SampleNumber);
  107. else if (SizeOfSampleNumber == 2) stream.WriteBEUInt16((ushort)entry.SampleNumber);
  108. else if (SizeOfSampleNumber == 3) stream.WriteBEUInt24((uint)entry.SampleNumber);
  109. else stream.WriteBEUInt32((uint)entry.SampleNumber);
  110. }
  111. }
  112. public uint TrackID { get; set; }
  113. private byte[] Reserved = new byte[4];
  114. private byte _SizeOf;
  115. public sbyte SizeOfTrafNumber
  116. {
  117. get
  118. {
  119. return (sbyte)(((_SizeOf & 0x30) >> 4) + 1);
  120. }
  121. private set
  122. {
  123. if (value < 1 || value > 4) throw new OverflowException("SizeOfTrafNumber must be a value between 1 and 4.");
  124. _SizeOf = (byte)((_SizeOf & 0xCF) | (((SizeOfTrafNumber - 1) & 0x30) << 4));
  125. }
  126. }
  127. public sbyte SizeOfTrunNumber
  128. {
  129. get
  130. {
  131. return (sbyte)(((_SizeOf & 0x30) >> 4) + 1);
  132. }
  133. private set
  134. {
  135. if (value < 1 || value > 4) throw new OverflowException("SizeOfTrunNumber must be a value between 1 and 4.");
  136. _SizeOf = (byte)((_SizeOf & 0xF3) | ((SizeOfSampleNumber - 1) & 0x03));
  137. }
  138. }
  139. public sbyte SizeOfSampleNumber
  140. {
  141. get
  142. {
  143. return (sbyte)(((_SizeOf & 0x30) >> 4) + 1);
  144. }
  145. private set
  146. {
  147. if (value < 1 || value > 4) throw new OverflowException("SizeOfSampleNumber must be a value between 1 and 4.");
  148. _SizeOf = (byte)((_SizeOf & 0xFC) | ((SizeOfTrunNumber - 1) & 0x0C << 2));
  149. }
  150. }
  151. public class TrackFragmentEntry
  152. {
  153. public TrackFragmentEntry() { }
  154. public ulong Time { get; set; }
  155. public ulong MoofOffset { get; set; }
  156. public uint TrafNumber { get; set; }
  157. public uint TrunNumber { get; set; }
  158. public uint SampleNumber { get; set; }
  159. }
  160. private IList<TrackFragmentEntry> _Entries = Portability.CreateList<TrackFragmentEntry>();
  161. public IList<TrackFragmentEntry> Entries
  162. {
  163. get
  164. {
  165. return _Entries;
  166. }
  167. }
  168. }
  169. }