shaka-player 4.1.3 → 4.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/build-and-test.yaml +31 -16
- package/.github/workflows/custom-actions/set-commit-status/action.yaml +1 -5
- package/.github/workflows/deflake.yaml +28 -0
- package/.github/workflows/selenium-lab-tests.yaml +168 -54
- package/AUTHORS +2 -0
- package/CHANGELOG.md +29 -0
- package/CONTRIBUTORS +2 -0
- package/demo/common/message_ids.js +1 -0
- package/demo/config.js +3 -1
- package/demo/locales/en.json +1 -0
- package/demo/locales/source.json +4 -0
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +6 -6
- package/dist/demo.compiled.debug.map +2 -2
- package/dist/demo.compiled.js +6 -6
- package/dist/demo.compiled.map +2 -2
- package/dist/deps.js +1 -1
- package/dist/locales.js +31 -31
- package/dist/receiver.compiled.debug.js +3 -3
- package/dist/receiver.compiled.debug.map +2 -2
- package/dist/receiver.compiled.js +3 -3
- package/dist/receiver.compiled.map +2 -2
- package/dist/shaka-player.compiled.d.ts +2 -2
- package/dist/shaka-player.compiled.debug.d.ts +2 -2
- package/dist/shaka-player.compiled.debug.externs.js +24 -24
- package/dist/shaka-player.compiled.debug.js +209 -200
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +24 -24
- package/dist/shaka-player.compiled.js +736 -733
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +2 -2
- package/dist/shaka-player.ui.debug.d.ts +2 -2
- package/dist/shaka-player.ui.debug.externs.js +24 -24
- package/dist/shaka-player.ui.debug.js +263 -254
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +24 -24
- package/dist/shaka-player.ui.js +900 -896
- package/dist/shaka-player.ui.map +4 -4
- package/docs/jsdoc-template/publish.js +33 -0
- package/docs/jsdoc-template/tmpl/container.tmpl +4 -1
- package/docs/jsdoc.conf.json +1 -0
- package/externs/shaka/manifest_parser.js +4 -1
- package/externs/shaka/player.js +7 -1
- package/lib/ads/client_side_ad_manager.js +7 -0
- package/lib/cast/cast_sender.js +39 -14
- package/lib/cea/cea608_memory.js +4 -0
- package/lib/hls/hls_parser.js +30 -8
- package/lib/media/drm_engine.js +52 -1
- package/lib/media/media_source_engine.js +43 -15
- package/lib/media/streaming_engine.js +79 -14
- package/lib/offline/storage.js +1 -0
- package/lib/player.js +29 -5
- package/lib/text/ttml_text_parser.js +6 -0
- package/lib/text/ui_text_displayer.js +8 -0
- package/lib/util/platform.js +24 -0
- package/lib/util/player_configuration.js +5 -0
- package/lib/util/pssh.js +2 -1
- package/lib/util/stream_utils.js +2 -1
- package/package.json +1 -1
- package/test/cea/cea608_memory_unit.js +88 -0
- package/test/dash/dash_parser_content_protection_unit.js +1 -0
- package/test/dash/dash_parser_live_unit.js +1 -0
- package/test/dash/dash_parser_manifest_unit.js +1 -0
- package/test/dash/dash_parser_segment_base_unit.js +1 -0
- package/test/dash/dash_parser_segment_list_unit.js +1 -0
- package/test/dash/dash_parser_segment_template_unit.js +1 -0
- package/test/hls/hls_live_unit.js +169 -247
- package/test/hls/hls_parser_unit.js +60 -2
- package/test/media/drm_engine_unit.js +90 -0
- package/test/media/media_source_engine_integration.js +36 -0
- package/test/media/media_source_engine_unit.js +118 -1
- package/test/media/streaming_engine_integration.js +9 -7
- package/test/media/streaming_engine_unit.js +29 -0
- package/test/offline/offline_integration.js +3 -3
- package/test/player_integration.js +2 -2
- package/test/player_src_equals_integration.js +2 -0
- package/test/player_unit.js +39 -1
- package/test/test/assets/small.mp4 +0 -0
- package/test/test/util/dash_parser_util.js +2 -0
- package/test/test/util/ttml_utils.js +0 -2
- package/test/text/ttml_text_parser_unit.js +46 -0
- package/test/ui/text_displayer_layout_unit.js +17 -2
- package/ui/controls.js +0 -7
- package/ui/less/ad_controls.less +4 -0
|
@@ -320,8 +320,14 @@ shaka.media.StreamingEngine = class {
|
|
|
320
320
|
* @param {number=} safeMargin
|
|
321
321
|
* @param {boolean=} force
|
|
322
322
|
* If true, reload the variant even if it did not change.
|
|
323
|
+
* @param {boolean=} adaptation
|
|
324
|
+
* If true, update the media state to indicate MediaSourceEngine should
|
|
325
|
+
* reset the timestamp offset to ensure the new track segments are correctly
|
|
326
|
+
* placed on the timeline.
|
|
323
327
|
*/
|
|
324
|
-
switchVariant(
|
|
328
|
+
switchVariant(
|
|
329
|
+
variant, clearBuffer = false, safeMargin = 0, force = false,
|
|
330
|
+
adaptation = false) {
|
|
325
331
|
this.currentVariant_ = variant;
|
|
326
332
|
|
|
327
333
|
if (!this.startupComplete_) {
|
|
@@ -332,12 +338,14 @@ shaka.media.StreamingEngine = class {
|
|
|
332
338
|
if (variant.video) {
|
|
333
339
|
this.switchInternal_(
|
|
334
340
|
variant.video, /* clearBuffer= */ clearBuffer,
|
|
335
|
-
/* safeMargin= */ safeMargin, /* force= */ force
|
|
341
|
+
/* safeMargin= */ safeMargin, /* force= */ force,
|
|
342
|
+
/* adaptation= */ adaptation);
|
|
336
343
|
}
|
|
337
344
|
if (variant.audio) {
|
|
338
345
|
this.switchInternal_(
|
|
339
346
|
variant.audio, /* clearBuffer= */ clearBuffer,
|
|
340
|
-
/* safeMargin= */ safeMargin, /* force= */ force
|
|
347
|
+
/* safeMargin= */ safeMargin, /* force= */ force,
|
|
348
|
+
/* adaptation= */ adaptation);
|
|
341
349
|
}
|
|
342
350
|
}
|
|
343
351
|
|
|
@@ -383,9 +391,13 @@ shaka.media.StreamingEngine = class {
|
|
|
383
391
|
* @param {number} safeMargin
|
|
384
392
|
* @param {boolean} force
|
|
385
393
|
* If true, reload the text stream even if it did not change.
|
|
394
|
+
* @param {boolean=} adaptation
|
|
395
|
+
* If true, update the media state to indicate MediaSourceEngine should
|
|
396
|
+
* reset the timestamp offset to ensure the new track segments are correctly
|
|
397
|
+
* placed on the timeline.
|
|
386
398
|
* @private
|
|
387
399
|
*/
|
|
388
|
-
switchInternal_(stream, clearBuffer, safeMargin, force) {
|
|
400
|
+
switchInternal_(stream, clearBuffer, safeMargin, force, adaptation) {
|
|
389
401
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
390
402
|
const type = /** @type {!ContentType} */(stream.type);
|
|
391
403
|
const mediaState = this.mediaStates_.get(type);
|
|
@@ -440,6 +452,7 @@ shaka.media.StreamingEngine = class {
|
|
|
440
452
|
|
|
441
453
|
mediaState.stream = stream;
|
|
442
454
|
mediaState.segmentIterator = null;
|
|
455
|
+
mediaState.adaptation = !!adaptation;
|
|
443
456
|
|
|
444
457
|
const streamTag = shaka.media.StreamingEngine.logPrefix_(mediaState);
|
|
445
458
|
shaka.log.debug('switch: switching to Stream ' + streamTag);
|
|
@@ -769,12 +782,11 @@ shaka.media.StreamingEngine = class {
|
|
|
769
782
|
const mediaSourceEngine = this.playerInterface_.mediaSourceEngine;
|
|
770
783
|
const forceTransmuxTS = this.config_.forceTransmuxTS;
|
|
771
784
|
|
|
772
|
-
|
|
773
785
|
await mediaSourceEngine.init(streamsByType, forceTransmuxTS,
|
|
774
786
|
this.manifest_.sequenceMode);
|
|
775
787
|
this.destroyer_.ensureNotDestroyed();
|
|
776
788
|
|
|
777
|
-
this.
|
|
789
|
+
this.updateDuration();
|
|
778
790
|
|
|
779
791
|
for (const type of streamsByType.keys()) {
|
|
780
792
|
const stream = streamsByType.get(type);
|
|
@@ -824,9 +836,8 @@ shaka.media.StreamingEngine = class {
|
|
|
824
836
|
|
|
825
837
|
/**
|
|
826
838
|
* Sets the MediaSource's duration.
|
|
827
|
-
* @private
|
|
828
839
|
*/
|
|
829
|
-
|
|
840
|
+
updateDuration() {
|
|
830
841
|
const duration = this.manifest_.presentationTimeline.getDuration();
|
|
831
842
|
if (duration < Infinity) {
|
|
832
843
|
this.playerInterface_.mediaSourceEngine.setDuration(duration);
|
|
@@ -1001,7 +1012,11 @@ shaka.media.StreamingEngine = class {
|
|
|
1001
1012
|
const timeUntilEnd =
|
|
1002
1013
|
this.manifest_.presentationTimeline.getDuration() - timeNeeded;
|
|
1003
1014
|
const oneMicrosecond = 1e-6;
|
|
1004
|
-
|
|
1015
|
+
|
|
1016
|
+
const bufferEnd =
|
|
1017
|
+
this.playerInterface_.mediaSourceEngine.bufferEnd(mediaState.type);
|
|
1018
|
+
|
|
1019
|
+
if (timeUntilEnd < oneMicrosecond && !!bufferEnd) {
|
|
1005
1020
|
// We shouldn't rebuffer if the playhead is close to the end of the
|
|
1006
1021
|
// presentation.
|
|
1007
1022
|
shaka.log.debug(logPrefix, 'buffered to end of presentation');
|
|
@@ -1031,8 +1046,6 @@ shaka.media.StreamingEngine = class {
|
|
|
1031
1046
|
return this.config_.updateIntervalSeconds / 2;
|
|
1032
1047
|
}
|
|
1033
1048
|
|
|
1034
|
-
const bufferEnd =
|
|
1035
|
-
this.playerInterface_.mediaSourceEngine.bufferEnd(mediaState.type);
|
|
1036
1049
|
const reference = this.getSegmentReferenceNeeded_(
|
|
1037
1050
|
mediaState, presentationTime, bufferEnd);
|
|
1038
1051
|
if (!reference) {
|
|
@@ -1235,7 +1248,16 @@ shaka.media.StreamingEngine = class {
|
|
|
1235
1248
|
// Enable MP4 low latency streaming with ReadableStream chunked data.
|
|
1236
1249
|
if (this.config_.lowLatencyMode && isReadableStreamSupported && isMP4) {
|
|
1237
1250
|
let remaining = new Uint8Array(0);
|
|
1251
|
+
let processingResult = false;
|
|
1252
|
+
let callbackCalled = false;
|
|
1238
1253
|
const streamDataCallback = async (data) => {
|
|
1254
|
+
if (processingResult) {
|
|
1255
|
+
// If the fallback result processing was triggered, don't also
|
|
1256
|
+
// append the buffer here. In theory this should never happen,
|
|
1257
|
+
// but it does on some older TVs.
|
|
1258
|
+
return;
|
|
1259
|
+
}
|
|
1260
|
+
callbackCalled = true;
|
|
1239
1261
|
this.destroyer_.ensureNotDestroyed();
|
|
1240
1262
|
if (this.fatalError_) {
|
|
1241
1263
|
return;
|
|
@@ -1266,7 +1288,33 @@ shaka.media.StreamingEngine = class {
|
|
|
1266
1288
|
}
|
|
1267
1289
|
};
|
|
1268
1290
|
|
|
1269
|
-
|
|
1291
|
+
const result =
|
|
1292
|
+
await this.fetch_(mediaState, reference, streamDataCallback);
|
|
1293
|
+
if (!callbackCalled) {
|
|
1294
|
+
// In some environments, we might be forced to use network plugins
|
|
1295
|
+
// that don't support streamDataCallback. In those cases, as a
|
|
1296
|
+
// fallback, append the buffer here.
|
|
1297
|
+
processingResult = true;
|
|
1298
|
+
this.destroyer_.ensureNotDestroyed();
|
|
1299
|
+
if (this.fatalError_) {
|
|
1300
|
+
return;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
// If the text stream gets switched between fetch_() and append_(),
|
|
1304
|
+
// the new text parser is initialized, but the new init segment is
|
|
1305
|
+
// not fetched yet. That would cause an error in
|
|
1306
|
+
// TextParser.parseMedia().
|
|
1307
|
+
// See http://b/168253400
|
|
1308
|
+
if (mediaState.waitingToClearBuffer) {
|
|
1309
|
+
shaka.log.info(logPrefix, 'waitingToClearBuffer, skip append');
|
|
1310
|
+
mediaState.performingUpdate = false;
|
|
1311
|
+
this.scheduleUpdate_(mediaState, 0);
|
|
1312
|
+
return;
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
await this.append_(
|
|
1316
|
+
mediaState, presentationTime, stream, reference, result);
|
|
1317
|
+
}
|
|
1270
1318
|
} else {
|
|
1271
1319
|
if (this.config_.lowLatencyMode && !isReadableStreamSupported) {
|
|
1272
1320
|
shaka.log.warning('Low latency streaming mode is enabled, but ' +
|
|
@@ -1554,6 +1602,8 @@ shaka.media.StreamingEngine = class {
|
|
|
1554
1602
|
shaka.log.v1(logPrefix, 'appending init segment');
|
|
1555
1603
|
const hasClosedCaptions = mediaState.stream.closedCaptions &&
|
|
1556
1604
|
mediaState.stream.closedCaptions.size > 0;
|
|
1605
|
+
await this.playerInterface_.beforeAppendSegment(
|
|
1606
|
+
mediaState.type, initSegment);
|
|
1557
1607
|
await this.playerInterface_.mediaSourceEngine.appendBuffer(
|
|
1558
1608
|
mediaState.type, initSegment, /* reference= */ null,
|
|
1559
1609
|
hasClosedCaptions);
|
|
@@ -1604,14 +1654,21 @@ shaka.media.StreamingEngine = class {
|
|
|
1604
1654
|
shaka.log.v1(logPrefix, 'appending media segment at',
|
|
1605
1655
|
(reference.syncTime == null ? 'unknown' : reference.syncTime));
|
|
1606
1656
|
|
|
1657
|
+
// 'seeked' or 'adaptation' triggered logic applies only to this
|
|
1658
|
+
// appendBuffer() call.
|
|
1607
1659
|
const seeked = mediaState.seeked;
|
|
1608
1660
|
mediaState.seeked = false;
|
|
1661
|
+
const adaptation = mediaState.adaptation;
|
|
1662
|
+
mediaState.adaptation = false;
|
|
1663
|
+
|
|
1664
|
+
await this.playerInterface_.beforeAppendSegment(mediaState.type, segment);
|
|
1609
1665
|
await this.playerInterface_.mediaSourceEngine.appendBuffer(
|
|
1610
1666
|
mediaState.type,
|
|
1611
1667
|
segment,
|
|
1612
1668
|
reference,
|
|
1613
1669
|
hasClosedCaptions,
|
|
1614
|
-
seeked
|
|
1670
|
+
seeked,
|
|
1671
|
+
adaptation);
|
|
1615
1672
|
this.destroyer_.ensureNotDestroyed();
|
|
1616
1673
|
shaka.log.v2(logPrefix, 'appended media segment');
|
|
1617
1674
|
}
|
|
@@ -1988,7 +2045,9 @@ shaka.media.StreamingEngine = class {
|
|
|
1988
2045
|
* onEvent: function(!Event),
|
|
1989
2046
|
* onManifestUpdate: function(),
|
|
1990
2047
|
* onSegmentAppended: function(),
|
|
1991
|
-
* onInitSegmentAppended: function(!number,!shaka.media.InitSegmentReference)
|
|
2048
|
+
* onInitSegmentAppended: function(!number,!shaka.media.InitSegmentReference),
|
|
2049
|
+
* beforeAppendSegment: function(
|
|
2050
|
+
* shaka.util.ManifestParserUtils.ContentType,!BufferSource):Promise
|
|
1992
2051
|
* }}
|
|
1993
2052
|
*
|
|
1994
2053
|
* @property {function():number} getPresentationTime
|
|
@@ -2016,6 +2075,9 @@ shaka.media.StreamingEngine = class {
|
|
|
2016
2075
|
* @property
|
|
2017
2076
|
* {function(!number, !shaka.media.InitSegmentReference)} onInitSegmentAppended
|
|
2018
2077
|
* Called when an init segment is appended to a MediaSource.
|
|
2078
|
+
* @property {!function(shaka.util.ManifestParserUtils.ContentType,
|
|
2079
|
+
* !BufferSource):Promise} beforeAppendSegment
|
|
2080
|
+
* A function called just before appending to the source buffer.
|
|
2019
2081
|
*/
|
|
2020
2082
|
shaka.media.StreamingEngine.PlayerInterface;
|
|
2021
2083
|
|
|
@@ -2039,6 +2101,7 @@ shaka.media.StreamingEngine.PlayerInterface;
|
|
|
2039
2101
|
* clearBufferSafeMargin: number,
|
|
2040
2102
|
* clearingBuffer: boolean,
|
|
2041
2103
|
* seeked: boolean,
|
|
2104
|
+
* adaptation: boolean,
|
|
2042
2105
|
* recovering: boolean,
|
|
2043
2106
|
* hasError: boolean,
|
|
2044
2107
|
* operation: shaka.net.NetworkingEngine.PendingRequest
|
|
@@ -2085,6 +2148,8 @@ shaka.media.StreamingEngine.PlayerInterface;
|
|
|
2085
2148
|
* True indicates that the buffer is being cleared.
|
|
2086
2149
|
* @property {boolean} seeked
|
|
2087
2150
|
* True indicates that the presentation just seeked.
|
|
2151
|
+
* @property {boolean} adaptation
|
|
2152
|
+
* True indicates that the presentation just automatically switched variants.
|
|
2088
2153
|
* @property {boolean} recovering
|
|
2089
2154
|
* True indicates that the last segment was not appended because it could not
|
|
2090
2155
|
* fit in the buffer.
|
package/lib/offline/storage.js
CHANGED
package/lib/player.js
CHANGED
|
@@ -1770,6 +1770,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1770
1770
|
enableLowLatencyMode: () => {
|
|
1771
1771
|
this.configure('streaming.lowLatencyMode', true);
|
|
1772
1772
|
},
|
|
1773
|
+
updateDuration: () => {
|
|
1774
|
+
if (this.streamingEngine_) {
|
|
1775
|
+
this.streamingEngine_.updateDuration();
|
|
1776
|
+
}
|
|
1777
|
+
},
|
|
1773
1778
|
};
|
|
1774
1779
|
|
|
1775
1780
|
const startTime = Date.now() / 1000;
|
|
@@ -2945,6 +2950,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2945
2950
|
this.qualityObserver_.addMediaQualityChange(mediaQuality, position);
|
|
2946
2951
|
}
|
|
2947
2952
|
},
|
|
2953
|
+
beforeAppendSegment: (contentType, segment) => {
|
|
2954
|
+
return this.drmEngine_.parseInbandPssh(contentType, segment);
|
|
2955
|
+
},
|
|
2948
2956
|
};
|
|
2949
2957
|
|
|
2950
2958
|
return new shaka.media.StreamingEngine(this.manifest_, playerInterface);
|
|
@@ -3831,8 +3839,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3831
3839
|
return;
|
|
3832
3840
|
}
|
|
3833
3841
|
|
|
3834
|
-
this.switchVariant_(
|
|
3835
|
-
safeMargin);
|
|
3842
|
+
this.switchVariant_(
|
|
3843
|
+
variant, /* fromAdaptation= */ false, clearBuffer, safeMargin);
|
|
3836
3844
|
|
|
3837
3845
|
// Workaround for
|
|
3838
3846
|
// https://github.com/shaka-project/shaka-player/issues/1299
|
|
@@ -4452,6 +4460,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4452
4460
|
this.stats_.setBandwidthEstimate(estimate);
|
|
4453
4461
|
}
|
|
4454
4462
|
|
|
4463
|
+
if (this.loadMode_ == shaka.Player.LoadMode.SRC_EQUALS) {
|
|
4464
|
+
this.stats_.setResolution(
|
|
4465
|
+
/* width= */ element.videoWidth || NaN,
|
|
4466
|
+
/* height= */ element.videoHeight || NaN);
|
|
4467
|
+
}
|
|
4468
|
+
|
|
4455
4469
|
return this.stats_.getBlob();
|
|
4456
4470
|
}
|
|
4457
4471
|
|
|
@@ -5363,7 +5377,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5363
5377
|
const currentVariant = this.streamingEngine_.getCurrentVariant();
|
|
5364
5378
|
if (variant == currentVariant) {
|
|
5365
5379
|
shaka.log.debug('Variant already selected.');
|
|
5366
|
-
// If you want to clear the buffer, we force to reselect the same variant
|
|
5380
|
+
// If you want to clear the buffer, we force to reselect the same variant.
|
|
5381
|
+
// We don't need to reset the timestampOffset since it's the same variant,
|
|
5382
|
+
// so 'adaptation' isn't passed here.
|
|
5367
5383
|
if (clearBuffer) {
|
|
5368
5384
|
this.streamingEngine_.switchVariant(variant, clearBuffer, safeMargin,
|
|
5369
5385
|
/* force= */ true);
|
|
@@ -5373,7 +5389,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5373
5389
|
|
|
5374
5390
|
// Add entries to the history.
|
|
5375
5391
|
this.addVariantToSwitchHistory_(variant, fromAdaptation);
|
|
5376
|
-
this.streamingEngine_.switchVariant(
|
|
5392
|
+
this.streamingEngine_.switchVariant(
|
|
5393
|
+
variant, clearBuffer, safeMargin, /* force= */ undefined,
|
|
5394
|
+
/* adaptation= */ fromAdaptation);
|
|
5377
5395
|
let oldTrack = null;
|
|
5378
5396
|
if (currentVariant) {
|
|
5379
5397
|
oldTrack = shaka.util.StreamUtils.variantToTrack(currentVariant);
|
|
@@ -5618,6 +5636,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5618
5636
|
return false;
|
|
5619
5637
|
}
|
|
5620
5638
|
|
|
5639
|
+
if (!navigator.onLine) {
|
|
5640
|
+
// Don't restrict variants if we're completely offline, or else we end up
|
|
5641
|
+
// rapidly restricting all of them.
|
|
5642
|
+
return false;
|
|
5643
|
+
}
|
|
5644
|
+
|
|
5621
5645
|
let maxDisabledTime = this.config_.streaming.maxDisabledTime;
|
|
5622
5646
|
if (maxDisabledTime == 0) {
|
|
5623
5647
|
if (error.code == shaka.util.Error.Code.SEGMENT_MISSING) {
|
|
@@ -6551,7 +6575,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6551
6575
|
* @define {string} A version number taken from git at compile time.
|
|
6552
6576
|
* @export
|
|
6553
6577
|
*/
|
|
6554
|
-
shaka.Player.version = 'v4.1.
|
|
6578
|
+
shaka.Player.version = 'v4.1.5-uncompiled';
|
|
6555
6579
|
|
|
6556
6580
|
// Initialize the deprecation system using the version string we just set
|
|
6557
6581
|
// on the player.
|
|
@@ -164,6 +164,12 @@ shaka.text.TtmlTextParser = class {
|
|
|
164
164
|
cellResolutionInfo, /* parentCueElement= */ null,
|
|
165
165
|
/* isContent= */ false);
|
|
166
166
|
if (cue) {
|
|
167
|
+
// According to the TTML spec, backgrounds default to transparent.
|
|
168
|
+
// So default the background of the top-level element to transparent.
|
|
169
|
+
// Nested elements may override that background color already.
|
|
170
|
+
if (!cue.backgroundColor) {
|
|
171
|
+
cue.backgroundColor = 'transparent';
|
|
172
|
+
}
|
|
167
173
|
cues.push(cue);
|
|
168
174
|
}
|
|
169
175
|
}
|
|
@@ -493,6 +493,14 @@ shaka.text.UITextDisplayer = class {
|
|
|
493
493
|
style.backgroundRepeat = 'no-repeat';
|
|
494
494
|
style.backgroundSize = 'contain';
|
|
495
495
|
style.backgroundPosition = 'center';
|
|
496
|
+
|
|
497
|
+
// Quoting https://www.w3.org/TR/ttml-imsc1.2/:
|
|
498
|
+
// "The width and height (in pixels) of the image resource referenced by
|
|
499
|
+
// smpte:backgroundImage SHALL be equal to the width and height expressed
|
|
500
|
+
// by the tts:extent attribute of the region in which the div element is
|
|
501
|
+
// presented".
|
|
502
|
+
style.width = '100%';
|
|
503
|
+
style.height = '100%';
|
|
496
504
|
} else {
|
|
497
505
|
// If we have both text and nested cues, then style everything; otherwise
|
|
498
506
|
// place the text in its own <span> so the background doesn't fill the
|
package/lib/util/platform.js
CHANGED
|
@@ -173,6 +173,30 @@ shaka.util.Platform = class {
|
|
|
173
173
|
shaka.util.Platform.userAgentContains_('Android');
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
+
/**
|
|
177
|
+
* Returns a major version number for Chrome, or Chromium-based browsers.
|
|
178
|
+
*
|
|
179
|
+
* For example:
|
|
180
|
+
* - Chrome 106.0.5249.61 returns 106.
|
|
181
|
+
* - Edge 106.0.1370.34 returns 106 (since this is based on Chromium).
|
|
182
|
+
* - Safari returns null (since this is independent of Chromium).
|
|
183
|
+
*
|
|
184
|
+
* @return {?number} A major version number or null if not Chromium-based.
|
|
185
|
+
*/
|
|
186
|
+
static chromeVersion() {
|
|
187
|
+
if (!shaka.util.Platform.userAgentContains_('Chrome')) {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Looking for something like "Chrome/106.0.0.0".
|
|
192
|
+
const match = navigator.userAgent.match(/Chrome\/(\d+)/);
|
|
193
|
+
if (match) {
|
|
194
|
+
return parseInt(match[1], /* base= */ 10);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
|
|
176
200
|
/**
|
|
177
201
|
* Check if the current platform is Google Chrome.
|
|
178
202
|
*
|
|
@@ -75,6 +75,10 @@ shaka.util.PlayerConfiguration = class {
|
|
|
75
75
|
updateExpirationTime: 1,
|
|
76
76
|
preferredKeySystems: [],
|
|
77
77
|
keySystemsMapping: {},
|
|
78
|
+
// The Xbox One browser does not detect DRM key changes signalled by a
|
|
79
|
+
// change in the PSSH in media segments. We need to parse PSSH from media
|
|
80
|
+
// segments to detect key changes.
|
|
81
|
+
parseInbandPsshEnabled: shaka.util.Platform.isXboxOne(),
|
|
78
82
|
};
|
|
79
83
|
|
|
80
84
|
const manifest = {
|
|
@@ -321,6 +325,7 @@ shaka.util.PlayerConfiguration = class {
|
|
|
321
325
|
*/
|
|
322
326
|
static mergeConfigObjects(destination, updates, template) {
|
|
323
327
|
const overrides = {
|
|
328
|
+
'.drm.keySystemsMapping': '',
|
|
324
329
|
'.drm.servers': '',
|
|
325
330
|
'.drm.clearKeys': '',
|
|
326
331
|
'.drm.advanced': {
|
package/lib/util/pssh.js
CHANGED
|
@@ -42,11 +42,12 @@ shaka.util.Pssh = class {
|
|
|
42
42
|
|
|
43
43
|
new shaka.util.Mp4Parser()
|
|
44
44
|
.box('moov', shaka.util.Mp4Parser.children)
|
|
45
|
+
.box('moof', shaka.util.Mp4Parser.children)
|
|
45
46
|
.fullBox('pssh', (box) => this.parsePsshBox_(box))
|
|
46
47
|
.parse(psshBox);
|
|
47
48
|
|
|
48
49
|
if (this.data.length == 0) {
|
|
49
|
-
shaka.log.
|
|
50
|
+
shaka.log.v2('No pssh box found!');
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
53
|
|
package/lib/util/stream_utils.js
CHANGED
|
@@ -474,7 +474,8 @@ shaka.util.StreamUtils = class {
|
|
|
474
474
|
if (shaka.util.Platform.isXboxOne() && video &&
|
|
475
475
|
((video.width && video.width > 1920) ||
|
|
476
476
|
(video.height && video.height > 1080)) &&
|
|
477
|
-
video.codecs.includes('avc1.')
|
|
477
|
+
(video.codecs.includes('avc1.') ||
|
|
478
|
+
video.codecs.includes('avc3.'))) {
|
|
478
479
|
shaka.log.debug('Dropping variant - not compatible with platform',
|
|
479
480
|
shaka.util.StreamUtils.getVariantSummaryString_(variant));
|
|
480
481
|
return false;
|
package/package.json
CHANGED
|
@@ -295,5 +295,93 @@ describe('Cea608Memory', () => {
|
|
|
295
295
|
const caption = memory.forceEmit(startTime, endTime);
|
|
296
296
|
expect(caption).toEqual(expectedCaption);
|
|
297
297
|
});
|
|
298
|
+
|
|
299
|
+
it('does not move rows if source row index is negative', () => {
|
|
300
|
+
const startTime = 1;
|
|
301
|
+
const endTime = 2;
|
|
302
|
+
const text = 'test';
|
|
303
|
+
|
|
304
|
+
// Add the text to the buffer, each character on separate rows.
|
|
305
|
+
// At this point, the memory looks like:
|
|
306
|
+
// [1]: t
|
|
307
|
+
// [2]: e
|
|
308
|
+
// [3]: s
|
|
309
|
+
// [4]: t
|
|
310
|
+
for (const c of text) {
|
|
311
|
+
memory.addChar(CharSet.BASIC_NORTH_AMERICAN,
|
|
312
|
+
c.charCodeAt(0));
|
|
313
|
+
memory.setRow(memory.getRow() + 1); // increment row
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const srcRowIdx = -1;
|
|
317
|
+
const dstRowIdx = 2;
|
|
318
|
+
const rowsToMove = 3;
|
|
319
|
+
memory.moveRows(dstRowIdx, srcRowIdx, rowsToMove);
|
|
320
|
+
|
|
321
|
+
// Expected text is 't\ne\ns\nt'
|
|
322
|
+
const topLevelCue = new shaka.text.Cue(startTime, endTime, '');
|
|
323
|
+
topLevelCue.nestedCues = [
|
|
324
|
+
CeaUtils.createDefaultCue(startTime, endTime, 't'),
|
|
325
|
+
CeaUtils.createLineBreakCue(startTime, endTime),
|
|
326
|
+
CeaUtils.createDefaultCue(startTime, endTime, 'e'),
|
|
327
|
+
CeaUtils.createLineBreakCue(startTime, endTime),
|
|
328
|
+
CeaUtils.createDefaultCue(startTime, endTime, 's'),
|
|
329
|
+
CeaUtils.createLineBreakCue(startTime, endTime),
|
|
330
|
+
CeaUtils.createDefaultCue(startTime, endTime, 't'),
|
|
331
|
+
];
|
|
332
|
+
|
|
333
|
+
const expectedCaption = {
|
|
334
|
+
stream,
|
|
335
|
+
cue: topLevelCue,
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
// Force out the new memory.
|
|
339
|
+
const caption = memory.forceEmit(startTime, endTime);
|
|
340
|
+
expect(caption).toEqual(expectedCaption);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it('does not move rows if destination row index is negative', () => {
|
|
344
|
+
const startTime = 1;
|
|
345
|
+
const endTime = 2;
|
|
346
|
+
const text = 'test';
|
|
347
|
+
|
|
348
|
+
// Add the text to the buffer, each character on separate rows.
|
|
349
|
+
// At this point, the memory looks like:
|
|
350
|
+
// [1]: t
|
|
351
|
+
// [2]: e
|
|
352
|
+
// [3]: s
|
|
353
|
+
// [4]: t
|
|
354
|
+
for (const c of text) {
|
|
355
|
+
memory.addChar(CharSet.BASIC_NORTH_AMERICAN,
|
|
356
|
+
c.charCodeAt(0));
|
|
357
|
+
memory.setRow(memory.getRow() + 1); // increment row
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const srcRowIdx = 1;
|
|
361
|
+
const dstRowIdx = -2;
|
|
362
|
+
const rowsToMove = 3;
|
|
363
|
+
memory.moveRows(dstRowIdx, srcRowIdx, rowsToMove);
|
|
364
|
+
|
|
365
|
+
// Expected text is 't\ne\ns\nt'
|
|
366
|
+
const topLevelCue = new shaka.text.Cue(startTime, endTime, '');
|
|
367
|
+
topLevelCue.nestedCues = [
|
|
368
|
+
CeaUtils.createDefaultCue(startTime, endTime, 't'),
|
|
369
|
+
CeaUtils.createLineBreakCue(startTime, endTime),
|
|
370
|
+
CeaUtils.createDefaultCue(startTime, endTime, 'e'),
|
|
371
|
+
CeaUtils.createLineBreakCue(startTime, endTime),
|
|
372
|
+
CeaUtils.createDefaultCue(startTime, endTime, 's'),
|
|
373
|
+
CeaUtils.createLineBreakCue(startTime, endTime),
|
|
374
|
+
CeaUtils.createDefaultCue(startTime, endTime, 't'),
|
|
375
|
+
];
|
|
376
|
+
|
|
377
|
+
const expectedCaption = {
|
|
378
|
+
stream,
|
|
379
|
+
cue: topLevelCue,
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
// Force out the new memory.
|
|
383
|
+
const caption = memory.forceEmit(startTime, endTime);
|
|
384
|
+
expect(caption).toEqual(expectedCaption);
|
|
385
|
+
});
|
|
298
386
|
});
|
|
299
387
|
});
|
|
@@ -348,6 +348,7 @@ describe('DashParser SegmentList', () => {
|
|
|
348
348
|
isLowLatencyMode: () => false,
|
|
349
349
|
isAutoLowLatencyMode: () => false,
|
|
350
350
|
enableLowLatencyMode: () => {},
|
|
351
|
+
updateDuration: () => {},
|
|
351
352
|
};
|
|
352
353
|
const manifest = await dashParser.start('dummy://foo', playerInterface);
|
|
353
354
|
const stream = manifest.variants[0].video;
|