WindowsMediaPlayer.cs 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644
  1. // NOTE: We only allow this script to compile in editor so we can easily check for compilation issues
  2. #if (UNITY_EDITOR || (UNITY_STANDALONE_WIN || UNITY_WSA_10_0))
  3. #if UNITY_WSA_10 || ENABLE_IL2CPP
  4. #define AVPROVIDEO_MARSHAL_RETURN_BOOL
  5. #endif
  6. #if UNITY_5_4_OR_NEWER && !UNITY_2019_3_OR_NEWER
  7. #define AVPROVIDEO_FIXREGRESSION_TEXTUREQUALITY_UNITY542
  8. #endif
  9. #if UNITY_2019_3_OR_NEWER && !UNITY_2020_1_OR_NEWER
  10. #define AVPROVIDEO_FIX_UPDATEEXTERNALTEXTURE_LEAK
  11. #endif
  12. using UnityEngine;
  13. using System.Runtime.InteropServices;
  14. using System.Collections.Generic;
  15. using System;
  16. using System.Text;
  17. #if NETFX_CORE
  18. using Windows.Storage.Streams;
  19. #endif
  20. //-----------------------------------------------------------------------------
  21. // Copyright 2015-2021 RenderHeads Ltd. All rights reserved.
  22. //-----------------------------------------------------------------------------
  23. namespace RenderHeads.Media.AVProVideo
  24. {
  25. /// <summary>
  26. /// Windows desktop and UWP implementation of BaseMediaPlayer
  27. /// </summary>
  28. public /*sealed*/ partial class WindowsMediaPlayer : BaseMediaPlayer
  29. {
  30. private Windows.AudioOutput _audioOutput = Windows.AudioOutput.System;
  31. private string _audioDeviceOutputName = string.Empty;
  32. private List<string> _preferredFilters = new List<string>();
  33. private Audio360ChannelMode _audio360ChannelMode = Audio360ChannelMode.TBE_8_2;
  34. private bool _useCustomMovParser = false;
  35. private bool _useStereoDetection = true;
  36. private bool _useHapNotchLC = true;
  37. private bool _useTextTrackSupport = true;
  38. private bool _useFacebookAudio360Support = true;
  39. private bool _useAudioDelay = false;
  40. private int _decoderParallelFrameCount = 3;
  41. private int _decodePrerollFrameCount = 5;
  42. private bool _isPlaying = false;
  43. private bool _isPaused = false;
  44. private bool _audioMuted = false;
  45. private float _volume = 1.0f;
  46. private float _balance = 0.0f;
  47. private bool _isLooping = false;
  48. private bool _canPlay = false;
  49. private bool _hasMetaData = false;
  50. private int _width = 0;
  51. private int _height = 0;
  52. private float _frameRate = 0f;
  53. private bool _hasAudio = false;
  54. private bool _hasVideo = false;
  55. private bool _isTextureTopDown = true;
  56. private System.IntPtr _nativeTexture = System.IntPtr.Zero;
  57. private Texture2D _texture;
  58. private RenderTexture _resolvedTexture;
  59. private System.IntPtr _instance = System.IntPtr.Zero;
  60. private Windows.VideoApi _videoApi = Windows.VideoApi.MediaFoundation;
  61. private bool _useHardwareDecoding = true;
  62. private bool _useTextureMips = false;
  63. private bool _use10BitTextures = false;
  64. private bool _hintAlphaChannel = false;
  65. private bool _useLowLatency = false;
  66. private bool _supportsLinearColorSpace = true;
  67. private TextureFrame _textureFrame;
  68. #if AVPROVIDEO_FIX_UPDATEEXTERNALTEXTURE_LEAK
  69. private TextureFrame _textureFramePrev;
  70. #endif
  71. private static bool _isInitialised = false;
  72. private static string _version = "Plug-in not yet initialised";
  73. private static System.IntPtr _nativeFunction_UpdateAllTextures;
  74. private static System.IntPtr _nativeFunction_FreeTextures;
  75. private static System.IntPtr _nativeFunction_ExtractFrame;
  76. #if AVPROVIDEO_FIXREGRESSION_TEXTUREQUALITY_UNITY542
  77. private int _textureQuality = QualitySettings.masterTextureLimit;
  78. #endif
  79. public static bool InitialisePlatform()
  80. {
  81. if (!_isInitialised)
  82. {
  83. try
  84. {
  85. #if !UNITY_2019_3_OR_NEWER
  86. if (SystemInfo.graphicsDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Direct3D12)
  87. {
  88. Debug.LogError("[AVProVideo] Direct3D 12 is not supported until Unity 2019.3");
  89. return false;
  90. }
  91. #endif
  92. if (SystemInfo.graphicsDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Null ||
  93. SystemInfo.graphicsDeviceType == UnityEngine.Rendering.GraphicsDeviceType.OpenGLCore ||
  94. #if !UNITY_2017_2_OR_NEWER
  95. SystemInfo.graphicsDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Direct3D9 ||
  96. #endif
  97. SystemInfo.graphicsDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Direct3D11 ||
  98. SystemInfo.graphicsDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Direct3D12)
  99. {
  100. if (!Native.Init(QualitySettings.activeColorSpace == ColorSpace.Linear, true))
  101. {
  102. Debug.LogError("[AVProVideo] Failing to initialise platform");
  103. }
  104. else
  105. {
  106. _isInitialised = true;
  107. _version = GetPluginVersion();
  108. _nativeFunction_UpdateAllTextures = Native.GetRenderEventFunc_UpdateAllTextures();
  109. _nativeFunction_FreeTextures = Native.GetRenderEventFunc_FreeTextures();
  110. _nativeFunction_ExtractFrame = Native.GetRenderEventFunc_WaitForNewFrame();
  111. if (_nativeFunction_UpdateAllTextures != IntPtr.Zero &&
  112. _nativeFunction_FreeTextures != IntPtr.Zero &&
  113. _nativeFunction_ExtractFrame != IntPtr.Zero)
  114. {
  115. _isInitialised = true;
  116. }
  117. }
  118. }
  119. else
  120. {
  121. Debug.LogError("[AVProVideo] graphicsDeviceType not supported: " + SystemInfo.graphicsDeviceType);
  122. }
  123. }
  124. catch (System.DllNotFoundException e)
  125. {
  126. Debug.LogError("[AVProVideo] Failed to load DLL. " + e.Message);
  127. }
  128. }
  129. return _isInitialised;
  130. }
  131. public static void DeinitPlatform()
  132. {
  133. Native.Deinit();
  134. _isInitialised = false;
  135. }
  136. public override int GetAudioChannelCount()
  137. {
  138. return Native.GetAudioChannelCount(_instance);
  139. }
  140. public override AudioChannelMaskFlags GetAudioChannelMask()
  141. {
  142. return (AudioChannelMaskFlags)Native.GetAudioChannelMask(_instance);
  143. }
  144. public WindowsMediaPlayer(MediaPlayer.OptionsWindows options) : base()
  145. {
  146. SetOptions(options.videoApi, options.audioOutput, options.useHardwareDecoding, options.useTextureMips, options.use10BitTextures, options.hintAlphaChannel, options.useLowLatency, options.forceAudioOutputDeviceName, options.preferredFilters, options.useCustomMovParser, options.parallelFrameCount, options.prerollFrameCount, options.useHapNotchLC, options.useStereoDetection, options.useTextTrackSupport, options.useFacebookAudio360Support, options.bufferedFrameSelection, options.pauseOnPrerollComplete, options.useAudioDelay);
  147. }
  148. public WindowsMediaPlayer(MediaPlayer.OptionsWindowsUWP options) : base()
  149. {
  150. Windows.VideoApi api = (options.videoApi == WindowsUWP.VideoApi.MediaFoundation)?Windows.VideoApi.MediaFoundation:Windows.VideoApi.WinRT;
  151. Windows.AudioOutput audioOutput = (Windows.AudioOutput)(int)options.audioOutput;
  152. SetOptions(api, audioOutput, options.useHardwareDecoding, options.useTextureMips, options.use10BitTextures, false, options.useLowLatency, string.Empty, null, false, 1, 0, false, true, false, true, BufferedFrameSelectionMode.None, false, false);
  153. }
  154. public void SetOptions(Windows.VideoApi videoApi, Windows.AudioOutput audioOutput, bool useHardwareDecoding, bool useTextureMips, bool use10BitTextures, bool hintAlphaChannel,
  155. bool useLowLatency, string audioDeviceOutputName, List<string> preferredFilters, bool useCustomMovParser, int parallelFrameCount, int prerollFrameCount,
  156. bool useHapNotchLC, bool useStereoDetection, bool useTextTrackSupport, bool useFacebookAudio360Support,
  157. BufferedFrameSelectionMode bufferedFrameSelection, bool pauseOnPrerollComplete, bool useAudioDelay)
  158. {
  159. _videoApi = videoApi;
  160. _audioOutput = audioOutput;
  161. _useHardwareDecoding = useHardwareDecoding;
  162. _useTextureMips = useTextureMips;
  163. _use10BitTextures = use10BitTextures;
  164. _hintAlphaChannel = hintAlphaChannel;
  165. _useLowLatency = useLowLatency;
  166. _useStereoDetection = useStereoDetection;
  167. _useTextTrackSupport = useTextTrackSupport;
  168. _useFacebookAudio360Support = useFacebookAudio360Support;
  169. _frameSelectionMode = bufferedFrameSelection;
  170. _pauseOnPrerollComplete = pauseOnPrerollComplete;
  171. _useHapNotchLC = useHapNotchLC;
  172. _useCustomMovParser = useCustomMovParser;
  173. _decoderParallelFrameCount = parallelFrameCount;
  174. _decodePrerollFrameCount = prerollFrameCount;
  175. _useAudioDelay = useAudioDelay;
  176. _audioDeviceOutputName = audioDeviceOutputName;
  177. if (!string.IsNullOrEmpty(_audioDeviceOutputName))
  178. {
  179. _audioDeviceOutputName = _audioDeviceOutputName.Trim();
  180. }
  181. _preferredFilters = preferredFilters;
  182. if (_preferredFilters != null)
  183. {
  184. for (int i = 0; i < _preferredFilters.Count; ++i)
  185. {
  186. if (!string.IsNullOrEmpty(_preferredFilters[i]))
  187. {
  188. _preferredFilters[i] = _preferredFilters[i].Trim();
  189. }
  190. }
  191. }
  192. }
  193. public override string GetVersion()
  194. {
  195. return _version;
  196. }
  197. public override string GetExpectedVersion()
  198. {
  199. return Helper.ExpectedPluginVersion.Windows;
  200. }
  201. private bool UseNativeMips()
  202. {
  203. // RJT TODO: Heuristic(s) to decide whether mipping should be performed at native level or here
  204. // - Query native first to see whether it can handle?
  205. // - E.g. D3D11/12 hardware path should be able to handle but software not
  206. // - May become moot if we're going to create a resolved texture at this level anyhow (makes sense to generate mips as final step?)
  207. return _useTextureMips;//true;// false;// _useTextureMips;
  208. }
  209. public override bool OpenMedia(string path, long offset, string httpHeader, MediaHints mediaHints, int forceFileFormat = 0, bool startWithHighestBitrate = false)
  210. {
  211. CloseMedia();
  212. uint filterCount = 0U;
  213. IntPtr[] filters = null;
  214. if (_preferredFilters != null && _preferredFilters.Count > 0)
  215. {
  216. filterCount = (uint)_preferredFilters.Count;
  217. filters = new IntPtr[_preferredFilters.Count];
  218. for (int i = 0; i < filters.Length; ++i)
  219. {
  220. filters[i] = Marshal.StringToHGlobalUni(_preferredFilters[i]);
  221. }
  222. }
  223. _instance = Native.BeginOpenSource(_instance, _videoApi, _audioOutput, _useHardwareDecoding, UseNativeMips(), mediaHints.transparency == TransparencyMode.Transparent, _useLowLatency, _use10BitTextures, _audioDeviceOutputName, _audioOutput == Windows.AudioOutput.Unity?Helper.GetUnityAudioSampleRate():0, filters, filterCount, (int)_audio360ChannelMode);
  224. if (_instance != System.IntPtr.Zero)
  225. {
  226. Native.SetCustomMovParserEnabled(_instance, _useCustomMovParser);
  227. Native.SetHapNotchLCEnabled(_instance, _useHapNotchLC);
  228. Native.SetFrameBufferingEnabled(_instance, (_frameSelectionMode != BufferedFrameSelectionMode.None), _pauseOnPrerollComplete);
  229. Native.SetStereoDetectEnabled(_instance, _useStereoDetection);
  230. Native.SetTextTrackSupportEnabled(_instance, _useTextTrackSupport);
  231. Native.SetAudioDelayEnabled(_instance, _useAudioDelay, true, 0.0);
  232. Native.SetFacebookAudio360SupportEnabled(_instance, _useFacebookAudio360Support);
  233. Native.SetDecoderHints(_instance, _decoderParallelFrameCount, _decodePrerollFrameCount);
  234. _instance = Native.EndOpenSource(_instance, path);
  235. }
  236. if (filters != null)
  237. {
  238. for (int i = 0; i < filters.Length; ++i)
  239. {
  240. Marshal.FreeHGlobal(filters[i]);
  241. }
  242. }
  243. if (_instance == System.IntPtr.Zero)
  244. {
  245. DisplayLoadFailureSuggestion(path);
  246. return false;
  247. }
  248. _mediaHints = mediaHints;
  249. return true;
  250. }
  251. public override bool OpenMediaFromBuffer(byte[] buffer)
  252. {
  253. CloseMedia();
  254. IntPtr[] filters;
  255. if (_preferredFilters.Count == 0)
  256. {
  257. filters = null;
  258. }
  259. else
  260. {
  261. filters = new IntPtr[_preferredFilters.Count];
  262. for (int i = 0; i < filters.Length; ++i)
  263. {
  264. filters[i] = Marshal.StringToHGlobalUni(_preferredFilters[i]);
  265. }
  266. }
  267. _instance = Native.OpenSourceFromBuffer(_instance, buffer, (ulong)buffer.Length, _videoApi, _audioOutput, _useHardwareDecoding, UseNativeMips(), _mediaHints.transparency == TransparencyMode.Transparent, _useLowLatency, _use10BitTextures, _audioDeviceOutputName, _audioOutput == Windows.AudioOutput.Unity?Helper.GetUnityAudioSampleRate():0, filters, (uint)_preferredFilters.Count);
  268. if (filters != null)
  269. {
  270. for (int i = 0; i < filters.Length; ++i)
  271. {
  272. Marshal.FreeHGlobal(filters[i]);
  273. }
  274. }
  275. if (_instance == System.IntPtr.Zero)
  276. {
  277. return false;
  278. }
  279. return true;
  280. }
  281. public override bool StartOpenMediaFromBuffer(ulong length)
  282. {
  283. CloseMedia();
  284. _instance = Native.StartOpenSourceFromBuffer(_instance, _videoApi, length);
  285. return _instance != IntPtr.Zero;
  286. }
  287. public override bool AddChunkToMediaBuffer(byte[] chunk, ulong offset, ulong length)
  288. {
  289. return Native.AddChunkToSourceBuffer(_instance, chunk, offset, length);
  290. }
  291. public override bool EndOpenMediaFromBuffer()
  292. {
  293. IntPtr[] filters;
  294. if (_preferredFilters.Count == 0)
  295. {
  296. filters = null;
  297. }
  298. else
  299. {
  300. filters = new IntPtr[_preferredFilters.Count];
  301. for (int i = 0; i < filters.Length; ++i)
  302. {
  303. filters[i] = Marshal.StringToHGlobalUni(_preferredFilters[i]);
  304. }
  305. }
  306. _instance = Native.EndOpenSourceFromBuffer(_instance, _audioOutput, _useHardwareDecoding, UseNativeMips(), _hintAlphaChannel, _useLowLatency, _use10BitTextures, _audioDeviceOutputName, _audioOutput == Windows.AudioOutput.Unity?Helper.GetUnityAudioSampleRate():0, filters, (uint)_preferredFilters.Count);
  307. if (filters != null)
  308. {
  309. for (int i = 0; i < filters.Length; ++i)
  310. {
  311. Marshal.FreeHGlobal(filters[i]);
  312. }
  313. }
  314. if (_instance == System.IntPtr.Zero)
  315. {
  316. return false;
  317. }
  318. return true;
  319. }
  320. #if NETFX_CORE
  321. public override bool OpenMedia(IRandomAccessStream ras, string path, long offset, string httpHeader)
  322. {
  323. CloseMedia();
  324. _instance = Native.OpenSourceFromStream(_instance, ras, path, _videoApi, _audioOutput, _useHardwareDecoding, UseNativeMips(), _hintAlphaChannel, _useLowLatency, _use10BitTextures, _audioDeviceOutputName, _audioOutput == Windows.AudioOutput.Unity?Helper.GetUnityAudioSampleRate():0);
  325. if (_instance == System.IntPtr.Zero)
  326. {
  327. DisplayLoadFailureSuggestion(path);
  328. return false;
  329. }
  330. return true;
  331. }
  332. #endif
  333. private void DisplayLoadFailureSuggestion(string path)
  334. {
  335. bool usingDirectShow = (_videoApi == Windows.VideoApi.DirectShow) || SystemInfo.operatingSystem.Contains("Windows 7") || SystemInfo.operatingSystem.Contains("Windows Vista") || SystemInfo.operatingSystem.Contains("Windows XP");
  336. if (usingDirectShow && path.Contains(".mp4"))
  337. {
  338. 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.");
  339. }
  340. }
  341. public override void CloseMedia()
  342. {
  343. _width = 0;
  344. _height = 0;
  345. _frameRate = 0f;
  346. _hasAudio = _hasVideo = false;
  347. _hasMetaData = false;
  348. _canPlay = false;
  349. _isPaused = true;
  350. _isPlaying = false;
  351. _isLooping = false;
  352. _audioMuted = false;
  353. _volume = 1f;
  354. _balance = 0f;
  355. _supportsLinearColorSpace = true;
  356. _displayClockTime = 0.0;
  357. _timeAccumulation = 0.0;
  358. FlushFrameBuffering(true);
  359. ReleaseTexture();
  360. if (_instance != System.IntPtr.Zero)
  361. {
  362. Native.CloseSource(_instance);
  363. _instance = System.IntPtr.Zero;
  364. }
  365. // Issue thread event to free the texture on the GPU
  366. IssueRenderThreadEvent(Native.RenderThreadEvent.FreeTextures);
  367. base.CloseMedia();
  368. }
  369. public override void SetLooping(bool looping)
  370. {
  371. _isLooping = looping;
  372. Native.SetLooping(_instance, looping);
  373. }
  374. public override bool IsLooping()
  375. {
  376. return _isLooping;
  377. }
  378. public override bool HasMetaData()
  379. {
  380. return _hasMetaData;
  381. }
  382. public override bool HasAudio()
  383. {
  384. return _hasAudio;
  385. }
  386. public override bool HasVideo()
  387. {
  388. return _hasVideo;
  389. }
  390. public override bool CanPlay()
  391. {
  392. return _canPlay;
  393. }
  394. public override void Play()
  395. {
  396. _isPlaying = true;
  397. _isPaused = false;
  398. Native.Play(_instance);
  399. }
  400. public override void Pause()
  401. {
  402. _isPlaying = false;
  403. _isPaused = true;
  404. Native.Pause(_instance);
  405. }
  406. public override void Stop()
  407. {
  408. _isPlaying = false;
  409. _isPaused = true;
  410. Native.Pause(_instance);
  411. }
  412. public override bool IsSeeking()
  413. {
  414. return Native.IsSeeking(_instance);
  415. }
  416. public override bool IsPlaying()
  417. {
  418. if (_isPlaying && _frameSelectionMode != BufferedFrameSelectionMode.None)
  419. {
  420. // In case we're still playing the buffered frames at the end of the video
  421. // We want to return true, even though internally it has stopping playing
  422. if (Native.IsFinished(_instance) && !IsFinished())
  423. {
  424. return true;
  425. }
  426. // In this case internal state can change so we need to check that too
  427. if (_pauseOnPrerollComplete)
  428. {
  429. return Native.IsPlaying(_instance);
  430. }
  431. }
  432. return _isPlaying;
  433. }
  434. public override bool IsPaused()
  435. {
  436. if (_pauseOnPrerollComplete)
  437. {
  438. // In this case internal state can change so we need to check that too
  439. return _isPaused || !Native.IsPlaying(_instance);
  440. }
  441. return _isPaused;
  442. }
  443. public override bool IsFinished()
  444. {
  445. bool result = false;
  446. if (!IsLooping())
  447. {
  448. result = Native.IsFinished(_instance);
  449. if (!result)
  450. {
  451. // This fixes a bug in Media Foundation where in some rare cases Native.IsFinished() returns false
  452. result = (GetCurrentTime() > GetDuration());
  453. }
  454. // During buffered playback we need to wait until all frames have been displayed
  455. if (result && _frameSelectionMode != BufferedFrameSelectionMode.None)
  456. {
  457. BufferedFramesState state = GetBufferedFramesState();
  458. if (state.bufferedFrameCount != 0)
  459. {
  460. result = false;
  461. }
  462. }
  463. }
  464. return result;
  465. }
  466. public override bool IsBuffering()
  467. {
  468. return Native.IsBuffering(_instance);
  469. }
  470. public override double GetDuration()
  471. {
  472. return Native.GetDuration(_instance);
  473. }
  474. public override int GetVideoWidth()
  475. {
  476. return _width;
  477. }
  478. public override int GetVideoHeight()
  479. {
  480. return _height;
  481. }
  482. public override float GetVideoFrameRate()
  483. {
  484. return _frameRate;
  485. }
  486. public override Texture GetTexture(int index)
  487. {
  488. Texture result = null;
  489. if (GetTextureFrameCount() > 0)
  490. {
  491. if (_resolvedTexture) { result = _resolvedTexture; }
  492. else { result = _texture; }
  493. }
  494. return result;
  495. }
  496. public override int GetTextureFrameCount()
  497. {
  498. #if AVPROVIDEO_SUPPORT_BUFFERED_DISPLAY
  499. if (_frameSelectionMode != BufferedFrameSelectionMode.None)
  500. {
  501. return (int)_textureFrame.frameCounter;
  502. }
  503. #endif
  504. return Native.GetTextureFrameCount(_instance);
  505. }
  506. public override long GetTextureTimeStamp()
  507. {
  508. #if AVPROVIDEO_SUPPORT_BUFFERED_DISPLAY
  509. if (_frameSelectionMode != BufferedFrameSelectionMode.None)
  510. {
  511. return _textureFrame.timeStamp;
  512. }
  513. #endif
  514. return Native.GetTextureTimeStamp(_instance);
  515. }
  516. // This is DAR/SAR ratio
  517. public override float GetTexturePixelAspectRatio()
  518. {
  519. // Only DirectShow supports this currently as the other APIs create textures already in the final DAR size
  520. // RJT NOTE: Expanded check to include MF as our HAP implementation also returns a PAR
  521. if ((_videoApi == Windows.VideoApi.DirectShow) || (_videoApi == Windows.VideoApi.MediaFoundation))
  522. {
  523. return Native.GetTexturePixelAspectRatio(_instance);
  524. }
  525. return 1f;
  526. }
  527. public override bool RequiresVerticalFlip()
  528. {
  529. return _isTextureTopDown;
  530. }
  531. internal override StereoPacking InternalGetTextureStereoPacking()
  532. {
  533. return Native.GetStereoPacking(_instance);
  534. }
  535. public override void Seek(double time)
  536. {
  537. Native.SetCurrentTime(_instance, time, false);
  538. FlushFrameBuffering(false);
  539. }
  540. public override void SeekFast(double time)
  541. {
  542. Native.SetCurrentTime(_instance, time, true);
  543. FlushFrameBuffering(false);
  544. }
  545. public override double GetCurrentTime()
  546. {
  547. return Native.GetCurrentTime(_instance);
  548. }
  549. public override void SetPlaybackRate(float rate)
  550. {
  551. Native.SetPlaybackRate(_instance, rate);
  552. }
  553. public override float GetPlaybackRate()
  554. {
  555. return Native.GetPlaybackRate(_instance);
  556. }
  557. public override void MuteAudio(bool bMuted)
  558. {
  559. _audioMuted = bMuted;
  560. Native.SetMuted(_instance, _audioMuted);
  561. }
  562. public override bool IsMuted()
  563. {
  564. return _audioMuted;
  565. }
  566. public override void SetVolume(float volume)
  567. {
  568. _volume = volume;
  569. Native.SetVolume(_instance, volume);
  570. }
  571. public override float GetVolume()
  572. {
  573. return _volume;
  574. }
  575. public override void SetBalance(float balance)
  576. {
  577. _balance = balance;
  578. Native.SetBalance(_instance, balance);
  579. }
  580. public override float GetBalance()
  581. {
  582. return _balance;
  583. }
  584. public override bool IsPlaybackStalled()
  585. {
  586. bool result = Native.IsPlaybackStalled(_instance);
  587. if (!result)
  588. {
  589. result = base.IsPlaybackStalled();
  590. }
  591. return result;
  592. }
  593. public override bool WaitForNextFrame(Camera dummyCamera, int previousFrameCount)
  594. {
  595. // Mark as extracting
  596. Native.StartExtractFrame(_instance);
  597. // Queue up render thread event to wait for the new frame
  598. IssueRenderThreadEvent(Native.RenderThreadEvent.WaitForNewFrame);
  599. // Force render thread to run
  600. dummyCamera.Render();
  601. // Wait for the frame to change
  602. Native.WaitForExtract(_instance);
  603. // Return whether the frame changed
  604. return (previousFrameCount != Native.GetTextureFrameCount(_instance));
  605. }
  606. public override void SetAudioChannelMode(Audio360ChannelMode channelMode)
  607. {
  608. _audio360ChannelMode = channelMode;
  609. Native.SetAudioChannelMode(_instance, (int)channelMode);
  610. }
  611. public override void SetAudioHeadRotation(Quaternion q)
  612. {
  613. Native.SetHeadOrientation(_instance, q.x, q.y, q.z, q.w);
  614. }
  615. public override void ResetAudioHeadRotation()
  616. {
  617. Native.SetHeadOrientation(_instance, Quaternion.identity.x, Quaternion.identity.y, Quaternion.identity.z, Quaternion.identity.w);
  618. }
  619. public override void SetAudioFocusEnabled(bool enabled)
  620. {
  621. Native.SetAudioFocusEnabled(_instance, enabled);
  622. }
  623. public override void SetAudioFocusProperties(float offFocusLevel, float widthDegrees)
  624. {
  625. Native.SetAudioFocusProps(_instance, offFocusLevel, widthDegrees);
  626. }
  627. public override void SetAudioFocusRotation(Quaternion q)
  628. {
  629. Native.SetAudioFocusRotation(_instance, q.x, q.y, q.z, q.w);
  630. }
  631. public override void ResetAudioFocus()
  632. {
  633. Native.SetAudioFocusEnabled(_instance, false);
  634. Native.SetAudioFocusProps(_instance, 0f, 90f);
  635. Native.SetAudioFocusRotation(_instance, 0f, 0f, 0f, 1f);
  636. }
  637. //public override void SetAudioDeviceName(string name)
  638. //{
  639. //}
  640. //double timeOfDesiredFrameToDisplay = 0.0;
  641. //int frameFrames = 0;
  642. public override void Update()
  643. {
  644. Native.Update(_instance);
  645. /*Native.GetPlayerState(_instance, ref _playerState);
  646. if (_playerState.status.HasFlag(Native.Status.UpdatedAssetInfo))
  647. {
  648. Native.GetAssetInfo(_instance, ref _assetInfo);
  649. }*/
  650. UpdateTracks();
  651. UpdateTextCue();
  652. _lastError = (ErrorCode)Native.GetLastErrorCode(_instance);
  653. UpdateTimeRanges();
  654. UpdateSubtitles();
  655. if (!_canPlay)
  656. {
  657. if (!_hasMetaData)
  658. {
  659. if (Native.HasMetaData(_instance))
  660. {
  661. if (Native.HasVideo(_instance))
  662. {
  663. _width = Native.GetWidth(_instance);
  664. _height = Native.GetHeight(_instance);
  665. _frameRate = Native.GetFrameRate(_instance);
  666. // Sometimes the dimensions aren't available yet, in which case fail and poll them again next loop
  667. if (_width > 0 && _height > 0)
  668. {
  669. _hasVideo = true;
  670. // Note: If the Unity editor Build platform isn't set to Windows then maxTextureSize will not be correct
  671. if (Mathf.Max(_width, _height) > SystemInfo.maxTextureSize
  672. // If we're running in the editor it may be emulating another platform
  673. // in which case maxTextureSize won't be correct, so ignore it.
  674. #if UNITY_EDITOR
  675. && !SystemInfo.graphicsDeviceName.ToLower().Contains("emulated")
  676. #endif
  677. )
  678. {
  679. Debug.LogError(string.Format("[AVProVideo] Video dimensions ({0}x{1}) larger than maxTextureSize ({2} for current build target)", _width, _height, SystemInfo.maxTextureSize));
  680. _width = _height = 0;
  681. _hasVideo = false;
  682. }
  683. }
  684. if (_hasVideo)
  685. {
  686. if (Native.HasAudio(_instance))
  687. {
  688. _hasAudio = true;
  689. }
  690. }
  691. }
  692. else
  693. {
  694. if (Native.HasAudio(_instance))
  695. {
  696. _hasAudio = true;
  697. }
  698. }
  699. if (_hasVideo || _hasAudio)
  700. {
  701. _hasMetaData = true;
  702. }
  703. _playerDescription = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(Native.GetPlayerDescription(_instance));
  704. _supportsLinearColorSpace = Native.IsTextureSampleLinear(_instance);
  705. Helper.LogInfo("Using playback path: " + _playerDescription + " (" + _width + "x" + _height + "@" + GetVideoFrameRate().ToString("F2") + ")");
  706. if (_hasVideo)
  707. {
  708. OnTextureSizeChanged();
  709. }
  710. }
  711. }
  712. if (_hasMetaData)
  713. {
  714. _canPlay = Native.CanPlay(_instance);
  715. }
  716. }
  717. #if UNITY_WSA
  718. // NOTE: I think this issue has been resolved now as of version 1.5.24.
  719. // The issue was caused by functions returning booleans incorrectly (4 bytes vs 1)
  720. // and as been resolved by specifying the return type during marshalling..
  721. // Still we'll keep this code here until after more testing.
  722. // WSA has an issue where it can load the audio track first and the video track later
  723. // Here we try to handle this case and get the video track information when it arrives
  724. if (_hasAudio && !_hasVideo)
  725. {
  726. _width = Native.GetWidth(_instance);
  727. _height = Native.GetHeight(_instance);
  728. _frameRate = Native.GetFrameRate(_instance);
  729. if (_width > 0 && _height > 0)
  730. {
  731. _hasVideo = true;
  732. OnTextureSizeChanged();
  733. }
  734. }
  735. #endif
  736. // Handle texture creation, resizing, selection
  737. if (_hasVideo)
  738. {
  739. System.IntPtr newTexturePtr = System.IntPtr.Zero;
  740. #if AVPROVIDEO_SUPPORT_BUFFERED_DISPLAY
  741. if (_frameSelectionMode != BufferedFrameSelectionMode.None)
  742. {
  743. UpdateBufferedDisplay();
  744. newTexturePtr = _textureFrame.texturePointer;
  745. }
  746. else
  747. #endif
  748. {
  749. newTexturePtr = Native.GetTexturePointer(_instance);
  750. }
  751. UpdateTexture(newTexturePtr);
  752. }
  753. _playbackQualityStats.Update();
  754. }
  755. private void ReleaseTexture()
  756. {
  757. _nativeTexture = System.IntPtr.Zero;
  758. #if UNITY_EDITOR
  759. if (!Application.isPlaying)
  760. {
  761. if (_resolvedTexture) RenderTexture.DestroyImmediate(_resolvedTexture);
  762. if (_texture) Texture2D.DestroyImmediate(_texture);
  763. }
  764. else
  765. #endif
  766. {
  767. if (_resolvedTexture) RenderTexture.Destroy(_resolvedTexture);
  768. if (_texture) Texture2D.Destroy(_texture);
  769. }
  770. _resolvedTexture = null;
  771. _texture = null;
  772. _textureFrame = new TextureFrame();
  773. #if AVPROVIDEO_FIX_UPDATEEXTERNALTEXTURE_LEAK
  774. _textureFramePrev = new TextureFrame();
  775. #endif
  776. }
  777. private void UpdateTexture(System.IntPtr newPtr)
  778. {
  779. // Check for texture recreation (due to device loss or change in texture size)
  780. if (_texture != null && _nativeTexture != System.IntPtr.Zero && _nativeTexture != newPtr)
  781. {
  782. _width = Native.GetWidth(_instance);
  783. _height = Native.GetHeight(_instance);
  784. if (newPtr == System.IntPtr.Zero)
  785. {
  786. ReleaseTexture();
  787. }
  788. else if (_width != _texture.width || _height != _texture.height)
  789. {
  790. Helper.LogInfo("Texture size changed: " + _width + " X " + _height);
  791. OnTextureSizeChanged();
  792. ReleaseTexture();
  793. }
  794. else if (_nativeTexture != newPtr)
  795. {
  796. if (newPtr != System.IntPtr.Zero)
  797. {
  798. #if AVPROVIDEO_FIX_UPDATEEXTERNALTEXTURE_LEAK
  799. Native.ReleaseTextureFrame(_instance, ref _textureFramePrev);
  800. #endif
  801. _texture.UpdateExternalTexture(newPtr);
  802. #if AVPROVIDEO_FIX_UPDATEEXTERNALTEXTURE_LEAK
  803. _textureFramePrev = _textureFrame;
  804. #endif
  805. }
  806. _nativeTexture = newPtr;
  807. }
  808. }
  809. #if AVPROVIDEO_FIXREGRESSION_TEXTUREQUALITY_UNITY542
  810. // In Unity 5.4.2 and above the video texture turns black when changing the TextureQuality in the Quality Settings
  811. // The code below gets around this issue. A bug report has been sent to Unity. So far we have tested and replicated the
  812. // "bug" in Windows only, but a user has reported it in Android too.
  813. // Texture.GetNativeTexturePtr() must sync with the rendering thread, so this is a large performance hit!
  814. if(_textureQuality != QualitySettings.masterTextureLimit)
  815. {
  816. ApplyTextureQualityChangeFix();
  817. }
  818. #endif
  819. // Check if a new texture has to be created
  820. if (_texture == null && _width > 0 && _height > 0 && newPtr != System.IntPtr.Zero)
  821. {
  822. _isTextureTopDown = Native.IsTextureTopDown(_instance);
  823. bool isLinear = (!_supportsLinearColorSpace && QualitySettings.activeColorSpace == ColorSpace.Linear);
  824. // Texture format
  825. // RJT NOTE: It seems Unity 2022/D3D12 now honours texture format here (internally creating
  826. // an SRV) so 'BGRA32' is no longer valid for some of our native formats (e.g. HAP, NotchLC)
  827. // - Unfortunately, there doesn't appear to be a Unity 'TextureFormat' analog for 'DXGI_FORMAT_R10G10B10A2_UNORM'
  828. // so we're currently working around this by using a format it seems to deem compatible instead
  829. // - Originally used 'ETC_RGB4' on the assumption an invalid format would bypass SRV creation but that
  830. // only worked in editor, so replaced with 'RGB24' which appears to work in builds too
  831. // - https://github.com/RenderHeads/UnityPlugin-AVProVideo/issues/1286
  832. // RJT TODO: Once AVPC is fully integrated and texture formats addressed, move to an (ideally shared!) enum rather than DXGI indices!
  833. // - Also expand to full range of supported formats at that point too
  834. TextureFormat textureFormat = TextureFormat.BGRA32;
  835. int dxgiTextureFormat = Native.GetTextureFormat(_instance);
  836. switch (dxgiTextureFormat)
  837. {
  838. default:
  839. break;
  840. case -1: // 'DXGI_FORMAT_B8G8R8A8_UNORM' (Default)
  841. break;
  842. case 24: // 'DXGI_FORMAT_R10G10B10A2_UNORM'
  843. textureFormat = TextureFormat.RGB24;//ETC_RGB4;
  844. break;
  845. case 71: // 'DXGI_FORMAT_BC1_UNORM'
  846. case 72: // 'DXGI_FORMAT_BC1_UNORM_SRGB'
  847. textureFormat = TextureFormat.DXT1;
  848. break;
  849. case 77: // 'DXGI_FORMAT_BC3_UNORM'
  850. case 78: // 'DXGI_FORMAT_BC3_UNORM_SRGB'
  851. textureFormat = TextureFormat.DXT5;
  852. break;
  853. }
  854. _texture = Texture2D.CreateExternalTexture(_width, _height, textureFormat, UseNativeMips(), isLinear, newPtr);
  855. if (_texture != null)
  856. {
  857. #if AVPROVIDEO_FIX_UPDATEEXTERNALTEXTURE_LEAK
  858. _textureFramePrev = _textureFrame;
  859. #endif
  860. _texture.name = "AVProVideo";
  861. _nativeTexture = newPtr;
  862. _playbackQualityStats.Start(this);
  863. ApplyTextureProperties(_texture);
  864. // Use an intermediate resolved texture?
  865. // RJT NOTE: Currently based on if/how mips are generated but may evolve (see 'Blit()' notes below)
  866. // RJT TODO: Appears support for '_useTextureMips' is not dynamic during a single run? Would be nice to address..
  867. if (_useTextureMips && !UseNativeMips())
  868. {
  869. // RJT TODO: Support 'isLinear'?
  870. _resolvedTexture = new RenderTexture(_width, _height, 0);// RenderTextureFormat.ARGB32);
  871. _resolvedTexture.useMipMap = _resolvedTexture.autoGenerateMips = false;
  872. }
  873. }
  874. else
  875. {
  876. Debug.LogError("[AVProVideo] Failed to create texture");
  877. }
  878. }
  879. // RJT TODO: If we have a resolved texture (Render Target) then blit into it, which will also generate mips if necessary
  880. // - 1. For certain paths (i.e. D3D11/12 hardware) our 'Native.GetTexturePointer()' texture is already an RT
  881. // so is it possible to directly wrap that instead of creating a duplicate RT at this level?
  882. // - 2. There's probably a Unity version regression point at which this fails?
  883. // - I.e. do we still need lower level support? (Ignoring standalone version of AVP etc..)
  884. // - 3. Possible to move this to a higher level for full cross-platform support?
  885. // - This could also become the start of the resolved render discussed, where as well as mip generation we also resolve to a final output texture?
  886. // - I.e. move into caller of above 'GetTexture()' function?
  887. // - 'ApplyMapping()' functions could apply to an internal intermediate texture (/material?) that _then_ gets applied as if it were the
  888. // original texture making sure that rendering performance isn't unecessarily comprimised (i.e. may have to defer/change location)
  889. // - Also, better location than 'Update()'? (I.e. 'Render()'?)
  890. if (_texture && _resolvedTexture)
  891. {
  892. _resolvedTexture.useMipMap = _resolvedTexture.autoGenerateMips = _useTextureMips;
  893. Graphics.Blit(_texture, _resolvedTexture);
  894. }
  895. }
  896. public override void EndUpdate()
  897. {
  898. Native.EndUpdate(_instance);
  899. }
  900. public override long GetLastExtendedErrorCode()
  901. {
  902. return Native.GetLastExtendedErrorCode(_instance);
  903. }
  904. private void OnTextureSizeChanged()
  905. {
  906. }
  907. public override void Render()
  908. {
  909. UpdateDisplayFrameRate();
  910. IssueRenderThreadEvent(Native.RenderThreadEvent.UpdateAllTextures);
  911. }
  912. public override void Dispose()
  913. {
  914. CloseMedia();
  915. }
  916. public override int GrabAudio(float[] buffer, int sampleCount, int channelCount)
  917. {
  918. return Native.GrabAudio(_instance, buffer, sampleCount, channelCount);
  919. }
  920. public override int GetAudioBufferedSampleCount()
  921. {
  922. return Native.GetAudioBufferedSampleCount(_instance);
  923. }
  924. public override bool PlayerSupportsLinearColorSpace()
  925. {
  926. return _supportsLinearColorSpace;
  927. }
  928. public override bool GetDecoderPerformance(ref int activeDecodeThreadCount, ref int decodedFrameCount, ref int droppedFrameCount)
  929. {
  930. return Native.GetDecoderPerformance(_instance, ref activeDecodeThreadCount, ref decodedFrameCount, ref droppedFrameCount);
  931. }
  932. private static int _lastUpdateAllTexturesFrame = -1;
  933. //private static int _lastFreeUnusedTexturesFrame = -1;
  934. private static void IssueRenderThreadEvent(Native.RenderThreadEvent renderEvent)
  935. {
  936. // We only want to update all textures once per Unity frame
  937. if (renderEvent == Native.RenderThreadEvent.UpdateAllTextures)
  938. {
  939. #if UNITY_EDITOR
  940. // In the editor Time.frameCount is not updated when not in play mode, in which case skip this check and always allow rendering
  941. if (Application.isPlaying)
  942. #endif
  943. if (_lastUpdateAllTexturesFrame == Time.frameCount)
  944. return;
  945. _lastUpdateAllTexturesFrame = Time.frameCount;
  946. }
  947. /*else if (renderEvent == Native.RenderThreadEvent.FreeTextures)
  948. {
  949. // We only want to free unused textures once per Unity frame
  950. if (_lastFreeUnusedTexturesFrame == Time.frameCount)
  951. return;
  952. _lastFreeUnusedTexturesFrame = Time.frameCount;
  953. }*/
  954. if (renderEvent == Native.RenderThreadEvent.UpdateAllTextures)
  955. {
  956. GL.IssuePluginEvent(_nativeFunction_UpdateAllTextures, 0);
  957. }
  958. else if (renderEvent == Native.RenderThreadEvent.FreeTextures)
  959. {
  960. GL.IssuePluginEvent(_nativeFunction_FreeTextures, 0);
  961. }
  962. else if (renderEvent == Native.RenderThreadEvent.WaitForNewFrame)
  963. {
  964. GL.IssuePluginEvent(_nativeFunction_ExtractFrame, 0);
  965. }
  966. }
  967. private static string GetPluginVersion()
  968. {
  969. return System.Runtime.InteropServices.Marshal.PtrToStringAnsi(Native.GetPluginVersion());
  970. }
  971. #if AVPROVIDEO_FIXREGRESSION_TEXTUREQUALITY_UNITY542
  972. private void ApplyTextureQualityChangeFix()
  973. {
  974. if (_texture != null && _nativeTexture != System.IntPtr.Zero && _texture.GetNativeTexturePtr() == System.IntPtr.Zero)
  975. {
  976. Debug.LogWarning("[AVProVideo] Applying Texture Quality/Lost Fix");
  977. _texture.UpdateExternalTexture(_nativeTexture);
  978. }
  979. _textureQuality = QualitySettings.masterTextureLimit;
  980. }
  981. public override void OnEnable()
  982. {
  983. base.OnEnable();
  984. ApplyTextureQualityChangeFix();
  985. }
  986. #endif
  987. internal override bool InternalSetActiveTrack(TrackType trackType, int trackUid)
  988. {
  989. bool result = false;
  990. switch (trackType)
  991. {
  992. case TrackType.Video:
  993. case TrackType.Audio:
  994. case TrackType.Text:
  995. {
  996. result = Native.SetActiveTrack(_instance, trackType, trackUid);
  997. break;
  998. }
  999. }
  1000. return result;
  1001. }
  1002. // Has it changed since the last frame 'tick'
  1003. internal override bool InternalIsChangedTextCue()
  1004. {
  1005. return Native.IsChangedTextCue(_instance);
  1006. }
  1007. internal override string InternalGetCurrentTextCue()
  1008. {
  1009. string result = null;
  1010. System.IntPtr ptr = Native.GetCurrentTextCue(_instance);
  1011. if (ptr != System.IntPtr.Zero)
  1012. {
  1013. result = System.Runtime.InteropServices.Marshal.PtrToStringUni(ptr);
  1014. }
  1015. return result;
  1016. }
  1017. // Has it changed since the last frame 'tick'
  1018. internal override bool InternalIsChangedTracks(TrackType trackType)
  1019. {
  1020. bool result = false;
  1021. switch (trackType)
  1022. {
  1023. case TrackType.Video:
  1024. case TrackType.Audio:
  1025. case TrackType.Text:
  1026. {
  1027. result = Native.IsChangedTracks(_instance, trackType);
  1028. break;
  1029. }
  1030. }
  1031. return result;
  1032. }
  1033. internal override int InternalGetTrackCount(TrackType trackType)
  1034. {
  1035. int result = 0;
  1036. switch (trackType)
  1037. {
  1038. case TrackType.Video:
  1039. case TrackType.Audio:
  1040. case TrackType.Text:
  1041. {
  1042. result = Native.GetTrackCount(_instance, trackType);
  1043. break;
  1044. }
  1045. }
  1046. return result;
  1047. }
  1048. internal override TrackBase InternalGetTrackInfo(TrackType trackType, int trackIndex, ref bool isActiveTrack)
  1049. {
  1050. TrackBase result = null;
  1051. switch (trackType)
  1052. {
  1053. case TrackType.Video:
  1054. case TrackType.Audio:
  1055. case TrackType.Text:
  1056. {
  1057. StringBuilder name = new StringBuilder(128);
  1058. StringBuilder language = new StringBuilder(16);
  1059. int uid = -1;
  1060. if (Native.GetTrackInfo(_instance, trackType, trackIndex, ref uid, ref isActiveTrack, name, name.Capacity, language, language.Capacity))
  1061. {
  1062. if (trackType == TrackType.Video)
  1063. {
  1064. result = new VideoTrack(uid, name.ToString(), language.ToString(), false);
  1065. }
  1066. else if (trackType == TrackType.Audio)
  1067. {
  1068. result = new AudioTrack(uid, name.ToString(), language.ToString(), false);
  1069. }
  1070. else if (trackType == TrackType.Text)
  1071. {
  1072. result = new TextTrack(uid, name.ToString(), language.ToString(), false);
  1073. }
  1074. }
  1075. break;
  1076. }
  1077. }
  1078. return result;
  1079. }
  1080. /*private Native.PlayerState _playerState = new Native.PlayerState();
  1081. private Native.AssetInfo _assetInfo = new Native.AssetInfo();*/
  1082. private partial struct Native
  1083. {
  1084. /*[Flags]
  1085. internal enum Status : long
  1086. {
  1087. Unknown = 0,
  1088. UpdatedAssetInfo = 1 << 8,
  1089. UpdatedBufferedTimeRanges = 1 << 10,
  1090. UpdatedSeekableTimeRanges = 1 << 11,
  1091. UpdatedTextCue = 1 << 12,
  1092. UpdatedVideoTracks = 1 << 16,
  1093. UpdatedAudioTracks = 1 << 17,
  1094. UpdatedTextTracks = 1 << 18,
  1095. Failed = 1 << 63
  1096. }
  1097. [StructLayout(LayoutKind.Sequential)]
  1098. internal struct PlayerState
  1099. {
  1100. internal Status status;
  1101. internal double currentTime;
  1102. internal double currentDate;
  1103. }
  1104. [StructLayout(LayoutKind.Sequential)]
  1105. internal struct AssetInfo
  1106. {
  1107. internal double duration;
  1108. internal int width; // current video track
  1109. internal int height; // current video track
  1110. internal float frameRate; // current video track
  1111. internal int videoTrackCount;
  1112. internal int audioTrackCount;
  1113. internal int textTrackCount;
  1114. internal int metadataTrackCount;
  1115. internal int bufferedTimeRangesCount;
  1116. internal int seekableTimeRangesCount;
  1117. }
  1118. [DllImport("AVProVideo")]
  1119. public static extern void GetPlayerState(System.IntPtr instance, ref PlayerState playerState);
  1120. [DllImport("AVProVideo")]
  1121. public static extern void GetAssetInfo(System.IntPtr instance, ref AssetInfo assetInfo);*/
  1122. [DllImport("AVProVideo")]
  1123. [return: MarshalAs(UnmanagedType.I1)]
  1124. public static extern bool IsChangedTracks(System.IntPtr instance, TrackType trackType);
  1125. [DllImport("AVProVideo")]
  1126. public static extern int GetTrackCount(System.IntPtr instance, TrackType trackType);
  1127. [DllImport("AVProVideo")]
  1128. [return: MarshalAs(UnmanagedType.I1)]
  1129. public static extern bool GetTrackInfo(System.IntPtr instance, TrackType trackType, int index, ref int uid,
  1130. ref bool isActive,
  1131. [MarshalAs(UnmanagedType.LPWStr)] StringBuilder name, int maxNameLength,
  1132. [MarshalAs(UnmanagedType.LPWStr)] StringBuilder language, int maxLanguageLength);
  1133. [DllImport("AVProVideo")]
  1134. [return: MarshalAs(UnmanagedType.I1)]
  1135. public static extern bool SetActiveTrack(System.IntPtr instance, TrackType trackType, int trackUid);
  1136. [DllImport("AVProVideo")]
  1137. [return: MarshalAs(UnmanagedType.I1)]
  1138. public static extern bool IsChangedTextCue(System.IntPtr instance);
  1139. [DllImport("AVProVideo")]
  1140. public static extern System.IntPtr GetCurrentTextCue(System.IntPtr instance);
  1141. }
  1142. private void UpdateTimeRanges()
  1143. {
  1144. UpdateTimeRange(ref _seekableTimes._ranges, Native.TimeRangeTypes.Seekable);
  1145. UpdateTimeRange(ref _bufferedTimes._ranges, Native.TimeRangeTypes.Buffered);
  1146. _seekableTimes.CalculateRange();
  1147. _bufferedTimes.CalculateRange();
  1148. }
  1149. private void UpdateTimeRange(ref TimeRange[] range, Native.TimeRangeTypes timeRangeType)
  1150. {
  1151. int newCount = Native.GetTimeRanges(_instance, range, range.Length, timeRangeType);
  1152. if (newCount != range.Length)
  1153. {
  1154. range = new TimeRange[newCount];
  1155. Native.GetTimeRanges(_instance, range, range.Length, timeRangeType);
  1156. }
  1157. }
  1158. private partial struct Native
  1159. {
  1160. internal enum TimeRangeTypes
  1161. {
  1162. Seekable = 0,
  1163. Buffered = 1,
  1164. }
  1165. [DllImport("AVProVideo")]
  1166. public static extern int GetTimeRanges(System.IntPtr playerInstance, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=2)] TimeRange[] ranges, int rangeCount, TimeRangeTypes timeRangeType);
  1167. }
  1168. private partial struct Native
  1169. {
  1170. public enum RenderThreadEvent
  1171. {
  1172. UpdateAllTextures,
  1173. FreeTextures,
  1174. WaitForNewFrame,
  1175. }
  1176. // Global
  1177. [DllImport("AVProVideo")]
  1178. #if AVPROVIDEO_MARSHAL_RETURN_BOOL
  1179. [return: MarshalAs(UnmanagedType.I1)]
  1180. #endif
  1181. public static extern bool Init(bool linearColorSpace, bool isD3D11NoSingleThreaded);
  1182. [DllImport("AVProVideo")]
  1183. public static extern void Deinit();
  1184. [DllImport("AVProVideo")]
  1185. public static extern System.IntPtr GetPluginVersion();
  1186. [DllImport("AVProVideo")]
  1187. #if AVPROVIDEO_MARSHAL_RETURN_BOOL
  1188. [return: MarshalAs(UnmanagedType.I1)]
  1189. #endif
  1190. public static extern bool IsTrialVersion();
  1191. // Open and Close
  1192. [DllImport("AVProVideo")]
  1193. public static extern System.IntPtr BeginOpenSource(System.IntPtr instance, Windows.VideoApi videoApi, Windows.AudioOutput audioOutput, bool useHardwareDecoding,
  1194. bool generateTextureMips, bool hintAlphaChannel, bool useLowLatency, bool use10BitTextures, [MarshalAs(UnmanagedType.LPWStr)]string forceAudioOutputDeviceName,
  1195. int unitySampleRate, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)]IntPtr[] preferredFilter, uint numFilters,
  1196. int audio360ChannelMode);
  1197. [DllImport("AVProVideo")]
  1198. public static extern System.IntPtr EndOpenSource(System.IntPtr instance, [MarshalAs(UnmanagedType.LPWStr)]string path);
  1199. [DllImport("AVProVideo")]
  1200. public static extern System.IntPtr OpenSourceFromBuffer(System.IntPtr instance, byte[] buffer, ulong bufferLength, Windows.VideoApi videoApi, Windows.AudioOutput audioOutput, bool useHardwareDecoding,
  1201. bool generateTextureMips, bool hintAlphaChannel, bool useLowLatency, bool use10BitTextures, [MarshalAs(UnmanagedType.LPWStr)]string forceAudioOutputDeviceName,
  1202. int unitySampleRate, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)]IntPtr[] preferredFilter, uint numFilters);
  1203. [DllImport("AVProVideo")]
  1204. public static extern System.IntPtr StartOpenSourceFromBuffer(System.IntPtr instance, Windows.VideoApi videoApi, ulong bufferLength);
  1205. [DllImport("AVProVideo")]
  1206. #if AVPROVIDEO_MARSHAL_RETURN_BOOL
  1207. [return: MarshalAs(UnmanagedType.I1)]
  1208. #endif
  1209. public static extern bool AddChunkToSourceBuffer(System.IntPtr instance, byte[] buffer, ulong offset, ulong chunkLength);
  1210. [DllImport("AVProVideo")]
  1211. public static extern System.IntPtr EndOpenSourceFromBuffer(System.IntPtr instance, Windows.AudioOutput audioOutput, bool useHardwareDecoding, bool generateTextureMips, bool hintAlphaChannel,
  1212. bool useLowLatency, bool use10BitTextures, [MarshalAs(UnmanagedType.LPWStr)]string forceAudioOutputDeviceName, int unitySampleRate,
  1213. [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)]IntPtr[] preferredFilter, uint numFilters);
  1214. #if NETFX_CORE
  1215. [DllImport("AVProVideo")]
  1216. public static extern System.IntPtr OpenSourceFromStream(System.IntPtr instance, IRandomAccessStream ras,
  1217. [MarshalAs(UnmanagedType.LPWStr)]string path, Windows.VideoApi videoApi, Windows.AudioOutput audioOutput, bool useHardwareDecoding, bool generateTextureMips,
  1218. bool hintAlphaChannel, bool useLowLatency, bool use10BitTextures, [MarshalAs(UnmanagedType.LPWStr)]string forceAudioOutputDeviceName, int unitySampleRate);
  1219. #endif
  1220. [DllImport("AVProVideo")]
  1221. public static extern void CloseSource(System.IntPtr instance);
  1222. [DllImport("AVProVideo")]
  1223. public static extern System.IntPtr GetPlayerDescription(System.IntPtr instance);
  1224. // Custom Filters
  1225. [DllImport("AVProVideo")]
  1226. public static extern void SetCustomMovParserEnabled(System.IntPtr instance, bool enabled);
  1227. [DllImport("AVProVideo")]
  1228. public static extern void SetHapNotchLCEnabled(System.IntPtr instance, bool enabled);
  1229. [DllImport("AVProVideo")]
  1230. public static extern void SetFrameBufferingEnabled(System.IntPtr instance, bool enabled, bool pauseOnPrerollComplete);
  1231. [DllImport("AVProVideo")]
  1232. public static extern void SetStereoDetectEnabled(System.IntPtr instance, bool enabled);
  1233. [DllImport("AVProVideo")]
  1234. public static extern void SetTextTrackSupportEnabled(System.IntPtr instance, bool enabled);
  1235. [DllImport("AVProVideo")]
  1236. public static extern void SetAudioDelayEnabled(System.IntPtr instance, bool enabled, bool isAutomatic, double timeSeconds);
  1237. [DllImport("AVProVideo")]
  1238. public static extern void SetFacebookAudio360SupportEnabled(System.IntPtr instance, bool enabled);
  1239. // Hap & NotchLC Decoder
  1240. [DllImport("AVProVideo")]
  1241. public static extern void SetDecoderHints(System.IntPtr instance, int parallelFrameCount, int prerollFrameCount);
  1242. [DllImport("AVProVideo")]
  1243. #if AVPROVIDEO_MARSHAL_RETURN_BOOL
  1244. [return: MarshalAs(UnmanagedType.I1)]
  1245. #endif
  1246. public static extern bool GetDecoderPerformance(System.IntPtr instance, ref int activeDecodeThreadCount, ref int decodedFrameCount, ref int droppedFrameCount);
  1247. // Errors
  1248. [DllImport("AVProVideo")]
  1249. public static extern int GetLastErrorCode(System.IntPtr instance);
  1250. [DllImport("AVProVideo")]
  1251. public static extern long GetLastExtendedErrorCode(System.IntPtr instance);
  1252. // Controls
  1253. [DllImport("AVProVideo")]
  1254. public static extern void Play(System.IntPtr instance);
  1255. [DllImport("AVProVideo")]
  1256. public static extern void Pause(System.IntPtr instance);
  1257. [DllImport("AVProVideo")]
  1258. public static extern void SetMuted(System.IntPtr instance, bool muted);
  1259. [DllImport("AVProVideo")]
  1260. public static extern void SetVolume(System.IntPtr instance, float volume);
  1261. [DllImport("AVProVideo")]
  1262. public static extern void SetBalance(System.IntPtr instance, float volume);
  1263. [DllImport("AVProVideo")]
  1264. public static extern void SetLooping(System.IntPtr instance, bool looping);
  1265. // Properties
  1266. [DllImport("AVProVideo")]
  1267. #if AVPROVIDEO_MARSHAL_RETURN_BOOL
  1268. [return: MarshalAs(UnmanagedType.I1)]
  1269. #endif
  1270. public static extern bool HasVideo(System.IntPtr instance);
  1271. [DllImport("AVProVideo")]
  1272. #if AVPROVIDEO_MARSHAL_RETURN_BOOL
  1273. [return: MarshalAs(UnmanagedType.I1)]
  1274. #endif
  1275. public static extern bool HasAudio(System.IntPtr instance);
  1276. [DllImport("AVProVideo")]
  1277. public static extern int GetWidth(System.IntPtr instance);
  1278. [DllImport("AVProVideo")]
  1279. public static extern int GetHeight(System.IntPtr instance);
  1280. [DllImport("AVProVideo")]
  1281. public static extern float GetFrameRate(System.IntPtr instance);
  1282. [DllImport("AVProVideo")]
  1283. public static extern StereoPacking GetStereoPacking(System.IntPtr instance);
  1284. [DllImport("AVProVideo")]
  1285. public static extern double GetDuration(System.IntPtr instance);
  1286. [DllImport("AVProVideo")]
  1287. #if AVPROVIDEO_MARSHAL_RETURN_BOOL
  1288. [return: MarshalAs(UnmanagedType.I1)]
  1289. #endif
  1290. public static extern bool IsPlaybackStalled(System.IntPtr instance);
  1291. // State
  1292. [DllImport("AVProVideo")]
  1293. #if AVPROVIDEO_MARSHAL_RETURN_BOOL
  1294. [return: MarshalAs(UnmanagedType.I1)]
  1295. #endif
  1296. public static extern bool HasMetaData(System.IntPtr instance);
  1297. [DllImport("AVProVideo")]
  1298. #if AVPROVIDEO_MARSHAL_RETURN_BOOL
  1299. [return: MarshalAs(UnmanagedType.I1)]
  1300. #endif
  1301. public static extern bool CanPlay(System.IntPtr instance);
  1302. [DllImport("AVProVideo")]
  1303. #if AVPROVIDEO_MARSHAL_RETURN_BOOL
  1304. [return: MarshalAs(UnmanagedType.I1)]
  1305. #endif
  1306. public static extern bool IsSeeking(System.IntPtr instance);
  1307. [DllImport("AVProVideo")]
  1308. #if AVPROVIDEO_MARSHAL_RETURN_BOOL
  1309. [return: MarshalAs(UnmanagedType.I1)]
  1310. #endif
  1311. public static extern bool IsPlaying(System.IntPtr instance);
  1312. [DllImport("AVProVideo")]
  1313. #if AVPROVIDEO_MARSHAL_RETURN_BOOL
  1314. [return: MarshalAs(UnmanagedType.I1)]
  1315. #endif
  1316. public static extern bool IsFinished(System.IntPtr instance);
  1317. [DllImport("AVProVideo")]
  1318. #if AVPROVIDEO_MARSHAL_RETURN_BOOL
  1319. [return: MarshalAs(UnmanagedType.I1)]
  1320. #endif
  1321. public static extern bool IsBuffering(System.IntPtr instance);
  1322. [DllImport("AVProVideo")]
  1323. public static extern double GetCurrentTime(System.IntPtr instance);
  1324. [DllImport("AVProVideo")]
  1325. public static extern void SetCurrentTime(System.IntPtr instance, double time, bool fast);
  1326. [DllImport("AVProVideo")]
  1327. public static extern float GetPlaybackRate(System.IntPtr instance);
  1328. [DllImport("AVProVideo")]
  1329. public static extern void SetPlaybackRate(System.IntPtr instance, float rate);
  1330. [DllImport("AVProVideo")]
  1331. public static extern void StartExtractFrame(System.IntPtr instance);
  1332. [DllImport("AVProVideo")]
  1333. public static extern void WaitForExtract(System.IntPtr instance);
  1334. // Update and Rendering
  1335. [DllImport("AVProVideo")]
  1336. public static extern void Update(System.IntPtr instance);
  1337. [DllImport("AVProVideo")]
  1338. public static extern void EndUpdate(System.IntPtr instance);
  1339. [DllImport("AVProVideo")]
  1340. public static extern System.IntPtr GetTexturePointer(System.IntPtr instance);
  1341. [DllImport("AVProVideo")]
  1342. public static extern int GetTextureFormat(System.IntPtr instance);
  1343. [DllImport("AVProVideo")]
  1344. #if AVPROVIDEO_MARSHAL_RETURN_BOOL
  1345. [return: MarshalAs(UnmanagedType.I1)]
  1346. #endif
  1347. public static extern bool IsTextureTopDown(System.IntPtr instance);
  1348. [DllImport("AVProVideo")]
  1349. #if AVPROVIDEO_MARSHAL_RETURN_BOOL
  1350. [return: MarshalAs(UnmanagedType.I1)]
  1351. #endif
  1352. public static extern bool IsTextureSampleLinear(System.IntPtr instance);
  1353. [DllImport("AVProVideo")]
  1354. public static extern int GetTextureFrameCount(System.IntPtr instance);
  1355. [DllImport("AVProVideo")]
  1356. public static extern long GetTextureTimeStamp(System.IntPtr instance);
  1357. [DllImport("AVProVideo")]
  1358. public static extern float GetTexturePixelAspectRatio(System.IntPtr instance);
  1359. [DllImport("AVProVideo")]
  1360. public static extern System.IntPtr GetRenderEventFunc_UpdateAllTextures();
  1361. [DllImport("AVProVideo")]
  1362. public static extern System.IntPtr GetRenderEventFunc_FreeTextures();
  1363. [DllImport("AVProVideo")]
  1364. public static extern System.IntPtr GetRenderEventFunc_WaitForNewFrame();
  1365. // Audio Grabbing
  1366. [DllImport("AVProVideo")]
  1367. public static extern int GrabAudio(System.IntPtr instance, float[] buffer, int sampleCount, int channelCount);
  1368. [DllImport("AVProVideo")]
  1369. public static extern int GetAudioBufferedSampleCount(System.IntPtr instance);
  1370. [DllImport("AVProVideo")]
  1371. public static extern int GetAudioChannelCount(System.IntPtr instance);
  1372. [DllImport("AVProVideo")]
  1373. public static extern int GetAudioChannelMask(System.IntPtr instance);
  1374. // Audio 360
  1375. [DllImport("AVProVideo")]
  1376. public static extern int SetAudioChannelMode(System.IntPtr instance, int audio360ChannelMode);
  1377. [DllImport("AVProVideo")]
  1378. public static extern void SetHeadOrientation(System.IntPtr instance, float x, float y, float z, float w);
  1379. [DllImport("AVProVideo")]
  1380. public static extern void SetAudioFocusEnabled(System.IntPtr instance, bool enabled);
  1381. [DllImport("AVProVideo")]
  1382. public static extern void SetAudioFocusProps(System.IntPtr instance, float offFocusLevel, float widthDegrees);
  1383. [DllImport("AVProVideo")]
  1384. public static extern void SetAudioFocusRotation(System.IntPtr instance, float x, float y, float z, float w);
  1385. }
  1386. }
  1387. }
  1388. #endif