shaka-player 4.6.3 → 4.6.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 (49) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/demo/common/asset.js +0 -1
  3. package/demo/common/assets.js +0 -1
  4. package/dist/demo.compiled.debug.map +1 -1
  5. package/dist/demo.compiled.map +1 -1
  6. package/dist/deps.js +5 -5
  7. package/dist/locales.js +33 -33
  8. package/dist/receiver.compiled.debug.map +1 -1
  9. package/dist/receiver.compiled.map +1 -1
  10. package/dist/shaka-player.compiled.d.ts +1 -1
  11. package/dist/shaka-player.compiled.debug.d.ts +1 -1
  12. package/dist/shaka-player.compiled.debug.externs.js +5 -2
  13. package/dist/shaka-player.compiled.debug.js +172 -171
  14. package/dist/shaka-player.compiled.debug.map +3 -3
  15. package/dist/shaka-player.compiled.externs.js +5 -2
  16. package/dist/shaka-player.compiled.js +227 -224
  17. package/dist/shaka-player.compiled.map +3 -3
  18. package/dist/shaka-player.ui.d.ts +1 -1
  19. package/dist/shaka-player.ui.debug.d.ts +1 -1
  20. package/dist/shaka-player.ui.debug.externs.js +5 -2
  21. package/dist/shaka-player.ui.debug.js +196 -195
  22. package/dist/shaka-player.ui.debug.map +3 -3
  23. package/dist/shaka-player.ui.externs.js +5 -2
  24. package/dist/shaka-player.ui.js +223 -220
  25. package/dist/shaka-player.ui.map +3 -3
  26. package/docs/tutorials/ui.md +3 -1
  27. package/lib/ads/client_side_ad_manager.js +4 -0
  28. package/lib/ads/media_tailor_ad_manager.js +5 -0
  29. package/lib/ads/server_side_ad_manager.js +4 -0
  30. package/lib/hls/hls_parser.js +17 -5
  31. package/lib/media/drm_engine.js +0 -3
  32. package/lib/media/media_source_engine.js +1 -1
  33. package/lib/media/streaming_engine.js +3 -2
  34. package/lib/media/video_wrapper.js +4 -3
  35. package/lib/net/networking_utils.js +12 -3
  36. package/lib/player.js +5 -7
  37. package/lib/text/simple_text_displayer.js +8 -7
  38. package/lib/text/text_utils.js +39 -13
  39. package/lib/text/ui_text_displayer.js +20 -11
  40. package/lib/text/web_vtt_generator.js +1 -1
  41. package/lib/util/ts_parser.js +12 -8
  42. package/package.json +1 -1
  43. package/test/media/drm_engine_unit.js +27 -0
  44. package/test/player_unit.js +31 -0
  45. package/test/test/util/layout_tests.js +2 -1
  46. package/test/text/simple_text_displayer_unit.js +1 -1
  47. package/test/text/web_vtt_generator_unit.js +3 -3
  48. package/test/transmuxer/transmuxer_integration.js +3 -3
  49. package/ui/volume_bar.js +10 -6
@@ -204,11 +204,13 @@ constructor.
204
204
  // "local" because it is for local playback only, as opposed to the player proxy
205
205
  // object, which will route your calls to the ChromeCast receiver as necessary.
206
206
  const localPlayer = new shaka.Player();
207
- await localPlayer.attach(videoElement);
208
207
  // "Overlay" because the UI will add DOM elements inside the container,
209
208
  // to visually overlay the video element
210
209
  const ui = new shaka.ui.Overlay(localPlayer, videoContainerElement,
211
210
  videoElement);
211
+ // Now that the player has been configured to be part of a UI, attach it to the
212
+ // video.
213
+ await localPlayer.attach(videoElement);
212
214
 
213
215
  // As with DOM-based setup, get access to the UI controls and player from the
214
216
  // UI.
@@ -13,6 +13,10 @@ goog.provide('shaka.ads.ClientSideAdManager');
13
13
 
14
14
  goog.require('goog.asserts');
15
15
  goog.require('shaka.ads.ClientSideAd');
16
+ goog.require('shaka.log');
17
+ goog.require('shaka.util.Dom');
18
+ goog.require('shaka.util.EventManager');
19
+ goog.require('shaka.util.FakeEvent');
16
20
  goog.require('shaka.util.IReleasable');
17
21
 
18
22
  /**
@@ -15,7 +15,12 @@ goog.require('goog.asserts');
15
15
  goog.require('shaka.ads.MediaTailorAd');
16
16
  goog.require('shaka.log');
17
17
  goog.require('shaka.net.NetworkingEngine');
18
+ goog.require('goog.Uri');
19
+ goog.require('shaka.util.EventManager');
20
+ goog.require('shaka.util.Error');
21
+ goog.require('shaka.util.FakeEvent');
18
22
  goog.require('shaka.util.IReleasable');
23
+ goog.require('shaka.util.PublicPromise');
19
24
  goog.require('shaka.util.StringUtils');
20
25
 
21
26
 
@@ -14,7 +14,11 @@ goog.provide('shaka.ads.ServerSideAdManager');
14
14
  goog.require('goog.asserts');
15
15
  goog.require('shaka.ads.ServerSideAd');
16
16
  goog.require('shaka.log');
17
+ goog.require('shaka.util.EventManager');
18
+ goog.require('shaka.util.Error');
19
+ goog.require('shaka.util.FakeEvent');
17
20
  goog.require('shaka.util.IReleasable');
21
+ goog.require('shaka.util.PublicPromise');
18
22
 
19
23
 
20
24
  /**
@@ -3753,14 +3753,26 @@ shaka.hls.HlsParser = class {
3753
3753
 
3754
3754
  // If unable to guess mime type, request a segment and try getting it
3755
3755
  // from the response.
3756
+ let contentMimeType;
3757
+ const type = shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT;
3756
3758
  const headRequest = shaka.net.NetworkingEngine.makeRequest(
3757
3759
  middleSegmentUris, this.config_.retryParameters);
3758
- headRequest.method = 'HEAD';
3759
- const type = shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT;
3760
- const response = await this.makeNetworkRequest_(
3761
- headRequest, requestType, {type});
3760
+ try {
3761
+ headRequest.method = 'HEAD';
3762
+ const response = await this.makeNetworkRequest_(
3763
+ headRequest, requestType, {type});
3764
+
3765
+ contentMimeType = response.headers['content-type'];
3766
+ } catch (error) {
3767
+ if (error && error.code == shaka.util.Error.Code.HTTP_ERROR) {
3768
+ headRequest.method = 'GET';
3769
+ const response = await this.makeNetworkRequest_(
3770
+ headRequest, requestType, {type});
3771
+
3772
+ contentMimeType = response.headers['content-type'];
3773
+ }
3774
+ }
3762
3775
 
3763
- const contentMimeType = response.headers['content-type'];
3764
3776
  if (contentMimeType) {
3765
3777
  // Split the MIME type in case the server sent additional parameters.
3766
3778
  return contentMimeType.split(';')[0];
@@ -2038,9 +2038,6 @@ shaka.media.DrmEngine = class {
2038
2038
 
2039
2039
  for (const drm1 of drms1) {
2040
2040
  for (const drm2 of drms2) {
2041
- // This method is only called to compare drmInfos of a video and an
2042
- // audio adaptations, so we shouldn't have to worry about checking
2043
- // robustness.
2044
2041
  if (drm1.keySystem == drm2.keySystem) {
2045
2042
  const initDataMap = new Map();
2046
2043
  const bothInitDatas = (drm1.initData || [])
@@ -864,7 +864,7 @@ shaka.media.MediaSourceEngine = class {
864
864
  const calculatedTimestampOffset = reference.startTime - timestamp;
865
865
  const timestampOffsetDifference =
866
866
  Math.abs(timestampOffset - calculatedTimestampOffset);
867
- if ((timestampOffsetDifference >= 0.1 || seeked || adaptation) &&
867
+ if ((timestampOffsetDifference >= 0.001 || seeked || adaptation) &&
868
868
  (!isChunkedData || calculatedTimestampOffset > 0 ||
869
869
  !timestampOffset)) {
870
870
  timestampOffset = calculatedTimestampOffset;
@@ -6,7 +6,6 @@
6
6
 
7
7
  /**
8
8
  * @fileoverview
9
- * @suppress {missingRequire} TODO(b/152540451): this shouldn't be needed
10
9
  */
11
10
 
12
11
  goog.provide('shaka.media.StreamingEngine');
@@ -14,12 +13,14 @@ goog.provide('shaka.media.StreamingEngine');
14
13
  goog.require('goog.asserts');
15
14
  goog.require('shaka.log');
16
15
  goog.require('shaka.media.InitSegmentReference');
16
+ goog.require('shaka.media.ManifestParser');
17
17
  goog.require('shaka.media.MediaSourceEngine');
18
18
  goog.require('shaka.media.SegmentIterator');
19
19
  goog.require('shaka.media.SegmentReference');
20
20
  goog.require('shaka.media.SegmentPrefetch');
21
21
  goog.require('shaka.net.Backoff');
22
22
  goog.require('shaka.net.NetworkingEngine');
23
+ goog.require('shaka.util.BufferUtils');
23
24
  goog.require('shaka.util.DelayedTick');
24
25
  goog.require('shaka.util.Destroyer');
25
26
  goog.require('shaka.util.Error');
@@ -28,6 +29,7 @@ goog.require('shaka.util.IDestroyable');
28
29
  goog.require('shaka.util.Id3Utils');
29
30
  goog.require('shaka.util.ManifestParserUtils');
30
31
  goog.require('shaka.util.MimeUtils');
32
+ goog.require('shaka.util.Mp4BoxParsers');
31
33
  goog.require('shaka.util.Mp4Parser');
32
34
  goog.require('shaka.util.Networking');
33
35
 
@@ -2203,7 +2205,6 @@ shaka.media.StreamingEngine = class {
2203
2205
  *
2204
2206
  * @return {!Promise.<BufferSource>}
2205
2207
  * @private
2206
- * @suppress {strictMissingProperties}
2207
2208
  */
2208
2209
  async fetch_(mediaState, reference, streamDataCallback) {
2209
2210
  if (reference instanceof shaka.media.InitSegmentReference) {
@@ -183,8 +183,8 @@ shaka.media.VideoWrapper = class {
183
183
 
184
184
  /**
185
185
  * A class used to move the playhead away from its current time. Sometimes,
186
- * Edge ignores re-seeks. After changing the current time, check every 100ms,
187
- * retrying if the change was not accepted.
186
+ * legacy Edge ignores re-seeks. After changing the current time, check every
187
+ * 100ms, retrying if the change was not accepted.
188
188
  *
189
189
  * Delay stats over 100 runs of a re-seeking integration test:
190
190
  * Edge - 0ms - 2%
@@ -194,7 +194,8 @@ shaka.media.VideoWrapper = class {
194
194
  * Edge - 400ms - 2%
195
195
  * Chrome - 0ms - 100%
196
196
  *
197
- * TODO: File a bug on Edge about this.
197
+ * Unfortunately, legacy Edge is not receiving updates anymore, but it still
198
+ * must be supported as it is used for web browsers on XBox.
198
199
  *
199
200
  * @implements {shaka.util.IReleasable}
200
201
  * @final
@@ -8,6 +8,7 @@ goog.provide('shaka.net.NetworkingUtils');
8
8
 
9
9
  goog.require('goog.Uri');
10
10
  goog.require('shaka.net.NetworkingEngine');
11
+ goog.require('shaka.util.Error');
11
12
 
12
13
 
13
14
  /**
@@ -30,13 +31,21 @@ shaka.net.NetworkingUtils = class {
30
31
  const type = shaka.net.NetworkingEngine.RequestType.MANIFEST;
31
32
 
32
33
  const request = shaka.net.NetworkingEngine.makeRequest([uri], retryParams);
33
- request.method = 'HEAD';
34
34
 
35
- const response = await netEngine.request(type, request).promise;
35
+ try {
36
+ request.method = 'HEAD';
37
+ const response = await netEngine.request(type, request).promise;
38
+ mimeType = response.headers['content-type'];
39
+ } catch (error) {
40
+ if (error && error.code == shaka.util.Error.Code.HTTP_ERROR) {
41
+ request.method = 'GET';
42
+ const response = await netEngine.request(type, request).promise;
43
+ mimeType = response.headers['content-type'];
44
+ }
45
+ }
36
46
 
37
47
  // https://bit.ly/2K9s9kf says this header should always be available,
38
48
  // but just to be safe:
39
- mimeType = response.headers['content-type'];
40
49
  return mimeType ? mimeType.toLowerCase().split(';').shift() : '';
41
50
  }
42
51
 
package/lib/player.js CHANGED
@@ -4525,7 +4525,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4525
4525
 
4526
4526
  if (this.isLive()) {
4527
4527
  const now = this.getPresentationStartTimeAsDate().valueOf() +
4528
- this.seekRange().end * 1000;
4528
+ element.currentTime * 1000;
4529
4529
  const latency = (Date.now() - now) / 1000;
4530
4530
  this.stats_.setLiveLatency(latency);
4531
4531
  }
@@ -5144,7 +5144,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5144
5144
  } else {
5145
5145
  // eslint-disable-next-line no-restricted-syntax
5146
5146
  if (HTMLMediaElement.prototype.addTextTrack) {
5147
- return new shaka.text.SimpleTextDisplayer(this.video_);
5147
+ return new shaka.text.SimpleTextDisplayer(
5148
+ this.video_, shaka.Player.TextTrackLabel);
5148
5149
  } else {
5149
5150
  shaka.log.warning('Text tracks are not supported by the ' +
5150
5151
  'browser, disabling.');
@@ -6386,6 +6387,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6386
6387
  } // if (keyIds.size)
6387
6388
 
6388
6389
  if (tracksChanged) {
6390
+ this.onTracksChanged_();
6389
6391
  const variantsUpdated = this.updateAbrManagerVariants_();
6390
6392
  if (!variantsUpdated) {
6391
6393
  return;
@@ -6397,10 +6399,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6397
6399
  shaka.log.debug('Choosing new streams after key status changed');
6398
6400
  this.chooseVariantAndSwitch_();
6399
6401
  }
6400
-
6401
- if (tracksChanged) {
6402
- this.onTracksChanged_();
6403
- }
6404
6402
  }
6405
6403
 
6406
6404
  /**
@@ -6781,7 +6779,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
6781
6779
  * @export
6782
6780
  */
6783
6781
  // eslint-disable-next-line no-useless-concat
6784
- shaka.Player.version = 'v4.6.3' + '-uncompiled'; // x-release-please-version
6782
+ shaka.Player.version = 'v4.6.5' + '-uncompiled'; // x-release-please-version
6785
6783
 
6786
6784
  // Initialize the deprecation system using the version string we just set
6787
6785
  // on the player.
@@ -6,7 +6,6 @@
6
6
 
7
7
  /**
8
8
  * @fileoverview
9
- * @suppress {missingRequire} TODO(b/152540451): this shouldn't be needed
10
9
  */
11
10
 
12
11
  goog.provide('shaka.text.SimpleTextDisplayer');
@@ -24,8 +23,11 @@ goog.require('shaka.text.Utils');
24
23
  * @export
25
24
  */
26
25
  shaka.text.SimpleTextDisplayer = class {
27
- /** @param {HTMLMediaElement} video */
28
- constructor(video) {
26
+ /**
27
+ * @param {HTMLMediaElement} video
28
+ * @param {string} label
29
+ */
30
+ constructor(video, label) {
29
31
  /** @private {TextTrack} */
30
32
  this.textTrack_ = null;
31
33
 
@@ -39,7 +41,7 @@ shaka.text.SimpleTextDisplayer = class {
39
41
  // element.
40
42
  track.mode = 'disabled';
41
43
 
42
- if (track.label == shaka.Player.TextTrackLabel) {
44
+ if (track.label == label) {
43
45
  this.textTrack_ = track;
44
46
  }
45
47
  }
@@ -49,8 +51,7 @@ shaka.text.SimpleTextDisplayer = class {
49
51
  // kind to 'subtitles' or 'captions' when creating the TextTrack object.
50
52
  // The individual text tracks from the manifest will still have their own
51
53
  // kinds which can be displayed in the app's UI.
52
- this.textTrack_ = video.addTextTrack(
53
- 'subtitles', shaka.Player.TextTrackLabel);
54
+ this.textTrack_ = video.addTextTrack('subtitles', label);
54
55
  }
55
56
  this.textTrack_.mode = 'hidden';
56
57
  }
@@ -80,7 +81,7 @@ shaka.text.SimpleTextDisplayer = class {
80
81
  * @export
81
82
  */
82
83
  append(cues) {
83
- const flattenedCues = shaka.text.Utils.getCuesToFlatten(cues, []);
84
+ const flattenedCues = shaka.text.Utils.getCuesToFlatten(cues);
84
85
 
85
86
  // Convert cues.
86
87
  const textTrackCues = [];
@@ -15,16 +15,19 @@ shaka.text.Utils = class {
15
15
  * their contents should be combined and replace the payload of the parent.
16
16
  *
17
17
  * @param {!shaka.text.Cue} cue
18
+ * @param {?shaka.text.Cue=} parentCue
18
19
  * @return {string}
19
20
  * @private
20
21
  */
21
- static flattenPayload_(cue) {
22
+ static flattenPayload_(cue, parentCue) {
22
23
  if (cue.lineBreak) {
23
24
  // This is a vertical lineBreak, so insert a newline.
24
25
  return '\n';
25
26
  }
26
27
  if (cue.nestedCues.length) {
27
- return cue.nestedCues.map(shaka.text.Utils.flattenPayload_).join('');
28
+ return cue.nestedCues.map((nested) => {
29
+ return shaka.text.Utils.flattenPayload_(nested, cue);
30
+ }).join('');
28
31
  }
29
32
 
30
33
  // Handle bold, italics and underline
@@ -43,14 +46,22 @@ shaka.text.Utils = class {
43
46
  openStyleTags.push(['u']);
44
47
  }
45
48
  // Handle color classes, if the value consists of letters
49
+ let color = cue.color;
50
+ if (color == '' && parentCue) {
51
+ color = parentCue.color;
52
+ }
46
53
  let classes = '';
47
- const color = shaka.text.Utils.getColorName_(cue.color);
48
- if (color) {
49
- classes += `.${color}`;
54
+ const colorName = shaka.text.Utils.getColorName_(color);
55
+ if (colorName) {
56
+ classes += `.${colorName}`;
57
+ }
58
+ let bgColor = cue.backgroundColor;
59
+ if (bgColor == '' && parentCue) {
60
+ bgColor = parentCue.backgroundColor;
50
61
  }
51
- const bgColor = shaka.text.Utils.getColorName_(cue.backgroundColor);
52
- if (bgColor) {
53
- classes += `.bg_${bgColor}`;
62
+ const bgColorName = shaka.text.Utils.getColorName_(bgColor);
63
+ if (bgColorName) {
64
+ classes += `.bg_${bgColorName}`;
54
65
  }
55
66
  if (classes) {
56
67
  openStyleTags.push(['c', classes]);
@@ -69,7 +80,20 @@ shaka.text.Utils = class {
69
80
  * @private
70
81
  */
71
82
  static getColorName_(string) {
72
- switch (string.toLowerCase()) {
83
+ let colorString = string.toLowerCase();
84
+ const rgb = colorString.replace(/\s/g, '')
85
+ .match(/^rgba?\((\d+),(\d+),(\d+),?([^,\s)]+)?/i);
86
+ if (rgb) {
87
+ colorString = '#' +
88
+ (parseInt(rgb[1], 10) | (1 << 8)).toString(16).slice(1) +
89
+ (parseInt(rgb[2], 10) | (1 << 8)).toString(16).slice(1) +
90
+ (parseInt(rgb[3], 10) | (1 << 8)).toString(16).slice(1);
91
+ } else if (colorString.startsWith('#') && colorString.length > 7) {
92
+ // With this we lose the alpha of the color, but it is better than having
93
+ // no color.
94
+ colorString = colorString.slice(0, 7);
95
+ }
96
+ switch (colorString) {
73
97
  case 'white':
74
98
  case '#fff':
75
99
  case '#ffffff':
@@ -92,6 +116,7 @@ shaka.text.Utils = class {
92
116
  return 'yellow';
93
117
  case 'magenta':
94
118
  case '#f0f':
119
+ case '#ff00ff':
95
120
  return 'magenta';
96
121
  case 'blue':
97
122
  case '#00f':
@@ -118,19 +143,20 @@ shaka.text.Utils = class {
118
143
  * isContainer = false.
119
144
  *
120
145
  * @param {!Array.<!shaka.text.Cue>} cues
121
- * @param {!Array.<!shaka.text.Cue>} result
146
+ * @param {?shaka.text.Cue=} parentCue
122
147
  * @return {!Array.<!shaka.text.Cue>}
123
148
  */
124
- static getCuesToFlatten(cues, result) {
149
+ static getCuesToFlatten(cues, parentCue) {
150
+ const result = [];
125
151
  for (const cue of cues) {
126
152
  if (cue.isContainer) {
127
153
  // Recurse to find the actual text payload cues.
128
- shaka.text.Utils.getCuesToFlatten(cue.nestedCues, result);
154
+ result.push(...shaka.text.Utils.getCuesToFlatten(cue.nestedCues, cue));
129
155
  } else {
130
156
  // Flatten the payload.
131
157
  const flatCue = cue.clone();
132
158
  flatCue.nestedCues = [];
133
- flatCue.payload = shaka.text.Utils.flattenPayload_(cue);
159
+ flatCue.payload = shaka.text.Utils.flattenPayload_(cue, parentCue);
134
160
  result.push(flatCue);
135
161
  }
136
162
  }
@@ -707,37 +707,46 @@ shaka.text.UITextDisplayer = class {
707
707
  // (for vertical growing left) is aligned at the line.
708
708
  // TODO: Implement line alignment with line number.
709
709
  // TODO: Implement lineAlignment of 'CENTER'.
710
- if (cue.line != null) {
710
+ let line = cue.line;
711
+ if (line != null) {
711
712
  let lineInterpretation = cue.lineInterpretation;
712
713
  // HACK: the current implementation of UITextDisplayer only handled
713
- // PERCENTAGE, as cue.line=0 is zero, we can interpret it as percentage
714
- // safely.
715
- if (cue.line == 0 &&
716
- lineInterpretation == Cue.lineInterpretation.LINE_NUMBER) {
714
+ // PERCENTAGE, so we need convert LINE_NUMBER to PERCENTAGE
715
+ if (lineInterpretation == Cue.lineInterpretation.LINE_NUMBER) {
717
716
  lineInterpretation = Cue.lineInterpretation.PERCENTAGE;
717
+ let maxLines = 16;
718
+ // The maximum number of lines is different if it is a vertical video.
719
+ if (this.aspectRatio_ && this.aspectRatio_ < 1) {
720
+ maxLines = 32;
721
+ }
722
+ if (line < 0) {
723
+ line = 100 + line / maxLines * 100;
724
+ } else {
725
+ line = line / maxLines * 100;
726
+ }
718
727
  }
719
728
  if (lineInterpretation == Cue.lineInterpretation.PERCENTAGE) {
720
729
  style.position = 'absolute';
721
730
  if (cue.writingMode == Cue.writingMode.HORIZONTAL_TOP_TO_BOTTOM) {
722
731
  style.width = '100%';
723
732
  if (cue.lineAlign == Cue.lineAlign.START) {
724
- style.top = cue.line + '%';
733
+ style.top = line + '%';
725
734
  } else if (cue.lineAlign == Cue.lineAlign.END) {
726
- style.bottom = (100 - cue.line) + '%';
735
+ style.bottom = (100 - line) + '%';
727
736
  }
728
737
  } else if (cue.writingMode == Cue.writingMode.VERTICAL_LEFT_TO_RIGHT) {
729
738
  style.height = '100%';
730
739
  if (cue.lineAlign == Cue.lineAlign.START) {
731
- style.left = cue.line + '%';
740
+ style.left = line + '%';
732
741
  } else if (cue.lineAlign == Cue.lineAlign.END) {
733
- style.right = (100 - cue.line) + '%';
742
+ style.right = (100 - line) + '%';
734
743
  }
735
744
  } else {
736
745
  style.height = '100%';
737
746
  if (cue.lineAlign == Cue.lineAlign.START) {
738
- style.right = cue.line + '%';
747
+ style.right = line + '%';
739
748
  } else if (cue.lineAlign == Cue.lineAlign.END) {
740
- style.left = (100 - cue.line) + '%';
749
+ style.left = (100 - line) + '%';
741
750
  }
742
751
  }
743
752
  }
@@ -40,7 +40,7 @@ shaka.text.WebVttGenerator = class {
40
40
  milliseconds;
41
41
  };
42
42
 
43
- const flattenedCues = shaka.text.Utils.getCuesToFlatten(cues, []);
43
+ const flattenedCues = shaka.text.Utils.getCuesToFlatten(cues);
44
44
 
45
45
  let webvttString = 'WEBVTT\n\n';
46
46
  for (const cue of flattenedCues) {
@@ -614,9 +614,11 @@ shaka.util.TsParser = class {
614
614
  let sort = false;
615
615
  for (const audioData of this.audioData_) {
616
616
  const pes = this.parsePES_(audioData);
617
- if (pes && pes.pts != null && pes.dts != null) {
618
- if (this.audioPes_.length &&
619
- pes.dts < (this.audioPes_[this.audioPes_.length - 1].dts || 0)) {
617
+ let previousPes = this.audioPes_.length ?
618
+ this.audioPes_[this.audioPes_.length - 1] : null;
619
+ if (pes && pes.pts != null && pes.dts != null && (!previousPes ||
620
+ (previousPes.pts != pes.pts && previousPes.dts != pes.dts))) {
621
+ if (this.audioPes_.length && pes.dts < (previousPes.dts || 0)) {
620
622
  sort = true;
621
623
  }
622
624
  this.audioPes_.push(pes);
@@ -625,7 +627,7 @@ shaka.util.TsParser = class {
625
627
  if (!data) {
626
628
  continue;
627
629
  }
628
- const previousPes = this.audioPes_.pop();
630
+ previousPes = this.audioPes_.pop();
629
631
  previousPes.data =
630
632
  shaka.util.Uint8ArrayUtils.concat(previousPes.data, data);
631
633
  this.audioPes_.push(previousPes);
@@ -654,9 +656,11 @@ shaka.util.TsParser = class {
654
656
  let sort = false;
655
657
  for (const videoData of this.videoData_) {
656
658
  const pes = this.parsePES_(videoData);
657
- if (pes && pes.pts != null && pes.dts != null) {
658
- if (this.videoPes_.length &&
659
- pes.dts < (this.videoPes_[this.videoPes_.length - 1].dts || 0)) {
659
+ let previousPes = this.videoPes_.length ?
660
+ this.videoPes_[this.videoPes_.length - 1] : null;
661
+ if (pes && pes.pts != null && pes.dts != null && (!previousPes ||
662
+ (previousPes.pts != pes.pts && previousPes.dts != pes.dts))) {
663
+ if (this.videoPes_.length && pes.dts < (previousPes.dts || 0)) {
660
664
  sort = true;
661
665
  }
662
666
  this.videoPes_.push(pes);
@@ -665,7 +669,7 @@ shaka.util.TsParser = class {
665
669
  if (!data) {
666
670
  continue;
667
671
  }
668
- const previousPes = this.videoPes_.pop();
672
+ previousPes = this.videoPes_.pop();
669
673
  previousPes.data =
670
674
  shaka.util.Uint8ArrayUtils.concat(previousPes.data, data);
671
675
  this.videoPes_.push(previousPes);
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": "4.6.3",
4
+ "version": "4.6.5",
5
5
  "homepage": "https://github.com/shaka-project/shaka-player",
6
6
  "author": "Google",
7
7
  "maintainers": [
@@ -2390,6 +2390,33 @@ describe('DrmEngine', () => {
2390
2390
  [drmInfoAudio]);
2391
2391
  expect(returned).toEqual([drmInfoDesired]);
2392
2392
  });
2393
+
2394
+ it('does not match incompatible drmInfos', () => {
2395
+ // Different key systems do not match.
2396
+ const drmInfo1 = {
2397
+ keySystem: 'drm.abc',
2398
+ licenseServerUri: undefined,
2399
+ distinctiveIdentifierRequired: false,
2400
+ persistentStateRequired: false,
2401
+ serverCertificate: undefined,
2402
+ serverCertificateUri: '',
2403
+ initData: [],
2404
+ keyIds: new Set(),
2405
+ };
2406
+ const drmInfo2 = {
2407
+ keySystem: 'drm.foobar',
2408
+ licenseServerUri: undefined,
2409
+ distinctiveIdentifierRequired: false,
2410
+ persistentStateRequired: false,
2411
+ serverCertificate: undefined,
2412
+ serverCertificateUri: '',
2413
+ initData: [],
2414
+ keyIds: new Set(),
2415
+ };
2416
+ const returned1 = shaka.media.DrmEngine.getCommonDrmInfos(
2417
+ [drmInfo1], [drmInfo2]);
2418
+ expect(returned1).toEqual([]);
2419
+ });
2393
2420
  }); // describe('getCommonDrmInfos')
2394
2421
 
2395
2422
  describe('configure', () => {
@@ -3484,6 +3484,37 @@ describe('Player', () => {
3484
3484
  expect(tracks[0].id).toBe(2);
3485
3485
  });
3486
3486
 
3487
+ it('removes based on frameRate', async () => {
3488
+ manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3489
+ manifest.addVariant(0, (variant) => {
3490
+ variant.addVideo(1, (stream) => {
3491
+ stream.frameRate = 15;
3492
+ });
3493
+ });
3494
+
3495
+ manifest.addVariant(1, (variant) => {
3496
+ variant.addVideo(2, (stream) => {
3497
+ stream.frameRate = 30;
3498
+ });
3499
+ });
3500
+
3501
+ manifest.addVariant(2, (variant) => {
3502
+ variant.addVideo(3, (stream) => {
3503
+ stream.frameRate = 60;
3504
+ });
3505
+ });
3506
+ });
3507
+
3508
+ await player.load(fakeManifestUri, 0, fakeMimeType);
3509
+ expect(player.getVariantTracks().length).toBe(3);
3510
+
3511
+ player.configure({restrictions: {minFrameRate: 20, maxFrameRate: 40}});
3512
+
3513
+ const tracks = player.getVariantTracks();
3514
+ expect(tracks.length).toBe(1);
3515
+ expect(tracks[0].id).toBe(1);
3516
+ });
3517
+
3487
3518
  it('removes the whole variant if one stream is restricted', async () => {
3488
3519
  manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3489
3520
  manifest.addVariant(0, (variant) => {
@@ -377,7 +377,8 @@ shaka.test.NativeTextLayoutTests = class extends shaka.test.TextLayoutTests {
377
377
 
378
378
  /** @override */
379
379
  recreateTextDisplayer() {
380
- this.textDisplayer = new shaka.text.SimpleTextDisplayer(this.video);
380
+ this.textDisplayer = new shaka.text.SimpleTextDisplayer(
381
+ this.video, shaka.Player.TextTrackLabel);
381
382
  this.textDisplayer.setTextVisibility(true);
382
383
  }
383
384
 
@@ -18,7 +18,7 @@ describe('SimpleTextDisplayer', () => {
18
18
 
19
19
  beforeEach(() => {
20
20
  video = new shaka.test.FakeVideo();
21
- displayer = new SimpleTextDisplayer(video);
21
+ displayer = new SimpleTextDisplayer(video, shaka.Player.TextTrackLabel);
22
22
 
23
23
  expect(video.textTracks.length).toBe(1);
24
24
  mockTrack = /** @type {!shaka.test.FakeTextTrack} */ (video.textTracks[0]);
@@ -18,11 +18,11 @@ describe('WebVttGenerator', () => {
18
18
  const shakaCue2 = new shaka.text.Cue(40, 50, 'Test2');
19
19
  shakaCue2.textAlign = shaka.text.Cue.textAlign.RIGHT;
20
20
  shakaCue2.writingMode = shaka.text.Cue.writingMode.VERTICAL_RIGHT_TO_LEFT;
21
- shakaCue2.color = '#0f0';
22
- shakaCue2.backgroundColor = 'lime';
21
+ shakaCue2.color = '#00ff00ff';
22
+ shakaCue2.backgroundColor = 'rgba(0,255,0,1)';
23
23
  const shakaCue3 = new shaka.text.Cue(50, 51, 'Test3');
24
24
  shakaCue3.textAlign = shaka.text.Cue.textAlign.CENTER;
25
- shakaCue3.color = '#ffff00';
25
+ shakaCue3.color = 'rgb(255,255,0)';
26
26
  shakaCue3.backgroundColor = '#00ffff';
27
27
  const shakaCue4 = new shaka.text.Cue(52, 53, 'Test4');
28
28
  shakaCue4.textAlign = shaka.text.Cue.textAlign.START;