using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;

namespace RenderHeads.Media.AVProVideo
{
	public class WindowsMediaPlayer : BaseMediaPlayer
	{
		public WindowsMediaPlayer(Windows.VideoApi videoApi, bool useHardwareDecoding, bool useTextureMips, bool hintAlphaChannel, bool useLowLatency, string audioDeviceOutputName, bool useUnityAudio, bool forceResample, List<string> preferredFilters)
		{
			this.SetOptions(videoApi, useHardwareDecoding, useTextureMips, hintAlphaChannel, useLowLatency, audioDeviceOutputName, useUnityAudio, forceResample, preferredFilters);
		}

		public static bool InitialisePlatform()
		{
			if (!WindowsMediaPlayer._isInitialised)
			{
				try
				{
					if (!WindowsMediaPlayer.Native.Init(QualitySettings.activeColorSpace == ColorSpace.Linear, true))
					{
						Debug.LogError("[AVProVideo] Failing to initialise platform");
					}
					else
					{
						WindowsMediaPlayer._isInitialised = true;
						WindowsMediaPlayer._version = WindowsMediaPlayer.GetPluginVersion();
						WindowsMediaPlayer._nativeFunction_UpdateAllTextures = WindowsMediaPlayer.Native.GetRenderEventFunc_UpdateAllTextures();
						WindowsMediaPlayer._nativeFunction_FreeTextures = WindowsMediaPlayer.Native.GetRenderEventFunc_FreeTextures();
						WindowsMediaPlayer._nativeFunction_ExtractFrame = WindowsMediaPlayer.Native.GetRenderEventFunc_WaitForNewFrame();
					}
				}
				catch (DllNotFoundException ex)
				{
					Debug.LogError("[AVProVideo] Failed to load DLL. " + ex.Message);
				}
			}
			return WindowsMediaPlayer._isInitialised;
		}

		public static void DeinitPlatform()
		{
			WindowsMediaPlayer.Native.Deinit();
			WindowsMediaPlayer._isInitialised = false;
		}

		public override int GetNumAudioChannels()
		{
			return WindowsMediaPlayer.Native.GetAudioChannelCount(this._instance);
		}

		public void SetOptions(Windows.VideoApi videoApi, bool useHardwareDecoding, bool useTextureMips, bool hintAlphaChannel, bool useLowLatency, string audioDeviceOutputName, bool useUnityAudio, bool forceResample, List<string> preferredFilters)
		{
			this._videoApi = videoApi;
			this._useHardwareDecoding = useHardwareDecoding;
			this._useTextureMips = useTextureMips;
			this._hintAlphaChannel = hintAlphaChannel;
			this._useLowLatency = useLowLatency;
			this._audioDeviceOutputName = audioDeviceOutputName;
			if (!string.IsNullOrEmpty(this._audioDeviceOutputName))
			{
				this._audioDeviceOutputName = this._audioDeviceOutputName.Trim();
			}
			this._useUnityAudio = useUnityAudio;
			this._forceAudioResample = forceResample;
			this._preferredFilters = preferredFilters;
			if (this._preferredFilters != null)
			{
				for (int i = 0; i < this._preferredFilters.Count; i++)
				{
					if (!string.IsNullOrEmpty(this._preferredFilters[i]))
					{
						this._preferredFilters[i] = this._preferredFilters[i].Trim();
					}
				}
			}
		}

		public override string GetVersion()
		{
			return WindowsMediaPlayer._version;
		}

		public override bool OpenVideoFromFile(string path, long offset, string httpHeaderJson)
		{
			this.CloseVideo();
			uint numFilters = 0u;
			IntPtr[] array = null;
			if (this._preferredFilters != null && this._preferredFilters.Count > 0)
			{
				numFilters = (uint)this._preferredFilters.Count;
				array = new IntPtr[this._preferredFilters.Count];
				for (int i = 0; i < array.Length; i++)
				{
					array[i] = Marshal.StringToHGlobalUni(this._preferredFilters[i]);
				}
			}
			this._instance = WindowsMediaPlayer.Native.OpenSource(this._instance, path, (int)this._videoApi, this._useHardwareDecoding, this._useTextureMips, this._hintAlphaChannel, this._useLowLatency, this._audioDeviceOutputName, this._useUnityAudio, this._forceAudioResample, AudioSettings.outputSampleRate, array, numFilters, (int)this._audioChannelMode);
			if (array != null)
			{
				for (int j = 0; j < array.Length; j++)
				{
					Marshal.FreeHGlobal(array[j]);
				}
			}
			if (this._instance == IntPtr.Zero)
			{
				this.DisplayLoadFailureSuggestion(path);
				return false;
			}
			WindowsMediaPlayer.Native.SetUnityAudioEnabled(this._instance, this._useUnityAudio);
			return true;
		}

		public override bool OpenVideoFromBuffer(byte[] buffer)
		{
			this.CloseVideo();
			IntPtr[] array;
			if (this._preferredFilters.Count == 0)
			{
				array = null;
			}
			else
			{
				array = new IntPtr[this._preferredFilters.Count];
				for (int i = 0; i < array.Length; i++)
				{
					array[i] = Marshal.StringToHGlobalUni(this._preferredFilters[i]);
				}
			}
			this._instance = WindowsMediaPlayer.Native.OpenSourceFromBuffer(this._instance, buffer, (ulong)((long)buffer.Length), (int)this._videoApi, this._useHardwareDecoding, this._useTextureMips, this._hintAlphaChannel, this._useLowLatency, this._audioDeviceOutputName, this._useUnityAudio, array, (uint)this._preferredFilters.Count);
			if (array != null)
			{
				for (int j = 0; j < array.Length; j++)
				{
					Marshal.FreeHGlobal(array[j]);
				}
			}
			if (this._instance == IntPtr.Zero)
			{
				return false;
			}
			WindowsMediaPlayer.Native.SetUnityAudioEnabled(this._instance, this._useUnityAudio);
			return true;
		}

		private void DisplayLoadFailureSuggestion(string path)
		{
			bool flag = this._videoApi == Windows.VideoApi.DirectShow || SystemInfo.operatingSystem.Contains("Windows 7") || SystemInfo.operatingSystem.Contains("Windows Vista") || SystemInfo.operatingSystem.Contains("Windows XP");
			if (flag && path.Contains(".mp4"))
			{
				Debug.LogWarning("[AVProVideo] The native Windows DirectShow H.264 decoder doesn't support videos with resolution above 1920x1080. You may need to reduce your video resolution, switch to another codec (such as DivX or Hap), or install 3rd party DirectShow codec (eg LAV Filters).  This shouldn't be a problem for Windows 8 and above as it has a native limitation of 3840x2160.");
			}
		}

		public override void CloseVideo()
		{
			this._width = 0;
			this._height = 0;
			this._frameRate = 0f;
			this._hasAudio = (this._hasVideo = false);
			this._hasMetaData = false;
			this._canPlay = false;
			this._isPaused = false;
			this._isPlaying = false;
			this._bLoop = false;
			this._audioMuted = false;
			this._volume = 1f;
			this._balance = 0f;
			this._lastFrameCount = 0;
			this._displayRate = 0f;
			this._displayRateTimer = 0f;
			this._queueSetAudioTrackIndex = -1;
			this._supportsLinearColorSpace = true;
			this._lastError = ErrorCode.None;
			this._nativeTexture = IntPtr.Zero;
			if (this._texture != null)
			{
				UnityEngine.Object.Destroy(this._texture);
				this._texture = null;
			}
			if (this._instance != IntPtr.Zero)
			{
				WindowsMediaPlayer.Native.CloseSource(this._instance);
				this._instance = IntPtr.Zero;
			}
			WindowsMediaPlayer.IssueRenderThreadEvent(WindowsMediaPlayer.Native.RenderThreadEvent.FreeTextures);
		}

		public override void SetLooping(bool looping)
		{
			this._bLoop = looping;
			WindowsMediaPlayer.Native.SetLooping(this._instance, looping);
		}

		public override bool IsLooping()
		{
			return this._bLoop;
		}

		public override bool HasMetaData()
		{
			return this._hasMetaData;
		}

		public override bool HasAudio()
		{
			return this._hasAudio;
		}

		public override bool HasVideo()
		{
			return this._hasVideo;
		}

		public override bool CanPlay()
		{
			return this._canPlay;
		}

		public override void Play()
		{
			this._isPlaying = true;
			this._isPaused = false;
			WindowsMediaPlayer.Native.Play(this._instance);
		}

		public override void Pause()
		{
			this._isPlaying = false;
			this._isPaused = true;
			WindowsMediaPlayer.Native.Pause(this._instance);
		}

		public override void Stop()
		{
			this._isPlaying = false;
			this._isPaused = false;
			WindowsMediaPlayer.Native.Pause(this._instance);
		}

		public override bool IsSeeking()
		{
			return WindowsMediaPlayer.Native.IsSeeking(this._instance);
		}

		public override bool IsPlaying()
		{
			return this._isPlaying;
		}

		public override bool IsPaused()
		{
			return this._isPaused;
		}

		public override bool IsFinished()
		{
			return WindowsMediaPlayer.Native.IsFinished(this._instance);
		}

		public override bool IsBuffering()
		{
			return WindowsMediaPlayer.Native.IsBuffering(this._instance);
		}

		public override float GetDurationMs()
		{
			return WindowsMediaPlayer.Native.GetDuration(this._instance) * 1000f;
		}

		public override int GetVideoWidth()
		{
			return this._width;
		}

		public override int GetVideoHeight()
		{
			return this._height;
		}

		public override float GetVideoFrameRate()
		{
			return this._frameRate;
		}

		public override float GetVideoDisplayRate()
		{
			return this._displayRate;
		}

		public override Texture GetTexture(int index)
		{
			Texture result = null;
			if (WindowsMediaPlayer.Native.GetTextureFrameCount(this._instance) > 0)
			{
				result = this._texture;
			}
			return result;
		}

		public override int GetTextureFrameCount()
		{
			return WindowsMediaPlayer.Native.GetTextureFrameCount(this._instance);
		}

		public override long GetTextureTimeStamp()
		{
			return WindowsMediaPlayer.Native.GetTextureTimeStamp(this._instance);
		}

		public override bool RequiresVerticalFlip()
		{
			return this._isTextureTopDown;
		}

		public override void Rewind()
		{
			this.Seek(0f);
		}

		public override void Seek(float timeMs)
		{
			WindowsMediaPlayer.Native.SetCurrentTime(this._instance, timeMs / 1000f, false);
		}

		public override void SeekFast(float timeMs)
		{
			WindowsMediaPlayer.Native.SetCurrentTime(this._instance, timeMs / 1000f, true);
		}

		public override float GetCurrentTimeMs()
		{
			return WindowsMediaPlayer.Native.GetCurrentTime(this._instance) * 1000f;
		}

		public override void SetPlaybackRate(float rate)
		{
			WindowsMediaPlayer.Native.SetPlaybackRate(this._instance, rate);
		}

		public override float GetPlaybackRate()
		{
			return WindowsMediaPlayer.Native.GetPlaybackRate(this._instance);
		}

		public override float GetBufferingProgress()
		{
			return WindowsMediaPlayer.Native.GetBufferingProgress(this._instance);
		}

		public override int GetBufferedTimeRangeCount()
		{
			return this._bufferedTimeRangeCount;
		}

		public override bool GetBufferedTimeRange(int index, ref float startTimeMs, ref float endTimeMs)
		{
			bool result = false;
			if (index >= 0 && index < this._bufferedTimeRangeCount)
			{
				result = true;
				startTimeMs = 1000f * this._bufferedTimeRanges[index * 2];
				endTimeMs = 1000f * this._bufferedTimeRanges[index * 2 + 1];
			}
			return result;
		}

		public override void MuteAudio(bool bMuted)
		{
			this._audioMuted = bMuted;
			WindowsMediaPlayer.Native.SetMuted(this._instance, this._audioMuted);
		}

		public override bool IsMuted()
		{
			return this._audioMuted;
		}

		public override void SetVolume(float volume)
		{
			this._volume = volume;
			WindowsMediaPlayer.Native.SetVolume(this._instance, volume);
		}

		public override float GetVolume()
		{
			return this._volume;
		}

		public override void SetBalance(float balance)
		{
			this._balance = balance;
			WindowsMediaPlayer.Native.SetBalance(this._instance, balance);
		}

		public override float GetBalance()
		{
			return this._balance;
		}

		public override int GetAudioTrackCount()
		{
			return WindowsMediaPlayer.Native.GetAudioTrackCount(this._instance);
		}

		public override int GetCurrentAudioTrack()
		{
			return WindowsMediaPlayer.Native.GetAudioTrack(this._instance);
		}

		public override void SetAudioTrack(int index)
		{
			this._queueSetAudioTrackIndex = index;
		}

		public override int GetVideoTrackCount()
		{
			int result = 0;
			if (this.HasVideo())
			{
				result = 1;
			}
			return result;
		}

		public override bool IsPlaybackStalled()
		{
			return WindowsMediaPlayer.Native.IsPlaybackStalled(this._instance);
		}

		public override string GetCurrentAudioTrackId()
		{
			return string.Empty;
		}

		public override int GetCurrentAudioTrackBitrate()
		{
			return 0;
		}

		public override int GetCurrentVideoTrack()
		{
			return 0;
		}

		public override void SetVideoTrack(int index)
		{
		}

		public override string GetCurrentVideoTrackId()
		{
			return string.Empty;
		}

		public override int GetCurrentVideoTrackBitrate()
		{
			return 0;
		}

		public override bool WaitForNextFrame(Camera dummyCamera, int previousFrameCount)
		{
			WindowsMediaPlayer.Native.StartExtractFrame(this._instance);
			WindowsMediaPlayer.IssueRenderThreadEvent(WindowsMediaPlayer.Native.RenderThreadEvent.WaitForNewFrame);
			dummyCamera.Render();
			WindowsMediaPlayer.Native.WaitForExtract(this._instance);
			return previousFrameCount != WindowsMediaPlayer.Native.GetTextureFrameCount(this._instance);
		}

		public override void SetAudioChannelMode(Audio360ChannelMode channelMode)
		{
			this._audioChannelMode = channelMode;
			WindowsMediaPlayer.Native.SetAudioChannelMode(this._instance, (int)channelMode);
		}

		public override void SetAudioHeadRotation(Quaternion q)
		{
			WindowsMediaPlayer.Native.SetHeadOrientation(this._instance, q.x, q.y, q.z, q.w);
		}

		public override void ResetAudioHeadRotation()
		{
			WindowsMediaPlayer.Native.SetHeadOrientation(this._instance, Quaternion.identity.x, Quaternion.identity.y, Quaternion.identity.z, Quaternion.identity.w);
		}

		public override void SetAudioFocusEnabled(bool enabled)
		{
			WindowsMediaPlayer.Native.SetAudioFocusEnabled(this._instance, enabled);
		}

		public override void SetAudioFocusProperties(float offFocusLevel, float widthDegrees)
		{
			WindowsMediaPlayer.Native.SetAudioFocusProps(this._instance, offFocusLevel, widthDegrees);
		}

		public override void SetAudioFocusRotation(Quaternion q)
		{
			WindowsMediaPlayer.Native.SetAudioFocusRotation(this._instance, q.x, q.y, q.z, q.w);
		}

		public override void ResetAudioFocus()
		{
			WindowsMediaPlayer.Native.SetAudioFocusEnabled(this._instance, false);
			WindowsMediaPlayer.Native.SetAudioFocusProps(this._instance, 0f, 90f);
			WindowsMediaPlayer.Native.SetAudioFocusRotation(this._instance, 0f, 0f, 0f, 1f);
		}

		public override void Update()
		{
			WindowsMediaPlayer.Native.Update(this._instance);
			this._lastError = (ErrorCode)WindowsMediaPlayer.Native.GetLastErrorCode(this._instance);
			if (this._queueSetAudioTrackIndex >= 0 && this._hasAudio)
			{
				WindowsMediaPlayer.Native.SetAudioTrack(this._instance, this._queueSetAudioTrackIndex);
				this._queueSetAudioTrackIndex = -1;
			}
			this._bufferedTimeRangeCount = WindowsMediaPlayer.Native.GetBufferedRanges(this._instance, this._bufferedTimeRanges, this._bufferedTimeRanges.Length / 2);
			if (this._bufferedTimeRangeCount > this._bufferedTimeRanges.Length / 2)
			{
				this._bufferedTimeRanges = new float[this._bufferedTimeRangeCount * 2];
				this._bufferedTimeRangeCount = WindowsMediaPlayer.Native.GetBufferedRanges(this._instance, this._bufferedTimeRanges, this._bufferedTimeRanges.Length / 2);
			}
			this.UpdateSubtitles();
			if (!this._canPlay)
			{
				if (!this._hasMetaData && WindowsMediaPlayer.Native.HasMetaData(this._instance))
				{
					if (WindowsMediaPlayer.Native.HasVideo(this._instance))
					{
						this._width = WindowsMediaPlayer.Native.GetWidth(this._instance);
						this._height = WindowsMediaPlayer.Native.GetHeight(this._instance);
						this._frameRate = WindowsMediaPlayer.Native.GetFrameRate(this._instance);
						if (this._width > 0 && this._height > 0)
						{
							this._hasVideo = true;
							if (Mathf.Max(this._width, this._height) > SystemInfo.maxTextureSize)
							{
								Debug.LogError(string.Format("[AVProVideo] Video dimensions ({0}x{1}) larger than maxTextureSize ({2} for current build target)", this._width, this._height, SystemInfo.maxTextureSize));
								this._width = (this._height = 0);
								this._hasVideo = false;
							}
						}
						if (this._hasVideo && WindowsMediaPlayer.Native.HasAudio(this._instance))
						{
							this._hasAudio = true;
						}
					}
					else if (WindowsMediaPlayer.Native.HasAudio(this._instance))
					{
						this._hasAudio = true;
					}
					if (this._hasVideo || this._hasAudio)
					{
						this._hasMetaData = true;
					}
					this._playerDescription = Marshal.PtrToStringAnsi(WindowsMediaPlayer.Native.GetPlayerDescription(this._instance));
					this._supportsLinearColorSpace = !this._playerDescription.Contains("MF-MediaEngine-Hardware");
					Helper.LogInfo(string.Concat(new object[]
					{
						"Using playback path: ",
						this._playerDescription,
						" (",
						this._width,
						"x",
						this._height,
						"@",
						this.GetVideoFrameRate().ToString("F2"),
						")"
					}), null);
					if (this._hasVideo)
					{
						this.OnTextureSizeChanged();
					}
				}
				if (this._hasMetaData)
				{
					this._canPlay = WindowsMediaPlayer.Native.CanPlay(this._instance);
				}
			}
			if (this._hasVideo)
			{
				IntPtr texturePointer = WindowsMediaPlayer.Native.GetTexturePointer(this._instance);
				if (this._texture != null && this._nativeTexture != IntPtr.Zero && this._nativeTexture != texturePointer)
				{
					this._width = WindowsMediaPlayer.Native.GetWidth(this._instance);
					this._height = WindowsMediaPlayer.Native.GetHeight(this._instance);
					if (texturePointer == IntPtr.Zero || this._width != this._texture.width || this._height != this._texture.height)
					{
						if (this._width != this._texture.width || this._height != this._texture.height)
						{
							Helper.LogInfo(string.Concat(new object[]
							{
								"Texture size changed: ",
								this._width,
								" X ",
								this._height
							}), null);
							this.OnTextureSizeChanged();
						}
						this._nativeTexture = IntPtr.Zero;
						UnityEngine.Object.Destroy(this._texture);
						this._texture = null;
					}
					else if (this._nativeTexture != texturePointer)
					{
						this._texture.UpdateExternalTexture(texturePointer);
						this._nativeTexture = texturePointer;
					}
				}
				if (this._textureQuality != QualitySettings.masterTextureLimit)
				{
					if (this._texture != null && this._nativeTexture != IntPtr.Zero && this._texture.GetNativeTexturePtr() == IntPtr.Zero)
					{
						this._texture.UpdateExternalTexture(this._nativeTexture);
					}
					this._textureQuality = QualitySettings.masterTextureLimit;
				}
				if (this._texture == null && this._width > 0 && this._height > 0 && texturePointer != IntPtr.Zero)
				{
					this._isTextureTopDown = WindowsMediaPlayer.Native.IsTextureTopDown(this._instance);
					this._texture = Texture2D.CreateExternalTexture(this._width, this._height, TextureFormat.RGBA32, this._useTextureMips, false, texturePointer);
					if (this._texture != null)
					{
						this._texture.name = "AVProVideo";
						this._nativeTexture = texturePointer;
						this.ApplyTextureProperties(this._texture);
					}
					else
					{
						Debug.LogError("[AVProVideo] Failed to create texture");
					}
				}
			}
		}

		private void OnTextureSizeChanged()
		{
			if ((this._width == 720 || this._height == 480) && this._playerDescription.Contains("DirectShow"))
			{
				Debug.LogWarning("[AVProVideo] If video fails to play then it may be due to the resolution being higher than 1920x1080 which is the limitation of the Microsoft DirectShow H.264 decoder.\nTo resolve this you can either use Windows 8 or above (and disable 'Force DirectShow' option), resize your video, use a different codec (such as Hap or DivX), or install a 3rd party H.264 decoder such as LAV Filters.");
			}
			else if ((this._width <= 1920 && this._height <= 1080) || this._playerDescription.Contains("MF-MediaEngine-Software"))
			{
			}
		}

		private void UpdateDisplayFrameRate()
		{
			this._displayRateTimer += Time.deltaTime;
			if (this._displayRateTimer >= 0.5f)
			{
				int textureFrameCount = WindowsMediaPlayer.Native.GetTextureFrameCount(this._instance);
				this._displayRate = (float)(textureFrameCount - this._lastFrameCount) / this._displayRateTimer;
				this._displayRateTimer -= 0.5f;
				if (this._displayRateTimer >= 0.5f)
				{
					this._displayRateTimer = 0f;
				}
				this._lastFrameCount = textureFrameCount;
			}
		}

		public override void Render()
		{
			this.UpdateDisplayFrameRate();
			WindowsMediaPlayer.IssueRenderThreadEvent(WindowsMediaPlayer.Native.RenderThreadEvent.UpdateAllTextures);
		}

		public override void Dispose()
		{
			this.CloseVideo();
		}

		public override void GrabAudio(float[] buffer, int floatCount, int channelCount)
		{
			WindowsMediaPlayer.Native.GrabAudio(this._instance, buffer, floatCount, channelCount);
		}

		public override bool PlayerSupportsLinearColorSpace()
		{
			return this._supportsLinearColorSpace;
		}

		private static void IssueRenderThreadEvent(WindowsMediaPlayer.Native.RenderThreadEvent renderEvent)
		{
			if (renderEvent == WindowsMediaPlayer.Native.RenderThreadEvent.UpdateAllTextures)
			{
				GL.IssuePluginEvent(WindowsMediaPlayer._nativeFunction_UpdateAllTextures, 0);
			}
			else if (renderEvent == WindowsMediaPlayer.Native.RenderThreadEvent.FreeTextures)
			{
				GL.IssuePluginEvent(WindowsMediaPlayer._nativeFunction_FreeTextures, 0);
			}
			else if (renderEvent == WindowsMediaPlayer.Native.RenderThreadEvent.WaitForNewFrame)
			{
				GL.IssuePluginEvent(WindowsMediaPlayer._nativeFunction_ExtractFrame, 0);
			}
		}

		private static string GetPluginVersion()
		{
			return Marshal.PtrToStringAnsi(WindowsMediaPlayer.Native.GetPluginVersion());
		}

		public override void OnEnable()
		{
			base.OnEnable();
			if (this._texture != null && this._nativeTexture != IntPtr.Zero && this._texture.GetNativeTexturePtr() == IntPtr.Zero)
			{
				this._texture.UpdateExternalTexture(this._nativeTexture);
			}
			this._textureQuality = QualitySettings.masterTextureLimit;
		}

		private bool _forceAudioResample = true;

		private bool _useUnityAudio;

		private string _audioDeviceOutputName = string.Empty;

		private List<string> _preferredFilters = new List<string>();

		private Audio360ChannelMode _audioChannelMode;

		private bool _isPlaying;

		private bool _isPaused;

		private bool _audioMuted;

		private float _volume = 1f;

		private float _balance;

		private bool _bLoop;

		private bool _canPlay;

		private bool _hasMetaData;

		private int _width;

		private int _height;

		private float _frameRate;

		private bool _hasAudio;

		private bool _hasVideo;

		private bool _isTextureTopDown = true;

		private IntPtr _nativeTexture = IntPtr.Zero;

		private Texture2D _texture;

		private IntPtr _instance = IntPtr.Zero;

		private float _displayRateTimer;

		private int _lastFrameCount;

		private float _displayRate = 1f;

		private Windows.VideoApi _videoApi;

		private bool _useHardwareDecoding = true;

		private bool _useTextureMips;

		private bool _hintAlphaChannel;

		private bool _useLowLatency;

		private int _queueSetAudioTrackIndex = -1;

		private bool _supportsLinearColorSpace = true;

		private int _bufferedTimeRangeCount;

		private float[] _bufferedTimeRanges = new float[0];

		private static bool _isInitialised;

		private static string _version = "Plug-in not yet initialised";

		private static IntPtr _nativeFunction_UpdateAllTextures;

		private static IntPtr _nativeFunction_FreeTextures;

		private static IntPtr _nativeFunction_ExtractFrame;

		private int _textureQuality = QualitySettings.masterTextureLimit;

		private struct Native
		{
			[DllImport("AVProVideo")]
			public static extern bool Init(bool linearColorSpace, bool isD3D11NoSingleThreaded);

			[DllImport("AVProVideo")]
			public static extern void Deinit();

			[DllImport("AVProVideo")]
			public static extern IntPtr GetPluginVersion();

			[DllImport("AVProVideo")]
			public static extern bool IsTrialVersion();

			[DllImport("AVProVideo")]
			public static extern IntPtr OpenSource(IntPtr instance, [MarshalAs(UnmanagedType.LPWStr)] string path, int videoApiIndex, bool useHardwareDecoding, bool generateTextureMips, bool hintAlphaChannel, bool useLowLatency, [MarshalAs(UnmanagedType.LPWStr)] string forceAudioOutputDeviceName, bool useUnityAudio, bool forceResample, int sampleRate, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] IntPtr[] preferredFilter, uint numFilters, int audioChannelMode);

			[DllImport("AVProVideo")]
			public static extern IntPtr OpenSourceFromBuffer(IntPtr instance, byte[] buffer, ulong bufferLength, int videoApiIndex, bool useHardwareDecoding, bool generateTextureMips, bool hintAlphaChannel, bool useLowLatency, [MarshalAs(UnmanagedType.LPWStr)] string forceAudioOutputDeviceName, bool useUnityAudio, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] IntPtr[] preferredFilter, uint numFilters);

			[DllImport("AVProVideo")]
			public static extern void CloseSource(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern IntPtr GetPlayerDescription(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern int GetLastErrorCode(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern void Play(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern void Pause(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern void SetMuted(IntPtr instance, bool muted);

			[DllImport("AVProVideo")]
			public static extern void SetVolume(IntPtr instance, float volume);

			[DllImport("AVProVideo")]
			public static extern void SetBalance(IntPtr instance, float volume);

			[DllImport("AVProVideo")]
			public static extern void SetLooping(IntPtr instance, bool looping);

			[DllImport("AVProVideo")]
			public static extern bool HasVideo(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern bool HasAudio(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern int GetWidth(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern int GetHeight(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern float GetFrameRate(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern float GetDuration(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern int GetAudioTrackCount(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern bool IsPlaybackStalled(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern bool HasMetaData(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern bool CanPlay(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern bool IsSeeking(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern bool IsFinished(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern bool IsBuffering(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern float GetCurrentTime(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern void SetCurrentTime(IntPtr instance, float time, bool fast);

			[DllImport("AVProVideo")]
			public static extern float GetPlaybackRate(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern void SetPlaybackRate(IntPtr instance, float rate);

			[DllImport("AVProVideo")]
			public static extern int GetAudioTrack(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern void SetAudioTrack(IntPtr instance, int index);

			[DllImport("AVProVideo")]
			public static extern float GetBufferingProgress(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern int GetBufferedRanges(IntPtr instance, float[] timeArray, int arrayCount);

			[DllImport("AVProVideo")]
			public static extern void StartExtractFrame(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern void WaitForExtract(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern void Update(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern IntPtr GetTexturePointer(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern bool IsTextureTopDown(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern int GetTextureFrameCount(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern long GetTextureTimeStamp(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern IntPtr GetRenderEventFunc_UpdateAllTextures();

			[DllImport("AVProVideo")]
			public static extern IntPtr GetRenderEventFunc_FreeTextures();

			[DllImport("AVProVideo")]
			public static extern IntPtr GetRenderEventFunc_WaitForNewFrame();

			[DllImport("AVProVideo")]
			public static extern void SetUnityAudioEnabled(IntPtr instance, bool enabled);

			[DllImport("AVProVideo")]
			public static extern void GrabAudio(IntPtr instance, float[] buffer, int floatCount, int channelCount);

			[DllImport("AVProVideo")]
			public static extern int GetAudioChannelCount(IntPtr instance);

			[DllImport("AVProVideo")]
			public static extern int SetAudioChannelMode(IntPtr instance, int channelMode);

			[DllImport("AVProVideo")]
			public static extern void SetHeadOrientation(IntPtr instance, float x, float y, float z, float w);

			[DllImport("AVProVideo")]
			public static extern void SetAudioFocusEnabled(IntPtr instance, bool enabled);

			[DllImport("AVProVideo")]
			public static extern void SetAudioFocusProps(IntPtr instance, float offFocusLevel, float widthDegrees);

			[DllImport("AVProVideo")]
			public static extern void SetAudioFocusRotation(IntPtr instance, float x, float y, float z, float w);

			public const int PluginID = 262537216;

			public enum RenderThreadEvent
			{
				UpdateAllTextures,
				FreeTextures,
				WaitForNewFrame
			}
		}
	}
}
