UniversalMediaPlayer.cs 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. using UnityEngine.Events;
  6. using System.IO;
  7. using UMP.Services;
  8. using UMP.Services.Youtube;
  9. using UnityEngine.Networking;
  10. using UnityEngine.UI;
  11. //using UnityEditor.Experimental.GraphView;
  12. //using UnityEngine.Rendering.VirtualTexturing;
  13. #if UNITY_EDITOR
  14. using UnityEditor;
  15. #endif
  16. namespace UMP
  17. {
  18. public class UniversalMediaPlayer : MonoBehaviour, IMediaListener, IPathPreparedListener, IPlayerPreparedListener, IPlayerTimeChangedListener, IPlayerPositionChangedListener, IPlayerSnapshotTakenListener
  19. {
  20. private const float DEFAULT_POSITION_CHANGED_OFFSET = 0.05f;
  21. #region Editor Visible Properties
  22. [SerializeField]
  23. private GameObject[] _renderingObjects;
  24. [SerializeField]
  25. string _path = string.Empty;
  26. [SerializeField]
  27. private bool _autoPlay = false;
  28. [SerializeField]
  29. private bool _loop = false;
  30. [SerializeField]
  31. private bool _loopSmooth = false;
  32. [SerializeField]
  33. private bool _mute = false;
  34. #pragma warning disable 0414
  35. [SerializeField]
  36. private bool _useAdvanced = false;
  37. [SerializeField]
  38. private bool _useFixedSize = false;
  39. [SerializeField]
  40. private int _fixedVideoWidth = -1;
  41. [SerializeField]
  42. private int _fixedVideoHeight = -1;
  43. [SerializeField]
  44. private int _chosenPlatform = 0;
  45. [SerializeField]
  46. private int _volume = 50;
  47. [SerializeField]
  48. private float _playRate = 1;
  49. [SerializeField]
  50. private float _position = 0;
  51. [SerializeField]
  52. private LogLevels _logDetail = LogLevels.Disable;
  53. [SerializeField]
  54. private string _lastEventMsg = string.Empty;
  55. #pragma warning restore 0414
  56. #region Desktop Options
  57. [SerializeField]
  58. private AudioOutput[] _desktopAudioOutputs;
  59. [SerializeField]
  60. private PlayerOptions.States _desktopHardwareDecoding = PlayerOptions.States.Default;
  61. [SerializeField]
  62. private bool _desktopFlipVertically = true;
  63. [SerializeField]
  64. private bool _desktopVideoBufferSize = false;
  65. [SerializeField]
  66. private bool _desktopOutputToFile = false;
  67. [SerializeField]
  68. private bool _desktopDisplayOutput = false;
  69. [SerializeField]
  70. private string _desktopOutputFilePath = string.Empty;
  71. [SerializeField]
  72. private bool _desktopRtspOverTcp = false;
  73. [SerializeField]
  74. private int _desktopFileCaching = 300;
  75. [SerializeField]
  76. private int _desktopLiveCaching = 300;
  77. [SerializeField]
  78. private int _desktopDiskCaching = 300;
  79. [SerializeField]
  80. private int _desktopNetworkCaching = 300;
  81. #endregion
  82. #region Android Options
  83. [SerializeField]
  84. private PlayerOptionsAndroid.PlayerTypes _androidPlayerType = PlayerOptionsAndroid.PlayerTypes.LibVLC;
  85. [SerializeField]
  86. private PlayerOptionsAndroid.DecodingStates _androidHardwareAcceleration = PlayerOptionsAndroid.DecodingStates.Automatic;
  87. [SerializeField]
  88. private PlayerOptions.States _androidOpenGLDecoding = PlayerOptions.States.Disable;
  89. [SerializeField]
  90. private PlayerOptionsAndroid.ChromaTypes _androidVideoChroma = PlayerOptionsAndroid.ChromaTypes.RGB16Bit;
  91. [SerializeField]
  92. private bool _androidPlayInBackground = false;
  93. [SerializeField]
  94. private bool _androidRtspOverTcp = false;
  95. [SerializeField]
  96. private int _androidNetworkCaching = 300;
  97. #endregion
  98. #region IPhone Options
  99. [SerializeField]
  100. private PlayerOptionsIPhone.PlayerTypes _iphonePlayerType = PlayerOptionsIPhone.PlayerTypes.FFmpeg;
  101. [SerializeField]
  102. private bool _iphoneFlipVertically = true;
  103. [SerializeField]
  104. private bool _iphoneVideoToolbox = true;
  105. [SerializeField]
  106. private int _iphoneVideoToolboxMaxFrameWidth = 4096;
  107. [SerializeField]
  108. private bool _iphoneVideoToolboxAsync = false;
  109. [SerializeField]
  110. private bool _iphoneVideoToolboxWaitAsync = true;
  111. [SerializeField]
  112. private bool _iphonePlayInBackground = false;
  113. [SerializeField]
  114. private bool _iphoneRtspOverTcp = false;
  115. [SerializeField]
  116. private bool _iphonePacketBuffering = true;
  117. [SerializeField]
  118. private int _iphoneMaxBufferSize = 15 * 1024 * 1024;
  119. [SerializeField]
  120. private int _iphoneMinFrames = 50000;
  121. [SerializeField]
  122. private bool _iphoneInfbuf = false;
  123. [SerializeField]
  124. private int _iphoneFramedrop = 0;
  125. [SerializeField]
  126. private int _iphoneMaxFps = 31;
  127. #endregion
  128. [Serializable]
  129. private class EventTextType : UnityEvent<string> { }
  130. [Serializable]
  131. private class EventFloatType : UnityEvent<float> { }
  132. [Serializable]
  133. private class EventLongType : UnityEvent<long> { }
  134. [Serializable]
  135. private class EventSizeType : UnityEvent<int, int> { }
  136. [Serializable]
  137. private class EventTextureType : UnityEvent<Texture2D> { }
  138. [SerializeField]
  139. private EventTextType _pathPreparedEvent = new EventTextType();
  140. [SerializeField]
  141. private UnityEvent _openingEvent = new UnityEvent();
  142. [SerializeField]
  143. private EventFloatType _bufferingEvent = new EventFloatType();
  144. [SerializeField]
  145. private EventTextureType _imageReadyEvent = new EventTextureType();
  146. [SerializeField]
  147. private EventSizeType _preparedEvent = new EventSizeType();
  148. [SerializeField]
  149. private UnityEvent _playingEvent = new UnityEvent();
  150. [SerializeField]
  151. private UnityEvent _pausedEvent = new UnityEvent();
  152. [SerializeField]
  153. private UnityEvent _stoppedEvent = new UnityEvent();
  154. [SerializeField]
  155. private UnityEvent _endReachedEvent = new UnityEvent();
  156. [SerializeField]
  157. private UnityEvent _encounteredErrorEvent = new UnityEvent();
  158. [SerializeField]
  159. private EventLongType _timeChangedEvent = new EventLongType();
  160. [SerializeField]
  161. private EventFloatType _positionChangedEvent = new EventFloatType();
  162. [SerializeField]
  163. private EventTextType _snapshotTakenEvent = new EventTextType();
  164. #endregion
  165. #region Properties
  166. /// <summary>
  167. /// Get/Set simple array that consist with Unity 'GameObject' that have 'Mesh Renderer' (with some material)
  168. /// or 'Raw Image' component
  169. /// </summary>
  170. public GameObject[] RenderingObjects
  171. {
  172. get
  173. {
  174. if (_mediaPlayer != null)
  175. return _mediaPlayer.VideoOutputObjects;
  176. return null;
  177. }
  178. set
  179. {
  180. if (_mediaPlayer != null)
  181. _mediaPlayer.VideoOutputObjects = value;
  182. _renderingObjects = value;
  183. }
  184. }
  185. /// <summary>
  186. /// Get simple array that consist with Unity 'AudioSource' components
  187. /// (will be used for audio data output instead default one)
  188. /// * Warning: in current stage correctly working only with audio that has 2 channels
  189. /// </summary>
  190. public AudioOutput[] AudioOutputs
  191. {
  192. get
  193. {
  194. return _desktopAudioOutputs;
  195. }
  196. }
  197. /// <summary>
  198. /// Get media player object for current running platform
  199. /// (supported: Standalone, WebGL, Android and iOS platforms)
  200. /// for get more additional possibilities that exists only for this platform.
  201. /// Example of using:
  202. /// if (_mediaPlayer.PlatformPlayer is MediaPlayerStandalone)
  203. /// return (_mediaPlayer.PlatformPlayer as MediaPlayerStandalone).GetLastError();
  204. /// </summary>
  205. public object PlatformPlayer
  206. {
  207. get
  208. {
  209. return _mediaPlayer != null ? _mediaPlayer.PlatformPlayer : null;
  210. }
  211. }
  212. /// <summary>
  213. /// Get/Set local path or url link to your video/audio file/stream
  214. /// Example of using:
  215. /// Local storage space - 'file:///C:\MyFolder\Videos\video1.mp4' or 'C:\MyFolder\Videos\video1.mp4' or
  216. /// 'file:///DCIM/100ANDRO/MyVideo.mp4' (example for Android platform);
  217. /// Remote space (streams) - 'rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov';
  218. /// 'StreamingAssets' folder - 'file:///myVideoFile.mp4';
  219. /// </summary>
  220. public string Path
  221. {
  222. set { _path = value; }
  223. get { return _path; }
  224. }
  225. /// <summary>
  226. /// Get/Set start playback automatically after video is buffered
  227. /// </summary>
  228. public bool AutoPlay
  229. {
  230. set { _autoPlay = value; }
  231. get { return _autoPlay; }
  232. }
  233. /// <summary>
  234. /// Get/Set jumps to the start and plays again if playback reaches the end position
  235. /// </summary>
  236. public bool Loop
  237. {
  238. set { _loop = value; }
  239. get { return _loop; }
  240. }
  241. /// <summary>
  242. /// Get/Set mute status for current video playback
  243. /// </summary>
  244. public bool Mute
  245. {
  246. set
  247. {
  248. _mediaPlayer.Mute = value;
  249. _mute = value;
  250. }
  251. get { return _mediaPlayer.Mute; }
  252. }
  253. /// <summary>
  254. /// Get/Set current software audio volume
  255. /// (by default you can change this value from '0' to '100')
  256. /// </summary>
  257. public float Volume
  258. {
  259. set
  260. {
  261. _mediaPlayer.Volume = (int)value;
  262. _volume = (int)value;
  263. }
  264. get { return _mediaPlayer.Volume; }
  265. }
  266. /// <summary>
  267. /// Get/Set video position.
  268. /// This has no effect if playback is not enabled.
  269. /// This might not work depending on the underlying input format and protocol
  270. /// </summary>
  271. public float Position
  272. {
  273. set { _mediaPlayer.Position = value; }
  274. get { return _mediaPlayer.Position; }
  275. }
  276. /// <summary>
  277. /// Get/Set the current video time (in milliseconds).
  278. /// This has no effect if no media is being played.
  279. /// Not all formats and protocols support this
  280. /// </summary>
  281. public long Time
  282. {
  283. set
  284. {
  285. if (_mediaPlayer != null)
  286. _mediaPlayer.Time = value;
  287. }
  288. get
  289. {
  290. if (_mediaPlayer != null)
  291. return _mediaPlayer.Time;
  292. return -1;
  293. }
  294. }
  295. /// <summary>
  296. /// Get/Set the requested video play rate
  297. /// </summary>
  298. public float PlayRate
  299. {
  300. set
  301. {
  302. _mediaPlayer.PlaybackRate = value;
  303. _playRate = value;
  304. }
  305. get { return _mediaPlayer.PlaybackRate; }
  306. }
  307. /// <summary>
  308. /// Is the player able to play
  309. /// </summary>
  310. public bool AbleToPlay
  311. {
  312. get
  313. {
  314. if (_mediaPlayer != null)
  315. return _mediaPlayer.AbleToPlay;
  316. return false;
  317. }
  318. }
  319. /// <summary>
  320. /// Is media is currently playing
  321. /// </summary>
  322. public bool IsPlaying
  323. {
  324. get
  325. {
  326. if (_mediaPlayer != null)
  327. return _mediaPlayer.IsPlaying;
  328. return false;
  329. }
  330. }
  331. /// <summary>
  332. /// Is media is ready to play (first frame available)
  333. /// </summary>
  334. public bool IsReady
  335. {
  336. get
  337. {
  338. if (_mediaPlayer != null)
  339. return _mediaPlayer.IsReady;
  340. return false;
  341. }
  342. }
  343. /// <summary>
  344. /// Is current media is parsing from video hosting service (in our case Youtube)
  345. /// </summary>
  346. public bool IsParsing
  347. {
  348. get
  349. {
  350. return _isParsing;
  351. }
  352. }
  353. /// <summary>
  354. /// Get frames per second (fps) for current video playback.
  355. /// * Warning: it's not a predefined value from video file/stream - calculated in video playback process
  356. /// </summary>
  357. public float FrameRate
  358. {
  359. get
  360. {
  361. if (_mediaPlayer != null)
  362. return _mediaPlayer.FrameRate;
  363. return 0;
  364. }
  365. }
  366. /// <summary>
  367. /// Get video frames counter
  368. /// </summary>
  369. public long FramesCounter
  370. {
  371. get
  372. {
  373. if (_mediaPlayer != null)
  374. return _mediaPlayer.FramesCounter;
  375. return 0;
  376. }
  377. }
  378. /// <summary>
  379. /// Get pixels of current video frame
  380. /// Example of using:
  381. /// texture.LoadRawTextureData(_player.FramePixels);
  382. /// texture.Apply();
  383. /// </summary>
  384. public byte[] FramePixels
  385. {
  386. get
  387. {
  388. if (_mediaPlayer != null)
  389. return _mediaPlayer.FramePixels;
  390. return null;
  391. }
  392. }
  393. /// <summary>
  394. /// Get the current video length (in milliseconds)
  395. /// </summary>
  396. public long Length
  397. {
  398. get
  399. {
  400. if (_mediaPlayer != null)
  401. return _mediaPlayer.Length;
  402. return 0;
  403. }
  404. }
  405. /// <summary>
  406. /// Get current video width in pixels
  407. /// </summary>
  408. public int VideoWidth
  409. {
  410. get
  411. {
  412. if (_mediaPlayer != null)
  413. return _mediaPlayer.VideoWidth;
  414. return 0;
  415. }
  416. }
  417. /// <summary>
  418. /// Get current video height in pixels
  419. /// </summary>
  420. public int VideoHeight
  421. {
  422. get
  423. {
  424. if (_mediaPlayer != null)
  425. return _mediaPlayer.VideoHeight;
  426. return 0;
  427. }
  428. }
  429. /// <summary>
  430. /// Get the pixel dimensions of current video
  431. /// </summary>
  432. public Vector2 VideoSize
  433. {
  434. get
  435. {
  436. if (_mediaPlayer != null)
  437. return _mediaPlayer.VideoSize;
  438. return new Vector2(0, 0);
  439. }
  440. }
  441. /// <summary>
  442. /// Get/Set the current audio track
  443. /// </summary>
  444. public MediaTrackInfo AudioTrack
  445. {
  446. set
  447. {
  448. if (_mediaPlayer != null)
  449. _mediaPlayer.AudioTrack = value;
  450. }
  451. get
  452. {
  453. if (_mediaPlayer != null)
  454. return _mediaPlayer.AudioTrack;
  455. return null;
  456. }
  457. }
  458. /// <summary>
  459. /// Get the available audio tracks
  460. /// </summary>
  461. public MediaTrackInfo[] AudioTracks
  462. {
  463. get
  464. {
  465. if (_mediaPlayer != null)
  466. return _mediaPlayer.AudioTracks;
  467. return null;
  468. }
  469. }
  470. /// <summary>
  471. /// Get/Set the current spu (subtitle) track (supported only on Standalone platform)
  472. /// </summary>
  473. public MediaTrackInfo SpuTrack
  474. {
  475. set
  476. {
  477. if (_mediaPlayer != null)
  478. _mediaPlayer.SpuTrack = value;
  479. }
  480. get
  481. {
  482. if (_mediaPlayer != null)
  483. return _mediaPlayer.SpuTrack;
  484. return null;
  485. }
  486. }
  487. /// <summary>
  488. /// Gets the available spu (subtitle) tracks (supported only on Standalone platform)
  489. /// </summary>
  490. public MediaTrackInfo[] SpuTracks
  491. {
  492. get
  493. {
  494. if (_mediaPlayer != null)
  495. return _mediaPlayer.SpuTracks;
  496. return null;
  497. }
  498. }
  499. /// <summary>
  500. /// Get event manager for current media player to add possibility to attach/detach special playback listeners
  501. /// </summary>
  502. public PlayerManagerEvents EventManager
  503. {
  504. get
  505. {
  506. if (_mediaPlayer != null)
  507. return _mediaPlayer.EventManager;
  508. return null;
  509. }
  510. }
  511. #endregion
  512. private MediaPlayer _mediaPlayer;
  513. private MediaPlayer _mediaPlayerLoop;
  514. private VideoServices _videoServices;
  515. private string _tmpPath = string.Empty;
  516. private bool _isParsing;
  517. private static bool _isExportCompleted;
  518. private static Dictionary<string, string> _cachedVideoPaths = new Dictionary<string, string>();
  519. private static IEnumerator _exportedHandlerEnum;
  520. private IEnumerator _videoPathPreparingEnum;
  521. #pragma warning disable 0414
  522. private bool _isFirstEditorStateChange = true;
  523. #pragma warning restore 0414
  524. private void Awake()
  525. {
  526. #if UNITY_EDITOR
  527. #if UNITY_4 || UNITY_5 || UNITY_2017_1
  528. EditorApplication.playmodeStateChanged += HandleOnPlayModeChanged;
  529. #else
  530. EditorApplication.playModeStateChanged += HandleOnPlayModeChanged;
  531. #endif
  532. #endif
  533. if (UMPSettings.Instance.UseAudioSource && (_desktopAudioOutputs == null || _desktopAudioOutputs.Length <= 0))
  534. {
  535. var audioOutput = gameObject.AddComponent<UMPAudioOutput>();
  536. _desktopAudioOutputs = new UMPAudioOutput[] { audioOutput };
  537. }
  538. PlayerOptions options = new PlayerOptions(null);
  539. switch (UMPSettings.RuntimePlatform)
  540. {
  541. case UMPSettings.Platforms.Win:
  542. case UMPSettings.Platforms.Mac:
  543. case UMPSettings.Platforms.Linux:
  544. var standaloneOptions = new PlayerOptionsStandalone(null)
  545. {
  546. FixedVideoSize = _useFixedSize ? new Vector2(_fixedVideoWidth, _fixedVideoHeight) : Vector2.zero,
  547. AudioOutputs = _desktopAudioOutputs,
  548. //DirectAudioDevice = "Digital Audio",
  549. HardwareDecoding = _desktopHardwareDecoding,
  550. FlipVertically = _desktopFlipVertically,
  551. VideoBufferSize = _desktopVideoBufferSize,
  552. UseTCP = _desktopRtspOverTcp,
  553. FileCaching = _desktopFileCaching,
  554. LiveCaching = _desktopLiveCaching,
  555. DiskCaching = _desktopDiskCaching,
  556. NetworkCaching = _desktopNetworkCaching
  557. };
  558. if (_desktopOutputToFile)
  559. standaloneOptions.RedirectToFile(_desktopDisplayOutput, _desktopOutputFilePath);
  560. standaloneOptions.SetLogDetail(_logDetail, UnityConsoleLogging);
  561. options = standaloneOptions;
  562. break;
  563. case UMPSettings.Platforms.Android:
  564. var androidOptions = new PlayerOptionsAndroid(null)
  565. {
  566. FixedVideoSize = _useFixedSize ? new Vector2(_fixedVideoWidth, _fixedVideoHeight) : Vector2.zero,
  567. PlayerType = _androidPlayerType,
  568. HardwareAcceleration = _androidHardwareAcceleration,
  569. OpenGLDecoding = _androidOpenGLDecoding,
  570. VideoChroma = _androidVideoChroma,
  571. PlayInBackground = _androidPlayInBackground,
  572. UseTCP = _androidRtspOverTcp,
  573. NetworkCaching = _androidNetworkCaching
  574. };
  575. options = androidOptions;
  576. if (_exportedHandlerEnum == null)
  577. {
  578. _exportedHandlerEnum = AndroidExpoterdHandler();
  579. StartCoroutine(_exportedHandlerEnum);
  580. }
  581. break;
  582. case UMPSettings.Platforms.iOS:
  583. var iphoneOptions = new PlayerOptionsIPhone(null)
  584. {
  585. FixedVideoSize = _useFixedSize ? new Vector2(_fixedVideoWidth, _fixedVideoHeight) : Vector2.zero,
  586. PlayerType = _iphonePlayerType,
  587. FlipVertically = _iphoneFlipVertically,
  588. VideoToolbox = _iphoneVideoToolbox,
  589. VideoToolboxFrameWidth = _iphoneVideoToolboxMaxFrameWidth,
  590. VideoToolboxAsync = _iphoneVideoToolboxAsync,
  591. VideoToolboxWaitAsync = _iphoneVideoToolboxWaitAsync,
  592. PlayInBackground = _iphonePlayInBackground,
  593. UseTCP = _iphoneRtspOverTcp,
  594. PacketBuffering = _iphonePacketBuffering,
  595. MaxBufferSize = _iphoneMaxBufferSize,
  596. MinFrames = _iphoneMinFrames,
  597. Infbuf = _iphoneInfbuf,
  598. Framedrop = _iphoneFramedrop,
  599. MaxFps = _iphoneMaxFps
  600. };
  601. options = iphoneOptions;
  602. break;
  603. }
  604. _mediaPlayer = new MediaPlayer(this, _renderingObjects, options);
  605. // Create scpecial parser to add possibiity of get video link from different video hosting servies (like youtube)
  606. _videoServices = new VideoServices(this);
  607. // Attach scecial listeners to MediaPlayer instance
  608. AddListeners();
  609. // Create additional media player for add smooth loop possibility
  610. if (_loopSmooth)
  611. {
  612. _mediaPlayerLoop = new MediaPlayer(this, _mediaPlayer);
  613. _mediaPlayerLoop.VideoOutputObjects = null;
  614. _mediaPlayerLoop.EventManager.RemoveAllEvents();
  615. }
  616. GetNVRData();
  617. }
  618. private IEnumerator AndroidExpoterdHandler()
  619. {
  620. var settings = UMPSettings.Instance;
  621. foreach (var exportedPath in settings.AndroidExportedPaths)
  622. {
  623. var tempFilePath = System.IO.Path.Combine(Application.temporaryCachePath, exportedPath);
  624. var saPath = "Assets" + System.IO.Path.AltDirectorySeparatorChar + "StreamingAssets" + System.IO.Path.AltDirectorySeparatorChar;
  625. var localFilePath = exportedPath.Replace(saPath, "");
  626. if (File.Exists(tempFilePath))
  627. {
  628. _cachedVideoPaths.Add(localFilePath, tempFilePath);
  629. continue;
  630. }
  631. var data = new byte[0];
  632. #if UNITY_2017_2_OR_NEWER
  633. var www = UnityWebRequest.Get(System.IO.Path.Combine(Application.streamingAssetsPath, localFilePath));
  634. yield return www.SendWebRequest();
  635. data = www.downloadHandler.data;
  636. #else
  637. var www = new WWW(System.IO.Path.Combine(Application.streamingAssetsPath, localFilePath));
  638. yield return www;
  639. data = www.bytes;
  640. #endif
  641. if (string.IsNullOrEmpty(www.error))
  642. {
  643. var tempFile = new FileInfo(tempFilePath);
  644. tempFile.Directory.Create();
  645. File.WriteAllBytes(tempFile.FullName, data);
  646. _cachedVideoPaths.Add(localFilePath, tempFilePath);
  647. }
  648. else
  649. {
  650. Debug.LogError("Can't create temp file from asset folder: " + www.error);
  651. }
  652. www.Dispose();
  653. }
  654. _isExportCompleted = true;
  655. }
  656. #region Editor Additional Possibility
  657. #if UNITY_EDITOR
  658. private bool _cachedPlayState;
  659. #if UNITY_4 || UNITY_5 || UNITY_2017_1
  660. //Used for defined in new Unity version 'playmodeStateChanged' method
  661. private void HandleOnPlayModeChanged()
  662. #else
  663. //Used for new 'playModeStateChanged' method that available in new Unity 2017.2+ version
  664. private void HandleOnPlayModeChanged(PlayModeStateChange modeState)
  665. #endif
  666. {
  667. if (_isFirstEditorStateChange)
  668. {
  669. _isFirstEditorStateChange = false;
  670. return;
  671. }
  672. if (_mediaPlayer == null)
  673. return;
  674. if (EditorApplication.isPaused)
  675. {
  676. _cachedPlayState = _mediaPlayer.IsPlaying;
  677. Pause();
  678. }
  679. else
  680. {
  681. if (!isActiveAndEnabled)
  682. {
  683. Stop();
  684. return;
  685. }
  686. if (_cachedPlayState)
  687. {
  688. _mediaPlayer.Play();
  689. }
  690. else
  691. {
  692. Pause();
  693. }
  694. }
  695. }
  696. private void OnValidate()
  697. {
  698. if (_mediaPlayer != null && _mediaPlayer.IsReady)
  699. {
  700. if (_mediaPlayer.Mute != _mute)
  701. _mediaPlayer.Mute = _mute;
  702. if (_mediaPlayer.Volume != _volume)
  703. _mediaPlayer.Volume = _volume;
  704. if (_mediaPlayer.PlaybackRate != _playRate)
  705. _mediaPlayer.PlaybackRate = _playRate;
  706. if (_position > _mediaPlayer.Position + DEFAULT_POSITION_CHANGED_OFFSET ||
  707. _position < _mediaPlayer.Position - DEFAULT_POSITION_CHANGED_OFFSET)
  708. {
  709. _mediaPlayer.Position = _position;
  710. }
  711. }
  712. }
  713. #endif
  714. #endregion
  715. private void Start()
  716. {
  717. if (!_autoPlay)
  718. return;
  719. Play();
  720. }
  721. private void OnDisable()
  722. {
  723. if (_mediaPlayer != null && _mediaPlayer.IsPlaying)
  724. {
  725. Stop();
  726. }
  727. }
  728. private void OnDestroy()
  729. {
  730. #if UNITY_EDITOR
  731. #if UNITY_4 || UNITY_5 || UNITY_2017_1
  732. EditorApplication.playmodeStateChanged -= HandleOnPlayModeChanged;
  733. #else
  734. EditorApplication.playModeStateChanged -= HandleOnPlayModeChanged;
  735. #endif
  736. #endif
  737. if (_mediaPlayer != null)
  738. {
  739. // Release MediaPlayer
  740. Release();
  741. }
  742. }
  743. private void AddListeners()
  744. {
  745. if (_mediaPlayer == null || _mediaPlayer.EventManager == null)
  746. return;
  747. // Add to MediaPlayer new main group of listeners
  748. _mediaPlayer.AddMediaListener(this);
  749. // Add to MediaPlayer new "OnPlayerTimeChanged" listener
  750. _mediaPlayer.EventManager.PlayerTimeChangedListener += OnPlayerTimeChanged;
  751. // Add to MediaPlayer new "OnPlayerPositionChanged" listener
  752. _mediaPlayer.EventManager.PlayerPositionChangedListener += OnPlayerPositionChanged;
  753. // Add to MediaPlayer new "OnPlayerSnapshotTaken" listener
  754. _mediaPlayer.EventManager.PlayerSnapshotTakenListener += OnPlayerSnapshotTaken;
  755. }
  756. private void RemoveListeners()
  757. {
  758. if (_mediaPlayer == null)
  759. return;
  760. // Remove from MediaPlayer the main group of listeners
  761. _mediaPlayer.RemoveMediaListener(this);
  762. // Remove from MediaPlayer "OnPlayerTimeChanged" listener
  763. _mediaPlayer.EventManager.PlayerTimeChangedListener -= OnPlayerTimeChanged;
  764. // Remove from MediaPlayer "OnPlayerPositionChanged" listener
  765. _mediaPlayer.EventManager.PlayerPositionChangedListener -= OnPlayerPositionChanged;
  766. // Remove from MediaPlayer new "OnPlayerSnapshotTaken" listener
  767. _mediaPlayer.EventManager.PlayerSnapshotTakenListener -= OnPlayerSnapshotTaken;
  768. }
  769. private IEnumerator VideoPathPreparing(string path, bool playImmediately, IPathPreparedListener listener)
  770. {
  771. if (_cachedVideoPaths.ContainsKey(path))
  772. {
  773. listener.OnPathPrepared(_cachedVideoPaths[path], playImmediately);
  774. yield break;
  775. }
  776. #if UNITY_EDITOR
  777. _lastEventMsg = "Path Preparing";
  778. #endif
  779. if (UMPSettings.RuntimePlatform == UMPSettings.Platforms.Android)
  780. {
  781. /// Check if we try to play exported videos and wait when export process will be completed
  782. var exptPaths = UMPSettings.Instance.AndroidExportedPaths;
  783. var filePath = path.Replace("file:///", "");
  784. foreach (var exptPath in exptPaths)
  785. {
  786. if (exptPath.Contains(filePath))
  787. {
  788. while (!_isExportCompleted)
  789. yield return null;
  790. if (_cachedVideoPaths.ContainsKey(filePath))
  791. {
  792. listener.OnPathPrepared(_cachedVideoPaths[filePath], playImmediately);
  793. yield break;
  794. }
  795. break;
  796. }
  797. }
  798. if ((_mediaPlayer.Options as PlayerOptionsAndroid).PlayerType ==
  799. PlayerOptionsAndroid.PlayerTypes.LibVLC
  800. && MediaPlayerHelper.IsAssetsFile(path))
  801. {
  802. var tempFilePath = System.IO.Path.Combine(Application.temporaryCachePath, filePath);
  803. if (File.Exists(tempFilePath))
  804. {
  805. _cachedVideoPaths.Add(path, tempFilePath);
  806. listener.OnPathPrepared(tempFilePath, playImmediately);
  807. yield break;
  808. }
  809. var data = new byte[0];
  810. #if UNITY_2017_2_OR_NEWER
  811. var www = UnityWebRequest.Get(System.IO.Path.Combine(Application.streamingAssetsPath, filePath));
  812. yield return www.SendWebRequest();
  813. data = www.downloadHandler.data;
  814. #else
  815. var www = new WWW(System.IO.Path.Combine(Application.streamingAssetsPath, filePath));
  816. yield return www;
  817. data = www.bytes;
  818. #endif
  819. if (string.IsNullOrEmpty(www.error))
  820. {
  821. var tempFile = new FileInfo(tempFilePath);
  822. tempFile.Directory.Create();
  823. File.WriteAllBytes(tempFile.FullName, data);
  824. _cachedVideoPaths.Add(path, tempFilePath);
  825. path = tempFilePath;
  826. }
  827. else
  828. {
  829. Debug.LogError("Can't create temp file from asset folder: " + www.error);
  830. }
  831. www.Dispose();
  832. }
  833. }
  834. if (_videoServices.ValidUrl(path))
  835. {
  836. Video serviceVideo = null;
  837. _isParsing = true;
  838. yield return _videoServices.GetVideos(path, (videos) =>
  839. {
  840. _isParsing = false;
  841. serviceVideo = VideoServices.FindVideo(videos, int.MaxValue, int.MaxValue);
  842. }, (error) =>
  843. {
  844. _isParsing = false;
  845. Debug.LogError(string.Format("[UniversalMediaPlayer.GetVideos] {0}", error));
  846. OnPlayerEncounteredError();
  847. });
  848. if (serviceVideo == null)
  849. {
  850. Debug.LogError("[UniversalMediaPlayer.VideoPathPreparing] Can't get service video information");
  851. OnPlayerEncounteredError();
  852. }
  853. else
  854. {
  855. if (serviceVideo is YoutubeVideo)
  856. {
  857. yield return (serviceVideo as YoutubeVideo).Decrypt(UMPSettings.Instance.YoutubeDecryptFunction, (error) =>
  858. {
  859. Debug.LogError(string.Format("[UniversalMediaPlayer.Decrypt] {0}", error));
  860. OnPlayerEncounteredError();
  861. });
  862. }
  863. path = serviceVideo.Url;
  864. }
  865. }
  866. listener.OnPathPrepared(path, playImmediately);
  867. yield return null;
  868. }
  869. public void Prepare()
  870. {
  871. if (_videoPathPreparingEnum != null)
  872. StopCoroutine(_videoPathPreparingEnum);
  873. _videoPathPreparingEnum = VideoPathPreparing(_path, false, this);
  874. StartCoroutine(_videoPathPreparingEnum);
  875. }
  876. IniController ini;
  877. string nvr_username, nvr_password, nvr_ip, nvr_port, rtsp, rtsp_id;
  878. int start_channel;
  879. void GetNVRData()
  880. {
  881. ini = new IniController(Application.streamingAssetsPath + "/Config.ini");
  882. if (ini.IsIniPath())
  883. {
  884. //nvr_ip = ini.keyVal["nvr_ip"];
  885. //nvr_port = ini.keyVal["nvr_port"];
  886. //nvr_username = ini.keyVal["nvr_username"];
  887. //nvr_password = ini.keyVal["nvr_password"];
  888. //rtsp_id = ini.keyVal["rtsp_id"];
  889. //start_channel = int.Parse(ini.keyVal["start_channel"]);
  890. //rtsp = "rtsp://" + nvr_username + ":" + nvr_password + "@";// + nvr_ip + "/Streaming/channels/";// + rtsp_id;
  891. }
  892. }
  893. public void Play()
  894. {
  895. //GetNVRData();
  896. rtsp = "rtsp://" + MainCameraController.username + ":" + MainCameraController.pwd + "@";
  897. if (MainCameraController.brand != default && MainCameraController.ip != default&& MainCameraController.devNo!= default)
  898. {
  899. if(MainCameraController.brand=="Hik")
  900. {
  901. _path = rtsp + MainCameraController.ip + "/Streaming/channels/" + MainCameraController.devNo + "01";
  902. }
  903. else
  904. {
  905. _path = rtsp + MainCameraController.ip + "/cam/realmonitor?channel="+ MainCameraController.devNo + "&subtype=1";
  906. }
  907. }
  908. LogHandle.LogInfo(_path);
  909. //_path = rtsp + rtsp_id;
  910. //}
  911. if (_videoPathPreparingEnum != null)
  912. StopCoroutine(_videoPathPreparingEnum);
  913. _videoPathPreparingEnum = VideoPathPreparing(_path, true, this);
  914. StartCoroutine(_videoPathPreparingEnum);
  915. }
  916. public void Pause()
  917. {
  918. if (_mediaPlayer == null)
  919. return;
  920. if (_mediaPlayer.IsPlaying)
  921. _mediaPlayer.Pause();
  922. }
  923. public void Stop()
  924. {
  925. Stop(true);
  926. }
  927. public void Stop(bool clearVideoTexture)
  928. {
  929. #if UNITY_EDITOR
  930. if (EditorApplication.isPaused)
  931. return;
  932. #endif
  933. if (_videoPathPreparingEnum != null)
  934. StopCoroutine(_videoPathPreparingEnum);
  935. _position = 0;
  936. if (_mediaPlayer == null)
  937. return;
  938. _mediaPlayer.Stop(clearVideoTexture);
  939. if (_mediaPlayerLoop != null)
  940. _mediaPlayerLoop.Stop(clearVideoTexture);
  941. }
  942. public void Release()
  943. {
  944. Stop();
  945. if (_mediaPlayer != null)
  946. {
  947. // Release MediaPlayer
  948. _mediaPlayer.Release();
  949. _mediaPlayer = null;
  950. if (_mediaPlayerLoop != null)
  951. _mediaPlayerLoop.Release();
  952. RemoveListeners();
  953. _openingEvent.RemoveAllListeners();
  954. _bufferingEvent.RemoveAllListeners();
  955. _imageReadyEvent.RemoveAllListeners();
  956. _preparedEvent.RemoveAllListeners();
  957. _playingEvent.RemoveAllListeners();
  958. _pausedEvent.RemoveAllListeners();
  959. _stoppedEvent.RemoveAllListeners();
  960. _endReachedEvent.RemoveAllListeners();
  961. _encounteredErrorEvent.RemoveAllListeners();
  962. _timeChangedEvent.RemoveAllListeners();
  963. _positionChangedEvent.RemoveAllListeners();
  964. _snapshotTakenEvent.RemoveAllListeners();
  965. }
  966. }
  967. public string GetFormattedLength(bool detail)
  968. {
  969. if (_mediaPlayer != null)
  970. return _mediaPlayer.GetFormattedLength(detail);
  971. return string.Empty;
  972. }
  973. public void Snapshot(string path)
  974. {
  975. #if UNITY_EDITOR
  976. if (EditorApplication.isPaused)
  977. return;
  978. #endif
  979. if (_mediaPlayer == null)
  980. return;
  981. if (_mediaPlayer.AbleToPlay)
  982. {
  983. if (_mediaPlayer.PlatformPlayer is MediaPlayerStandalone)
  984. (_mediaPlayer.PlatformPlayer as MediaPlayerStandalone).TakeSnapShot(path);
  985. #if UNITY_EDITOR
  986. Debug.Log("Snapshot path: " + path);
  987. #endif
  988. }
  989. }
  990. private void UnityConsoleLogging(PlayerManagerLogs.PlayerLog args)
  991. {
  992. if (args.Level != _logDetail)
  993. return;
  994. Debug.Log(args.Level.ToString() + ": " + args.Message);
  995. }
  996. public void OnPathPrepared(string path, bool playImmediately)
  997. {
  998. #if UNITY_EDITOR
  999. if (EditorApplication.isPaused)
  1000. return;
  1001. #endif
  1002. _mediaPlayer.Mute = _mute;
  1003. _mediaPlayer.Volume = _volume;
  1004. _mediaPlayer.PlaybackRate = _playRate;
  1005. if (!_path.Equals(_tmpPath))
  1006. {
  1007. if (IsPlaying)
  1008. Stop();
  1009. _tmpPath = _path;
  1010. _mediaPlayer.DataSource = path;
  1011. }
  1012. if (!playImmediately)
  1013. _mediaPlayer.Prepare();
  1014. else
  1015. _mediaPlayer.Play();
  1016. if (_mediaPlayerLoop != null && !_mediaPlayerLoop.IsReady)
  1017. {
  1018. _mediaPlayerLoop.DataSource = _mediaPlayer.DataSource;
  1019. _mediaPlayerLoop.Prepare();
  1020. }
  1021. if (_pathPreparedEvent != null)
  1022. _pathPreparedEvent.Invoke(path);
  1023. }
  1024. public void AddPathPreparedEvent(UnityAction<string> action)
  1025. {
  1026. _pathPreparedEvent.AddListener(action);
  1027. }
  1028. public void RemovePathPreparedEvent(UnityAction<string> action)
  1029. {
  1030. _pathPreparedEvent.RemoveListener(action);
  1031. }
  1032. public void OnPlayerOpening()
  1033. {
  1034. #if UNITY_EDITOR
  1035. _lastEventMsg = "Opening";
  1036. #endif
  1037. if (_openingEvent != null)
  1038. _openingEvent.Invoke();
  1039. }
  1040. public void AddOpeningEvent(UnityAction action)
  1041. {
  1042. _openingEvent.AddListener(action);
  1043. }
  1044. public void RemoveOpeningEvent(UnityAction action)
  1045. {
  1046. _openingEvent.RemoveListener(action);
  1047. }
  1048. public void OnPlayerBuffering(float percentage)
  1049. {
  1050. #if UNITY_EDITOR
  1051. _lastEventMsg = "Buffering: " + percentage;
  1052. #endif
  1053. if (_bufferingEvent != null)
  1054. _bufferingEvent.Invoke(percentage);
  1055. }
  1056. public void AddBufferingEvent(UnityAction<float> action)
  1057. {
  1058. _bufferingEvent.AddListener(action);
  1059. }
  1060. public void RemoveBufferingEvent(UnityAction<float> action)
  1061. {
  1062. _bufferingEvent.RemoveListener(action);
  1063. }
  1064. public void OnPlayerImageReady(Texture2D image)
  1065. {
  1066. #if UNITY_EDITOR
  1067. _lastEventMsg = "ImageReady";
  1068. #endif
  1069. if (_imageReadyEvent != null)
  1070. _imageReadyEvent.Invoke(image);
  1071. }
  1072. public void AddImageReadyEvent(UnityAction<Texture2D> action)
  1073. {
  1074. _imageReadyEvent.AddListener(action);
  1075. }
  1076. public void RemoveImageReadyEvent(UnityAction<Texture2D> action)
  1077. {
  1078. _imageReadyEvent.RemoveListener(action);
  1079. }
  1080. public void OnPlayerPrepared(int videoWidth, int videoHeight)
  1081. {
  1082. #if UNITY_EDITOR
  1083. _lastEventMsg = "Prepared";
  1084. #endif
  1085. _mediaPlayer.Mute = _mute;
  1086. _mediaPlayer.Volume = _volume;
  1087. _mediaPlayer.PlaybackRate = _playRate;
  1088. if (_preparedEvent != null)
  1089. _preparedEvent.Invoke(videoWidth, videoHeight);
  1090. }
  1091. public void AddPreparedEvent(UnityAction<int, int> action)
  1092. {
  1093. _preparedEvent.AddListener(action);
  1094. }
  1095. public void RemovePreparedEvent(UnityAction<int, int> action)
  1096. {
  1097. _preparedEvent.RemoveListener(action);
  1098. }
  1099. public void OnPlayerPlaying()
  1100. {
  1101. #if UNITY_EDITOR
  1102. _lastEventMsg = "Playing";
  1103. #endif
  1104. if (_playingEvent != null)
  1105. _playingEvent.Invoke();
  1106. }
  1107. public void AddPlayingEvent(UnityAction action)
  1108. {
  1109. _playingEvent.AddListener(action);
  1110. }
  1111. public void RemovePlayingEvent(UnityAction action)
  1112. {
  1113. _playingEvent.RemoveListener(action);
  1114. }
  1115. public void OnPlayerPaused()
  1116. {
  1117. #if UNITY_EDITOR
  1118. _lastEventMsg = "Paused";
  1119. #endif
  1120. if (_pausedEvent != null)
  1121. _pausedEvent.Invoke();
  1122. }
  1123. public void AddPausedEvent(UnityAction action)
  1124. {
  1125. _pausedEvent.AddListener(action);
  1126. }
  1127. public void RemovePausedEvent(UnityAction action)
  1128. {
  1129. _pausedEvent.RemoveListener(action);
  1130. }
  1131. public void OnPlayerStopped()
  1132. {
  1133. #if UNITY_EDITOR
  1134. if (!_lastEventMsg.Contains("Error"))
  1135. _lastEventMsg = "Stopped";
  1136. #endif
  1137. if (_stoppedEvent != null)
  1138. _stoppedEvent.Invoke();
  1139. }
  1140. public void AddStoppedEvent(UnityAction action)
  1141. {
  1142. _stoppedEvent.AddListener(action);
  1143. }
  1144. public void RemoveStoppedEvent(UnityAction action)
  1145. {
  1146. _stoppedEvent.RemoveListener(action);
  1147. }
  1148. public void OnPlayerEndReached()
  1149. {
  1150. #if UNITY_EDITOR
  1151. _lastEventMsg = "End";
  1152. #endif
  1153. _position = 0;
  1154. _mediaPlayer.Stop(!_loop);
  1155. if (_loop)
  1156. {
  1157. if (_mediaPlayerLoop != null)
  1158. {
  1159. _mediaPlayerLoop.EventManager.CopyPlayerEvents(_mediaPlayer.EventManager);
  1160. _mediaPlayerLoop.VideoOutputObjects = _mediaPlayer.VideoOutputObjects;
  1161. _mediaPlayer.VideoOutputObjects = null;
  1162. _mediaPlayer.EventManager.RemoveAllEvents();
  1163. var tempPlayer = _mediaPlayer;
  1164. _mediaPlayer = _mediaPlayerLoop;
  1165. _mediaPlayerLoop = tempPlayer;
  1166. }
  1167. if (!string.IsNullOrEmpty(_path))
  1168. Play();
  1169. }
  1170. if (_endReachedEvent != null)
  1171. _endReachedEvent.Invoke();
  1172. }
  1173. public void AddEndReachedEvent(UnityAction action)
  1174. {
  1175. _endReachedEvent.AddListener(action);
  1176. }
  1177. public void RemoveEndReachedEvent(UnityAction action)
  1178. {
  1179. _endReachedEvent.RemoveListener(action);
  1180. }
  1181. public void OnPlayerEncounteredError()
  1182. {
  1183. #if UNITY_EDITOR
  1184. _lastEventMsg = "Error (" + (_mediaPlayer.PlatformPlayer as MediaPlayerStandalone).GetLastError() + ")";
  1185. #endif
  1186. Stop();
  1187. if (_encounteredErrorEvent != null)
  1188. _encounteredErrorEvent.Invoke();
  1189. }
  1190. public void AddEncounteredErrorEvent(UnityAction action)
  1191. {
  1192. _encounteredErrorEvent.AddListener(action);
  1193. }
  1194. public void RemoveEncounteredErrorEvent(UnityAction action)
  1195. {
  1196. _encounteredErrorEvent.RemoveListener(action);
  1197. }
  1198. public void OnPlayerTimeChanged(long time)
  1199. {
  1200. #if UNITY_EDITOR
  1201. _lastEventMsg = "TimeChanged";
  1202. #endif
  1203. if (_timeChangedEvent != null)
  1204. _timeChangedEvent.Invoke(time);
  1205. }
  1206. public void AddTimeChangedEvent(UnityAction<long> action)
  1207. {
  1208. _timeChangedEvent.AddListener(action);
  1209. }
  1210. public void RemoveTimeChangedEvent(UnityAction<long> action)
  1211. {
  1212. _timeChangedEvent.RemoveListener(action);
  1213. }
  1214. public void OnPlayerPositionChanged(float position)
  1215. {
  1216. #if UNITY_EDITOR
  1217. _lastEventMsg = "PositionChanged";
  1218. #endif
  1219. _position = _mediaPlayer.Position;
  1220. if (_positionChangedEvent != null)
  1221. _positionChangedEvent.Invoke(position);
  1222. }
  1223. public void AddPositionChangedEvent(UnityAction<float> action)
  1224. {
  1225. _positionChangedEvent.AddListener(action);
  1226. }
  1227. public void RemovePositionChangedEvent(UnityAction<float> action)
  1228. {
  1229. _positionChangedEvent.RemoveListener(action);
  1230. }
  1231. public void OnPlayerSnapshotTaken(string path)
  1232. {
  1233. if (_snapshotTakenEvent != null)
  1234. _snapshotTakenEvent.Invoke(path);
  1235. }
  1236. public void AddSnapshotTakenEvent(UnityAction<string> action)
  1237. {
  1238. _snapshotTakenEvent.AddListener(action);
  1239. }
  1240. public void RemoveSnapshotTakenEvent(UnityAction<string> action)
  1241. {
  1242. _snapshotTakenEvent.RemoveListener(action);
  1243. }
  1244. }
  1245. }