shaka-player 3.2.7 → 3.2.10

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 (144) hide show
  1. package/.github/workflows/release-please.yaml +3 -2
  2. package/AUTHORS +1 -1
  3. package/CHANGELOG.md +35 -0
  4. package/CONTRIBUTORS +4 -1
  5. package/README.md +20 -6
  6. package/demo/common/assets.js +1 -1
  7. package/demo/demo.less +0 -1
  8. package/demo/index.html +0 -2
  9. package/demo/main.js +3 -3
  10. package/dist/controls.css +2 -2
  11. package/dist/controls.css.map +1 -1
  12. package/dist/demo.compiled.debug.js +3 -3
  13. package/dist/demo.compiled.debug.map +2 -2
  14. package/dist/demo.compiled.js +3 -3
  15. package/dist/demo.compiled.map +2 -2
  16. package/dist/demo.css +1 -1
  17. package/dist/demo.css.map +1 -1
  18. package/dist/deps.js +3 -3
  19. package/dist/locales.js +27 -27
  20. package/dist/receiver.compiled.debug.js +1 -1
  21. package/dist/receiver.compiled.debug.map +1 -1
  22. package/dist/receiver.compiled.js +1 -1
  23. package/dist/receiver.compiled.map +1 -1
  24. package/dist/shaka-player.compiled.d.ts +235 -224
  25. package/dist/shaka-player.compiled.debug.d.ts +235 -224
  26. package/dist/shaka-player.compiled.debug.externs.js +48 -37
  27. package/dist/shaka-player.compiled.debug.js +176 -170
  28. package/dist/shaka-player.compiled.debug.map +4 -4
  29. package/dist/shaka-player.compiled.externs.js +48 -37
  30. package/dist/shaka-player.compiled.js +763 -760
  31. package/dist/shaka-player.compiled.map +4 -4
  32. package/dist/shaka-player.ui.d.ts +277 -266
  33. package/dist/shaka-player.ui.debug.d.ts +277 -266
  34. package/dist/shaka-player.ui.debug.externs.js +48 -37
  35. package/dist/shaka-player.ui.debug.js +156 -151
  36. package/dist/shaka-player.ui.debug.map +4 -4
  37. package/dist/shaka-player.ui.externs.js +48 -37
  38. package/dist/shaka-player.ui.js +868 -865
  39. package/dist/shaka-player.ui.map +4 -4
  40. package/docs/tutorials/welcome.md +6 -3
  41. package/lib/abr/simple_abr_manager.js +2 -1
  42. package/lib/dash/dash_parser.js +5 -0
  43. package/lib/hls/hls_parser.js +28 -9
  44. package/lib/media/drm_engine.js +3 -0
  45. package/lib/media/presentation_timeline.js +24 -1
  46. package/lib/player.js +1 -1
  47. package/lib/polyfill/media_capabilities.js +1 -0
  48. package/lib/polyfill/videoplaybackquality.js +3 -1
  49. package/lib/util/mime_utils.js +14 -5
  50. package/lib/util/platform.js +41 -1
  51. package/lib/util/stream_utils.js +1 -0
  52. package/lib/util/string_utils.js +56 -14
  53. package/maintained-branches.md +15 -0
  54. package/package.json +6 -5
  55. package/test/hls/hls_live_unit.js +60 -7
  56. package/ui/less/containers.less +1 -1
  57. package/ui/less/general.less +1 -1
  58. package/ui/less/range_elements.less +1 -0
  59. package/.github/pull_request_template.md +0 -38
  60. package/app-engine/README.md +0 -9
  61. package/app-engine/demo-version-index/README.md +0 -14
  62. package/app-engine/demo-version-index/app.yaml +0 -2
  63. package/app-engine/demo-version-index/main.py +0 -162
  64. package/app-engine/demo-version-index/requirements.txt +0 -6
  65. package/app-engine/demo-version-index/templates/index.html +0 -114
  66. package/app-engine/shaka-player-demo/README.md +0 -18
  67. package/app-engine/shaka-player-demo/app.yaml +0 -61
  68. package/app-engine/shaka-player-demo/main.py +0 -95
  69. package/app-engine/shaka-player-demo/posters/10yo.png +0 -0
  70. package/app-engine/shaka-player-demo/posters/10yo.xcf +0 -0
  71. package/app-engine/shaka-player-demo/posters/1yo.jpg +0 -0
  72. package/app-engine/shaka-player-demo/posters/2yo.png +0 -0
  73. package/app-engine/shaka-player-demo/posters/2yo.xcf +0 -0
  74. package/app-engine/shaka-player-demo/posters/3yo.png +0 -0
  75. package/app-engine/shaka-player-demo/posters/3yo.xcf +0 -0
  76. package/app-engine/shaka-player-demo/posters/4yo.png +0 -0
  77. package/app-engine/shaka-player-demo/posters/4yo.xcf +0 -0
  78. package/app-engine/shaka-player-demo/posters/5yo.png +0 -0
  79. package/app-engine/shaka-player-demo/posters/5yo.xcf +0 -0
  80. package/app-engine/shaka-player-demo/posters/6yo.png +0 -0
  81. package/app-engine/shaka-player-demo/posters/6yo.xcf +0 -0
  82. package/app-engine/shaka-player-demo/posters/7yo.png +0 -0
  83. package/app-engine/shaka-player-demo/posters/7yo.xcf +0 -0
  84. package/app-engine/shaka-player-demo/posters/8yo.png +0 -0
  85. package/app-engine/shaka-player-demo/posters/8yo.xcf +0 -0
  86. package/app-engine/shaka-player-demo/posters/9yo.png +0 -0
  87. package/app-engine/shaka-player-demo/posters/9yo.xcf +0 -0
  88. package/app-engine/shaka-player-demo/posters/audioOnly.gif +0 -0
  89. package/app-engine/shaka-player-demo/posters/audioRickRoll.gif +0 -0
  90. package/app-engine/shaka-player-demo/posters/colorbars.gif +0 -0
  91. package/app-engine/shaka-player-demo/posters/fireworks.jpg +0 -0
  92. package/app-engine/shaka-player-demo/posters/party-hat.png +0 -0
  93. package/app-engine/shaka-player-demo/posters/sources.txt +0 -46
  94. package/app-engine/shaka-player-demo/posters/standard.png +0 -0
  95. package/app-engine/shaka-player-demo/posters/trek.jpg +0 -0
  96. package/app-engine/shaka-player-demo/posters/valentines.png +0 -0
  97. package/app-engine/shaka-player-demo/posters/zombie.jpg +0 -0
  98. package/app-engine/shaka-player-demo/posters.py +0 -110
  99. package/app-engine/shaka-player-demo/requirements.txt +0 -5
  100. package/app-engine/shaka-player-demo/time.txt +0 -1
  101. package/build/README.md +0 -127
  102. package/build/__init__.py +0 -0
  103. package/build/all.py +0 -150
  104. package/build/apps.py +0 -186
  105. package/build/build.py +0 -392
  106. package/build/check.py +0 -354
  107. package/build/checkversion.py +0 -84
  108. package/build/compiler.py +0 -513
  109. package/build/conformance.textproto +0 -321
  110. package/build/docker/Dockerfile +0 -20
  111. package/build/docker/docker-compose.yml +0 -10
  112. package/build/docs.py +0 -54
  113. package/build/eslint-plugin-shaka-rules/arg-comment-spacing.js +0 -72
  114. package/build/eslint-plugin-shaka-rules/index.js +0 -24
  115. package/build/eslint-plugin-shaka-rules/package.json +0 -7
  116. package/build/eslint-plugin-shaka-rules/private.js +0 -109
  117. package/build/gendeps.py +0 -71
  118. package/build/generateExterns.js +0 -867
  119. package/build/generateLocalizations.py +0 -262
  120. package/build/generateTsDefs.py +0 -137
  121. package/build/install-linux-prereqs.sh +0 -136
  122. package/build/license-header +0 -5
  123. package/build/misspellings.txt +0 -38
  124. package/build/pixelsChanged.js +0 -35
  125. package/build/shaka-lab.yaml +0 -163
  126. package/build/shakaBuildHelpers.py +0 -356
  127. package/build/stats.py +0 -816
  128. package/build/subprocessWindowsPatch.py +0 -103
  129. package/build/test.py +0 -541
  130. package/build/types/ads +0 -8
  131. package/build/types/cast +0 -6
  132. package/build/types/cea +0 -13
  133. package/build/types/complete +0 -9
  134. package/build/types/core +0 -106
  135. package/build/types/dash +0 -8
  136. package/build/types/hls +0 -9
  137. package/build/types/manifests +0 -5
  138. package/build/types/networking +0 -6
  139. package/build/types/offline +0 -21
  140. package/build/types/polyfill +0 -19
  141. package/build/types/text +0 -11
  142. package/build/types/ui +0 -37
  143. package/build/updateScreenshots.py +0 -85
  144. package/build/wrapper.template.js +0 -52
@@ -98,11 +98,14 @@ You can find a full list of available browsers with `--browsers help`, and you
98
98
  can find a complete list of testing options with `--help`.
99
99
 
100
100
 
101
- #### Join the announcement list
101
+ #### Announcements
102
102
 
103
- If you want to receive release or survey announcements, you should join our
103
+ To subscribe to new releases on GitHub, you can follow
104
+ [instructions from this blog](https://www.jessesquires.com/blog/2020/07/30/github-tip-watching-releases/).
105
+
106
+ To receive infrequent announcements and surveys from us, you can join our
104
107
  [mailing list](https://groups.google.com/forum/#!forum/shaka-player-users).
105
- The list is very low volume.
108
+ The list is very low volume, and can only be written to by us.
106
109
 
107
110
 
108
111
  #### Continue the Tutorials
@@ -216,8 +216,9 @@ shaka.abr.SimpleAbrManager = class {
216
216
  * @export
217
217
  */
218
218
  getBandwidthEstimate() {
219
+ const defaultBandwidthEstimate = this.getDefaultBandwidth_();
219
220
  return this.bandwidthEstimator_.getBandwidthEstimate(
220
- this.config_.defaultBandwidthEstimate);
221
+ defaultBandwidthEstimate);
221
222
  }
222
223
 
223
224
 
@@ -503,6 +503,11 @@ shaka.dash.DashParser = class {
503
503
  }
504
504
  presentationTimeline.setClockOffset(offset);
505
505
  }
506
+
507
+ // This is the first point where we have a meaningful presentation start
508
+ // time, and we need to tell PresentationTimeline that so that it can
509
+ // maintain consistency from here on.
510
+ presentationTimeline.lockStartTime();
506
511
  } else {
507
512
  // Just update the variants and text streams, which may change as periods
508
513
  // are added or removed.
@@ -547,8 +547,14 @@ shaka.hls.HlsParser = class {
547
547
  for (const stream of streamsToNotify) {
548
548
  this.segmentsToNotifyByStream_.push(stream.segmentIndex.references);
549
549
  }
550
+
550
551
  this.notifySegments_();
551
552
 
553
+ // This is the first point where we have a meaningful presentation start
554
+ // time, and we need to tell PresentationTimeline that so that it can
555
+ // maintain consistency from here on.
556
+ this.presentationTimeline_.lockStartTime();
557
+
552
558
  // This asserts that the live edge is being calculated from segment times.
553
559
  // For VOD and event streams, this check should still pass.
554
560
  goog.asserts.assert(
@@ -1660,8 +1666,6 @@ shaka.hls.HlsParser = class {
1660
1666
  /* presentationStartTime= */ null, /* delay= */ 0);
1661
1667
  this.presentationTimeline_.setStatic(true);
1662
1668
  }
1663
-
1664
- this.notifySegments_();
1665
1669
  }
1666
1670
 
1667
1671
  /**
@@ -1775,9 +1779,20 @@ shaka.hls.HlsParser = class {
1775
1779
  const pPreviousReference = i == 0 ?
1776
1780
  previousReference : partialSegmentRefs[partialSegmentRefs.length - 1];
1777
1781
  const pStartTime = (i == 0) ? startTime : pPreviousReference.endTime;
1778
- const pDuration = Number(item.getAttributeValue('DURATION'));
1779
- // A preload hinted partial segment doesn't have duration information,
1780
- // so its startTime and endTime are the same.
1782
+
1783
+ // If DURATION is missing from this partial segment, use the target
1784
+ // partial duration from the top of the playlist, which is a required
1785
+ // attribute for content with partial segments.
1786
+ const pDuration = Number(item.getAttributeValue('DURATION')) ||
1787
+ this.partialTargetDuration_;
1788
+
1789
+ // If for some reason we have neither an explicit duration, nor a target
1790
+ // partial duration, we should SKIP this partial segment to avoid
1791
+ // duplicating content in the presentation timeline.
1792
+ if (!pDuration) {
1793
+ continue;
1794
+ }
1795
+
1781
1796
  const pEndTime = pStartTime + pDuration;
1782
1797
 
1783
1798
  let pStartByte = 0;
@@ -2551,12 +2566,16 @@ shaka.hls.HlsParser = class {
2551
2566
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
2552
2567
  const requestType = shaka.net.NetworkingEngine.RequestType.SEGMENT;
2553
2568
 
2569
+ // If you wait long enough, requesting the first segment can fail
2570
+ // because it has fallen off the left edge of DVR, so to be safer,
2571
+ // let's request the middle segment.
2554
2572
  goog.asserts.assert(playlist.segments.length,
2555
2573
  'Playlist should have segments!');
2556
- const firstSegmentUri = this.variableSubstitution_(
2557
- playlist.segments[0].absoluteUri, variables);
2574
+ const middleSegmentIdx = Math.trunc((playlist.segments.length - 1) / 2);
2575
+ const middleSegmentUri = this.variableSubstitution_(
2576
+ playlist.segments[middleSegmentIdx].absoluteUri, variables);
2558
2577
 
2559
- const parsedUri = new goog.Uri(firstSegmentUri);
2578
+ const parsedUri = new goog.Uri(middleSegmentUri);
2560
2579
  const extension = parsedUri.getPath().split('.').pop();
2561
2580
  const map = HlsParser.EXTENSION_MAP_BY_CONTENT_TYPE_[contentType];
2562
2581
 
@@ -2587,7 +2606,7 @@ shaka.hls.HlsParser = class {
2587
2606
  // If unable to guess mime type, request a segment and try getting it
2588
2607
  // from the response.
2589
2608
  const headRequest = shaka.net.NetworkingEngine.makeRequest(
2590
- [firstSegmentUri], this.config_.retryParameters);
2609
+ [middleSegmentUri], this.config_.retryParameters);
2591
2610
  headRequest.method = 'HEAD';
2592
2611
 
2593
2612
  const response = await this.makeNetworkRequest_(
@@ -1372,6 +1372,9 @@ shaka.media.DrmEngine = class {
1372
1372
  }
1373
1373
  return;
1374
1374
  }
1375
+ if (this.destroyer_.destroyed()) {
1376
+ return;
1377
+ }
1375
1378
 
1376
1379
  const updateEvent = new shaka.util.FakeEvent('drmsessionupdate');
1377
1380
  this.playerInterface_.onEvent(updateEvent);
@@ -93,6 +93,9 @@ shaka.media.PresentationTimeline = class {
93
93
  * @private {number}
94
94
  */
95
95
  this.availabilityTimeOffset_ = 0;
96
+
97
+ /** @private {boolean} */
98
+ this.startTimeLocked_ = false;
96
99
  }
97
100
 
98
101
 
@@ -229,7 +232,8 @@ shaka.media.PresentationTimeline = class {
229
232
  this.maxSegmentEndTime_ =
230
233
  Math.max(this.maxSegmentEndTime_, lastReferenceEndTime);
231
234
 
232
- if (this.presentationStartTime_ != null && this.autoCorrectDrift_) {
235
+ if (this.presentationStartTime_ != null && this.autoCorrectDrift_ &&
236
+ !this.startTimeLocked_) {
233
237
  // Since we have explicit segment end times, calculate a presentation
234
238
  // start based on them. This start time accounts for drift.
235
239
  // Date.now() is in milliseconds, from which we compute "now" in seconds.
@@ -243,6 +247,25 @@ shaka.media.PresentationTimeline = class {
243
247
  }
244
248
 
245
249
 
250
+ /**
251
+ * Lock the presentation timeline's start time. After this is called, no
252
+ * further adjustments to presentationStartTime_ will be permitted.
253
+ *
254
+ * This should be called after all Periods have been parsed, and all calls to
255
+ * notifySegments() from the initial manifest parse have been made.
256
+ *
257
+ * Without this, we can get assertion failures in SegmentIndex for certain
258
+ * DAI content. If DAI adds ad segments to the manifest faster than
259
+ * real-time, adjustments to presentationStartTime_ can cause availability
260
+ * windows to jump around on updates.
261
+ *
262
+ * @export
263
+ */
264
+ lockStartTime() {
265
+ this.startTimeLocked_ = true;
266
+ }
267
+
268
+
246
269
  /**
247
270
  * Gives PresentationTimeline a Stream's minimum segment start time.
248
271
  *
package/lib/player.js CHANGED
@@ -6430,7 +6430,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
6430
6430
  * @define {string} A version number taken from git at compile time.
6431
6431
  * @export
6432
6432
  */
6433
- shaka.Player.version = 'v3.2.7-uncompiled';
6433
+ shaka.Player.version = 'v3.2.10-uncompiled';
6434
6434
 
6435
6435
  // Initialize the deprecation system using the version string we just set
6436
6436
  // on the player.
@@ -39,6 +39,7 @@ shaka.polyfill.MediaCapabilities = class {
39
39
  // Browsers.
40
40
  if (!shaka.util.Platform.isChromecast() &&
41
41
  !shaka.util.Platform.isApple() &&
42
+ !shaka.util.Platform.isPS4() &&
42
43
  !shaka.util.Platform.isPS5() &&
43
44
  navigator.mediaCapabilities) {
44
45
  shaka.log.info(
@@ -7,6 +7,7 @@
7
7
  goog.provide('shaka.polyfill.VideoPlaybackQuality');
8
8
 
9
9
  goog.require('shaka.polyfill');
10
+ goog.require('shaka.util.Platform');
10
11
 
11
12
 
12
13
  /**
@@ -33,7 +34,8 @@ shaka.polyfill.VideoPlaybackQuality = class {
33
34
  return;
34
35
  }
35
36
 
36
- if ('webkitDroppedFrameCount' in proto) {
37
+ if ('webkitDroppedFrameCount' in proto ||
38
+ shaka.util.Platform.isWebOS3()) {
37
39
  proto.getVideoPlaybackQuality =
38
40
  shaka.polyfill.VideoPlaybackQuality.webkit_;
39
41
  }
@@ -8,6 +8,7 @@ goog.provide('shaka.util.MimeUtils');
8
8
 
9
9
  goog.require('shaka.dependencies');
10
10
  goog.require('shaka.media.Transmuxer');
11
+ goog.require('shaka.util.ManifestParserUtils');
11
12
 
12
13
  /**
13
14
  * @summary A set of utility functions for dealing with MIME types.
@@ -32,6 +33,8 @@ shaka.util.MimeUtils = class {
32
33
  /**
33
34
  * Takes a MIME type and a codecs string and produces the full MIME
34
35
  * type. If it's a transport stream, convert its codecs to MP4 codecs.
36
+ * Otherwise for multiplexed content, convert the video MIME types to
37
+ * their audio equivalents if the content type is audio.
35
38
  *
36
39
  * @param {string} mimeType
37
40
  * @param {string} codecs
@@ -40,13 +43,19 @@ shaka.util.MimeUtils = class {
40
43
  */
41
44
  static getFullOrConvertedType(mimeType, codecs, contentType) {
42
45
  const fullMimeType = shaka.util.MimeUtils.getFullType(mimeType, codecs);
46
+ const ContentType = shaka.util.ManifestParserUtils.ContentType;
43
47
 
44
- if (!shaka.dependencies.muxjs() ||
45
- !shaka.media.Transmuxer.isTsContainer(fullMimeType)) {
46
- return fullMimeType;
48
+ if (shaka.media.Transmuxer.isTsContainer(fullMimeType)) {
49
+ if (shaka.dependencies.muxjs()) {
50
+ return shaka.media.Transmuxer.convertTsCodecs(
51
+ contentType, fullMimeType);
52
+ }
53
+ } else if (contentType == ContentType.AUDIO) {
54
+ // video/mp2t is the correct mime type for TS audio, so only replace the
55
+ // word "video" with "audio" for non-TS audio content.
56
+ return fullMimeType.replace('video', 'audio');
47
57
  }
48
-
49
- return shaka.media.Transmuxer.convertTsCodecs(contentType, fullMimeType);
58
+ return fullMimeType;
50
59
  }
51
60
 
52
61
 
@@ -142,6 +142,18 @@ shaka.util.Platform = class {
142
142
  return shaka.util.Platform.userAgentContains_('Web0S');
143
143
  }
144
144
 
145
+ /**
146
+ * Check if the current platform is a WebOS 3.
147
+ *
148
+ * @return {boolean}
149
+ */
150
+ static isWebOS3() {
151
+ // See: http://webostv.developer.lge.com/discover/specifications/web-engine/
152
+ return shaka.util.Platform.userAgentContains_('Web0S') &&
153
+ shaka.util.Platform.userAgentContains_(
154
+ 'Chrome/38.0.2125.122 Safari/537.36');
155
+ }
156
+
145
157
  /**
146
158
  * Check if the current platform is a Google Chromecast.
147
159
  *
@@ -175,7 +187,9 @@ shaka.util.Platform = class {
175
187
  */
176
188
  static isApple() {
177
189
  return !!navigator.vendor && navigator.vendor.includes('Apple') &&
178
- !shaka.util.Platform.isTizen();
190
+ !shaka.util.Platform.isTizen() &&
191
+ !shaka.util.Platform.isEOS() &&
192
+ !shaka.util.Platform.isPS4();
179
193
  }
180
194
 
181
195
  /**
@@ -191,6 +205,13 @@ shaka.util.Platform = class {
191
205
  return shaka.util.Platform.userAgentContains_('PlayStation 5');
192
206
  }
193
207
 
208
+ /**
209
+ * Check if the current platform is Playstation 4.
210
+ */
211
+ static isPS4() {
212
+ return shaka.util.Platform.userAgentContains_('PlayStation 4');
213
+ }
214
+
194
215
  /**
195
216
  * Returns a major version number for Safari, or Safari-based iOS browsers.
196
217
  *
@@ -228,6 +249,25 @@ shaka.util.Platform = class {
228
249
  return null;
229
250
  }
230
251
 
252
+ /**
253
+ * Check if the current platform is Apple Safari
254
+ * or Safari-based iOS browsers.
255
+ *
256
+ * @return {boolean}
257
+ */
258
+ static isSafari() {
259
+ return !!shaka.util.Platform.safariVersion();
260
+ }
261
+
262
+ /**
263
+ * Check if the current platform is an EOS set-top box.
264
+ *
265
+ * @return {boolean}
266
+ */
267
+ static isEOS() {
268
+ return shaka.util.Platform.userAgentContains_('PC=EOS');
269
+ }
270
+
231
271
  /**
232
272
  * Guesses if the platform is a mobile one (iOS or Android).
233
273
  *
@@ -981,6 +981,7 @@ shaka.util.StreamUtils = class {
981
981
  track.channelsCount = audio.channelsCount;
982
982
  track.audioSamplingRate = audio.audioSamplingRate;
983
983
  track.audioBandwidth = audio.bandwidth || null;
984
+ track.spatialAudio = audio.spatialAudio;
984
985
  track.label = audio.label;
985
986
  track.audioRoles = audio.roles;
986
987
  }
@@ -11,6 +11,7 @@ goog.require('shaka.log');
11
11
  goog.require('shaka.util.BufferUtils');
12
12
  goog.require('shaka.util.Error');
13
13
  goog.require('shaka.util.Lazy');
14
+ goog.require('shaka.util.Platform');
14
15
 
15
16
 
16
17
  /**
@@ -36,19 +37,38 @@ shaka.util.StringUtils = class {
36
37
  if (uint8[0] == 0xef && uint8[1] == 0xbb && uint8[2] == 0xbf) {
37
38
  uint8 = uint8.subarray(3);
38
39
  }
39
-
40
- // Use the TextDecoder interface to decode the text. This has the advantage
41
- // compared to the previously-standard decodeUriComponent that it will
42
- // continue parsing even if it finds an invalid UTF8 character, rather than
43
- // stop and throw an error.
44
- const utf8decoder = new TextDecoder();
45
- const decoded = utf8decoder.decode(uint8);
46
- if (decoded.includes('\uFFFD')) {
47
- shaka.log.alwaysError('Decoded string contains an "unknown character" ' +
48
- 'codepoint. That probably means the UTF8 ' +
49
- 'encoding was incorrect!');
40
+ if (window.TextDecoder && !shaka.util.Platform.isPS4()) {
41
+ // Use the TextDecoder interface to decode the text. This has the
42
+ // advantage compared to the previously-standard decodeUriComponent that
43
+ // it will continue parsing even if it finds an invalid UTF8 character,
44
+ // rather than stop and throw an error.
45
+ const utf8decoder = new TextDecoder();
46
+ const decoded = utf8decoder.decode(uint8);
47
+ if (decoded.includes('\uFFFD')) {
48
+ shaka.log.alwaysError('Decoded string contains an "unknown character' +
49
+ '" codepoint. That probably means the UTF8 ' +
50
+ 'encoding was incorrect!');
51
+ }
52
+ return decoded;
53
+ } else {
54
+ // http://stackoverflow.com/a/13691499
55
+ const utf8 = shaka.util.StringUtils.fromCharCode(uint8);
56
+ // This converts each character in the string to an escape sequence. If
57
+ // the character is in the ASCII range, it is not converted; otherwise it
58
+ // is converted to a URI escape sequence.
59
+ // Example: '\x67\x35\xe3\x82\xac' -> 'g#%E3%82%AC'
60
+ const escaped = escape(utf8);
61
+ // Decode the escaped sequence. This will interpret UTF-8 sequences into
62
+ // the correct character.
63
+ // Example: 'g#%E3%82%AC' -> 'g#€'
64
+ try {
65
+ return decodeURIComponent(escaped);
66
+ } catch (e) {
67
+ throw new shaka.util.Error(
68
+ shaka.util.Error.Severity.CRITICAL, shaka.util.Error.Category.TEXT,
69
+ shaka.util.Error.Code.BAD_ENCODING);
70
+ }
50
71
  }
51
- return decoded;
52
72
  }
53
73
 
54
74
 
@@ -141,8 +161,30 @@ shaka.util.StringUtils = class {
141
161
  * @export
142
162
  */
143
163
  static toUTF8(str) {
144
- const utf8Encoder = new TextEncoder();
145
- return shaka.util.BufferUtils.toArrayBuffer(utf8Encoder.encode(str));
164
+ if (window.TextEncoder && !shaka.util.Platform.isPS4()) {
165
+ const utf8Encoder = new TextEncoder();
166
+ return shaka.util.BufferUtils.toArrayBuffer(utf8Encoder.encode(str));
167
+ } else {
168
+ // http://stackoverflow.com/a/13691499
169
+ // Converts the given string to a URI encoded string. If a character
170
+ // falls in the ASCII range, it is not converted; otherwise it will be
171
+ // converted to a series of URI escape sequences according to UTF-8.
172
+ // Example: 'g#€' -> 'g#%E3%82%AC'
173
+ const encoded = encodeURIComponent(str);
174
+ // Convert each escape sequence individually into a character. Each
175
+ // escape sequence is interpreted as a code-point, so if an escape
176
+ // sequence happens to be part of a multi-byte sequence, each byte will
177
+ // be converted to a single character.
178
+ // Example: 'g#%E3%82%AC' -> '\x67\x35\xe3\x82\xac'
179
+ const utf8 = unescape(encoded);
180
+
181
+ const result = new Uint8Array(utf8.length);
182
+ for (let i = 0; i < utf8.length; i++) {
183
+ const item = utf8[i];
184
+ result[i] = item.charCodeAt(0);
185
+ }
186
+ return shaka.util.BufferUtils.toArrayBuffer(result);
187
+ }
146
188
  }
147
189
 
148
190
 
@@ -0,0 +1,15 @@
1
+ # Maintained Shaka Player Branches
2
+
3
+ We are currently maintaining the following branches of Shaka Player:
4
+
5
+ - v4.1 (latest)
6
+ - v4.0 (previous)
7
+ - v3.3 (LTS until April 30, 2023)
8
+ - v3.2 (in use by the Cast Application Framework)
9
+
10
+ Other branches are no longer receiving bug fixes, and we recommend you upgrade
11
+ to a maintained branch. For details on upgrading, please see our
12
+ [upgrade guide](https://shaka-player-demo.appspot.com/docs/api/tutorial-upgrade.html).
13
+
14
+ For more information on how these branches are chosen, please refer to our
15
+ [Branch Maintenance Policy](https://shaka-project.github.io/maintenance/shaka-player.html#branch-maintenance-policy).
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "shaka-player",
3
3
  "description": "DASH/EME video player library",
4
- "version": "3.2.7",
4
+ "version": "3.2.10",
5
5
  "homepage": "https://github.com/shaka-project/shaka-player",
6
6
  "author": "Google",
7
7
  "maintainers": [
@@ -27,7 +27,6 @@
27
27
  "eslint-config-google": "^0.14.0",
28
28
  "eslint-plugin-shaka-rules": "file:./build/eslint-plugin-shaka-rules",
29
29
  "esprima": "^4.0.1",
30
- "fastestsmallesttextencoderdecoder": "^1.0.22",
31
30
  "fontfaceonload": "^1.0.2",
32
31
  "google-closure-compiler-java": "^20220301.0.0",
33
32
  "google-closure-deps": "https://gitpkg.now.sh/google/closure-library/closure-deps?d7736da6",
@@ -50,7 +49,7 @@
50
49
  "less": "https://gitpkg.now.sh/joeyparrish/less.js/packages/less?28c63a43",
51
50
  "less-plugin-clean-css": "github:austingardner/less-plugin-clean-css#4e9e77bf",
52
51
  "material-design-lite": "^1.3.0",
53
- "mux.js": "^5.14.1",
52
+ "mux.js": "^6.2.0",
54
53
  "open-sans-fonts": "^1.6.2",
55
54
  "postcss-less": "^6.0.0",
56
55
  "pwacompat": "^2.0.17",
@@ -71,7 +70,6 @@
71
70
  "dialog-polyfill/dist/dialog-polyfill.js",
72
71
  "eme-encryption-scheme-polyfill/index.js",
73
72
  "es6-promise-polyfill/promise.min.js",
74
- "fastestsmallesttextencoderdecoder/EncoderDecoderTogether.min.js",
75
73
  "google-closure-library/closure/goog/base.js",
76
74
  "less/dist/less.js",
77
75
  "material-design-lite/dist/material.indigo-blue.min.css",
@@ -96,6 +94,9 @@
96
94
  "prepublishOnly": "python build/checkversion.py && python build/all.py --force"
97
95
  },
98
96
  "dependencies": {
99
- "eme-encryption-scheme-polyfill": "^2.0.3"
97
+ "eme-encryption-scheme-polyfill": "^2.0.5"
98
+ },
99
+ "engines": {
100
+ "node": ">=14"
100
101
  }
101
102
  }
@@ -630,11 +630,13 @@ describe('HlsParser live', () => {
630
630
  expect(ref.startTime).not.toBeLessThan(rolloverOffset);
631
631
  });
632
632
 
633
+ // Test for https://github.com/shaka-project/shaka-player/issues/4223
633
634
  it('parses streams with partial and preload hinted segments', async () => {
634
635
  playerInterface.isLowLatencyMode = () => true;
635
636
  const mediaWithPartialSegments = [
636
637
  '#EXTM3U\n',
637
638
  '#EXT-X-TARGETDURATION:5\n',
639
+ '#EXT-X-PART-INF:PART-TARGET=1.5\n',
638
640
  '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
639
641
  '#EXT-X-MEDIA-SEQUENCE:0\n',
640
642
  // ref includes partialRef, partialRef2
@@ -668,6 +670,11 @@ describe('HlsParser live', () => {
668
670
  segmentDataStartTime + 4, /* baseUri= */ '', /* startByte= */ 200,
669
671
  /* endByte= */ 429);
670
672
 
673
+ const ref = ManifestParser.makeReference(
674
+ 'test:/main.mp4', segmentDataStartTime, segmentDataStartTime + 4,
675
+ /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 429,
676
+ /* timestampOffset= */ 0, [partialRef, partialRef2]);
677
+
671
678
  const partialRef3 = ManifestParser.makeReference(
672
679
  'test:/partial.mp4', segmentDataStartTime + 4,
673
680
  segmentDataStartTime + 6,
@@ -677,17 +684,12 @@ describe('HlsParser live', () => {
677
684
  // so its startTime and endTime are the same.
678
685
  const preloadRef = ManifestParser.makeReference(
679
686
  'test:/partial.mp4', segmentDataStartTime + 6,
680
- segmentDataStartTime + 6,
687
+ segmentDataStartTime + 7.5,
681
688
  /* baseUri= */ '', /* startByte= */ 210, /* endByte= */ null);
682
689
 
683
- const ref = ManifestParser.makeReference(
684
- 'test:/main.mp4', segmentDataStartTime, segmentDataStartTime + 4,
685
- /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 429,
686
- /* timestampOffset= */ 0, [partialRef, partialRef2]);
687
-
688
690
  // ref2 is not fully published yet, so it doesn't have a segment uri.
689
691
  const ref2 = ManifestParser.makeReference(
690
- '', segmentDataStartTime + 4, segmentDataStartTime + 6,
692
+ '', segmentDataStartTime + 4, segmentDataStartTime + 7.5,
691
693
  /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
692
694
  /* timestampOffset= */ 0, [partialRef3, preloadRef]);
693
695
 
@@ -697,6 +699,56 @@ describe('HlsParser live', () => {
697
699
  ManifestParser.verifySegmentIndex(video, [ref, ref2]);
698
700
  });
699
701
 
702
+ // Test for https://github.com/shaka-project/shaka-player/issues/4223
703
+ it('ignores preload hinted segments without target duration', async () => {
704
+ playerInterface.isLowLatencyMode = () => true;
705
+
706
+ // Missing PART-TARGET, so preload hints are skipped.
707
+ const mediaWithPartialSegments = [
708
+ '#EXTM3U\n',
709
+ '#EXT-X-TARGETDURATION:5\n',
710
+ '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
711
+ '#EXT-X-MEDIA-SEQUENCE:0\n',
712
+ '#EXTINF:4,\n',
713
+ // ref1
714
+ 'main.mp4\n',
715
+ // ref2 includes partialRef, but not preloadRef
716
+ // partialRef
717
+ '#EXT-X-PART:DURATION=2,URI="partial.mp4",BYTERANGE=210@0\n',
718
+ // preloadRef
719
+ '#EXT-X-PRELOAD-HINT:TYPE=PART,URI="partial.mp4",BYTERANGE-START=210\n',
720
+ ].join('');
721
+
722
+ fakeNetEngine
723
+ .setResponseText('test:/master', master)
724
+ .setResponseText('test:/video', mediaWithPartialSegments)
725
+ .setResponseValue('test:/init.mp4', initSegmentData)
726
+ .setResponseValue('test:/main.mp4', segmentData)
727
+ .setResponseValue('test:/partial.mp4', segmentData)
728
+ .setResponseValue('test:/partial2.mp4', segmentData);
729
+
730
+ const ref1 = ManifestParser.makeReference(
731
+ 'test:/main.mp4', segmentDataStartTime, segmentDataStartTime + 4,
732
+ /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
733
+ /* timestampOffset= */ 0, []);
734
+
735
+ const partialRef = ManifestParser.makeReference(
736
+ 'test:/partial.mp4', segmentDataStartTime + 4,
737
+ segmentDataStartTime + 6,
738
+ /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 209);
739
+
740
+ // ref2 is not fully published yet, so it doesn't have a segment uri.
741
+ const ref2 = ManifestParser.makeReference(
742
+ '', segmentDataStartTime + 4, segmentDataStartTime + 6,
743
+ /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 209,
744
+ /* timestampOffset= */ 0, [partialRef]);
745
+
746
+ const manifest = await parser.start('test:/master', playerInterface);
747
+ const video = manifest.variants[0].video;
748
+ await video.createSegmentIndex();
749
+ ManifestParser.verifySegmentIndex(video, [ref1, ref2]);
750
+ });
751
+
700
752
  // Test for https://github.com/shaka-project/shaka-player/issues/4185
701
753
  it('does not fail on preload hints with LL mode off', async () => {
702
754
  // LL mode must be off for this test!
@@ -706,6 +758,7 @@ describe('HlsParser live', () => {
706
758
  '#EXTM3U\n',
707
759
  '#EXT-X-TARGETDURATION:5\n',
708
760
  '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
761
+ '#EXT-X-PART-INF:PART-TARGET=1.5\n',
709
762
  '#EXTINF:4,\n',
710
763
  'main.mp4\n',
711
764
  '#EXT-X-PART:DURATION=2,URI="partial.mp4",BYTERANGE=210@0\n',
@@ -161,7 +161,7 @@
161
161
  /* Consistent margins (external) and padding (internal) between controls. */
162
162
  .bottom-panels-elements-margin();
163
163
 
164
- padding: 0;
164
+ padding: 0 5px;
165
165
 
166
166
  /* Transparent backgrounds, no borders, and a pointer when you mouse over
167
167
  * them. */
@@ -37,7 +37,7 @@
37
37
  }
38
38
 
39
39
  .bottom-panels-elements-margin() {
40
- margin: 1px 6px;
40
+ margin: 1px;
41
41
  }
42
42
 
43
43
  /* For containers which host elements overlaying other things. */
@@ -140,6 +140,7 @@
140
140
 
141
141
  .shaka-volume-bar-container {
142
142
  width: 100px;
143
+ padding: 0;
143
144
  }
144
145
 
145
146
  .shaka-range-element {
@@ -1,38 +0,0 @@
1
- ## Description
2
-
3
- <!--
4
- Give the PR a helpful title that summaries what this PR changes. Here, include
5
- a summary of the change and which issue is fixed. Also include relevant
6
- motivation and context. List any dependencies that are required for this
7
- change.
8
-
9
- If this fixes any issues, include lines like this:
10
- Fixes #123
11
- -->
12
-
13
-
14
- ## Screenshots (optional)
15
-
16
- <!--
17
- If you change the UI, add before and after screenshots demonstrating your
18
- changes.
19
- -->
20
-
21
-
22
- ## Type of change
23
-
24
- - [ ] Bug fix (non-breaking change which fixes an issue)
25
- - [ ] New feature (non-breaking change which adds functionality)
26
- - [ ] Breaking change (fix or feature that would cause existing functionality to
27
- not work as expected)
28
- - [ ] This change requires a documentation update
29
-
30
- ## Checklist:
31
-
32
- - [ ] I have signed the Google CLA <https://cla.developers.google.com>
33
- - [ ] My code follows the style guidelines of this project
34
- - [ ] I have made corresponding changes to the documentation
35
- - [ ] I have added tests that prove my fix is effective or that my feature works
36
- - [ ] I have verified my change on multiple browsers on different platforms
37
- - [ ] I have run `./build/all.py` and the build passes
38
- - [ ] I have run `./build/test.py` and all tests pass