AVProVideo.jslib 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017
  1. var AVProVideoWebGL =
  2. {
  3. /*isNumber: function (item) {
  4. return typeof(item) === "number" && !isNaN(item);
  5. },
  6. assert: function (equality, message) {
  7. if (!equality)
  8. console.log(message);
  9. },*/
  10. count: 0,
  11. players: [],
  12. isSafari: function() {
  13. return navigator.vendor && navigator.vendor.indexOf('Apple') > -1 && navigator.userAgent && navigator.userAgent.indexOf('CriOS') == -1 && navigator.userAgent.indexOf('FxiOS') == -1;
  14. },
  15. is_iOS: function() {
  16. return [
  17. 'iPad Simulator',
  18. 'iPhone Simulator',
  19. 'iPod Simulator',
  20. 'iPad',
  21. 'iPhone',
  22. 'iPod'
  23. ].includes(navigator.platform)
  24. // iPad on iOS 13 detection
  25. || (navigator.userAgent.includes("Mac") && "ontouchend" in document);
  26. },
  27. hasPlayer__deps: ["players"],
  28. hasPlayer: function (videoIndex)
  29. {
  30. if (videoIndex)
  31. {
  32. if (videoIndex == -1)
  33. {
  34. return false;
  35. }
  36. if (_players)
  37. {
  38. if (_players[videoIndex])
  39. {
  40. return true;
  41. }
  42. }
  43. }
  44. else
  45. {
  46. if (_players)
  47. {
  48. if (_players.length > 0)
  49. {
  50. return true;
  51. }
  52. }
  53. }
  54. return false;
  55. },
  56. AVPPlayerInsertVideoElement__deps: ["count", "players", "isSafari", "is_iOS"],
  57. AVPPlayerInsertVideoElement: function (path, idValues, externalLibrary)
  58. {
  59. if (!path) { return false; }
  60. // NOTE: When loading from the indexedDB (Application.persistentDataPath),
  61. // URL.createObjectURL() must be used get a valid URL. See:
  62. // http://www.misfitgeek.com/html5-off-line-storing-and-retrieving-videos-with-indexeddb/
  63. path = Pointer_stringify(path);
  64. _count++;
  65. var vid = document.createElement("video");
  66. var useNativeSrcPath = true;
  67. var hls = null;
  68. if (externalLibrary == 1)
  69. {
  70. useNativeSrcPath = false;
  71. var player = dashjs.MediaPlayer().create();
  72. player.initialize(vid, path, true);
  73. }
  74. else if (externalLibrary == 2 && !(_is_iOS() || _isSafari()))
  75. {
  76. useNativeSrcPath = false;
  77. hls = new Hls();
  78. hls.loadSource(path);
  79. hls.attachMedia(vid);
  80. hls.on(Hls.Events.MANIFEST_PARSED, function()
  81. {
  82. //video.play();
  83. });
  84. }
  85. else if (externalLibrary == 3)
  86. {
  87. //useNativeSrcPath = false;
  88. }
  89. // Some sources say that this is the proper way to catch errors...
  90. /*vid.addEventListener('error', function(event) {
  91. console.log("Error: " + event);
  92. }, true);*/
  93. var hasSetCanPlay = false;
  94. var playerIndex;
  95. var id = _count;
  96. var vidData = {
  97. id: id,
  98. video: vid,
  99. ready: false,
  100. hasMetadata: false,
  101. isStalled: false,
  102. buffering: false,
  103. lastErrorCode: 0,
  104. hlsjs: hls
  105. };
  106. _players.push(vidData);
  107. playerIndex = (_players.length > 0) ? _players.length - 1 : 0;
  108. /*const frameCounterCallback = function (timeNow, metadata) {
  109. console.log("got a frame! " + metadata.presentedFrames + " " + metadata.presentationTime);
  110. vid.requestVideoFrameCallback(frameCounterCallback);
  111. };
  112. if (HTMLVideoElement.prototype.requestVideoFrameCallback)
  113. {
  114. console.log("has frame callback support");
  115. vid.requestVideoFrameCallback(frameCounterCallback);
  116. }*/
  117. vid.oncanplay = function()
  118. {
  119. if (!hasSetCanPlay)
  120. {
  121. hasSetCanPlay = true;
  122. vidData.ready = true;
  123. }
  124. };
  125. vid.onloadedmetadata = function()
  126. {
  127. vidData.hasMetadata = true;
  128. };
  129. vid.oncanplaythrough = function()
  130. {
  131. vidData.buffering = false;
  132. };
  133. vid.onplaying = function()
  134. {
  135. vidData.buffering = false;
  136. vidData.isStalled = false;
  137. //console.log("PLAYING");
  138. };
  139. vid.onwaiting = function()
  140. {
  141. vidData.buffering = true;
  142. //console.log("WAITING");
  143. };
  144. vid.onstalled = function()
  145. {
  146. vidData.isStalled = true;
  147. //console.log("STALLED");
  148. }
  149. /*vid.onpause = function() {
  150. };*/
  151. vid.onended = function()
  152. {
  153. vidData.buffering = false;
  154. vidData.isStalled = false;
  155. //console.log("ENDED");
  156. };
  157. vid.ontimeupdate = function()
  158. {
  159. vidData.buffering = false;
  160. vidData.isStalled = false;
  161. //console.log("vid current time: ", this.currentTime);
  162. };
  163. vid.onerror = function(texture)
  164. {
  165. var err = "unknown error";
  166. switch (vid.error.code) {
  167. case 1:
  168. err = "video loading aborted";
  169. break;
  170. case 2:
  171. err = "network loading error";
  172. break;
  173. case 3:
  174. err = "video decoding failed / corrupted data or unsupported codec";
  175. break;
  176. case 4:
  177. err = "video not supported";
  178. break;
  179. }
  180. vidData.lastErrorCode = vid.error.code;
  181. console.log("Error: " + err + " (errorcode=" + vid.error.code + ")", "color:red;");
  182. };
  183. vid.crossOrigin = "anonymous";
  184. vid.preload = 'auto';
  185. vid.autoplay = false;
  186. if (_is_iOS())
  187. {
  188. vid.autoplay = true;
  189. vid.playsInline = true;
  190. }
  191. if (useNativeSrcPath)
  192. {
  193. vid.src = path;
  194. }
  195. HEAP32[(idValues>>2)] = playerIndex;
  196. HEAP32[(idValues>>2)+1] = id;
  197. return true;
  198. },
  199. AVPPlayerGetLastError__deps: ["players", "hasPlayer"],
  200. AVPPlayerGetLastError: function(playerIndex)
  201. {
  202. if (!_hasPlayer(playerIndex)) { return 0; }
  203. var ret = _players[playerIndex].lastErrorCode
  204. _players[playerIndex].lastErrorCode = 0;
  205. return ret;
  206. },
  207. AVPPlayerCreateVideoTexture__deps: ["players", "hasPlayer"],
  208. AVPPlayerCreateVideoTexture: function (textureId)
  209. {
  210. const texture = GLctx.createTexture();
  211. GL.textures[textureId] = texture;
  212. //console.log("creating textureId " +textureId + " : " + GL.textures[textureId]);
  213. GLctx.bindTexture(GLctx.TEXTURE_2D, texture);
  214. },
  215. AVPPlayerDestroyVideoTexture__deps: ["players", "hasPlayer"],
  216. AVPPlayerDestroyVideoTexture: function (textureId)
  217. {
  218. GLctx.deleteTexture(GL.textures[textureId]);
  219. },
  220. AVPPlayerFetchVideoTexture__deps: ["players", "hasPlayer"],
  221. AVPPlayerFetchVideoTexture: function (playerIndex, textureId, init)
  222. {
  223. if (!_hasPlayer(playerIndex)) { return; }
  224. //console.log("updating textureId " +textureId + " : " + GL.textures[textureId]);
  225. GLctx.bindTexture(GLctx.TEXTURE_2D, GL.textures[textureId]);
  226. //GLctx.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  227. if (!init)
  228. {
  229. //GLctx.texImage2D(GLctx.TEXTURE_2D, 0, GLctx.RGBA, GLctx.RGBA, GLctx.UNSIGNED_BYTE, _players[playerIndex].video);
  230. GLctx.texSubImage2D(GLctx.TEXTURE_2D, 0, 0, 0, GLctx.RGBA, GLctx.UNSIGNED_BYTE, _players[playerIndex].video);
  231. }
  232. else
  233. {
  234. GLctx.texImage2D(GLctx.TEXTURE_2D, 0, GLctx.RGBA, GLctx.RGBA, GLctx.UNSIGNED_BYTE, _players[playerIndex].video);
  235. }
  236. //NB: This line causes the texture to not show unless something else is rendered (not sure why)
  237. //GLctx.bindTexture(GLctx.TEXTURE_2D, null);
  238. GLctx.texParameteri(GLctx.TEXTURE_2D, GLctx.TEXTURE_WRAP_S, GLctx.CLAMP_TO_EDGE);
  239. GLctx.texParameteri(GLctx.TEXTURE_2D, GLctx.TEXTURE_WRAP_T, GLctx.CLAMP_TO_EDGE);
  240. GLctx.pixelStorei(GLctx.UNPACK_FLIP_Y_WEBGL, false);
  241. },
  242. AVPPlayerUpdatePlayerIndex__deps: ["players", "hasPlayer"],
  243. AVPPlayerUpdatePlayerIndex: function (id)
  244. {
  245. var result = -1;
  246. if (!_hasPlayer()) { return result; }
  247. _players.forEach(function (currentVid, index)
  248. {
  249. if (currentVid != null && currentVid.id == id)
  250. {
  251. result = index;
  252. }
  253. });
  254. return result;
  255. },
  256. AVPPlayerWidth__deps: ["players", "hasPlayer"],
  257. AVPPlayerWidth: function (playerIndex)
  258. {
  259. if (!_hasPlayer(playerIndex)) { return 0; }
  260. return _players[playerIndex].video.videoWidth;
  261. },
  262. AVPPlayerHeight__deps: ["players", "hasPlayer"],
  263. AVPPlayerHeight: function (playerIndex)
  264. {
  265. if (!_hasPlayer(playerIndex)) { return 0; }
  266. return _players[playerIndex].video.videoHeight;
  267. },
  268. AVPPlayerReady__deps: ["players", "hasPlayer"],
  269. AVPPlayerReady: function (playerIndex)
  270. {
  271. if (!_hasPlayer(playerIndex)) { return false; }
  272. if (_players)
  273. {
  274. if (_players.length > 0)
  275. {
  276. if (_players[playerIndex])
  277. {
  278. return _players[playerIndex].ready;
  279. }
  280. }
  281. }
  282. else
  283. {
  284. return false;
  285. }
  286. //return _players[playerIndex].video.readyState >= _players[playerIndex].video.HAVE_CURRENT_DATA;
  287. },
  288. AVPPlayerClose__deps: ["players", "hasPlayer"],
  289. AVPPlayerClose: function (playerIndex)
  290. {
  291. if (!_hasPlayer(playerIndex)) { return; }
  292. var vid = _players[playerIndex].video;
  293. // Setting 'src' to an empty string results in the onerror handler being invoked and producing log noise on Chrome.
  294. // Removing the src attribute and invoking load is a recommended best practice in the HTML Standard.
  295. // See https://html.spec.whatwg.org/multipage/media.html#best-practices-for-authors-using-media-elements
  296. vid.pause();
  297. vid.removeAttribute("src"); // Previous: vid.src = "";
  298. vid.load();
  299. if (_players[playerIndex].hlsjs != null)
  300. {
  301. _players[playerIndex].hlsjs.destroy();
  302. _players[playerIndex].hlsjs = null;
  303. }
  304. _players[playerIndex].video = null;
  305. _players[playerIndex] = null;
  306. var allEmpty = true;
  307. for (i = 0; i < _players.length; i++) {
  308. if (_players[i] != null) {
  309. allEmpty = false;
  310. break;
  311. }
  312. }
  313. if (allEmpty)
  314. {
  315. _players = [];
  316. }
  317. //_players = _players.splice(playerIndex, 1);
  318. // Remove from DOM
  319. //vid.parentNode.removeChild(vid);
  320. },
  321. AVPPlayerSetLooping__deps: ["players", "hasPlayer"],
  322. AVPPlayerSetLooping: function (playerIndex, loop)
  323. {
  324. if (!_hasPlayer(playerIndex)) { return; }
  325. _players[playerIndex].video.loop = loop;
  326. },
  327. AVPPlayerIsLooping__deps: ["players", "hasPlayer"],
  328. AVPPlayerIsLooping: function (playerIndex)
  329. {
  330. if (!_hasPlayer(playerIndex)) { return false; }
  331. return _players[playerIndex].video.loop;
  332. },
  333. AVPPlayerHasMetadata__deps: ["players", "hasPlayer"],
  334. AVPPlayerHasMetadata: function (playerIndex)
  335. {
  336. if (!_hasPlayer(playerIndex)) { return false; }
  337. return (_players[playerIndex].video.readyState >= 1);
  338. },
  339. AVPPlayerIsPlaying__deps: ["players", "hasPlayer"],
  340. AVPPlayerIsPlaying: function (playerIndex)
  341. {
  342. if (!_hasPlayer(playerIndex)) { return false; }
  343. var video = _players[playerIndex].video;
  344. return (!video.paused && !video.ended);// || video.seeking || video.readyState < video.HAVE_FUTURE_DATA);
  345. },
  346. AVPPlayerIsSeeking__deps: ["players", "hasPlayer"],
  347. AVPPlayerIsSeeking: function (playerIndex)
  348. {
  349. if (!_hasPlayer(playerIndex)) { return false; }
  350. return _players[playerIndex].video.seeking;
  351. },
  352. AVPPlayerIsPaused__deps: ["players", "hasPlayer"],
  353. AVPPlayerIsPaused: function (playerIndex)
  354. {
  355. if (!_hasPlayer(playerIndex)) { return false; }
  356. return _players[playerIndex].video.paused;
  357. },
  358. AVPPlayerIsFinished__deps: ["players", "hasPlayer"],
  359. AVPPlayerIsFinished: function (playerIndex)
  360. {
  361. if (!_hasPlayer(playerIndex)) { return false; }
  362. return _players[playerIndex].video.ended;
  363. },
  364. AVPPlayerIsBuffering__deps: ["players", "hasPlayer"],
  365. AVPPlayerIsBuffering: function (playerIndex)
  366. {
  367. if (!_hasPlayer(playerIndex)) { return false; }
  368. return _players[playerIndex].buffering;
  369. },
  370. AVPPlayerIsPlaybackStalled__deps: ["players", "hasPlayer"],
  371. AVPPlayerIsPlaybackStalled: function (playerIndex)
  372. {
  373. if (!_hasPlayer(playerIndex)) { return false; }
  374. return _players[playerIndex].isStalled;
  375. },
  376. AVPPlayerPlay__deps: ["players", "hasPlayer"],
  377. AVPPlayerPlay: function (playerIndex)
  378. {
  379. if (!_hasPlayer(playerIndex)) { return false; }
  380. // https://webkit.org/blog/7734/auto-play-policy-changes-for-macos/
  381. // https://developers.google.com/web/updates/2017/06/play-request-was-interrupted
  382. var playPromise = _players[playerIndex].video.play();
  383. if (playPromise !== undefined)
  384. {
  385. playPromise.then(function()
  386. {
  387. // Automatic playback started!
  388. // Show playing UI.
  389. })
  390. .catch(function(error)
  391. {
  392. // Auto-play was prevented
  393. // Show paused UI.
  394. return false;
  395. });
  396. }
  397. return true;
  398. },
  399. AVPPlayerPause__deps: ["players", "hasPlayer"],
  400. AVPPlayerPause: function (playerIndex)
  401. {
  402. if (!_hasPlayer(playerIndex)) { return; }
  403. _players[playerIndex].video.pause();
  404. },
  405. AVPPlayerSeekToTime__deps: ["players", "hasPlayer"],
  406. AVPPlayerSeekToTime: function (playerIndex, timeSec, fast)
  407. {
  408. if (!_hasPlayer(playerIndex)) { return; }
  409. var vid = _players[playerIndex].video;
  410. if (vid.seekable && vid.seekable.length > 0)
  411. {
  412. var timeNorm = 0.0;
  413. if (vid.duration > 0.0)
  414. {
  415. timeNorm = timeSec / vid.duration;
  416. }
  417. for (i = 0; i < vid.seekable.length; i++)
  418. {
  419. if (timeNorm >= vid.seekable.start(i) && timeNorm <= vid.seekable.end(i))
  420. {
  421. if (fast && vid.fastSeek)
  422. {
  423. vid.fastSeek(timeNorm);
  424. }
  425. else
  426. {
  427. vid.currentTime = timeSec;
  428. }
  429. return;
  430. }
  431. }
  432. }
  433. else
  434. {
  435. if (timeSec == 0.0)
  436. {
  437. vid.load();
  438. }
  439. else
  440. {
  441. vid.currentTime = timeSec;
  442. }
  443. }
  444. },
  445. AVPPlayerGetCurrentTime__deps: ["players", "hasPlayer"],
  446. AVPPlayerGetCurrentTime: function (playerIndex)
  447. {
  448. if (!_hasPlayer(playerIndex)) { return 0.0; }
  449. return _players[playerIndex].video.currentTime;
  450. },
  451. AVPPlayerGetDuration__deps: ["players", "hasPlayer"],
  452. AVPPlayerGetDuration: function (playerIndex)
  453. {
  454. if (!_hasPlayer(playerIndex)) { return 0.0; }
  455. return _players[playerIndex].video.duration;
  456. },
  457. AVPPlayerGetPlaybackRate__deps: ["players", "hasPlayer"],
  458. AVPPlayerGetPlaybackRate: function (playerIndex)
  459. {
  460. if (!_hasPlayer(playerIndex)) { return 0.0; }
  461. return _players[playerIndex].video.playbackRate;
  462. },
  463. AVPPlayerSetPlaybackRate__deps: ["players", "hasPlayer"],
  464. AVPPlayerSetPlaybackRate: function (playerIndex, rate)
  465. {
  466. if (!_hasPlayer(playerIndex)) { return; }
  467. _players[playerIndex].video.playbackRate = rate;
  468. },
  469. AVPPlayerSetMuted__deps: ["players", "hasPlayer"],
  470. AVPPlayerSetMuted: function (playerIndex, mute)
  471. {
  472. if (!_hasPlayer(playerIndex)) { return; }
  473. _players[playerIndex].video.muted = mute;
  474. },
  475. AVPPlayerIsMuted__deps: ["players", "hasPlayer"],
  476. AVPPlayerIsMuted: function (playerIndex)
  477. {
  478. if (!_hasPlayer(playerIndex)) { return false; }
  479. return _players[playerIndex].video.muted;
  480. },
  481. AVPPlayerSetVolume__deps: ["players", "hasPlayer"],
  482. AVPPlayerSetVolume: function (playerIndex, volume)
  483. {
  484. if (!_hasPlayer(playerIndex)) { return; }
  485. _players[playerIndex].video.volume = volume;
  486. },
  487. AVPPlayerGetVolume__deps: ["players", "hasPlayer"],
  488. AVPPlayerGetVolume: function (playerIndex)
  489. {
  490. if (!_hasPlayer(playerIndex)) { return 0.0; }
  491. return _players[playerIndex].video.volume;
  492. },
  493. AVPPlayerHasVideo__deps: ["players", "hasPlayer"],
  494. AVPPlayerHasVideo: function (playerIndex)
  495. {
  496. if (!_hasPlayer(playerIndex)) { return false; }
  497. var isChrome = !!window.chrome && !!window.chrome.webstore;
  498. if (isChrome)
  499. {
  500. return Boolean(_players[playerIndex].video.webkitVideoDecodedByteCount > 0);
  501. }
  502. if (_players[playerIndex].video.videoTracks)
  503. {
  504. return Boolean(_players[playerIndex].video.videoTracks.length > 0);
  505. }
  506. return true;
  507. },
  508. AVPPlayerHasAudio__deps: ["players", "hasPlayer"],
  509. AVPPlayerHasAudio: function (playerIndex)
  510. {
  511. if (!_hasPlayer(playerIndex)) { return false; }
  512. return _players[playerIndex].video.mozHasAudio || Boolean(_players[playerIndex].video.webkitAudioDecodedByteCount) ||
  513. Boolean(_players[playerIndex].video.audioTracks && _players[playerIndex].video.audioTracks.length);
  514. },
  515. AVPPlayerGetDecodedFrameCount__deps: ["players", "hasPlayer"],
  516. AVPPlayerGetDecodedFrameCount: function (playerIndex)
  517. {
  518. if (!_hasPlayer(playerIndex)) { return 0; }
  519. var vid = _players[playerIndex].video;
  520. if (vid.readyState <= HTMLMediaElement.HAVE_CURRENT_DATA) { return 0; }
  521. var frameCount = 0;
  522. if (vid.mozPresentedFrames)
  523. {
  524. frameCount = vid.mozPresentedFrames;
  525. }
  526. else if (vid.mozDecodedFrames)
  527. {
  528. frameCount = vid.mozDecodedFrames;
  529. }
  530. else if (vid.webkitDecodedFrameCount)
  531. {
  532. frameCount = vid.webkitDecodedFrameCount;
  533. }
  534. /*var q = vid.getVideoPlaybackQuality();
  535. if (q)
  536. {
  537. console.log("frames: " + q.totalVideoFrames + " " + q.droppedVideoFrames);
  538. }*/
  539. return frameCount;
  540. },
  541. AVPPlayerSupportedDecodedFrameCount__deps: ["players", "hasPlayer"],
  542. AVPPlayerSupportedDecodedFrameCount: function (playerIndex)
  543. {
  544. if (!_hasPlayer(playerIndex)) { return false; }
  545. var vid = _players[playerIndex].video;
  546. if (vid.mozPresentedFrames)
  547. {
  548. return true;
  549. }
  550. else if (vid.mozDecodedFrames)
  551. {
  552. return true;
  553. }
  554. else if (vid.webkitDecodedFrameCount)
  555. {
  556. return true;
  557. }
  558. return false;
  559. },
  560. AVPPlayerGetNumBufferedTimeRanges__deps: ["players", "hasPlayer"],
  561. AVPPlayerGetNumBufferedTimeRanges: function(playerIndex)
  562. {
  563. if (!_hasPlayer(playerIndex)) { return 0; }
  564. if (_players[playerIndex].video.buffered)
  565. {
  566. return _players[playerIndex].video.buffered.length;
  567. }
  568. return 0;
  569. },
  570. AVPPlayerGetTimeRangeStart__deps: ["players", "hasPlayer"],
  571. AVPPlayerGetTimeRangeStart: function(playerIndex, rangeIndex)
  572. {
  573. if (!_hasPlayer(playerIndex)) { return 0.0; }
  574. if (_players[playerIndex].video.buffered)
  575. {
  576. if(rangeIndex >= _players[playerIndex].video.buffered.length)
  577. {
  578. return 0.0;
  579. }
  580. return _players[playerIndex].video.buffered.start(rangeIndex);
  581. }
  582. return 0.0;
  583. },
  584. AVPPlayerGetTimeRangeEnd__deps: ["players", "hasPlayer"],
  585. AVPPlayerGetTimeRangeEnd: function(playerIndex, rangeIndex)
  586. {
  587. if (!_hasPlayer(playerIndex)) { return 0.0; }
  588. if (_players[playerIndex].video.buffered)
  589. {
  590. if(rangeIndex >= _players[playerIndex].video.buffered.length)
  591. {
  592. return 0.0;
  593. }
  594. return _players[playerIndex].video.buffered.end(rangeIndex);
  595. }
  596. return 0.0;
  597. },
  598. AVPPlayerGetVideoTrackCount__deps: ["players", "hasPlayer", "AVPPlayerHasVideo"],
  599. AVPPlayerGetVideoTrackCount: function (playerIndex)
  600. {
  601. if (!_hasPlayer(playerIndex)) { return 0; }
  602. var result = 0;
  603. var tracks = _players[playerIndex].video.videoTracks;
  604. if (tracks)
  605. {
  606. result = tracks.length;
  607. }
  608. else
  609. {
  610. if (_AVPPlayerHasVideo(playerIndex))
  611. {
  612. result = 1;
  613. }
  614. }
  615. return result;
  616. },
  617. AVPPlayerGetAudioTrackCount__deps: ["players", "hasPlayer", "AVPPlayerHasAudio"],
  618. AVPPlayerGetAudioTrackCount: function (playerIndex)
  619. {
  620. if (!_hasPlayer(playerIndex)) { return 0; }
  621. var result = 0;
  622. var tracks = _players[playerIndex].video.audioTracks;
  623. if (tracks)
  624. {
  625. result = tracks.length;
  626. }
  627. else
  628. {
  629. if (_AVPPlayerHasAudio(playerIndex))
  630. {
  631. result = 1;
  632. }
  633. }
  634. return result;
  635. },
  636. AVPPlayerGetTextTrackCount__deps: ["players", "hasPlayer"],
  637. AVPPlayerGetTextTrackCount: function (playerIndex)
  638. {
  639. if (!_hasPlayer(playerIndex)) { return 0; }
  640. var result = 0;
  641. var tracks = _players[playerIndex].video.textTracks;
  642. if (tracks)
  643. {
  644. result = tracks.length;
  645. }
  646. return result;
  647. },
  648. AVPPlayerSetActiveVideoTrack__deps: ["players", "hasPlayer"],
  649. AVPPlayerSetActiveVideoTrack: function (playerIndex, trackIndex)
  650. {
  651. if (!_hasPlayer(playerIndex)) { return false; }
  652. var result = false;
  653. if (_players[playerIndex].video.videoTracks)
  654. {
  655. var tracks = _players[playerIndex].video.videoTracks;
  656. if (trackIndex >=0 && trackIndex < tracks.length)
  657. {
  658. tracks[trackIndex].selected = true;
  659. result = true;
  660. }
  661. }
  662. return result;
  663. },
  664. AVPPlayerSetActiveAudioTrack: ["players", "hasPlayer"],
  665. AVPPlayerSetActiveAudioTrack: function (playerIndex, trackIndex)
  666. {
  667. if (!_hasPlayer(playerIndex)) { return false; }
  668. var result = false;
  669. if (_players[playerIndex].video.audioTracks)
  670. {
  671. var tracks = _players[playerIndex].video.audioTracks;
  672. if (trackIndex >=0 && trackIndex < tracks.length)
  673. {
  674. for (i = 0; i < tracks.length; i++)
  675. {
  676. tracks[i].enabled = (i === trackIndex);
  677. }
  678. result = true;
  679. }
  680. }
  681. return result;
  682. },
  683. AVPPlayerSetActiveTextTrack: ["players", "hasPlayer"],
  684. AVPPlayerSetActiveTextTrack: function (playerIndex, trackIndex)
  685. {
  686. if (!_hasPlayer(playerIndex)) { return false; }
  687. var result = false;
  688. if (_players[playerIndex].video.textTracks)
  689. {
  690. var tracks = _players[playerIndex].video.textTracks;
  691. if (trackIndex >=0 && trackIndex < tracks.length)
  692. {
  693. for (i = 0; i < tracks.length; i++)
  694. {
  695. tracks[i].mode = (i === trackIndex)?"showing":"disabled";
  696. }
  697. result = true;
  698. }
  699. }
  700. return result;
  701. },
  702. AVPPlayerStringToBuffer: [],
  703. AVPPlayerStringToBuffer: function (text)
  704. {
  705. // Get size of the string
  706. var bufferSize = lengthBytesUTF8(text) + 1;
  707. // Allocate memory space
  708. var buffer = _malloc(bufferSize);
  709. // Copy old data to the new one then return it
  710. stringToUTF8(text, buffer, bufferSize);
  711. return buffer;
  712. },
  713. AVPPlayerGetVideoTrackName: ["players", "hasPlayer", "AVPPlayerStringToBuffer"],
  714. AVPPlayerGetVideoTrackName: function (playerIndex, trackIndex)
  715. {
  716. if (!_hasPlayer(playerIndex)) { return false; }
  717. var result = null;
  718. var tracks = _players[playerIndex].video.videoTracks;
  719. if (tracks)
  720. {
  721. if (trackIndex >=0 && trackIndex < tracks.length)
  722. {
  723. result = _AVPPlayerStringToBuffer(tracks[trackIndex].label);
  724. }
  725. }
  726. return result;
  727. },
  728. AVPPlayerGetAudioTrackName: ["players", "hasPlayer", "AVPPlayerStringToBuffer"],
  729. AVPPlayerGetAudioTrackName: function (playerIndex, trackIndex)
  730. {
  731. if (!_hasPlayer(playerIndex)) { return false; }
  732. var result = null;
  733. var tracks = _players[playerIndex].video.audioTracks;
  734. if (tracks)
  735. {
  736. if (trackIndex >=0 && trackIndex < tracks.length)
  737. {
  738. result = _AVPPlayerStringToBuffer(tracks[trackIndex].label);
  739. }
  740. }
  741. return result;
  742. },
  743. AVPPlayerGetTextTrackName: ["players", "hasPlayer", "AVPPlayerStringToBuffer"],
  744. AVPPlayerGetTextTrackName: function (playerIndex, trackIndex)
  745. {
  746. if (!_hasPlayer(playerIndex)) { return false; }
  747. var result = null;
  748. var tracks = _players[playerIndex].video.textTracks;
  749. if (tracks)
  750. {
  751. if (trackIndex >=0 && trackIndex < tracks.length)
  752. {
  753. result = _AVPPlayerStringToBuffer(tracks[trackIndex].label);
  754. }
  755. }
  756. return result;
  757. },
  758. AVPPlayerGetVideoTrackLanguage: ["players", "hasPlayer", "AVPPlayerStringToBuffer"],
  759. AVPPlayerGetVideoTrackLanguage: function (playerIndex, trackIndex)
  760. {
  761. if (!_hasPlayer(playerIndex)) { return false; }
  762. var result = null;
  763. var tracks = _players[playerIndex].video.videoTracks;
  764. if (tracks)
  765. {
  766. if (trackIndex >=0 && trackIndex < tracks.length)
  767. {
  768. result = _AVPPlayerStringToBuffer(tracks[trackIndex].language);
  769. }
  770. }
  771. return result;
  772. },
  773. AVPPlayerGetAudioTrackLanguage: ["players", "hasPlayer", "AVPPlayerStringToBuffer"],
  774. AVPPlayerGetAudioTrackLanguage: function (playerIndex, trackIndex)
  775. {
  776. if (!_hasPlayer(playerIndex)) { return false; }
  777. var result = null;
  778. var tracks = _players[playerIndex].video.audioTracks;
  779. if (tracks)
  780. {
  781. if (trackIndex >=0 && trackIndex < tracks.length)
  782. {
  783. result = _AVPPlayerStringToBuffer(tracks[trackIndex].language);
  784. }
  785. }
  786. return result;
  787. },
  788. AVPPlayerGetTextTrackLanguage: ["players", "hasPlayer", "AVPPlayerStringToBuffer"],
  789. AVPPlayerGetTextTrackLanguage: function (playerIndex, trackIndex)
  790. {
  791. if (!_hasPlayer(playerIndex)) { return false; }
  792. var result = null;
  793. var tracks = _players[playerIndex].video.textTracks;
  794. if (tracks)
  795. {
  796. if (trackIndex >=0 && trackIndex < tracks.length)
  797. {
  798. result = _AVPPlayerStringToBuffer(tracks[trackIndex].language);
  799. }
  800. }
  801. return result;
  802. },
  803. AVPPlayerIsVideoTrackActive: ["players", "hasPlayer", "AVPPlayerHasVideo"],
  804. AVPPlayerIsVideoTrackActive: function (playerIndex, trackIndex)
  805. {
  806. if (!_hasPlayer(playerIndex)) { return false; }
  807. var result = false;
  808. var tracks = _players[playerIndex].video.videoTracks;
  809. if (tracks)
  810. {
  811. result = (tracks.selectedIndex === trackIndex);
  812. }
  813. else
  814. {
  815. result = _AVPPlayerHasVideo(playerIndex);
  816. }
  817. return result;
  818. },
  819. AVPPlayerIsAudioTrackActive: ["players", "hasPlayer", "AVPPlayerHasAudio"],
  820. AVPPlayerIsAudioTrackActive: function (playerIndex, trackIndex)
  821. {
  822. if (!_hasPlayer(playerIndex)) { return false; }
  823. var result = false;
  824. var tracks = _players[playerIndex].video.audioTracks;
  825. if (tracks)
  826. {
  827. if (trackIndex >=0 && trackIndex < tracks.length)
  828. {
  829. result = tracks[trackIndex].enabled;
  830. }
  831. }
  832. else
  833. {
  834. result = _AVPPlayerHasAudio(playerIndex);
  835. }
  836. return result;
  837. },
  838. AVPPlayerIsTextTrackActive: ["players", "hasPlayer"],
  839. AVPPlayerIsTextTrackActive: function (playerIndex, trackIndex)
  840. {
  841. if (!_hasPlayer(playerIndex)) { return false; }
  842. var result = false;
  843. var tracks = _players[playerIndex].video.textTracks;
  844. if (tracks)
  845. {
  846. if (trackIndex >=0 && trackIndex < tracks.length)
  847. {
  848. result = (tracks[trackIndex].mode === "showing");
  849. }
  850. }
  851. return result;
  852. }
  853. };
  854. autoAddDeps(AVProVideoWebGL, 'count');
  855. autoAddDeps(AVProVideoWebGL, 'players');
  856. autoAddDeps(AVProVideoWebGL, 'hasPlayer');
  857. autoAddDeps(AVProVideoWebGL, 'AVPPlayerHasVideo');
  858. autoAddDeps(AVProVideoWebGL, 'AVPPlayerHasAudio');
  859. autoAddDeps(AVProVideoWebGL, 'AVPPlayerStringToBuffer');
  860. mergeInto(LibraryManager.library, AVProVideoWebGL);