shaka-player 4.10.12 → 4.10.13
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 +38 -38
- package/dist/shaka-player.compiled.d.ts +1 -1
- package/dist/shaka-player.compiled.debug.d.ts +1 -1
- package/dist/shaka-player.compiled.debug.externs.js +2 -1
- package/dist/shaka-player.compiled.debug.js +262 -259
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.externs.js +2 -1
- package/dist/shaka-player.compiled.js +1168 -1166
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.d.ts +1 -1
- package/dist/shaka-player.ui.debug.d.ts +1 -1
- package/dist/shaka-player.ui.debug.externs.js +2 -1
- package/dist/shaka-player.ui.debug.js +63 -60
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.externs.js +2 -1
- package/dist/shaka-player.ui.js +1388 -1386
- package/dist/shaka-player.ui.map +3 -3
- package/lib/dash/dash_parser.js +83 -48
- package/lib/media/streaming_engine.js +55 -6
- package/lib/player.js +24 -8
- package/lib/util/periods.js +16 -9
- package/lib/util/tXml.js +58 -7
- package/package.json +1 -1
package/lib/dash/dash_parser.js
CHANGED
|
@@ -30,6 +30,7 @@ goog.require('shaka.util.LanguageUtils');
|
|
|
30
30
|
goog.require('shaka.util.ManifestParserUtils');
|
|
31
31
|
goog.require('shaka.util.MimeUtils');
|
|
32
32
|
goog.require('shaka.util.Networking');
|
|
33
|
+
goog.require('shaka.util.ObjectUtils');
|
|
33
34
|
goog.require('shaka.util.OperationManager');
|
|
34
35
|
goog.require('shaka.util.PeriodCombiner');
|
|
35
36
|
goog.require('shaka.util.PlayerConfiguration');
|
|
@@ -93,12 +94,19 @@ shaka.dash.DashParser = class {
|
|
|
93
94
|
|
|
94
95
|
/**
|
|
95
96
|
* A map of IDs to Stream objects.
|
|
96
|
-
* ID: Period@id,
|
|
97
|
-
* e.g.: '1,
|
|
97
|
+
* ID: Period@id,Representation@id
|
|
98
|
+
* e.g.: '1,23'
|
|
98
99
|
* @private {!Object.<string, !shaka.extern.Stream>}
|
|
99
100
|
*/
|
|
100
101
|
this.streamMap_ = {};
|
|
101
102
|
|
|
103
|
+
/**
|
|
104
|
+
* A map of Period IDs to Stream Map IDs.
|
|
105
|
+
* Use to have direct access to streamMap key.
|
|
106
|
+
* @private {!Object.<string, !Array<string>>}
|
|
107
|
+
*/
|
|
108
|
+
this.indexStreamMap_ = {};
|
|
109
|
+
|
|
102
110
|
/**
|
|
103
111
|
* A map of period ids to their durations
|
|
104
112
|
* @private {!Object.<string, number>}
|
|
@@ -256,6 +264,7 @@ shaka.dash.DashParser = class {
|
|
|
256
264
|
this.manifestUris_ = [];
|
|
257
265
|
this.manifest_ = null;
|
|
258
266
|
this.streamMap_ = {};
|
|
267
|
+
this.indexStreamMap_ = {};
|
|
259
268
|
this.contextCache_.clear();
|
|
260
269
|
this.manifestPatchContext_ = {
|
|
261
270
|
mpdId: '',
|
|
@@ -653,7 +662,7 @@ shaka.dash.DashParser = class {
|
|
|
653
662
|
}
|
|
654
663
|
|
|
655
664
|
this.manifestPatchContext_.type = mpdType;
|
|
656
|
-
|
|
665
|
+
this.cleanStreamMap_();
|
|
657
666
|
/** @type {!shaka.media.PresentationTimeline} */
|
|
658
667
|
let presentationTimeline;
|
|
659
668
|
if (this.manifest_) {
|
|
@@ -734,7 +743,8 @@ shaka.dash.DashParser = class {
|
|
|
734
743
|
};
|
|
735
744
|
|
|
736
745
|
this.gapCount_ = 0;
|
|
737
|
-
const periodsAndDuration = this.parsePeriods_(
|
|
746
|
+
const periodsAndDuration = this.parsePeriods_(
|
|
747
|
+
context, getBaseUris, mpd, /* newPeriod= */ false);
|
|
738
748
|
const duration = periodsAndDuration.duration;
|
|
739
749
|
const periods = periodsAndDuration.periods;
|
|
740
750
|
|
|
@@ -1013,7 +1023,7 @@ shaka.dash.DashParser = class {
|
|
|
1013
1023
|
};
|
|
1014
1024
|
|
|
1015
1025
|
const periodsAndDuration = this.parsePeriods_(context,
|
|
1016
|
-
this.manifestPatchContext_.getBaseUris, periods);
|
|
1026
|
+
this.manifestPatchContext_.getBaseUris, periods, /* newPeriod= */ true);
|
|
1017
1027
|
|
|
1018
1028
|
return periodsAndDuration.periods;
|
|
1019
1029
|
}
|
|
@@ -1033,6 +1043,10 @@ shaka.dash.DashParser = class {
|
|
|
1033
1043
|
this.contextCache_.delete(contextId);
|
|
1034
1044
|
}
|
|
1035
1045
|
}
|
|
1046
|
+
const newPeriods = this.lastManifestUpdatePeriodIds_.filter((pID) => {
|
|
1047
|
+
return pID !== periodId;
|
|
1048
|
+
});
|
|
1049
|
+
this.lastManifestUpdatePeriodIds_ = newPeriods;
|
|
1036
1050
|
}
|
|
1037
1051
|
|
|
1038
1052
|
/**
|
|
@@ -1274,6 +1288,7 @@ shaka.dash.DashParser = class {
|
|
|
1274
1288
|
* @param {shaka.dash.DashParser.Context} context
|
|
1275
1289
|
* @param {function():!Array.<string>} getBaseUris
|
|
1276
1290
|
* @param {!shaka.extern.xml.Node} mpd
|
|
1291
|
+
* @param {!boolean} newPeriod
|
|
1277
1292
|
* @return {{
|
|
1278
1293
|
* periods: !Array.<shaka.extern.Period>,
|
|
1279
1294
|
* duration: ?number,
|
|
@@ -1281,7 +1296,7 @@ shaka.dash.DashParser = class {
|
|
|
1281
1296
|
* }}
|
|
1282
1297
|
* @private
|
|
1283
1298
|
*/
|
|
1284
|
-
parsePeriods_(context, getBaseUris, mpd) {
|
|
1299
|
+
parsePeriods_(context, getBaseUris, mpd, newPeriod) {
|
|
1285
1300
|
const TXml = shaka.util.TXml;
|
|
1286
1301
|
let presentationDuration = context.mediaPresentationDuration;
|
|
1287
1302
|
|
|
@@ -1413,8 +1428,18 @@ shaka.dash.DashParser = class {
|
|
|
1413
1428
|
prevEnd = start + periodDuration;
|
|
1414
1429
|
} // end of period parsing loop
|
|
1415
1430
|
|
|
1416
|
-
|
|
1417
|
-
|
|
1431
|
+
if (newPeriod) {
|
|
1432
|
+
// append new period from the patch manifest
|
|
1433
|
+
for (const el of periods) {
|
|
1434
|
+
const periodID = el.id;
|
|
1435
|
+
if (!this.lastManifestUpdatePeriodIds_.includes(periodID)) {
|
|
1436
|
+
this.lastManifestUpdatePeriodIds_.push(periodID);
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
} else {
|
|
1440
|
+
// Replace previous seen periods with the current one.
|
|
1441
|
+
this.lastManifestUpdatePeriodIds_ = periods.map((el) => el.id);
|
|
1442
|
+
}
|
|
1418
1443
|
|
|
1419
1444
|
if (presentationDuration != null) {
|
|
1420
1445
|
if (prevEnd != null) {
|
|
@@ -1442,6 +1467,26 @@ shaka.dash.DashParser = class {
|
|
|
1442
1467
|
}
|
|
1443
1468
|
}
|
|
1444
1469
|
|
|
1470
|
+
/**
|
|
1471
|
+
* Clean StreamMap Object to remove reference of deleted Stream Object
|
|
1472
|
+
* @private
|
|
1473
|
+
*/
|
|
1474
|
+
cleanStreamMap_() {
|
|
1475
|
+
const oldPeriodIds = Object.keys(this.indexStreamMap_);
|
|
1476
|
+
if (oldPeriodIds.length === this.lastManifestUpdatePeriodIds_.length) {
|
|
1477
|
+
return;
|
|
1478
|
+
}
|
|
1479
|
+
const diffPeriodsIDs = oldPeriodIds.filter((pId) => {
|
|
1480
|
+
return !this.lastManifestUpdatePeriodIds_.includes(pId);
|
|
1481
|
+
});
|
|
1482
|
+
for (const pId of diffPeriodsIDs) {
|
|
1483
|
+
for (const contextId of this.indexStreamMap_[pId]) {
|
|
1484
|
+
delete this.streamMap_[contextId];
|
|
1485
|
+
}
|
|
1486
|
+
delete this.indexStreamMap_[pId];
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1445
1490
|
/**
|
|
1446
1491
|
* Parses a Period XML element. Unlike the other parse methods, this is not
|
|
1447
1492
|
* given the Node; it is given a PeriodInfo structure. Also, partial parsing
|
|
@@ -1458,6 +1503,7 @@ shaka.dash.DashParser = class {
|
|
|
1458
1503
|
const TXml = shaka.util.TXml;
|
|
1459
1504
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
1460
1505
|
|
|
1506
|
+
goog.asserts.assert(periodInfo.node, 'periodInfo.node should exist');
|
|
1461
1507
|
context.period = this.createFrame_(periodInfo.node, null, getBaseUris);
|
|
1462
1508
|
context.periodInfo = periodInfo;
|
|
1463
1509
|
context.period.availabilityTimeOffset = context.availabilityTimeOffset;
|
|
@@ -2221,7 +2267,12 @@ shaka.dash.DashParser = class {
|
|
|
2221
2267
|
};
|
|
2222
2268
|
|
|
2223
2269
|
if (contextId && context.dynamic && !this.streamMap_[contextId]) {
|
|
2270
|
+
const periodId = context.period.id || '';
|
|
2271
|
+
if (!this.indexStreamMap_[periodId]) {
|
|
2272
|
+
this.indexStreamMap_[periodId] = [];
|
|
2273
|
+
}
|
|
2224
2274
|
this.streamMap_[contextId] = stream;
|
|
2275
|
+
this.indexStreamMap_[periodId].push(contextId);
|
|
2225
2276
|
}
|
|
2226
2277
|
|
|
2227
2278
|
return stream;
|
|
@@ -2235,45 +2286,29 @@ shaka.dash.DashParser = class {
|
|
|
2235
2286
|
* @private
|
|
2236
2287
|
*/
|
|
2237
2288
|
cloneContext_(context) {
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
segmentBase: null,
|
|
2246
|
-
segmentList: null,
|
|
2247
|
-
segmentTemplate: frameRef.segmentTemplate,
|
|
2248
|
-
getBaseUris: frameRef.getBaseUris,
|
|
2249
|
-
width: frameRef.width,
|
|
2250
|
-
height: frameRef.height,
|
|
2251
|
-
contentType: frameRef.contentType,
|
|
2252
|
-
mimeType: frameRef.mimeType,
|
|
2253
|
-
language: frameRef.language,
|
|
2254
|
-
codecs: frameRef.codecs,
|
|
2255
|
-
frameRate: frameRef.frameRate,
|
|
2256
|
-
pixelAspectRatio: frameRef.pixelAspectRatio,
|
|
2257
|
-
emsgSchemeIdUris: frameRef.emsgSchemeIdUris,
|
|
2258
|
-
id: frameRef.id,
|
|
2259
|
-
position: frameRef.position,
|
|
2260
|
-
numChannels: frameRef.numChannels,
|
|
2261
|
-
audioSamplingRate: frameRef.audioSamplingRate,
|
|
2262
|
-
availabilityTimeOffset: frameRef.availabilityTimeOffset,
|
|
2263
|
-
initialization: frameRef.initialization,
|
|
2264
|
-
};
|
|
2265
|
-
} else if (k == 'periodInfo') {
|
|
2266
|
-
/** @type {shaka.dash.DashParser.PeriodInfo} */
|
|
2267
|
-
const frameRef = context[k];
|
|
2268
|
-
contextClone[k] = {
|
|
2269
|
-
start: frameRef.start,
|
|
2270
|
-
duration: frameRef.duration,
|
|
2271
|
-
node: null,
|
|
2272
|
-
isLastPeriod: frameRef.isLastPeriod,
|
|
2273
|
-
};
|
|
2274
|
-
} else {
|
|
2275
|
-
contextClone[k] = context[k];
|
|
2289
|
+
/**
|
|
2290
|
+
* @param {?shaka.dash.DashParser.InheritanceFrame} frame
|
|
2291
|
+
* @return {?shaka.dash.DashParser.InheritanceFrame}
|
|
2292
|
+
*/
|
|
2293
|
+
const cloneFrame = (frame) => {
|
|
2294
|
+
if (!frame) {
|
|
2295
|
+
return null;
|
|
2276
2296
|
}
|
|
2297
|
+
const clone = shaka.util.ObjectUtils.shallowCloneObject(frame);
|
|
2298
|
+
clone.segmentBase = null;
|
|
2299
|
+
clone.segmentList = null;
|
|
2300
|
+
clone.segmentTemplate = shaka.util.TXml.cloneNode(clone.segmentTemplate);
|
|
2301
|
+
return clone;
|
|
2302
|
+
};
|
|
2303
|
+
const contextClone = shaka.util.ObjectUtils.shallowCloneObject(context);
|
|
2304
|
+
contextClone.period = cloneFrame(contextClone.period);
|
|
2305
|
+
contextClone.adaptationSet = cloneFrame(contextClone.adaptationSet);
|
|
2306
|
+
contextClone.representation = cloneFrame(contextClone.representation);
|
|
2307
|
+
|
|
2308
|
+
if (contextClone.periodInfo) {
|
|
2309
|
+
contextClone.periodInfo =
|
|
2310
|
+
shaka.util.ObjectUtils.shallowCloneObject(contextClone.periodInfo);
|
|
2311
|
+
contextClone.periodInfo.node = null;
|
|
2277
2312
|
}
|
|
2278
2313
|
|
|
2279
2314
|
return contextClone;
|
|
@@ -3137,7 +3172,7 @@ shaka.dash.DashParser.Context;
|
|
|
3137
3172
|
* @typedef {{
|
|
3138
3173
|
* start: number,
|
|
3139
3174
|
* duration: ?number,
|
|
3140
|
-
* node:
|
|
3175
|
+
* node: ?shaka.extern.xml.Node,
|
|
3141
3176
|
* isLastPeriod: boolean
|
|
3142
3177
|
* }}
|
|
3143
3178
|
*
|
|
@@ -3149,7 +3184,7 @@ shaka.dash.DashParser.Context;
|
|
|
3149
3184
|
* @property {?number} duration
|
|
3150
3185
|
* The duration of the period; or null if the duration is not given. This
|
|
3151
3186
|
* will be non-null for all periods except the last.
|
|
3152
|
-
* @property {
|
|
3187
|
+
* @property {?shaka.extern.xml.Node} node
|
|
3153
3188
|
* The XML Node for the Period.
|
|
3154
3189
|
* @property {boolean} isLastPeriod
|
|
3155
3190
|
* Whether this Period is the last one in the manifest.
|
|
@@ -73,6 +73,13 @@ shaka.media.StreamingEngine = class {
|
|
|
73
73
|
/** @private {?shaka.extern.StreamingConfiguration} */
|
|
74
74
|
this.config_ = null;
|
|
75
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Retains a reference to the function used to close SegmentIndex objects
|
|
78
|
+
* for streams which were switched away from during an ongoing update_().
|
|
79
|
+
* @private {!Map.<string, !function()>}
|
|
80
|
+
*/
|
|
81
|
+
this.deferredCloseSegmentIndex_ = new Map();
|
|
82
|
+
|
|
76
83
|
/** @private {number} */
|
|
77
84
|
this.bufferingGoalScale_ = 1;
|
|
78
85
|
|
|
@@ -504,6 +511,24 @@ shaka.media.StreamingEngine = class {
|
|
|
504
511
|
}
|
|
505
512
|
|
|
506
513
|
|
|
514
|
+
/**
|
|
515
|
+
* Handles deferred releases of old SegmentIndexes for the mediaState's
|
|
516
|
+
* content type from a previous update.
|
|
517
|
+
* @param {!shaka.media.StreamingEngine.MediaState_} mediaState
|
|
518
|
+
* @private
|
|
519
|
+
*/
|
|
520
|
+
handleDeferredCloseSegmentIndexes_(mediaState) {
|
|
521
|
+
for (const [key, value] of this.deferredCloseSegmentIndex_.entries()) {
|
|
522
|
+
const streamId = /** @type {string} */ (key);
|
|
523
|
+
const closeSegmentIndex = /** @type {!function()} */ (value);
|
|
524
|
+
if (streamId.includes(mediaState.type)) {
|
|
525
|
+
closeSegmentIndex();
|
|
526
|
+
this.deferredCloseSegmentIndex_.delete(streamId);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
|
|
507
532
|
/**
|
|
508
533
|
* Switches to the given Stream. |stream| may be from any Variant.
|
|
509
534
|
*
|
|
@@ -576,7 +601,23 @@ shaka.media.StreamingEngine = class {
|
|
|
576
601
|
// Do not close segment indexes we are prefetching.
|
|
577
602
|
if (!this.audioPrefetchMap_.has(mediaState.stream)) {
|
|
578
603
|
if (mediaState.stream.closeSegmentIndex) {
|
|
579
|
-
mediaState.
|
|
604
|
+
if (mediaState.performingUpdate) {
|
|
605
|
+
const oldStreamTag =
|
|
606
|
+
shaka.media.StreamingEngine.logPrefix_(mediaState);
|
|
607
|
+
if (!this.deferredCloseSegmentIndex_.has(oldStreamTag)) {
|
|
608
|
+
// The ongoing update is still using the old stream's segment
|
|
609
|
+
// reference information.
|
|
610
|
+
// If we close the old stream now, the update will not complete
|
|
611
|
+
// correctly.
|
|
612
|
+
// The next onUpdate_() for this content type will resume the
|
|
613
|
+
// closeSegmentIndex() operation for the old stream once the ongoing
|
|
614
|
+
// update has finished, then immediately create a new segment index.
|
|
615
|
+
this.deferredCloseSegmentIndex_.set(
|
|
616
|
+
oldStreamTag, mediaState.stream.closeSegmentIndex);
|
|
617
|
+
}
|
|
618
|
+
} else {
|
|
619
|
+
mediaState.stream.closeSegmentIndex();
|
|
620
|
+
}
|
|
580
621
|
}
|
|
581
622
|
}
|
|
582
623
|
|
|
@@ -1169,6 +1210,13 @@ shaka.media.StreamingEngine = class {
|
|
|
1169
1210
|
return;
|
|
1170
1211
|
}
|
|
1171
1212
|
|
|
1213
|
+
// If stream switches happened during the previous update_() for this
|
|
1214
|
+
// content type, close out the old streams that were switched away from.
|
|
1215
|
+
// Even if we had switched away from the active stream 'A' during the
|
|
1216
|
+
// update_(), e.g. (A -> B -> A), closing 'A' is permissible here since we
|
|
1217
|
+
// will immediately re-create it in the logic below.
|
|
1218
|
+
this.handleDeferredCloseSegmentIndexes_(mediaState);
|
|
1219
|
+
|
|
1172
1220
|
// Make sure the segment index exists. If not, create the segment index.
|
|
1173
1221
|
if (!mediaState.stream.segmentIndex) {
|
|
1174
1222
|
const thisStream = mediaState.stream;
|
|
@@ -1455,14 +1503,11 @@ shaka.media.StreamingEngine = class {
|
|
|
1455
1503
|
mediaState.stream.segmentIndex,
|
|
1456
1504
|
'segment index should have been generated already');
|
|
1457
1505
|
|
|
1458
|
-
|
|
1459
|
-
mediaState.segmentIterator.current() : null;
|
|
1460
|
-
|
|
1461
|
-
if (currentSegment) {
|
|
1506
|
+
if (mediaState.segmentIterator) {
|
|
1462
1507
|
// Something is buffered from the same Stream. Use the current position
|
|
1463
1508
|
// in the segment index. This is updated via next() after each segment is
|
|
1464
1509
|
// appended.
|
|
1465
|
-
return
|
|
1510
|
+
return mediaState.segmentIterator.current();
|
|
1466
1511
|
} else if (mediaState.lastSegmentReference || bufferEnd) {
|
|
1467
1512
|
// Something is buffered from another Stream.
|
|
1468
1513
|
const time = mediaState.lastSegmentReference ?
|
|
@@ -2755,6 +2800,10 @@ shaka.media.StreamingEngine = class {
|
|
|
2755
2800
|
this.destroyer_.ensureNotDestroyed();
|
|
2756
2801
|
// Try to recover from network errors
|
|
2757
2802
|
if (error.category === shaka.util.Error.Category.NETWORK) {
|
|
2803
|
+
if (mediaState.restoreStreamAfterTrickPlay) {
|
|
2804
|
+
this.setTrickPlay(/* on= */ false);
|
|
2805
|
+
return;
|
|
2806
|
+
}
|
|
2758
2807
|
const maxDisabledTime = this.getDisabledTime_(error);
|
|
2759
2808
|
error.handled = this.playerInterface_.disableStream(
|
|
2760
2809
|
mediaState.stream, maxDisabledTime);
|
package/lib/player.js
CHANGED
|
@@ -4454,9 +4454,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4454
4454
|
* beginning or end of the seekable range for the content.
|
|
4455
4455
|
*
|
|
4456
4456
|
* @param {number} rate
|
|
4457
|
+
* @param {boolean=} useTrickPlayTrack
|
|
4457
4458
|
* @export
|
|
4458
4459
|
*/
|
|
4459
|
-
trickPlay(rate) {
|
|
4460
|
+
trickPlay(rate, useTrickPlayTrack = true) {
|
|
4460
4461
|
// A playbackRate of 0 is used internally when we are in a buffering state,
|
|
4461
4462
|
// and doesn't make sense for trick play. If you set a rate of 0 for trick
|
|
4462
4463
|
// play, we will reject it and issue a warning. If it happens during a
|
|
@@ -4478,7 +4479,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4478
4479
|
|
|
4479
4480
|
if (this.loadMode_ == shaka.Player.LoadMode.MEDIA_SOURCE) {
|
|
4480
4481
|
this.abrManager_.playbackRateChanged(rate);
|
|
4481
|
-
this.streamingEngine_.setTrickPlay(
|
|
4482
|
+
this.streamingEngine_.setTrickPlay(
|
|
4483
|
+
useTrickPlayTrack && Math.abs(rate) > 1);
|
|
4482
4484
|
}
|
|
4483
4485
|
if (this.isLive()) {
|
|
4484
4486
|
this.trickPlayEventManager_.listen(this.video_, 'timeupdate', () => {
|
|
@@ -5561,6 +5563,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5561
5563
|
}
|
|
5562
5564
|
|
|
5563
5565
|
if (this.loadMode_ == shaka.Player.LoadMode.SRC_EQUALS) {
|
|
5566
|
+
this.stats_.addBytesDownloaded(NaN);
|
|
5564
5567
|
this.stats_.setResolution(
|
|
5565
5568
|
/* width= */ element.videoWidth || NaN,
|
|
5566
5569
|
/* height= */ element.videoHeight || NaN);
|
|
@@ -6502,7 +6505,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
6502
6505
|
shaka.log.debug('Buffer fullness ratio (' + bufferFullness + ') ' +
|
|
6503
6506
|
'is less than the vodDynamicPlaybackRateBufferRatio (' +
|
|
6504
6507
|
bufferThreshold + '). Updating playbackRate to ' + minPlaybackRate);
|
|
6505
|
-
this.trickPlay(minPlaybackRate);
|
|
6508
|
+
this.trickPlay(minPlaybackRate, /* useTrickPlayTrack= */ false);
|
|
6506
6509
|
}
|
|
6507
6510
|
} else if (bufferFullness == 1) {
|
|
6508
6511
|
if (playbackRate !== this.playRateController_.getDefaultRate()) {
|
|
@@ -6629,7 +6632,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
6629
6632
|
timeSinceLastRebuffer + 's) ' +
|
|
6630
6633
|
'is less than the live sync panicThreshold (' + panicThreshold +
|
|
6631
6634
|
's). Updating playbackRate to ' + minPlaybackRate);
|
|
6632
|
-
this.trickPlay(minPlaybackRate);
|
|
6635
|
+
this.trickPlay(minPlaybackRate, /* useTrickPlayTrack= */ false);
|
|
6633
6636
|
}
|
|
6634
6637
|
} else if (maxLatency && maxPlaybackRate &&
|
|
6635
6638
|
(latency - offset) > maxLatency) {
|
|
@@ -6637,7 +6640,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
6637
6640
|
shaka.log.debug('Latency (' + latency + 's) is greater than ' +
|
|
6638
6641
|
'live sync maxLatency (' + maxLatency + 's). ' +
|
|
6639
6642
|
'Updating playbackRate to ' + maxPlaybackRate);
|
|
6640
|
-
this.trickPlay(maxPlaybackRate);
|
|
6643
|
+
this.trickPlay(maxPlaybackRate, /* useTrickPlayTrack= */ false);
|
|
6641
6644
|
}
|
|
6642
6645
|
this.targetLatencyReached_ = null;
|
|
6643
6646
|
} else if (minLatency && minPlaybackRate &&
|
|
@@ -6646,7 +6649,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
6646
6649
|
shaka.log.debug('Latency (' + latency + 's) is smaller than ' +
|
|
6647
6650
|
'live sync minLatency (' + minLatency + 's). ' +
|
|
6648
6651
|
'Updating playbackRate to ' + minPlaybackRate);
|
|
6649
|
-
this.trickPlay(minPlaybackRate);
|
|
6652
|
+
this.trickPlay(minPlaybackRate, /* useTrickPlayTrack= */ false);
|
|
6650
6653
|
}
|
|
6651
6654
|
this.targetLatencyReached_ = null;
|
|
6652
6655
|
} else if (playbackRate !== this.playRateController_.getDefaultRate()) {
|
|
@@ -7257,19 +7260,32 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
7257
7260
|
if (hasAltStream) {
|
|
7258
7261
|
let didDisableStream = false;
|
|
7259
7262
|
|
|
7263
|
+
let isTrickModeVideo = false;
|
|
7264
|
+
|
|
7260
7265
|
for (const variant of this.manifest_.variants) {
|
|
7261
7266
|
const candidate = variant[stream.type];
|
|
7262
7267
|
|
|
7263
|
-
if (candidate
|
|
7268
|
+
if (!candidate) {
|
|
7269
|
+
continue;
|
|
7270
|
+
}
|
|
7271
|
+
|
|
7272
|
+
if (candidate.id === stream.id) {
|
|
7264
7273
|
variant.disabledUntilTime = (Date.now() / 1000) + disableTime;
|
|
7265
7274
|
didDisableStream = true;
|
|
7266
7275
|
|
|
7267
7276
|
shaka.log.v2(
|
|
7268
7277
|
'Disabled stream ' + stream.type + ':' + stream.id +
|
|
7269
7278
|
' for ' + disableTime + ' seconds...');
|
|
7279
|
+
} else if (candidate.trickModeVideo &&
|
|
7280
|
+
candidate.trickModeVideo.id == stream.id) {
|
|
7281
|
+
isTrickModeVideo = true;
|
|
7270
7282
|
}
|
|
7271
7283
|
}
|
|
7272
7284
|
|
|
7285
|
+
if (!didDisableStream && isTrickModeVideo) {
|
|
7286
|
+
return false;
|
|
7287
|
+
}
|
|
7288
|
+
|
|
7273
7289
|
goog.asserts.assert(didDisableStream, 'Must have disabled stream');
|
|
7274
7290
|
|
|
7275
7291
|
this.checkVariantsTimer_.tickEvery(1);
|
|
@@ -7832,7 +7848,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
7832
7848
|
* @export
|
|
7833
7849
|
*/
|
|
7834
7850
|
// eslint-disable-next-line no-useless-concat
|
|
7835
|
-
shaka.Player.version = 'v4.10.
|
|
7851
|
+
shaka.Player.version = 'v4.10.13' + '-uncompiled'; // x-release-please-version
|
|
7836
7852
|
|
|
7837
7853
|
// Initialize the deprecation system using the version string we just set
|
|
7838
7854
|
// on the player.
|
package/lib/util/periods.js
CHANGED
|
@@ -890,26 +890,33 @@ shaka.util.PeriodCombiner = class {
|
|
|
890
890
|
// Create a fresh output stream for trick-mode playback.
|
|
891
891
|
output.trickModeVideo = shaka.util.PeriodCombiner.cloneStream_(
|
|
892
892
|
input.trickModeVideo);
|
|
893
|
-
|
|
894
|
-
// The trick-mode tracks in multi-period content should have trick-mode
|
|
895
|
-
// segment indexes whenever available, rather than only regular-mode
|
|
896
|
-
// segment indexes.
|
|
893
|
+
output.trickModeVideo.matchedStreams = [];
|
|
897
894
|
output.trickModeVideo.createSegmentIndex = () => {
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
895
|
+
if (output.trickModeVideo.segmentIndex) {
|
|
896
|
+
return Promise.resolve();
|
|
897
|
+
}
|
|
898
|
+
const segmentIndex = new shaka.media.MetaSegmentIndex();
|
|
899
|
+
goog.asserts.assert(output.trickModeVideo.matchedStreams,
|
|
900
|
+
'trickmode matched streams should exist');
|
|
901
|
+
for (const stream of output.trickModeVideo.matchedStreams) {
|
|
902
|
+
goog.asserts.assert(stream.segmentIndex,
|
|
903
|
+
'trickmode segment index should exist');
|
|
904
|
+
segmentIndex.appendSegmentIndex(stream.segmentIndex);
|
|
905
|
+
}
|
|
906
|
+
output.trickModeVideo.segmentIndex = segmentIndex;
|
|
907
|
+
|
|
903
908
|
return Promise.resolve();
|
|
904
909
|
};
|
|
905
910
|
}
|
|
906
911
|
|
|
907
912
|
// Concatenate the trick mode input onto the trick mode output.
|
|
913
|
+
output.trickModeVideo.matchedStreams.push(input.trickModeVideo);
|
|
908
914
|
shaka.util.PeriodCombiner.concatenateStreams_(
|
|
909
915
|
output.trickModeVideo, input.trickModeVideo);
|
|
910
916
|
} else if (output.trickModeVideo) {
|
|
911
917
|
// We have a trick mode output, but no input from this Period. Fill it in
|
|
912
918
|
// from the standard input Stream.
|
|
919
|
+
output.trickModeVideo.matchedStreams.push(input);
|
|
913
920
|
shaka.util.PeriodCombiner.concatenateStreams_(
|
|
914
921
|
output.trickModeVideo, input);
|
|
915
922
|
}
|
package/lib/util/tXml.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
goog.provide('shaka.util.TXml');
|
|
8
8
|
|
|
9
|
+
goog.require('shaka.util.ObjectUtils');
|
|
9
10
|
goog.require('shaka.util.StringUtils');
|
|
10
11
|
goog.require('shaka.log');
|
|
11
12
|
|
|
@@ -71,24 +72,37 @@ shaka.util.TXml = class {
|
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
/**
|
|
74
|
-
*
|
|
75
|
+
* Get namespace based on schema
|
|
75
76
|
* @param {string} schema
|
|
76
77
|
* @return {string}
|
|
77
78
|
*/
|
|
78
79
|
static getKnownNameSpace(schema) {
|
|
79
|
-
if (shaka.util.TXml.
|
|
80
|
-
return shaka.util.TXml.
|
|
80
|
+
if (shaka.util.TXml.uriToNameSpace_.has(schema)) {
|
|
81
|
+
return shaka.util.TXml.uriToNameSpace_.get(schema);
|
|
81
82
|
}
|
|
82
83
|
return '';
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
/**
|
|
86
|
-
*
|
|
87
|
+
* Get schema based on namespace
|
|
88
|
+
* @param {string} NS
|
|
89
|
+
* @return {string}
|
|
90
|
+
*/
|
|
91
|
+
static getKnownSchema(NS) {
|
|
92
|
+
if (shaka.util.TXml.nameSpaceToUri_.has(NS)) {
|
|
93
|
+
return shaka.util.TXml.nameSpaceToUri_.get(NS);
|
|
94
|
+
}
|
|
95
|
+
return '';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Sets NS <-> schema bidirectional mapping
|
|
87
100
|
* @param {string} schema
|
|
88
101
|
* @param {string} NS
|
|
89
102
|
*/
|
|
90
103
|
static setKnownNameSpace(schema, NS) {
|
|
91
|
-
shaka.util.TXml.
|
|
104
|
+
shaka.util.TXml.uriToNameSpace_.set(schema, NS);
|
|
105
|
+
shaka.util.TXml.nameSpaceToUri_.set(NS, schema);
|
|
92
106
|
}
|
|
93
107
|
|
|
94
108
|
/**
|
|
@@ -873,7 +887,12 @@ shaka.util.TXml = class {
|
|
|
873
887
|
*/
|
|
874
888
|
static txmlNodeToDomElement(node) {
|
|
875
889
|
const TXml = shaka.util.TXml;
|
|
876
|
-
|
|
890
|
+
let namespace = '';
|
|
891
|
+
const parts = node.tagName.split(':');
|
|
892
|
+
if (parts.length > 0) {
|
|
893
|
+
namespace = TXml.getKnownSchema(parts[0]);
|
|
894
|
+
}
|
|
895
|
+
const element = document.createElementNS(namespace, node.tagName);
|
|
877
896
|
|
|
878
897
|
for (const k in node.attributes) {
|
|
879
898
|
const v = node.attributes[k];
|
|
@@ -892,9 +911,41 @@ shaka.util.TXml = class {
|
|
|
892
911
|
|
|
893
912
|
return element;
|
|
894
913
|
}
|
|
914
|
+
|
|
915
|
+
/**
|
|
916
|
+
* Clones node and its children recursively. Skips parent.
|
|
917
|
+
* @param {?shaka.extern.xml.Node} node
|
|
918
|
+
* @return {?shaka.extern.xml.Node}
|
|
919
|
+
*/
|
|
920
|
+
static cloneNode(node) {
|
|
921
|
+
if (!node) {
|
|
922
|
+
return null;
|
|
923
|
+
}
|
|
924
|
+
/** @type {!shaka.extern.xml.Node} */
|
|
925
|
+
const clone = {
|
|
926
|
+
tagName: node.tagName,
|
|
927
|
+
attributes: shaka.util.ObjectUtils.shallowCloneObject(node.attributes),
|
|
928
|
+
children: [],
|
|
929
|
+
parent: null,
|
|
930
|
+
};
|
|
931
|
+
for (const child of node.children) {
|
|
932
|
+
if (typeof child === 'string') {
|
|
933
|
+
clone.children.push(child);
|
|
934
|
+
} else {
|
|
935
|
+
const clonedChild = shaka.util.TXml.cloneNode(child);
|
|
936
|
+
clonedChild.parent = clone;
|
|
937
|
+
clone.children.push(clonedChild);
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
return clone;
|
|
941
|
+
}
|
|
895
942
|
};
|
|
896
943
|
|
|
897
|
-
|
|
944
|
+
/** @private {!Map<string, string>} */
|
|
945
|
+
shaka.util.TXml.uriToNameSpace_ = new Map();
|
|
946
|
+
|
|
947
|
+
/** @private {!Map<string, string>} */
|
|
948
|
+
shaka.util.TXml.nameSpaceToUri_ = new Map();
|
|
898
949
|
|
|
899
950
|
|
|
900
951
|
/**
|