shaka-player 4.7.13 → 4.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/AUTHORS +1 -0
  2. package/CONTRIBUTORS +1 -0
  3. package/LICENSE +54 -0
  4. package/README.md +22 -1
  5. package/dist/controls.css +1 -1
  6. package/dist/controls.css.map +1 -1
  7. package/dist/deps.js +34 -23
  8. package/dist/locales.js +44 -34
  9. package/dist/shaka-player.compiled.d.ts +194 -44
  10. package/dist/shaka-player.compiled.debug.d.ts +194 -44
  11. package/dist/shaka-player.compiled.debug.externs.js +474 -337
  12. package/dist/shaka-player.compiled.debug.js +949 -832
  13. package/dist/shaka-player.compiled.debug.map +4 -4
  14. package/dist/shaka-player.compiled.externs.js +474 -337
  15. package/dist/shaka-player.compiled.js +1237 -1171
  16. package/dist/shaka-player.compiled.map +4 -4
  17. package/dist/shaka-player.ui.d.ts +257 -47
  18. package/dist/shaka-player.ui.debug.d.ts +257 -47
  19. package/dist/shaka-player.ui.debug.externs.js +591 -376
  20. package/dist/shaka-player.ui.debug.js +1165 -965
  21. package/dist/shaka-player.ui.debug.map +4 -4
  22. package/dist/shaka-player.ui.externs.js +591 -376
  23. package/dist/shaka-player.ui.js +1521 -1404
  24. package/dist/shaka-player.ui.map +4 -4
  25. package/externs/device_sensor_event.js +18 -0
  26. package/externs/hisense.js +16 -0
  27. package/externs/playstation.js +31 -0
  28. package/externs/shaka/abr_manager.js +3 -1
  29. package/externs/shaka/ads.js +5 -0
  30. package/externs/shaka/codecs.js +13 -0
  31. package/externs/shaka/manifest.js +58 -6
  32. package/externs/shaka/net.js +13 -1
  33. package/externs/shaka/player.js +184 -13
  34. package/externs/shaka/text.js +19 -0
  35. package/externs/tizen.js +41 -0
  36. package/externs/webos.js +19 -0
  37. package/externs/xbox.js +43 -0
  38. package/lib/abr/simple_abr_manager.js +9 -1
  39. package/lib/ads/ad_manager.js +19 -2
  40. package/lib/ads/client_side_ad_manager.js +5 -3
  41. package/lib/ads/media_tailor_ad_manager.js +9 -0
  42. package/lib/cast/cast_receiver.js +0 -14
  43. package/lib/cast/cast_utils.js +1 -0
  44. package/lib/cea/mp4_cea_parser.js +6 -1
  45. package/lib/dash/content_protection.js +97 -53
  46. package/lib/dash/dash_parser.js +230 -176
  47. package/lib/dash/mpd_utils.js +72 -65
  48. package/lib/dash/segment_base.js +27 -21
  49. package/lib/dash/segment_list.js +18 -16
  50. package/lib/dash/segment_template.js +26 -21
  51. package/lib/hls/hls_parser.js +358 -164
  52. package/lib/media/buffering_observer.js +25 -1
  53. package/lib/media/drm_engine.js +91 -71
  54. package/lib/media/manifest_filterer.js +220 -0
  55. package/lib/media/media_source_engine.js +34 -5
  56. package/lib/media/preload_manager.js +827 -0
  57. package/lib/media/presentation_timeline.js +11 -0
  58. package/lib/media/segment_index.js +40 -30
  59. package/lib/media/segment_prefetch.js +140 -43
  60. package/lib/media/segment_reference.js +31 -8
  61. package/lib/media/segment_utils.js +208 -25
  62. package/lib/media/streaming_engine.js +319 -63
  63. package/lib/mss/content_protection.js +31 -25
  64. package/lib/mss/mss_parser.js +74 -55
  65. package/lib/net/networking_engine.js +49 -4
  66. package/lib/offline/storage.js +3 -3
  67. package/lib/player.js +882 -673
  68. package/lib/polyfill/media_capabilities.js +16 -1
  69. package/lib/text/simple_text_displayer.js +9 -0
  70. package/lib/text/stub_text_displayer.js +7 -0
  71. package/lib/text/text_engine.js +16 -3
  72. package/lib/text/ttml_text_parser.js +116 -114
  73. package/lib/text/ui_text_displayer.js +28 -11
  74. package/lib/text/vtt_text_parser.js +54 -115
  75. package/lib/transmuxer/opus.js +91 -0
  76. package/lib/transmuxer/ts_transmuxer.js +115 -0
  77. package/lib/util/cmcd_manager.js +152 -3
  78. package/lib/util/dom_utils.js +11 -0
  79. package/lib/util/error.js +5 -0
  80. package/lib/util/fake_event.js +2 -0
  81. package/lib/util/manifest_parser_utils.js +97 -3
  82. package/lib/util/mp4_box_parsers.js +346 -17
  83. package/lib/util/mp4_generator.js +23 -0
  84. package/lib/util/periods.js +19 -0
  85. package/lib/util/platform.js +161 -9
  86. package/lib/util/player_configuration.js +61 -3
  87. package/lib/util/stats.js +16 -0
  88. package/lib/util/stream_utils.js +16 -6
  89. package/lib/util/string_utils.js +36 -0
  90. package/lib/util/tXml.js +814 -0
  91. package/lib/util/ts_parser.js +50 -0
  92. package/lib/util/xml_utils.js +10 -338
  93. package/package.json +2 -2
  94. package/shaka-player.uncompiled.js +8 -0
  95. package/ui/controls.js +187 -5
  96. package/ui/enums.js +2 -0
  97. package/ui/externs/ui.js +30 -3
  98. package/ui/gl_matrix/matrix_4x4.js +568 -0
  99. package/ui/gl_matrix/matrix_quaternion.js +45 -0
  100. package/ui/less/containers.less +11 -0
  101. package/ui/locales/en-GB.json +2 -0
  102. package/ui/locales/en.json +2 -0
  103. package/ui/locales/es-419.json +2 -0
  104. package/ui/locales/es.json +2 -0
  105. package/ui/locales/source.json +8 -0
  106. package/ui/recenter_vr.js +126 -0
  107. package/ui/resolution_selection.js +25 -5
  108. package/ui/statistics_button.js +12 -0
  109. package/ui/text_selection.js +1 -1
  110. package/ui/toggle_stereoscopic.js +127 -0
  111. package/ui/ui.js +74 -38
  112. package/ui/vr_manager.js +557 -0
  113. package/ui/vr_utils.js +232 -0
  114. package/ui/vr_webgl.js +697 -0
package/ui/vr_webgl.js ADDED
@@ -0,0 +1,697 @@
1
+ /*! @license
2
+ * Shaka Player
3
+ * Copyright 2016 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+
8
+ goog.provide('shaka.ui.VRWebgl');
9
+
10
+ goog.require('goog.asserts');
11
+ goog.require('shaka.log');
12
+ goog.require('shaka.Player');
13
+ goog.require('shaka.ui.Matrix4x4');
14
+ goog.require('shaka.ui.MatrixQuaternion');
15
+ goog.require('shaka.ui.VRUtils');
16
+ goog.require('shaka.util.EventManager');
17
+ goog.require('shaka.util.IReleasable');
18
+ goog.require('shaka.util.Timer');
19
+
20
+
21
+ /**
22
+ * @implements {shaka.util.IReleasable}
23
+ */
24
+ shaka.ui.VRWebgl = class {
25
+ /**
26
+ * @param {!HTMLMediaElement} video
27
+ * @param {!shaka.Player} player
28
+ * @param {!HTMLCanvasElement} canvas
29
+ * @param {WebGLRenderingContext} gl
30
+ * @param {string} projectionMode
31
+ */
32
+ constructor(video, player, canvas, gl, projectionMode) {
33
+ /** @private {HTMLVideoElement} */
34
+ this.video_ = /** @type {!HTMLVideoElement} */ (video);
35
+
36
+ /** @private {shaka.Player} */
37
+ this.player_ = player;
38
+
39
+ /** @private {HTMLCanvasElement} */
40
+ this.canvas_ = canvas;
41
+
42
+ /** @private {WebGLRenderingContext} */
43
+ this.gl_ = gl;
44
+
45
+ /** @private {shaka.util.EventManager} */
46
+ this.eventManager_ = new shaka.util.EventManager();
47
+
48
+ /** @private {!Float32Array} */
49
+ this.originalQuaternion_ = shaka.ui.MatrixQuaternion.create();
50
+
51
+ /** @private {!Float32Array} */
52
+ this.currentQuaternion_ = shaka.ui.MatrixQuaternion.create();
53
+
54
+ /** @private {?WebGLProgram} */
55
+ this.shaderProgram_ = null;
56
+
57
+ /** @private {?WebGLBuffer} */
58
+ this.verticesBuffer_ = null;
59
+
60
+ /** @private {?WebGLBuffer} */
61
+ this.verticesTextureCoordBuffer_ = null;
62
+
63
+ /** @private {?WebGLBuffer} */
64
+ this.verticesIndexBuffer_ = null;
65
+
66
+ /** @private {!Float32Array} */
67
+ this.viewMatrix_ = shaka.ui.Matrix4x4.create();
68
+
69
+ /** @private {!Float32Array} */
70
+ this.projectionMatrix_ = shaka.ui.Matrix4x4.create();
71
+
72
+ /** @private {!Float32Array} */
73
+ this.viewProjectionMatrix_ = shaka.ui.Matrix4x4.create();
74
+
75
+ /** @private {!Float32Array} */
76
+ this.identityMatrix_ = shaka.ui.Matrix4x4.create();
77
+
78
+ /** @private {?Float32Array} */
79
+ this.diff_ = null;
80
+
81
+ /** @private {boolean} */
82
+ this.stereoscopicMode_ = false;
83
+
84
+ /** @private {?shaka.util.Timer} */
85
+ this.activeTimer_ = null;
86
+
87
+ /** @private {?shaka.util.Timer} */
88
+ this.resetTimer_ = null;
89
+
90
+ /** @private {number} */
91
+ this.previousCanvasWidth_ = 0;
92
+
93
+ /** @private {number} */
94
+ this.previousCanvasHeight_ = 0;
95
+
96
+ /**
97
+ * @private {?{vertices: !Array.<number>, textureCoords: !Array.<number>,
98
+ * indices: !Array.<number>}}
99
+ */
100
+ this.geometry_ = null;
101
+
102
+ /** @private {?number} */
103
+ this.vertexPositionAttribute_ = null;
104
+
105
+ /** @private {?number} */
106
+ this.textureCoordAttribute_ = null;
107
+
108
+ /** @private {?WebGLTexture} */
109
+ this.texture_ = null;
110
+
111
+ /** @private {number} */
112
+ this.positionY_ = 0;
113
+
114
+ /** @private {number} */
115
+ this.fieldOfView_ = 75;
116
+
117
+ /** @private {number} */
118
+ this.cont_ = 0;
119
+
120
+ /** @private {string} */
121
+ this.projectionMode_ = projectionMode;
122
+
123
+ this.init_();
124
+ }
125
+
126
+ /**
127
+ * @override
128
+ */
129
+ release() {
130
+ if (this.eventManager_) {
131
+ this.eventManager_.release();
132
+ this.eventManager_ = null;
133
+ }
134
+ if (this.activeTimer_) {
135
+ this.activeTimer_.stop();
136
+ this.activeTimer_ = null;
137
+ }
138
+ if (this.resetTimer_) {
139
+ this.resetTimer_.stop();
140
+ this.resetTimer_ = null;
141
+ }
142
+ }
143
+
144
+ /**
145
+ * @return {string}
146
+ */
147
+ getProjectionMode() {
148
+ return this.projectionMode_;
149
+ }
150
+
151
+ /**
152
+ * @param {!Float32Array} quat
153
+ * @return {{pitch: number, yaw: number, roll: number}} as radians
154
+ * @private
155
+ */
156
+ toEulerAngles_(quat) {
157
+ const angles = {
158
+ pitch: 0,
159
+ yaw: 0,
160
+ roll: 0,
161
+ };
162
+ const x = quat[0];
163
+ const y = quat[1];
164
+ const z = quat[2];
165
+ const w = quat[3];
166
+ const x2 = x * x;
167
+ const y2 = y * y;
168
+ const z2 = z * z;
169
+ const w2 = w * w;
170
+ const unit = x2 + y2 + z2 + w2;
171
+ const test = x * w - y * z;
172
+ if (test > 0.499995 * unit) {
173
+ // singularity at the north pole
174
+ angles.pitch = Math.PI / 2;
175
+ angles.yaw = 2 * Math.atan2(y, x);
176
+ angles.roll = 0;
177
+ } else if (test < -0.499995 * unit) {
178
+ // singularity at the south pole
179
+ angles.pitch = -Math.PI / 2;
180
+ angles.yaw = 2 * Math.atan2(y, x);
181
+ angles.roll = 0;
182
+ } else {
183
+ angles.pitch = Math.asin(2 * (x * z - w * y));
184
+ angles.yaw = Math.atan2(2 * (x * w + y * z), 1 - 2 * (z2 + w2));
185
+ angles.roll = Math.atan2(2 * (x * y + z * w), 1 - 2 * (y2 + z2));
186
+ }
187
+ return angles;
188
+ }
189
+
190
+ /**
191
+ * Toogle stereoscopic mode
192
+ */
193
+ toggleStereoscopicMode() {
194
+ this.stereoscopicMode_ = !this.stereoscopicMode_;
195
+ if (!this.stereoscopicMode_) {
196
+ this.gl_.viewport(0, 0, this.canvas_.width, this.canvas_.height);
197
+ }
198
+ this.renderGL_(false);
199
+ }
200
+
201
+ /**
202
+ * Returns true if stereoscopic mode is enabled.
203
+ *
204
+ * @return {boolean}
205
+ */
206
+ isStereoscopicModeEnabled() {
207
+ return this.stereoscopicMode_;
208
+ }
209
+
210
+ /**
211
+ * @private
212
+ */
213
+ init_() {
214
+ this.initMatrices_();
215
+ this.initGL_();
216
+ this.initGLShaders_();
217
+ this.initGLBuffers_();
218
+ this.initGLTexture_();
219
+
220
+ this.eventManager_.listenOnce(this.video_, 'loadeddata', () => {
221
+ let frameRate;
222
+ this.eventManager_.listen(this.video_, 'canplaythrough', () => {
223
+ this.renderGL_();
224
+ });
225
+ this.eventManager_.listen(this.video_, 'playing', () => {
226
+ if (this.activeTimer_) {
227
+ this.activeTimer_.stop();
228
+ }
229
+ if (!frameRate) {
230
+ const variants = this.player_.getVariantTracks();
231
+ for (const variant of variants) {
232
+ const variantFrameRate = variant.frameRate;
233
+ if (variantFrameRate &&
234
+ (!frameRate || frameRate < variantFrameRate)) {
235
+ frameRate = variantFrameRate;
236
+ }
237
+ }
238
+ }
239
+ if (!frameRate) {
240
+ frameRate = 60;
241
+ }
242
+ this.renderGL_();
243
+ this.activeTimer_ = new shaka.util.Timer(() => {
244
+ this.renderGL_();
245
+ }).tickNow().tickEvery(1 / frameRate);
246
+ });
247
+ this.eventManager_.listen(this.video_, 'pause', () => {
248
+ this.activeTimer_.stop();
249
+ this.activeTimer_ = null;
250
+ this.renderGL_();
251
+ });
252
+ this.eventManager_.listen(this.video_, 'seeked', () => {
253
+ this.renderGL_();
254
+ });
255
+
256
+ this.eventManager_.listen(document, 'visibilitychange', () => {
257
+ this.renderGL_();
258
+ });
259
+ });
260
+ }
261
+
262
+ /**
263
+ * @private
264
+ */
265
+ initMatrices_() {
266
+ shaka.ui.Matrix4x4.lookAt(
267
+ this.viewMatrix_, [0, 0, 0], [1, 0, 0], [0, 1, 0]);
268
+ shaka.ui.Matrix4x4.getRotation(
269
+ this.originalQuaternion_, this.viewMatrix_);
270
+ shaka.ui.Matrix4x4.scale(
271
+ this.identityMatrix_, this.identityMatrix_, [4.0, 4.0, 4.0]);
272
+ }
273
+
274
+ /**
275
+ * @private
276
+ */
277
+ initGL_() {
278
+ this.updateViewPort_();
279
+ this.gl_.viewport(
280
+ 0, 0, this.gl_.drawingBufferWidth, this.gl_.drawingBufferHeight);
281
+ this.gl_.clearColor(0.0, 0.0, 0.0, 1.0);
282
+ this.gl_.enable(this.gl_.CULL_FACE);
283
+ this.gl_.cullFace(this.gl_.FRONT);
284
+ // Clear the context with the newly set color. This is
285
+ // the function call that actually does the drawing.
286
+ this.gl_.clear(this.gl_.COLOR_BUFFER_BIT);
287
+ }
288
+
289
+ /**
290
+ * @private
291
+ */
292
+ initGLShaders_() {
293
+ const vertexShader = this.getGLShader_(this.gl_.VERTEX_SHADER);
294
+ const fragmentShader = this.getGLShader_(this.gl_.FRAGMENT_SHADER);
295
+
296
+ // Create program
297
+ this.shaderProgram_ = this.gl_.createProgram();
298
+ this.gl_.attachShader(this.shaderProgram_, vertexShader);
299
+ this.gl_.attachShader(this.shaderProgram_, fragmentShader);
300
+ this.gl_.linkProgram(this.shaderProgram_);
301
+
302
+ // If creating the shader program failed, alert
303
+ if (!this.gl_.getProgramParameter(
304
+ this.shaderProgram_, this.gl_.LINK_STATUS)) {
305
+ shaka.log.error('Unable to initialize the shader program: ',
306
+ this.gl_.getProgramInfoLog(this.shaderProgram_));
307
+ }
308
+
309
+ // Bind data
310
+ if (this.projectionMode_ == 'cubemap') {
311
+ this.vertexPositionAttribute_ = this.gl_.getAttribLocation(
312
+ this.shaderProgram_, 'aVertexPosition');
313
+ this.textureCoordAttribute_ = this.gl_.getAttribLocation(
314
+ this.shaderProgram_, 'aTextureCoord');
315
+ } else {
316
+ this.vertexPositionAttribute_ = this.gl_.getAttribLocation(
317
+ this.shaderProgram_, 'a_vPosition');
318
+ this.gl_.enableVertexAttribArray(this.vertexPositionAttribute_);
319
+ this.textureCoordAttribute_ = this.gl_.getAttribLocation(
320
+ this.shaderProgram_, 'a_TexCoordinate');
321
+ this.gl_.enableVertexAttribArray(this.textureCoordAttribute_);
322
+ }
323
+ }
324
+
325
+ /**
326
+ * Read and generate WebGL shader
327
+ *
328
+ * @param {number} glType Type of shader requested.
329
+ * @return {?WebGLShader}
330
+ * @private
331
+ */
332
+ getGLShader_(glType) {
333
+ let source;
334
+
335
+ switch (glType) {
336
+ case this.gl_.VERTEX_SHADER:
337
+ if (this.projectionMode_ == 'cubemap') {
338
+ source = shaka.ui.VRUtils.VERTEX_CUBE_SHADER;
339
+ } else {
340
+ source = shaka.ui.VRUtils.VERTEX_SPHERE_SHADER;
341
+ }
342
+ break;
343
+ case this.gl_.FRAGMENT_SHADER:
344
+ if (this.projectionMode_ == 'cubemap') {
345
+ source = shaka.ui.VRUtils.FRAGMENT_CUBE_SHADER;
346
+ } else {
347
+ source = shaka.ui.VRUtils.FRAGMENT_SPHERE_SHADER;
348
+ }
349
+ break;
350
+ default:
351
+ return null;
352
+ }
353
+
354
+ const shader = this.gl_.createShader(glType);
355
+
356
+ this.gl_.shaderSource(shader, source);
357
+
358
+ this.gl_.compileShader(shader);
359
+
360
+ if (!this.gl_.getShaderParameter(shader, this.gl_.COMPILE_STATUS)) {
361
+ shaka.log.warning('Error in ' + glType + ' shader: ' +
362
+ this.gl_.getShaderInfoLog(shader));
363
+ }
364
+
365
+ goog.asserts.assert(shader, 'Should have a shader!');
366
+
367
+ return shader;
368
+ }
369
+
370
+ /**
371
+ * @private
372
+ */
373
+ initGLBuffers_() {
374
+ if (this.projectionMode_ == 'cubemap') {
375
+ this.geometry_ = shaka.ui.VRUtils.generateCube();
376
+ } else {
377
+ this.geometry_ = shaka.ui.VRUtils.generateSphere(100);
378
+ }
379
+ this.verticesBuffer_ = this.gl_.createBuffer();
380
+ this.gl_.bindBuffer(this.gl_.ARRAY_BUFFER, this.verticesBuffer_);
381
+ this.gl_.bufferData(this.gl_.ARRAY_BUFFER,
382
+ new Float32Array(this.geometry_.vertices), this.gl_.STATIC_DRAW);
383
+ this.verticesTextureCoordBuffer_ = this.gl_.createBuffer();
384
+ this.gl_.bindBuffer(
385
+ this.gl_.ARRAY_BUFFER, this.verticesTextureCoordBuffer_);
386
+ this.gl_.bufferData(this.gl_.ARRAY_BUFFER,
387
+ new Float32Array(this.geometry_.textureCoords), this.gl_.STATIC_DRAW);
388
+ this.verticesIndexBuffer_ = this.gl_.createBuffer();
389
+ this.gl_.bindBuffer(
390
+ this.gl_.ELEMENT_ARRAY_BUFFER, this.verticesIndexBuffer_);
391
+ this.gl_.bufferData(this.gl_.ELEMENT_ARRAY_BUFFER,
392
+ new Uint16Array(this.geometry_.indices), this.gl_.STATIC_DRAW);
393
+ }
394
+
395
+ /**
396
+ * @private
397
+ */
398
+ initGLTexture_() {
399
+ this.texture_ = this.gl_.createTexture();
400
+ this.gl_.bindTexture(this.gl_.TEXTURE_2D, this.texture_);
401
+
402
+ this.gl_.texParameteri(this.gl_.TEXTURE_2D,
403
+ this.gl_.TEXTURE_WRAP_S, this.gl_.CLAMP_TO_EDGE);
404
+ this.gl_.texParameteri(this.gl_.TEXTURE_2D,
405
+ this.gl_.TEXTURE_WRAP_T, this.gl_.CLAMP_TO_EDGE);
406
+ this.gl_.texParameteri(this.gl_.TEXTURE_2D,
407
+ this.gl_.TEXTURE_MIN_FILTER, this.gl_.NEAREST);
408
+ this.gl_.texParameteri(this.gl_.TEXTURE_2D,
409
+ this.gl_.TEXTURE_MAG_FILTER, this.gl_.NEAREST);
410
+ }
411
+
412
+ /**
413
+ * @param {boolean=} textureUpdate
414
+ * @private
415
+ */
416
+ renderGL_(textureUpdate = true) {
417
+ const loadMode = this.player_.getLoadMode();
418
+ const isMSE = loadMode == shaka.Player.LoadMode.MEDIA_SOURCE;
419
+ if (!this.video_ || this.video_.readyState < 2 ||
420
+ (!isMSE && this.video_.playbackRate == 0)) {
421
+ return;
422
+ }
423
+ shaka.ui.Matrix4x4.perspective(this.projectionMatrix_,
424
+ this.fieldOfView_ * Math.PI / 180, 5 / 3.2, 0.1, 100.0);
425
+
426
+ if (this.projectionMode_ == 'cubemap') {
427
+ shaka.ui.Matrix4x4.perspective(this.projectionMatrix_,
428
+ this.fieldOfView_ * Math.PI / 180, 5 / 2, 0.1, 100.0);
429
+ } else {
430
+ shaka.ui.Matrix4x4.perspective(this.projectionMatrix_,
431
+ this.fieldOfView_ * Math.PI / 180, 5 / 3.2, 0.1, 100.0);
432
+ }
433
+
434
+ this.gl_.useProgram(this.shaderProgram_);
435
+
436
+ this.gl_.clear(this.gl_.COLOR_BUFFER_BIT);
437
+ this.updateViewPort_();
438
+
439
+ if (textureUpdate) {
440
+ this.gl_.activeTexture(this.gl_.TEXTURE0);
441
+ this.gl_.bindTexture(this.gl_.TEXTURE_2D, this.texture_);
442
+ this.gl_.pixelStorei(this.gl_.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 0);
443
+ this.gl_.texImage2D(this.gl_.TEXTURE_2D, 0, this.gl_.RGBA,
444
+ this.gl_.RGBA, this.gl_.UNSIGNED_BYTE, this.video_);
445
+ }
446
+
447
+ // Update matrix
448
+ if (this.projectionMode_ == 'equirectangular') {
449
+ shaka.ui.Matrix4x4.multiply(this.viewProjectionMatrix_,
450
+ this.viewMatrix_, this.identityMatrix_);
451
+ shaka.ui.Matrix4x4.multiply(this.viewProjectionMatrix_,
452
+ this.projectionMatrix_, this.viewProjectionMatrix_);
453
+ }
454
+
455
+ // Plumbing
456
+ // Vertices
457
+ this.gl_.bindBuffer(this.gl_.ARRAY_BUFFER, this.verticesBuffer_);
458
+ goog.asserts.assert(this.vertexPositionAttribute_ != null,
459
+ 'Should have a texture attribute!');
460
+ this.gl_.vertexAttribPointer(
461
+ this.vertexPositionAttribute_, 3, this.gl_.FLOAT, false, 0, 0);
462
+ this.gl_.enableVertexAttribArray(this.vertexPositionAttribute_);
463
+
464
+ // UVs
465
+ this.gl_.bindBuffer(
466
+ this.gl_.ARRAY_BUFFER, this.verticesTextureCoordBuffer_);
467
+ goog.asserts.assert(this.textureCoordAttribute_ != null,
468
+ 'Should have a texture attribute!');
469
+ this.gl_.vertexAttribPointer(
470
+ this.textureCoordAttribute_, 2, this.gl_.FLOAT, false, 0, 0);
471
+ this.gl_.enableVertexAttribArray(this.textureCoordAttribute_);
472
+
473
+ this.gl_.bindBuffer(
474
+ this.gl_.ELEMENT_ARRAY_BUFFER, this.verticesIndexBuffer_);
475
+
476
+ this.setMatrixUniforms_();
477
+
478
+ this.gl_.uniform1i(
479
+ this.gl_.getUniformLocation(this.shaderProgram_, 'uSampler'), 0);
480
+
481
+ if (this.stereoscopicMode_) {
482
+ this.gl_.viewport(0, 0, this.canvas_.width / 2, this.canvas_.height);
483
+ }
484
+
485
+ // Draw
486
+ this.gl_.drawElements(this.gl_.TRIANGLES,
487
+ this.geometry_.indices.length, this.gl_.UNSIGNED_SHORT, 0);
488
+
489
+ if (this.stereoscopicMode_) {
490
+ this.gl_.viewport(this.canvas_.width / 2, 0,
491
+ this.canvas_.width / 2, this.canvas_.height);
492
+ this.gl_.drawElements(this.gl_.TRIANGLES,
493
+ this.geometry_.indices.length, this.gl_.UNSIGNED_SHORT, 0);
494
+ }
495
+ }
496
+
497
+ /**
498
+ * @private
499
+ */
500
+ setMatrixUniforms_() {
501
+ if (this.projectionMode_ == 'cubemap') {
502
+ this.gl_.uniformMatrix4fv(
503
+ this.gl_.getUniformLocation(this.shaderProgram_, 'uProjectionMatrix'),
504
+ false, this.projectionMatrix_);
505
+ this.gl_.uniformMatrix4fv(
506
+ this.gl_.getUniformLocation(this.shaderProgram_, 'uModelViewMatrix'),
507
+ false, this.viewProjectionMatrix_);
508
+ } else {
509
+ this.gl_.uniformMatrix4fv(
510
+ this.gl_.getUniformLocation(this.shaderProgram_, 'u_VPMatrix'),
511
+ false, this.viewProjectionMatrix_);
512
+ }
513
+ }
514
+
515
+ /**
516
+ * @private
517
+ */
518
+ updateViewPort_() {
519
+ let currentWidth = this.video_.videoWidth;
520
+ if (!currentWidth) {
521
+ currentWidth = this.canvas_.scrollWidth;
522
+ }
523
+ let currentHeight = this.video_.videoHeight;
524
+ if (!currentHeight) {
525
+ currentHeight = this.canvas_.scrollHeight;
526
+ }
527
+
528
+ if (this.previousCanvasWidth_ !== currentWidth ||
529
+ this.previousCanvasHeight_ !== currentHeight) {
530
+ this.canvas_.width = currentWidth;
531
+ this.canvas_.height = currentHeight;
532
+
533
+ this.previousCanvasWidth_ = currentWidth;
534
+ this.previousCanvasHeight_ = currentHeight;
535
+
536
+ const ratio = currentWidth / currentHeight;
537
+
538
+ this.projectionMatrix_ = shaka.ui.Matrix4x4.frustum(
539
+ this.projectionMatrix_, -ratio, ratio, -1, 1, 0, 1);
540
+
541
+ this.gl_.viewport(0, 0, currentWidth, currentHeight);
542
+ }
543
+ }
544
+
545
+ /**
546
+ * Rotate the view matrix global
547
+ *
548
+ * @param {!number} yaw Yaw.
549
+ * @param {!number} pitch Pitch.
550
+ * @param {!number} roll Roll.
551
+ */
552
+ rotateViewGlobal(yaw, pitch, roll) {
553
+ const pitchBoundary = 90.0 * Math.PI / 180;
554
+ let matrix;
555
+ if (this.projectionMode_ == 'cubemap') {
556
+ matrix = this.viewProjectionMatrix_;
557
+ } else {
558
+ matrix = this.viewMatrix_;
559
+ }
560
+
561
+ // Rotate global axis
562
+ shaka.ui.Matrix4x4.rotateY(matrix, matrix, yaw);
563
+
564
+ // Variable to limit the pitch movement
565
+ this.positionY_ += pitch;
566
+
567
+ if (this.positionY_ < pitchBoundary &&
568
+ this.positionY_ > -pitchBoundary) {
569
+ const out = shaka.ui.Matrix4x4.create();
570
+ shaka.ui.Matrix4x4.rotateX(out, shaka.ui.Matrix4x4.create(), -1 * pitch);
571
+ // Rotate local axis
572
+ shaka.ui.Matrix4x4.multiply(matrix, out, matrix);
573
+ } else {
574
+ // Doing this we restart the value to the previous position,
575
+ // to not mantain a value over 90º or under -90º.
576
+ this.positionY_ -= pitch;
577
+ }
578
+
579
+ const out2 = shaka.ui.Matrix4x4.create();
580
+ shaka.ui.Matrix4x4.rotateZ(out2, shaka.ui.Matrix4x4.create(), roll);
581
+
582
+ // Rotate local axis
583
+ shaka.ui.Matrix4x4.multiply(matrix, out2, matrix);
584
+
585
+ this.renderGL_(false);
586
+ }
587
+
588
+ /**
589
+ * @param {number} amount
590
+ */
591
+ zoom(amount) {
592
+ const zoomMin = 20;
593
+ const zoomMax = 100;
594
+ amount /= 50;
595
+ if (this.fieldOfView_ >= zoomMin && this.fieldOfView_ <= zoomMax) {
596
+ this.fieldOfView_ += amount;
597
+ }
598
+ if (this.fieldOfView_ < zoomMin) {
599
+ this.fieldOfView_ = zoomMin;
600
+ } else if (this.fieldOfView_ > zoomMax) {
601
+ this.fieldOfView_ = zoomMax;
602
+ }
603
+ this.renderGL_(false);
604
+ }
605
+
606
+ /**
607
+ * @return {number}
608
+ */
609
+ getFieldOfView() {
610
+ return this.fieldOfView_;
611
+ }
612
+
613
+ /**
614
+ * @param {number} fieldOfView
615
+ */
616
+ setFieldOfView(fieldOfView) {
617
+ this.fieldOfView_ = fieldOfView;
618
+ this.renderGL_(false);
619
+ }
620
+
621
+ /**
622
+ * @return {number}
623
+ */
624
+ getNorth() {
625
+ shaka.ui.Matrix4x4.getRotation(this.currentQuaternion_, this.viewMatrix_);
626
+
627
+ const angles = this.toEulerAngles_(this.currentQuaternion_);
628
+
629
+ const normalizedDir = {
630
+ x: Math.cos(angles.yaw) * Math.cos(angles.pitch),
631
+ y: Math.sin(angles.yaw) * Math.cos(angles.pitch),
632
+ z: Math.sin(angles.pitch),
633
+ };
634
+
635
+ const northYaw = Math.acos(normalizedDir.x);
636
+
637
+ return ((northYaw * 180) / Math.PI);
638
+ }
639
+
640
+ /**
641
+ * @param {boolean=} firstTime
642
+ */
643
+ reset(firstTime = true) {
644
+ const steps = 20;
645
+
646
+ if (firstTime) {
647
+ shaka.ui.Matrix4x4.getRotation(
648
+ this.currentQuaternion_, this.viewMatrix_);
649
+ this.cont_ = 0;
650
+ this.diff_ = shaka.ui.MatrixQuaternion.create();
651
+ this.diff_[0] =
652
+ (this.currentQuaternion_[0] - this.originalQuaternion_[0]) / steps;
653
+ this.diff_[1] =
654
+ (this.currentQuaternion_[1] - this.originalQuaternion_[1]) / steps;
655
+ this.diff_[2] =
656
+ (this.currentQuaternion_[2] - this.originalQuaternion_[2]) / steps;
657
+ this.diff_[3] =
658
+ (this.currentQuaternion_[3] - this.originalQuaternion_[3]) / steps;
659
+ }
660
+
661
+ this.currentQuaternion_[0] -= this.diff_[0];
662
+ this.currentQuaternion_[1] -= this.diff_[1];
663
+ this.currentQuaternion_[2] -= this.diff_[2];
664
+ this.currentQuaternion_[3] -= this.diff_[3];
665
+
666
+ // Set the view to the original matrix
667
+ const out = shaka.ui.Matrix4x4.create();
668
+
669
+ shaka.ui.MatrixQuaternion.normalize(
670
+ this.currentQuaternion_, this.currentQuaternion_);
671
+
672
+ shaka.ui.Matrix4x4.fromQuat(out, this.currentQuaternion_);
673
+
674
+ this.viewMatrix_ = out;
675
+
676
+ if (this.resetTimer_) {
677
+ this.resetTimer_.stop();
678
+ this.resetTimer_ = null;
679
+ }
680
+ if (this.cont_ < steps) {
681
+ this.resetTimer_ = new shaka.util.Timer(() => {
682
+ this.reset(false);
683
+ this.positionY_ = 0;
684
+ this.cont_++;
685
+ this.renderGL_(false);
686
+ }).tickAfter(shaka.ui.VRWebgl.ANIMATION_DURATION_ / steps);
687
+ } else {
688
+ shaka.ui.Matrix4x4.fromQuat(out, this.originalQuaternion_);
689
+ this.viewMatrix_ = out;
690
+ }
691
+ }
692
+ };
693
+
694
+ /**
695
+ * @constant {number}
696
+ */
697
+ shaka.ui.VRWebgl.ANIMATION_DURATION_ = 0.5;