/FlvPropertySheet/FlvTag/FlvTagReader.cs

http://tsanie-shellextension.googlecode.com/ · C# · 166 lines · 148 code · 17 blank · 1 comment · 27 complexity · cdd897ee65d635b8f4ae4382b6df72bd MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading;
  6. using System.IO;
  7. using Tsanie.ShellExtension;
  8. using Tsanie.ShellExtension.Util;
  9. namespace Tsanie.FlvTag {
  10. public class FlvTagReader {
  11. #region - Fields -
  12. private string _filename;
  13. private long _length;
  14. private long _seek;
  15. private uint _duration;
  16. private double _rate;
  17. private ScriptTag _metaTag;
  18. private List<FlvTag> _tags;
  19. private int _maxTagSize;
  20. private Predicate<FlvTag> _predicate;
  21. private Action<long> _maximumGetted;
  22. private Action<int> _done;
  23. #endregion
  24. #region - Properties -
  25. public Predicate<FlvTag> Predicate { set { _predicate = value; } }
  26. public Action<long> MaximumGetted { set { _maximumGetted = value; } }
  27. public Action<int> Done { set { _done = value; } }
  28. public long Length { get { return _length; } }
  29. public long Seek { get { return _seek; } }
  30. public uint Duration { get { return _duration; } }
  31. public double Rate { get { return _rate; } }
  32. public List<FlvTag> Tags { get { return _tags; } }
  33. public string Filename { get { return _filename; } }
  34. public ScriptTag MetaTag { get { return _metaTag; } }
  35. public int MaxTagSize { get { return _maxTagSize; } }
  36. #endregion
  37. public FlvTagReader(string filename) {
  38. _filename = filename;
  39. _length = 0;
  40. _seek = 0;
  41. _duration = 0;
  42. _rate = 0;
  43. _metaTag = null;
  44. _tags = new List<FlvTag>();
  45. _predicate = (t) => true;
  46. }
  47. #region - Public Methods -
  48. public Thread StartRead() {
  49. if (_filename == null)
  50. return null;
  51. FileStream fs = new FileStream(_filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
  52. _length = fs.Length;
  53. _maximumGetted.SafeRun(_length);
  54. FLVHeader header = FLVHeader.ReadHeader(fs);
  55. if (!header.IsFlv)
  56. return null;
  57. Thread thread = new Thread(delegate() {
  58. try {
  59. fs.Seek(header.Length, SeekOrigin.Begin);
  60. _tags.Clear();
  61. FlvTag tag;
  62. while ((tag = FlvTag.ReadTag(fs)) != null) {
  63. if (tag is ScriptTag)
  64. _metaTag = tag as ScriptTag;
  65. _tags.Add(tag);
  66. if (_duration < tag.TimeStamp)
  67. _duration = tag.TimeStamp;
  68. if (_maxTagSize < tag.DataSize)
  69. _maxTagSize = tag.DataSize;
  70. _seek += tag.DataSize;
  71. if (!_predicate.SafeRun(tag))
  72. break;
  73. }
  74. if (_tags.Count > 1) {
  75. _length = _length - _tags[1].Offset + 11;
  76. _rate = (_duration == 0 ? 0 : _length * 8 / _duration);
  77. }
  78. #if TRACE
  79. Common.OutputDebugString("StartRead(void):: read {0} tag(s).", _tags.Count);
  80. #endif
  81. } catch (Exception e) {
  82. Common.OutputDebugString("StartRead(void):: {0} - {1}", e.GetType().FullName, e.Message);
  83. } finally {
  84. fs.Close();
  85. fs = null;
  86. _done.SafeRun(_tags.Count);
  87. }
  88. });
  89. thread.Name = "thread_ReadFile_" + _filename;
  90. thread.Start();
  91. return thread;
  92. }
  93. public void Remove(int index) {
  94. if (index < 0 || index >= _tags.Count)
  95. return;
  96. FlvTag tag = _tags[index];
  97. if (_duration <= tag.TimeStamp)
  98. RefreshDuration();
  99. _length -= tag.DataSize + 11;
  100. _tags.RemoveAt(index);
  101. }
  102. public void RefreshDuration() {
  103. uint max = 0;
  104. foreach (FlvTag t in _tags)
  105. if (max < t.TimeStamp)
  106. max = t.TimeStamp;
  107. _duration = max;
  108. _rate = (_duration == 0 ? 0 : _length * 8 / _duration);
  109. }
  110. #endregion
  111. }
  112. class FLVHeader {
  113. private byte[] signature;
  114. private byte version;
  115. private byte typeflag;
  116. private int dataoffset;
  117. private FLVHeader() {
  118. signature = new byte[3];
  119. version = 0;
  120. typeflag = 0;
  121. dataoffset = 0;
  122. }
  123. public static FLVHeader ReadHeader(Stream stream) {
  124. FLVHeader header = new FLVHeader();
  125. byte[] buffer = new byte[4];
  126. stream.Read(header.signature, 0, 3);
  127. stream.Read(buffer, 0, 1);
  128. header.version = buffer[0];
  129. stream.Read(buffer, 0, 1);
  130. header.typeflag = buffer[0];
  131. try {
  132. header.dataoffset = (int)stream.ReadUI32();
  133. } catch { }
  134. return header;
  135. }
  136. public bool IsFlv {
  137. get {
  138. if (signature == null || signature.Length != 3)
  139. return false;
  140. // 'FLV'
  141. return (signature[0] == 0x46) && (signature[1] == 0x4C) && (signature[2] == 0x56);
  142. }
  143. }
  144. public int Version { get { return version; } }
  145. public bool HasVideo { get { return (typeflag & 0x1) == 0x1; } }
  146. public bool HasAudio { get { return (typeflag & 0x4) == 0x4; } }
  147. public int Length { get { return dataoffset; } }
  148. }
  149. }