using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

namespace RenderHeads.Media.AVProVideo
{
	[AddComponentMenu("AVPro Video/Media Player", -100)]
	[HelpURL("http://renderheads.com/product/avpro-video/")]
	public class MediaPlayer : MonoBehaviour
	{
		public Resampler FrameResampler
		{
			get
			{
				return this.m_Resampler;
			}
		}

		public bool DisplayDebugGUI
		{
			get
			{
				return this.m_DebugGui;
			}
			set
			{
				this.m_DebugGui = value;
			}
		}

		public bool DisplayDebugGUIControls
		{
			get
			{
				return this.m_DebugGuiControls;
			}
			set
			{
				this.m_DebugGuiControls = value;
			}
		}

		public bool Persistent
		{
			get
			{
				return this.m_Persistent;
			}
			set
			{
				this.m_Persistent = value;
			}
		}

		public IMediaInfo Info
		{
			get
			{
				return this.m_Info;
			}
		}

		public IMediaControl Control
		{
			get
			{
				return this.m_Control;
			}
		}

		public IMediaPlayer Player
		{
			get
			{
				return this.m_Player;
			}
		}

		public virtual IMediaProducer TextureProducer
		{
			get
			{
				return this.m_Texture;
			}
		}

		public virtual IMediaSubtitles Subtitles
		{
			get
			{
				return this.m_Subtitles;
			}
		}

		public MediaPlayerEvent Events
		{
			get
			{
				if (this.m_events == null)
				{
					this.m_events = new MediaPlayerEvent();
				}
				return this.m_events;
			}
		}

		public bool VideoOpened
		{
			get
			{
				return this.m_VideoOpened;
			}
		}

		public Transform AudioHeadTransform
		{
			get
			{
				return this.m_AudioHeadTransform;
			}
			set
			{
				this.m_AudioHeadTransform = value;
			}
		}

		public bool AudioFocusEnabled
		{
			get
			{
				return this.m_AudioFocusEnabled;
			}
			set
			{
				this.m_AudioFocusEnabled = value;
			}
		}

		public float AudioFocusOffLevelDB
		{
			get
			{
				return this.m_AudioFocusOffLevelDB;
			}
			set
			{
				this.m_AudioFocusOffLevelDB = value;
			}
		}

		public float AudioFocusWidthDegrees
		{
			get
			{
				return this.m_AudioFocusWidthDegrees;
			}
			set
			{
				this.m_AudioFocusWidthDegrees = value;
			}
		}

		public Transform AudioFocusTransform
		{
			get
			{
				return this.m_AudioFocusTransform;
			}
			set
			{
				this.m_AudioFocusTransform = value;
			}
		}

		public MediaPlayer.OptionsWindows PlatformOptionsWindows
		{
			get
			{
				return this._optionsWindows;
			}
		}

		public MediaPlayer.OptionsMacOSX PlatformOptionsMacOSX
		{
			get
			{
				return this._optionsMacOSX;
			}
		}

		public MediaPlayer.OptionsIOS PlatformOptionsIOS
		{
			get
			{
				return this._optionsIOS;
			}
		}

		public MediaPlayer.OptionsTVOS PlatformOptionsTVOS
		{
			get
			{
				return this._optionsTVOS;
			}
		}

		public MediaPlayer.OptionsAndroid PlatformOptionsAndroid
		{
			get
			{
				return this._optionsAndroid;
			}
		}

		public MediaPlayer.OptionsWindowsPhone PlatformOptionsWindowsPhone
		{
			get
			{
				return this._optionsWindowsPhone;
			}
		}

		public MediaPlayer.OptionsWindowsUWP PlatformOptionsWindowsUWP
		{
			get
			{
				return this._optionsWindowsUWP;
			}
		}

		public MediaPlayer.OptionsWebGL PlatformOptionsWebGL
		{
			get
			{
				return this._optionsWebGL;
			}
		}

		public MediaPlayer.OptionsPS4 PlatformOptionsPS4
		{
			get
			{
				return this._optionsPS4;
			}
		}

		private void Awake()
		{
			if (this.m_Persistent)
			{
				UnityEngine.Object.DontDestroyOnLoad(base.gameObject);
			}
		}

		protected void Initialise()
		{
			BaseMediaPlayer baseMediaPlayer = this.CreatePlatformMediaPlayer();
			if (baseMediaPlayer != null)
			{
				this.m_Control = baseMediaPlayer;
				this.m_Texture = baseMediaPlayer;
				this.m_Info = baseMediaPlayer;
				this.m_Player = baseMediaPlayer;
				this.m_Subtitles = baseMediaPlayer;
				this.m_Dispose = baseMediaPlayer;
				if (!MediaPlayer.s_GlobalStartup)
				{
					Helper.LogInfo(string.Format("Initialising AVPro Video (script v{0} plugin v{1}) on {2}/{3} (MT {4}) on {5}", new object[]
					{
						"1.7.5",
						baseMediaPlayer.GetVersion(),
						SystemInfo.graphicsDeviceName,
						SystemInfo.graphicsDeviceVersion,
						SystemInfo.graphicsMultiThreaded,
						Application.platform
					}), null);
					MediaPlayer.s_GlobalStartup = true;
				}
			}
		}

		private void Start()
		{
			if (this.m_Control == null)
			{
				this.Initialise();
			}
			if (this.m_Control != null)
			{
				if (this.m_AutoOpen)
				{
					this.OpenVideoFromFile();
					if (this.m_LoadSubtitles && this.m_Subtitles != null && !string.IsNullOrEmpty(this.m_SubtitlePath))
					{
						this.EnableSubtitles(this.m_SubtitleLocation, this.m_SubtitlePath);
					}
				}
				this.StartRenderCoroutine();
			}
		}

		public bool OpenVideoFromFile(MediaPlayer.FileLocation location, string path, bool autoPlay = true)
		{
			this.m_VideoLocation = location;
			this.m_VideoPath = path;
			this.m_AutoStart = autoPlay;
			if (this.m_Control == null)
			{
				this.Initialise();
			}
			return this.OpenVideoFromFile();
		}

		public bool OpenVideoFromBuffer(byte[] buffer, bool autoPlay = true)
		{
			this.m_VideoLocation = MediaPlayer.FileLocation.AbsolutePathOrURL;
			this.m_VideoPath = "buffer";
			this.m_AutoStart = autoPlay;
			if (this.m_Control == null)
			{
				this.Initialise();
			}
			return this.OpenVideoFromBufferInternal(buffer);
		}

		public bool SubtitlesEnabled
		{
			get
			{
				return this.m_LoadSubtitles;
			}
		}

		public string SubtitlePath
		{
			get
			{
				return this.m_SubtitlePath;
			}
		}

		public MediaPlayer.FileLocation SubtitleLocation
		{
			get
			{
				return this.m_SubtitleLocation;
			}
		}

		public bool EnableSubtitles(MediaPlayer.FileLocation fileLocation, string filePath)
		{
			bool result = false;
			if (this.m_Subtitles != null)
			{
				if (!string.IsNullOrEmpty(filePath))
				{
					string platformFilePath = this.GetPlatformFilePath(MediaPlayer.GetPlatform(), ref filePath, ref fileLocation);
					bool flag = true;
					if (platformFilePath.Contains("://"))
					{
						flag = false;
					}
					if (flag && !File.Exists(platformFilePath))
					{
						Debug.LogError("[AVProVideo] Subtitle file not found: " + platformFilePath, this);
					}
					else
					{
						Helper.LogInfo("Opening subtitles " + platformFilePath, this);
						this.m_previousSubtitleIndex = -1;
						try
						{
							if (platformFilePath.Contains("://"))
							{
								if (this.m_loadSubtitlesRoutine != null)
								{
									base.StopCoroutine(this.m_loadSubtitlesRoutine);
									this.m_loadSubtitlesRoutine = null;
								}
								this.m_loadSubtitlesRoutine = base.StartCoroutine(this.LoadSubtitlesCoroutine(platformFilePath, fileLocation, filePath));
							}
							else
							{
								string data = File.ReadAllText(platformFilePath);
								if (this.m_Subtitles.LoadSubtitlesSRT(data))
								{
									this.m_SubtitleLocation = fileLocation;
									this.m_SubtitlePath = filePath;
									this.m_LoadSubtitles = false;
									result = true;
								}
								else
								{
									Debug.LogError("[AVProVideo] Failed to load subtitles" + platformFilePath, this);
								}
							}
						}
						catch (Exception exception)
						{
							Debug.LogError("[AVProVideo] Failed to load subtitles " + platformFilePath, this);
							Debug.LogException(exception, this);
						}
					}
				}
				else
				{
					Debug.LogError("[AVProVideo] No subtitle file path specified", this);
				}
			}
			else
			{
				this.m_queueSubtitleLocation = fileLocation;
				this.m_queueSubtitlePath = filePath;
			}
			return result;
		}

		private IEnumerator LoadSubtitlesCoroutine(string url, MediaPlayer.FileLocation fileLocation, string filePath)
		{
			WWW www = new WWW(url);
			yield return www;
			string subtitleData = string.Empty;
			if (string.IsNullOrEmpty(www.error))
			{
				subtitleData = www.text;
			}
			else
			{
				Debug.LogError("[AVProVideo] Error loading subtitles '" + www.error + "' from " + url);
			}
			if (this.m_Subtitles.LoadSubtitlesSRT(subtitleData))
			{
				this.m_SubtitleLocation = fileLocation;
				this.m_SubtitlePath = filePath;
				this.m_LoadSubtitles = false;
			}
			else
			{
				Debug.LogError("[AVProVideo] Failed to load subtitles" + url, this);
			}
			this.m_loadSubtitlesRoutine = null;
			yield break;
		}

		public void DisableSubtitles()
		{
			if (this.m_loadSubtitlesRoutine != null)
			{
				base.StopCoroutine(this.m_loadSubtitlesRoutine);
				this.m_loadSubtitlesRoutine = null;
			}
			if (this.m_Subtitles != null)
			{
				this.m_previousSubtitleIndex = -1;
				this.m_LoadSubtitles = false;
				this.m_Subtitles.LoadSubtitlesSRT(string.Empty);
			}
			else
			{
				this.m_queueSubtitlePath = string.Empty;
			}
		}

		private bool OpenVideoFromBufferInternal(byte[] buffer)
		{
			bool result = false;
			if (this.m_Control != null)
			{
				this.CloseVideo();
				this.m_VideoOpened = true;
				this.m_AutoStartTriggered = !this.m_AutoStart;
				this.m_EventFired_MetaDataReady = false;
				this.m_EventFired_ReadyToPlay = false;
				this.m_EventFired_Started = false;
				this.m_EventFired_FirstFrameReady = false;
				this.m_EventFired_FinishedPlaying = false;
				this.m_previousSubtitleIndex = -1;
				Helper.LogInfo("Opening buffer of length " + buffer.Length, this);
				if (!this.m_Control.OpenVideoFromBuffer(buffer))
				{
					Debug.LogError("[AVProVideo] Failed to open buffer", this);
					if (this.GetCurrentPlatformOptions() != this.PlatformOptionsWindows || this.PlatformOptionsWindows.videoApi != Windows.VideoApi.DirectShow)
					{
						Debug.LogError("[AVProVideo] Loading from buffer is currently only supported in Windows when using the DirectShow API");
					}
				}
				else
				{
					this.SetPlaybackOptions();
					result = true;
					this.StartRenderCoroutine();
				}
			}
			return result;
		}

		private bool OpenVideoFromFile()
		{
			bool result = false;
			if (this.m_Control != null)
			{
				this.CloseVideo();
				this.m_VideoOpened = true;
				this.m_AutoStartTriggered = !this.m_AutoStart;
				this.m_EventFired_MetaDataReady = false;
				this.m_EventFired_ReadyToPlay = false;
				this.m_EventFired_Started = false;
				this.m_EventFired_FirstFrameReady = false;
				this.m_EventFired_FinishedPlaying = false;
				this.m_FinishedFrameOpenCheck = true;
				this.m_previousSubtitleIndex = -1;
				long platformFileOffset = this.GetPlatformFileOffset();
				string platformFilePath = this.GetPlatformFilePath(MediaPlayer.GetPlatform(), ref this.m_VideoPath, ref this.m_VideoLocation);
				if (!string.IsNullOrEmpty(this.m_VideoPath))
				{
					string httpHeaderJson = null;
					bool flag = true;
					if (platformFilePath.Contains("://"))
					{
						flag = false;
						httpHeaderJson = this.GetPlatformHttpHeaderJson();
					}
					if (flag && !File.Exists(platformFilePath))
					{
						Debug.LogError("[AVProVideo] File not found: " + platformFilePath, this);
					}
					else
					{
						Helper.LogInfo(string.Concat(new object[]
						{
							"Opening ",
							platformFilePath,
							" (offset ",
							platformFileOffset,
							")"
						}), this);
						if (this._optionsWindows.enableAudio360)
						{
							this.m_Control.SetAudioChannelMode(this._optionsWindows.audio360ChannelMode);
						}
						if (!this.m_Control.OpenVideoFromFile(platformFilePath, platformFileOffset, httpHeaderJson))
						{
							Debug.LogError("[AVProVideo] Failed to open " + platformFilePath, this);
						}
						else
						{
							this.SetPlaybackOptions();
							result = true;
							this.StartRenderCoroutine();
						}
					}
				}
				else
				{
					Debug.LogError("[AVProVideo] No file path specified", this);
				}
			}
			return result;
		}

		private void SetPlaybackOptions()
		{
			if (this.m_Control != null)
			{
				this.m_Control.SetLooping(this.m_Loop);
				this.m_Control.SetVolume(this.m_Volume);
				this.m_Control.SetBalance(this.m_Balance);
				this.m_Control.SetPlaybackRate(this.m_PlaybackRate);
				this.m_Control.MuteAudio(this.m_Muted);
				this.m_Control.SetTextureProperties(this.m_FilterMode, this.m_WrapMode, this.m_AnisoLevel);
			}
		}

		public void CloseVideo()
		{
			if (this.m_Control != null)
			{
				if (this.m_events != null && this.m_VideoOpened)
				{
					this.m_events.Invoke(this, MediaPlayerEvent.EventType.Closing, ErrorCode.None);
				}
				this.m_AutoStartTriggered = false;
				this.m_VideoOpened = false;
				this.m_EventFired_ReadyToPlay = false;
				this.m_EventFired_Started = false;
				this.m_EventFired_MetaDataReady = false;
				this.m_EventFired_FirstFrameReady = false;
				this.m_EventFired_FinishedPlaying = false;
				if (this.m_loadSubtitlesRoutine != null)
				{
					base.StopCoroutine(this.m_loadSubtitlesRoutine);
					this.m_loadSubtitlesRoutine = null;
				}
				this.m_previousSubtitleIndex = -1;
				this.m_isPlaybackStalled = false;
				this.m_Control.CloseVideo();
			}
			if (this.m_Resampler != null)
			{
				this.m_Resampler.Reset();
			}
			this.StopRenderCoroutine();
		}

		public void Play()
		{
			if (this.m_Control != null && this.m_Control.CanPlay())
			{
				this.m_Control.Play();
				this.m_EventFired_ReadyToPlay = true;
			}
			else
			{
				this.m_AutoStart = true;
			}
		}

		public void Pause()
		{
			if (this.m_Control != null && this.m_Control.IsPlaying())
			{
				this.m_Control.Pause();
			}
		}

		public void Stop()
		{
			if (this.m_Control != null)
			{
				this.m_Control.Stop();
			}
		}

		public void Rewind(bool pause)
		{
			if (this.m_Control != null)
			{
				if (pause)
				{
					this.Pause();
				}
				this.m_Control.Rewind();
			}
		}

		private void Update()
		{
			if (this.m_Control != null)
			{
				if (this.m_VideoOpened && this.m_AutoStart && !this.m_AutoStartTriggered && this.m_Control.CanPlay())
				{
					this.m_AutoStartTriggered = true;
					this.Play();
				}
				if (this._renderingCoroutine == null && this.m_Control.CanPlay())
				{
					this.StartRenderCoroutine();
				}
				if (this.m_Subtitles != null && !string.IsNullOrEmpty(this.m_queueSubtitlePath))
				{
					this.EnableSubtitles(this.m_queueSubtitleLocation, this.m_queueSubtitlePath);
					this.m_queueSubtitlePath = string.Empty;
				}
				this.UpdateAudioHeadTransform();
				this.UpdateAudioFocus();
				this.m_Player.Update();
				this.UpdateErrors();
				this.UpdateEvents();
			}
		}

		private void LateUpdate()
		{
			if (this.m_Resample && this.m_Resampler == null)
			{
				this.m_Resampler = new Resampler(this, base.gameObject.name, this.m_ResampleBufferSize, this.m_ResampleMode);
			}
			if (this.m_Resampler != null)
			{
				this.m_Resampler.Update();
				this.m_Resampler.UpdateTimestamp();
			}
		}

		private void OnEnable()
		{
			if (this.m_Control != null && this.m_WasPlayingOnPause)
			{
				this.m_AutoStart = true;
				this.m_AutoStartTriggered = false;
				this.m_WasPlayingOnPause = false;
			}
			if (this.m_Player != null)
			{
				this.m_Player.OnEnable();
			}
			this.StartRenderCoroutine();
		}

		private void OnDisable()
		{
			if (this.m_Control != null && this.m_Control.IsPlaying())
			{
				this.m_WasPlayingOnPause = true;
				this.Pause();
			}
			this.StopRenderCoroutine();
		}

		private void OnDestroy()
		{
			this.CloseVideo();
			if (this.m_Dispose != null)
			{
				this.m_Dispose.Dispose();
				this.m_Dispose = null;
			}
			this.m_Control = null;
			this.m_Texture = null;
			this.m_Info = null;
			this.m_Player = null;
			if (this.m_Resampler != null)
			{
				this.m_Resampler.Release();
				this.m_Resampler = null;
			}
		}

		private void OnApplicationQuit()
		{
			if (MediaPlayer.s_GlobalStartup)
			{
				Helper.LogInfo("Shutdown", null);
				MediaPlayer[] array = Resources.FindObjectsOfTypeAll<MediaPlayer>();
				if (array != null && array.Length > 0)
				{
					for (int i = 0; i < array.Length; i++)
					{
						array[i].CloseVideo();
					}
				}
				WindowsMediaPlayer.DeinitPlatform();
				MediaPlayer.s_GlobalStartup = false;
			}
		}

		private void StartRenderCoroutine()
		{
			if (this._renderingCoroutine == null)
			{
				this._renderingCoroutine = base.StartCoroutine(this.FinalRenderCapture());
			}
		}

		private void StopRenderCoroutine()
		{
			if (this._renderingCoroutine != null)
			{
				base.StopCoroutine(this._renderingCoroutine);
				this._renderingCoroutine = null;
			}
		}

		private IEnumerator FinalRenderCapture()
		{
			YieldInstruction wait = new WaitForEndOfFrame();
			while (Application.isPlaying)
			{
				yield return wait;
				if (base.enabled && this.m_Player != null)
				{
					this.m_Player.Render();
				}
			}
			yield break;
		}

		public static Platform GetPlatform()
		{
			return Platform.Windows;
		}

		public MediaPlayer.PlatformOptions GetCurrentPlatformOptions()
		{
			return this._optionsWindows;
		}

		public static string GetPath(MediaPlayer.FileLocation location)
		{
			string text = string.Empty;
			switch (location)
			{
			case MediaPlayer.FileLocation.RelativeToProjectFolder:
			{
				string path = "..";
				text = Path.GetFullPath(Path.Combine(Application.dataPath, path));
				text = text.Replace('\\', '/');
				break;
			}
			case MediaPlayer.FileLocation.RelativeToStreamingAssetsFolder:
				text = Application.streamingAssetsPath;
				break;
			case MediaPlayer.FileLocation.RelativeToDataFolder:
				text = Application.dataPath;
				break;
			case MediaPlayer.FileLocation.RelativeToPeristentDataFolder:
				text = Application.persistentDataPath;
				break;
			}
			return text;
		}

		public static string GetFilePath(string path, MediaPlayer.FileLocation location)
		{
			string result = string.Empty;
			if (!string.IsNullOrEmpty(path))
			{
				switch (location)
				{
				case MediaPlayer.FileLocation.AbsolutePathOrURL:
					result = path;
					break;
				case MediaPlayer.FileLocation.RelativeToProjectFolder:
				case MediaPlayer.FileLocation.RelativeToStreamingAssetsFolder:
				case MediaPlayer.FileLocation.RelativeToDataFolder:
				case MediaPlayer.FileLocation.RelativeToPeristentDataFolder:
					result = Path.Combine(MediaPlayer.GetPath(location), path);
					break;
				}
			}
			return result;
		}

		private long GetPlatformFileOffset()
		{
			return 0L;
		}

		private string GetPlatformHttpHeaderJson()
		{
			string text = null;
			if (!string.IsNullOrEmpty(text))
			{
				text = text.Trim();
			}
			return text;
		}

		private string GetPlatformFilePath(Platform platform, ref string filePath, ref MediaPlayer.FileLocation fileLocation)
		{
			string empty = string.Empty;
			if (platform != Platform.Unknown)
			{
				MediaPlayer.PlatformOptions currentPlatformOptions = this.GetCurrentPlatformOptions();
				if (currentPlatformOptions != null && currentPlatformOptions.overridePath)
				{
					filePath = currentPlatformOptions.path;
					fileLocation = currentPlatformOptions.pathLocation;
				}
			}
			return MediaPlayer.GetFilePath(filePath, fileLocation);
		}

		public virtual BaseMediaPlayer CreatePlatformMediaPlayer()
		{
			BaseMediaPlayer baseMediaPlayer = null;
			if (WindowsMediaPlayer.InitialisePlatform())
			{
				baseMediaPlayer = new WindowsMediaPlayer(this._optionsWindows.videoApi, this._optionsWindows.useHardwareDecoding, this._optionsWindows.useTextureMips, this._optionsWindows.hintAlphaChannel, this._optionsWindows.useLowLatency, this._optionsWindows.forceAudioOutputDeviceName, this._optionsWindows.useUnityAudio, this._optionsWindows.forceAudioResample, this._optionsWindows.preferredFilters);
			}
			if (baseMediaPlayer == null)
			{
				Debug.LogError(string.Format("[AVProVideo] Not supported on this platform {0} {1} {2} {3}.  Using null media player!", new object[]
				{
					Application.platform,
					SystemInfo.deviceModel,
					SystemInfo.processorType,
					SystemInfo.operatingSystem
				}));
				baseMediaPlayer = new NullMediaPlayer();
			}
			return baseMediaPlayer;
		}

		private bool ForceWaitForNewFrame(int lastFrameCount, float timeoutMs)
		{
			bool result = false;
			DateTime now = DateTime.Now;
			int num = 0;
			while (this.Control != null && (DateTime.Now - now).TotalMilliseconds < (double)timeoutMs)
			{
				this.m_Player.Update();
				if (lastFrameCount != this.TextureProducer.GetTextureFrameCount())
				{
					result = true;
					break;
				}
				num++;
			}
			this.m_Player.Render();
			return result;
		}

		private void UpdateAudioFocus()
		{
			this.m_Control.SetAudioFocusEnabled(this.m_AudioFocusEnabled);
			this.m_Control.SetAudioFocusProperties(this.m_AudioFocusOffLevelDB, this.m_AudioFocusWidthDegrees);
			this.m_Control.SetAudioFocusRotation((!(this.m_AudioFocusTransform == null)) ? this.m_AudioFocusTransform.rotation : Quaternion.identity);
		}

		private void UpdateAudioHeadTransform()
		{
			if (this.m_AudioHeadTransform != null)
			{
				this.m_Control.SetAudioHeadRotation(this.m_AudioHeadTransform.rotation);
			}
			else
			{
				this.m_Control.ResetAudioHeadRotation();
			}
		}

		private void UpdateErrors()
		{
			ErrorCode lastError = this.m_Control.GetLastError();
			if (lastError != ErrorCode.None)
			{
				Debug.LogError("[AVProVideo] Error: " + Helper.GetErrorMessage(lastError));
				if (this.m_events != null)
				{
					this.m_events.Invoke(this, MediaPlayerEvent.EventType.Error, lastError);
				}
			}
		}

		private void UpdateEvents()
		{
			if (this.m_events != null && this.m_Control != null)
			{
				this.m_FinishedFrameOpenCheck = false;
				if (this.FireEventIfPossible(MediaPlayerEvent.EventType.FinishedPlaying, this.m_EventFired_FinishedPlaying))
				{
					this.m_EventFired_FinishedPlaying = !this.m_FinishedFrameOpenCheck;
				}
				if (this.m_EventFired_Started && this.m_Control != null && !this.m_Control.IsPlaying() && !this.m_Control.IsSeeking())
				{
					this.m_EventFired_Started = false;
				}
				if (this.m_EventFired_FinishedPlaying && this.m_Control != null && this.m_Control.IsPlaying() && !this.m_Control.IsFinished())
				{
					bool flag = false;
					float num = 1000f / this.m_Info.GetVideoFrameRate();
					if (this.m_Info.GetDurationMs() - this.m_Control.GetCurrentTimeMs() > num)
					{
						flag = true;
					}
					if (flag)
					{
						this.m_EventFired_FinishedPlaying = false;
					}
				}
				this.m_EventFired_MetaDataReady = this.FireEventIfPossible(MediaPlayerEvent.EventType.MetaDataReady, this.m_EventFired_MetaDataReady);
				this.m_EventFired_ReadyToPlay = this.FireEventIfPossible(MediaPlayerEvent.EventType.ReadyToPlay, this.m_EventFired_ReadyToPlay);
				this.m_EventFired_Started = this.FireEventIfPossible(MediaPlayerEvent.EventType.Started, this.m_EventFired_Started);
				this.m_EventFired_FirstFrameReady = this.FireEventIfPossible(MediaPlayerEvent.EventType.FirstFrameReady, this.m_EventFired_FirstFrameReady);
				if (this.FireEventIfPossible(MediaPlayerEvent.EventType.SubtitleChange, false))
				{
					this.m_previousSubtitleIndex = this.m_Subtitles.GetSubtitleIndex();
				}
				bool flag2 = this.m_Info.IsPlaybackStalled();
				if (flag2 != this.m_isPlaybackStalled)
				{
					this.m_isPlaybackStalled = flag2;
					MediaPlayerEvent.EventType eventType = (!this.m_isPlaybackStalled) ? MediaPlayerEvent.EventType.Unstalled : MediaPlayerEvent.EventType.Stalled;
					this.FireEventIfPossible(eventType, false);
				}
			}
		}

		private bool FireEventIfPossible(MediaPlayerEvent.EventType eventType, bool hasFired)
		{
			if (this.CanFireEvent(eventType, hasFired))
			{
				hasFired = true;
				this.m_events.Invoke(this, eventType, ErrorCode.None);
			}
			return hasFired;
		}

		private bool CanFireEvent(MediaPlayerEvent.EventType et, bool hasFired)
		{
			bool result = false;
			if (this.m_events != null && this.m_Control != null && !hasFired)
			{
				switch (et)
				{
				case MediaPlayerEvent.EventType.MetaDataReady:
					result = this.m_Control.HasMetaData();
					break;
				case MediaPlayerEvent.EventType.ReadyToPlay:
					result = (!this.m_Control.IsPlaying() && this.m_Control.CanPlay() && !this.m_AutoStart);
					break;
				case MediaPlayerEvent.EventType.Started:
					result = this.m_Control.IsPlaying();
					break;
				case MediaPlayerEvent.EventType.FirstFrameReady:
					result = (this.m_Texture != null && this.m_Control.CanPlay() && this.m_Texture.GetTextureFrameCount() > 0);
					break;
				case MediaPlayerEvent.EventType.FinishedPlaying:
					result = ((!this.m_Control.IsLooping() && this.m_Control.CanPlay() && this.m_Control.IsFinished()) || (this.m_Control.GetCurrentTimeMs() > this.m_Info.GetDurationMs() && !this.m_Control.IsLooping()));
					break;
				case MediaPlayerEvent.EventType.SubtitleChange:
					result = (this.m_previousSubtitleIndex != this.m_Subtitles.GetSubtitleIndex());
					break;
				case MediaPlayerEvent.EventType.Stalled:
					result = this.m_Info.IsPlaybackStalled();
					break;
				case MediaPlayerEvent.EventType.Unstalled:
					result = !this.m_Info.IsPlaybackStalled();
					break;
				}
			}
			return result;
		}

		private void OnApplicationFocus(bool focusStatus)
		{
		}

		private void OnApplicationPause(bool pauseStatus)
		{
		}

		[ContextMenu("Save Frame To PNG")]
		public void SaveFrameToPng()
		{
			Texture2D texture2D = this.ExtractFrame(null, -1f, true, 1000);
			if (texture2D != null)
			{
				byte[] array = texture2D.EncodeToPNG();
				if (array != null)
				{
					string str = Mathf.FloorToInt(this.Control.GetCurrentTimeMs()).ToString("D8");
					File.WriteAllBytes("frame-" + str + ".png", array);
				}
				UnityEngine.Object.Destroy(texture2D);
			}
		}

		private static Camera GetDummyCamera()
		{
			if (MediaPlayer.m_DummyCamera == null)
			{
				GameObject gameObject = GameObject.Find("AVPro Video Dummy Camera");
				if (gameObject == null)
				{
					gameObject = new GameObject("AVPro Video Dummy Camera");
					gameObject.hideFlags = (HideFlags.HideInHierarchy | HideFlags.DontSaveInEditor | HideFlags.DontSaveInBuild | HideFlags.DontUnloadUnusedAsset);
					gameObject.SetActive(false);
					UnityEngine.Object.DontDestroyOnLoad(gameObject);
					MediaPlayer.m_DummyCamera = gameObject.AddComponent<Camera>();
					MediaPlayer.m_DummyCamera.hideFlags = (HideFlags.HideInInspector | HideFlags.DontSaveInEditor | HideFlags.DontSaveInBuild | HideFlags.DontUnloadUnusedAsset);
					MediaPlayer.m_DummyCamera.cullingMask = 0;
					MediaPlayer.m_DummyCamera.clearFlags = CameraClearFlags.Nothing;
					MediaPlayer.m_DummyCamera.enabled = false;
				}
				else
				{
					MediaPlayer.m_DummyCamera = gameObject.GetComponent<Camera>();
				}
			}
			return MediaPlayer.m_DummyCamera;
		}

		private IEnumerator ExtractFrameCoroutine(Texture2D target, MediaPlayer.ProcessExtractedFrame callback, float timeSeconds = -1f, bool accurateSeek = true, int timeoutMs = 1000)
		{
			Texture2D result = target;
			Texture frame = null;
			if (this.m_Control != null)
			{
				if (timeSeconds >= 0f)
				{
					this.Pause();
					float seekTimeMs = timeSeconds * 1000f;
					if (this.TextureProducer.GetTexture(0) != null && this.m_Control.GetCurrentTimeMs() == seekTimeMs)
					{
						frame = this.TextureProducer.GetTexture(0);
					}
					else
					{
						int preSeekFrameCount = this.m_Texture.GetTextureFrameCount();
						if (accurateSeek)
						{
							this.m_Control.Seek(seekTimeMs);
						}
						else
						{
							this.m_Control.SeekFast(seekTimeMs);
						}
						if (!this.m_Control.WaitForNextFrame(MediaPlayer.GetDummyCamera(), preSeekFrameCount))
						{
							int currFc = this.TextureProducer.GetTextureFrameCount();
							int iterations = 0;
							int maxIterations = 50;
							while (currFc + 1 >= this.TextureProducer.GetTextureFrameCount())
							{
								int num;
								iterations = (num = iterations) + 1;
								if (num >= maxIterations)
								{
									break;
								}
								yield return null;
							}
						}
						frame = this.TextureProducer.GetTexture(0);
					}
				}
				else
				{
					frame = this.TextureProducer.GetTexture(0);
				}
			}
			if (frame != null)
			{
				result = Helper.GetReadableTexture(frame, this.TextureProducer.RequiresVerticalFlip(), Helper.GetOrientation(this.Info.GetTextureTransform()), target);
			}
			callback(result);
			yield return null;
			yield break;
		}

		public void ExtractFrameAsync(Texture2D target, MediaPlayer.ProcessExtractedFrame callback, float timeSeconds = -1f, bool accurateSeek = true, int timeoutMs = 1000)
		{
			base.StartCoroutine(this.ExtractFrameCoroutine(target, callback, timeSeconds, accurateSeek, timeoutMs));
		}

		public Texture2D ExtractFrame(Texture2D target, float timeSeconds = -1f, bool accurateSeek = true, int timeoutMs = 1000)
		{
			Texture2D result = target;
			Texture texture = this.ExtractFrame(timeSeconds, accurateSeek, timeoutMs);
			if (texture != null)
			{
				result = Helper.GetReadableTexture(texture, this.TextureProducer.RequiresVerticalFlip(), Helper.GetOrientation(this.Info.GetTextureTransform()), target);
			}
			return result;
		}

		private Texture ExtractFrame(float timeSeconds = -1f, bool accurateSeek = true, int timeoutMs = 1000)
		{
			Texture result = null;
			if (this.m_Control != null)
			{
				if (timeSeconds >= 0f)
				{
					this.Pause();
					float num = timeSeconds * 1000f;
					if (this.TextureProducer.GetTexture(0) != null && this.m_Control.GetCurrentTimeMs() == num)
					{
						result = this.TextureProducer.GetTexture(0);
					}
					else
					{
						int textureFrameCount = this.TextureProducer.GetTextureFrameCount();
						if (accurateSeek)
						{
							this.m_Control.Seek(num);
						}
						else
						{
							this.m_Control.SeekFast(num);
						}
						this.ForceWaitForNewFrame(textureFrameCount, (float)timeoutMs);
						result = this.TextureProducer.GetTexture(0);
					}
				}
				else
				{
					result = this.TextureProducer.GetTexture(0);
				}
			}
			return result;
		}

		public void SetGuiPositionFromVideoIndex(int index)
		{
			this.m_GuiPositionX = Mathf.FloorToInt(15f + (float)(180 * index) * 1.5f);
		}

		public void SetDebugGuiEnabled(bool bEnabled)
		{
			this.m_DebugGui = bEnabled;
		}

		private void OnGUI()
		{
			if (this.m_Info != null && this.m_DebugGui)
			{
				GUI.depth = -1000;
				GUI.matrix = Matrix4x4.TRS(new Vector3((float)this.m_GuiPositionX, 10f, 0f), Quaternion.identity, new Vector3(1.5f, 1.5f, 1f));
				GUILayout.BeginVertical("box", new GUILayoutOption[]
				{
					GUILayout.MaxWidth(180f)
				});
				GUILayout.Label(Path.GetFileName(this.m_VideoPath), new GUILayoutOption[0]);
				GUILayout.Label(string.Concat(new object[]
				{
					"Dimensions: ",
					this.m_Info.GetVideoWidth(),
					"x",
					this.m_Info.GetVideoHeight(),
					"@",
					this.m_Info.GetVideoFrameRate().ToString("F2")
				}), new GUILayoutOption[0]);
				GUILayout.Label(string.Concat(new string[]
				{
					"Time: ",
					(this.m_Control.GetCurrentTimeMs() * 0.001f).ToString("F1"),
					"s / ",
					(this.m_Info.GetDurationMs() * 0.001f).ToString("F1"),
					"s"
				}), new GUILayoutOption[0]);
				GUILayout.Label("Rate: " + this.m_Info.GetVideoDisplayRate().ToString("F2") + "Hz", new GUILayoutOption[0]);
				if (this.m_Resample && this.m_Resampler != null)
				{
					GUILayout.BeginVertical(new GUILayoutOption[0]);
					GUILayout.Label("Resampler Info:", new GUILayoutOption[0]);
					GUILayout.Label("Resampler timestamp: " + this.m_Resampler.TextureTimeStamp, new GUILayoutOption[0]);
					GUILayout.Label("Resampler frames dropped: " + this.m_Resampler.DroppedFrames, new GUILayoutOption[0]);
					GUILayout.Label("Resampler frame displayed timer: " + this.m_Resampler.FrameDisplayedTimer, new GUILayoutOption[0]);
					GUILayout.EndVertical();
				}
				if (this.TextureProducer != null && this.TextureProducer.GetTexture(0) != null)
				{
					GUILayout.BeginHorizontal(new GUILayoutOption[0]);
					Rect rect = GUILayoutUtility.GetRect(32f, 32f);
					GUILayout.Space(8f);
					Rect rect2 = GUILayoutUtility.GetRect(32f, 32f);
					Matrix4x4 matrix = GUI.matrix;
					if (this.TextureProducer.RequiresVerticalFlip())
					{
						GUIUtility.ScaleAroundPivot(new Vector2(1f, -1f), new Vector2(0f, rect.y + rect.height / 2f));
					}
					GUI.DrawTexture(rect, this.TextureProducer.GetTexture(0), ScaleMode.ScaleToFit, false);
					GUI.DrawTexture(rect2, this.TextureProducer.GetTexture(0), ScaleMode.ScaleToFit, true);
					GUI.matrix = matrix;
					GUILayout.FlexibleSpace();
					GUILayout.EndHorizontal();
				}
				if (this.m_DebugGuiControls)
				{
					GUILayout.BeginHorizontal(new GUILayoutOption[0]);
					if (this.m_Control.IsPaused())
					{
						if (GUILayout.Button("Play", new GUILayoutOption[]
						{
							GUILayout.Width(50f)
						}))
						{
							this.m_Control.Play();
						}
					}
					else if (GUILayout.Button("Pause", new GUILayoutOption[]
					{
						GUILayout.Width(50f)
					}))
					{
						this.m_Control.Pause();
					}
					float durationMs = this.m_Info.GetDurationMs();
					float currentTimeMs = this.m_Control.GetCurrentTimeMs();
					float num = GUILayout.HorizontalSlider(currentTimeMs, 0f, durationMs, new GUILayoutOption[0]);
					if (num != currentTimeMs)
					{
						this.m_Control.Seek(num);
					}
					GUILayout.EndHorizontal();
				}
				GUILayout.EndVertical();
			}
		}

		public MediaPlayer.FileLocation m_VideoLocation = MediaPlayer.FileLocation.RelativeToStreamingAssetsFolder;

		public string m_VideoPath;

		public bool m_AutoOpen = true;

		public bool m_AutoStart = true;

		public bool m_Loop;

		[Range(0f, 1f)]
		public float m_Volume = 1f;

		[SerializeField]
		[Range(-1f, 1f)]
		private float m_Balance;

		public bool m_Muted;

		[SerializeField]
		[Range(-4f, 4f)]
		public float m_PlaybackRate = 1f;

		public bool m_Resample;

		public Resampler.ResampleMode m_ResampleMode;

		[Range(3f, 10f)]
		public int m_ResampleBufferSize = 5;

		private Resampler m_Resampler;

		[SerializeField]
		private bool m_DebugGui;

		[SerializeField]
		private bool m_DebugGuiControls = true;

		[SerializeField]
		private bool m_Persistent;

		public StereoPacking m_StereoPacking;

		public AlphaPacking m_AlphaPacking;

		public bool m_DisplayDebugStereoColorTint;

		public FilterMode m_FilterMode = FilterMode.Bilinear;

		public TextureWrapMode m_WrapMode = TextureWrapMode.Clamp;

		[Range(0f, 16f)]
		public int m_AnisoLevel;

		[SerializeField]
		private bool m_LoadSubtitles;

		[SerializeField]
		private MediaPlayer.FileLocation m_SubtitleLocation = MediaPlayer.FileLocation.RelativeToStreamingAssetsFolder;

		private MediaPlayer.FileLocation m_queueSubtitleLocation;

		[SerializeField]
		private string m_SubtitlePath;

		private string m_queueSubtitlePath;

		private Coroutine m_loadSubtitlesRoutine;

		[SerializeField]
		private Transform m_AudioHeadTransform;

		[SerializeField]
		private bool m_AudioFocusEnabled;

		[SerializeField]
		private Transform m_AudioFocusTransform;

		[SerializeField]
		[Range(40f, 120f)]
		private float m_AudioFocusWidthDegrees = 90f;

		[SerializeField]
		[Range(-24f, 0f)]
		private float m_AudioFocusOffLevelDB;

		[SerializeField]
		private MediaPlayerEvent m_events;

		private IMediaControl m_Control;

		private IMediaProducer m_Texture;

		private IMediaInfo m_Info;

		private IMediaPlayer m_Player;

		private IMediaSubtitles m_Subtitles;

		private IDisposable m_Dispose;

		private bool m_VideoOpened;

		private bool m_AutoStartTriggered;

		private bool m_WasPlayingOnPause;

		private Coroutine _renderingCoroutine;

		private const int s_GuiDepth = -1000;

		private const float s_GuiScale = 1.5f;

		private const int s_GuiStartWidth = 10;

		private const int s_GuiWidth = 180;

		private int m_GuiPositionX = 10;

		private static bool s_GlobalStartup;

		private bool m_EventFired_ReadyToPlay;

		private bool m_EventFired_Started;

		private bool m_EventFired_FirstFrameReady;

		private bool m_EventFired_FinishedPlaying;

		private bool m_EventFired_MetaDataReady;

		private int m_previousSubtitleIndex = -1;

		private bool m_isPlaybackStalled;

		private static Camera m_DummyCamera;

		private bool m_FinishedFrameOpenCheck;

		[SerializeField]
		private MediaPlayer.OptionsWindows _optionsWindows = new MediaPlayer.OptionsWindows();

		[SerializeField]
		private MediaPlayer.OptionsMacOSX _optionsMacOSX = new MediaPlayer.OptionsMacOSX();

		[SerializeField]
		private MediaPlayer.OptionsIOS _optionsIOS = new MediaPlayer.OptionsIOS();

		[SerializeField]
		private MediaPlayer.OptionsTVOS _optionsTVOS = new MediaPlayer.OptionsTVOS();

		[SerializeField]
		private MediaPlayer.OptionsAndroid _optionsAndroid = new MediaPlayer.OptionsAndroid();

		[SerializeField]
		private MediaPlayer.OptionsWindowsPhone _optionsWindowsPhone = new MediaPlayer.OptionsWindowsPhone();

		[SerializeField]
		private MediaPlayer.OptionsWindowsUWP _optionsWindowsUWP = new MediaPlayer.OptionsWindowsUWP();

		[SerializeField]
		private MediaPlayer.OptionsWebGL _optionsWebGL = new MediaPlayer.OptionsWebGL();

		[SerializeField]
		private MediaPlayer.OptionsPS4 _optionsPS4 = new MediaPlayer.OptionsPS4();

		[Serializable]
		public class Setup
		{
			public bool displayDebugGUI;

			public bool persistent;
		}

		public enum FileLocation
		{
			AbsolutePathOrURL,
			RelativeToProjectFolder,
			RelativeToStreamingAssetsFolder,
			RelativeToDataFolder,
			RelativeToPeristentDataFolder
		}

		[Serializable]
		public class PlatformOptions
		{
			public virtual bool IsModified()
			{
				return this.overridePath;
			}

			public bool overridePath;

			public MediaPlayer.FileLocation pathLocation = MediaPlayer.FileLocation.RelativeToStreamingAssetsFolder;

			public string path;
		}

		[Serializable]
		public class OptionsWindows : MediaPlayer.PlatformOptions
		{
			public override bool IsModified()
			{
				return base.IsModified() || !this.useHardwareDecoding || this.useTextureMips || this.hintAlphaChannel || this.useLowLatency || this.useUnityAudio || this.videoApi != Windows.VideoApi.MediaFoundation || !this.forceAudioResample || this.enableAudio360 || this.audio360ChannelMode != Audio360ChannelMode.TBE_8_2 || !string.IsNullOrEmpty(this.forceAudioOutputDeviceName) || this.preferredFilters.Count != 0;
			}

			public Windows.VideoApi videoApi;

			public bool useHardwareDecoding = true;

			public bool useUnityAudio;

			public bool forceAudioResample = true;

			public bool useTextureMips;

			public bool hintAlphaChannel;

			public bool useLowLatency;

			public string forceAudioOutputDeviceName = string.Empty;

			public List<string> preferredFilters = new List<string>();

			public bool enableAudio360;

			public Audio360ChannelMode audio360ChannelMode;
		}

		[Serializable]
		public class OptionsMacOSX : MediaPlayer.PlatformOptions
		{
			public override bool IsModified()
			{
				return base.IsModified() || !string.IsNullOrEmpty(this.httpHeaderJson);
			}

			[Multiline]
			public string httpHeaderJson;
		}

		[Serializable]
		public class OptionsIOS : MediaPlayer.PlatformOptions
		{
			public override bool IsModified()
			{
				return base.IsModified() || !string.IsNullOrEmpty(this.httpHeaderJson) || !this.useYpCbCr420Textures;
			}

			public bool useYpCbCr420Textures = true;

			[Multiline]
			public string httpHeaderJson;
		}

		[Serializable]
		public class OptionsTVOS : MediaPlayer.PlatformOptions
		{
			public override bool IsModified()
			{
				return base.IsModified() || !string.IsNullOrEmpty(this.httpHeaderJson) || !this.useYpCbCr420Textures;
			}

			public bool useYpCbCr420Textures = true;

			[Multiline]
			public string httpHeaderJson;
		}

		[Serializable]
		public class OptionsAndroid : MediaPlayer.PlatformOptions
		{
			public override bool IsModified()
			{
				return base.IsModified() || this.fileOffset != 0 || this.useFastOesPath || this.showPosterFrame || this.videoApi != Android.VideoApi.MediaPlayer || !string.IsNullOrEmpty(this.httpHeaderJson) || this.enableAudio360 || this.audio360ChannelMode != Audio360ChannelMode.TBE_8_2;
			}

			public Android.VideoApi videoApi = Android.VideoApi.MediaPlayer;

			public bool useFastOesPath;

			public bool showPosterFrame;

			public bool enableAudio360;

			public Audio360ChannelMode audio360ChannelMode;

			[Multiline]
			public string httpHeaderJson;

			[SerializeField]
			[Tooltip("Byte offset into the file where the media file is located.  This is useful when hiding or packing media files within another file.")]
			public int fileOffset;
		}

		[Serializable]
		public class OptionsWindowsPhone : MediaPlayer.PlatformOptions
		{
			public override bool IsModified()
			{
				return base.IsModified() || !this.useHardwareDecoding || this.useTextureMips || this.useLowLatency || this.useUnityAudio || !this.forceAudioResample;
			}

			public bool useHardwareDecoding = true;

			public bool useUnityAudio;

			public bool forceAudioResample = true;

			public bool useTextureMips;

			public bool useLowLatency;
		}

		[Serializable]
		public class OptionsWindowsUWP : MediaPlayer.PlatformOptions
		{
			public override bool IsModified()
			{
				return base.IsModified() || !this.useHardwareDecoding || this.useTextureMips || this.useLowLatency || this.useUnityAudio || !this.forceAudioResample;
			}

			public bool useHardwareDecoding = true;

			public bool useUnityAudio;

			public bool forceAudioResample = true;

			public bool useTextureMips;

			public bool useLowLatency;
		}

		[Serializable]
		public class OptionsWebGL : MediaPlayer.PlatformOptions
		{
		}

		[Serializable]
		public class OptionsPS4 : MediaPlayer.PlatformOptions
		{
		}

		public delegate void ProcessExtractedFrame(Texture2D extractedFrame);
	}
}
