MediaPlayer_Events.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. using UnityEngine;
  2. //-----------------------------------------------------------------------------
  3. // Copyright 2015-2022 RenderHeads Ltd. All rights reserved.
  4. //-----------------------------------------------------------------------------
  5. namespace RenderHeads.Media.AVProVideo
  6. {
  7. public partial class MediaPlayer : MonoBehaviour
  8. {
  9. #region Events
  10. // Event state
  11. private bool _eventFired_MetaDataReady = false;
  12. private bool _eventFired_ReadyToPlay = false;
  13. private bool _eventFired_Started = false;
  14. private bool _eventFired_FirstFrameReady = false;
  15. private bool _eventFired_FinishedPlaying = false;
  16. private bool _eventState_PlaybackBuffering = false;
  17. private bool _eventState_PlaybackSeeking = false;
  18. private bool _eventState_PlaybackStalled = false;
  19. private int _eventState_PreviousWidth = 0;
  20. private int _eventState_PreviousHeight = 0;
  21. private int _previousSubtitleIndex = -1;
  22. private bool _finishedFrameOpenCheck = false;
  23. #if UNITY_EDITOR
  24. public static MediaPlayerLoadEvent InternalMediaLoadedEvent = new MediaPlayerLoadEvent();
  25. #endif
  26. private void ResetEvents()
  27. {
  28. _eventFired_MetaDataReady = false;
  29. _eventFired_ReadyToPlay = false;
  30. _eventFired_Started = false;
  31. _eventFired_FirstFrameReady = false;
  32. _eventFired_FinishedPlaying = false;
  33. _eventState_PlaybackBuffering = false;
  34. _eventState_PlaybackSeeking = false;
  35. _eventState_PlaybackStalled = false;
  36. _eventState_PreviousWidth = 0;
  37. _eventState_PreviousHeight = 0;
  38. _previousSubtitleIndex = -1;
  39. _finishedFrameOpenCheck = false;
  40. }
  41. private void UpdateEvents()
  42. {
  43. if (_events != null && _controlInterface != null && _events.HasListeners())
  44. {
  45. //NOTE: Fixes a bug where the event was being fired immediately, so when a file is opened, the finishedPlaying fired flag gets set but
  46. //is then set to true immediately afterwards due to the returned value
  47. _finishedFrameOpenCheck = false;
  48. if (IsHandleEvent(MediaPlayerEvent.EventType.FinishedPlaying))
  49. {
  50. if (FireEventIfPossible(MediaPlayerEvent.EventType.FinishedPlaying, _eventFired_FinishedPlaying))
  51. {
  52. _eventFired_FinishedPlaying = !_finishedFrameOpenCheck;
  53. }
  54. }
  55. // Reset some event states that can reset during playback
  56. {
  57. // Keep track of whether the Playing state has changed
  58. if (_eventFired_Started && IsHandleEvent(MediaPlayerEvent.EventType.Started) &&
  59. _controlInterface != null && !_controlInterface.IsPlaying() && !_controlInterface.IsSeeking())
  60. {
  61. // Playing has stopped
  62. _eventFired_Started = false;
  63. }
  64. // NOTE: We check _controlInterface isn't null in case the scene is unloaded in response to the FinishedPlaying event
  65. if (_eventFired_FinishedPlaying && IsHandleEvent(MediaPlayerEvent.EventType.FinishedPlaying) &&
  66. _controlInterface != null && _controlInterface.IsPlaying() && !_controlInterface.IsFinished())
  67. {
  68. bool reset = true;
  69. #if UNITY_EDITOR_WIN || (!UNITY_EDITOR && (UNITY_STANDALONE_WIN || UNITY_WSA))
  70. reset = false;
  71. if (_infoInterface.HasVideo())
  72. {
  73. // Some streaming HLS/Dash content don't provide a frame rate
  74. if (_infoInterface.GetVideoFrameRate() > 0f)
  75. {
  76. // Don't reset if within a frame of the end of the video, important for time > duration workaround
  77. float secondsPerFrame = 1f / _infoInterface.GetVideoFrameRate();
  78. if (_infoInterface.GetDuration() - _controlInterface.GetCurrentTime() > secondsPerFrame)
  79. {
  80. reset = true;
  81. }
  82. }
  83. else
  84. {
  85. // Just check if we're not beyond the duration
  86. if (_controlInterface.GetCurrentTime() < _infoInterface.GetDuration())
  87. {
  88. reset = true;
  89. }
  90. }
  91. }
  92. else
  93. {
  94. // For audio only media just check if we're not beyond the duration
  95. if (_controlInterface.GetCurrentTime() < _infoInterface.GetDuration())
  96. {
  97. reset = true;
  98. }
  99. }
  100. #endif
  101. if (reset)
  102. {
  103. //Debug.Log("Reset");
  104. _eventFired_FinishedPlaying = false;
  105. }
  106. }
  107. }
  108. // Events that can only fire once
  109. {
  110. _eventFired_MetaDataReady = FireEventIfPossible(MediaPlayerEvent.EventType.MetaDataReady, _eventFired_MetaDataReady);
  111. _eventFired_ReadyToPlay = FireEventIfPossible(MediaPlayerEvent.EventType.ReadyToPlay, _eventFired_ReadyToPlay);
  112. _eventFired_Started = FireEventIfPossible(MediaPlayerEvent.EventType.Started, _eventFired_Started);
  113. _eventFired_FirstFrameReady = FireEventIfPossible(MediaPlayerEvent.EventType.FirstFrameReady, _eventFired_FirstFrameReady);
  114. }
  115. // Events that can fire multiple times
  116. {
  117. // Subtitle changing
  118. if (FireEventIfPossible(MediaPlayerEvent.EventType.SubtitleChange, false))
  119. {
  120. _previousSubtitleIndex = _subtitlesInterface.GetSubtitleIndex();
  121. }
  122. // Resolution changing
  123. if (FireEventIfPossible(MediaPlayerEvent.EventType.ResolutionChanged, false))
  124. {
  125. _eventState_PreviousWidth = _infoInterface.GetVideoWidth();
  126. _eventState_PreviousHeight = _infoInterface.GetVideoHeight();
  127. }
  128. // Stalling
  129. if (IsHandleEvent(MediaPlayerEvent.EventType.Stalled))
  130. {
  131. bool newState = _infoInterface.IsPlaybackStalled();
  132. if (newState != _eventState_PlaybackStalled)
  133. {
  134. _eventState_PlaybackStalled = newState;
  135. var newEvent = _eventState_PlaybackStalled ? MediaPlayerEvent.EventType.Stalled : MediaPlayerEvent.EventType.Unstalled;
  136. FireEventIfPossible(newEvent, false);
  137. }
  138. }
  139. // Seeking
  140. if (IsHandleEvent(MediaPlayerEvent.EventType.StartedSeeking))
  141. {
  142. bool newState = _controlInterface.IsSeeking();
  143. if (newState != _eventState_PlaybackSeeking)
  144. {
  145. _eventState_PlaybackSeeking = newState;
  146. var newEvent = _eventState_PlaybackSeeking ? MediaPlayerEvent.EventType.StartedSeeking : MediaPlayerEvent.EventType.FinishedSeeking;
  147. FireEventIfPossible(newEvent, false);
  148. }
  149. }
  150. // Buffering
  151. if (IsHandleEvent(MediaPlayerEvent.EventType.StartedBuffering))
  152. {
  153. bool newState = _controlInterface.IsBuffering();
  154. if (newState != _eventState_PlaybackBuffering)
  155. {
  156. _eventState_PlaybackBuffering = newState;
  157. var newEvent = _eventState_PlaybackBuffering ? MediaPlayerEvent.EventType.StartedBuffering : MediaPlayerEvent.EventType.FinishedBuffering;
  158. FireEventIfPossible(newEvent, false);
  159. }
  160. }
  161. }
  162. }
  163. }
  164. protected bool IsHandleEvent(MediaPlayerEvent.EventType eventType)
  165. {
  166. return ((uint)_eventMask & (1 << (int)eventType)) != 0;
  167. }
  168. private bool FireEventIfPossible(MediaPlayerEvent.EventType eventType, bool hasFired)
  169. {
  170. if (CanFireEvent(eventType, hasFired))
  171. {
  172. #if UNITY_EDITOR
  173. // Special internal global event, called when media is loaded
  174. // Currently used by the RecentItem class
  175. if (eventType == MediaPlayerEvent.EventType.Started)
  176. {
  177. string fullPath = GetResolvedFilePath(_mediaPath.Path, _mediaPath.PathType);
  178. InternalMediaLoadedEvent.Invoke(fullPath);
  179. }
  180. #endif
  181. hasFired = true;
  182. _events.Invoke(this, eventType, ErrorCode.None);
  183. }
  184. return hasFired;
  185. }
  186. private bool CanFireEvent(MediaPlayerEvent.EventType et, bool hasFired)
  187. {
  188. bool result = false;
  189. if (_events != null && _controlInterface != null && !hasFired && IsHandleEvent(et))
  190. {
  191. switch (et)
  192. {
  193. case MediaPlayerEvent.EventType.FinishedPlaying:
  194. result = (!_controlInterface.IsLooping() && _controlInterface.CanPlay() && _controlInterface.IsFinished());
  195. break;
  196. case MediaPlayerEvent.EventType.MetaDataReady:
  197. result = (_controlInterface.HasMetaData());
  198. break;
  199. case MediaPlayerEvent.EventType.FirstFrameReady:
  200. // [MOZ 20/1/21] Removed HasMetaData check as preventing the event from being triggered on (i|mac|tv)OS
  201. result = (_textureInterface != null && _controlInterface.CanPlay() /*&& _controlInterface.HasMetaData()*/ && _textureInterface.GetTextureFrameCount() > 0);
  202. break;
  203. case MediaPlayerEvent.EventType.ReadyToPlay:
  204. result = (!_controlInterface.IsPlaying() && _controlInterface.CanPlay() && !_autoPlayOnStart);
  205. break;
  206. case MediaPlayerEvent.EventType.Started:
  207. result = (_controlInterface.IsPlaying());
  208. break;
  209. case MediaPlayerEvent.EventType.SubtitleChange:
  210. {
  211. result = (_previousSubtitleIndex != _subtitlesInterface.GetSubtitleIndex());
  212. if (!result)
  213. {
  214. result = _baseMediaPlayer.InternalIsChangedTextCue();
  215. }
  216. break;
  217. }
  218. case MediaPlayerEvent.EventType.Stalled:
  219. result = _infoInterface.IsPlaybackStalled();
  220. break;
  221. case MediaPlayerEvent.EventType.Unstalled:
  222. result = !_infoInterface.IsPlaybackStalled();
  223. break;
  224. case MediaPlayerEvent.EventType.StartedSeeking:
  225. result = _controlInterface.IsSeeking();
  226. break;
  227. case MediaPlayerEvent.EventType.FinishedSeeking:
  228. result = !_controlInterface.IsSeeking();
  229. break;
  230. case MediaPlayerEvent.EventType.StartedBuffering:
  231. result = _controlInterface.IsBuffering();
  232. break;
  233. case MediaPlayerEvent.EventType.FinishedBuffering:
  234. result = !_controlInterface.IsBuffering();
  235. break;
  236. case MediaPlayerEvent.EventType.ResolutionChanged:
  237. result = (_infoInterface != null && (_eventState_PreviousWidth != _infoInterface.GetVideoWidth() || _eventState_PreviousHeight != _infoInterface.GetVideoHeight()));
  238. break;
  239. default:
  240. Debug.LogWarning("[AVProVideo] Unhandled event type");
  241. break;
  242. }
  243. }
  244. return result;
  245. }
  246. #endregion // Events
  247. }
  248. }