PlaylistMediaPlayer.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. //-----------------------------------------------------------------------------
  5. // Copyright 2015-2022 RenderHeads Ltd. All rights reserved.
  6. //-----------------------------------------------------------------------------
  7. namespace RenderHeads.Media.AVProVideo
  8. {
  9. [System.Serializable]
  10. public class MediaPlaylist
  11. {
  12. [System.Serializable]
  13. public class MediaItem
  14. {
  15. public enum SourceType
  16. {
  17. AVProVideoPlayer,
  18. //Texture2D,
  19. }
  20. [SerializeField] public string name = string.Empty;
  21. [SerializeField] public SourceType sourceType = SourceType.AVProVideoPlayer;
  22. [SerializeField] public MediaPath mediaPath = new MediaPath();
  23. [SerializeField] public Texture2D texture = null;
  24. [SerializeField] public float textureDuration;
  25. [SerializeField] public bool loop = false;
  26. [SerializeField] public PlaylistMediaPlayer.StartMode startMode = PlaylistMediaPlayer.StartMode.Immediate;
  27. [SerializeField] public PlaylistMediaPlayer.ProgressMode progressMode = PlaylistMediaPlayer.ProgressMode.OnFinish;
  28. [SerializeField] public float progressTimeSeconds = 0.5f;
  29. [SerializeField] public bool isOverrideTransition = false;
  30. [SerializeField] public PlaylistMediaPlayer.Transition overrideTransition = PlaylistMediaPlayer.Transition.None;
  31. [SerializeField] public float overrideTransitionDuration = 1f;
  32. [SerializeField] public PlaylistMediaPlayer.Easing.Preset overrideTransitionEasing = PlaylistMediaPlayer.Easing.Preset.Linear;
  33. }
  34. [SerializeField] List<MediaItem> _items = new List<MediaItem>(8);
  35. public List<MediaItem> Items { get { return _items; } }
  36. public bool HasItemAt(int index)
  37. {
  38. return (index >= 0 && index < _items.Count);
  39. }
  40. }
  41. /// <summary>
  42. /// This is a BETA component
  43. /// </summary>
  44. [AddComponentMenu("AVPro Video/Playlist Media Player (BETA)", -80)]
  45. [HelpURL("https://www.renderheads.com/products/avpro-video/")]
  46. public class PlaylistMediaPlayer : MediaPlayer, ITextureProducer
  47. {
  48. public enum Transition
  49. {
  50. None,
  51. Fade,
  52. Black,
  53. White,
  54. Transparent,
  55. Horiz,
  56. Vert,
  57. Diag,
  58. MirrorH,
  59. MirrorV,
  60. MirrorD,
  61. ScrollV,
  62. ScrollH,
  63. Circle,
  64. Diamond,
  65. Blinds,
  66. Arrows,
  67. SlideH,
  68. SlideV,
  69. Zoom,
  70. RectV,
  71. Random,
  72. }
  73. public enum PlaylistLoopMode
  74. {
  75. None,
  76. Loop,
  77. }
  78. public enum StartMode
  79. {
  80. Immediate,
  81. //AfterSeconds,
  82. Manual,
  83. }
  84. public enum ProgressMode
  85. {
  86. OnFinish,
  87. BeforeFinish,
  88. //AfterTime,
  89. Manual,
  90. }
  91. [SerializeField] Shader _transitionShader = null;
  92. [SerializeField] MediaPlayer _playerA = null;
  93. [SerializeField] MediaPlayer _playerB = null;
  94. [SerializeField] bool _playlistAutoProgress = true;
  95. [Tooltip("Close the video on the other MediaPlayer when it is not visible any more. This is useful for freeing up memory and GPU decoding resources.")]
  96. [SerializeField] bool _autoCloseVideo = true;
  97. [SerializeField] PlaylistLoopMode _playlistLoopMode = PlaylistLoopMode.None;
  98. [SerializeField] MediaPlaylist _playlist = new MediaPlaylist();
  99. [Tooltip("Pause the previously playing video. This is useful for systems that will struggle to play 2 videos at once")]
  100. [SerializeField] bool _pausePreviousOnTransition = true;
  101. [SerializeField] Transition _defaultTransition = Transition.None;
  102. [SerializeField] float _defaultTransitionDuration = 1f;
  103. [SerializeField] Easing.Preset _defaultTransitionEasing = Easing.Preset.Linear;
  104. private static readonly LazyShaderProperty PropFromTex = new LazyShaderProperty("_FromTex");
  105. private static readonly LazyShaderProperty PropFade = new LazyShaderProperty("_Fade");
  106. private bool _isPaused = false;
  107. private int _playlistIndex = 0;
  108. private MediaPlayer _nextPlayer;
  109. private Material _material;
  110. private Transition _currentTransition = Transition.None;
  111. private string _currentTransitionName = "LERP_NONE";
  112. private float _currentTransitionDuration = 1f;
  113. private Easing.Preset _currentTransitionEasing = Easing.Preset.Linear;
  114. private float _textureTimer;
  115. private float _transitionTimer;
  116. private System.Func<float, float> _easeFunc;
  117. private RenderTexture _rt;
  118. private MediaPlaylist.MediaItem _currentItem;
  119. private MediaPlaylist.MediaItem _nextItem;
  120. public MediaPlayer CurrentPlayer
  121. {
  122. get
  123. {
  124. if (NextPlayer == _playerA)
  125. {
  126. return _playerB;
  127. }
  128. return _playerA;
  129. }
  130. }
  131. public MediaPlayer NextPlayer
  132. {
  133. get
  134. {
  135. return _nextPlayer;
  136. }
  137. }
  138. public MediaPlaylist Playlist { get { return _playlist; } }
  139. public int PlaylistIndex { get { return _playlistIndex; } }
  140. public MediaPlaylist.MediaItem PlaylistItem { get { if (_playlist.HasItemAt(_playlistIndex)) return _playlist.Items[_playlistIndex]; return null; } }
  141. /// <summary>
  142. /// The default transition to use if the transition is not overridden in the MediaItem
  143. /// </summary>
  144. public Transition DefaultTransition { get { return _defaultTransition; } set { _defaultTransition = value; } }
  145. /// <summary>
  146. /// The default duration the transition will take (in seconds) if the transition is not overridden in the MediaItem
  147. /// </summary>
  148. public float DefaultTransitionDuration { get { return _defaultTransitionDuration; } set { _defaultTransitionDuration = value; } }
  149. /// <summary>
  150. /// The default easing the transition will use if the transition is not overridden in the MediaItem
  151. /// </summary>
  152. public Easing.Preset DefaultTransitionEasing { get { return _defaultTransitionEasing; } set { _defaultTransitionEasing = value; } }
  153. /// <summary>
  154. /// Closes videos that aren't playing. This will save memory but adds extra overhead
  155. /// </summary>
  156. public bool AutoCloseVideo { get { return _autoCloseVideo; } set { _autoCloseVideo = value; } }
  157. /// <summary>
  158. /// None: Do not loop the playlist when the end is reached.<br/>Loop: Rewind the playlist and play again when the each is reached
  159. /// </summary>
  160. public PlaylistLoopMode LoopMode { get { return _playlistLoopMode; } set { _playlistLoopMode = value; } }
  161. /// <summary>
  162. /// Enable the playlist to progress to the next item automatically, or wait for manual trigger via scripting
  163. /// </summary>
  164. public bool AutoProgress { get { return _playlistAutoProgress; } set { _playlistAutoProgress = value; } }
  165. /// <summary>
  166. /// Returns the IMediaInfo interface for the MediaPlayer that is playing the current active item in the playlist (returned by CurrentPlayer property). This will change during each transition.
  167. /// </summary>
  168. public override IMediaInfo Info
  169. {
  170. get { if (CurrentPlayer != null) return CurrentPlayer.Info; return null; }
  171. }
  172. /// <summary>
  173. /// Returns the IMediaControl interface for the MediaPlayer that is playing the current active item in the playlist (returned by CurrentPlayer property). This will change during each transition.
  174. /// </summary>
  175. public override IMediaControl Control
  176. {
  177. get { if (CurrentPlayer != null) return CurrentPlayer.Control; return null; }
  178. }
  179. public override ITextureProducer TextureProducer
  180. {
  181. get
  182. {
  183. if (CurrentPlayer != null)
  184. {
  185. if (IsTransitioning())
  186. {
  187. return this;
  188. }
  189. /*if (_currentItem != null && _currentItem.sourceType == MediaPlaylist.MediaItem.SourceType.Texture2D && _currentItem.texture != null)
  190. {
  191. return this;
  192. }*/
  193. return CurrentPlayer.TextureProducer;
  194. }
  195. return null;
  196. }
  197. }
  198. [SerializeField, Range(0.0f, 1.0f)] float _playlistAudioVolume = 1.0f;
  199. [SerializeField] bool _playlistAudioMuted = false;
  200. public override float AudioVolume
  201. {
  202. get { return _playlistAudioVolume; }
  203. set { _playlistAudioVolume = Mathf.Clamp01(value); if (!IsTransitioning() && CurrentPlayer != null) CurrentPlayer.AudioVolume = _playlistAudioVolume; }
  204. }
  205. public override bool AudioMuted
  206. {
  207. get { return _playlistAudioMuted; }
  208. set { _playlistAudioMuted = value; if (!IsTransitioning() && CurrentPlayer != null) CurrentPlayer.AudioMuted = _playlistAudioMuted; }
  209. }
  210. public override void Play()
  211. {
  212. _isPaused = false;
  213. if (Control != null)
  214. {
  215. Control.Play();
  216. }
  217. if (IsTransitioning())
  218. {
  219. if (!_pausePreviousOnTransition && NextPlayer.Control != null)
  220. {
  221. NextPlayer.Control.Play();
  222. }
  223. }
  224. }
  225. public override void Pause()
  226. {
  227. _isPaused = true;
  228. if (Control != null)
  229. {
  230. Control.Pause();
  231. }
  232. if (IsTransitioning())
  233. {
  234. if (NextPlayer.Control != null)
  235. {
  236. NextPlayer.Control.Pause();
  237. }
  238. }
  239. }
  240. public bool IsPaused()
  241. {
  242. return _isPaused;
  243. }
  244. private void SwapPlayers()
  245. {
  246. // Pause the previously playing video
  247. // This is useful for systems that will struggle to play 2 videos at once
  248. if (_pausePreviousOnTransition)
  249. {
  250. CurrentPlayer.Pause();
  251. }
  252. // Tell listeners that the playlist item has changed
  253. Events.Invoke(this, MediaPlayerEvent.EventType.PlaylistItemChanged, ErrorCode.None);
  254. // Start the transition
  255. if (_currentTransition != Transition.None)
  256. {
  257. // Create a new transition texture if required
  258. Texture currentTexture = GetCurrentTexture();
  259. Texture nextTexture = GetNextTexture();
  260. if (currentTexture != null && nextTexture != null)
  261. {
  262. int maxWidth = Mathf.Max(nextTexture.width, currentTexture.width);
  263. int maxHeight = Mathf.Max(nextTexture.height, currentTexture.height);
  264. if (_rt != null)
  265. {
  266. if (_rt.width != maxWidth || _rt.height != maxHeight)
  267. {
  268. RenderTexture.ReleaseTemporary(_rt);
  269. _rt = null;
  270. }
  271. }
  272. if (_rt == null)
  273. {
  274. _rt = RenderTexture.GetTemporary(maxWidth, maxHeight, 0, RenderTextureFormat.Default, RenderTextureReadWrite.Default, 1);
  275. }
  276. Graphics.Blit(currentTexture, _rt);
  277. _material.SetTexture(PropFromTex.Id, currentTexture);
  278. _easeFunc = Easing.GetFunction(_currentTransitionEasing);
  279. _transitionTimer = 0f;
  280. }
  281. else
  282. {
  283. // Immediately complete the transition
  284. _transitionTimer = _currentTransitionDuration;
  285. // Immediately update the audio volume
  286. NextPlayer.AudioVolume = this.AudioVolume;
  287. CurrentPlayer.AudioVolume = 0f;
  288. if (_autoCloseVideo)
  289. {
  290. CurrentPlayer.MediaPath.Path = string.Empty;
  291. CurrentPlayer.CloseMedia();
  292. }
  293. }
  294. }
  295. // Swap the videos
  296. if (NextPlayer == _playerA)
  297. {
  298. _nextPlayer = _playerB;
  299. }
  300. else
  301. {
  302. _nextPlayer = _playerA;
  303. }
  304. // Swap the items
  305. _currentItem = _nextItem;
  306. _nextItem = null;
  307. }
  308. private Texture GetCurrentTexture()
  309. {
  310. /*if (_currentItem != null && _currentItem.sourceType == MediaPlaylist.MediaItem.SourceType.Texture2D && _currentItem.texture != null)
  311. {
  312. return _currentItem.texture;
  313. }
  314. else*/ if (CurrentPlayer != null && CurrentPlayer.TextureProducer != null)
  315. {
  316. return CurrentPlayer.TextureProducer.GetTexture();
  317. }
  318. return null;
  319. }
  320. private Texture GetNextTexture()
  321. {
  322. /*if (_nextItem != null && _nextItem.sourceType == MediaPlaylist.MediaItem.SourceType.Texture2D && _nextItem.texture != null)
  323. {
  324. return _nextItem.texture;
  325. }
  326. else*/ if (_nextPlayer != null && _nextPlayer.TextureProducer != null)
  327. {
  328. return _nextPlayer.TextureProducer.GetTexture();
  329. }
  330. return null;
  331. }
  332. private void Awake()
  333. {
  334. #if UNITY_IOS && !UNITY_EDITOR_OSX
  335. Application.targetFrameRate = 60;
  336. #endif
  337. _nextPlayer = _playerA;
  338. if (_transitionShader == null)
  339. {
  340. _transitionShader = Shader.Find("AVProVideo/Internal/Transition");
  341. if (_transitionShader == null)
  342. {
  343. Debug.LogError("[AVProVideo] Missing transition shader");
  344. }
  345. }
  346. _material = new Material(_transitionShader);
  347. _easeFunc = Easing.GetFunction(_defaultTransitionEasing);
  348. }
  349. protected override void OnDestroy()
  350. {
  351. if (_rt != null)
  352. {
  353. RenderTexture.ReleaseTemporary(_rt);
  354. _rt = null;
  355. }
  356. if (_material != null)
  357. {
  358. if (Application.isPlaying)
  359. {
  360. Material.Destroy(_material);
  361. }
  362. else
  363. {
  364. Material.DestroyImmediate(_material);
  365. }
  366. _material = null;
  367. }
  368. base.OnDestroy();
  369. }
  370. private void Start()
  371. {
  372. if (Application.isPlaying)
  373. {
  374. if (CurrentPlayer)
  375. {
  376. CurrentPlayer.Events.AddListener(OnVideoEvent);
  377. if (NextPlayer)
  378. {
  379. NextPlayer.Events.AddListener(OnVideoEvent);
  380. }
  381. }
  382. JumpToItem(0);
  383. }
  384. }
  385. public void OnVideoEvent(MediaPlayer mp, MediaPlayerEvent.EventType et, ErrorCode errorCode)
  386. {
  387. if (mp == CurrentPlayer)
  388. {
  389. Events.Invoke(mp, et, errorCode);
  390. }
  391. switch (et)
  392. {
  393. case MediaPlayerEvent.EventType.FirstFrameReady:
  394. if (mp == NextPlayer)
  395. {
  396. SwapPlayers();
  397. Events.Invoke(mp, et, errorCode);
  398. }
  399. break;
  400. case MediaPlayerEvent.EventType.FinishedPlaying:
  401. if (_playlistAutoProgress && mp == CurrentPlayer && _currentItem.progressMode == ProgressMode.OnFinish)
  402. {
  403. NextItem();
  404. }
  405. break;
  406. }
  407. }
  408. public bool PrevItem()
  409. {
  410. return JumpToItem(_playlistIndex - 1);
  411. }
  412. public bool NextItem()
  413. {
  414. bool result = JumpToItem(_playlistIndex + 1);
  415. if (!result)
  416. {
  417. Events.Invoke(this, MediaPlayerEvent.EventType.PlaylistFinished, ErrorCode.None);
  418. }
  419. return result;
  420. }
  421. public bool CanJumpToItem(int index)
  422. {
  423. if (_playlistLoopMode == PlaylistLoopMode.Loop)
  424. {
  425. if (_playlist.Items.Count > 0)
  426. {
  427. index %= _playlist.Items.Count;
  428. if (index < 0)
  429. {
  430. index += _playlist.Items.Count;
  431. }
  432. }
  433. }
  434. return _playlist.HasItemAt(index);
  435. }
  436. public bool JumpToItem(int index)
  437. {
  438. if (_playlistLoopMode == PlaylistLoopMode.Loop)
  439. {
  440. if (_playlist.Items.Count > 0)
  441. {
  442. index %= _playlist.Items.Count;
  443. if (index < 0)
  444. {
  445. index += _playlist.Items.Count;
  446. }
  447. }
  448. }
  449. if (_playlist.HasItemAt(index))
  450. {
  451. _playlistIndex = index;
  452. _nextItem = _playlist.Items[_playlistIndex];
  453. OpenVideoFile(_nextItem);
  454. return true;
  455. }
  456. return false;
  457. }
  458. public void OpenVideoFile(MediaPlaylist.MediaItem mediaItem)
  459. {
  460. bool isMediaAlreadyLoaded = false;
  461. if (NextPlayer.MediaPath == mediaItem.mediaPath)
  462. {
  463. isMediaAlreadyLoaded = true;
  464. }
  465. if (!mediaItem.isOverrideTransition)
  466. {
  467. SetTransition(_defaultTransition, _defaultTransitionDuration, _defaultTransitionEasing);
  468. }
  469. else
  470. {
  471. SetTransition(mediaItem.overrideTransition, mediaItem.overrideTransitionDuration, mediaItem.overrideTransitionEasing);
  472. }
  473. this.Loop = NextPlayer.Loop = mediaItem.loop;
  474. NextPlayer.MediaPath = new MediaPath(mediaItem.mediaPath);
  475. this.MediaPath = new MediaPath(mediaItem.mediaPath);
  476. NextPlayer.AudioMuted = _playlistAudioMuted;
  477. NextPlayer.AudioVolume = _playlistAudioVolume;
  478. if (_transitionTimer < _currentTransitionDuration && _currentTransition != Transition.None)
  479. {
  480. NextPlayer.AudioVolume = 0f;
  481. }
  482. if (isMediaAlreadyLoaded)
  483. {
  484. NextPlayer.Rewind(false);
  485. if (_nextItem.startMode == StartMode.Immediate)
  486. {
  487. NextPlayer.Play();
  488. }
  489. // TODO: We probably want to wait until the new frame arrives before swapping after a Rewind()
  490. SwapPlayers();
  491. }
  492. else
  493. {
  494. if (string.IsNullOrEmpty(NextPlayer.MediaPath.Path))
  495. {
  496. NextPlayer.CloseMedia();
  497. }
  498. else
  499. {
  500. NextPlayer.OpenMedia(NextPlayer.MediaPath.PathType, NextPlayer.MediaPath.Path, _nextItem.startMode == StartMode.Immediate);
  501. }
  502. }
  503. }
  504. private bool IsTransitioning()
  505. {
  506. if (_rt != null && _transitionTimer < _currentTransitionDuration && _currentTransition != Transition.None)
  507. {
  508. return true;
  509. }
  510. return false;
  511. }
  512. private void SetTransition(Transition transition, float duration, Easing.Preset easing)
  513. {
  514. if (transition == Transition.Random)
  515. {
  516. transition = (Transition)Random.Range(0, (int)Transition.Random);
  517. }
  518. if (transition != _currentTransition)
  519. {
  520. // Disable the previous transition
  521. if (!string.IsNullOrEmpty(_currentTransitionName))
  522. {
  523. _material.DisableKeyword(_currentTransitionName);
  524. }
  525. // Enable the next transition
  526. _currentTransition = transition;
  527. _currentTransitionName = GetTransitionName(transition);
  528. _material.EnableKeyword(_currentTransitionName);
  529. }
  530. _currentTransitionDuration = duration;
  531. _currentTransitionEasing = easing;
  532. }
  533. protected override void Update()
  534. {
  535. if (!Application.isPlaying) return;
  536. if (!IsPaused())
  537. {
  538. if (IsTransitioning())
  539. {
  540. _transitionTimer += Time.deltaTime;
  541. float t = _easeFunc(Mathf.Clamp01(_transitionTimer / _currentTransitionDuration));
  542. // Fade the audio volume
  543. NextPlayer.AudioVolume = (1f - t) * this.AudioVolume;
  544. CurrentPlayer.AudioVolume = t * this.AudioVolume;
  545. // TODO: support going from mono to stereo
  546. // TODO: support videos of different aspect ratios by rendering with scaling to fit
  547. // This can be done by blitting twice, once for each eye
  548. // If the stereo mode is different for playera/b then both should be set to stereo during the transition
  549. // if (CurrentPlayer.m_StereoPacking == StereoPacking.TopBottom)....
  550. _material.SetFloat(PropFade.Id, t);
  551. _rt.DiscardContents();
  552. Graphics.Blit(GetCurrentTexture(), _rt, _material);
  553. // After the transition is now complete, close/pause the previous video if required
  554. bool isTransitioning = IsTransitioning();
  555. if (!isTransitioning)
  556. {
  557. if (_autoCloseVideo)
  558. {
  559. if (NextPlayer != null)
  560. {
  561. NextPlayer.MediaPath.Path = string.Empty;
  562. NextPlayer.CloseMedia();
  563. }
  564. }
  565. else if (!_pausePreviousOnTransition)
  566. {
  567. if (NextPlayer != null && NextPlayer.Control.IsPlaying())
  568. {
  569. NextPlayer.Pause();
  570. }
  571. }
  572. }
  573. }
  574. else
  575. {
  576. if (_playlistAutoProgress && _nextItem == null && _currentItem != null && _currentItem.progressMode == ProgressMode.BeforeFinish && Control != null && Control.HasMetaData() && Control.GetCurrentTime() >= (Info.GetDuration() - (_currentItem.progressTimeSeconds)))
  577. {
  578. this.NextItem();
  579. }
  580. else if (_playlistAutoProgress && _currentItem == null)
  581. {
  582. JumpToItem(_playlistIndex);
  583. }
  584. }
  585. }
  586. base.Update();
  587. }
  588. #region Implementing ITextureProducer
  589. public Texture GetTexture(int index = 0)
  590. {
  591. // TODO: support iOS YCbCr by supporting multiple textures
  592. /*if (!IsTransitioning())
  593. {
  594. if (_currentItem != null && _currentItem.sourceType == MediaPlaylist.MediaItem.SourceType.Texture2D && _currentItem.texture != null)
  595. {
  596. return _currentItem.texture;
  597. }
  598. }*/
  599. return _rt;
  600. }
  601. public int GetTextureCount()
  602. {
  603. return CurrentPlayer.TextureProducer.GetTextureCount();
  604. }
  605. public int GetTextureFrameCount()
  606. {
  607. return CurrentPlayer.TextureProducer.GetTextureFrameCount();
  608. }
  609. public bool SupportsTextureFrameCount()
  610. {
  611. return CurrentPlayer.TextureProducer.SupportsTextureFrameCount();
  612. }
  613. public long GetTextureTimeStamp()
  614. {
  615. return CurrentPlayer.TextureProducer.GetTextureTimeStamp();
  616. }
  617. public float GetTexturePixelAspectRatio()
  618. {
  619. return CurrentPlayer.TextureProducer.GetTexturePixelAspectRatio();
  620. }
  621. public bool RequiresVerticalFlip()
  622. {
  623. return CurrentPlayer.TextureProducer.RequiresVerticalFlip();
  624. }
  625. public Matrix4x4 GetYpCbCrTransform()
  626. {
  627. return CurrentPlayer.TextureProducer.GetYpCbCrTransform();
  628. }
  629. public StereoPacking GetTextureStereoPacking()
  630. {
  631. return CurrentPlayer.TextureProducer.GetTextureStereoPacking();
  632. }
  633. public TransparencyMode GetTextureTransparency()
  634. {
  635. return CurrentPlayer.TextureProducer.GetTextureTransparency();
  636. }
  637. public AlphaPacking GetTextureAlphaPacking()
  638. {
  639. return CurrentPlayer.TextureProducer.GetTextureAlphaPacking();
  640. }
  641. public float[] GetAffineTransform()
  642. {
  643. return CurrentPlayer.TextureProducer.GetAffineTransform();
  644. }
  645. public Matrix4x4 GetTextureMatrix()
  646. {
  647. return CurrentPlayer.TextureProducer.GetTextureMatrix();
  648. }
  649. #endregion Implementing ITextureProducer
  650. private static string GetTransitionName(Transition transition)
  651. {
  652. switch (transition)
  653. {
  654. case Transition.None: return "LERP_NONE";
  655. case Transition.Fade: return "LERP_FADE";
  656. case Transition.Black: return "LERP_BLACK";
  657. case Transition.White: return "LERP_WHITE";
  658. case Transition.Transparent:return "LERP_TRANSP";
  659. case Transition.Horiz: return "LERP_HORIZ";
  660. case Transition.Vert: return "LERP_VERT";
  661. case Transition.Diag: return "LERP_DIAG";
  662. case Transition.MirrorH: return "LERP_HORIZ_MIRROR";
  663. case Transition.MirrorV: return "LERP_VERT_MIRROR";
  664. case Transition.MirrorD: return "LERP_DIAG_MIRROR";
  665. case Transition.ScrollV: return "LERP_SCROLL_VERT";
  666. case Transition.ScrollH: return "LERP_SCROLL_HORIZ";
  667. case Transition.Circle: return "LERP_CIRCLE";
  668. case Transition.Diamond: return "LERP_DIAMOND";
  669. case Transition.Blinds: return "LERP_BLINDS";
  670. case Transition.Arrows: return "LERP_ARROW";
  671. case Transition.SlideH: return "LERP_SLIDE_HORIZ";
  672. case Transition.SlideV: return "LERP_SLIDE_VERT";
  673. case Transition.Zoom: return "LERP_ZOOM_FADE";
  674. case Transition.RectV: return "LERP_RECTS_VERT";
  675. }
  676. return string.Empty;
  677. }
  678. #region Easing
  679. /// <summary>
  680. /// Easing functions
  681. /// </summary>
  682. [System.Serializable]
  683. public class Easing
  684. {
  685. public Preset preset = Preset.Linear;
  686. public enum Preset
  687. {
  688. Step,
  689. Linear,
  690. InQuad,
  691. OutQuad,
  692. InOutQuad,
  693. InCubic,
  694. OutCubic,
  695. InOutCubic,
  696. InQuint,
  697. OutQuint,
  698. InOutQuint,
  699. InQuart,
  700. OutQuart,
  701. InOutQuart,
  702. InExpo,
  703. OutExpo,
  704. InOutExpo,
  705. Random,
  706. RandomNotStep,
  707. }
  708. public static System.Func<float, float> GetFunction(Preset preset)
  709. {
  710. System.Func<float, float> result = null;
  711. switch (preset)
  712. {
  713. case Preset.Step:
  714. result = Step;
  715. break;
  716. case Preset.Linear:
  717. result = Linear;
  718. break;
  719. case Preset.InQuad:
  720. result = InQuad;
  721. break;
  722. case Preset.OutQuad:
  723. result = OutQuad;
  724. break;
  725. case Preset.InOutQuad:
  726. result = InOutQuad;
  727. break;
  728. case Preset.InCubic:
  729. result = InCubic;
  730. break;
  731. case Preset.OutCubic:
  732. result = OutCubic;
  733. break;
  734. case Preset.InOutCubic:
  735. result = InOutCubic;
  736. break;
  737. case Preset.InQuint:
  738. result = InQuint;
  739. break;
  740. case Preset.OutQuint:
  741. result = OutQuint;
  742. break;
  743. case Preset.InOutQuint:
  744. result = InOutQuint;
  745. break;
  746. case Preset.InQuart:
  747. result = InQuart;
  748. break;
  749. case Preset.OutQuart:
  750. result = OutQuart;
  751. break;
  752. case Preset.InOutQuart:
  753. result = InOutQuart;
  754. break;
  755. case Preset.InExpo:
  756. result = InExpo;
  757. break;
  758. case Preset.OutExpo:
  759. result = OutExpo;
  760. break;
  761. case Preset.InOutExpo:
  762. result = InOutExpo;
  763. break;
  764. case Preset.Random:
  765. result = GetFunction((Preset)Random.Range(0, (int)Preset.Random));
  766. break;
  767. case Preset.RandomNotStep:
  768. result = GetFunction((Preset)Random.Range((int)Preset.Step+1, (int)Preset.Random));
  769. break;
  770. }
  771. return result;
  772. }
  773. public static float PowerEaseIn(float t, float power)
  774. {
  775. return Mathf.Pow(t, power);
  776. }
  777. public static float PowerEaseOut(float t, float power)
  778. {
  779. return 1f - Mathf.Abs(Mathf.Pow(t - 1f, power));
  780. }
  781. public static float PowerEaseInOut(float t, float power)
  782. {
  783. float result;
  784. if (t < 0.5f)
  785. {
  786. result = PowerEaseIn(t * 2f, power) / 2f;
  787. }
  788. else
  789. {
  790. result = PowerEaseOut(t * 2f - 1f, power) / 2f + 0.5f;
  791. }
  792. return result;
  793. }
  794. public static float Step(float t)
  795. {
  796. float result = 0f;
  797. if (t >= 0.5f)
  798. {
  799. result = 1f;
  800. }
  801. return result;
  802. }
  803. public static float Linear(float t)
  804. {
  805. return t;
  806. }
  807. public static float InQuad(float t)
  808. {
  809. return PowerEaseIn(t, 2f);
  810. }
  811. public static float OutQuad(float t)
  812. {
  813. return PowerEaseOut(t, 2f);
  814. //return t * (2f - t);
  815. }
  816. public static float InOutQuad(float t)
  817. {
  818. return PowerEaseInOut(t, 2f);
  819. //return t < 0.5 ? (2f * t * t) : (-1f + (4f - 2f * t) * t);
  820. }
  821. public static float InCubic(float t)
  822. {
  823. return PowerEaseIn(t, 3f);
  824. //return t * t * t;
  825. }
  826. public static float OutCubic(float t)
  827. {
  828. return PowerEaseOut(t, 3f);
  829. //return (--t) * t * t + 1f;
  830. }
  831. public static float InOutCubic(float t)
  832. {
  833. return PowerEaseInOut(t, 3f);
  834. //return t < .5f ? (4f * t * t * t) : ((t - 1f) * (2f * t - 2f) * (2f * t - 2f) + 1f);
  835. }
  836. public static float InQuart(float t)
  837. {
  838. return PowerEaseIn(t, 4f);
  839. //return t * t * t * t;
  840. }
  841. public static float OutQuart(float t)
  842. {
  843. return PowerEaseOut(t, 4f);
  844. //return 1f - (--t) * t * t * t;
  845. }
  846. public static float InOutQuart(float t)
  847. {
  848. return PowerEaseInOut(t, 4f);
  849. //return t < 0.5f ? (8f * t * t * t * t) : (1f - 8f * (--t) * t * t * t);
  850. }
  851. public static float InQuint(float t)
  852. {
  853. return PowerEaseIn(t, 5f);
  854. //return t * t * t * t * t;
  855. }
  856. public static float OutQuint(float t)
  857. {
  858. return PowerEaseOut(t, 5f);
  859. //return 1f + (--t) * t * t * t * t;
  860. }
  861. public static float InOutQuint(float t)
  862. {
  863. return PowerEaseInOut(t, 5f);
  864. //return t < 0.5f ? (16f * t * t * t * t * t) : (1f + 16f * (--t) * t * t * t * t);
  865. }
  866. public static float InExpo(float t)
  867. {
  868. float result = 0f;
  869. if (t != 0f)
  870. {
  871. result = Mathf.Pow(2f, 10f * (t - 1f));
  872. }
  873. return result;
  874. }
  875. public static float OutExpo(float t)
  876. {
  877. float result = 1f;
  878. if (t != 1f)
  879. {
  880. result = -Mathf.Pow(2f, -10f * t) + 1f;
  881. }
  882. return result;
  883. }
  884. public static float InOutExpo(float t)
  885. {
  886. float result = 0f;
  887. if (t > 0f)
  888. {
  889. result = 1f;
  890. if (t < 1f)
  891. {
  892. t *= 2f;
  893. if (t < 1f)
  894. {
  895. result = 0.5f * Mathf.Pow(2f, 10f * (t - 1f));
  896. }
  897. else
  898. {
  899. t--;
  900. result = 0.5f * (-Mathf.Pow(2f, -10f * t) + 2f);
  901. }
  902. }
  903. }
  904. return result;
  905. }
  906. }
  907. #endregion Easing
  908. }
  909. }