shaka-player 4.9.22 → 4.9.23
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 +10 -10
- package/dist/locales.js +34 -34
- package/dist/shaka-player.compiled.debug.js +440 -444
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.js +1181 -1178
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.debug.js +487 -492
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.js +1380 -1377
- package/dist/shaka-player.ui.map +3 -3
- package/lib/dash/dash_parser.js +31 -7
- package/lib/hls/hls_classes.js +5 -1
- package/lib/hls/hls_parser.js +2 -2
- package/lib/media/media_source_engine.js +3 -1
- package/lib/media/streaming_engine.js +14 -1
- package/lib/player.js +29 -9
- package/lib/polyfill/abort_controller.js +24 -16
- package/lib/text/ui_text_displayer.js +1 -1
- package/lib/util/stream_utils.js +7 -0
- package/lib/util/tXml.js +40 -1
- package/package.json +3 -3
- package/ui/presentation_time.js +4 -1
- package/ui/resolution_selection.js +11 -3
- package/ui/seek_bar.js +2 -1
package/lib/dash/dash_parser.js
CHANGED
|
@@ -1006,12 +1006,16 @@ shaka.dash.DashParser = class {
|
|
|
1006
1006
|
getContextIdsFromPath_(paths) {
|
|
1007
1007
|
let periodId = '';
|
|
1008
1008
|
let adaptationSetId = '';
|
|
1009
|
+
let adaptationSetPosition = -1;
|
|
1009
1010
|
let representationId = '';
|
|
1010
1011
|
for (const node of paths) {
|
|
1011
1012
|
if (node.name === 'Period') {
|
|
1012
1013
|
periodId = node.id;
|
|
1013
1014
|
} else if (node.name === 'AdaptationSet') {
|
|
1014
1015
|
adaptationSetId = node.id;
|
|
1016
|
+
if (node.position !== null) {
|
|
1017
|
+
adaptationSetPosition = node.position;
|
|
1018
|
+
}
|
|
1015
1019
|
} else if (node.name === 'Representation') {
|
|
1016
1020
|
representationId = node.id;
|
|
1017
1021
|
}
|
|
@@ -1023,14 +1027,27 @@ shaka.dash.DashParser = class {
|
|
|
1023
1027
|
if (representationId) {
|
|
1024
1028
|
contextIds.push(periodId + ',' + representationId);
|
|
1025
1029
|
} else {
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1030
|
+
if (adaptationSetId) {
|
|
1031
|
+
for (const context of this.contextCache_.values()) {
|
|
1032
|
+
if (context.period.id === periodId &&
|
|
1033
|
+
context.adaptationSet.id === adaptationSetId &&
|
|
1034
|
+
context.representation.id) {
|
|
1035
|
+
contextIds.push(periodId + ',' + context.representation.id);
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
} else {
|
|
1039
|
+
if (adaptationSetPosition > -1) {
|
|
1040
|
+
for (const context of this.contextCache_.values()) {
|
|
1041
|
+
if (context.period.id === periodId &&
|
|
1042
|
+
context.adaptationSet.position === adaptationSetPosition &&
|
|
1043
|
+
context.representation.id) {
|
|
1044
|
+
contextIds.push(periodId + ',' + context.representation.id);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1031
1047
|
}
|
|
1032
1048
|
}
|
|
1033
1049
|
}
|
|
1050
|
+
|
|
1034
1051
|
return contextIds;
|
|
1035
1052
|
}
|
|
1036
1053
|
|
|
@@ -1423,7 +1440,8 @@ shaka.dash.DashParser = class {
|
|
|
1423
1440
|
const adaptationSetNodes =
|
|
1424
1441
|
TXml.findChildren(periodInfo.node, 'AdaptationSet');
|
|
1425
1442
|
const adaptationSets = adaptationSetNodes
|
|
1426
|
-
.map((node) =>
|
|
1443
|
+
.map((node, position) =>
|
|
1444
|
+
this.parseAdaptationSet_(context, position, node))
|
|
1427
1445
|
.filter(Functional.isNotNull);
|
|
1428
1446
|
|
|
1429
1447
|
// For dynamic manifests, we use rep IDs internally, and they must be
|
|
@@ -1530,11 +1548,12 @@ shaka.dash.DashParser = class {
|
|
|
1530
1548
|
* Parses an AdaptationSet XML element.
|
|
1531
1549
|
*
|
|
1532
1550
|
* @param {shaka.dash.DashParser.Context} context
|
|
1551
|
+
* @param {number} position
|
|
1533
1552
|
* @param {!shaka.extern.xml.Node} elem The AdaptationSet element.
|
|
1534
1553
|
* @return {?shaka.dash.DashParser.AdaptationInfo}
|
|
1535
1554
|
* @private
|
|
1536
1555
|
*/
|
|
1537
|
-
parseAdaptationSet_(context, elem) {
|
|
1556
|
+
parseAdaptationSet_(context, position, elem) {
|
|
1538
1557
|
const TXml = shaka.util.TXml;
|
|
1539
1558
|
const Functional = shaka.util.Functional;
|
|
1540
1559
|
const ManifestParserUtils = shaka.util.ManifestParserUtils;
|
|
@@ -1542,6 +1561,7 @@ shaka.dash.DashParser = class {
|
|
|
1542
1561
|
const ContentProtection = shaka.dash.ContentProtection;
|
|
1543
1562
|
|
|
1544
1563
|
context.adaptationSet = this.createFrame_(elem, context.period, null);
|
|
1564
|
+
context.adaptationSet.position = position;
|
|
1545
1565
|
|
|
1546
1566
|
let main = false;
|
|
1547
1567
|
const roleElements = TXml.findChildren(elem, 'Role');
|
|
@@ -2199,6 +2219,7 @@ shaka.dash.DashParser = class {
|
|
|
2199
2219
|
pixelAspectRatio: frameRef.pixelAspectRatio,
|
|
2200
2220
|
emsgSchemeIdUris: frameRef.emsgSchemeIdUris,
|
|
2201
2221
|
id: frameRef.id,
|
|
2222
|
+
position: frameRef.position,
|
|
2202
2223
|
numChannels: frameRef.numChannels,
|
|
2203
2224
|
audioSamplingRate: frameRef.audioSamplingRate,
|
|
2204
2225
|
availabilityTimeOffset: frameRef.availabilityTimeOffset,
|
|
@@ -2949,6 +2970,7 @@ shaka.dash.DashParser.RequestSegmentCallback;
|
|
|
2949
2970
|
* pixelAspectRatio: (string|undefined),
|
|
2950
2971
|
* emsgSchemeIdUris: !Array.<string>,
|
|
2951
2972
|
* id: ?string,
|
|
2973
|
+
* position: (number|undefined),
|
|
2952
2974
|
* language: ?string,
|
|
2953
2975
|
* numChannels: ?number,
|
|
2954
2976
|
* audioSamplingRate: ?number,
|
|
@@ -2988,6 +3010,8 @@ shaka.dash.DashParser.RequestSegmentCallback;
|
|
|
2988
3010
|
* emsg registered schemeIdUris.
|
|
2989
3011
|
* @property {?string} id
|
|
2990
3012
|
* The ID of the element.
|
|
3013
|
+
* @property {number|undefined} position
|
|
3014
|
+
* Position of the element used for indexing in case of no id
|
|
2991
3015
|
* @property {?string} language
|
|
2992
3016
|
* The original language of the element.
|
|
2993
3017
|
* @property {?number} numChannels
|
package/lib/hls/hls_classes.js
CHANGED
|
@@ -120,9 +120,13 @@ shaka.hls.Tag = class {
|
|
|
120
120
|
/**
|
|
121
121
|
* Create the string key of the tag.
|
|
122
122
|
*
|
|
123
|
+
* @param {boolean} keepAllAtributtes
|
|
123
124
|
* @return {string}
|
|
124
125
|
*/
|
|
125
|
-
getTagKey() {
|
|
126
|
+
getTagKey(keepAllAtributtes) {
|
|
127
|
+
if (keepAllAtributtes) {
|
|
128
|
+
return this.toString();
|
|
129
|
+
}
|
|
126
130
|
const attributesToSkip = new Set()
|
|
127
131
|
.add('AUDIO')
|
|
128
132
|
.add('VIDEO')
|
package/lib/hls/hls_parser.js
CHANGED
|
@@ -1375,7 +1375,7 @@ shaka.hls.HlsParser = class {
|
|
|
1375
1375
|
|
|
1376
1376
|
const groupedTags = {};
|
|
1377
1377
|
for (const tag of mediaTags) {
|
|
1378
|
-
const key = tag.getTagKey();
|
|
1378
|
+
const key = tag.getTagKey(!this.contentSteeringManager_);
|
|
1379
1379
|
if (!groupedTags[key]) {
|
|
1380
1380
|
groupedTags[key] = [tag];
|
|
1381
1381
|
} else {
|
|
@@ -1456,7 +1456,7 @@ shaka.hls.HlsParser = class {
|
|
|
1456
1456
|
|
|
1457
1457
|
const groupedTags = {};
|
|
1458
1458
|
for (const tag of tags) {
|
|
1459
|
-
const key = tag.getTagKey();
|
|
1459
|
+
const key = tag.getTagKey(!this.contentSteeringManager_);
|
|
1460
1460
|
if (!groupedTags[key]) {
|
|
1461
1461
|
groupedTags[key] = [tag];
|
|
1462
1462
|
} else {
|
|
@@ -1082,13 +1082,15 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1082
1082
|
bufferedBefore, bufferedAfter);
|
|
1083
1083
|
if (newBuffered) {
|
|
1084
1084
|
const segmentDuration = reference.endTime - reference.startTime;
|
|
1085
|
+
const timeAdded = newBuffered.end - newBuffered.start;
|
|
1085
1086
|
// Check end times instead of start times. We may be overwriting a
|
|
1086
1087
|
// buffer and only the end changes, and that would be fine.
|
|
1087
1088
|
// Also, exclude tiny segments. Sometimes alignment segments as small
|
|
1088
1089
|
// as 33ms are seen in Google DAI content. For such tiny segments,
|
|
1089
1090
|
// half a segment duration would be no issue.
|
|
1090
1091
|
const offset = Math.abs(newBuffered.end - reference.endTime);
|
|
1091
|
-
if (segmentDuration > 0.100 && offset > segmentDuration / 2
|
|
1092
|
+
if (segmentDuration > 0.100 && (offset > segmentDuration / 2 ||
|
|
1093
|
+
Math.abs(segmentDuration - timeAdded) > 0.030)) {
|
|
1092
1094
|
shaka.log.error('Possible encoding problem detected!',
|
|
1093
1095
|
'Unexpected buffered range for reference', reference,
|
|
1094
1096
|
'from URIs', reference.getUris(),
|
|
@@ -1993,6 +1993,8 @@ shaka.media.StreamingEngine = class {
|
|
|
1993
1993
|
const MimeUtils = shaka.util.MimeUtils;
|
|
1994
1994
|
const StreamingEngine = shaka.media.StreamingEngine;
|
|
1995
1995
|
const logPrefix = StreamingEngine.logPrefix_(mediaState);
|
|
1996
|
+
const nullLastReferences = mediaState.lastSegmentReference == null &&
|
|
1997
|
+
mediaState.lastInitSegmentReference == null;
|
|
1996
1998
|
|
|
1997
1999
|
/** @type {!Array.<!Promise>} */
|
|
1998
2000
|
const operations = [];
|
|
@@ -2190,8 +2192,19 @@ shaka.media.StreamingEngine = class {
|
|
|
2190
2192
|
throw error;
|
|
2191
2193
|
}
|
|
2192
2194
|
};
|
|
2195
|
+
let initSegmentTime = reference.startTime;
|
|
2196
|
+
if (nullLastReferences) {
|
|
2197
|
+
const bufferEnd =
|
|
2198
|
+
this.playerInterface_.mediaSourceEngine.bufferEnd(mediaState.type);
|
|
2199
|
+
if (bufferEnd != null) {
|
|
2200
|
+
// Adjust init segment appendance time if we have something in
|
|
2201
|
+
// a buffer, i.e. due to running switchVariant() with non zero
|
|
2202
|
+
// safe margin value.
|
|
2203
|
+
initSegmentTime = bufferEnd;
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2193
2206
|
this.playerInterface_.onInitSegmentAppended(
|
|
2194
|
-
|
|
2207
|
+
initSegmentTime, reference.initSegmentReference);
|
|
2195
2208
|
operations.push(append());
|
|
2196
2209
|
}
|
|
2197
2210
|
}
|
package/lib/player.js
CHANGED
|
@@ -1728,7 +1728,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1728
1728
|
this.dispatchEvent(shaka.Player.makeEvent_(
|
|
1729
1729
|
shaka.util.FakeEvent.EventName.Loaded));
|
|
1730
1730
|
} catch (error) {
|
|
1731
|
-
if (error.code != shaka.util.Error.Code.LOAD_INTERRUPTED) {
|
|
1731
|
+
if (error && error.code != shaka.util.Error.Code.LOAD_INTERRUPTED) {
|
|
1732
1732
|
await this.unload(/* initializeMediaSource= */ false);
|
|
1733
1733
|
}
|
|
1734
1734
|
throw error;
|
|
@@ -2787,8 +2787,21 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2787
2787
|
|
|
2788
2788
|
// By setting |src| we are done "loading" with src=. We don't need to set
|
|
2789
2789
|
// the current time because |playhead| will do that for us.
|
|
2790
|
-
|
|
2791
|
-
|
|
2790
|
+
let playbackUri = this.cmcdManager_.appendSrcData(this.assetUri_, mimeType);
|
|
2791
|
+
// Apply temporal clipping using playRangeStart and playRangeEnd based
|
|
2792
|
+
// in https://www.w3.org/TR/media-frags/
|
|
2793
|
+
if (!playbackUri.includes('#t=') &&
|
|
2794
|
+
(this.config_.playRangeStart > 0 ||
|
|
2795
|
+
isFinite(this.config_.playRangeEnd))) {
|
|
2796
|
+
playbackUri += '#t=';
|
|
2797
|
+
if (this.config_.playRangeStart > 0) {
|
|
2798
|
+
playbackUri += this.config_.playRangeStart;
|
|
2799
|
+
}
|
|
2800
|
+
if (isFinite(this.config_.playRangeEnd)) {
|
|
2801
|
+
playbackUri += ',' + this.config_.playRangeEnd;
|
|
2802
|
+
}
|
|
2803
|
+
}
|
|
2804
|
+
mediaElement.src = playbackUri;
|
|
2792
2805
|
|
|
2793
2806
|
// Tizen 3 / WebOS won't load anything unless you call load() explicitly,
|
|
2794
2807
|
// no matter the value of the preload attribute. This is harmful on some
|
|
@@ -6166,10 +6179,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
6166
6179
|
let updateState = 'playing';
|
|
6167
6180
|
if (this.bufferObserver_.getState() == State.STARVING) {
|
|
6168
6181
|
updateState = 'buffering';
|
|
6169
|
-
} else if (this.video_.paused) {
|
|
6170
|
-
updateState = 'paused';
|
|
6171
6182
|
} else if (this.video_.ended) {
|
|
6172
6183
|
updateState = 'ended';
|
|
6184
|
+
} else if (this.video_.paused) {
|
|
6185
|
+
updateState = 'paused';
|
|
6173
6186
|
}
|
|
6174
6187
|
const stateChanged = history.update(updateState);
|
|
6175
6188
|
|
|
@@ -7072,18 +7085,25 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
7072
7085
|
/**
|
|
7073
7086
|
* Turn the media element's error object into a Shaka Player error object.
|
|
7074
7087
|
*
|
|
7088
|
+
* @param {boolean=} printAllErrors
|
|
7075
7089
|
* @return {shaka.util.Error}
|
|
7076
7090
|
* @private
|
|
7077
7091
|
*/
|
|
7078
|
-
videoErrorToShakaError_() {
|
|
7092
|
+
videoErrorToShakaError_(printAllErrors = true) {
|
|
7079
7093
|
goog.asserts.assert(this.video_.error,
|
|
7080
7094
|
'Video error expected, but missing!');
|
|
7081
7095
|
if (!this.video_.error) {
|
|
7096
|
+
if (printAllErrors) {
|
|
7097
|
+
return new shaka.util.Error(
|
|
7098
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
7099
|
+
shaka.util.Error.Category.MEDIA,
|
|
7100
|
+
shaka.util.Error.Code.VIDEO_ERROR);
|
|
7101
|
+
}
|
|
7082
7102
|
return null;
|
|
7083
7103
|
}
|
|
7084
7104
|
|
|
7085
7105
|
const code = this.video_.error.code;
|
|
7086
|
-
if (code == 1 /* MEDIA_ERR_ABORTED */) {
|
|
7106
|
+
if (!printAllErrors && code == 1 /* MEDIA_ERR_ABORTED */) {
|
|
7087
7107
|
// Ignore this error code, which should only occur when navigating away or
|
|
7088
7108
|
// deliberately stopping playback of HTTP content.
|
|
7089
7109
|
return null;
|
|
@@ -7115,7 +7135,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
7115
7135
|
* @private
|
|
7116
7136
|
*/
|
|
7117
7137
|
onVideoError_(event) {
|
|
7118
|
-
const error = this.videoErrorToShakaError_();
|
|
7138
|
+
const error = this.videoErrorToShakaError_(/* printAllErrors= */ false);
|
|
7119
7139
|
if (!error) {
|
|
7120
7140
|
return;
|
|
7121
7141
|
}
|
|
@@ -7484,7 +7504,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
7484
7504
|
* @export
|
|
7485
7505
|
*/
|
|
7486
7506
|
// eslint-disable-next-line no-useless-concat
|
|
7487
|
-
shaka.Player.version = 'v4.9.
|
|
7507
|
+
shaka.Player.version = 'v4.9.23' + '-uncompiled'; // x-release-please-version
|
|
7488
7508
|
|
|
7489
7509
|
// Initialize the deprecation system using the version string we just set
|
|
7490
7510
|
// on the player.
|
|
@@ -58,14 +58,11 @@ shaka.polyfill.AbortController = class {
|
|
|
58
58
|
|
|
59
59
|
/**
|
|
60
60
|
* @summary A polyfill for AbortSignal, part of the AbortController API.
|
|
61
|
-
* @
|
|
61
|
+
* @extends AbortSignal
|
|
62
62
|
*/
|
|
63
|
-
shaka.polyfill.AbortController.AbortSignal =
|
|
64
|
-
class extends shaka.util.FakeEventTarget {
|
|
63
|
+
shaka.polyfill.AbortController.AbortSignal = class {
|
|
65
64
|
/** */
|
|
66
65
|
constructor() {
|
|
67
|
-
super();
|
|
68
|
-
|
|
69
66
|
/** @private {boolean} */
|
|
70
67
|
this.aborted_ = false;
|
|
71
68
|
|
|
@@ -74,6 +71,24 @@ class extends shaka.util.FakeEventTarget {
|
|
|
74
71
|
|
|
75
72
|
/** @type {?function(!Event)} */
|
|
76
73
|
this.onabort = null;
|
|
74
|
+
|
|
75
|
+
/** @private {!shaka.util.FakeEventTarget} */
|
|
76
|
+
this.eventTarget_ = new shaka.util.FakeEventTarget();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** @override */
|
|
80
|
+
addEventListener(type, listener, options) {
|
|
81
|
+
return this.eventTarget_.addEventListener(type, listener, options);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** @override */
|
|
85
|
+
removeEventListener(type, listener, options) {
|
|
86
|
+
return this.eventTarget_.removeEventListener(type, listener, options);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** @override */
|
|
90
|
+
dispatchEvent(event) {
|
|
91
|
+
return this.eventTarget_.dispatchEvent(event);
|
|
77
92
|
}
|
|
78
93
|
|
|
79
94
|
/** @override */
|
|
@@ -81,12 +96,12 @@ class extends shaka.util.FakeEventTarget {
|
|
|
81
96
|
return this.aborted_;
|
|
82
97
|
}
|
|
83
98
|
|
|
84
|
-
/** @
|
|
99
|
+
/** @override */
|
|
85
100
|
get reason() {
|
|
86
101
|
return this.reason_;
|
|
87
102
|
}
|
|
88
103
|
|
|
89
|
-
/** @
|
|
104
|
+
/** @override */
|
|
90
105
|
throwIfAborted() {
|
|
91
106
|
if (this.aborted_) {
|
|
92
107
|
throw this.reason_;
|
|
@@ -119,21 +134,14 @@ class extends shaka.util.FakeEventTarget {
|
|
|
119
134
|
this.dispatchEvent(event);
|
|
120
135
|
}
|
|
121
136
|
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* @param {*=} reason
|
|
125
|
-
* @return {!AbortSignal}
|
|
126
|
-
*/
|
|
137
|
+
/** @override */
|
|
127
138
|
static abort(reason) {
|
|
128
139
|
const signal = new shaka.polyfill.AbortController.AbortSignal();
|
|
129
140
|
signal.doAbort_(reason);
|
|
130
141
|
return signal;
|
|
131
142
|
}
|
|
132
143
|
|
|
133
|
-
/**
|
|
134
|
-
* @param {number} timeMs
|
|
135
|
-
* @return {!AbortSignal}
|
|
136
|
-
*/
|
|
144
|
+
/** @override */
|
|
137
145
|
static timeout(timeMs) {
|
|
138
146
|
const signal = new shaka.polyfill.AbortController.AbortSignal();
|
|
139
147
|
|
|
@@ -842,7 +842,7 @@ shaka.text.UITextDisplayer = class {
|
|
|
842
842
|
if (cue.position !== null) {
|
|
843
843
|
style.position = 'absolute';
|
|
844
844
|
if (cue.writingMode == Cue.writingMode.HORIZONTAL_TOP_TO_BOTTOM) {
|
|
845
|
-
style.right = cue.position + '%';
|
|
845
|
+
style.right = (100 - cue.position) + '%';
|
|
846
846
|
style.width = 'auto';
|
|
847
847
|
} else {
|
|
848
848
|
style.bottom = cue.position + '%';
|
package/lib/util/stream_utils.js
CHANGED
|
@@ -1382,6 +1382,13 @@ shaka.util.StreamUtils = class {
|
|
|
1382
1382
|
track.hdr = video.hdr || null;
|
|
1383
1383
|
track.colorGamut = video.colorGamut || null;
|
|
1384
1384
|
track.videoLayout = video.videoLayout || null;
|
|
1385
|
+
|
|
1386
|
+
if (videoCodec.includes(',')) {
|
|
1387
|
+
track.channelsCount = video.channelsCount;
|
|
1388
|
+
track.audioSamplingRate = video.audioSamplingRate;
|
|
1389
|
+
track.spatialAudio = video.spatialAudio;
|
|
1390
|
+
track.originalLanguage = video.originalLanguage;
|
|
1391
|
+
}
|
|
1385
1392
|
}
|
|
1386
1393
|
|
|
1387
1394
|
if (audio) {
|
package/lib/util/tXml.js
CHANGED
|
@@ -753,11 +753,18 @@ shaka.util.TXml = class {
|
|
|
753
753
|
// We only want the id attribute in which case
|
|
754
754
|
// /'(.*?)'/ will suffice to get it.
|
|
755
755
|
const idAttr = path.match(/(@id='(.*?)')/);
|
|
756
|
+
const tAttr = path.match(/(@t='(\d+)')/);
|
|
757
|
+
const numberIndex = path.match(/(@n='(\d+)')/);
|
|
756
758
|
const position = path.match(/\[(\d+)\]/);
|
|
757
759
|
returnPaths.push({
|
|
758
760
|
name: nodeName[0],
|
|
759
761
|
id: idAttr ?
|
|
760
762
|
idAttr[0].match(/'(.*?)'/)[0].replace(/'/gm, '') : null,
|
|
763
|
+
t: tAttr ?
|
|
764
|
+
Number(tAttr[0].match(/'(.*?)'/)[0].replace(/'/gm, '')) : null,
|
|
765
|
+
n: numberIndex ?
|
|
766
|
+
Number(numberIndex[0].match(/'(.*?)'/)[0].replace(/'/gm, '')):
|
|
767
|
+
null,
|
|
761
768
|
// position is counted from 1, so make it readable for devs
|
|
762
769
|
position: position ? Number(position[1]) - 1 : null,
|
|
763
770
|
attribute: path.split('/@')[1] || null,
|
|
@@ -787,6 +794,14 @@ shaka.util.TXml = class {
|
|
|
787
794
|
const position = patchNode.attributes['pos'] || null;
|
|
788
795
|
|
|
789
796
|
let index = lastNode.position;
|
|
797
|
+
if (index == null) {
|
|
798
|
+
if (lastNode.t !== null) {
|
|
799
|
+
index = TXml.nodePositionByAttribute_(nodes, 't', lastNode.t);
|
|
800
|
+
}
|
|
801
|
+
if (lastNode.n !== null) {
|
|
802
|
+
index = TXml.nodePositionByAttribute_(nodes, 'n', lastNode.n);
|
|
803
|
+
}
|
|
804
|
+
}
|
|
790
805
|
if (index === null) {
|
|
791
806
|
index = position === 'prepend' ? 0 : nodes.length;
|
|
792
807
|
} else if (position === 'prepend') {
|
|
@@ -798,7 +813,7 @@ shaka.util.TXml = class {
|
|
|
798
813
|
const attribute = lastNode.attribute;
|
|
799
814
|
|
|
800
815
|
// Modify attribute
|
|
801
|
-
if (attribute) {
|
|
816
|
+
if (attribute && nodes[index]) {
|
|
802
817
|
TXml.modifyNodeAttribute(nodes[index], action, attribute,
|
|
803
818
|
TXml.getContents(patchNode) || '');
|
|
804
819
|
// Rearrange nodes
|
|
@@ -814,6 +829,28 @@ shaka.util.TXml = class {
|
|
|
814
829
|
}
|
|
815
830
|
|
|
816
831
|
|
|
832
|
+
/**
|
|
833
|
+
* Search the node index by the t attribute
|
|
834
|
+
* and return the index. if not found return null
|
|
835
|
+
* @param {!Array<shaka.extern.xml.Node>} nodes
|
|
836
|
+
* @param {!string} attribute
|
|
837
|
+
* @param {!number} value
|
|
838
|
+
* @private
|
|
839
|
+
*/
|
|
840
|
+
static nodePositionByAttribute_(nodes, attribute, value) {
|
|
841
|
+
let index = 0;
|
|
842
|
+
for (const node of nodes) {
|
|
843
|
+
const attrs = node.attributes;
|
|
844
|
+
const val = Number(attrs[attribute]);
|
|
845
|
+
if (val === value) {
|
|
846
|
+
return index;
|
|
847
|
+
}
|
|
848
|
+
index++;
|
|
849
|
+
}
|
|
850
|
+
return null;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
|
|
817
854
|
/**
|
|
818
855
|
* @param {!shaka.extern.xml.Node} node
|
|
819
856
|
* @param {string} action
|
|
@@ -875,6 +912,8 @@ shaka.util.TXml.knownNameSpaces_ = new Map([]);
|
|
|
875
912
|
* @typedef {{
|
|
876
913
|
* name: string,
|
|
877
914
|
* id: ?string,
|
|
915
|
+
* t: ?number,
|
|
916
|
+
* n: ?number,
|
|
878
917
|
* position: ?number,
|
|
879
918
|
* attribute: ?string
|
|
880
919
|
* }}
|
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.23",
|
|
5
5
|
"homepage": "https://github.com/shaka-project/shaka-player",
|
|
6
6
|
"author": "Google",
|
|
7
7
|
"maintainers": [
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
"eslint-plugin-shaka-rules": "file:./build/eslint-plugin-shaka-rules",
|
|
32
32
|
"esprima": "^4.0.1",
|
|
33
33
|
"fontfaceonload": "^1.0.2",
|
|
34
|
-
"google-closure-compiler-java": "^
|
|
35
|
-
"google-closure-deps": "^
|
|
34
|
+
"google-closure-compiler-java": "^20240317.0.0",
|
|
35
|
+
"google-closure-deps": "^20230802.0.0",
|
|
36
36
|
"google-closure-library": "^20221102.0.0",
|
|
37
37
|
"htmlhint": "^1.1.3",
|
|
38
38
|
"jasmine-ajax": "^4.0.0",
|
package/ui/presentation_time.js
CHANGED
|
@@ -83,7 +83,10 @@ shaka.ui.PresentationTimeTracker = class extends shaka.ui.Element {
|
|
|
83
83
|
const seekRangeSize = seekRange.end - seekRange.start;
|
|
84
84
|
const Utils = shaka.ui.Utils;
|
|
85
85
|
|
|
86
|
-
if (
|
|
86
|
+
if (!isFinite(seekRangeSize)) {
|
|
87
|
+
this.setValue_(this.localization.resolve(shaka.ui.Locales.Ids.LIVE));
|
|
88
|
+
this.currentTime_.disabled = true;
|
|
89
|
+
} else if (this.player.isLive()) {
|
|
87
90
|
// The amount of time we are behind the live edge.
|
|
88
91
|
const behindLive = Math.floor(seekRange.end - displayTime);
|
|
89
92
|
displayTime = Math.max(0, behindLive);
|
|
@@ -259,9 +259,17 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.SettingsMenu {
|
|
|
259
259
|
if (height == 2160) {
|
|
260
260
|
text = '4K';
|
|
261
261
|
}
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
262
|
+
const frameRates = new Set();
|
|
263
|
+
for (const item of tracks) {
|
|
264
|
+
if (item.frameRate) {
|
|
265
|
+
frameRates.add(Math.round(item.frameRate));
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
if (frameRates.size > 1) {
|
|
269
|
+
const frameRate = track.frameRate;
|
|
270
|
+
if (frameRate && (frameRate >= 50 || frameRate <= 20)) {
|
|
271
|
+
text += Math.round(track.frameRate);
|
|
272
|
+
}
|
|
265
273
|
}
|
|
266
274
|
if (track.hdr == 'PQ' || track.hdr == 'HLG') {
|
|
267
275
|
text += ' (HDR)';
|
package/ui/seek_bar.js
CHANGED
|
@@ -470,7 +470,8 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement {
|
|
|
470
470
|
const seekRangeSize = seekRange.end - seekRange.start;
|
|
471
471
|
|
|
472
472
|
if (this.player.isLive() &&
|
|
473
|
-
seekRangeSize < shaka.ui.Constants.MIN_SEEK_WINDOW_TO_SHOW_SEEKBAR
|
|
473
|
+
(seekRangeSize < shaka.ui.Constants.MIN_SEEK_WINDOW_TO_SHOW_SEEKBAR ||
|
|
474
|
+
!isFinite(seekRangeSize))) {
|
|
474
475
|
return false;
|
|
475
476
|
}
|
|
476
477
|
|