AndroidMediaPlayer.cs 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708
  1. // NOTE: We only allow this script to compile in editor so we can easily check for compilation issues
  2. #if (UNITY_EDITOR || UNITY_ANDROID)
  3. #define AVPROVIDEO_FIXREGRESSION_TEXTUREQUALITY_UNITY542
  4. #define DLL_METHODS
  5. using UnityEngine;
  6. using System;
  7. using System.Text;
  8. using System.Runtime.InteropServices;
  9. //-----------------------------------------------------------------------------
  10. // Copyright 2015-2021 RenderHeads Ltd. All rights reserved.
  11. //-----------------------------------------------------------------------------
  12. namespace RenderHeads.Media.AVProVideo
  13. {
  14. /// <summary>
  15. /// Android implementation of BaseMediaPlayer
  16. /// </summary>
  17. // TODO: seal this class
  18. public class AndroidMediaPlayer : BaseMediaPlayer
  19. {
  20. protected static AndroidJavaObject s_ActivityContext = null;
  21. protected static AndroidJavaObject s_Interface = null;
  22. protected static bool s_bInitialised = false;
  23. private static string s_Version = "Plug-in not yet initialised";
  24. private static System.IntPtr _nativeFunction_RenderEvent = System.IntPtr.Zero;
  25. protected AndroidJavaObject m_Video;
  26. private Texture2D m_Texture;
  27. private int m_TextureHandle;
  28. private bool m_UseFastOesPath;
  29. // private string m_AuthToken;
  30. private double m_Duration = 0.0;
  31. private int m_Width = 0;
  32. private int m_Height = 0;
  33. protected int m_iPlayerIndex = -1;
  34. private Android.VideoApi m_API;
  35. private bool m_HeadRotationEnabled = false;
  36. private bool m_FocusEnabled = false;
  37. private System.IntPtr m_Method_Update;
  38. private System.IntPtr m_Method_SetHeadRotation;
  39. private System.IntPtr m_Method_GetCurrentTimeS;
  40. private System.IntPtr m_Method_GetSourceVideoFrameRate;
  41. private System.IntPtr m_Method_IsPlaying;
  42. private System.IntPtr m_Method_IsPaused;
  43. private System.IntPtr m_Method_IsFinished;
  44. private System.IntPtr m_Method_IsSeeking;
  45. private System.IntPtr m_Method_IsBuffering;
  46. private System.IntPtr m_Method_IsLooping;
  47. private System.IntPtr m_Method_HasVideo;
  48. private System.IntPtr m_Method_HasAudio;
  49. private System.IntPtr m_Method_HasMetaData;
  50. private System.IntPtr m_Method_SetFocusProps;
  51. private System.IntPtr m_Method_SetFocusEnabled;
  52. private System.IntPtr m_Method_SetFocusRotation;
  53. private jvalue[] m_Value0 = new jvalue[0];
  54. private jvalue[] m_Value1 = new jvalue[1];
  55. private jvalue[] m_Value2 = new jvalue[2];
  56. private jvalue[] m_Value4 = new jvalue[4];
  57. private MediaPlayer.OptionsAndroid m_Options;
  58. private enum NativeStereoPacking : int
  59. {
  60. Unknown = -1, // Unknown
  61. Monoscopic = 0, // Monoscopic
  62. TopBottom = 1, // Top is the left eye, bottom is the right eye
  63. LeftRight = 2, // Left is the left eye, right is the right eye
  64. Mesh = 3, // Use the mesh UV to unpack, uv0=left eye, uv1=right eye
  65. }
  66. #if AVPROVIDEO_FIXREGRESSION_TEXTUREQUALITY_UNITY542
  67. private int _textureQuality = QualitySettings.masterTextureLimit;
  68. #endif
  69. static private System.Threading.Thread m_MainThread;
  70. public static bool InitialisePlatform()
  71. {
  72. m_MainThread = System.Threading.Thread.CurrentThread;
  73. // Get the activity context
  74. if (s_ActivityContext == null)
  75. {
  76. AndroidJavaClass activityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
  77. if (activityClass != null)
  78. {
  79. s_ActivityContext = activityClass.GetStatic<AndroidJavaObject>("currentActivity");
  80. }
  81. }
  82. if (!s_bInitialised)
  83. {
  84. s_Interface = new AndroidJavaObject("com.renderheads.AVPro.Video.Manager");
  85. if (s_Interface != null)
  86. {
  87. s_Version = s_Interface.Call<string>("GetPluginVersion");
  88. s_Interface.Call("SetContext", s_ActivityContext);
  89. // Calling this native function cause the .SO library to become loaded
  90. // This is important for Unity < 5.2.0 where GL.IssuePluginEvent works differently
  91. _nativeFunction_RenderEvent = Native.GetRenderEventFunc();
  92. if (_nativeFunction_RenderEvent != IntPtr.Zero)
  93. {
  94. s_bInitialised = true;
  95. }
  96. }
  97. }
  98. return s_bInitialised;
  99. }
  100. public static void DeinitPlatform()
  101. {
  102. if (s_bInitialised)
  103. {
  104. if (s_Interface != null)
  105. {
  106. s_Interface.CallStatic("Deinitialise");
  107. s_Interface = null;
  108. }
  109. s_ActivityContext = null;
  110. s_bInitialised = false;
  111. }
  112. }
  113. private static void IssuePluginEvent(Native.AVPPluginEvent type, int param)
  114. {
  115. // Build eventId from the type and param.
  116. int eventId = 0x5d5ac000 | ((int)type << 8);
  117. switch (type)
  118. {
  119. case Native.AVPPluginEvent.PlayerSetup:
  120. case Native.AVPPluginEvent.PlayerUpdate:
  121. case Native.AVPPluginEvent.PlayerDestroy:
  122. case Native.AVPPluginEvent.ExtractFrame:
  123. {
  124. eventId |= param & 0xff;
  125. }
  126. break;
  127. }
  128. GL.IssuePluginEvent(_nativeFunction_RenderEvent, eventId);
  129. }
  130. private System.IntPtr GetMethod(string methodName, string signature)
  131. {
  132. Debug.Assert(m_Video != null);
  133. System.IntPtr result = AndroidJNIHelper.GetMethodID(m_Video.GetRawClass(), methodName, signature, false);
  134. Debug.Assert(result != System.IntPtr.Zero);
  135. if (result == System.IntPtr.Zero)
  136. {
  137. Debug.LogError("[AVProVideo] Unable to get method " + methodName + " " + signature);
  138. throw new System.Exception("[AVProVideo] Unable to get method " + methodName + " " + signature);
  139. }
  140. return result;
  141. }
  142. public AndroidMediaPlayer(MediaPlayer.OptionsAndroid options) : base()
  143. {
  144. Debug.Assert(s_Interface != null);
  145. Debug.Assert(s_bInitialised);
  146. m_Options = options;
  147. m_API = options.videoApi;
  148. if (SystemInfo.graphicsDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Vulkan)
  149. {
  150. Debug.LogWarning("[AVProVideo] Vulkan graphics API is not supported. Please select OpenGL ES 2.0 and 3.0 are supported on Android.");
  151. }
  152. #if UNITY_2017_2_OR_NEWER
  153. Vector2 vPreferredVideo = GetPreferredVideoResolution(options.preferredMaximumResolution, options.customPreferredMaximumResolution);
  154. #else
  155. Vector2 vPreferredVideo = GetPreferredVideoResolution(options.preferredMaximumResolution, new Vector2(0.0f, 0.0f));
  156. #endif
  157. // Create a java-size video class up front
  158. Debug.Log("s_Interface " + s_Interface);
  159. m_Video = s_Interface.Call<AndroidJavaObject>( "CreatePlayer", (int)(m_API), options.useFastOesPath, options.preferSoftwareDecoder, (int)(options.audioOutput), (int)(options.audio360ChannelMode), Helper.GetUnityAudioSampleRate(),
  160. options.StartWithHighestBandwidth(), options.minBufferMs, options.maxBufferMs, options.bufferForPlaybackMs, options.bufferForPlaybackAfterRebufferMs,
  161. (int)(options.GetPreferredPeakBitRateInBitsPerSecond()), (int)(vPreferredVideo.x), (int)(vPreferredVideo.y), (int)(options.blitTextureFiltering) );
  162. Debug.Log("m_Video " + m_Video);
  163. if (m_Video != null)
  164. {
  165. m_Method_Update = GetMethod("Update", "()V");
  166. m_Method_SetHeadRotation = GetMethod("SetHeadRotation", "(FFFF)V");
  167. m_Method_SetFocusProps = GetMethod("SetFocusProps", "(FF)V");
  168. m_Method_SetFocusEnabled = GetMethod("SetFocusEnabled", "(Z)V");
  169. m_Method_SetFocusRotation = GetMethod("SetFocusRotation", "(FFFF)V");
  170. m_Method_GetCurrentTimeS = GetMethod("GetCurrentTimeS", "()D");
  171. m_Method_GetSourceVideoFrameRate = GetMethod("GetSourceVideoFrameRate", "()F");
  172. m_Method_IsPlaying = GetMethod("IsPlaying", "()Z");
  173. m_Method_IsPaused = GetMethod("IsPaused", "()Z");
  174. m_Method_IsFinished = GetMethod("IsFinished", "()Z");
  175. m_Method_IsSeeking = GetMethod("IsSeeking", "()Z");
  176. m_Method_IsBuffering = GetMethod("IsBuffering", "()Z");
  177. m_Method_IsLooping = GetMethod("IsLooping", "()Z");
  178. m_Method_HasVideo = GetMethod("HasVideo", "()Z");
  179. m_Method_HasAudio = GetMethod("HasAudio", "()Z");
  180. m_Method_HasMetaData = GetMethod("HasMetaData", "()Z");
  181. m_iPlayerIndex = m_Video.Call<int>("GetPlayerIndex");
  182. Helper.LogInfo("Creating player " + m_iPlayerIndex);
  183. SetOptions(options.useFastOesPath, options.showPosterFrame);
  184. // Initialise renderer, on the render thread
  185. AndroidMediaPlayer.IssuePluginEvent(Native.AVPPluginEvent.PlayerSetup, m_iPlayerIndex);
  186. }
  187. else
  188. {
  189. Debug.LogError("[AVProVideo] Failed to create player instance");
  190. }
  191. }
  192. public void SetOptions(bool useFastOesPath, bool showPosterFrame)
  193. {
  194. m_UseFastOesPath = useFastOesPath;
  195. if (m_Video != null)
  196. {
  197. // Show poster frame is only needed when using the MediaPlayer API
  198. showPosterFrame = (m_API == Android.VideoApi.MediaPlayer) ? showPosterFrame:false;
  199. m_Video.Call("SetPlayerOptions", m_UseFastOesPath, showPosterFrame);
  200. }
  201. }
  202. public override long GetEstimatedTotalBandwidthUsed()
  203. {
  204. long result = -1;
  205. if (s_Interface != null)
  206. {
  207. result = m_Video.Call<long>("GetEstimatedBandwidthUsed");
  208. }
  209. return result;
  210. }
  211. public override string GetVersion()
  212. {
  213. return s_Version;
  214. }
  215. public override string GetExpectedVersion()
  216. {
  217. return Helper.ExpectedPluginVersion.Android;
  218. }
  219. public override bool OpenMedia(string path, long offset, string httpHeader, MediaHints mediaHints, int forceFileFormat = 0, bool startWithHighestBitrate = false)
  220. {
  221. bool bReturn = false;
  222. if (m_Video != null)
  223. {
  224. _mediaHints = mediaHints;
  225. Debug.Assert(m_Width == 0 && m_Height == 0 && m_Duration == 0.0);
  226. bReturn = m_Video.Call<bool>("OpenVideoFromFile", path, offset, httpHeader, forceFileFormat, (int)(m_Options.audioOutput), (int)(m_Options.audio360ChannelMode));
  227. if (!bReturn)
  228. {
  229. DisplayLoadFailureSuggestion(path);
  230. }
  231. }
  232. else
  233. {
  234. Debug.LogError("[AVProVideo] m_Video is null!");
  235. }
  236. return bReturn;
  237. }
  238. public override void SetKeyServerAuthToken(string token)
  239. {
  240. if (m_Video != null)
  241. {
  242. m_Video.Call("SetKeyServerAuthToken", token);
  243. }
  244. }
  245. public override void SetOverrideDecryptionKey(byte[] key)
  246. {
  247. if( m_Video != null )
  248. {
  249. m_Video.Call("SetOverrideDecryptionKey", key);
  250. }
  251. }
  252. private void DisplayLoadFailureSuggestion(string path)
  253. {
  254. if (path.ToLower().Contains("http://"))
  255. {
  256. Debug.LogError("Android 8 and above require HTTPS by default, change to HTTPS or enable ClearText in the AndroidManifest.xml");
  257. }
  258. }
  259. public override void CloseMedia()
  260. {
  261. if (m_Texture != null)
  262. {
  263. Texture2D.Destroy(m_Texture);
  264. m_Texture = null;
  265. }
  266. m_TextureHandle = 0;
  267. m_Duration = 0.0;
  268. m_Width = 0;
  269. m_Height = 0;
  270. if (m_Video != null)
  271. {
  272. m_Video.Call("CloseVideo");
  273. }
  274. base.CloseMedia();
  275. }
  276. public override void SetLooping( bool bLooping )
  277. {
  278. if( m_Video != null )
  279. {
  280. m_Video.Call("SetLooping", bLooping);
  281. }
  282. }
  283. public override bool IsLooping()
  284. {
  285. bool result = false;
  286. if( m_Video != null )
  287. {
  288. if (m_Method_IsLooping != System.IntPtr.Zero)
  289. {
  290. result = AndroidJNI.CallBooleanMethod(m_Video.GetRawObject(), m_Method_IsLooping, m_Value0);
  291. }
  292. else
  293. {
  294. result = m_Video.Call<bool>("IsLooping");
  295. }
  296. }
  297. return result;
  298. }
  299. public override bool HasVideo()
  300. {
  301. bool result = false;
  302. if( m_Video != null )
  303. {
  304. if (m_Method_HasVideo != System.IntPtr.Zero)
  305. {
  306. result = AndroidJNI.CallBooleanMethod(m_Video.GetRawObject(), m_Method_HasVideo, m_Value0);
  307. }
  308. else
  309. {
  310. result = m_Video.Call<bool>("HasVideo");
  311. }
  312. }
  313. return result;
  314. }
  315. public override bool HasAudio()
  316. {
  317. bool result = false;
  318. if( m_Video != null )
  319. {
  320. if (m_Method_HasAudio != System.IntPtr.Zero)
  321. {
  322. result = AndroidJNI.CallBooleanMethod(m_Video.GetRawObject(), m_Method_HasAudio, m_Value0);
  323. }
  324. else
  325. {
  326. result = m_Video.Call<bool>("HasAudio");
  327. }
  328. }
  329. return result;
  330. }
  331. public override bool HasMetaData()
  332. {
  333. bool result = false;
  334. if (m_Video != null)
  335. {
  336. if (m_Method_HasMetaData != System.IntPtr.Zero)
  337. {
  338. result = AndroidJNI.CallBooleanMethod(m_Video.GetRawObject(), m_Method_HasMetaData, m_Value0);
  339. }
  340. else
  341. {
  342. result = m_Video.Call<bool>("HasMetaData");
  343. }
  344. }
  345. return result;
  346. }
  347. public override bool CanPlay()
  348. {
  349. bool result = false;
  350. #if DLL_METHODS
  351. result = Native._CanPlay( m_iPlayerIndex );
  352. #else
  353. if (m_Video != null)
  354. {
  355. result = m_Video.Call<bool>("CanPlay");
  356. }
  357. #endif
  358. return result;
  359. }
  360. public override void Play()
  361. {
  362. if (m_Video != null)
  363. {
  364. m_Video.Call("Play");
  365. }
  366. }
  367. public override void Pause()
  368. {
  369. if (m_Video != null)
  370. {
  371. m_Video.Call("Pause");
  372. }
  373. }
  374. public override void Stop()
  375. {
  376. if (m_Video != null)
  377. {
  378. // On Android we never need to actually Stop the playback, pausing is fine
  379. m_Video.Call("Pause");
  380. }
  381. }
  382. public override void Seek(double time)
  383. {
  384. if (m_Video != null)
  385. {
  386. // time is in seconds
  387. m_Video.Call("Seek", time);
  388. }
  389. }
  390. public override void SeekFast(double time)
  391. {
  392. if (m_Video != null)
  393. {
  394. // time is in seconds
  395. m_Video.Call("SeekFast", time);
  396. }
  397. }
  398. public override double GetCurrentTime()
  399. {
  400. double result = 0.0;
  401. if (m_Video != null)
  402. {
  403. if (m_Method_GetCurrentTimeS != System.IntPtr.Zero)
  404. {
  405. result = AndroidJNI.CallDoubleMethod(m_Video.GetRawObject(), m_Method_GetCurrentTimeS, m_Value0);
  406. }
  407. else
  408. {
  409. result = (double)m_Video.Call<double>("GetCurrentTimeS");
  410. }
  411. }
  412. return result;
  413. }
  414. public override void SetPlaybackRate(float rate)
  415. {
  416. if (m_Video != null)
  417. {
  418. m_Video.Call("SetPlaybackRate", rate);
  419. }
  420. }
  421. public override float GetPlaybackRate()
  422. {
  423. float result = 0.0f;
  424. if (m_Video != null)
  425. {
  426. result = m_Video.Call<float>("GetPlaybackRate");
  427. }
  428. return result;
  429. }
  430. public override void SetAudioHeadRotation(Quaternion q)
  431. {
  432. if (m_Video != null)
  433. {
  434. if (!m_HeadRotationEnabled)
  435. {
  436. m_Video.Call("SetPositionTrackingEnabled", true);
  437. m_HeadRotationEnabled = true;
  438. }
  439. if (m_Method_SetHeadRotation != System.IntPtr.Zero)
  440. {
  441. m_Value4[0].f = q.x;
  442. m_Value4[1].f = q.y;
  443. m_Value4[2].f = q.z;
  444. m_Value4[3].f = q.w;
  445. AndroidJNI.CallVoidMethod(m_Video.GetRawObject(), m_Method_SetHeadRotation, m_Value4);
  446. }
  447. else
  448. {
  449. m_Video.Call("SetHeadRotation", q.x, q.y, q.z, q.w);
  450. }
  451. }
  452. }
  453. public override void ResetAudioHeadRotation()
  454. {
  455. if (m_Video != null && m_HeadRotationEnabled)
  456. {
  457. m_Video.Call("SetPositionTrackingEnabled", false);
  458. m_HeadRotationEnabled = false;
  459. }
  460. }
  461. public override void SetAudioFocusEnabled(bool enabled)
  462. {
  463. if (m_Video != null && enabled != m_FocusEnabled)
  464. {
  465. if (m_Method_SetFocusEnabled != System.IntPtr.Zero)
  466. {
  467. m_Value1[0].z = enabled;
  468. AndroidJNI.CallVoidMethod(m_Video.GetRawObject(), m_Method_SetFocusEnabled, m_Value1);
  469. }
  470. else
  471. {
  472. m_Video.Call("SetFocusEnabled", enabled);
  473. }
  474. m_FocusEnabled = enabled;
  475. }
  476. }
  477. public override void SetAudioFocusProperties(float offFocusLevel, float widthDegrees)
  478. {
  479. if(m_Video != null && m_FocusEnabled)
  480. {
  481. if (m_Method_SetFocusProps != System.IntPtr.Zero)
  482. {
  483. m_Value2[0].f = offFocusLevel;
  484. m_Value2[1].f = widthDegrees;
  485. AndroidJNI.CallVoidMethod(m_Video.GetRawObject(), m_Method_SetFocusProps, m_Value2);
  486. }
  487. else
  488. {
  489. m_Video.Call("SetFocusProps", offFocusLevel, widthDegrees);
  490. }
  491. }
  492. }
  493. public override void SetAudioFocusRotation(Quaternion q)
  494. {
  495. if (m_Video != null && m_FocusEnabled)
  496. {
  497. if (m_Method_SetFocusRotation != System.IntPtr.Zero)
  498. {
  499. m_Value4[0].f = q.x;
  500. m_Value4[1].f = q.y;
  501. m_Value4[2].f = q.z;
  502. m_Value4[3].f = q.w;
  503. AndroidJNI.CallVoidMethod(m_Video.GetRawObject(), m_Method_SetFocusRotation, m_Value4);
  504. }
  505. else
  506. {
  507. m_Video.Call("SetFocusRotation", q.x, q.y, q.z, q.w);
  508. }
  509. }
  510. }
  511. public override void ResetAudioFocus()
  512. {
  513. if (m_Video != null)
  514. {
  515. if (m_Method_SetFocusProps != System.IntPtr.Zero &&
  516. m_Method_SetFocusEnabled != System.IntPtr.Zero &&
  517. m_Method_SetFocusRotation != System.IntPtr.Zero)
  518. {
  519. m_Value2[0].f = 0f;
  520. m_Value2[1].f = 90f;
  521. AndroidJNI.CallVoidMethod(m_Video.GetRawObject(), m_Method_SetFocusProps, m_Value2);
  522. m_Value1[0].z = false;
  523. AndroidJNI.CallVoidMethod(m_Video.GetRawObject(), m_Method_SetFocusEnabled, m_Value1);
  524. m_Value4[0].f = 0f;
  525. m_Value4[1].f = 0f;
  526. m_Value4[2].f = 0f;
  527. m_Value4[3].f = 1f;
  528. AndroidJNI.CallVoidMethod(m_Video.GetRawObject(), m_Method_SetFocusRotation, m_Value4);
  529. }
  530. else
  531. {
  532. m_Video.Call("SetFocusProps", 0f, 90f);
  533. m_Video.Call("SetFocusEnabled", false);
  534. m_Video.Call("SetFocusRotation", 0f, 0f, 0f, 1f);
  535. }
  536. }
  537. }
  538. public override double GetDuration()
  539. {
  540. return m_Duration;
  541. }
  542. public override int GetVideoWidth()
  543. {
  544. return m_Width;
  545. }
  546. public override int GetVideoHeight()
  547. {
  548. return m_Height;
  549. }
  550. public override float GetVideoFrameRate()
  551. {
  552. float result = 0.0f;
  553. if( m_Video != null )
  554. {
  555. if (m_Method_GetSourceVideoFrameRate != System.IntPtr.Zero)
  556. {
  557. result = AndroidJNI.CallFloatMethod(m_Video.GetRawObject(), m_Method_GetSourceVideoFrameRate, m_Value0);
  558. }
  559. else
  560. {
  561. result = m_Video.Call<float>("GetSourceVideoFrameRate");
  562. }
  563. }
  564. return result;
  565. }
  566. public override float GetVideoDisplayRate()
  567. {
  568. float result = 0.0f;
  569. #if DLL_METHODS
  570. result = Native._GetVideoDisplayRate( m_iPlayerIndex );
  571. #else
  572. if (m_Video != null)
  573. {
  574. result = m_Video.Call<float>("GetDisplayRate");
  575. }
  576. #endif
  577. return result;
  578. }
  579. public override bool IsSeeking()
  580. {
  581. bool result = false;
  582. if (m_Video != null)
  583. {
  584. if (m_Method_IsSeeking != System.IntPtr.Zero)
  585. {
  586. result = AndroidJNI.CallBooleanMethod(m_Video.GetRawObject(), m_Method_IsSeeking, m_Value0);
  587. }
  588. else
  589. {
  590. result = m_Video.Call<bool>("IsSeeking");
  591. }
  592. }
  593. return result;
  594. }
  595. public override bool IsPlaying()
  596. {
  597. bool result = false;
  598. if (m_Video != null)
  599. {
  600. if (m_Method_IsPlaying != System.IntPtr.Zero)
  601. {
  602. result = AndroidJNI.CallBooleanMethod(m_Video.GetRawObject(), m_Method_IsPlaying, m_Value0);
  603. }
  604. else
  605. {
  606. result = m_Video.Call<bool>("IsPlaying");
  607. }
  608. }
  609. return result;
  610. }
  611. public override bool IsPaused()
  612. {
  613. bool result = false;
  614. if (m_Video != null)
  615. {
  616. if (m_Method_IsPaused != System.IntPtr.Zero)
  617. {
  618. result = AndroidJNI.CallBooleanMethod(m_Video.GetRawObject(), m_Method_IsPaused, m_Value0);
  619. }
  620. else
  621. {
  622. result = m_Video.Call<bool>("IsPaused");
  623. }
  624. }
  625. return result;
  626. }
  627. public override bool IsFinished()
  628. {
  629. bool result = false;
  630. if (m_Video != null)
  631. {
  632. if (m_Method_IsFinished != System.IntPtr.Zero)
  633. {
  634. result = AndroidJNI.CallBooleanMethod(m_Video.GetRawObject(), m_Method_IsFinished, m_Value0);
  635. }
  636. else
  637. {
  638. result = m_Video.Call<bool>("IsFinished");
  639. }
  640. }
  641. return result;
  642. }
  643. public override bool IsBuffering()
  644. {
  645. bool result = false;
  646. if (m_Video != null)
  647. {
  648. if (m_Method_IsBuffering != System.IntPtr.Zero)
  649. {
  650. result = AndroidJNI.CallBooleanMethod(m_Video.GetRawObject(), m_Method_IsBuffering, m_Value0);
  651. }
  652. else
  653. {
  654. result = m_Video.Call<bool>("IsBuffering");
  655. }
  656. }
  657. return result;
  658. }
  659. public override Texture GetTexture( int index )
  660. {
  661. Texture result = null;
  662. if (GetTextureFrameCount() > 0)
  663. {
  664. result = m_Texture;
  665. }
  666. return result;
  667. }
  668. public override int GetTextureFrameCount()
  669. {
  670. int result = 0;
  671. if( m_Texture != null )
  672. {
  673. #if DLL_METHODS
  674. result = Native._GetFrameCount( m_iPlayerIndex );
  675. #else
  676. if (m_Video != null)
  677. {
  678. result = m_Video.Call<int>("GetFrameCount");
  679. }
  680. #endif
  681. }
  682. return result;
  683. }
  684. internal override StereoPacking InternalGetTextureStereoPacking()
  685. {
  686. StereoPacking result = StereoPacking.Unknown;
  687. if (m_Video != null)
  688. {
  689. NativeStereoPacking internalStereoMode = (NativeStereoPacking)( m_Video.Call<int>("GetCurrentVideoTrackStereoMode") );
  690. switch( internalStereoMode )
  691. {
  692. case NativeStereoPacking.Monoscopic: result = StereoPacking.None; break;
  693. case NativeStereoPacking.TopBottom: result = StereoPacking.TopBottom; break;
  694. case NativeStereoPacking.LeftRight: result = StereoPacking.LeftRight; break;
  695. case NativeStereoPacking.Mesh: result = StereoPacking.Unknown; break;
  696. }
  697. }
  698. return result;
  699. }
  700. public override bool RequiresVerticalFlip()
  701. {
  702. return false;
  703. }
  704. public override void MuteAudio(bool bMuted)
  705. {
  706. if (m_Video != null)
  707. {
  708. m_Video.Call("MuteAudio", bMuted);
  709. }
  710. }
  711. public override bool IsMuted()
  712. {
  713. bool result = false;
  714. if( m_Video != null )
  715. {
  716. result = m_Video.Call<bool>("IsMuted");
  717. }
  718. return result;
  719. }
  720. public override void SetVolume(float volume)
  721. {
  722. if (m_Video != null)
  723. {
  724. m_Video.Call("SetVolume", volume);
  725. }
  726. }
  727. public override float GetVolume()
  728. {
  729. float result = 0.0f;
  730. if( m_Video != null )
  731. {
  732. result = m_Video.Call<float>("GetVolume");
  733. }
  734. return result;
  735. }
  736. public override void SetBalance(float balance)
  737. {
  738. if( m_Video != null )
  739. {
  740. m_Video.Call("SetAudioPan", balance);
  741. }
  742. }
  743. public override float GetBalance()
  744. {
  745. float result = 0.0f;
  746. if( m_Video != null )
  747. {
  748. result = m_Video.Call<float>("GetAudioPan");
  749. }
  750. return result;
  751. }
  752. public override bool WaitForNextFrame(Camera dummyCamera, int previousFrameCount)
  753. {
  754. // Mark as extracting
  755. bool isMultiThreaded = m_Video.Call<bool>("StartExtractFrame");
  756. // In single threaded Android this method won't work, so just return
  757. if (isMultiThreaded)
  758. {
  759. // Queue up render thread event to wait for the new frame
  760. IssuePluginEvent(Native.AVPPluginEvent.ExtractFrame, m_iPlayerIndex);
  761. // Force render thread to run
  762. dummyCamera.Render();
  763. // Wait for the frame to change
  764. m_Video.Call("WaitForExtract");
  765. // Return whether the frame changed
  766. return (previousFrameCount != GetTextureFrameCount());
  767. }
  768. return false;
  769. }
  770. public override long GetTextureTimeStamp()
  771. {
  772. long timeStamp = long.MinValue;
  773. if (m_Video != null)
  774. {
  775. timeStamp = m_Video.Call<long>("GetTextureTimeStamp");
  776. }
  777. return timeStamp;
  778. }
  779. public override void Render()
  780. {
  781. if (m_Video != null)
  782. {
  783. if (m_UseFastOesPath)
  784. {
  785. // This is needed for at least Unity 5.5.0, otherwise it just renders black in OES mode
  786. GL.InvalidateState();
  787. }
  788. AndroidMediaPlayer.IssuePluginEvent( Native.AVPPluginEvent.PlayerUpdate, m_iPlayerIndex );
  789. if (m_UseFastOesPath)
  790. {
  791. GL.InvalidateState();
  792. }
  793. }
  794. }
  795. public override void OnEnable()
  796. {
  797. base.OnEnable();
  798. #if DLL_METHODS
  799. int textureHandle = Native._GetTextureHandle(m_iPlayerIndex);
  800. #else
  801. int textureHandle = m_Video.Call<int>("GetTextureHandle");
  802. #endif
  803. if (m_Texture != null && textureHandle > 0 && m_Texture.GetNativeTexturePtr() == System.IntPtr.Zero)
  804. {
  805. //Debug.Log("RECREATING");
  806. m_Texture.UpdateExternalTexture(new System.IntPtr(textureHandle));
  807. }
  808. #if AVPROVIDEO_FIXREGRESSION_TEXTUREQUALITY_UNITY542
  809. _textureQuality = QualitySettings.masterTextureLimit;
  810. #endif
  811. }
  812. public override System.DateTime GetProgramDateTime()
  813. {
  814. System.DateTime result;
  815. if (m_Video != null)
  816. {
  817. double seconds = m_Video.Call<double>("GetCurrentAbsoluteTimestamp");
  818. result = Helper.ConvertSecondsSince1970ToDateTime(seconds);
  819. }
  820. else
  821. {
  822. result = base.GetProgramDateTime();
  823. }
  824. return result;
  825. }
  826. public override void Update()
  827. {
  828. if (m_Video != null)
  829. {
  830. if (m_Method_Update != System.IntPtr.Zero)
  831. {
  832. AndroidJNI.CallVoidMethod(m_Video.GetRawObject(), m_Method_Update, m_Value0);
  833. }
  834. else
  835. {
  836. m_Video.Call("Update");
  837. }
  838. // _lastError = (ErrorCode)( m_Video.Call<int>("GetLastErrorCode") );
  839. _lastError = (ErrorCode)( Native._GetLastErrorCode( m_iPlayerIndex ) );
  840. }
  841. if( m_Options.HasChanged( MediaPlayer.OptionsAndroid.ChangeFlags.All, true ) )
  842. {
  843. if (m_Video != null)
  844. {
  845. #if UNITY_2017_2_OR_NEWER
  846. Vector2 vPreferredVideo = GetPreferredVideoResolution(m_Options.preferredMaximumResolution, m_Options.customPreferredMaximumResolution);
  847. #else
  848. Vector2 vPreferredVideo = GetPreferredVideoResolution(m_Options.preferredMaximumResolution, new Vector2(0.0f, 0.0f));
  849. #endif
  850. int iNewBitrate = (int)(m_Options.GetPreferredPeakBitRateInBitsPerSecond());
  851. /*bool bSetMaxResolutionAndBitrate =*/ m_Video.Call<bool>("SetPreferredVideoResolutionAndBitrate", (int)(vPreferredVideo.x), (int)(vPreferredVideo.y), iNewBitrate);
  852. }
  853. }
  854. /*
  855. m_fTestTime += Time.deltaTime;
  856. if( m_fTestTime > 4.0f )
  857. {
  858. m_fTestTime = 0.0f;
  859. int iNumStreams = InternalGetAdaptiveStreamCount( TrackType.Video );
  860. int iNewStreamIndex = UnityEngine.Random.Range( -1, iNumStreams );
  861. SetVideoAdaptiveStreamIndex( TrackType.Video, iNewStreamIndex );
  862. }
  863. */
  864. // Call before the native update call
  865. UpdateTracks();
  866. UpdateTextCue();
  867. UpdateSubtitles();
  868. UpdateTimeRanges();
  869. UpdateDisplayFrameRate();
  870. if (Mathf.Approximately((float)m_Duration, 0f))
  871. {
  872. #if DLL_METHODS
  873. m_Duration = (double)( Native._GetDuration( m_iPlayerIndex ) );
  874. #else
  875. m_Duration = m_Video.Call<double>("GetDurationS");
  876. #endif
  877. // if( m_DurationMs > 0.0f ) { Helper.LogInfo("Duration: " + m_DurationMs); }
  878. }
  879. // Check if we can create the texture
  880. // Scan for a change in resolution
  881. int newWidth = -1;
  882. int newHeight = -1;
  883. if (m_Texture != null)
  884. {
  885. #if DLL_METHODS
  886. newWidth = Native._GetWidth(m_iPlayerIndex);
  887. newHeight = Native._GetHeight(m_iPlayerIndex);
  888. #else
  889. newWidth = m_Video.Call<int>("GetWidth");
  890. newHeight = m_Video.Call<int>("GetHeight");
  891. #endif
  892. if (newWidth != m_Width || newHeight != m_Height)
  893. {
  894. m_Texture = null;
  895. m_TextureHandle = 0;
  896. }
  897. }
  898. #if DLL_METHODS
  899. int textureHandle = Native._GetTextureHandle(m_iPlayerIndex);
  900. #else
  901. int textureHandle = m_Video.Call<int>("GetTextureHandle");
  902. #endif
  903. if (textureHandle != 0 && textureHandle != m_TextureHandle)
  904. {
  905. // Already got? (from above)
  906. if (newWidth == -1 || newHeight == -1)
  907. {
  908. #if DLL_METHODS
  909. newWidth = Native._GetWidth(m_iPlayerIndex);
  910. newHeight = Native._GetHeight(m_iPlayerIndex);
  911. #else
  912. newWidth = m_Video.Call<int>("GetWidth");
  913. newHeight = m_Video.Call<int>("GetHeight");
  914. #endif
  915. }
  916. if (Mathf.Max(newWidth, newHeight) > SystemInfo.maxTextureSize)
  917. {
  918. m_Width = newWidth;
  919. m_Height = newHeight;
  920. m_TextureHandle = textureHandle;
  921. Debug.LogError("[AVProVideo] Video dimensions larger than maxTextureSize");
  922. }
  923. else if (newWidth > 0 && newHeight > 0)
  924. {
  925. m_Width = newWidth;
  926. m_Height = newHeight;
  927. m_TextureHandle = textureHandle;
  928. switch (m_API)
  929. {
  930. case Android.VideoApi.MediaPlayer:
  931. _playerDescription = "MediaPlayer";
  932. break;
  933. case Android.VideoApi.ExoPlayer:
  934. _playerDescription = "ExoPlayer";
  935. break;
  936. default:
  937. _playerDescription = "UnknownPlayer";
  938. break;
  939. }
  940. if (m_UseFastOesPath)
  941. {
  942. _playerDescription += " OES";
  943. }
  944. else
  945. {
  946. _playerDescription += " NonOES";
  947. }
  948. Helper.LogInfo("Using playback path: " + _playerDescription + " (" + m_Width + "x" + m_Height + "@" + GetVideoFrameRate().ToString("F2") + ")");
  949. // NOTE: From Unity 5.4.x when using OES textures, an error "OPENGL NATIVE PLUG-IN ERROR: GL_INVALID_OPERATION: Operation illegal in current state" will be logged.
  950. // We assume this is because we're passing in TextureFormat.RGBA32 which isn't the true texture format. This error should be safe to ignore.
  951. m_Texture = Texture2D.CreateExternalTexture(m_Width, m_Height, TextureFormat.RGBA32, false, false, new System.IntPtr(textureHandle));
  952. if (m_Texture != null)
  953. {
  954. ApplyTextureProperties(m_Texture);
  955. }
  956. Helper.LogInfo("Texture ID: " + textureHandle);
  957. }
  958. }
  959. #if AVPROVIDEO_FIXREGRESSION_TEXTUREQUALITY_UNITY542
  960. // In Unity 5.4.2 and above the video texture turns black when changing the TextureQuality in the Quality Settings
  961. // The code below gets around this issue. A bug report has been sent to Unity. So far we have tested and replicated the
  962. // "bug" in Windows only, but a user has reported it in Android too.
  963. // Texture.GetNativeTexturePtr() must sync with the rendering thread, so this is a large performance hit!
  964. if (_textureQuality != QualitySettings.masterTextureLimit)
  965. {
  966. if (m_Texture != null && textureHandle > 0 && m_Texture.GetNativeTexturePtr() == System.IntPtr.Zero)
  967. {
  968. //Debug.Log("RECREATING");
  969. m_Texture.UpdateExternalTexture(new System.IntPtr(textureHandle));
  970. }
  971. _textureQuality = QualitySettings.masterTextureLimit;
  972. }
  973. #endif
  974. }
  975. protected override void ApplyTextureProperties(Texture texture)
  976. {
  977. // NOTE: According to OES_EGL_image_external: For external textures, the default min filter is GL_LINEAR and the default S and T wrap modes are GL_CLAMP_TO_EDGE
  978. // See https://www.khronos.org/registry/gles/extensions/OES/OES_EGL_image_external_essl3.txt
  979. // But there is a new extension that allows some wrap modes:
  980. // https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_EGL_image_external_wrap_modes.txt
  981. // So really we need to detect whether these extensions exist when m_UseFastOesPath is true
  982. //if (!m_UseFastOesPath)
  983. {
  984. base.ApplyTextureProperties(texture);
  985. }
  986. }
  987. public override bool PlayerSupportsLinearColorSpace()
  988. {
  989. return false;
  990. }
  991. public override float[] GetTextureTransform()
  992. {
  993. float[] transform = null;
  994. if (m_Video != null)
  995. {
  996. transform = m_Video.Call<float[]>("GetTextureTransform");
  997. /*if (transform != null)
  998. {
  999. Debug.Log("xform: " + transform[0] + " " + transform[1] + " " + transform[2] + " " + transform[3] + " " + transform[4] + " " + transform[5]);
  1000. }*/
  1001. }
  1002. return transform;
  1003. }
  1004. public override void Dispose()
  1005. {
  1006. //Debug.LogError("DISPOSE");
  1007. if (m_Video != null)
  1008. {
  1009. m_Video.Call("SetDeinitialiseFlagged");
  1010. m_Video.Dispose();
  1011. m_Video = null;
  1012. }
  1013. if (s_Interface != null)
  1014. {
  1015. s_Interface.Call("DestroyPlayer", m_iPlayerIndex);
  1016. }
  1017. if (m_Texture != null)
  1018. {
  1019. Texture2D.Destroy(m_Texture);
  1020. m_Texture = null;
  1021. }
  1022. // Deinitialise player (replaces call directly as GL textures are involved)
  1023. AndroidMediaPlayer.IssuePluginEvent( Native.AVPPluginEvent.PlayerDestroy, m_iPlayerIndex );
  1024. }
  1025. private void UpdateTimeRanges()
  1026. {
  1027. if( m_Video != null )
  1028. {
  1029. // Seekable time ranges
  1030. AndroidJavaObject seekableReturnObject = m_Video.Call<AndroidJavaObject>("GetSeekableTimeRanges");
  1031. if( seekableReturnObject.GetRawObject().ToInt32() != 0 )
  1032. {
  1033. double[] aSeekableRanges = AndroidJNIHelper.ConvertFromJNIArray<double[]>( seekableReturnObject.GetRawObject() );
  1034. if( aSeekableRanges.Length > 1 )
  1035. {
  1036. int iNumRanges = aSeekableRanges.Length / 2;
  1037. _seekableTimes._ranges = new TimeRange[ iNumRanges ];
  1038. int iRangeIndex = 0;
  1039. for( int iRange = 0; iRange < iNumRanges; ++iRange )
  1040. {
  1041. _seekableTimes._ranges[ iRange ] = new TimeRange( aSeekableRanges[ iRangeIndex ], aSeekableRanges[ iRangeIndex + 1 ] );
  1042. iRangeIndex += 2;
  1043. }
  1044. _seekableTimes.CalculateRange();
  1045. }
  1046. seekableReturnObject.Dispose();
  1047. }
  1048. // Buffered time ranges
  1049. AndroidJavaObject bufferedReturnObject = m_Video.Call<AndroidJavaObject>("GetBufferedTimeRanges");
  1050. if( bufferedReturnObject.GetRawObject().ToInt32() != 0 )
  1051. {
  1052. double[] aBufferedRanges = AndroidJNIHelper.ConvertFromJNIArray<double[]>( bufferedReturnObject.GetRawObject() );
  1053. if( aBufferedRanges.Length > 1 )
  1054. {
  1055. int iNumRanges = aBufferedRanges.Length / 2;
  1056. _bufferedTimes._ranges = new TimeRange[ iNumRanges ];
  1057. int iRangeIndex = 0;
  1058. for( int iRange = 0; iRange < iNumRanges; ++iRange )
  1059. {
  1060. _bufferedTimes._ranges[iRange] = new TimeRange( aBufferedRanges[iRangeIndex], aBufferedRanges[iRangeIndex + 1] );
  1061. iRangeIndex += 2;
  1062. }
  1063. _bufferedTimes.CalculateRange();
  1064. }
  1065. bufferedReturnObject.Dispose();
  1066. }
  1067. }
  1068. }
  1069. bool isMainThread()
  1070. {
  1071. return m_MainThread.Equals(System.Threading.Thread.CurrentThread);
  1072. }
  1073. public override int GetAudioChannelCount()
  1074. {
  1075. return Native._GetCurrentAudioTrackNumChannels(m_iPlayerIndex);
  1076. }
  1077. /*
  1078. public override AudioChannelMaskFlags GetAudioChannelMask()
  1079. {
  1080. return (AudioChannelMaskFlags)Native.GetAudioChannelMask(_instance);
  1081. }
  1082. */
  1083. public override int GrabAudio(float[] buffer, int sampleCount, int channelCount)
  1084. {
  1085. int iReturn = 0;
  1086. // Get audio data
  1087. iReturn = Native._GrabAudioNative( buffer, m_iPlayerIndex, sampleCount, channelCount );
  1088. return iReturn;
  1089. }
  1090. public override int GetAudioBufferedSampleCount()
  1091. {
  1092. int iBufferedSampleCount = 0;
  1093. if (m_Video != null)
  1094. {
  1095. // Get audio data
  1096. iBufferedSampleCount = m_Video.Call<int>("GetAudioBufferedSampleCount");
  1097. }
  1098. return iBufferedSampleCount;
  1099. }
  1100. internal override bool InternalIsChangedTextCue()
  1101. {
  1102. // Has the text cue changed since the last frame 'tick'
  1103. if( m_Video != null )
  1104. {
  1105. return m_Video.Call<bool>("GetTextCueDirty");
  1106. }
  1107. return false;
  1108. }
  1109. internal override string InternalGetCurrentTextCue()
  1110. {
  1111. // Return a pointer to the current text cue string in UTF16 format
  1112. if ( m_Video != null )
  1113. {
  1114. return m_Video.Call<string>("GetCurrentTextCue");
  1115. }
  1116. return string.Empty;
  1117. }
  1118. internal override bool InternalIsChangedTracks(TrackType trackType)
  1119. {
  1120. // Has it changed since the last frame 'tick'
  1121. bool result = false;
  1122. switch (trackType)
  1123. {
  1124. case TrackType.Video:
  1125. {
  1126. result = ( m_Video != null ) ? m_Video.Call<bool>("GetVideoTracksDirty") : false;
  1127. break;
  1128. }
  1129. case TrackType.Audio:
  1130. {
  1131. result = ( m_Video != null ) ? m_Video.Call<bool>("GetAudioTracksDirty") : false;
  1132. break;
  1133. }
  1134. case TrackType.Text:
  1135. {
  1136. result = ( m_Video != null ) ? m_Video.Call<bool>("GetTextTracksDirty") : false;
  1137. break;
  1138. }
  1139. }
  1140. return result;
  1141. }
  1142. internal override int InternalGetTrackCount(TrackType trackType)
  1143. {
  1144. int result = 0;
  1145. switch (trackType)
  1146. {
  1147. case TrackType.Video:
  1148. {
  1149. result = ( m_Video != null ) ? m_Video.Call<int>("GetNumberVideoTracks") : 0;
  1150. break;
  1151. }
  1152. case TrackType.Audio:
  1153. {
  1154. result = ( m_Video != null ) ? m_Video.Call<int>("GetNumberAudioTracks") : 0;
  1155. break;
  1156. }
  1157. case TrackType.Text:
  1158. {
  1159. result = ( m_Video != null ) ? m_Video.Call<int>("GetNumberTextTracks") : 0;
  1160. break;
  1161. }
  1162. }
  1163. return result;
  1164. }
  1165. internal override bool InternalSetActiveTrack(TrackType trackType, int trackUid)
  1166. {
  1167. bool result = false;
  1168. switch (trackType)
  1169. {
  1170. case TrackType.Video:
  1171. {
  1172. result = ( m_Video != null ) ? m_Video.Call<bool>("SetVideoTrack", trackUid) : false;
  1173. break;
  1174. }
  1175. case TrackType.Audio:
  1176. {
  1177. result = ( m_Video != null ) ? m_Video.Call<bool>("SetAudioTrack", trackUid) : false;
  1178. break;
  1179. }
  1180. case TrackType.Text:
  1181. {
  1182. result = ( m_Video != null ) ? m_Video.Call<bool>("SetTextTrack", trackUid) : false;
  1183. break;
  1184. }
  1185. }
  1186. return result;
  1187. }
  1188. internal override TrackBase InternalGetTrackInfo(TrackType trackType, int trackIndex, ref bool isActiveTrack)
  1189. {
  1190. TrackBase result = null;
  1191. switch (trackType)
  1192. {
  1193. case TrackType.Video:
  1194. {
  1195. if (m_Video != null)
  1196. {
  1197. AndroidJavaObject returnObject = m_Video.Call<AndroidJavaObject>("GetVideoTrackInfo", trackIndex);
  1198. if (returnObject.GetRawObject().ToInt32() != 0)
  1199. {
  1200. String[] aReturn = AndroidJNIHelper.ConvertFromJNIArray<String[]>(returnObject.GetRawObject());
  1201. bool bReturn = (aReturn.Length > 0) ? (int.Parse(aReturn[0]) == 1) : false;
  1202. if (bReturn)
  1203. {
  1204. VideoTrack videoTrack = new VideoTrack(trackIndex, aReturn[1], aReturn[2], (aReturn[3] == "1"));
  1205. int bitrate = 0;
  1206. bool gotBitrate = Int32.TryParse(aReturn[4], out bitrate);
  1207. if( gotBitrate )
  1208. {
  1209. videoTrack.Bitrate = bitrate;
  1210. }
  1211. result = videoTrack;
  1212. isActiveTrack = (m_Video != null && m_Video.Call<int>("GetCurrentVideoTrackIndex") == trackIndex);
  1213. }
  1214. returnObject.Dispose();
  1215. }
  1216. }
  1217. }
  1218. break;
  1219. case TrackType.Audio:
  1220. {
  1221. if (m_Video != null)
  1222. {
  1223. AndroidJavaObject returnObject = m_Video.Call<AndroidJavaObject>("GetAudioTrackInfo", trackIndex);
  1224. if (returnObject.GetRawObject().ToInt32() != 0)
  1225. {
  1226. String[] aReturn = AndroidJNIHelper.ConvertFromJNIArray<String[]>( returnObject.GetRawObject() );
  1227. bool bReturn = ( aReturn.Length > 0 ) ? ( int.Parse( aReturn[ 0 ]) == 1 ) : false;
  1228. if (bReturn)
  1229. {
  1230. int iBitrate = 0;
  1231. int.TryParse( aReturn[ 4 ], out iBitrate );
  1232. int iChannelCount = 0;
  1233. int.TryParse(aReturn[ 5 ], out iChannelCount);
  1234. result = new AudioTrack( trackIndex, aReturn[ 1 ], aReturn[ 2 ], (aReturn[ 3 ] == "1") );
  1235. isActiveTrack = (m_Video != null && m_Video.Call<int>("GetCurrentAudioTrackIndex") == trackIndex);
  1236. }
  1237. returnObject.Dispose();
  1238. }
  1239. }
  1240. }
  1241. break;
  1242. case TrackType.Text:
  1243. {
  1244. if (m_Video != null)
  1245. {
  1246. AndroidJavaObject returnObject = m_Video.Call<AndroidJavaObject>( "GetTextTrackInfo", trackIndex );
  1247. if (returnObject.GetRawObject().ToInt32() != 0)
  1248. {
  1249. String[] aReturn = AndroidJNIHelper.ConvertFromJNIArray<String[]>( returnObject.GetRawObject() );
  1250. bool bReturn = ( aReturn.Length > 0 ) ? ( int.Parse(aReturn[ 0 ] ) == 1 ) : false;
  1251. int uid = -1;
  1252. if( bReturn )
  1253. {
  1254. int.TryParse(aReturn[1], out uid);
  1255. result = new TextTrack(uid, aReturn[ 2 ], aReturn[ 3 ], false);
  1256. isActiveTrack = (m_Video != null && m_Video.Call<int>("GetCurrentTextTrackIndex") == trackIndex);
  1257. }
  1258. returnObject.Dispose();
  1259. }
  1260. }
  1261. }
  1262. break;
  1263. }
  1264. return result;
  1265. }
  1266. internal /*override*/ int InternalGetAdaptiveStreamCount(TrackType trackType, int trackIndex = -1)
  1267. {
  1268. int result = 0;
  1269. switch (trackType)
  1270. {
  1271. case TrackType.Video:
  1272. {
  1273. result = (m_Video != null) ? m_Video.Call<int>("GetNumberVideoAdaptiveStreams", trackIndex) : 0;
  1274. Debug.Log("[AVProVideo]: InternalGetAdaptiveStreamCount return = " + result);
  1275. break;
  1276. }
  1277. case TrackType.Audio:
  1278. {
  1279. break;
  1280. }
  1281. case TrackType.Text:
  1282. {
  1283. break;
  1284. }
  1285. }
  1286. return result;
  1287. }
  1288. internal /*override*/ void InternalGetAdaptiveStreamInfo(TrackType trackType, int trackIndex = -1)
  1289. {
  1290. switch( trackType )
  1291. {
  1292. case TrackType.Video:
  1293. {
  1294. if( m_Video != null )
  1295. {
  1296. AndroidJavaObject returnObject = m_Video.Call<AndroidJavaObject>("GetVideoAdaptiveStreamInfo", trackIndex);
  1297. if( returnObject.GetRawObject().ToInt32() != 0 )
  1298. {
  1299. String[] aReturn = AndroidJNIHelper.ConvertFromJNIArray<String[]>(returnObject.GetRawObject());
  1300. bool bReturn = (aReturn.Length > 0) ? (int.Parse(aReturn[0]) == 1) : false;
  1301. string toLog = "";
  1302. foreach( string str in aReturn ) { toLog += str + ", "; }
  1303. Debug.Log( "[AVProVideo]: InternalGetAdaptiveStreamInfo return = " + toLog );
  1304. if ( bReturn )
  1305. {
  1306. }
  1307. returnObject.Dispose();
  1308. }
  1309. }
  1310. }
  1311. break;
  1312. case TrackType.Audio:
  1313. {
  1314. }
  1315. break;
  1316. case TrackType.Text:
  1317. {
  1318. }
  1319. break;
  1320. }
  1321. }
  1322. internal /*override*/ int SetVideoAdaptiveStreamIndex(TrackType trackType, int streamIndex)
  1323. {
  1324. int result = 0;
  1325. switch( trackType )
  1326. {
  1327. case TrackType.Video:
  1328. {
  1329. Debug.Log("[AVProVideo]: SetVideoAdaptiveStreamIndex : streamIndex = " + streamIndex);
  1330. result = (m_Video != null) ? m_Video.Call<int>("SetVideoAdaptiveStreams", streamIndex) : 0;
  1331. break;
  1332. }
  1333. case TrackType.Audio:
  1334. {
  1335. break;
  1336. }
  1337. case TrackType.Text:
  1338. {
  1339. break;
  1340. }
  1341. }
  1342. return result;
  1343. }
  1344. private Vector2 GetPreferredVideoResolution(MediaPlayer.OptionsAndroid.Resolution preferredMaximumResolution, Vector2 customPreferredMaximumResolution)
  1345. {
  1346. Vector2 vResolution = new Vector2( 0.0f, 0.0f );
  1347. switch( preferredMaximumResolution )
  1348. {
  1349. case MediaPlayer.OptionsAndroid.Resolution.NoPreference:
  1350. break;
  1351. case MediaPlayer.OptionsAndroid.Resolution._480p:
  1352. vResolution.x = 640;
  1353. vResolution.y = 480;
  1354. break;
  1355. case MediaPlayer.OptionsAndroid.Resolution._720p:
  1356. vResolution.x = 1280;
  1357. vResolution.y = 720;
  1358. break;
  1359. case MediaPlayer.OptionsAndroid.Resolution._1080p:
  1360. vResolution.x = 1920;
  1361. vResolution.y = 1080;
  1362. break;
  1363. case MediaPlayer.OptionsAndroid.Resolution._2160p:
  1364. vResolution.x = 3840;
  1365. vResolution.y = 2160;
  1366. break;
  1367. case MediaPlayer.OptionsAndroid.Resolution.Custom:
  1368. #if UNITY_2017_2_OR_NEWER
  1369. vResolution.x = customPreferredMaximumResolution.x;
  1370. vResolution.y = customPreferredMaximumResolution.y;
  1371. #endif
  1372. break;
  1373. }
  1374. return vResolution;
  1375. }
  1376. public override bool IsMediaCachingSupported()
  1377. {
  1378. if( m_Video != null )
  1379. {
  1380. return m_Video.Call<bool>("IsMediaCachingSupported");
  1381. }
  1382. return true;
  1383. }
  1384. public override void AddMediaToCache(string url, string headers, MediaCachingOptions options)
  1385. {
  1386. if (m_Video != null)
  1387. {
  1388. double dMinBitrate = -1.0f;
  1389. int iMinWidth = -1;
  1390. int iMinHeight = -1;
  1391. double dMaxBitrate = -1.0f;
  1392. int iMaxWidth = -1;
  1393. int iMaxHeight = -1;
  1394. if (options != null )
  1395. {
  1396. dMinBitrate = options.minimumRequiredBitRate;
  1397. iMinWidth = (int)( options.minimumRequiredResolution.x );
  1398. iMinHeight = (int)( options.minimumRequiredResolution.y );
  1399. dMaxBitrate = options.maximumRequiredBitRate;
  1400. iMaxWidth = (int)(options.maximumRequiredResolution.x);
  1401. iMaxHeight = (int)(options.maximumRequiredResolution.y);
  1402. }
  1403. m_Video.Call("AddMediaToCache", url, headers, dMinBitrate, iMinWidth, iMinHeight, dMaxBitrate, iMaxWidth, iMaxHeight);
  1404. }
  1405. }
  1406. public override void RemoveMediaFromCache(string url)
  1407. {
  1408. if(m_Video != null)
  1409. {
  1410. m_Video.Call("RemoveMediaFromCache", url);
  1411. }
  1412. }
  1413. public override void CancelDownloadOfMediaToCache(string url)
  1414. {
  1415. if (m_Video != null)
  1416. {
  1417. m_Video.Call("CancelDownloadOfMediaToCache", url);
  1418. }
  1419. }
  1420. public override void PauseDownloadOfMediaToCache(string url)
  1421. {
  1422. if (m_Video != null)
  1423. {
  1424. m_Video.Call("PauseDownloadOfMediaToCache", url);
  1425. }
  1426. }
  1427. public override void ResumeDownloadOfMediaToCache(string url)
  1428. {
  1429. if (m_Video != null)
  1430. {
  1431. m_Video.Call("ResumeDownloadOfMediaToCache", url);
  1432. }
  1433. }
  1434. public override CachedMediaStatus GetCachedMediaStatus(string url, ref float progress)
  1435. {
  1436. CachedMediaStatus eStatus = CachedMediaStatus.NotCached;
  1437. if (m_Video != null)
  1438. {
  1439. float[] afReturn = m_Video.Call<float[]>("GetCachedMediaStatus", url);
  1440. eStatus = (CachedMediaStatus)( afReturn[ 0 ] );
  1441. progress = afReturn[ 1 ] * 0.01f;
  1442. // if( eStatus != CachedMediaStatus.NotCached && progress < 1.0f )
  1443. // {
  1444. // Debug.Log("AVProVideo: GetCachedMediaStatus | url = " + url + " | eStatus = " + eStatus + " | progress = " + progress);
  1445. // }
  1446. }
  1447. return eStatus;
  1448. }
  1449. private struct Native
  1450. {
  1451. internal const string LibraryName = "AVProVideo2Native";
  1452. [DllImport (LibraryName)]
  1453. public static extern IntPtr GetRenderEventFunc();
  1454. [DllImport(LibraryName)]
  1455. public static extern bool JNIAttachCurrentThread();
  1456. [DllImport(LibraryName)]
  1457. public static extern void JNIDetachCurrentThread();
  1458. [DllImport(LibraryName)]
  1459. public static extern int _GetCurrentAudioTrackNumChannels( int iPlayerIndex );
  1460. [DllImport(LibraryName)]
  1461. // unsafe public static extern int _GrabAudioNative(float* pBuffer, int iPlayerIndex, int sampleCount, int channelCount);
  1462. public static extern int _GrabAudioNative(float[] pBuffer, int iPlayerIndex, int sampleCount, int channelCount);
  1463. [DllImport (LibraryName)]
  1464. public static extern int _GetWidth( int iPlayerIndex );
  1465. [DllImport (LibraryName)]
  1466. public static extern int _GetHeight( int iPlayerIndex );
  1467. [DllImport (LibraryName)]
  1468. public static extern int _GetTextureHandle( int iPlayerIndex );
  1469. [DllImport (LibraryName)]
  1470. public static extern double _GetDuration( int iPlayerIndex );
  1471. [DllImport (LibraryName)]
  1472. public static extern int _GetLastErrorCode( int iPlayerIndex );
  1473. [DllImport (LibraryName)]
  1474. public static extern int _GetFrameCount( int iPlayerIndex );
  1475. [DllImport (LibraryName)]
  1476. public static extern float _GetVideoDisplayRate( int iPlayerIndex );
  1477. [DllImport (LibraryName)]
  1478. public static extern bool _CanPlay( int iPlayerIndex );
  1479. public enum AVPPluginEvent
  1480. {
  1481. Nop,
  1482. PlayerSetup,
  1483. PlayerUpdate,
  1484. PlayerDestroy,
  1485. ExtractFrame,
  1486. }
  1487. }
  1488. }
  1489. }
  1490. #endif