//#define AVPROVIDEO_BETA_SUPPORT_TIMESCALE // BETA FEATURE: comment this in if you want to support frame stepping based on changes in Time.timeScale or Time.captureFramerate #if UNITY_ANDROID && !UNITY_EDITOR #define REAL_ANDROID #endif using UnityEngine; using System.Collections; using System.IO; using Video; //----------------------------------------------------------------------------- // Copyright 2015-2016 RenderHeads Ltd. All rights reserverd. //----------------------------------------------------------------------------- namespace RenderHeads.Media.AVProVideo { [AddComponentMenu("AVPro Video/Media Player")] public class MediaPlayer : MonoBehaviour { // These fields are just used to setup the default properties for a new video that is about to be loaded // Once a video has been loaded you should use the interfaces exposed in the properties to // change playback properties (eg volume, looping, mute) public FileLocation m_VideoLocation = FileLocation.RelativeToStreamingAssetsFolder; public string m_VideoPath; public bool m_AutoOpen = true; public bool m_AutoStart = false; public bool m_Loop = false; [Range(0.0f, 1.0f)] public float m_Volume = 1.0f; public bool m_Muted = false; [Range(-4.0f, 8.0f)]//-4,4 public float m_PlaybackRate = 1.0f;//1.0 // Component Properties public bool m_DebugGui = false; public bool m_Persistent = false; public StereoPacking m_StereoPacking = StereoPacking.None; public bool m_DisplayDebugStereoColorTint = false; public FilterMode m_FilterMode = FilterMode.Bilinear; public TextureWrapMode m_WrapMode = TextureWrapMode.Clamp; [Range(0, 16)] public int m_AnisoLevel = 0; [SerializeField] private MediaPlayerEvent m_events; private IMediaControl m_Control; private IMediaProducer m_Texture; private IMediaInfo m_Info; private IMediaPlayer m_Player; private System.IDisposable m_Dispose; private bool m_VideoOpened = false; private bool m_AutoStartTriggered = false; private bool m_WasPlayingOnPause = false; private bool m_isRenderCoroutineRunning = false; // Debug GUI private const float s_GuiScale = 1.5f; private const int s_GuiStartWidth = 10; private const int s_GuiWidth = 180; private int m_GuiPositionX = s_GuiStartWidth; // Global init private static bool s_GlobalStartup = false; // Events private bool m_EventFired_ReadyToPlay = false; private bool m_EventFired_Started = false; private bool m_EventFired_FirstFrameReady = false; private bool m_EventFired_FinishedPlaying = false; private bool m_EventFired_MetaDataReady = false; public enum FileLocation { AbsolutePathOrURL, RelativeToProjectFolder, RelativeToStreamingAssetsFolder, RelativeToDataFolder, RelativeToPeristentDataFolder, // TODO: Resource? } [System.Serializable] public class PlatformOptions { public bool overridePath = false; public FileLocation pathLocation = FileLocation.RelativeToStreamingAssetsFolder; public string path; } [System.Serializable] public class OptionsWindows : PlatformOptions { public bool forceDirectShowApi = false; public string forceAudioOutputDeviceName = string.Empty; } [System.Serializable] public class OptionsMacOSX : PlatformOptions { } [System.Serializable] public class OptionsIOS : PlatformOptions { } [System.Serializable] public class OptionsTVOS : PlatformOptions { } [System.Serializable] public class OptionsAndroid : PlatformOptions { } [System.Serializable] public class OptionsWindowsPhone : PlatformOptions { } [System.Serializable] public class OptionsWindowsUWP : PlatformOptions { } public OptionsWindows _optionsWindows = new OptionsWindows(); public OptionsMacOSX _optionsMacOSX = new OptionsMacOSX(); public OptionsIOS _optionsIOS = new OptionsIOS(); public OptionsTVOS _optionsTVOS = new OptionsTVOS(); public OptionsAndroid _optionsAndroid = new OptionsAndroid(); public OptionsWindowsPhone _optionsWindowsPhone = new OptionsWindowsPhone(); public OptionsWindowsUWP _optionsWindowsUWP = new OptionsWindowsUWP(); /// /// Properties /// public IMediaInfo Info { get { return m_Info; } } public IMediaControl Control { get { return m_Control; } } public IMediaPlayer Player { get { return m_Player; } } public virtual IMediaProducer TextureProducer { get { return m_Texture; } } public MediaPlayerEvent Events { get { if (m_events == null) { m_events = new MediaPlayerEvent(); } return m_events; } } /// /// Methods /// void Awake() { if (m_Persistent) { // TODO: set "this.transform.root.gameObject" to also DontDestroyOnLoad? DontDestroyOnLoad(this.gameObject); } } private void Initialise() { BaseMediaPlayer mediaPlayer = CreatePlatformMediaPlayer(); if (mediaPlayer != null) { // Set-up interface m_Control = mediaPlayer; m_Texture = mediaPlayer; m_Info = mediaPlayer; m_Player = mediaPlayer; m_Dispose = mediaPlayer; if (!s_GlobalStartup) { #if UNITY_5 // Debug.Log(string.Format("[AVProVideo] Initialising AVPro Video (script v{0} plugin v{1}) on {2}/{3} (MT {4})", Helper.ScriptVersion, mediaPlayer.GetVersion(), SystemInfo.graphicsDeviceName, SystemInfo.graphicsDeviceVersion, SystemInfo.graphicsMultiThreaded)); #else Debug.Log(string.Format("[AVProVideo] Initialising AVPro Video (script v{0} plugin v{1}) on {2}/{3}", Helper.ScriptVersion, mediaPlayer.GetVersion(), SystemInfo.graphicsDeviceName, SystemInfo.graphicsDeviceVersion)); #endif #if AVPROVIDEO_BETA_SUPPORT_TIMESCALE Debug.LogWarning("[AVProVideo] TimeScale support used. This could affect performance when changing Time.timeScale or Time.captureFramerate. This feature is useful for supporting video capture system that adjust time scale during capturing."); #endif s_GlobalStartup = true; } } } void Start() { if (m_Control == null) { Initialise(); } if (m_Control != null) { if (m_AutoOpen) { OpenVideoFromFile(); } StartRenderCoroutine(); } } public bool OpenVideoFromFile(FileLocation location, string path, bool autoPlay = true) { m_VideoLocation = location; m_VideoPath = path; m_AutoStart = autoPlay; if (m_Control == null) { Initialise(); } return OpenVideoFromFile(); } private bool OpenVideoFromFile() { bool result = false; // Open the video file if ( m_Control != null ) { CloseVideo(); m_VideoOpened = true; m_AutoStartTriggered = !m_AutoStart; m_EventFired_MetaDataReady = false; m_EventFired_ReadyToPlay = false; m_EventFired_Started = false; m_EventFired_FirstFrameReady = false; // Potentially override the file location string fullPath = GetPlatformFilePath(GetPlatform(), ref m_VideoPath, ref m_VideoLocation); if (!string.IsNullOrEmpty(m_VideoPath)) { bool checkForFileExist = true; if (fullPath.Contains("://")) { checkForFileExist = false; } #if (UNITY_ANDROID) checkForFileExist = false; #endif if (checkForFileExist && !System.IO.File.Exists(fullPath)) { Debug.LogError("[AVProVideo] File not found: " + fullPath, this); VCR.Instance().CloseMediaPlayer();//关闭播放器 } else { Debug.Log("[AVProVideo] Opening " + fullPath); if (!m_Control.OpenVideoFromFile(fullPath)) { Debug.LogError("[AVProVideo] Failed to open " + fullPath, this); VCR.Instance().CloseMediaPlayer();//关闭播放器 } else { SetPlaybackOptions(); result = true; } } } else { Debug.LogError("[AVProVideo] No file path specified", this); VCR.Instance().CloseMediaPlayer();//关闭播放器 } } return result; } private void SetPlaybackOptions() { // Set playback options if (m_Control != null) { m_Control.SetLooping(m_Loop); m_Control.SetVolume(m_Volume); m_Control.SetPlaybackRate(m_PlaybackRate); m_Control.MuteAudio(m_Muted); m_Control.SetTextureProperties(m_FilterMode, m_WrapMode, m_AnisoLevel); } } public void CloseVideo() { // Open the video file if( m_Control != null ) { if (m_events != null) { m_events.Invoke(this, MediaPlayerEvent.EventType.Closing, ErrorCode.None); } m_AutoStartTriggered = false; m_VideoOpened = false; m_EventFired_ReadyToPlay = false; m_EventFired_Started = false; m_EventFired_MetaDataReady = false; m_EventFired_FirstFrameReady = false; m_Control.CloseVideo(); } } public void Play() { if (m_Control != null && m_Control.CanPlay()) { m_Control.Play(); } else { // Can't play, perhaps it's still loading? Queuing play using m_AutoStart to play after loading m_AutoStart = true; } } public void Pause() { if (m_Control != null && m_Control.IsPlaying()) { m_Control.Pause(); } #if AVPROVIDEO_BETA_SUPPORT_TIMESCALE _timeScaleIsControlling = false; #endif } public void Stop() { if (m_Control != null) { m_Control.Stop(); } #if AVPROVIDEO_BETA_SUPPORT_TIMESCALE _timeScaleIsControlling = false; #endif } public void Rewind(bool pause) { if (m_Control != null) { if (pause) { Pause(); } m_Control.Rewind(); } } void Update() { // Auto start the playback if (m_Control != null) { if (m_VideoOpened && m_AutoStart && !m_AutoStartTriggered && m_Control.CanPlay()) { m_AutoStartTriggered = true; m_Control.Play(); } #if AVPROVIDEO_BETA_SUPPORT_TIMESCALE UpdateTimeScale(); #endif // Update m_Player.Update(); // Render (done in co-routine) //m_Player.Render(); UpdateErrors(); UpdateEvents(); } } void OnEnable() { if (m_Control != null && m_WasPlayingOnPause) { m_AutoStart = true; m_AutoStartTriggered = false; m_WasPlayingOnPause = false; } StartRenderCoroutine(); } void OnDisable() { if (m_Control != null) { if (m_Control.IsPlaying()) { m_WasPlayingOnPause = true; Pause(); } } StopRenderCoroutine(); } void OnDestroy() { StopRenderCoroutine(); m_VideoOpened = false; if (m_Dispose != null) { m_Dispose.Dispose(); m_Dispose = null; } m_Control = null; m_Texture = null; m_Info = null; m_Player = null; // TODO: possible bug if MediaPlayers are created and destroyed manually (instantiated), OnApplicationQuit won't be called! } //public void OnApplicationQuit() public static void OnQuiteEvent() { if (s_GlobalStartup) { //Debug.Log("[AVProVideo] Shutdown"); // Clean up any open media players MediaPlayer[] players = Resources.FindObjectsOfTypeAll(); if (players != null && players.Length > 0) { for (int i = 0; i < players.Length; i++) { players[i].CloseVideo(); } } #if UNITY_EDITOR #if UNITY_EDITOR_WIN WindowsMediaPlayer.DeinitPlatform(); #endif #else #if (UNITY_STANDALONE_WIN) WindowsMediaPlayer.DeinitPlatform(); #endif #endif s_GlobalStartup = false; } } #region Rendering Coroutine private void StartRenderCoroutine() { if (!m_isRenderCoroutineRunning) { m_isRenderCoroutineRunning = true; StartCoroutine("FinalRenderCapture"); } } private void StopRenderCoroutine() { if (m_isRenderCoroutineRunning) { StopCoroutine("FinalRenderCapture"); m_isRenderCoroutineRunning = false; } } private IEnumerator FinalRenderCapture() { while (Application.isPlaying) { yield return new WaitForEndOfFrame(); if (this.enabled) { if (m_Player != null) { m_Player.Render(); } } } } #endregion #region Platform and Path public static Platform GetPlatform() { Platform result = Platform.Unknown; // Setup for running in the editor (Either OSX, Windows or Linux) #if UNITY_EDITOR #if (UNITY_EDITOR_OSX && UNITY_EDITOR_64) result = Platform.MacOSX; #elif UNITY_EDITOR_WIN result = Platform.Windows; #endif #else // Setup for running builds #if (UNITY_STANDALONE_WIN) result = Platform.Windows; #elif (UNITY_STANDALONE_OSX) result = Platform.MacOSX; #elif (UNITY_IPHONE || UNITY_IOS) result = Platform.iOS; #elif (UNITY_TVOS) result = Platform.tvOS; #elif (UNITY_ANDROID) result = Platform.Android; #elif (UNITY_WP8) // TODO: add Windows Phone 8 suppport #elif (UNITY_WP81) // TODO: add Windows Phone 8.1 suppport #endif #endif return result; } public PlatformOptions GetPlatformOptions(Platform platform) { PlatformOptions result = null; #if UNITY_EDITOR #if (UNITY_EDITOR_OSX && UNITY_EDITOR_64) result = _optionsMacOSX; #elif UNITY_EDITOR_WIN result = _optionsWindows; #endif #else // Setup for running builds #if (UNITY_STANDALONE_WIN) result = _optionsWindows; #elif (UNITY_STANDALONE_OSX) result = _optionsMacOSX; #elif (UNITY_IPHONE || UNITY_IOS) result = _optionsIOS; #elif (UNITY_TVOS) result = _optionsTVOS; #elif (UNITY_ANDROID) result = _optionsAndroid; #elif (UNITY_WP8 || UNITY_WP81 || UNITY_WINRT_8_1) result = _optionsWindowsPhone; #elif (UNITY_WSA_10_0) result = _optionsWindowsUWP; #endif #endif return result; } #if UNITY_EDITOR public static string GetPlatformOptionsVariable(Platform platform) { string result = string.Empty; switch (platform) { case Platform.Windows: result = "_optionsWindows"; break; case Platform.MacOSX: result = "_optionsMacOSX"; break; case Platform.iOS: result = "_optionsIOS"; break; case Platform.tvOS: result = "_optionsTVOS"; break; case Platform.Android: result = "_optionsAndroid"; break; case Platform.WindowsPhone: result = "_optionsWindowsPhone"; break; case Platform.WindowsUWP: result = "_optionsWindowsUWP"; break; } return result; } #endif public static string GetPath(FileLocation location) { string result = string.Empty; switch (location) { case FileLocation.AbsolutePathOrURL: break; case FileLocation.RelativeToDataFolder: result = Application.dataPath; break; case FileLocation.RelativeToPeristentDataFolder: result = Application.persistentDataPath; break; case FileLocation.RelativeToProjectFolder: #if !UNITY_WINRT_8_1 result = System.IO.Path.GetFullPath(System.IO.Path.Combine(Application.dataPath, "..")); result = result.Replace('\\', '/'); #endif break; case FileLocation.RelativeToStreamingAssetsFolder: result = Application.streamingAssetsPath; break; } return result; } public static string GetFilePath(string path, FileLocation location) { string result = string.Empty; if (!string.IsNullOrEmpty(path)) { switch (location) { case FileLocation.AbsolutePathOrURL: result = path; break; case FileLocation.RelativeToDataFolder: case FileLocation.RelativeToPeristentDataFolder: case FileLocation.RelativeToProjectFolder: case FileLocation.RelativeToStreamingAssetsFolder: result = System.IO.Path.Combine(GetPath(location), path); break; } } return result; } private string GetPlatformFilePath(Platform platform, ref string filePath, ref FileLocation fileLocation) { string result = string.Empty; // Replace file path and location if overriden by platform options if (platform != Platform.Unknown) { PlatformOptions options = GetPlatformOptions(platform); if (options != null) { if (options.overridePath) { filePath = options.path; fileLocation = options.pathLocation; } } } result = GetFilePath(filePath, fileLocation); return result; } #endregion public virtual BaseMediaPlayer CreatePlatformMediaPlayer() { BaseMediaPlayer mediaPlayer = null; // Setup for running in the editor (Either OSX, Windows or Linux) #if UNITY_EDITOR #if (UNITY_EDITOR_OSX) #if UNITY_EDITOR_64 mediaPlayer = new OSXMediaPlayer(); #else Debug.LogError("[AVProVideo] 32-bit OS X Unity editor not supported. 64-bit required."); #endif #elif UNITY_EDITOR_WIN WindowsMediaPlayer.InitialisePlatform(); mediaPlayer = new WindowsMediaPlayer(_optionsWindows.forceDirectShowApi, _optionsWindows.forceAudioOutputDeviceName); #endif #else // Setup for running builds #if (UNITY_STANDALONE_WIN || UNITY_WSA_10_0 || UNITY_WINRT_8_1) WindowsMediaPlayer.InitialisePlatform(); mediaPlayer = new WindowsMediaPlayer(_optionsWindows.forceDirectShowApi); #elif (UNITY_STANDALONE_OSX || UNITY_IPHONE || UNITY_IOS || UNITY_TVOS) mediaPlayer = new OSXMediaPlayer(); #elif (UNITY_ANDROID) // Initialise platform (also unpacks videos from StreamingAsset folder (inside a jar), to the persistent data path) AndroidMediaPlayer.InitialisePlatform(); mediaPlayer = new AndroidMediaPlayer(); #endif #endif // Fallback if (mediaPlayer == null) { Debug.LogWarning("[AVProVideo] Not supported on this platform. Using placeholder player!"); mediaPlayer = new NullMediaPlayer(); } return mediaPlayer; } #region Support for Time Scale #if AVPROVIDEO_BETA_SUPPORT_TIMESCALE // Adjust this value to get faster performance but may drop frames. // Wait longer to ensure there is enough time for frames to process private const float TimeScaleTimeoutMs = 20f; private bool _timeScaleIsControlling; private float _timeScaleVideoTime; private void UpdateTimeScale() { if (Time.timeScale != 1f || Time.captureFramerate != 0) { if (Control.IsPlaying()) { Control.Pause(); _timeScaleIsControlling = true; _timeScaleVideoTime = Control.GetCurrentTimeMs(); } if (_timeScaleIsControlling) { int frameCount = TextureProducer.GetTextureFrameCount(); // Progress time _timeScaleVideoTime += (Time.deltaTime * 1000f); // Handle looping if (m_Loop && _timeScaleVideoTime >= Info.GetDurationMs()) { _timeScaleVideoTime = 0f; } // Seek Control.Seek(_timeScaleVideoTime); // Wait for frame to change ForceWaitForNewFrame(frameCount, TimeScaleTimeoutMs); } } else { // Restore playback when timeScale becomes 1 if (_timeScaleIsControlling) { Control.Play(); _timeScaleIsControlling = false; } } } #endif #endregion private bool ForceWaitForNewFrame(int lastFrameCount, float timeoutMs) { bool result = false; // Wait for the frame to change, or timeout to happen (for the case that there is no new frame for this time) System.DateTime startTime = System.DateTime.Now; int iterationCount = 0; while (Control != null && (System.DateTime.Now - startTime).TotalMilliseconds < (double)timeoutMs) { m_Player.Update(); // TODO: check if Seeking has completed! Then we don't have to wait // If frame has changed we can continue // NOTE: this will never happen because GL.IssuePlugin.Event is never called in this loop if (lastFrameCount != TextureProducer.GetTextureFrameCount()) { result = true; break; } iterationCount++; // NOTE: we tried to add Sleep for 1ms but it was very slow, so switched to this time based method which burns more CPU but about double the speed // NOTE: had to add the Sleep back in as after too many iterations (over 1000000) of GL.IssuePluginEvent Unity seems to lock up // NOTE: seems that GL.IssuePluginEvent can't be called if we're stuck in a while loop and they just stack up //System.Threading.Thread.Sleep(0); } m_Player.Render(); return result; } private void UpdateErrors() { ErrorCode errorCode = m_Control.GetLastError(); if (ErrorCode.None != errorCode) { Debug.LogError("[AVProVideo] Error: " + errorCode.ToString()); VCR.Instance().CloseMediaPlayer();//关闭播放器 if (m_events != null) { m_events.Invoke(this, MediaPlayerEvent.EventType.Error, errorCode); } } } private void UpdateEvents() { if (m_events != null && m_Control != null) { // Finished event if (!m_EventFired_FinishedPlaying && !m_Control.IsLooping() && m_Control.CanPlay() && m_Control.IsFinished()) { m_EventFired_FinishedPlaying = true; m_events.Invoke(this, MediaPlayerEvent.EventType.FinishedPlaying, ErrorCode.None); } // Keep track of whether the Playing state has changed if (m_EventFired_Started && !m_Control.IsPlaying()) { // Playing has stopped m_EventFired_Started = false; } if (m_EventFired_FinishedPlaying && m_Control.IsPlaying() && !m_Control.IsFinished()) { m_EventFired_FinishedPlaying = false; } // Fire events if (!m_EventFired_MetaDataReady && m_Control.HasMetaData()) { m_EventFired_MetaDataReady = true; m_events.Invoke(this, MediaPlayerEvent.EventType.MetaDataReady, ErrorCode.None); } if (!m_EventFired_ReadyToPlay && !m_Control.IsPlaying() && m_Control.CanPlay()) { m_EventFired_ReadyToPlay = true; m_events.Invoke(this, MediaPlayerEvent.EventType.ReadyToPlay, ErrorCode.None); } if (!m_EventFired_Started && m_Control.IsPlaying()) { m_EventFired_Started = true; m_events.Invoke(this, MediaPlayerEvent.EventType.Started, ErrorCode.None); } if (m_Texture != null) { if (!m_EventFired_FirstFrameReady && m_Control.CanPlay() && m_Texture.GetTextureFrameCount() > 0) { m_EventFired_FirstFrameReady = true; m_events.Invoke(this, MediaPlayerEvent.EventType.FirstFrameReady, ErrorCode.None); } } } } #region Application Focus and Pausing #if !UNITY_EDITOR void OnApplicationFocus( bool focusStatus ) { #if !(UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN) // Debug.Log("OnApplicationFocus: focusStatus: " + focusStatus); if( focusStatus ) { if( m_Control != null && m_WasPlayingOnPause ) { m_WasPlayingOnPause = false; m_Control.Play(); Debug.Log("OnApplicationFocus: playing video again"); } } #endif } void OnApplicationPause( bool pauseStatus ) { #if !(UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN) // Debug.Log("OnApplicationPause: pauseStatus: " + pauseStatus); if( pauseStatus ) { if( m_Control!= null && m_Control.IsPlaying() ) { m_WasPlayingOnPause = true; m_Control.Pause(); Debug.Log("OnApplicationPause: pausing video"); } } else { // Catch coming back from power off state when no lock screen OnApplicationFocus( true ); } #endif } #endif #endregion #region Save Frame To PNG #if UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_EDITOR [ContextMenu("Save Frame To PNG")] public void SaveFrameToPng() { Texture2D frame = ExtractFrame(null); if (frame != null) { byte[] imageBytes = frame.EncodeToPNG(); if (imageBytes != null) { #if !UNITY_WEBPLAYER string timecode = Mathf.FloorToInt(Control.GetCurrentTimeMs()).ToString("D8"); System.IO.File.WriteAllBytes("frame-" + timecode + ".png", imageBytes); #else Debug.LogError("Web Player platform doesn't support file writing. Change platform in Build Settings."); #endif } Destroy(frame); } } #endif #endregion #region Extract Frame // "target" can be null or you can pass in an existing texture. public Texture2D ExtractFrame(Texture2D target, float timeSeconds = -1f, bool accurateSeek = true, int timeoutMs = 1000) { Texture2D result = target; // Extract frames returns the interal frame of the video player Texture frame = ExtractFrame(timeSeconds, accurateSeek, timeoutMs); if (frame != null) { result = Helper.GetReadableTexture(frame, TextureProducer.RequiresVerticalFlip(), target); } return result; } private Texture ExtractFrame(float timeSeconds = -1f, bool accurateSeek = true, int timeoutMs = 1000) { Texture result = null; if (m_Control != null) { if (timeSeconds >= 0f) { Pause(); float seekTimeMs = timeSeconds * 1000f; // If the frame is already avaiable just grab it if (TextureProducer.GetTexture() != null && m_Control.GetCurrentTimeMs() == seekTimeMs) { result = TextureProducer.GetTexture(); } else { // Store frame count before seek int frameCount = TextureProducer.GetTextureFrameCount(); // Seek to the frame if (accurateSeek) { m_Control.Seek(seekTimeMs); } else { m_Control.SeekFast(seekTimeMs); } // Wait for frame to change ForceWaitForNewFrame(frameCount, timeoutMs); result = TextureProducer.GetTexture(); } } else { result = TextureProducer.GetTexture(); } } return result; } #endregion #region Play/Pause Support for Unity Editor // This code handles the pause/play buttons in the editor #if UNITY_EDITOR static MediaPlayer() { UnityEditor.EditorApplication.playmodeStateChanged -= OnUnityPlayModeChanged; UnityEditor.EditorApplication.playmodeStateChanged += OnUnityPlayModeChanged; } private static void OnUnityPlayModeChanged() { if (UnityEditor.EditorApplication.isPlaying) { if (UnityEditor.EditorApplication.isPaused) { MediaPlayer[] players = Resources.FindObjectsOfTypeAll(); foreach (MediaPlayer player in players) { player.EditorPause(); } } else { MediaPlayer[] players = Resources.FindObjectsOfTypeAll(); foreach (MediaPlayer player in players) { player.EditorUnpause(); } } } } private void EditorPause() { if (this.isActiveAndEnabled) { if (m_Control != null && m_Control.IsPlaying()) { m_WasPlayingOnPause = true; Pause(); } StopRenderCoroutine(); } } private void EditorUnpause() { if (this.isActiveAndEnabled) { if (m_Control != null && m_WasPlayingOnPause) { m_AutoStart = true; m_WasPlayingOnPause = false; m_AutoStartTriggered = false; } StartRenderCoroutine(); } } #endif #endregion #region IMGUI Debug Information Display public void SetGuiPositionFromVideoIndex(int index) { m_GuiPositionX = Mathf.FloorToInt((s_GuiStartWidth * s_GuiScale) + (s_GuiWidth * index * s_GuiScale)); } public void SetDebugGuiEnabled(bool bEnabled) { m_DebugGui = bEnabled; } void OnGUI() { if (m_Info != null && m_DebugGui) { GUI.depth = -1; GUI.matrix = Matrix4x4.TRS(new Vector3(m_GuiPositionX, 10f, 0f), Quaternion.identity, new Vector3(s_GuiScale, s_GuiScale, 1.0f)); GUILayout.BeginVertical("box", GUILayout.MaxWidth(s_GuiWidth)); GUILayout.Label(System.IO.Path.GetFileName(m_VideoPath)); GUILayout.Label("Dimensions: " + m_Info.GetVideoWidth() + " x " + m_Info.GetVideoHeight()); GUILayout.Label("Time: " + (m_Control.GetCurrentTimeMs() * 0.001f).ToString("F1") + "s / " + (m_Info.GetDurationMs() * 0.001f).ToString("F1") + "s"); GUILayout.Label("Rate: " + m_Info.GetVideoPlaybackRate().ToString("F2") + "Hz"); if (TextureProducer != null && TextureProducer.GetTexture() != null) { // Show texture without and with alpha blending GUILayout.BeginHorizontal(); Rect r1 = GUILayoutUtility.GetRect(32f, 32f); GUILayout.Space(8f); Rect r2 = GUILayoutUtility.GetRect(32f, 32f); if (TextureProducer.RequiresVerticalFlip()) { GUIUtility.ScaleAroundPivot(new Vector2(1f, -1f), new Vector2(0, r1.y + (r1.height / 2))); } GUI.DrawTexture(r1, TextureProducer.GetTexture(), ScaleMode.ScaleToFit, false); GUI.DrawTexture(r2, TextureProducer.GetTexture(), ScaleMode.ScaleToFit, true); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); } GUILayout.EndVertical(); } } #endregion } }