BaseMediaPlayer.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. #if UNITY_EDITOR || UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN
  2. #define UNITY_PLATFORM_SUPPORTS_LINEAR
  3. #elif UNITY_IOS || UNITY_ANDROID
  4. #if UNITY_5_5_OR_NEWER || (UNITY_5 && !UNITY_5_0 && !UNITY_5_1 && !UNITY_5_2 && !UNITY_5_3 && !UNITY_5_4)
  5. #define UNITY_PLATFORM_SUPPORTS_LINEAR
  6. #endif
  7. #endif
  8. using UnityEngine;
  9. using System.Collections.Generic;
  10. #if NETFX_CORE
  11. using Windows.Storage.Streams;
  12. #endif
  13. //-----------------------------------------------------------------------------
  14. // Copyright 2015-2020 RenderHeads Ltd. All rights reserved.
  15. //-----------------------------------------------------------------------------
  16. namespace RenderHeads.Media.AVProVideo
  17. {
  18. /// <summary>
  19. /// Base class for all platform specific MediaPlayers
  20. /// </summary>
  21. public abstract class BaseMediaPlayer : IMediaPlayer, IMediaControl, IMediaInfo, IMediaProducer, IMediaSubtitles, System.IDisposable
  22. {
  23. public abstract string GetVersion();
  24. public abstract bool OpenVideoFromFile(string path, long offset, string httpHeaderJson, uint sourceSamplerate = 0, uint sourceChannels = 0, int forceFileFormat = 0);
  25. #if NETFX_CORE
  26. public virtual bool OpenVideoFromFile(IRandomAccessStream ras, string path, long offset, string httpHeaderJson, uint sourceSamplerate = 0, uint sourceChannels = 0){return false;}
  27. #endif
  28. public virtual bool OpenVideoFromBuffer(byte[] buffer) { return false; }
  29. public virtual bool StartOpenVideoFromBuffer(ulong length) { return false; }
  30. public virtual bool AddChunkToVideoBuffer(byte[] chunk, ulong offset, ulong length) { return false; }
  31. public virtual bool EndOpenVideoFromBuffer() { return false; }
  32. public virtual void CloseVideo()
  33. {
  34. _stallDetectionTimer = 0f;
  35. _stallDetectionFrame = 0;
  36. _lastError = ErrorCode.None;
  37. }
  38. public abstract void SetLooping(bool bLooping);
  39. public abstract bool IsLooping();
  40. public abstract bool HasMetaData();
  41. public abstract bool CanPlay();
  42. public abstract void Play();
  43. public abstract void Pause();
  44. public abstract void Stop();
  45. public virtual void Rewind() { SeekFast(0.0f); }
  46. public abstract void Seek(float timeMs);
  47. public abstract void SeekFast(float timeMs);
  48. public virtual void SeekWithTolerance(float timeMs, float beforeMs, float afterMs) { Seek(timeMs); }
  49. public abstract float GetCurrentTimeMs();
  50. public virtual double GetCurrentDateTimeSecondsSince1970() { return 0.0; }
  51. public virtual TimeRange[] GetSeekableTimeRanges() { return _seekableTimeRanges; }
  52. public abstract float GetPlaybackRate();
  53. public abstract void SetPlaybackRate(float rate);
  54. public abstract float GetDurationMs();
  55. public abstract int GetVideoWidth();
  56. public abstract int GetVideoHeight();
  57. public virtual Rect GetCropRect() { return new Rect(0f, 0f, 0f, 0f); }
  58. public abstract float GetVideoDisplayRate();
  59. public abstract bool HasAudio();
  60. public abstract bool HasVideo();
  61. public abstract bool IsSeeking();
  62. public abstract bool IsPlaying();
  63. public abstract bool IsPaused();
  64. public abstract bool IsFinished();
  65. public abstract bool IsBuffering();
  66. public virtual bool WaitForNextFrame(Camera dummyCamera, int previousFrameCount) { return false; }
  67. public virtual void SetPlayWithoutBuffering(bool playWithoutBuffering) { }
  68. public virtual void SetKeyServerURL(string url) { }
  69. public virtual void SetKeyServerAuthToken(string token) { }
  70. public virtual void SetDecryptionKeyBase64(string key) { }
  71. public virtual void SetDecryptionKey(byte[] key) { }
  72. public virtual int GetTextureCount() { return 1; }
  73. public abstract Texture GetTexture(int index = 0);
  74. public abstract int GetTextureFrameCount();
  75. public virtual bool SupportsTextureFrameCount() { return true; }
  76. public virtual long GetTextureTimeStamp() { return long.MinValue; }
  77. public abstract bool RequiresVerticalFlip();
  78. public virtual float[] GetTextureTransform() { return new float[] { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }; }
  79. public virtual Matrix4x4 GetYpCbCrTransform() { return Matrix4x4.identity; }
  80. public abstract void MuteAudio(bool bMuted);
  81. public abstract bool IsMuted();
  82. public abstract void SetVolume(float volume);
  83. public virtual void SetBalance(float balance) { }
  84. public abstract float GetVolume();
  85. public virtual float GetBalance() { return 0f; }
  86. public abstract int GetAudioTrackCount();
  87. public virtual string GetAudioTrackId(int index) { return index.ToString(); }
  88. public abstract int GetCurrentAudioTrack();
  89. public abstract void SetAudioTrack(int index);
  90. public abstract string GetCurrentAudioTrackId();
  91. public abstract int GetCurrentAudioTrackBitrate();
  92. public virtual int GetNumAudioChannels() { return -1; }
  93. public virtual void SetAudioHeadRotation(Quaternion q) { }
  94. public virtual void ResetAudioHeadRotation() { }
  95. public virtual void SetAudioChannelMode(Audio360ChannelMode channelMode) { }
  96. public virtual void SetAudioFocusEnabled(bool enabled) { }
  97. public virtual void SetAudioFocusProperties(float offFocusLevel, float widthDegrees) { }
  98. public virtual void SetAudioFocusRotation(Quaternion q) { }
  99. public virtual void ResetAudioFocus() { }
  100. public abstract int GetVideoTrackCount();
  101. public virtual string GetVideoTrackId(int index) { return index.ToString(); }
  102. public abstract int GetCurrentVideoTrack();
  103. public abstract void SetVideoTrack(int index);
  104. public abstract string GetCurrentVideoTrackId();
  105. public abstract int GetCurrentVideoTrackBitrate();
  106. public abstract float GetVideoFrameRate();
  107. public virtual long GetEstimatedTotalBandwidthUsed() { return -1; }
  108. public abstract float GetBufferingProgress();
  109. public abstract void Update();
  110. public abstract void Render();
  111. public abstract void Dispose();
  112. public ErrorCode GetLastError()
  113. {
  114. return _lastError;
  115. }
  116. public virtual long GetLastExtendedErrorCode()
  117. {
  118. return 0;
  119. }
  120. public string GetPlayerDescription()
  121. {
  122. return _playerDescription;
  123. }
  124. public virtual bool PlayerSupportsLinearColorSpace()
  125. {
  126. #if UNITY_PLATFORM_SUPPORTS_LINEAR
  127. return true;
  128. #else
  129. return false;
  130. #endif
  131. }
  132. public virtual int GetBufferedTimeRangeCount() { return 0; }
  133. public virtual bool GetBufferedTimeRange(int index, ref float startTimeMs, ref float endTimeMs) { return false; }
  134. protected string _playerDescription = string.Empty;
  135. protected ErrorCode _lastError = ErrorCode.None;
  136. protected FilterMode _defaultTextureFilterMode = FilterMode.Bilinear;
  137. protected TextureWrapMode _defaultTextureWrapMode = TextureWrapMode.Clamp;
  138. protected int _defaultTextureAnisoLevel = 1;
  139. protected TimeRange[] _seekableTimeRanges = new TimeRange[0];
  140. public void SetTextureProperties(FilterMode filterMode = FilterMode.Bilinear, TextureWrapMode wrapMode = TextureWrapMode.Clamp, int anisoLevel = 0)
  141. {
  142. _defaultTextureFilterMode = filterMode;
  143. _defaultTextureWrapMode = wrapMode;
  144. _defaultTextureAnisoLevel = anisoLevel;
  145. for (int i = 0; i < GetTextureCount(); ++i)
  146. {
  147. ApplyTextureProperties(GetTexture(i));
  148. }
  149. }
  150. protected virtual void ApplyTextureProperties(Texture texture)
  151. {
  152. if (texture != null)
  153. {
  154. texture.filterMode = _defaultTextureFilterMode;
  155. texture.wrapMode = _defaultTextureWrapMode;
  156. texture.anisoLevel = _defaultTextureAnisoLevel;
  157. }
  158. }
  159. public virtual void GrabAudio(float[] buffer, int floatCount, int channelCount)
  160. {
  161. }
  162. protected bool IsExpectingNewVideoFrame()
  163. {
  164. if (HasVideo())
  165. {
  166. // If we're playing then we expect a new frame
  167. if (!IsFinished() && (!IsPaused() || IsPlaying()))
  168. {
  169. // NOTE: if a new frame isn't available then we could either be seeking or stalled
  170. return true;
  171. }
  172. }
  173. return false;
  174. }
  175. public virtual bool IsPlaybackStalled()
  176. {
  177. const float StallDetectionDuration = 0.75f;
  178. // Manually detect stalled video if the platform doesn't have native support to detect it
  179. if (SupportsTextureFrameCount() && IsExpectingNewVideoFrame())
  180. {
  181. int frameCount = GetTextureFrameCount();
  182. if (frameCount != _stallDetectionFrame)
  183. {
  184. _stallDetectionTimer = 0f;
  185. _stallDetectionFrame = frameCount;
  186. }
  187. else
  188. {
  189. _stallDetectionTimer += Time.deltaTime;
  190. }
  191. return (_stallDetectionTimer > StallDetectionDuration);
  192. }
  193. else
  194. {
  195. _stallDetectionTimer = 0f;
  196. }
  197. return false;
  198. }
  199. private float _stallDetectionTimer;
  200. private int _stallDetectionFrame;
  201. protected List<Subtitle> _subtitles;
  202. protected Subtitle _currentSubtitle;
  203. public bool LoadSubtitlesSRT(string data)
  204. {
  205. if (string.IsNullOrEmpty(data))
  206. {
  207. // Disable subtitles
  208. _subtitles = null;
  209. _currentSubtitle = null;
  210. }
  211. else
  212. {
  213. _subtitles = Helper.LoadSubtitlesSRT(data);
  214. _currentSubtitle = null;
  215. }
  216. return (_subtitles != null);
  217. }
  218. public virtual void UpdateSubtitles()
  219. {
  220. if (_subtitles != null)
  221. {
  222. float time = GetCurrentTimeMs();
  223. // TODO: implement a more efficient subtitle index searcher
  224. int searchIndex = 0;
  225. if (_currentSubtitle != null)
  226. {
  227. if (!_currentSubtitle.IsTime(time))
  228. {
  229. if (time > _currentSubtitle.timeEndMs)
  230. {
  231. searchIndex = _currentSubtitle.index + 1;
  232. }
  233. _currentSubtitle = null;
  234. }
  235. }
  236. if (_currentSubtitle == null)
  237. {
  238. for (int i = searchIndex; i < _subtitles.Count; i++)
  239. {
  240. if (_subtitles[i].IsTime(time))
  241. {
  242. _currentSubtitle = _subtitles[i];
  243. break;
  244. }
  245. }
  246. }
  247. }
  248. }
  249. public virtual int GetSubtitleIndex()
  250. {
  251. int result = -1;
  252. if (_currentSubtitle != null)
  253. {
  254. result = _currentSubtitle.index;
  255. }
  256. return result;
  257. }
  258. public virtual string GetSubtitleText()
  259. {
  260. string result = string.Empty;
  261. if (_currentSubtitle != null)
  262. {
  263. result = _currentSubtitle.text;
  264. }
  265. return result;
  266. }
  267. public virtual void OnEnable()
  268. {
  269. }
  270. }
  271. }