shaka-player 4.9.30 → 4.9.32
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/.eslintrc.js +1 -0
- package/AUTHORS +2 -0
- package/CONTRIBUTORS +2 -0
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/deps.js +2 -2
- package/dist/locales.js +33 -33
- package/dist/shaka-player.compiled.d.ts +8 -7
- package/dist/shaka-player.compiled.debug.d.ts +8 -7
- package/dist/shaka-player.compiled.debug.externs.js +3 -0
- package/dist/shaka-player.compiled.debug.js +264 -260
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.externs.js +3 -0
- package/dist/shaka-player.compiled.js +1214 -1212
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.d.ts +8 -7
- package/dist/shaka-player.ui.debug.d.ts +8 -7
- package/dist/shaka-player.ui.debug.externs.js +3 -0
- package/dist/shaka-player.ui.debug.js +290 -285
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.externs.js +3 -0
- package/dist/shaka-player.ui.js +1417 -1414
- package/dist/shaka-player.ui.map +3 -3
- package/externs/shaka/abortable.js +36 -36
- package/lib/dash/segment_template.js +19 -2
- package/lib/hls/hls_parser.js +1 -1
- package/lib/media/adaptation_set_criteria.js +8 -1
- package/lib/media/content_workarounds.js +2 -1
- package/lib/media/drm_engine.js +10 -115
- package/lib/media/media_source_engine.js +99 -36
- package/lib/media/preload_manager.js +6 -1
- package/lib/media/segment_index.js +20 -0
- package/lib/media/segment_prefetch.js +7 -0
- package/lib/media/segment_reference.js +1 -1
- package/lib/media/streaming_engine.js +16 -13
- package/lib/mss/mss_parser.js +6 -0
- package/lib/net/networking_engine.js +3 -3
- package/lib/player.js +16 -2
- package/lib/polyfill/media_capabilities.js +48 -9
- package/lib/polyfill/mediasource.js +12 -0
- package/lib/text/ui_text_displayer.js +8 -0
- package/lib/text/vtt_text_parser.js +2 -8
- package/lib/util/abortable_operation.js +7 -5
- package/lib/util/mp4_generator.js +1 -1
- package/lib/util/platform.js +22 -11
- package/package.json +2 -2
- package/ui/controls.js +2 -2
- package/ui/less/containers.less +8 -0
- package/ui/remote_button.js +42 -17
- package/ui/statistics_button.js +0 -2
|
@@ -396,7 +396,12 @@ shaka.media.PreloadManager = class extends shaka.util.FakeEventTarget {
|
|
|
396
396
|
|
|
397
397
|
this.successPromise_.resolve();
|
|
398
398
|
} catch (error) {
|
|
399
|
-
|
|
399
|
+
// Ignore OPERATION_ABORTED and OBJECT_DESTROYED errors.
|
|
400
|
+
if (!(error instanceof shaka.util.Error) ||
|
|
401
|
+
(error.code != shaka.util.Error.Code.OPERATION_ABORTED &&
|
|
402
|
+
error.code != shaka.util.Error.Code.OBJECT_DESTROYED)) {
|
|
403
|
+
this.successPromise_.reject(error);
|
|
404
|
+
}
|
|
400
405
|
}
|
|
401
406
|
})();
|
|
402
407
|
}
|
|
@@ -679,6 +679,26 @@ shaka.media.SegmentIterator = class {
|
|
|
679
679
|
'done': !res,
|
|
680
680
|
};
|
|
681
681
|
}
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* @export
|
|
685
|
+
*/
|
|
686
|
+
resetToLastIndependent() {
|
|
687
|
+
const current = this.current();
|
|
688
|
+
if (current.isPartial() && !current.isIndependent()) {
|
|
689
|
+
const ref = this.segmentIndex_.get(this.currentPosition_);
|
|
690
|
+
if (ref && ref.hasPartialSegments()) {
|
|
691
|
+
let partial = ref.partialReferences[this.currentPartialPosition_];
|
|
692
|
+
while (partial.isIndependent()) {
|
|
693
|
+
if (this.currentPartialPosition_ <= 0) {
|
|
694
|
+
break;
|
|
695
|
+
}
|
|
696
|
+
this.currentPartialPosition_--;
|
|
697
|
+
partial = ref.partialReferences[this.currentPartialPosition_];
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
}
|
|
682
702
|
};
|
|
683
703
|
|
|
684
704
|
|
|
@@ -111,6 +111,9 @@ shaka.media.SegmentPrefetch = class {
|
|
|
111
111
|
shaka.media.SegmentReference.Status.MISSING) {
|
|
112
112
|
prefetchAllowed = false;
|
|
113
113
|
}
|
|
114
|
+
if (reference.getSegmentData()) {
|
|
115
|
+
prefetchAllowed = false;
|
|
116
|
+
}
|
|
114
117
|
if (prefetchAllowed && reference.initSegmentReference) {
|
|
115
118
|
this.prefetchInitSegment(reference.initSegmentReference);
|
|
116
119
|
}
|
|
@@ -143,6 +146,10 @@ shaka.media.SegmentPrefetch = class {
|
|
|
143
146
|
return;
|
|
144
147
|
}
|
|
145
148
|
|
|
149
|
+
if (initSegmentReference.getSegmentData()) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
146
153
|
// init segments are ignored from the prefetch limit
|
|
147
154
|
const initSegments = Array.from(this.initSegmentPrefetchMap_.keys());
|
|
148
155
|
const someReference = initSegments.some((reference) => {
|
|
@@ -295,7 +295,7 @@ shaka.media.SegmentReference = class {
|
|
|
295
295
|
this.thumbnailSprite = null;
|
|
296
296
|
|
|
297
297
|
/** @type {number} */
|
|
298
|
-
this.discontinuitySequence =
|
|
298
|
+
this.discontinuitySequence = -1;
|
|
299
299
|
|
|
300
300
|
/** @type {boolean} */
|
|
301
301
|
this.allPartialSegments = allPartialSegments;
|
|
@@ -2001,8 +2001,7 @@ shaka.media.StreamingEngine = class {
|
|
|
2001
2001
|
const MimeUtils = shaka.util.MimeUtils;
|
|
2002
2002
|
const StreamingEngine = shaka.media.StreamingEngine;
|
|
2003
2003
|
const logPrefix = StreamingEngine.logPrefix_(mediaState);
|
|
2004
|
-
const nullLastReferences = mediaState.lastSegmentReference == null
|
|
2005
|
-
mediaState.lastInitSegmentReference == null;
|
|
2004
|
+
const nullLastReferences = mediaState.lastSegmentReference == null;
|
|
2006
2005
|
|
|
2007
2006
|
/** @type {!Array.<!Promise>} */
|
|
2008
2007
|
const operations = [];
|
|
@@ -2217,17 +2216,15 @@ shaka.media.StreamingEngine = class {
|
|
|
2217
2216
|
}
|
|
2218
2217
|
}
|
|
2219
2218
|
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
mediaState.type, reference.startTime));
|
|
2230
|
-
}
|
|
2219
|
+
const lastDiscontinuitySequence =
|
|
2220
|
+
mediaState.lastSegmentReference ?
|
|
2221
|
+
mediaState.lastSegmentReference.discontinuitySequence : null;
|
|
2222
|
+
// Across discontinuity bounds, we should resync timestamps. The next
|
|
2223
|
+
// segment appended should land at its theoretical timestamp from the
|
|
2224
|
+
// segment index.
|
|
2225
|
+
if (reference.discontinuitySequence != lastDiscontinuitySequence) {
|
|
2226
|
+
operations.push(this.playerInterface_.mediaSourceEngine.resync(
|
|
2227
|
+
mediaState.type, reference.startTime));
|
|
2231
2228
|
}
|
|
2232
2229
|
|
|
2233
2230
|
await Promise.all(operations);
|
|
@@ -2871,12 +2868,18 @@ shaka.media.StreamingEngine = class {
|
|
|
2871
2868
|
audioMediaState.lastInitSegmentReference = null;
|
|
2872
2869
|
this.forceClearBuffer_(audioMediaState);
|
|
2873
2870
|
this.abortOperations_(audioMediaState).catch(() => {});
|
|
2871
|
+
if (audioMediaState.segmentIterator) {
|
|
2872
|
+
audioMediaState.segmentIterator.resetToLastIndependent();
|
|
2873
|
+
}
|
|
2874
2874
|
}
|
|
2875
2875
|
const videoMediaState = this.mediaStates_.get(ContentType.VIDEO);
|
|
2876
2876
|
if (videoMediaState) {
|
|
2877
2877
|
videoMediaState.lastInitSegmentReference = null;
|
|
2878
2878
|
this.forceClearBuffer_(videoMediaState);
|
|
2879
2879
|
this.abortOperations_(videoMediaState).catch(() => {});
|
|
2880
|
+
if (videoMediaState.segmentIterator) {
|
|
2881
|
+
videoMediaState.segmentIterator.resetToLastIndependent();
|
|
2882
|
+
}
|
|
2880
2883
|
}
|
|
2881
2884
|
/**
|
|
2882
2885
|
* @type {!Map.<shaka.util.ManifestParserUtils.ContentType,
|
package/lib/mss/mss_parser.js
CHANGED
|
@@ -943,6 +943,12 @@ shaka.mss.MssParser = class {
|
|
|
943
943
|
let startTime = t != null ? t : lastEndTime;
|
|
944
944
|
|
|
945
945
|
let repeat = r || 0;
|
|
946
|
+
// Unlike in DASH, in MSS r does not start counting repetitions at 0 but
|
|
947
|
+
// at 1, to maintain the code equivalent to DASH if r exists we
|
|
948
|
+
// subtract 1.
|
|
949
|
+
if (repeat) {
|
|
950
|
+
repeat--;
|
|
951
|
+
}
|
|
946
952
|
if (repeat < 0) {
|
|
947
953
|
if (next) {
|
|
948
954
|
const nextStartTime =
|
|
@@ -565,12 +565,12 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
|
|
|
565
565
|
}
|
|
566
566
|
};
|
|
567
567
|
const headersReceived = (headers) => {
|
|
568
|
-
if (this.onHeadersReceived_) {
|
|
569
|
-
this.onHeadersReceived_(headers, request, type);
|
|
570
|
-
}
|
|
571
568
|
headersReceivedCalled = true;
|
|
572
569
|
request.timeToFirstByte = Date.now() -
|
|
573
570
|
/** @type {number} */ (request.requestStartTime);
|
|
571
|
+
if (this.onHeadersReceived_) {
|
|
572
|
+
this.onHeadersReceived_(headers, request, type);
|
|
573
|
+
}
|
|
574
574
|
};
|
|
575
575
|
request.requestStartTime = Date.now();
|
|
576
576
|
|
package/lib/player.js
CHANGED
|
@@ -5922,7 +5922,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5922
5922
|
// Because this.video_ may not be set when the config is built, the default
|
|
5923
5923
|
// TextDisplay factory must capture a reference to "this".
|
|
5924
5924
|
config.textDisplayFactory = () => {
|
|
5925
|
-
|
|
5925
|
+
// On iOS where the Fullscreen API is not available we prefer
|
|
5926
|
+
// SimpleTextDisplayer because it works with the Fullscreen API of the
|
|
5927
|
+
// video element itself.
|
|
5928
|
+
const Platform = shaka.util.Platform;
|
|
5929
|
+
if (this.videoContainer_ &&
|
|
5930
|
+
(!Platform.safariVersion() || document.fullscreenEnabled)) {
|
|
5926
5931
|
const latestConfig = this.getConfiguration();
|
|
5927
5932
|
return new shaka.text.UITextDisplayer(
|
|
5928
5933
|
this.video_, this.videoContainer_, latestConfig.textDisplayer);
|
|
@@ -6253,6 +6258,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
6253
6258
|
return;
|
|
6254
6259
|
}
|
|
6255
6260
|
|
|
6261
|
+
// We don't want to block the user from pausing the stream.
|
|
6262
|
+
if (this.video_.paused) {
|
|
6263
|
+
return;
|
|
6264
|
+
}
|
|
6265
|
+
|
|
6256
6266
|
let liveSyncMaxLatency;
|
|
6257
6267
|
let liveSyncPlaybackRate;
|
|
6258
6268
|
if (this.config_.streaming.liveSync) {
|
|
@@ -6943,6 +6953,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
6943
6953
|
return false;
|
|
6944
6954
|
}
|
|
6945
6955
|
|
|
6956
|
+
if (!this.manifest_) {
|
|
6957
|
+
return false;
|
|
6958
|
+
}
|
|
6959
|
+
|
|
6946
6960
|
// It only makes sense to disable a stream if we have an alternative else we
|
|
6947
6961
|
// end up disabling all variants.
|
|
6948
6962
|
const hasAltStream = this.manifest_.variants.some((variant) => {
|
|
@@ -7535,7 +7549,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
7535
7549
|
* @export
|
|
7536
7550
|
*/
|
|
7537
7551
|
// eslint-disable-next-line no-useless-concat, max-len
|
|
7538
|
-
shaka.Player.version = 'v4.9.
|
|
7552
|
+
shaka.Player.version = 'v4.9.32' + '-uncompiled'; // x-release-please-version
|
|
7539
7553
|
|
|
7540
7554
|
// Initialize the deprecation system using the version string we just set
|
|
7541
7555
|
// on the player.
|
|
@@ -61,7 +61,8 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
61
61
|
shaka.util.Platform.isWebOS() ||
|
|
62
62
|
shaka.util.Platform.isTizen() ||
|
|
63
63
|
shaka.util.Platform.isEOS() ||
|
|
64
|
-
shaka.util.Platform.isHisense()
|
|
64
|
+
shaka.util.Platform.isHisense() ||
|
|
65
|
+
shaka.util.Platform.isComcastX1()) {
|
|
65
66
|
canUseNativeMCap = false;
|
|
66
67
|
}
|
|
67
68
|
if (canUseNativeMCap && navigator.mediaCapabilities) {
|
|
@@ -326,18 +327,56 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
326
327
|
|
|
327
328
|
let displayType = videoConfig.contentType;
|
|
328
329
|
if (videoConfig.width && videoConfig.height) {
|
|
329
|
-
|
|
330
|
-
|
|
330
|
+
// All Chromecast can support 720p videos
|
|
331
|
+
if (videoConfig.width > 1280 || videoConfig.height > 720) {
|
|
332
|
+
displayType +=
|
|
333
|
+
`; width=${videoConfig.width}; height=${videoConfig.height}`;
|
|
334
|
+
}
|
|
331
335
|
}
|
|
332
336
|
if (videoConfig.framerate) {
|
|
333
|
-
|
|
337
|
+
// All Chromecast can support a framerate of 24, 25 or 30.
|
|
338
|
+
const framerate = Math.round(videoConfig.framerate);
|
|
339
|
+
if (framerate < 24 || framerate > 30) {
|
|
340
|
+
displayType += `; framerate=${videoConfig.framerate}`;
|
|
341
|
+
}
|
|
334
342
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
343
|
+
|
|
344
|
+
// Don't trust Closure types here. Although transferFunction is string or
|
|
345
|
+
// undefined, we don't want to count on the input type. A switch statement
|
|
346
|
+
// will, however, differentiate between null and undefined. So we default
|
|
347
|
+
// to a blank string.
|
|
348
|
+
const transferFunction = videoConfig.transferFunction || '';
|
|
349
|
+
|
|
350
|
+
// Based on internal sources. Googlers, see go/cast-hdr-queries for source.
|
|
351
|
+
switch (transferFunction) {
|
|
352
|
+
// The empty case falls through to SDR.
|
|
353
|
+
case '':
|
|
354
|
+
// These are the only 3 values defined by MCap as of November 2024.
|
|
355
|
+
case 'srgb':
|
|
356
|
+
// https://en.wikipedia.org/wiki/Standard-dynamic-range_video
|
|
357
|
+
// https://en.wikipedia.org/wiki/SRGB
|
|
358
|
+
// https://en.wikipedia.org/wiki/Rec._709
|
|
359
|
+
// This is SDR, standardized in BT 709.
|
|
360
|
+
// The platform recognizes "eotf=bt709", but we can also omit it.
|
|
361
|
+
break;
|
|
362
|
+
|
|
363
|
+
case 'pq':
|
|
364
|
+
// https://en.wikipedia.org/wiki/Perceptual_quantizer
|
|
365
|
+
// This HDR transfer function is standardized as SMPTE ST 2084.
|
|
366
|
+
displayType += '; eotf=smpte2084';
|
|
367
|
+
break;
|
|
368
|
+
|
|
369
|
+
case 'hlg':
|
|
370
|
+
// https://en.wikipedia.org/wiki/Hybrid_log%E2%80%93gamma
|
|
371
|
+
// This HDR transfer function is standardized as ARIB STD-B67.
|
|
372
|
+
displayType += '; eotf=arib-std-b67';
|
|
373
|
+
break;
|
|
374
|
+
|
|
375
|
+
default:
|
|
376
|
+
// An unrecognized transfer function. Reject this query.
|
|
377
|
+
return false;
|
|
340
378
|
}
|
|
379
|
+
|
|
341
380
|
let result = false;
|
|
342
381
|
if (displayType in shaka.polyfill.MediaCapabilities
|
|
343
382
|
.memoizedCanDisplayTypeRequests_) {
|
|
@@ -87,6 +87,18 @@ shaka.polyfill.MediaSource = class {
|
|
|
87
87
|
// the player from trying to play opus on Tizen, we will override media
|
|
88
88
|
// source to always reject opus content.
|
|
89
89
|
shaka.polyfill.MediaSource.rejectCodec_('opus');
|
|
90
|
+
} else if (shaka.util.Platform.isComcastX1()) {
|
|
91
|
+
// XOne look to be like safari 8 which do not correctly
|
|
92
|
+
// implement abort() on SourceBuffer.
|
|
93
|
+
// Calling abort() before appending a segment causes that segment to be
|
|
94
|
+
// incomplete in the buffer.
|
|
95
|
+
// Bug filed: https://bugs.webkit.org/show_bug.cgi?id=165342
|
|
96
|
+
shaka.polyfill.MediaSource.stubAbort_();
|
|
97
|
+
// If you remove up to a keyframe, Webkit 601.x.x incorrectly will also
|
|
98
|
+
// remove that keyframe and the content up to the next.
|
|
99
|
+
// Offsetting the end of the removal range seems to help.
|
|
100
|
+
// Bug filed: https://bugs.webkit.org/show_bug.cgi?id=177884
|
|
101
|
+
shaka.polyfill.MediaSource.patchRemovalRange_();
|
|
90
102
|
} else {
|
|
91
103
|
shaka.log.info('Using native MSE as-is.');
|
|
92
104
|
}
|
|
@@ -9,6 +9,7 @@ goog.provide('shaka.text.UITextDisplayer');
|
|
|
9
9
|
|
|
10
10
|
goog.require('goog.asserts');
|
|
11
11
|
goog.require('shaka.Deprecate');
|
|
12
|
+
goog.require('shaka.log');
|
|
12
13
|
goog.require('shaka.text.Cue');
|
|
13
14
|
goog.require('shaka.text.CueRegion');
|
|
14
15
|
goog.require('shaka.text.Utils');
|
|
@@ -35,6 +36,12 @@ shaka.text.UITextDisplayer = class {
|
|
|
35
36
|
constructor(video, videoContainer, config) {
|
|
36
37
|
goog.asserts.assert(videoContainer, 'videoContainer should be valid.');
|
|
37
38
|
|
|
39
|
+
if (!document.fullscreenEnabled) {
|
|
40
|
+
shaka.log.alwaysWarn('Using UITextDisplayer in a browser without ' +
|
|
41
|
+
'Fullscreen API support causes subtitles to not be rendered in ' +
|
|
42
|
+
'fullscreen');
|
|
43
|
+
}
|
|
44
|
+
|
|
38
45
|
/** @private {boolean} */
|
|
39
46
|
this.isTextVisible_ = false;
|
|
40
47
|
|
|
@@ -248,6 +255,7 @@ shaka.text.UITextDisplayer = class {
|
|
|
248
255
|
*/
|
|
249
256
|
setTextVisibility(on) {
|
|
250
257
|
this.isTextVisible_ = on;
|
|
258
|
+
this.updateCaptions_(/* forceUpdate= */ true);
|
|
251
259
|
}
|
|
252
260
|
|
|
253
261
|
/**
|
|
@@ -87,13 +87,7 @@ shaka.text.VttTextParser = class {
|
|
|
87
87
|
// Only use 'X-TIMESTAMP-MAP' with HLS. This overrides offset above.
|
|
88
88
|
if (blocks[0].includes('X-TIMESTAMP-MAP') &&
|
|
89
89
|
this.manifestType_ == shaka.media.ManifestParser.HLS) {
|
|
90
|
-
|
|
91
|
-
// Compute a different, rollover-based offset for sequence mode.
|
|
92
|
-
offset = this.computeHlsSequenceModeOffset_(blocks[0], time);
|
|
93
|
-
} else {
|
|
94
|
-
// Calculate the offset from the segment startTime.
|
|
95
|
-
offset = time.segmentStart;
|
|
96
|
-
}
|
|
90
|
+
offset = this.computeHlsOffset_(blocks[0], time);
|
|
97
91
|
}
|
|
98
92
|
|
|
99
93
|
// Parse VTT regions.
|
|
@@ -130,7 +124,7 @@ shaka.text.VttTextParser = class {
|
|
|
130
124
|
* @return {number}
|
|
131
125
|
* @private
|
|
132
126
|
*/
|
|
133
|
-
|
|
127
|
+
computeHlsOffset_(headerBlock, time) {
|
|
134
128
|
// https://bit.ly/2K92l7y
|
|
135
129
|
// The 'X-TIMESTAMP-MAP' header is used in HLS to align text with
|
|
136
130
|
// the rest of the media.
|
|
@@ -39,8 +39,8 @@ shaka.util.AbortableOperation = class {
|
|
|
39
39
|
/** @private {function():!Promise} */
|
|
40
40
|
this.onAbort_ = onAbort;
|
|
41
41
|
|
|
42
|
-
/** @private {
|
|
43
|
-
this.
|
|
42
|
+
/** @private {?Promise} */
|
|
43
|
+
this.abortPromise_ = null;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
/**
|
|
@@ -110,8 +110,10 @@ shaka.util.AbortableOperation = class {
|
|
|
110
110
|
* @export
|
|
111
111
|
*/
|
|
112
112
|
abort() {
|
|
113
|
-
this.
|
|
114
|
-
|
|
113
|
+
if (!this.abortPromise_) {
|
|
114
|
+
this.abortPromise_ = this.onAbort_();
|
|
115
|
+
}
|
|
116
|
+
return this.abortPromise_;
|
|
115
117
|
}
|
|
116
118
|
|
|
117
119
|
/**
|
|
@@ -166,7 +168,7 @@ shaka.util.AbortableOperation = class {
|
|
|
166
168
|
|
|
167
169
|
const makeCallback = (isSuccess) => {
|
|
168
170
|
return (value) => {
|
|
169
|
-
if (this.
|
|
171
|
+
if (this.abortPromise_ && isSuccess) {
|
|
170
172
|
// If "this" is not abortable(), or if abort() is called after "this"
|
|
171
173
|
// is complete but before the next stage in the chain begins, we
|
|
172
174
|
// should stop right away.
|
|
@@ -765,7 +765,7 @@ shaka.util.Mp4Generator = class {
|
|
|
765
765
|
0x00, 0x00, 0x00, 0x01, // default_sample_description_index
|
|
766
766
|
0x00, 0x00, 0x00, 0x00, // default_sample_duration
|
|
767
767
|
0x00, 0x00, 0x00, 0x00, // default_sample_size
|
|
768
|
-
0x00,
|
|
768
|
+
0x00, 0x00, 0x00, 0x00, // default_sample_flags
|
|
769
769
|
]);
|
|
770
770
|
return Mp4Generator.box('trex', bytes);
|
|
771
771
|
}
|
package/lib/util/platform.js
CHANGED
|
@@ -205,6 +205,17 @@ shaka.util.Platform = class {
|
|
|
205
205
|
shaka.util.Platform.chromeVersion() === 68;
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
+
/**
|
|
209
|
+
* Check if the current platform is a WebOS 6.
|
|
210
|
+
*
|
|
211
|
+
* @return {boolean}
|
|
212
|
+
*/
|
|
213
|
+
static isWebOS6() {
|
|
214
|
+
// See: https://webostv.developer.lge.com/develop/specifications/web-api-and-web-engine#useragent-string
|
|
215
|
+
return shaka.util.Platform.isWebOS() &&
|
|
216
|
+
shaka.util.Platform.chromeVersion() === 79;
|
|
217
|
+
}
|
|
218
|
+
|
|
208
219
|
/**
|
|
209
220
|
* Check if the current platform is a Google Chromecast.
|
|
210
221
|
*
|
|
@@ -300,7 +311,7 @@ shaka.util.Platform = class {
|
|
|
300
311
|
!shaka.util.Platform.isOrange() &&
|
|
301
312
|
!shaka.util.Platform.isPS4() &&
|
|
302
313
|
!shaka.util.Platform.isAmazonFireTV() &&
|
|
303
|
-
!shaka.util.Platform.
|
|
314
|
+
!shaka.util.Platform.isComcastX1() &&
|
|
304
315
|
!shaka.util.Platform.isZenterio() &&
|
|
305
316
|
!shaka.util.Platform.isSkyQ();
|
|
306
317
|
}
|
|
@@ -368,7 +379,7 @@ shaka.util.Platform = class {
|
|
|
368
379
|
* Check if the current platform is Comcast X1.
|
|
369
380
|
* @return {boolean}
|
|
370
381
|
*/
|
|
371
|
-
static
|
|
382
|
+
static isComcastX1() {
|
|
372
383
|
return shaka.util.Platform.userAgentContains_('WPE');
|
|
373
384
|
}
|
|
374
385
|
|
|
@@ -503,7 +514,7 @@ shaka.util.Platform = class {
|
|
|
503
514
|
if (!navigator.platform) {
|
|
504
515
|
return false;
|
|
505
516
|
}
|
|
506
|
-
return navigator.platform.toLowerCase().includes('
|
|
517
|
+
return navigator.platform.toLowerCase().includes('win32');
|
|
507
518
|
}
|
|
508
519
|
|
|
509
520
|
/**
|
|
@@ -536,7 +547,7 @@ shaka.util.Platform = class {
|
|
|
536
547
|
Platform.isPS5() || Platform.isAmazonFireTV() ||
|
|
537
548
|
Platform.isEOS() || Platform.isAPL() ||
|
|
538
549
|
Platform.isVirginMedia() || Platform.isOrange() ||
|
|
539
|
-
Platform.
|
|
550
|
+
Platform.isComcastX1() || Platform.isChromecast() ||
|
|
540
551
|
Platform.isHisense() || Platform.isZenterio()) {
|
|
541
552
|
return true;
|
|
542
553
|
}
|
|
@@ -627,19 +638,19 @@ shaka.util.Platform = class {
|
|
|
627
638
|
/**
|
|
628
639
|
* Returns if codec switching SMOOTH is known reliable device support.
|
|
629
640
|
*
|
|
630
|
-
* Some devices are known not to support
|
|
641
|
+
* Some devices are known not to support <code>SourceBuffer.changeType</code>
|
|
631
642
|
* well. These devices should use the reload strategy. If a device
|
|
632
|
-
* reports that it supports
|
|
633
|
-
* it should be
|
|
643
|
+
* reports that it supports <code<changeType</code> but supports it unreliably
|
|
644
|
+
* it should be disallowed in this method.
|
|
634
645
|
*
|
|
635
646
|
* @return {boolean}
|
|
636
647
|
*/
|
|
637
648
|
static supportsSmoothCodecSwitching() {
|
|
638
649
|
const Platform = shaka.util.Platform;
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
Platform.
|
|
650
|
+
// All Tizen versions (up to Tizen 8) do not support SMOOTH so far.
|
|
651
|
+
// webOS seems to support SMOOTH from webOS 22.
|
|
652
|
+
if (Platform.isTizen() || Platform.isPS4() || Platform.isPS5() ||
|
|
653
|
+
Platform.isWebOS6()) {
|
|
643
654
|
return false;
|
|
644
655
|
}
|
|
645
656
|
// Older chromecasts without GoogleTV seem to not support SMOOTH properly.
|
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.9.
|
|
4
|
+
"version": "4.9.32",
|
|
5
5
|
"homepage": "https://github.com/shaka-project/shaka-player",
|
|
6
6
|
"author": "Google",
|
|
7
7
|
"maintainers": [
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"core-js": "^3.21.1",
|
|
27
27
|
"dialog-polyfill": "^0.5.6",
|
|
28
28
|
"es6-promise-polyfill": "^1.2.0",
|
|
29
|
-
"eslint": "^8.
|
|
29
|
+
"eslint": "^8.57.1",
|
|
30
30
|
"eslint-config-google": "^0.14.0",
|
|
31
31
|
"eslint-plugin-shaka-rules": "file:./build/eslint-plugin-shaka-rules",
|
|
32
32
|
"esprima": "^4.0.1",
|
package/ui/controls.js
CHANGED
|
@@ -1301,7 +1301,7 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
|
|
|
1301
1301
|
}
|
|
1302
1302
|
|
|
1303
1303
|
// Use the cursor specified in the CSS file.
|
|
1304
|
-
this.videoContainer_.
|
|
1304
|
+
this.videoContainer_.classList.remove('no-cursor');
|
|
1305
1305
|
|
|
1306
1306
|
this.recentMouseMovement_ = true;
|
|
1307
1307
|
|
|
@@ -1354,7 +1354,7 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
|
|
|
1354
1354
|
*/
|
|
1355
1355
|
onMouseStill_() {
|
|
1356
1356
|
// Hide the cursor.
|
|
1357
|
-
this.videoContainer_.
|
|
1357
|
+
this.videoContainer_.classList.add('no-cursor');
|
|
1358
1358
|
this.recentMouseMovement_ = false;
|
|
1359
1359
|
this.computeOpacity();
|
|
1360
1360
|
}
|
package/ui/less/containers.less
CHANGED
package/ui/remote_button.js
CHANGED
|
@@ -33,6 +33,9 @@ shaka.ui.RemoteButton = class extends shaka.ui.Element {
|
|
|
33
33
|
constructor(parent, controls) {
|
|
34
34
|
super(parent, controls);
|
|
35
35
|
|
|
36
|
+
/** @private {boolean} */
|
|
37
|
+
this.isAirPlay_ = shaka.util.Platform.isSafari();
|
|
38
|
+
|
|
36
39
|
/** @private {!HTMLButtonElement} */
|
|
37
40
|
this.remoteButton_ = shaka.util.Dom.createButton();
|
|
38
41
|
this.remoteButton_.classList.add('shaka-remote-button');
|
|
@@ -42,12 +45,9 @@ shaka.ui.RemoteButton = class extends shaka.ui.Element {
|
|
|
42
45
|
/** @private {!HTMLElement} */
|
|
43
46
|
this.remoteIcon_ = shaka.util.Dom.createHTMLElement('i');
|
|
44
47
|
this.remoteIcon_.classList.add('material-icons-round');
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
icon = shaka.ui.Enums.MaterialDesignIcons.AIRPLAY;
|
|
49
|
-
}
|
|
50
|
-
this.remoteIcon_.textContent = icon;
|
|
48
|
+
this.remoteIcon_.textContent = this.isAirPlay_ ?
|
|
49
|
+
shaka.ui.Enums.MaterialDesignIcons.AIRPLAY :
|
|
50
|
+
shaka.ui.Enums.MaterialDesignIcons.CAST;
|
|
51
51
|
this.remoteButton_.appendChild(this.remoteIcon_);
|
|
52
52
|
|
|
53
53
|
const label = shaka.util.Dom.createHTMLElement('label');
|
|
@@ -95,21 +95,25 @@ shaka.ui.RemoteButton = class extends shaka.ui.Element {
|
|
|
95
95
|
|
|
96
96
|
this.eventManager.listen(this.video.remote, 'connect', () => {
|
|
97
97
|
this.updateRemoteState_();
|
|
98
|
+
this.updateIcon_();
|
|
98
99
|
});
|
|
99
100
|
|
|
100
101
|
this.eventManager.listen(this.video.remote, 'connecting', () => {
|
|
101
102
|
this.updateRemoteState_();
|
|
103
|
+
this.updateIcon_();
|
|
102
104
|
});
|
|
103
105
|
|
|
104
106
|
this.eventManager.listen(this.video.remote, 'disconnect', () => {
|
|
105
107
|
this.updateRemoteState_();
|
|
108
|
+
this.updateIcon_();
|
|
106
109
|
});
|
|
107
110
|
|
|
108
111
|
this.eventManager.listen(this.player, 'loaded', () => {
|
|
109
112
|
this.updateRemoteState_();
|
|
110
113
|
});
|
|
111
114
|
|
|
112
|
-
this.updateRemoteState_();
|
|
115
|
+
this.updateRemoteState_(/* force= */ true);
|
|
116
|
+
this.updateIcon_();
|
|
113
117
|
}
|
|
114
118
|
}
|
|
115
119
|
|
|
@@ -125,9 +129,10 @@ shaka.ui.RemoteButton = class extends shaka.ui.Element {
|
|
|
125
129
|
}
|
|
126
130
|
|
|
127
131
|
/**
|
|
132
|
+
* @param {boolean=} force
|
|
128
133
|
* @private
|
|
129
134
|
*/
|
|
130
|
-
async updateRemoteState_() {
|
|
135
|
+
async updateRemoteState_(force = false) {
|
|
131
136
|
if (this.controls.getCastProxy().canCast() &&
|
|
132
137
|
this.controls.isCastAllowed()) {
|
|
133
138
|
shaka.ui.Utils.setDisplay(this.remoteButton_, false);
|
|
@@ -135,14 +140,20 @@ shaka.ui.RemoteButton = class extends shaka.ui.Element {
|
|
|
135
140
|
this.video.remote.cancelWatchAvailability(this.callbackId_);
|
|
136
141
|
this.callbackId_ = -1;
|
|
137
142
|
}
|
|
138
|
-
} else if (this.video.remote.state == 'disconnected') {
|
|
143
|
+
} else if (this.video.remote.state == 'disconnected' || force) {
|
|
139
144
|
const handleAvailabilityChange = (availability) => {
|
|
140
145
|
if (this.player) {
|
|
141
146
|
const disableRemote = this.video.disableRemotePlayback;
|
|
142
|
-
|
|
143
|
-
|
|
147
|
+
let canCast = true;
|
|
148
|
+
if (shaka.util.Platform.isSafari()) {
|
|
149
|
+
const loadMode = this.player.getLoadMode();
|
|
150
|
+
const mseMode = loadMode == shaka.Player.LoadMode.MEDIA_SOURCE;
|
|
151
|
+
if (mseMode && this.player.getManifestType() != 'HLS') {
|
|
152
|
+
canCast = false;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
144
155
|
shaka.ui.Utils.setDisplay(
|
|
145
|
-
this.remoteButton_,
|
|
156
|
+
this.remoteButton_, canCast && availability && !disableRemote);
|
|
146
157
|
} else {
|
|
147
158
|
shaka.ui.Utils.setDisplay(this.remoteButton_, false);
|
|
148
159
|
}
|
|
@@ -175,14 +186,28 @@ shaka.ui.RemoteButton = class extends shaka.ui.Element {
|
|
|
175
186
|
*/
|
|
176
187
|
updateLocalizedStrings_() {
|
|
177
188
|
const LocIds = shaka.ui.Locales.Ids;
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
text = this.localization.resolve(LocIds.AIRPLAY);
|
|
182
|
-
}
|
|
189
|
+
const text = this.isAirPlay_ ?
|
|
190
|
+
this.localization.resolve(LocIds.AIRPLAY) :
|
|
191
|
+
this.localization.resolve(LocIds.CAST);
|
|
183
192
|
this.remoteButton_.ariaLabel = text;
|
|
184
193
|
this.remoteNameSpan_.textContent = text;
|
|
185
194
|
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* @private
|
|
198
|
+
*/
|
|
199
|
+
updateIcon_() {
|
|
200
|
+
if (this.isAirPlay_) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (this.video.remote.state == 'disconnected') {
|
|
204
|
+
this.remoteIcon_.textContent =
|
|
205
|
+
shaka.ui.Enums.MaterialDesignIcons.CAST;
|
|
206
|
+
} else {
|
|
207
|
+
this.remoteIcon_.textContent =
|
|
208
|
+
shaka.ui.Enums.MaterialDesignIcons.EXIT_CAST;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
186
211
|
};
|
|
187
212
|
|
|
188
213
|
|
package/ui/statistics_button.js
CHANGED
|
@@ -232,8 +232,6 @@ shaka.ui.StatisticsButton = class extends shaka.ui.Element {
|
|
|
232
232
|
const element = this.generateComponent_(name);
|
|
233
233
|
this.container_.appendChild(element);
|
|
234
234
|
this.statisticsList_.push(name);
|
|
235
|
-
shaka.ui.Utils.setDisplay(element.parentElement,
|
|
236
|
-
!isNaN(this.currentStats_[name]));
|
|
237
235
|
} else {
|
|
238
236
|
shaka.log.alwaysWarn('Unrecognized statistic element:', name);
|
|
239
237
|
}
|