Player.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. using Microsoft.Xna.Framework;
  2. using Microsoft.Xna.Framework.Graphics;
  3. using System;
  4. using System.Linq;
  5. namespace OpenVIII.Movie
  6. {
  7. public class Player : IDisposable
  8. {
  9. #region Fields
  10. public static readonly int[] LetterBox = new int[] { 101, 103, 104 };
  11. private static Files Files;
  12. private STATE _state;
  13. private AV.Audio Audio;
  14. private bool disposedValue = false;
  15. private bool SuppressDraw;
  16. private Texture2D Texture;
  17. private AV.Video Video;
  18. #endregion Fields
  19. #region Destructors
  20. // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
  21. ~Player()
  22. {
  23. // // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
  24. Dispose(false);
  25. }
  26. #endregion Destructors
  27. #region Events
  28. public event EventHandler<STATE> StateChanged;
  29. #endregion Events
  30. #region Properties
  31. public int ID { get; private set; }
  32. // To detect redundant calls
  33. public bool IsDisposed => disposedValue;
  34. public STATE STATE
  35. {
  36. get => _state; private set
  37. {
  38. _state = value;
  39. StateChanged?.Invoke(this, value);
  40. }
  41. }
  42. #endregion Properties
  43. #region Methods
  44. public static Player Load(int ID, bool OverlayingModels = false)
  45. {
  46. if (Files.Exists(ID))
  47. {
  48. Player Player = new Player()
  49. {
  50. ID = ID,
  51. STATE = STATE.LOAD,
  52. Video = AV.Video.Load(Files[ID]),
  53. Audio = AV.Audio.Load(Files[ID]),
  54. SuppressDraw = !OverlayingModels
  55. };
  56. Player.STATE++;
  57. return Player;
  58. }
  59. return null;
  60. }
  61. // This code added to correctly implement the disposable pattern.
  62. public void Dispose() =>
  63. // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
  64. Dispose(true);
  65. public void Draw()
  66. {
  67. switch (STATE)
  68. {
  69. case STATE.LOAD:
  70. break;
  71. case STATE.CLEAR:
  72. STATE++;
  73. ClearScreen();
  74. break;
  75. case STATE.STARTPLAY:
  76. case STATE.PLAYING:
  77. PlayingDraw();
  78. break;
  79. case STATE.PAUSED:
  80. break;
  81. case STATE.FINISHED:
  82. STATE++;
  83. PlayingDraw();
  84. break;
  85. case STATE.RESET:
  86. break;
  87. case STATE.RETURN:
  88. default:
  89. break;
  90. }
  91. }
  92. public void PlayingDraw()
  93. {
  94. if (Texture == null)
  95. {
  96. return;
  97. }
  98. //draw frame;
  99. Viewport vp = Memory.graphics.GraphicsDevice.Viewport;
  100. Memory.SpriteBatchStartStencil(ss: SamplerState.AnisotropicClamp);//by default xna filters all textures SamplerState.PointClamp disables that. so video is being filtered why playing.
  101. ClearScreen();
  102. Rectangle dst = new Rectangle(new Point(0), (new Vector2(Texture.Width, Texture.Height) * Memory.Scale(Texture.Width, Texture.Height, LetterBox.Contains(ID) ? Memory.ScaleMode.FitHorizontal : Memory.ScaleMode.FitBoth)).ToPoint());
  103. dst.Offset(Memory.Center.X - dst.Center.X, Memory.Center.Y - dst.Center.Y);
  104. Memory.spriteBatch.Draw(Texture, dst, Microsoft.Xna.Framework.Color.White);
  105. Memory.SpriteBatchEnd();
  106. }
  107. public void STOP()
  108. {
  109. Audio.Dispose();
  110. Video.Dispose();
  111. STATE = STATE.RETURN;
  112. }
  113. public void Update()
  114. {
  115. switch (STATE)
  116. {
  117. case STATE.LOAD:
  118. break;
  119. case STATE.CLEAR:
  120. break;
  121. case STATE.STARTPLAY:
  122. STATE++;
  123. if (Audio != null)
  124. {
  125. Audio.PlayInTask();
  126. }
  127. if (Video != null)
  128. {
  129. Video.Play();
  130. }
  131. break;
  132. case STATE.PLAYING:
  133. //if (Audio != null && !Audio.Ahead)
  134. //{
  135. // // if we are behind the timer get the next frame of audio.
  136. // Audio.Next();
  137. //}
  138. if (Video == null)
  139. STATE = STATE.FINISHED;
  140. else if (Video.Behind)
  141. {
  142. if (Video.Next() < 0)
  143. {
  144. STATE = STATE.FINISHED;
  145. //Memory.SuppressDraw = true;
  146. break;
  147. }
  148. else if (Texture != null)
  149. {
  150. Texture.Dispose();
  151. GC.Collect();
  152. GC.WaitForPendingFinalizers();
  153. Texture = null;
  154. }
  155. }
  156. else
  157. {
  158. //Memory next frame is skipped.
  159. Memory.SuppressDraw = SuppressDraw;
  160. }
  161. if (Texture == null)
  162. {
  163. if (Video != null)
  164. {
  165. if (Memory.State?.Fieldvars != null)
  166. Memory.State.Fieldvars.FMVFrames = (ulong)Video.CurrentFrameNum;
  167. Texture = Video.Texture2D();
  168. }
  169. }
  170. break;
  171. case STATE.PAUSED:
  172. //todo add a function to pause sound
  173. //pausing the stopwatch will cause the video to pause because it calcs the current frame based on time.
  174. break;
  175. case STATE.FINISHED:
  176. break;
  177. case STATE.RESET:
  178. break;
  179. case STATE.RETURN:
  180. default:
  181. break;
  182. }
  183. }
  184. protected virtual void Dispose(bool disposing)
  185. {
  186. if (!disposedValue)
  187. {
  188. if (disposing)
  189. {
  190. // TODO: dispose managed state (managed objects).
  191. }
  192. // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
  193. // TODO: set large fields to null.
  194. if (!Video.IsDisposed)
  195. Video.Dispose();
  196. if (!Audio.IsDisposed)
  197. Audio.Dispose();
  198. if (Texture != null && !Texture.IsDisposed)
  199. Texture.Dispose();
  200. disposedValue = true;
  201. }
  202. }
  203. private static void ClearScreen() => Memory.spriteBatch.GraphicsDevice.Clear(Microsoft.Xna.Framework.Color.Black);
  204. #endregion Methods
  205. // TODO: uncomment the following line if the finalizer is overridden above.// GC.SuppressFinalize(this);
  206. }
  207. }