TrackRunBox.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.IO;
  6. namespace MatrixIO.IO.Bmff.Boxes
  7. {
  8. /// <summary>
  9. /// Track Run Box ("trun")
  10. /// </summary>
  11. [Box("trun", "Track Run Box")]
  12. public class TrackRunBox : FullBox, ITableBox<TrackRunBox.TrackRunEntry>
  13. {
  14. public TrackRunBox() : base() { }
  15. public TrackRunBox(Stream stream) : base(stream) { }
  16. internal override ulong CalculateSize()
  17. {
  18. ulong calculatedSize = base.CalculateSize() + 4;
  19. if ((Flags & TrackRunFlags.DataOffsetPresent) == TrackRunFlags.DataOffsetPresent)
  20. calculatedSize += 4;
  21. if ((Flags & TrackRunFlags.FirstSampleFlagsPresent) == TrackRunFlags.FirstSampleFlagsPresent)
  22. calculatedSize += 4;
  23. ulong entryLength = 0;
  24. if ((Flags & TrackRunFlags.SampleDurationPresent) == TrackRunFlags.SampleDurationPresent)
  25. entryLength += 4;
  26. if ((Flags & TrackRunFlags.SampleSizePresent) == TrackRunFlags.SampleSizePresent)
  27. entryLength += 4;
  28. if ((Flags & TrackRunFlags.SampleFlagsPresent) == TrackRunFlags.SampleFlagsPresent)
  29. entryLength += 4;
  30. if ((Flags & TrackRunFlags.SampleCompositionTimeOffsetsPresent) == TrackRunFlags.SampleCompositionTimeOffsetsPresent)
  31. entryLength += 4;
  32. return calculatedSize + (entryLength * (ulong)_Entries.Count);
  33. }
  34. protected override void LoadFromStream(Stream stream)
  35. {
  36. base.LoadFromStream(stream);
  37. uint sampleCount = stream.ReadBEUInt32();
  38. if ((Flags & TrackRunFlags.DataOffsetPresent) == TrackRunFlags.DataOffsetPresent)
  39. DataOffset = stream.ReadBEInt32();
  40. if ((Flags & TrackRunFlags.FirstSampleFlagsPresent) == TrackRunFlags.FirstSampleFlagsPresent)
  41. FirstSampleFlags = new SampleFlags(stream.ReadBEUInt32());
  42. for (uint i = 0; i < sampleCount; i++)
  43. {
  44. TrackRunEntry entry = new TrackRunEntry();
  45. if ((Flags & TrackRunFlags.SampleDurationPresent) == TrackRunFlags.SampleDurationPresent)
  46. entry.SampleDuration = stream.ReadBEUInt32();
  47. if ((Flags & TrackRunFlags.SampleSizePresent) == TrackRunFlags.SampleSizePresent)
  48. entry.SampleSize = stream.ReadBEUInt32();
  49. if ((Flags & TrackRunFlags.SampleFlagsPresent) == TrackRunFlags.SampleFlagsPresent)
  50. entry.SampleFlags = new SampleFlags(stream.ReadBEUInt32());
  51. if ((Flags & TrackRunFlags.SampleCompositionTimeOffsetsPresent) == TrackRunFlags.SampleCompositionTimeOffsetsPresent)
  52. entry.SampleCompositionTimeOffset = stream.ReadBEUInt32();
  53. _Entries.Add(entry);
  54. }
  55. }
  56. protected override void SaveToStream(Stream stream)
  57. {
  58. if (DataOffset.HasValue) Flags |= TrackRunFlags.DataOffsetPresent;
  59. if (FirstSampleFlags != null) Flags |= TrackRunFlags.FirstSampleFlagsPresent;
  60. foreach (var entry in _Entries)
  61. {
  62. // TODO: There must be a better way... probably involves changing TrackRunEntry
  63. if (entry.SampleDuration.HasValue) Flags |= TrackRunFlags.SampleDurationPresent;
  64. if (entry.SampleSize.HasValue) Flags |= TrackRunFlags.SampleSizePresent;
  65. if (entry.SampleFlags != null) Flags |= TrackRunFlags.SampleFlagsPresent;
  66. if (entry.SampleCompositionTimeOffset.HasValue) Flags |= TrackRunFlags.SampleCompositionTimeOffsetsPresent;
  67. }
  68. base.SaveToStream(stream);
  69. stream.WriteBEUInt32((uint)_Entries.Count);
  70. if (DataOffset.HasValue)
  71. stream.WriteBEInt32(DataOffset.Value);
  72. if (FirstSampleFlags != null)
  73. stream.WriteBEUInt32(FirstSampleFlags._flags);
  74. foreach (TrackRunEntry entry in _Entries)
  75. {
  76. if ((Flags & TrackRunFlags.SampleDurationPresent) == TrackRunFlags.SampleDurationPresent)
  77. stream.WriteBEUInt32(entry.SampleDuration.HasValue ? entry.SampleDuration.Value : 0);
  78. if ((Flags & TrackRunFlags.SampleSizePresent) == TrackRunFlags.SampleSizePresent)
  79. stream.WriteBEUInt32(entry.SampleSize.HasValue ? entry.SampleSize.Value : 0);
  80. if ((Flags & TrackRunFlags.SampleFlagsPresent) == TrackRunFlags.SampleFlagsPresent)
  81. stream.WriteBEUInt32(entry.SampleFlags != null ? entry.SampleFlags._flags : 0);
  82. if ((Flags & TrackRunFlags.SampleCompositionTimeOffsetsPresent) == TrackRunFlags.SampleCompositionTimeOffsetsPresent)
  83. stream.WriteBEUInt32(entry.SampleCompositionTimeOffset.HasValue ? entry.SampleCompositionTimeOffset.Value : 0);
  84. }
  85. }
  86. private new TrackRunFlags Flags
  87. {
  88. get
  89. {
  90. return (TrackRunFlags)_Flags;
  91. }
  92. set
  93. {
  94. _Flags = (uint)value;
  95. }
  96. }
  97. public int? DataOffset { get; set; }
  98. public SampleFlags FirstSampleFlags { get; set; }
  99. private IList<TrackRunEntry> _Entries = Portability.CreateList<TrackRunEntry>();
  100. public IList<TrackRunEntry> Entries { get { return _Entries; } }
  101. [FlagsAttribute]
  102. public enum TrackRunFlags : uint
  103. {
  104. DataOffsetPresent = 0x000001,
  105. FirstSampleFlagsPresent = 0x000004,
  106. SampleDurationPresent = 0x000100,
  107. SampleSizePresent = 0x000200,
  108. SampleFlagsPresent = 0x000400,
  109. SampleCompositionTimeOffsetsPresent = 0x000800,
  110. }
  111. public class TrackRunEntry
  112. {
  113. public TrackRunEntry() { }
  114. public uint? SampleDuration { get; set; }
  115. public uint? SampleSize { get; set; }
  116. public SampleFlags SampleFlags { get; set; }
  117. public uint? SampleCompositionTimeOffset { get; set; }
  118. }
  119. }
  120. }