shaka-player 3.1.1 → 3.1.5

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 (151) hide show
  1. package/AUTHORS +7 -2
  2. package/CHANGELOG.md +199 -0
  3. package/CONTRIBUTORS +9 -3
  4. package/build/generateExterns.js +1 -1
  5. package/build/misspellings.txt +1 -0
  6. package/build/shakaBuildHelpers.py +6 -5
  7. package/build/subprocessWindowsPatch.py +103 -0
  8. package/demo/common/assets.js +1 -1
  9. package/dist/controls.css +2 -2
  10. package/dist/controls.css.map +1 -1
  11. package/dist/demo.compiled.debug.js +1 -1
  12. package/dist/demo.compiled.js +1 -1
  13. package/dist/deps.js +7 -7
  14. package/dist/locales.js +35 -33
  15. package/dist/receiver.compiled.debug.js +1 -1
  16. package/dist/receiver.compiled.js +1 -1
  17. package/dist/shaka-player.compiled.d.ts +171 -3
  18. package/dist/shaka-player.compiled.debug.d.ts +171 -3
  19. package/dist/shaka-player.compiled.debug.externs.js +179 -1
  20. package/dist/shaka-player.compiled.debug.js +365 -344
  21. package/dist/shaka-player.compiled.debug.map +3 -3
  22. package/dist/shaka-player.compiled.externs.js +179 -1
  23. package/dist/shaka-player.compiled.js +806 -798
  24. package/dist/shaka-player.compiled.map +3 -3
  25. package/dist/shaka-player.ui.d.ts +171 -3
  26. package/dist/shaka-player.ui.debug.d.ts +171 -3
  27. package/dist/shaka-player.ui.debug.externs.js +181 -3
  28. package/dist/shaka-player.ui.debug.js +458 -435
  29. package/dist/shaka-player.ui.debug.map +4 -4
  30. package/dist/shaka-player.ui.externs.js +181 -3
  31. package/dist/shaka-player.ui.js +927 -918
  32. package/dist/shaka-player.ui.map +4 -4
  33. package/docs/tutorials/fairplay.md +1 -1
  34. package/docs/tutorials/faq.md +14 -0
  35. package/docs/tutorials/index.json +2 -2
  36. package/docs/tutorials/upgrade-v3.md +38 -0
  37. package/docs/tutorials/upgrade.md +3 -3
  38. package/externs/ima.js +4 -0
  39. package/externs/shaka/ads.js +2 -0
  40. package/externs/shaka/player.js +6 -0
  41. package/externs/shaka/text.js +10 -0
  42. package/karma.conf.js +1 -0
  43. package/lib/ads/ad_manager.js +29 -11
  44. package/lib/ads/client_side_ad_manager.js +76 -86
  45. package/lib/ads/server_side_ad_manager.js +26 -11
  46. package/lib/cast/cast_proxy.js +3 -2
  47. package/lib/cast/cast_receiver.js +2 -1
  48. package/lib/cast/cast_sender.js +2 -2
  49. package/lib/cea/sei_processor.js +24 -17
  50. package/lib/dash/dash_parser.js +100 -5
  51. package/lib/dash/segment_list.js +1 -1
  52. package/lib/dash/segment_template.js +7 -4
  53. package/lib/hls/hls_parser.js +44 -17
  54. package/lib/media/closed_caption_parser.js +3 -1
  55. package/lib/media/content_workarounds.js +12 -0
  56. package/lib/media/drm_engine.js +20 -1
  57. package/lib/media/gap_jumping_controller.js +8 -4
  58. package/lib/media/media_source_engine.js +1 -2
  59. package/lib/media/playhead.js +1 -1
  60. package/lib/media/presentation_timeline.js +3 -1
  61. package/lib/media/segment_reference.js +8 -0
  62. package/lib/media/streaming_engine.js +28 -19
  63. package/lib/net/networking_engine.js +2 -1
  64. package/lib/player.js +108 -54
  65. package/lib/polyfill/encryption_scheme.js +2 -0
  66. package/lib/polyfill/fullscreen.js +2 -0
  67. package/lib/polyfill/mathround.js +2 -0
  68. package/lib/polyfill/media_capabilities.js +76 -22
  69. package/lib/polyfill/mediasource.js +8 -0
  70. package/lib/polyfill/orientation.js +3 -1
  71. package/lib/polyfill/patchedmediakeys_apple.js +6 -4
  72. package/lib/polyfill/patchedmediakeys_ms.js +6 -4
  73. package/lib/polyfill/patchedmediakeys_nop.js +2 -0
  74. package/lib/polyfill/patchedmediakeys_webkit.js +6 -4
  75. package/lib/polyfill/pip_webkit.js +2 -0
  76. package/lib/polyfill/storage_estimate.js +2 -0
  77. package/lib/polyfill/video_play_promise.js +2 -0
  78. package/lib/polyfill/videoplaybackquality.js +2 -0
  79. package/lib/polyfill/vttcue.js +2 -0
  80. package/lib/text/cue.js +17 -0
  81. package/lib/text/mp4_ttml_parser.js +3 -0
  82. package/lib/text/text_engine.js +14 -2
  83. package/lib/text/ttml_text_parser.js +135 -87
  84. package/lib/text/ui_text_displayer.js +233 -83
  85. package/lib/text/vtt_text_parser.js +4 -2
  86. package/lib/util/fake_event.js +53 -7
  87. package/lib/util/mp4_box_parsers.js +1 -1
  88. package/lib/util/periods.js +111 -35
  89. package/lib/util/platform.js +13 -1
  90. package/lib/util/stream_utils.js +79 -10
  91. package/lib/util/xml_utils.js +19 -0
  92. package/package.json +2 -2
  93. package/test/cast/cast_proxy_unit.js +12 -6
  94. package/test/cast/cast_receiver_integration.js +1 -1
  95. package/test/cast/cast_utils_unit.js +1 -1
  96. package/test/cea/mp4_cea_parser_unit.js +26 -0
  97. package/test/dash/dash_parser_live_unit.js +1 -0
  98. package/test/dash/dash_parser_manifest_unit.js +220 -2
  99. package/test/dash/dash_parser_segment_template_unit.js +3 -3
  100. package/test/hls/hls_parser_unit.js +5 -1
  101. package/test/media/closed_caption_parser_unit.js +20 -0
  102. package/test/media/drm_engine_unit.js +56 -0
  103. package/test/media/playhead_unit.js +27 -1
  104. package/test/media/presentation_timeline_unit.js +19 -0
  105. package/test/media/streaming_engine_integration.js +2 -1
  106. package/test/media/streaming_engine_unit.js +148 -3
  107. package/test/player_integration.js +38 -0
  108. package/test/player_unit.js +101 -0
  109. package/test/test/assets/3675/chunk-stream0-00001.m4s +0 -0
  110. package/test/test/assets/3675/chunk-stream0-00002.m4s +0 -0
  111. package/test/test/assets/3675/chunk-stream0-00003.m4s +0 -0
  112. package/test/test/assets/3675/chunk-stream0-00004.m4s +0 -0
  113. package/test/test/assets/3675/chunk-stream0-00005.m4s +0 -0
  114. package/test/test/assets/3675/chunk-stream0-00006.m4s +0 -0
  115. package/test/test/assets/3675/chunk-stream0-00007.m4s +0 -0
  116. package/test/test/assets/3675/dash_0.mpd +30 -0
  117. package/test/test/assets/3675/dash_1.mpd +30 -0
  118. package/test/test/assets/3675/dash_2.mpd +30 -0
  119. package/test/test/assets/3675/dash_3.mpd +30 -0
  120. package/test/test/assets/3675/dash_4.mpd +30 -0
  121. package/test/test/assets/3675/dash_5.mpd +26 -0
  122. package/test/test/assets/3675/init-stream0.m4s +0 -0
  123. package/test/test/assets/empty_caption_video_init.mp4 +0 -0
  124. package/test/test/assets/empty_caption_video_segment.mp4 +0 -0
  125. package/test/test/util/fake_ad_manager.js +4 -1
  126. package/test/test/util/simple_fakes.js +5 -3
  127. package/test/test/util/ttml_utils.js +81 -0
  128. package/test/text/mp4_ttml_parser_unit.js +11 -18
  129. package/test/text/ttml_text_parser_unit.js +542 -220
  130. package/test/text/ui_text_displayer_unit.js +95 -18
  131. package/test/text/vtt_text_parser_unit.js +17 -1
  132. package/test/ui/localization_unit.js +15 -14
  133. package/test/ui/text_displayer_layout_unit.js +52 -1
  134. package/test/util/mp4_box_parsers_unit.js +28 -0
  135. package/test/util/periods_unit.js +190 -2
  136. package/test/util/stream_utils_unit.js +59 -2
  137. package/ui/airplay_button.js +5 -0
  138. package/ui/big_play_button.js +10 -0
  139. package/ui/cast_button.js +2 -3
  140. package/ui/controls.js +8 -6
  141. package/ui/less/buttons.less +0 -4
  142. package/ui/less/containers.less +10 -5
  143. package/ui/locales/en.json +1 -0
  144. package/ui/locales/ru.json +6 -6
  145. package/ui/locales/source.json +4 -0
  146. package/ui/localization.js +28 -51
  147. package/ui/pip_button.js +2 -3
  148. package/ui/play_button.js +10 -10
  149. package/ui/small_play_button.js +12 -0
  150. package/ui/text_selection.js +1 -0
  151. package/docs/tutorials/upgrade-v2-4.md +0 -481
@@ -15,29 +15,49 @@ goog.require('shaka.util.Platform');
15
15
  * @summary A polyfill to provide navigator.mediaCapabilities on all browsers.
16
16
  * This is necessary for Tizen 3, Xbox One and possibly others we have yet to
17
17
  * discover.
18
+ * @export
18
19
  */
19
20
  shaka.polyfill.MediaCapabilities = class {
20
21
  /**
21
22
  * Install the polyfill if needed.
23
+ * @suppress {const}
24
+ * @export
22
25
  */
23
26
  static install() {
24
- shaka.log.debug('MediaCapabilities: install');
25
-
26
27
  // Since MediaCapabilities is not fully supported on Chromecast yet, we
27
28
  // should always install polyfill for Chromecast.
28
29
  // TODO: re-evaluate MediaCapabilities in the future versions of Chromecast.
29
- if (!shaka.util.Platform.isChromecast() && navigator.mediaCapabilities) {
30
- shaka.log.debug(
30
+ // Since MediaCapabilities implementation is buggy in Apple browsers, we
31
+ // should always install polyfill for Apple browsers.
32
+ // See: https://github.com/google/shaka-player/issues/3530
33
+ // TODO: re-evaluate MediaCapabilities in the future versions of Apple
34
+ // Browsers.
35
+ // Since MediaCapabilities implementation is buggy in PS5 browsers, we
36
+ // should always install polyfill for PS5 browsers.
37
+ // See: https://github.com/google/shaka-player/issues/3582
38
+ // TODO: re-evaluate MediaCapabilities in the future versions of PS5
39
+ // Browsers.
40
+ if (!shaka.util.Platform.isChromecast() &&
41
+ !shaka.util.Platform.isApple() &&
42
+ !shaka.util.Platform.isPS5() &&
43
+ navigator.mediaCapabilities) {
44
+ shaka.log.info(
31
45
  'MediaCapabilities: Native mediaCapabilities support found.');
32
46
  return;
33
- } else if (!window.MediaSource) {
34
- shaka.log.debug(
35
- 'MediaSource must be available to install mediaCapabilities ',
36
- 'polyfill.');
37
- return;
38
47
  }
39
48
 
40
- navigator.mediaCapabilities = /** @type {!MediaCapabilities} */ ({});
49
+ shaka.log.info('MediaCapabilities: install');
50
+
51
+ if (!navigator.mediaCapabilities) {
52
+ navigator.mediaCapabilities = /** @type {!MediaCapabilities} */ ({});
53
+ }
54
+
55
+ // Keep the patched MediaCapabilities object from being garbage-collected in
56
+ // Safari.
57
+ // See https://github.com/google/shaka-player/issues/3696#issuecomment-1009472718
58
+ shaka.polyfill.MediaCapabilities.originalMcap =
59
+ navigator.mediaCapabilities;
60
+
41
61
  navigator.mediaCapabilities.decodingInfo =
42
62
  shaka.polyfill.MediaCapabilities.decodingInfo_;
43
63
  }
@@ -60,21 +80,45 @@ shaka.polyfill.MediaCapabilities = class {
60
80
  return res;
61
81
  }
62
82
 
63
- // Use 'MediaSource.isTypeSupported' to check if the stream is supported.
64
- if (mediaDecodingConfig['video']) {
65
- const contentType = mediaDecodingConfig['video'].contentType;
66
- const isSupported = MediaSource.isTypeSupported(contentType);
67
- if (!isSupported) {
83
+ if (mediaDecodingConfig.type == 'media-source') {
84
+ if (!shaka.util.Platform.supportsMediaSource()) {
68
85
  return res;
69
86
  }
70
- }
87
+ // Use 'MediaSource.isTypeSupported' to check if the stream is supported.
88
+ if (mediaDecodingConfig['video']) {
89
+ const contentType = mediaDecodingConfig['video'].contentType;
90
+ const isSupported = MediaSource.isTypeSupported(contentType);
91
+ if (!isSupported) {
92
+ return res;
93
+ }
94
+ }
71
95
 
72
- if (mediaDecodingConfig['audio']) {
73
- const contentType = mediaDecodingConfig['audio'].contentType;
74
- const isSupported = MediaSource.isTypeSupported(contentType);
75
- if (!isSupported) {
76
- return res;
96
+ if (mediaDecodingConfig['audio']) {
97
+ const contentType = mediaDecodingConfig['audio'].contentType;
98
+ const isSupported = MediaSource.isTypeSupported(contentType);
99
+ if (!isSupported) {
100
+ return res;
101
+ }
77
102
  }
103
+ } else if (mediaDecodingConfig.type == 'file') {
104
+ if (mediaDecodingConfig['video']) {
105
+ const contentType = mediaDecodingConfig['video'].contentType;
106
+ const isSupported = shaka.util.Platform.supportsMediaType(contentType);
107
+ if (!isSupported) {
108
+ return res;
109
+ }
110
+ }
111
+
112
+ if (mediaDecodingConfig['audio']) {
113
+ const contentType = mediaDecodingConfig['audio'].contentType;
114
+ const isSupported = shaka.util.Platform.supportsMediaType(contentType);
115
+ if (!isSupported) {
116
+ return res;
117
+ }
118
+ }
119
+ } else {
120
+ // Otherwise not supported.
121
+ return res;
78
122
  }
79
123
 
80
124
  if (!mediaDecodingConfig.keySystemConfiguration) {
@@ -116,7 +160,7 @@ shaka.polyfill.MediaCapabilities = class {
116
160
  sessionTypes: mediaCapkeySystemConfig.sessionTypes,
117
161
  };
118
162
 
119
- // Only add the audio video capablities if they have valid data.
163
+ // Only add the audio video capabilities if they have valid data.
120
164
  // Otherwise the query will fail.
121
165
  if (audioCapabilities.length) {
122
166
  mediaKeySystemConfig.audioCapabilities = audioCapabilities;
@@ -143,6 +187,16 @@ shaka.polyfill.MediaCapabilities = class {
143
187
  }
144
188
  };
145
189
 
190
+ /**
191
+ * A copy of the MediaCapabilities instance, to prevent Safari from
192
+ * garbage-collecting the polyfilled method on it. We make it public and export
193
+ * it to ensure that it is not stripped out by the compiler.
194
+ *
195
+ * @type {MediaCapabilities}
196
+ * @export
197
+ */
198
+ shaka.polyfill.MediaCapabilities.originalMcap = null;
199
+
146
200
  // Install at a lower priority than MediaSource polyfill, so that we have
147
201
  // MediaSource available first.
148
202
  shaka.polyfill.register(shaka.polyfill.MediaCapabilities.install, -1);
@@ -13,10 +13,12 @@ goog.require('shaka.util.Platform');
13
13
 
14
14
  /**
15
15
  * @summary A polyfill to patch MSE bugs.
16
+ * @export
16
17
  */
17
18
  shaka.polyfill.MediaSource = class {
18
19
  /**
19
20
  * Install the polyfill if needed.
21
+ * @export
20
22
  */
21
23
  static install() {
22
24
  shaka.log.debug('MediaSource.install');
@@ -206,6 +208,12 @@ shaka.polyfill.MediaSource = class {
206
208
  static patchVp09_() {
207
209
  const originalIsTypeSupported = MediaSource.isTypeSupported;
208
210
 
211
+ if (shaka.util.Platform.isWebOS()) {
212
+ // Don't do this on LG webOS as otherwise it is unable
213
+ // to play vp09 at all.
214
+ return;
215
+ }
216
+
209
217
  MediaSource.isTypeSupported = (mimeType) => {
210
218
  // Split the MIME type into its various parameters.
211
219
  const pieces = mimeType.split(/ *; */);
@@ -15,10 +15,12 @@ goog.require('shaka.polyfill');
15
15
  * @summary A polyfill for systems that do not implement screen.orientation.
16
16
  * For now, this only handles systems that implement the deprecated
17
17
  * window.orientation feature... e.g. iPad.
18
+ * @export
18
19
  */
19
20
  shaka.polyfill.Orientation = class {
20
21
  /**
21
22
  * Install the polyfill if needed.
23
+ * @export
22
24
  */
23
25
  static install() {
24
26
  if (screen.orientation) {
@@ -90,7 +92,7 @@ class extends shaka.util.FakeEventTarget {
90
92
 
91
93
  /** Dispatch a 'change' event. */
92
94
  dispatchChangeEvent() {
93
- const event = new shaka.util.FakeEvent('change', {});
95
+ const event = new shaka.util.FakeEvent('change');
94
96
  this.dispatchEvent(event);
95
97
  }
96
98
 
@@ -22,10 +22,12 @@ goog.require('shaka.util.StringUtils');
22
22
  /**
23
23
  * @summary A polyfill to implement modern, standardized EME on top of Apple's
24
24
  * prefixed EME in Safari.
25
+ * @export
25
26
  */
26
27
  shaka.polyfill.PatchedMediaKeysApple = class {
27
28
  /**
28
29
  * Installs the polyfill if needed.
30
+ * @export
29
31
  */
30
32
  static install() {
31
33
  if (!window.HTMLVideoElement || !window.WebKitMediaKeys) {
@@ -565,10 +567,10 @@ class extends shaka.util.FakeEventTarget {
565
567
 
566
568
  const isNew = this.keyStatuses.getStatus() == undefined;
567
569
 
568
- const event2 = new shaka.util.FakeEvent('message', {
569
- messageType: isNew ? 'license-request' : 'license-renewal',
570
- message: shaka.util.BufferUtils.toArrayBuffer(event.message),
571
- });
570
+ const data = new Map()
571
+ .set('messageType', isNew ? 'license-request' : 'license-renewal')
572
+ .set('message', shaka.util.BufferUtils.toArrayBuffer(event.message));
573
+ const event2 = new shaka.util.FakeEvent('message', data);
572
574
 
573
575
  this.dispatchEvent(event2);
574
576
  }
@@ -24,10 +24,12 @@ goog.require('shaka.util.PublicPromise');
24
24
  * {@link https://bit.ly/EmeMar15 EME draft 12 March 2015}
25
25
  * on top of ms-prefixed
26
26
  * {@link https://www.w3.org/TR/2014/WD-encrypted-media-20140218/ EME v20140218}
27
+ * @export
27
28
  */
28
29
  shaka.polyfill.PatchedMediaKeysMs = class {
29
30
  /**
30
31
  * Installs the polyfill if needed.
32
+ * @export
31
33
  */
32
34
  static install() {
33
35
  if (!window.HTMLVideoElement || !window.MSMediaKeys ||
@@ -510,10 +512,10 @@ class extends shaka.util.FakeEventTarget {
510
512
 
511
513
  const isNew = this.keyStatuses.getStatus() == undefined;
512
514
 
513
- const event2 = new shaka.util.FakeEvent('message', {
514
- messageType: isNew ? 'license-request' : 'license-renewal',
515
- message: shaka.util.BufferUtils.toArrayBuffer(event.message),
516
- });
515
+ const data = new Map()
516
+ .set('messageType', isNew ? 'license-request' : 'license-renewal')
517
+ .set('message', shaka.util.BufferUtils.toArrayBuffer(event.message));
518
+ const event2 = new shaka.util.FakeEvent('message', data);
517
519
 
518
520
  this.dispatchEvent(event2);
519
521
  }
@@ -16,10 +16,12 @@ goog.require('shaka.polyfill');
16
16
  * {@link https://bit.ly/EmeMar15 EME draft 12 March 2015} on browsers without
17
17
  * EME.
18
18
  * All methods will fail.
19
+ * @export
19
20
  */
20
21
  shaka.polyfill.PatchedMediaKeysNop = class {
21
22
  /**
22
23
  * Installs the polyfill if needed.
24
+ * @export
23
25
  */
24
26
  static install() {
25
27
  if (!window.HTMLVideoElement ||
@@ -24,10 +24,12 @@ goog.require('shaka.util.Uint8ArrayUtils');
24
24
  * @summary A polyfill to implement
25
25
  * {@link https://bit.ly/EmeMar15 EME draft 12 March 2015} on top of
26
26
  * webkit-prefixed {@link https://bit.ly/Eme01b EME v0.1b}.
27
+ * @export
27
28
  */
28
29
  shaka.polyfill.PatchedMediaKeysWebkit = class {
29
30
  /**
30
31
  * Installs the polyfill if needed.
32
+ * @export
31
33
  */
32
34
  static install() {
33
35
  // Alias.
@@ -449,10 +451,10 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeys = class {
449
451
 
450
452
  const isNew = session.keyStatuses.getStatus() == undefined;
451
453
 
452
- const event2 = new shaka.util.FakeEvent('message', {
453
- messageType: isNew ? 'licenserequest' : 'licenserenewal',
454
- message: event.message,
455
- });
454
+ const data = new Map()
455
+ .set('messageType', isNew ? 'licenserequest' : 'licenserenewal')
456
+ .set('message', event.message);
457
+ const event2 = new shaka.util.FakeEvent('message', data);
456
458
 
457
459
  session.generated();
458
460
  session.dispatchEvent(event2);
@@ -12,10 +12,12 @@ goog.require('shaka.polyfill');
12
12
  /**
13
13
  * @summary A polyfill to provide PiP support in Safari.
14
14
  * Note that Safari only supports PiP on video elements, not audio.
15
+ * @export
15
16
  */
16
17
  shaka.polyfill.PiPWebkit = class {
17
18
  /**
18
19
  * Install the polyfill if needed.
20
+ * @export
19
21
  */
20
22
  static install() {
21
23
  if (!window.HTMLVideoElement) {
@@ -13,10 +13,12 @@ goog.require('shaka.polyfill');
13
13
  * @summary A polyfill to provide navigator.storage.estimate in old
14
14
  * webkit browsers.
15
15
  * See: https://developers.google.com/web/updates/2017/08/estimating-available-storage-space#the-present
16
+ * @export
16
17
  */
17
18
  shaka.polyfill.StorageEstimate = class {
18
19
  /**
19
20
  * Install the polyfill if needed.
21
+ * @export
20
22
  */
21
23
  static install() {
22
24
  if (navigator.storage && navigator.storage.estimate) {
@@ -12,10 +12,12 @@ goog.require('shaka.polyfill');
12
12
 
13
13
  /**
14
14
  * @summary A polyfill to silence the play() Promise in HTML5 video.
15
+ * @export
15
16
  */
16
17
  shaka.polyfill.VideoPlayPromise = class {
17
18
  /**
18
19
  * Install the polyfill if needed.
20
+ * @export
19
21
  */
20
22
  static install() {
21
23
  shaka.log.debug('VideoPlayPromise.install');
@@ -13,10 +13,12 @@ goog.require('shaka.polyfill');
13
13
  * @summary A polyfill to provide MSE VideoPlaybackQuality metrics.
14
14
  * Many browsers do not yet provide this API, and Chrome currently provides
15
15
  * similar data through individual prefixed attributes on HTMLVideoElement.
16
+ * @export
16
17
  */
17
18
  shaka.polyfill.VideoPlaybackQuality = class {
18
19
  /**
19
20
  * Install the polyfill if needed.
21
+ * @export
20
22
  */
21
23
  static install() {
22
24
  if (!window.HTMLVideoElement) {
@@ -12,10 +12,12 @@ goog.require('shaka.polyfill');
12
12
 
13
13
  /**
14
14
  * @summary A polyfill to provide VTTCue.
15
+ * @export
15
16
  */
16
17
  shaka.polyfill.VTTCue = class {
17
18
  /**
18
19
  * Install the polyfill if needed.
20
+ * @export
19
21
  */
20
22
  static install() {
21
23
  if (window.VTTCue) {
package/lib/text/cue.js CHANGED
@@ -210,6 +210,12 @@ shaka.text.Cue = class {
210
210
  */
211
211
  this.nestedCues = [];
212
212
 
213
+ /**
214
+ * @override
215
+ * @exportInterface
216
+ */
217
+ this.isContainer = false;
218
+
213
219
  /**
214
220
  * @override
215
221
  * @exportInterface
@@ -232,6 +238,17 @@ shaka.text.Cue = class {
232
238
  };
233
239
  }
234
240
 
241
+ /**
242
+ * @param {number} start
243
+ * @param {number} end
244
+ * @return {!shaka.text.Cue}
245
+ */
246
+ static lineBreak(start, end) {
247
+ const cue = new shaka.text.Cue(start, end, '');
248
+ cue.lineBreak = true;
249
+ return cue;
250
+ }
251
+
235
252
  /**
236
253
  * Create a copy of the cue with the same properties.
237
254
  * @return {!shaka.text.Cue}
@@ -88,6 +88,9 @@ shaka.text.Mp4TtmlParser = class {
88
88
 
89
89
  shaka.text.TextEngine.registerParser(
90
90
  'application/mp4; codecs="stpp"', () => new shaka.text.Mp4TtmlParser());
91
+ shaka.text.TextEngine.registerParser(
92
+ 'application/mp4; codecs="stpp.ttml"',
93
+ () => new shaka.text.Mp4TtmlParser());
91
94
  shaka.text.TextEngine.registerParser(
92
95
  'application/mp4; codecs="stpp.ttml.im1t"',
93
96
  () => new shaka.text.Mp4TtmlParser());
@@ -345,6 +345,19 @@ shaka.text.TextEngine = class {
345
345
  return cues;
346
346
  }
347
347
 
348
+ /**
349
+ * @param {!shaka.text.Cue} cue the cue to apply the timestamp to recursively
350
+ * @param {number} videoTimestampOffset the timestamp offset of the video
351
+ * @private
352
+ */
353
+ applyVideoTimestampOffsetRecursive_(cue, videoTimestampOffset) {
354
+ cue.startTime += videoTimestampOffset;
355
+ cue.endTime += videoTimestampOffset;
356
+ for (const nested of cue.nestedCues) {
357
+ this.applyVideoTimestampOffsetRecursive_(nested, videoTimestampOffset);
358
+ }
359
+ }
360
+
348
361
  /**
349
362
  * Store the closed captions in the text engine, and append the cues to the
350
363
  * text displayer. This is a side-channel used for embedded text only.
@@ -373,8 +386,7 @@ shaka.text.TextEngine = class {
373
386
 
374
387
  // Adjust CEA captions with respect to the timestamp offset of the video
375
388
  // stream in which they were embedded.
376
- cue.startTime += videoTimestampOffset;
377
- cue.endTime += videoTimestampOffset;
389
+ this.applyVideoTimestampOffsetRecursive_(cue, videoTimestampOffset);
378
390
 
379
391
  const keepThisCue =
380
392
  cue.startTime >= this.appendWindowStart_ &&