WindowsMediaPlayer.cs 53 KB

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