| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975 | // NOTE: We only allow this script to compile in editor so we can easily check for compilation issues#if (UNITY_EDITOR || (UNITY_STANDALONE_WIN || UNITY_WSA_10_0))#if UNITY_WSA_10 || ENABLE_IL2CPP	#define AVPROVIDEO_MARSHAL_RETURN_BOOL#endifusing UnityEngine;using System.Runtime.InteropServices;using System.Collections.Generic;using System;using System.Text;//-----------------------------------------------------------------------------// Copyright 2018-2021 RenderHeads Ltd.  All rights reserved.//-----------------------------------------------------------------------------namespace RenderHeads.Media.AVProVideo{	public enum PlaybackState	{		None = 0,		Opening = 1,		Buffering = 2,		// Replace with Stalled and add Buffering as State 64??		Playing = 3,		Paused = 4,		StateMask = 7,		Seeking = 32,	}	public class AuthData	{		public string URL { get; set; }		public string Token { get; set; }		public byte[] KeyBytes { get; set; }		public AuthData()		{			Clear();		}		public void Clear()		{			URL = string.Empty;			Token = string.Empty;			KeyBytes = null;		}		public string KeyBase64		{			get			{				if (KeyBytes != null)				{					return System.Convert.ToBase64String(KeyBytes);				}				else				{					return string.Empty;				}			}			set			{				if (value != null)				{					KeyBytes = System.Convert.FromBase64String(value);				}				else				{					KeyBytes = null;				}			}		}	};	public partial class WindowsRtMediaPlayer : BaseMediaPlayer	{		private bool _isMediaLoaded		= false;		private bool _isLooping			= false;		private float _volume			= 1.0f;		private bool _use10BitTextures	= false;		private bool _useLowLiveLatency = false;		public WindowsRtMediaPlayer(MediaPlayer.OptionsWindows options) : base()		{			_playerDescription = "WinRT";			_use10BitTextures = options.use10BitTextures;			_useLowLiveLatency = options.useLowLiveLatency;			for (int i = 0; i < _eyeTextures.Length; i++)			{				_eyeTextures[i] = new EyeTexture();			}		}		public WindowsRtMediaPlayer(MediaPlayer.OptionsWindowsUWP options) : base()		{			_playerDescription = "WinRT";			_use10BitTextures = options.use10BitTextures;			_useLowLiveLatency = options.useLowLiveLatency;			for (int i = 0; i < _eyeTextures.Length; i++)			{				_eyeTextures[i] = new EyeTexture();			}		}		public override bool CanPlay()		{			return HasMetaData();		}		public override void Dispose()		{			CloseMedia();			if (_playerInstance != System.IntPtr.Zero)			{				Native.DestroyPlayer(_playerInstance); _playerInstance = System.IntPtr.Zero;				Native.IssueRenderThreadEvent_FreeAllTextures();			}			for (int i = 0; i < _eyeTextures.Length; i++)			{				_eyeTextures[i].Dispose();			}		}		public override bool PlayerSupportsLinearColorSpace()		{			// The current player doesn't support rendering to SRGB textures			return false;		}		public override double GetCurrentTime()		{			return Native.GetCurrentPosition(_playerInstance);		}		public override double GetDuration()		{			return Native.GetDuration(_playerInstance);		}		public override float GetPlaybackRate()		{			return Native.GetPlaybackRate(_playerInstance);		}		public override Texture GetTexture(int index = 0)		{			Texture result = null;			if (_frameTimeStamp > 0 && index < _eyeTextures.Length)			{				result = _eyeTextures[index].texture;			}			return result;		}		public override int	GetTextureCount()		{			if (_eyeTextures[1].texture != null)			{				return 2;			}			return 1;		}		public override int GetTextureFrameCount()		{			return (int)_frameTimeStamp;		}		internal override StereoPacking InternalGetTextureStereoPacking()		{			return Native.GetStereoPacking(_playerInstance);		}		public override string GetVersion()		{			return _version;		}		public override string GetExpectedVersion()		{			return Helper.ExpectedPluginVersion.WinRT;		}		public override float GetVideoFrameRate()		{			float result = 0f;			Native.VideoTrack videoTrack;			if (Native.GetActiveVideoTrackInfo(_playerInstance, out videoTrack))			{				result = videoTrack.frameRate;			}			return result;		}		public override int GetVideoWidth()		{			int result = 0;			if (_eyeTextures[0].texture)			{				result = _eyeTextures[0].texture.width;			}			return result;		}		public override int GetVideoHeight()		{			int result = 0;			if (_eyeTextures[0].texture)			{				result = _eyeTextures[0].texture.height;			}			return result;		}		public override float GetVolume()		{			return _volume;//Native.GetAudioVolume(_playerInstance);		}		public override void SetBalance(float balance)		{			Native.SetAudioBalance(_playerInstance, balance);		}		public override float GetBalance()		{			return Native.GetAudioBalance(_playerInstance);		}		public override bool HasAudio()		{			return _audioTracks.Count > 0;		}		public override bool HasMetaData()		{			return Native.GetDuration(_playerInstance) > 0f;		}		public override bool HasVideo()		{			return _videoTracks.Count > 0;		}		public override bool IsBuffering()		{			return ((Native.GetPlaybackState(_playerInstance) & PlaybackState.StateMask) == PlaybackState.Buffering);		}		public override bool IsFinished()		{			bool result = false;			if (IsPaused() && !IsSeeking() && GetCurrentTime() >= GetDuration())			{				result = true;			}			return result;		}		public override bool IsLooping()		{			return _isLooping;//Native.IsLooping(_playerInstance);		}		public override bool IsMuted()		{			return Native.IsAudioMuted(_playerInstance);		}		public override bool IsPaused()		{			return ((Native.GetPlaybackState(_playerInstance) & PlaybackState.StateMask) == PlaybackState.Paused);		}		public override bool IsPlaying()		{			return ((Native.GetPlaybackState(_playerInstance) & PlaybackState.StateMask) == PlaybackState.Playing);		}		public override bool IsSeeking()		{			return ((Native.GetPlaybackState(_playerInstance) & PlaybackState.Seeking) != 0);		}		public override void MuteAudio(bool bMuted)		{			Native.SetAudioMuted(_playerInstance, bMuted);		}				// TODO: replace all these options with a structure		public override bool OpenMedia(string path, long offset, string httpHeader, MediaHints mediaHints, int forceFileFormat = 0, bool startWithHighestBitrate = false)		{			bool result = false;			// RJT NOTE: Commented out as already called by 'InternalOpenMedia()' which calls this function//			CloseMedia();			if (_playerInstance == System.IntPtr.Zero)			{				_playerInstance = Native.CreatePlayer();				// Force setting any auth data as it wouldn't have been set without a _playerInstance				AuthenticationData = _nextAuthData;			}			if (_playerInstance != System.IntPtr.Zero)			{				result = Native.OpenMedia(_playerInstance, path, httpHeader, (FileFormat)forceFileFormat, startWithHighestBitrate, _use10BitTextures);				if (result)				{					if (_useLowLiveLatency)					{						Native.SetLiveOffset(_playerInstance, 0.0);					}					// RJT NOTE: Other platforms create their native instances earlier than 'OpenMedia()' and set looping at that					// point which Windows misses, so make sure once we have an instance we pass the looping flag down retrospectively					// - https://github.com/RenderHeads/UnityPlugin-AVProVideo/issues/1913					// - Same now with volume: https://github.com/RenderHeads/UnityPlugin-AVProVideo/issues/1916					Native.SetLooping(_playerInstance, _isLooping);					Native.SetAudioVolume(_playerInstance, _volume);				}				_mediaHints = mediaHints;			}						return result;		}		public override void CloseMedia()		{			// NOTE: This unloads the current video, but the texture should remain			_isMediaLoaded	= false;			_isLooping		= false;			_volume			= 1.0f;			Native.CloseMedia(_playerInstance);			base.CloseMedia();		}		public override void Pause()		{			Native.Pause(_playerInstance);		}		public override void Play()		{			Native.Play(_playerInstance);		}		public override void Render()		{			Native.IssueRenderThreadEvent_UpdateAllTextures();		}		private void Update_Textures()		{			// See if there is a new frame ready			{				System.IntPtr texturePointerLeft = System.IntPtr.Zero;				System.IntPtr texturePointerRight = System.IntPtr.Zero;				ulong frameTimeStamp = 0;				int width, height;				if (Native.GetLatestFrame(_playerInstance, out texturePointerLeft, out texturePointerRight, out frameTimeStamp, out width, out height))				{					bool isFrameUpdated = false;					bool isNewFrameTime = (frameTimeStamp > _frameTimeStamp) || (_frameTimeStamp == 0 && frameTimeStamp == 0);					for (int i = 0; i < _eyeTextures.Length; i++)					{						EyeTexture eyeTexture = _eyeTextures[i];						System.IntPtr texturePointer = texturePointerLeft;						if (i == 1)						{							texturePointer = texturePointerRight;						}											bool isNewFrameSpecs = (eyeTexture.texture != null && (texturePointer == IntPtr.Zero || eyeTexture.texture.width != width || eyeTexture.texture.height != height));						//Debug.Log("tex? " + i + " " + width + " " + height + " " + (eyeTexture.texture != null) + " " + texturePointer.ToString() + " " + frameTimeStamp);											// Check whether the latest frame is newer than the one we got last time						if (isNewFrameTime || isNewFrameSpecs)						{							if (isNewFrameSpecs)							{								eyeTexture.Dispose();								// TODO: blit from the old texture to the new texture before destroying?							}							/// Switch to the latest texture pointer							if (eyeTexture.texture != null)							{								// TODO: check whether UpdateExternalTexture resets the sampling filter to POINT - it seems to in Unity 5.6.6								if (eyeTexture.nativePointer != texturePointer)								{									eyeTexture.texture.UpdateExternalTexture(texturePointer);									eyeTexture.nativePointer = texturePointer;								}							}							else							{								if (texturePointer != IntPtr.Zero)								{									eyeTexture.texture = Texture2D.CreateExternalTexture(width, height, TextureFormat.BGRA32, false, false, texturePointer);									if (eyeTexture.texture != null)									{										eyeTexture.texture.name = "AVProVideo";										eyeTexture.nativePointer = texturePointer;										ApplyTextureProperties(eyeTexture.texture);									}									else									{										Debug.LogError("[AVProVideo] Failed to create texture");									}								}							}							isFrameUpdated = true;						}					}					if (isFrameUpdated)					{						_frameTimeStamp = frameTimeStamp;					}				}			}		}		private AuthData _nextAuthData = new AuthData();		public AuthData AuthenticationData		{ 			get 			{ 				return _nextAuthData;			}			set			{				_nextAuthData = value;				Native.SetNextAuthData(_playerInstance, _nextAuthData);			}		}		public override bool RequiresVerticalFlip()		{			return true;		}		public override void Seek(double time)		{			Native.SeekParams seekParams = new Native.SeekParams();			seekParams.timeSeconds = time;			seekParams.mode = Native.SeekMode.Accurate;			Native.Seek(_playerInstance, ref seekParams);		}		public override void SeekFast(double time)		{			// Keyframe seeking is not supported on this platform			Seek(time);		}		public override void SetLooping(bool bLooping)		{			_isLooping = bLooping;			Native.SetLooping(_playerInstance, _isLooping);		}		public override void SetPlaybackRate(float rate)		{			// Clamp rate as WinRT doesn't seem to be able to handle negative rate			rate = Mathf.Max(0f, rate);			Native.SetPlaybackRate(_playerInstance, rate);		}		public override void SetVolume(float volume)		{			_volume = volume;			Native.SetAudioVolume(_playerInstance, _volume);		}		public override void Stop()		{			Pause();		}		private void UpdateTimeRanges()		{				UpdateTimeRange(ref _seekableTimes._ranges, Native.TimeRangeTypes.Seekable);			UpdateTimeRange(ref _bufferedTimes._ranges, Native.TimeRangeTypes.Buffered);			_seekableTimes.CalculateRange();			_bufferedTimes.CalculateRange();		}		private void UpdateTimeRange(ref TimeRange[] range, Native.TimeRangeTypes timeRangeType)		{			int newCount = Native.GetTimeRanges(_playerInstance, range, range.Length, timeRangeType);			if (newCount != range.Length)			{				range = new TimeRange[newCount];				Native.GetTimeRanges(_playerInstance, range, range.Length, timeRangeType);			}		}		public override System.DateTime GetProgramDateTime()		{			double seconds = Native.GetCurrentDateTimeSecondsSince1970(_playerInstance);			return Helper.ConvertSecondsSince1970ToDateTime(seconds);		}		public override void Update()		{			Native.Update(_playerInstance);			UpdateTracks();			UpdateTextCue();			_lastError = (ErrorCode)Native.GetLastErrorCode(_playerInstance);			UpdateTimeRanges();			UpdateSubtitles();			Update_Textures();			UpdateDisplayFrameRate();			if (!_isMediaLoaded)			{				if (HasVideo() && _eyeTextures[0].texture != null)				{					Native.VideoTrack videoTrack;					if (Native.GetActiveVideoTrackInfo(_playerInstance, out videoTrack))					{							Helper.LogInfo("Using playback path: " + _playerDescription + " (" + videoTrack.frameWidth + "x" + videoTrack.frameHeight + "@" + videoTrack.frameRate.ToString("F2") + ")");						_isMediaLoaded = true;					}				}				else if (HasAudio() && !HasVideo())				{					Helper.LogInfo("Using playback path: " + _playerDescription);					_isMediaLoaded = true;				}			}		}		/*public override void SetKeyServerURL(string url)		{			_nextAuthData.URL = url;			AuthenticationData = _nextAuthData;			}*/		public override void SetKeyServerAuthToken(string token)		{			_nextAuthData.Token = token;			AuthenticationData = _nextAuthData;			}		public override void SetOverrideDecryptionKey(byte[] key)		{			_nextAuthData.KeyBytes = key;			AuthenticationData = _nextAuthData;			}	}	// Tracks	public sealed partial class WindowsRtMediaPlayer	{			internal override bool InternalSetActiveTrack(TrackType trackType, int trackUid)		{			return Native.SetActiveTrack(_playerInstance, trackType, trackUid);		}		// Has it changed since the last frame 'tick'		internal override bool InternalIsChangedTracks(TrackType trackType)		{			return Native.IsChangedTracks(_playerInstance, trackType);		}		internal override int InternalGetTrackCount(TrackType trackType)		{			return Native.GetTrackCount(_playerInstance, trackType);		}		internal override TrackBase InternalGetTrackInfo(TrackType trackType, int trackIndex, ref bool isActiveTrack)		{			TrackBase result = null;			StringBuilder name = new StringBuilder(128);			StringBuilder language = new StringBuilder(16);			int uid = -1;			if (Native.GetTrackInfo(_playerInstance, trackType, trackIndex, ref uid, ref isActiveTrack, name, name.Capacity, language, language.Capacity))			{				if (trackType == TrackType.Video)				{					result = new VideoTrack(uid, name.ToString(), language.ToString(), false);				}				else if (trackType == TrackType.Audio)				{					result = new AudioTrack(uid, name.ToString(), language.ToString(), false);				}				else if (trackType == TrackType.Text)				{					result = new TextTrack(uid, name.ToString(), language.ToString(), false);				}			}			return result;		}		private partial struct Native		{			[DllImport("AVProVideoWinRT")]			[return: MarshalAs(UnmanagedType.I1)]			public static extern bool IsChangedTracks(System.IntPtr instance, TrackType trackType);			[DllImport("AVProVideoWinRT")]			public static extern int GetTrackCount(System.IntPtr instance, TrackType trackType);			[DllImport("AVProVideoWinRT")]			[return: MarshalAs(UnmanagedType.I1)]			public static extern bool GetTrackInfo(System.IntPtr instance, TrackType trackType, int index, ref int uid, 										ref bool isActive,										[MarshalAs(UnmanagedType.LPWStr)] StringBuilder name, int maxNameLength,										[MarshalAs(UnmanagedType.LPWStr)] StringBuilder language, int maxLanguageLength);			[DllImport("AVProVideoWinRT")]			[return: MarshalAs(UnmanagedType.I1)]			public static extern bool SetActiveTrack(System.IntPtr instance, TrackType trackType, int trackUid);		}	}	// Text Cue	public sealed partial class WindowsRtMediaPlayer	{			// Has it changed since the last frame 'tick'		internal override bool InternalIsChangedTextCue()		{			return Native.IsChangedTextCue(_playerInstance);		}		internal override string InternalGetCurrentTextCue()		{			string result = null;			System.IntPtr ptr = Native.GetCurrentTextCue(_playerInstance);			if (ptr != System.IntPtr.Zero)			{				result = System.Runtime.InteropServices.Marshal.PtrToStringUni(ptr);			}			return result;		}		private partial struct Native		{			[DllImport("AVProVideoWinRT")]			[return: MarshalAs(UnmanagedType.I1)]			public static extern bool IsChangedTextCue(System.IntPtr instance);			[DllImport("AVProVideoWinRT")]			public static extern System.IntPtr GetCurrentTextCue(System.IntPtr instance);		}	}	public sealed partial class WindowsRtMediaPlayer	{			private partial struct Native		{			[DllImport("AVProVideoWinRT", EntryPoint = "GetPluginVersion")]			private static extern System.IntPtr GetPluginVersionStringPointer();			public static string GetPluginVersion()			{				return System.Runtime.InteropServices.Marshal.PtrToStringAnsi(GetPluginVersionStringPointer());			}			[DllImport("AVProVideoWinRT")]			public static extern System.IntPtr CreatePlayer();			[DllImport("AVProVideoWinRT")]			public static extern void DestroyPlayer(System.IntPtr playerInstance);			[DllImport("AVProVideoWinRT")]#if AVPROVIDEO_MARSHAL_RETURN_BOOL			[return: MarshalAs(UnmanagedType.I1)]#endif			public static extern bool OpenMedia(System.IntPtr playerInstance, [MarshalAs(UnmanagedType.LPWStr)] string filePath, 												[MarshalAs(UnmanagedType.LPWStr)] string httpHeader, FileFormat overrideFileFormat, 												bool startWithHighestBitrate, bool use10BitTextures);			[DllImport("AVProVideoWinRT")]			public static extern void CloseMedia(System.IntPtr playerInstance);			[DllImport("AVProVideoWinRT")]			public static extern void Pause(System.IntPtr playerInstance);			[DllImport("AVProVideoWinRT")]			public static extern void Play(System.IntPtr playerInstance);			[DllImport("AVProVideoWinRT")]			public static extern void SetAudioVolume(System.IntPtr playerInstance, float volume);			[DllImport("AVProVideoWinRT")]			public static extern void SetAudioBalance(System.IntPtr playerInstance, float balance);			[DllImport("AVProVideoWinRT")]			public static extern void SetPlaybackRate(System.IntPtr playerInstance, float rate);			[DllImport("AVProVideoWinRT")]			public static extern void SetAudioMuted(System.IntPtr playerInstance, bool muted);			[DllImport("AVProVideoWinRT")]			public static extern float GetAudioVolume(System.IntPtr playerInstance);			[DllImport("AVProVideoWinRT")]#if AVPROVIDEO_MARSHAL_RETURN_BOOL			[return: MarshalAs(UnmanagedType.I1)]#endif			public static extern bool IsAudioMuted(System.IntPtr playerInstance);			[DllImport("AVProVideoWinRT")]			public static extern float GetAudioBalance(System.IntPtr playerInstance);			[DllImport("AVProVideoWinRT")]			public static extern float GetPlaybackRate(System.IntPtr playerInstance);			[DllImport("AVProVideoWinRT")]			public static extern void SetLooping(System.IntPtr playerInstance, bool looping);			[DllImport("AVProVideoWinRT")]#if AVPROVIDEO_MARSHAL_RETURN_BOOL			[return: MarshalAs(UnmanagedType.I1)]#endif			public static extern bool IsLooping(System.IntPtr playerInstance);			[DllImport("AVProVideoWinRT")]			public static extern int GetLastErrorCode(System.IntPtr playerInstance);			[DllImport("AVProVideoWinRT")]			public static extern void Update(System.IntPtr playerInstance);			[DllImport("AVProVideoWinRT")]			public static extern double GetDuration(System.IntPtr playerInstance);			[DllImport("AVProVideoWinRT")]			public static extern StereoPacking GetStereoPacking(System.IntPtr playerInstance);			[DllImport("AVProVideoWinRT")]			public static extern double GetCurrentPosition(System.IntPtr playerInstance);			[DllImport("AVProVideoWinRT")]#if AVPROVIDEO_MARSHAL_RETURN_BOOL			[return: MarshalAs(UnmanagedType.I1)]#endif			public static extern bool GetLatestFrame(System.IntPtr playerInstance, out System.IntPtr leftEyeTexturePointer, out System.IntPtr rightEyeTexturePointer, out ulong frameTimeStamp, out int width, out int height);			[DllImport("AVProVideoWinRT")]			public static extern PlaybackState GetPlaybackState(System.IntPtr playerInstance);			[DllImport("AVProVideoWinRT")]#if AVPROVIDEO_MARSHAL_RETURN_BOOL			[return: MarshalAs(UnmanagedType.I1)]#endif			public static extern bool GetActiveVideoTrackInfo(System.IntPtr playerInstance, out VideoTrack videoTrack);			[DllImport("AVProVideoWinRT")]#if AVPROVIDEO_MARSHAL_RETURN_BOOL			[return: MarshalAs(UnmanagedType.I1)]#endif			public static extern bool GetActiveAudioTrackInfo(System.IntPtr playerInstance, out AudioTrack audioTrack);			[DllImport("AVProVideoWinRT")]			public static extern double GetCurrentDateTimeSecondsSince1970(System.IntPtr playerInstance);			[DllImport("AVProVideoWinRT")]			public static extern void SetLiveOffset(System.IntPtr playerInstance, double seconds);			[DllImport("AVProVideoWinRT")]			public static extern void DebugValues(System.IntPtr playerInstance, out int isD3D, out int isUnityD3D, out int isTexture, out int isSharedTexture, out int isSurface);			public enum SeekMode			{				Fast = 0,				Accurate = 1,				// TODO: Add Fast_Before and Fast_After			}			[StructLayout(LayoutKind.Sequential, Pack = 1)]			public struct VideoTrack			{				public int trackIndex;				public int frameWidth;				public int frameHeight;				public float frameRate;				public uint averageBitRate;				//public string trackName;				// TODO: add index, language, name, bitrate, codec etc			}			[StructLayout(LayoutKind.Sequential, Pack = 1)]			public struct AudioTrack			{				public int trackIndex;				public uint channelCount;				public uint sampleRate;				public uint bitsPerSample;				public uint averageBitRate;				//public string trackName;				// TODO: add index, language, name, bitrate, codec etc			}						[StructLayout(LayoutKind.Sequential, Pack = 1)]			public struct SeekParams			{				public double timeSeconds;				public SeekMode mode;				// TODO: add min-max thresholds			}			[DllImport("AVProVideoWinRT")]			public static extern void Seek(System.IntPtr playerInstance, ref SeekParams seekParams);			public static void SetNextAuthData(System.IntPtr playerInstance, RenderHeads.Media.AVProVideo.AuthData srcAuthData)			{						Native.AuthData ad = new Native.AuthData();				ad.url = string.IsNullOrEmpty(srcAuthData.URL) ? null : srcAuthData.URL;				ad.token = string.IsNullOrEmpty(srcAuthData.Token) ? null : srcAuthData.Token;				if (srcAuthData.KeyBytes != null && srcAuthData.KeyBytes.Length > 0)				{					ad.keyBytes = Marshal.AllocHGlobal(srcAuthData.KeyBytes.Length);					Marshal.Copy(srcAuthData.KeyBytes, 0, ad.keyBytes, srcAuthData.KeyBytes.Length);					ad.keyBytesLength = srcAuthData.KeyBytes.Length;				}				else				{					ad.keyBytes = System.IntPtr.Zero;					ad.keyBytesLength = 0;				}				SetNextAuthData(playerInstance, ref ad);				if (ad.keyBytes != System.IntPtr.Zero)				{					Marshal.FreeHGlobal(ad.keyBytes);				}			}			[StructLayout(LayoutKind.Sequential, Pack = 1)]			public struct AuthData			{				[MarshalAs(UnmanagedType.LPWStr)]				public string url;				[MarshalAs(UnmanagedType.LPWStr)]				public string token;				public System.IntPtr keyBytes;				public int keyBytesLength;			};			[DllImport("AVProVideoWinRT")]			private static extern void SetNextAuthData(System.IntPtr playerInstance, ref AuthData authData);			internal enum TimeRangeTypes			{				Seekable = 0,				Buffered = 1,			}			[DllImport("AVProVideoWinRT")]			public static extern int GetTimeRanges(System.IntPtr playerInstance, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=2)] TimeRange[] ranges, int rangeCount, TimeRangeTypes timeRangeType);			// RJT TODO: Clean this up to better match non-WinRT			[DllImport("AVProVideoWinRT")]			public static extern System.IntPtr GetRenderEventFunc();			private static System.IntPtr _nativeFunction_UnityRenderEvent;			public static void IssueRenderThreadEvent_UpdateAllTextures()			{				if (_nativeFunction_UnityRenderEvent == System.IntPtr.Zero)				{					_nativeFunction_UnityRenderEvent = Native.GetRenderEventFunc();				}				if (_nativeFunction_UnityRenderEvent != System.IntPtr.Zero)				{					GL.IssuePluginEvent(_nativeFunction_UnityRenderEvent, /*(int)Native.RenderThreadEvent.UpdateAllTextures*/1);				}			}			public static void IssueRenderThreadEvent_FreeAllTextures()			{				if (_nativeFunction_UnityRenderEvent == System.IntPtr.Zero)				{					_nativeFunction_UnityRenderEvent = Native.GetRenderEventFunc();				}				if (_nativeFunction_UnityRenderEvent != System.IntPtr.Zero)				{					GL.IssuePluginEvent(_nativeFunction_UnityRenderEvent, /*(int)Native.RenderThreadEvent.FreeTextures*/2);				}			}		}	}	public sealed partial class WindowsRtMediaPlayer	{		private static bool _isInitialised = false;		private static string _version = "Plug-in not yet initialised";		private ulong _frameTimeStamp;		private System.IntPtr _playerInstance;		class EyeTexture		{			public Texture2D texture = null;			public System.IntPtr nativePointer = System.IntPtr.Zero;			public void Dispose()			{				if (texture)				{					if (Application.isPlaying) { Texture2D.Destroy(texture); }						else { Texture2D.DestroyImmediate(texture); }					texture = null;				}				nativePointer = System.IntPtr.Zero;			}		}		private EyeTexture[] _eyeTextures = new EyeTexture[2];		public static bool InitialisePlatform()		{			if (!_isInitialised)			{				try				{#if !UNITY_2019_3_OR_NEWER					if (SystemInfo.graphicsDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Direct3D12)					{						Debug.LogError("[AVProVideo] Direct3D 12 is not supported until Unity 2019.3");						return false;					}#endif					if (SystemInfo.graphicsDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Null ||						SystemInfo.graphicsDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Direct3D11 ||						SystemInfo.graphicsDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Direct3D12)					{						/*if (!Native.Init(QualitySettings.activeColorSpace == ColorSpace.Linear))						{							Debug.LogError("[AVProVideo] Failing to initialise platform");						}						else*/						{							_isInitialised = true;							_version = Native.GetPluginVersion();						}					}					else					{						Debug.LogError("[AVProVideo] Only Direct3D 11 and 12 are supported, graphicsDeviceType not supported: " + SystemInfo.graphicsDeviceType);					}				}				catch (System.DllNotFoundException e)				{					Debug.LogError("[AVProVideo] Failed to load DLL. " + e.Message);				}			}			return _isInitialised;		}		public static void DeinitPlatform()		{			//Native.Deinit();			_isInitialised = false;		}	}}#endif
 |