shaka-player 4.8.1 → 4.8.3
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.
- package/dist/deps.js +2 -2
- package/dist/locales.js +33 -33
- package/dist/shaka-player.compiled.debug.js +123 -118
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.js +944 -944
- package/dist/shaka-player.compiled.map +2 -2
- package/dist/shaka-player.ui.debug.js +44 -39
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.js +1143 -1143
- package/dist/shaka-player.ui.map +2 -2
- package/externs/shaka/player.js +5 -2
- package/lib/dash/mpd_utils.js +0 -6
- package/lib/dash/segment_template.js +5 -0
- package/lib/media/play_rate_controller.js +36 -8
- package/lib/media/playhead.js +3 -3
- package/lib/media/segment_prefetch.js +20 -4
- package/lib/media/stall_detector.js +3 -0
- package/lib/media/streaming_engine.js +5 -0
- package/lib/player.js +20 -1
- package/lib/text/ui_text_displayer.js +12 -1
- package/lib/util/platform.js +23 -2
- package/lib/util/tXml.js +1 -1
- package/package.json +1 -1
- package/ui/resolution_selection.js +1 -0
package/externs/shaka/player.js
CHANGED
|
@@ -1519,11 +1519,14 @@ shaka.extern.AdsConfiguration;
|
|
|
1519
1519
|
* @property {boolean} enabled
|
|
1520
1520
|
* If true, enable adaptation by the current AbrManager. Defaults to true.
|
|
1521
1521
|
* @property {boolean} useNetworkInformation
|
|
1522
|
-
* If true, use Network Information API in the current AbrManager
|
|
1522
|
+
* If true, use the Network Information API in the current AbrManager, if it
|
|
1523
|
+
* is available in the browser environment. If the Network Information API is
|
|
1524
|
+
* used, Shaka Player will ignore the defaultBandwidthEstimate config.
|
|
1523
1525
|
* Defaults to true.
|
|
1524
1526
|
* @property {number} defaultBandwidthEstimate
|
|
1525
1527
|
* The default bandwidth estimate to use if there is not enough data, in
|
|
1526
|
-
* bit/sec.
|
|
1528
|
+
* bit/sec. Only used if useNetworkInformation is false, or if the Network
|
|
1529
|
+
* Information API is not available.
|
|
1527
1530
|
* @property {shaka.extern.Restrictions} restrictions
|
|
1528
1531
|
* The restrictions to apply to ABR decisions. These are "soft" restrictions.
|
|
1529
1532
|
* Any track that fails to meet these restrictions will not be selected
|
package/lib/dash/mpd_utils.js
CHANGED
|
@@ -282,12 +282,6 @@ shaka.dash.MpdUtils = class {
|
|
|
282
282
|
const durationStr =
|
|
283
283
|
MpdUtils.inheritAttribute(context, callback, 'duration');
|
|
284
284
|
let segmentDuration = TXml.parsePositiveInt(durationStr || '');
|
|
285
|
-
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
286
|
-
// TODO: The specification is not clear, check this once it is resolved:
|
|
287
|
-
// https://github.com/Dash-Industry-Forum/DASH-IF-IOP/issues/404
|
|
288
|
-
if (context.representation.contentType == ContentType.IMAGE) {
|
|
289
|
-
segmentDuration = TXml.parseFloat(durationStr || '');
|
|
290
|
-
}
|
|
291
285
|
if (segmentDuration) {
|
|
292
286
|
segmentDuration /= timescale;
|
|
293
287
|
}
|
|
@@ -398,6 +398,11 @@ shaka.dash.SegmentTemplate = class {
|
|
|
398
398
|
Math.ceil(availablePeriodTimes[1] / segmentDuration) - 1,
|
|
399
399
|
];
|
|
400
400
|
|
|
401
|
+
// For Low Latency we can request the partial current position.
|
|
402
|
+
if (context.representation.availabilityTimeOffset) {
|
|
403
|
+
availablePeriodPositions[1]++;
|
|
404
|
+
}
|
|
405
|
+
|
|
401
406
|
// In absolute positions.
|
|
402
407
|
const availablePresentationPositions =
|
|
403
408
|
availablePeriodPositions.map((x) => x + startNumber);
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
goog.provide('shaka.media.PlayRateController');
|
|
8
8
|
|
|
9
|
+
goog.require('goog.asserts');
|
|
9
10
|
goog.require('shaka.log');
|
|
10
11
|
goog.require('shaka.util.IReleasable');
|
|
11
12
|
goog.require('shaka.util.Timer');
|
|
@@ -27,6 +28,9 @@ shaka.media.PlayRateController = class {
|
|
|
27
28
|
/** @private {?shaka.media.PlayRateController.Harness} */
|
|
28
29
|
this.harness_ = harness;
|
|
29
30
|
|
|
31
|
+
/** @private {boolean} */
|
|
32
|
+
this.isBuffering_ = false;
|
|
33
|
+
|
|
30
34
|
/** @private {number} */
|
|
31
35
|
this.rate_ = this.harness_.getRate();
|
|
32
36
|
|
|
@@ -51,15 +55,25 @@ shaka.media.PlayRateController = class {
|
|
|
51
55
|
}
|
|
52
56
|
|
|
53
57
|
/**
|
|
54
|
-
*
|
|
58
|
+
* Sets the buffering flag, which controls the effective playback rate.
|
|
59
|
+
*
|
|
60
|
+
* @param {boolean} isBuffering If true, forces playback rate to 0 internally.
|
|
61
|
+
*/
|
|
62
|
+
setBuffering(isBuffering) {
|
|
63
|
+
this.isBuffering_ = isBuffering;
|
|
64
|
+
this.apply_();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Set the playback rate. This rate will only be used as provided when the
|
|
69
|
+
* player is not buffering. You should never set the rate to 0.
|
|
55
70
|
*
|
|
56
71
|
* @param {number} rate
|
|
57
72
|
*/
|
|
58
73
|
set(rate) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
74
|
+
goog.asserts.assert(rate != 0, 'Should never set rate of 0 explicitly!');
|
|
75
|
+
this.rate_ = rate;
|
|
76
|
+
this.apply_();
|
|
63
77
|
}
|
|
64
78
|
|
|
65
79
|
/**
|
|
@@ -93,11 +107,14 @@ shaka.media.PlayRateController = class {
|
|
|
93
107
|
// Always stop the timer. We may not start it again.
|
|
94
108
|
this.timer_.stop();
|
|
95
109
|
|
|
96
|
-
|
|
110
|
+
/** @type {number} */
|
|
111
|
+
const rate = this.calculateCurrentRate_();
|
|
112
|
+
|
|
113
|
+
shaka.log.v1('Changing effective playback rate to', rate);
|
|
97
114
|
|
|
98
|
-
if (
|
|
115
|
+
if (rate >= 0) {
|
|
99
116
|
try {
|
|
100
|
-
this.applyRate_(
|
|
117
|
+
this.applyRate_(rate);
|
|
101
118
|
return;
|
|
102
119
|
} catch (e) {
|
|
103
120
|
// Fall through to the next clause.
|
|
@@ -117,6 +134,17 @@ shaka.media.PlayRateController = class {
|
|
|
117
134
|
this.applyRate_(0);
|
|
118
135
|
}
|
|
119
136
|
|
|
137
|
+
/**
|
|
138
|
+
* Calculate the rate that the controller wants the media element to have
|
|
139
|
+
* based on the current state of the controller.
|
|
140
|
+
*
|
|
141
|
+
* @return {number}
|
|
142
|
+
* @private
|
|
143
|
+
*/
|
|
144
|
+
calculateCurrentRate_() {
|
|
145
|
+
return this.isBuffering_ ? 0 : this.rate_;
|
|
146
|
+
}
|
|
147
|
+
|
|
120
148
|
/**
|
|
121
149
|
* If the new rate is different than the media element's playback rate, this
|
|
122
150
|
* will change the playback rate. If the rate does not need to change, it will
|
package/lib/media/playhead.js
CHANGED
|
@@ -382,10 +382,10 @@ shaka.media.MediaSourcePlayhead = class {
|
|
|
382
382
|
seekStart = seekEnd - this.minSeekRange_;
|
|
383
383
|
}
|
|
384
384
|
|
|
385
|
-
if (currentTime < seekStart
|
|
386
|
-
//
|
|
385
|
+
if (currentTime < seekStart) {
|
|
386
|
+
// The seek range has moved past the playhead. Move ahead to catch up.
|
|
387
387
|
const targetTime = this.reposition_(currentTime);
|
|
388
|
-
shaka.log.info('Jumping
|
|
388
|
+
shaka.log.info('Jumping forward ' + (targetTime - currentTime) +
|
|
389
389
|
' seconds to catch up with the seek range.');
|
|
390
390
|
this.mediaElement_.currentTime = targetTime;
|
|
391
391
|
}
|
|
@@ -147,7 +147,12 @@ shaka.media.SegmentPrefetch = class {
|
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
// init segments are ignored from the prefetch limit
|
|
150
|
-
|
|
150
|
+
const initSegments = Array.from(this.initSegmentPrefetchMap_.keys());
|
|
151
|
+
const someReference = initSegments.some((reference) => {
|
|
152
|
+
return shaka.media.InitSegmentReference.equal(
|
|
153
|
+
reference, initSegmentReference);
|
|
154
|
+
});
|
|
155
|
+
if (!someReference) {
|
|
151
156
|
const segmentPrefetchOperation =
|
|
152
157
|
new shaka.media.SegmentPrefetchOperation(this.fetchDispatcher_);
|
|
153
158
|
segmentPrefetchOperation.dispatchFetch(
|
|
@@ -233,6 +238,15 @@ shaka.media.SegmentPrefetch = class {
|
|
|
233
238
|
this.prefetchPosTime_ = 0;
|
|
234
239
|
}
|
|
235
240
|
|
|
241
|
+
/**
|
|
242
|
+
* Remove a reference of prefetched segment if already exists.
|
|
243
|
+
* @param {!shaka.media.SegmentReference} reference
|
|
244
|
+
* @public
|
|
245
|
+
*/
|
|
246
|
+
removeReference(reference) {
|
|
247
|
+
this.abortPrefetchedSegment_(reference);
|
|
248
|
+
}
|
|
249
|
+
|
|
236
250
|
/**
|
|
237
251
|
* @param {number} time
|
|
238
252
|
* @param {boolean=} clearInitSegments
|
|
@@ -261,9 +275,11 @@ shaka.media.SegmentPrefetch = class {
|
|
|
261
275
|
const segmentReferences = Array.from(this.segmentPrefetchMap_.keys());
|
|
262
276
|
for (const initSegmentReference of this.initSegmentPrefetchMap_.keys()) {
|
|
263
277
|
// if no segment references this init segment, we should remove it.
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
segmentReference.initSegmentReference
|
|
278
|
+
const someReference = segmentReferences.some((segmentReference) => {
|
|
279
|
+
return shaka.media.InitSegmentReference.equal(
|
|
280
|
+
segmentReference.initSegmentReference, initSegmentReference);
|
|
281
|
+
});
|
|
282
|
+
if (!someReference) {
|
|
267
283
|
this.abortPrefetchedSegment_(initSegmentReference);
|
|
268
284
|
}
|
|
269
285
|
}
|
|
@@ -174,6 +174,9 @@ shaka.media.StallDetector.MediaElementImplementation = class {
|
|
|
174
174
|
if (this.mediaElement_.paused) {
|
|
175
175
|
return false;
|
|
176
176
|
}
|
|
177
|
+
if (this.mediaElement_.playbackRate == 0) {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
177
180
|
|
|
178
181
|
// If we have don't have enough content, we are not stalled, we are
|
|
179
182
|
// buffering.
|
|
@@ -1702,6 +1702,11 @@ shaka.media.StreamingEngine = class {
|
|
|
1702
1702
|
error.code);
|
|
1703
1703
|
mediaState.hasError = true;
|
|
1704
1704
|
|
|
1705
|
+
if (error.category == shaka.util.Error.Category.NETWORK &&
|
|
1706
|
+
mediaState.segmentPrefetch) {
|
|
1707
|
+
mediaState.segmentPrefetch.removeReference(reference);
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1705
1710
|
error.severity = shaka.util.Error.Severity.CRITICAL;
|
|
1706
1711
|
await this.handleStreamingError_(mediaState, error);
|
|
1707
1712
|
}
|
package/lib/player.js
CHANGED
|
@@ -622,6 +622,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
622
622
|
*/
|
|
623
623
|
this.playRateController_ = null;
|
|
624
624
|
|
|
625
|
+
// We use the buffering observer and timer to track when we move from having
|
|
626
|
+
// enough buffered content to not enough. They only exist when content has
|
|
627
|
+
// been loaded and are not re-used between loads.
|
|
628
|
+
/** @private {shaka.util.Timer} */
|
|
629
|
+
this.bufferPoller_ = null;
|
|
630
|
+
|
|
625
631
|
/** @private {shaka.media.BufferingObserver} */
|
|
626
632
|
this.bufferObserver_ = null;
|
|
627
633
|
|
|
@@ -1228,6 +1234,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1228
1234
|
this.playheadObservers_ = null;
|
|
1229
1235
|
}
|
|
1230
1236
|
|
|
1237
|
+
if (this.bufferPoller_) {
|
|
1238
|
+
this.bufferPoller_.stop();
|
|
1239
|
+
this.bufferPoller_ = null;
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1231
1242
|
// Stop the parser early. Since it is at the start of the pipeline, it
|
|
1232
1243
|
// should be start early to avoid is pushing new data downstream.
|
|
1233
1244
|
if (this.parser_) {
|
|
@@ -3101,6 +3112,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3101
3112
|
!this.bufferObserver_,
|
|
3102
3113
|
'No buffering observer should exist before initialization.');
|
|
3103
3114
|
|
|
3115
|
+
goog.asserts.assert(
|
|
3116
|
+
!this.bufferPoller_,
|
|
3117
|
+
'No buffer timer should exist before initialization.');
|
|
3118
|
+
|
|
3104
3119
|
// Give dummy values, will be updated below.
|
|
3105
3120
|
this.bufferObserver_ = new shaka.media.BufferingObserver(1, 2);
|
|
3106
3121
|
|
|
@@ -3110,6 +3125,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3110
3125
|
this.updateBufferingSettings_(rebufferingGoal);
|
|
3111
3126
|
this.updateBufferState_();
|
|
3112
3127
|
|
|
3128
|
+
this.bufferPoller_ = new shaka.util.Timer(() => {
|
|
3129
|
+
this.pollBufferState_();
|
|
3130
|
+
}).tickEvery(/* seconds= */ 0.25);
|
|
3113
3131
|
this.loadEventManager_.listen(mediaElement, 'waiting',
|
|
3114
3132
|
(e) => this.pollBufferState_());
|
|
3115
3133
|
this.loadEventManager_.listen(mediaElement, 'stalled',
|
|
@@ -5833,6 +5851,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5833
5851
|
const loaded = this.stats_ && this.bufferObserver_ && this.playhead_;
|
|
5834
5852
|
|
|
5835
5853
|
if (loaded) {
|
|
5854
|
+
this.playRateController_.setBuffering(isBuffering);
|
|
5836
5855
|
if (this.cmcdManager_) {
|
|
5837
5856
|
this.cmcdManager_.setBuffering(isBuffering);
|
|
5838
5857
|
}
|
|
@@ -7182,7 +7201,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
7182
7201
|
* @export
|
|
7183
7202
|
*/
|
|
7184
7203
|
// eslint-disable-next-line no-useless-concat
|
|
7185
|
-
shaka.Player.version = 'v4.8.
|
|
7204
|
+
shaka.Player.version = 'v4.8.3' + '-uncompiled'; // x-release-please-version
|
|
7186
7205
|
|
|
7187
7206
|
// Initialize the deprecation system using the version string we just set
|
|
7188
7207
|
// on the player.
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
goog.provide('shaka.text.UITextDisplayer');
|
|
9
9
|
|
|
10
10
|
goog.require('goog.asserts');
|
|
11
|
+
goog.require('shaka.Deprecate');
|
|
11
12
|
goog.require('shaka.text.Cue');
|
|
12
13
|
goog.require('shaka.text.CueRegion');
|
|
13
14
|
goog.require('shaka.util.Dom');
|
|
@@ -65,12 +66,22 @@ shaka.text.UITextDisplayer = class {
|
|
|
65
66
|
|
|
66
67
|
this.videoContainer_.appendChild(this.textContainer_);
|
|
67
68
|
|
|
69
|
+
if (!config || !config.captionsUpdatePeriod) {
|
|
70
|
+
shaka.Deprecate.deprecateFeature(5,
|
|
71
|
+
'UITextDisplayer w/ config',
|
|
72
|
+
'Please migrate to initializing UITextDisplayer with a config.');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** @private {number} */
|
|
76
|
+
const updatePeriod = (config && config.captionsUpdatePeriod) ?
|
|
77
|
+
config.captionsUpdatePeriod : 0.25;
|
|
78
|
+
|
|
68
79
|
/** @private {shaka.util.Timer} */
|
|
69
80
|
this.captionsTimer_ = new shaka.util.Timer(() => {
|
|
70
81
|
if (!this.video_.paused) {
|
|
71
82
|
this.updateCaptions_();
|
|
72
83
|
}
|
|
73
|
-
}).tickEvery(
|
|
84
|
+
}).tickEvery(updatePeriod);
|
|
74
85
|
|
|
75
86
|
/**
|
|
76
87
|
* Maps cues to cue elements. Specifically points out the wrapper element of
|
package/lib/util/platform.js
CHANGED
|
@@ -186,6 +186,17 @@ shaka.util.Platform = class {
|
|
|
186
186
|
return shaka.util.Platform.userAgentContains_('CrKey');
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
+
/**
|
|
190
|
+
* Check if the current platform is a Google Chromecast with Android
|
|
191
|
+
* (i.e. Chromecast with GoogleTV).
|
|
192
|
+
*
|
|
193
|
+
* @return {boolean}
|
|
194
|
+
*/
|
|
195
|
+
static isAndroidCastDevice() {
|
|
196
|
+
const Platform = shaka.util.Platform;
|
|
197
|
+
return Platform.isChromecast() && Platform.isAndroid();
|
|
198
|
+
}
|
|
199
|
+
|
|
189
200
|
/**
|
|
190
201
|
* Returns a major version number for Chrome, or Chromium-based browsers.
|
|
191
202
|
*
|
|
@@ -416,6 +427,9 @@ shaka.util.Platform = class {
|
|
|
416
427
|
return navigator.userAgentData.platform.toLowerCase() == 'macos';
|
|
417
428
|
}
|
|
418
429
|
// Fall back to the old API, with less strict matching.
|
|
430
|
+
if (!navigator.platform) {
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
419
433
|
return navigator.platform.toLowerCase().includes('mac');
|
|
420
434
|
}
|
|
421
435
|
|
|
@@ -430,6 +444,9 @@ shaka.util.Platform = class {
|
|
|
430
444
|
return navigator.userAgentData.platform.toLowerCase() == 'windows';
|
|
431
445
|
}
|
|
432
446
|
// Fall back to the old API, with less strict matching.
|
|
447
|
+
if (!navigator.platform) {
|
|
448
|
+
return false;
|
|
449
|
+
}
|
|
433
450
|
return navigator.platform.toLowerCase().includes('windows');
|
|
434
451
|
}
|
|
435
452
|
|
|
@@ -556,6 +573,10 @@ shaka.util.Platform = class {
|
|
|
556
573
|
Platform.isWebOS4() || Platform.isWebOS5()) {
|
|
557
574
|
return false;
|
|
558
575
|
}
|
|
576
|
+
// Older chromecasts without GoogleTV seem to not support SMOOTH properly.
|
|
577
|
+
if (Platform.isChromecast() && !Platform.isAndroidCastDevice()) {
|
|
578
|
+
return false;
|
|
579
|
+
}
|
|
559
580
|
// See: https://chromium-review.googlesource.com/c/chromium/src/+/4577759
|
|
560
581
|
if (Platform.isWindows() && Platform.isEdge()) {
|
|
561
582
|
return false;
|
|
@@ -663,8 +684,8 @@ shaka.util.Platform = class {
|
|
|
663
684
|
/** @type {{screenWidth: number, screenHeight: number}} */(
|
|
664
685
|
JSON.parse(window.PalmSystem.deviceInfo));
|
|
665
686
|
// WebOS has always been able to do 1080p. Assume a 1080p limit.
|
|
666
|
-
maxResolution.width = Math.max(1920, deviceInfo
|
|
667
|
-
maxResolution.height = Math.max(1080, deviceInfo
|
|
687
|
+
maxResolution.width = Math.max(1920, deviceInfo['screenWidth']);
|
|
688
|
+
maxResolution.height = Math.max(1080, deviceInfo['screenHeight']);
|
|
668
689
|
} catch (e) {
|
|
669
690
|
shaka.log.alwaysWarn('WebOS: Error detecting screen size, default ' +
|
|
670
691
|
'screen size 1920x1080.');
|
package/lib/util/tXml.js
CHANGED
|
@@ -779,7 +779,7 @@ shaka.util.TXml = class {
|
|
|
779
779
|
element.setAttribute(k, v);
|
|
780
780
|
}
|
|
781
781
|
|
|
782
|
-
if (doParents && node.parent) {
|
|
782
|
+
if (doParents && node.parent && node.parent.tagName != '?xml') {
|
|
783
783
|
const parentElement = TXml.txmlNodeToDomElement(
|
|
784
784
|
node.parent, /* doParents= */ true, /* doChildren= */ false);
|
|
785
785
|
parentElement.appendChild(element);
|
package/package.json
CHANGED
|
@@ -116,6 +116,7 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.SettingsMenu {
|
|
|
116
116
|
} else {
|
|
117
117
|
otherIdx = tracks.findIndex((t) => {
|
|
118
118
|
return t.height == track.height &&
|
|
119
|
+
t.videoBandwidth == track.videoBandwidth &&
|
|
119
120
|
t.frameRate == track.frameRate &&
|
|
120
121
|
t.hdr == track.hdr &&
|
|
121
122
|
t.videoLayout == track.videoLayout;
|