天津23维预案
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1118 lines
28 KiB

//#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();
/// <summary>
/// Properties
/// </summary>
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;
}
}
/// <summary>
/// Methods
/// </summary>
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<MediaPlayer>();
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<MediaPlayer>();
foreach (MediaPlayer player in players)
{
player.EditorPause();
}
}
else
{
MediaPlayer[] players = Resources.FindObjectsOfTypeAll<MediaPlayer>();
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
}
}