shaka-player 3.2.8 → 3.2.11
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 +67 -15
- package/.github/workflows/compute-incremental-coverage.py +251 -0
- package/.github/workflows/report-incremental-coverage.yaml +39 -0
- package/.github/workflows/selenium-lab-tests.yaml +44 -1
- package/AUTHORS +1 -1
- package/CHANGELOG.md +37 -0
- package/CONTRIBUTORS +4 -1
- package/README.md +20 -6
- package/demo/common/assets.js +1 -1
- package/demo/index.html +0 -2
- package/demo/main.js +3 -3
- package/dist/controls.css +1 -1
- package/dist/demo.compiled.debug.js +3 -3
- package/dist/demo.compiled.debug.map +2 -2
- package/dist/demo.compiled.js +3 -3
- package/dist/demo.compiled.map +2 -2
- package/dist/deps.js +2 -2
- package/dist/locales.js +29 -29
- package/dist/receiver.compiled.debug.js +1 -1
- package/dist/receiver.compiled.debug.map +1 -1
- package/dist/receiver.compiled.js +1 -1
- package/dist/receiver.compiled.map +1 -1
- package/dist/shaka-player.compiled.d.ts +12 -1
- package/dist/shaka-player.compiled.debug.d.ts +12 -1
- package/dist/shaka-player.compiled.debug.externs.js +49 -38
- package/dist/shaka-player.compiled.debug.js +238 -227
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +49 -38
- package/dist/shaka-player.compiled.js +766 -760
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +12 -1
- package/dist/shaka-player.ui.debug.d.ts +12 -1
- package/dist/shaka-player.ui.debug.externs.js +49 -38
- package/dist/shaka-player.ui.debug.js +227 -217
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +49 -38
- package/dist/shaka-player.ui.js +870 -865
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/welcome.md +6 -3
- package/karma.conf.js +3 -11
- package/lib/dash/dash_parser.js +5 -0
- package/lib/hls/hls_parser.js +14 -6
- package/lib/media/drm_engine.js +1 -1
- package/lib/media/presentation_timeline.js +24 -1
- package/lib/media/streaming_engine.js +1 -0
- package/lib/player.js +1 -6
- package/lib/polyfill/media_capabilities.js +3 -0
- package/lib/polyfill/videoplaybackquality.js +3 -1
- package/lib/text/cue.js +0 -5
- package/lib/text/simple_text_displayer.js +21 -9
- package/lib/text/ui_text_displayer.js +83 -19
- package/lib/util/buffer_utils.js +3 -0
- package/lib/util/object_utils.js +1 -0
- package/lib/util/platform.js +41 -1
- package/lib/util/stream_utils.js +24 -3
- package/lib/util/string_utils.js +102 -13
- package/maintained-branches.md +15 -0
- package/package.json +6 -5
- package/test/text/simple_text_displayer_unit.js +27 -0
- package/test/text/ui_text_displayer_unit.js +65 -0
- package/test/util/string_utils_unit.js +46 -8
- package/app-engine/README.md +0 -9
- package/app-engine/demo-version-index/README.md +0 -14
- package/app-engine/demo-version-index/app.yaml +0 -2
- package/app-engine/demo-version-index/main.py +0 -162
- package/app-engine/demo-version-index/requirements.txt +0 -6
- package/app-engine/demo-version-index/templates/index.html +0 -114
- package/app-engine/shaka-player-demo/README.md +0 -18
- package/app-engine/shaka-player-demo/app.yaml +0 -61
- package/app-engine/shaka-player-demo/main.py +0 -95
- package/app-engine/shaka-player-demo/posters/10yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/10yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/1yo.jpg +0 -0
- package/app-engine/shaka-player-demo/posters/2yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/2yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/3yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/3yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/4yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/4yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/5yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/5yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/6yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/6yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/7yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/7yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/8yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/8yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/9yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/9yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/audioOnly.gif +0 -0
- package/app-engine/shaka-player-demo/posters/audioRickRoll.gif +0 -0
- package/app-engine/shaka-player-demo/posters/colorbars.gif +0 -0
- package/app-engine/shaka-player-demo/posters/fireworks.jpg +0 -0
- package/app-engine/shaka-player-demo/posters/party-hat.png +0 -0
- package/app-engine/shaka-player-demo/posters/sources.txt +0 -46
- package/app-engine/shaka-player-demo/posters/standard.png +0 -0
- package/app-engine/shaka-player-demo/posters/trek.jpg +0 -0
- package/app-engine/shaka-player-demo/posters/valentines.png +0 -0
- package/app-engine/shaka-player-demo/posters/zombie.jpg +0 -0
- package/app-engine/shaka-player-demo/posters.py +0 -110
- package/app-engine/shaka-player-demo/requirements.txt +0 -5
- package/app-engine/shaka-player-demo/time.txt +0 -1
- package/build/README.md +0 -127
- package/build/__init__.py +0 -0
- package/build/all.py +0 -150
- package/build/apps.py +0 -186
- package/build/build.py +0 -392
- package/build/check.py +0 -354
- package/build/checkversion.py +0 -84
- package/build/compiler.py +0 -513
- package/build/conformance.textproto +0 -321
- package/build/docker/Dockerfile +0 -20
- package/build/docker/docker-compose.yml +0 -10
- package/build/docs.py +0 -54
- package/build/eslint-plugin-shaka-rules/arg-comment-spacing.js +0 -72
- package/build/eslint-plugin-shaka-rules/index.js +0 -24
- package/build/eslint-plugin-shaka-rules/package.json +0 -7
- package/build/eslint-plugin-shaka-rules/private.js +0 -109
- package/build/gendeps.py +0 -71
- package/build/generateExterns.js +0 -867
- package/build/generateLocalizations.py +0 -262
- package/build/generateTsDefs.py +0 -137
- package/build/install-linux-prereqs.sh +0 -136
- package/build/license-header +0 -5
- package/build/misspellings.txt +0 -38
- package/build/pixelsChanged.js +0 -35
- package/build/shaka-lab.yaml +0 -163
- package/build/shakaBuildHelpers.py +0 -356
- package/build/stats.py +0 -816
- package/build/subprocessWindowsPatch.py +0 -103
- package/build/test.py +0 -541
- package/build/types/ads +0 -8
- package/build/types/cast +0 -6
- package/build/types/cea +0 -13
- package/build/types/complete +0 -9
- package/build/types/core +0 -106
- package/build/types/dash +0 -8
- package/build/types/hls +0 -9
- package/build/types/manifests +0 -5
- package/build/types/networking +0 -6
- package/build/types/offline +0 -21
- package/build/types/polyfill +0 -19
- package/build/types/text +0 -11
- package/build/types/ui +0 -37
- package/build/updateScreenshots.py +0 -85
- package/build/wrapper.template.js +0 -52
|
@@ -98,11 +98,14 @@ You can find a full list of available browsers with `--browsers help`, and you
|
|
|
98
98
|
can find a complete list of testing options with `--help`.
|
|
99
99
|
|
|
100
100
|
|
|
101
|
-
####
|
|
101
|
+
#### Announcements
|
|
102
102
|
|
|
103
|
-
|
|
103
|
+
To subscribe to new releases on GitHub, you can follow
|
|
104
|
+
[instructions from this blog](https://www.jessesquires.com/blog/2020/07/30/github-tip-watching-releases/).
|
|
105
|
+
|
|
106
|
+
To receive infrequent announcements and surveys from us, you can join our
|
|
104
107
|
[mailing list](https://groups.google.com/forum/#!forum/shaka-player-users).
|
|
105
|
-
The list is very low volume.
|
|
108
|
+
The list is very low volume, and can only be written to by us.
|
|
106
109
|
|
|
107
110
|
|
|
108
111
|
#### Continue the Tutorials
|
package/karma.conf.js
CHANGED
|
@@ -160,10 +160,6 @@ module.exports = (config) => {
|
|
|
160
160
|
'node_modules/es6-promise-polyfill/promise.js',
|
|
161
161
|
// Babel polyfill, required for async/await
|
|
162
162
|
'node_modules/@babel/polyfill/dist/polyfill.js',
|
|
163
|
-
// TextDecoder polyfill, required for TextDecoder/TextEncoder on IE and
|
|
164
|
-
// legacy Edge
|
|
165
|
-
// eslint-disable-next-line max-len
|
|
166
|
-
'node_modules/fastestsmallesttextencoderdecoder/EncoderDecoderTogether.min.js',
|
|
167
163
|
|
|
168
164
|
// muxjs module next
|
|
169
165
|
'node_modules/mux.js/dist/mux.min.js',
|
|
@@ -306,13 +302,6 @@ module.exports = (config) => {
|
|
|
306
302
|
// Force failure when running empty test-suites.
|
|
307
303
|
failOnEmptyTestSuite: true,
|
|
308
304
|
|
|
309
|
-
coverageReporter: {
|
|
310
|
-
includeAllSources: true,
|
|
311
|
-
reporters: [
|
|
312
|
-
{type: 'text'},
|
|
313
|
-
],
|
|
314
|
-
},
|
|
315
|
-
|
|
316
305
|
specReporter: {
|
|
317
306
|
suppressSkipped: true,
|
|
318
307
|
showBrowser: true,
|
|
@@ -405,9 +394,12 @@ module.exports = (config) => {
|
|
|
405
394
|
|
|
406
395
|
config.set({
|
|
407
396
|
coverageReporter: {
|
|
397
|
+
includeAllSources: true,
|
|
408
398
|
reporters: [
|
|
409
399
|
{type: 'html', dir: 'coverage'},
|
|
410
400
|
{type: 'cobertura', dir: 'coverage', file: 'coverage.xml'},
|
|
401
|
+
{type: 'json-summary', dir: 'coverage', file: 'coverage.json'},
|
|
402
|
+
{type: 'json', dir: 'coverage', file: 'coverage-details.json'},
|
|
411
403
|
],
|
|
412
404
|
},
|
|
413
405
|
});
|
package/lib/dash/dash_parser.js
CHANGED
|
@@ -503,6 +503,11 @@ shaka.dash.DashParser = class {
|
|
|
503
503
|
}
|
|
504
504
|
presentationTimeline.setClockOffset(offset);
|
|
505
505
|
}
|
|
506
|
+
|
|
507
|
+
// This is the first point where we have a meaningful presentation start
|
|
508
|
+
// time, and we need to tell PresentationTimeline that so that it can
|
|
509
|
+
// maintain consistency from here on.
|
|
510
|
+
presentationTimeline.lockStartTime();
|
|
506
511
|
} else {
|
|
507
512
|
// Just update the variants and text streams, which may change as periods
|
|
508
513
|
// are added or removed.
|
package/lib/hls/hls_parser.js
CHANGED
|
@@ -547,8 +547,14 @@ shaka.hls.HlsParser = class {
|
|
|
547
547
|
for (const stream of streamsToNotify) {
|
|
548
548
|
this.segmentsToNotifyByStream_.push(stream.segmentIndex.references);
|
|
549
549
|
}
|
|
550
|
+
|
|
550
551
|
this.notifySegments_();
|
|
551
552
|
|
|
553
|
+
// This is the first point where we have a meaningful presentation start
|
|
554
|
+
// time, and we need to tell PresentationTimeline that so that it can
|
|
555
|
+
// maintain consistency from here on.
|
|
556
|
+
this.presentationTimeline_.lockStartTime();
|
|
557
|
+
|
|
552
558
|
// This asserts that the live edge is being calculated from segment times.
|
|
553
559
|
// For VOD and event streams, this check should still pass.
|
|
554
560
|
goog.asserts.assert(
|
|
@@ -1660,8 +1666,6 @@ shaka.hls.HlsParser = class {
|
|
|
1660
1666
|
/* presentationStartTime= */ null, /* delay= */ 0);
|
|
1661
1667
|
this.presentationTimeline_.setStatic(true);
|
|
1662
1668
|
}
|
|
1663
|
-
|
|
1664
|
-
this.notifySegments_();
|
|
1665
1669
|
}
|
|
1666
1670
|
|
|
1667
1671
|
/**
|
|
@@ -2562,12 +2566,16 @@ shaka.hls.HlsParser = class {
|
|
|
2562
2566
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
2563
2567
|
const requestType = shaka.net.NetworkingEngine.RequestType.SEGMENT;
|
|
2564
2568
|
|
|
2569
|
+
// If you wait long enough, requesting the first segment can fail
|
|
2570
|
+
// because it has fallen off the left edge of DVR, so to be safer,
|
|
2571
|
+
// let's request the middle segment.
|
|
2565
2572
|
goog.asserts.assert(playlist.segments.length,
|
|
2566
2573
|
'Playlist should have segments!');
|
|
2567
|
-
const
|
|
2568
|
-
|
|
2574
|
+
const middleSegmentIdx = Math.trunc((playlist.segments.length - 1) / 2);
|
|
2575
|
+
const middleSegmentUri = this.variableSubstitution_(
|
|
2576
|
+
playlist.segments[middleSegmentIdx].absoluteUri, variables);
|
|
2569
2577
|
|
|
2570
|
-
const parsedUri = new goog.Uri(
|
|
2578
|
+
const parsedUri = new goog.Uri(middleSegmentUri);
|
|
2571
2579
|
const extension = parsedUri.getPath().split('.').pop();
|
|
2572
2580
|
const map = HlsParser.EXTENSION_MAP_BY_CONTENT_TYPE_[contentType];
|
|
2573
2581
|
|
|
@@ -2598,7 +2606,7 @@ shaka.hls.HlsParser = class {
|
|
|
2598
2606
|
// If unable to guess mime type, request a segment and try getting it
|
|
2599
2607
|
// from the response.
|
|
2600
2608
|
const headRequest = shaka.net.NetworkingEngine.makeRequest(
|
|
2601
|
-
[
|
|
2609
|
+
[middleSegmentUri], this.config_.retryParameters);
|
|
2602
2610
|
headRequest.method = 'HEAD';
|
|
2603
2611
|
|
|
2604
2612
|
const response = await this.makeNetworkRequest_(
|
package/lib/media/drm_engine.js
CHANGED
|
@@ -1495,7 +1495,7 @@ shaka.media.DrmEngine = class {
|
|
|
1495
1495
|
if (shaka.media.DrmEngine.isPlayReadyKeySystem(
|
|
1496
1496
|
this.currentDrmInfo_.keySystem) &&
|
|
1497
1497
|
keyId.byteLength == 16 &&
|
|
1498
|
-
shaka.util.Platform.isEdge()) {
|
|
1498
|
+
(shaka.util.Platform.isEdge() || shaka.util.Platform.isPS4())) {
|
|
1499
1499
|
// Read out some fields in little-endian:
|
|
1500
1500
|
const dataView = shaka.util.BufferUtils.toDataView(keyId);
|
|
1501
1501
|
const part0 = dataView.getUint32(0, /* LE= */ true);
|
|
@@ -93,6 +93,9 @@ shaka.media.PresentationTimeline = class {
|
|
|
93
93
|
* @private {number}
|
|
94
94
|
*/
|
|
95
95
|
this.availabilityTimeOffset_ = 0;
|
|
96
|
+
|
|
97
|
+
/** @private {boolean} */
|
|
98
|
+
this.startTimeLocked_ = false;
|
|
96
99
|
}
|
|
97
100
|
|
|
98
101
|
|
|
@@ -229,7 +232,8 @@ shaka.media.PresentationTimeline = class {
|
|
|
229
232
|
this.maxSegmentEndTime_ =
|
|
230
233
|
Math.max(this.maxSegmentEndTime_, lastReferenceEndTime);
|
|
231
234
|
|
|
232
|
-
if (this.presentationStartTime_ != null && this.autoCorrectDrift_
|
|
235
|
+
if (this.presentationStartTime_ != null && this.autoCorrectDrift_ &&
|
|
236
|
+
!this.startTimeLocked_) {
|
|
233
237
|
// Since we have explicit segment end times, calculate a presentation
|
|
234
238
|
// start based on them. This start time accounts for drift.
|
|
235
239
|
// Date.now() is in milliseconds, from which we compute "now" in seconds.
|
|
@@ -243,6 +247,25 @@ shaka.media.PresentationTimeline = class {
|
|
|
243
247
|
}
|
|
244
248
|
|
|
245
249
|
|
|
250
|
+
/**
|
|
251
|
+
* Lock the presentation timeline's start time. After this is called, no
|
|
252
|
+
* further adjustments to presentationStartTime_ will be permitted.
|
|
253
|
+
*
|
|
254
|
+
* This should be called after all Periods have been parsed, and all calls to
|
|
255
|
+
* notifySegments() from the initial manifest parse have been made.
|
|
256
|
+
*
|
|
257
|
+
* Without this, we can get assertion failures in SegmentIndex for certain
|
|
258
|
+
* DAI content. If DAI adds ad segments to the manifest faster than
|
|
259
|
+
* real-time, adjustments to presentationStartTime_ can cause availability
|
|
260
|
+
* windows to jump around on updates.
|
|
261
|
+
*
|
|
262
|
+
* @export
|
|
263
|
+
*/
|
|
264
|
+
lockStartTime() {
|
|
265
|
+
this.startTimeLocked_ = true;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
|
|
246
269
|
/**
|
|
247
270
|
* Gives PresentationTimeline a Stream's minimum segment start time.
|
|
248
271
|
*
|
|
@@ -1754,6 +1754,7 @@ shaka.media.StreamingEngine = class {
|
|
|
1754
1754
|
*
|
|
1755
1755
|
* @return {!Promise.<BufferSource>}
|
|
1756
1756
|
* @private
|
|
1757
|
+
* @suppress {strictMissingProperties}
|
|
1757
1758
|
*/
|
|
1758
1759
|
async fetch_(mediaState, reference, streamDataCallback) {
|
|
1759
1760
|
const requestType = shaka.net.NetworkingEngine.RequestType.SEGMENT;
|
package/lib/player.js
CHANGED
|
@@ -792,14 +792,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
792
792
|
if (!window.Promise) {
|
|
793
793
|
shaka.log.alwaysWarn('A Promise implementation or polyfill is required');
|
|
794
794
|
}
|
|
795
|
-
if (!window.TextDecoder || !window.TextEncoder) {
|
|
796
|
-
shaka.log.alwaysWarn(
|
|
797
|
-
'A TextDecoder/TextEncoder implementation or polyfill is required');
|
|
798
|
-
}
|
|
799
795
|
|
|
800
796
|
// Basic features needed for the library to be usable.
|
|
801
797
|
const basicSupport = !!window.Promise && !!window.Uint8Array &&
|
|
802
|
-
!!window.TextDecoder && !!window.TextEncoder &&
|
|
803
798
|
// eslint-disable-next-line no-restricted-syntax
|
|
804
799
|
!!Array.prototype.forEach;
|
|
805
800
|
if (!basicSupport) {
|
|
@@ -6430,7 +6425,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6430
6425
|
* @define {string} A version number taken from git at compile time.
|
|
6431
6426
|
* @export
|
|
6432
6427
|
*/
|
|
6433
|
-
shaka.Player.version = 'v3.2.
|
|
6428
|
+
shaka.Player.version = 'v3.2.11-uncompiled';
|
|
6434
6429
|
|
|
6435
6430
|
// Initialize the deprecation system using the version string we just set
|
|
6436
6431
|
// on the player.
|
|
@@ -39,7 +39,10 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
39
39
|
// Browsers.
|
|
40
40
|
if (!shaka.util.Platform.isChromecast() &&
|
|
41
41
|
!shaka.util.Platform.isApple() &&
|
|
42
|
+
!shaka.util.Platform.isPS4() &&
|
|
42
43
|
!shaka.util.Platform.isPS5() &&
|
|
44
|
+
!shaka.util.Platform.isWebOS() &&
|
|
45
|
+
!shaka.util.Platform.isTizen() &&
|
|
43
46
|
navigator.mediaCapabilities) {
|
|
44
47
|
shaka.log.info(
|
|
45
48
|
'MediaCapabilities: Native mediaCapabilities support found.');
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
goog.provide('shaka.polyfill.VideoPlaybackQuality');
|
|
8
8
|
|
|
9
9
|
goog.require('shaka.polyfill');
|
|
10
|
+
goog.require('shaka.util.Platform');
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -33,7 +34,8 @@ shaka.polyfill.VideoPlaybackQuality = class {
|
|
|
33
34
|
return;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
if ('webkitDroppedFrameCount' in proto
|
|
37
|
+
if ('webkitDroppedFrameCount' in proto ||
|
|
38
|
+
shaka.util.Platform.isWebOS3()) {
|
|
37
39
|
proto.getVideoPlaybackQuality =
|
|
38
40
|
shaka.polyfill.VideoPlaybackQuality.webkit_;
|
|
39
41
|
}
|
package/lib/text/cue.js
CHANGED
|
@@ -41,14 +41,9 @@ shaka.text.Cue = class {
|
|
|
41
41
|
*/
|
|
42
42
|
this.endTime = endTime;
|
|
43
43
|
|
|
44
|
-
// The explicit type here is to work around an apparent compiler bug where
|
|
45
|
-
// the compiler seems to get confused about the type. Since we are
|
|
46
|
-
// overriding the interface type, it shouldn't be necessary to do this.
|
|
47
|
-
// Compiler version 20200517.
|
|
48
44
|
/**
|
|
49
45
|
* @override
|
|
50
46
|
* @exportInterface
|
|
51
|
-
* @type {string}
|
|
52
47
|
*/
|
|
53
48
|
this.payload = payload;
|
|
54
49
|
|
|
@@ -127,16 +127,28 @@ shaka.text.SimpleTextDisplayer = class {
|
|
|
127
127
|
// We don't want to modify the array or objects passed in, since we don't
|
|
128
128
|
// technically own them. So we build a new array and replace certain items
|
|
129
129
|
// in it if they need to be flattened.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
130
|
+
// We also don't want to flatten the text payloads starting at a container
|
|
131
|
+
// element; otherwise, for containers encapsulating multiple caption lines,
|
|
132
|
+
// the lines would merge into a single cue. This is undesirable when a
|
|
133
|
+
// subset of the captions are outside of the append time window. To fix
|
|
134
|
+
// this, we only call flattenPayload() starting at elements marked as
|
|
135
|
+
// isContainer = false.
|
|
136
|
+
const getCuesToFlatten = (cues, result) => {
|
|
137
|
+
for (const cue of cues) {
|
|
138
|
+
if (cue.isContainer) {
|
|
139
|
+
// Recurse to find the actual text payload cues.
|
|
140
|
+
getCuesToFlatten(cue.nestedCues, result);
|
|
141
|
+
} else {
|
|
142
|
+
// Flatten the payload.
|
|
143
|
+
const flatCue = cue.clone();
|
|
144
|
+
flatCue.nestedCues = [];
|
|
145
|
+
flatCue.payload = flattenPayload(cue);
|
|
146
|
+
result.push(flatCue);
|
|
147
|
+
}
|
|
138
148
|
}
|
|
139
|
-
|
|
149
|
+
return result;
|
|
150
|
+
};
|
|
151
|
+
const flattenedCues = getCuesToFlatten(cues, []);
|
|
140
152
|
|
|
141
153
|
// Convert cues.
|
|
142
154
|
const textTrackCues = [];
|
|
@@ -78,6 +78,7 @@ shaka.text.UITextDisplayer = class {
|
|
|
78
78
|
* the cue (e.g. the HTML element to put nested cues inside).
|
|
79
79
|
* @private {Map.<!shaka.extern.Cue, !{
|
|
80
80
|
* cueElement: !HTMLElement,
|
|
81
|
+
* regionElement: HTMLElement,
|
|
81
82
|
* wrapper: !HTMLElement
|
|
82
83
|
* }>}
|
|
83
84
|
*/
|
|
@@ -98,6 +99,9 @@ shaka.text.UITextDisplayer = class {
|
|
|
98
99
|
});
|
|
99
100
|
this.resizeObserver_.observe(this.textContainer_);
|
|
100
101
|
}
|
|
102
|
+
|
|
103
|
+
/** @private {Map.<string, !HTMLElement>} */
|
|
104
|
+
this.regionElements_ = new Map();
|
|
101
105
|
}
|
|
102
106
|
|
|
103
107
|
|
|
@@ -235,6 +239,11 @@ shaka.text.UITextDisplayer = class {
|
|
|
235
239
|
// even ones which are going to be planted again.
|
|
236
240
|
toUproot.push(cueRegistry.cueElement);
|
|
237
241
|
|
|
242
|
+
// Also uproot all displayed region elements.
|
|
243
|
+
if (cueRegistry.regionElement) {
|
|
244
|
+
toUproot.push(cueRegistry.regionElement);
|
|
245
|
+
}
|
|
246
|
+
|
|
238
247
|
// If the cue should not be displayed, remove it entirely.
|
|
239
248
|
if (!shouldBeDisplayed) {
|
|
240
249
|
// Since something has to be removed, we will need to update the DOM.
|
|
@@ -269,8 +278,12 @@ shaka.text.UITextDisplayer = class {
|
|
|
269
278
|
goog.asserts.assert(topCue == cue, 'Parent cues should be kept in order');
|
|
270
279
|
}
|
|
271
280
|
if (updateDOM) {
|
|
272
|
-
for (const
|
|
273
|
-
|
|
281
|
+
for (const element of toUproot) {
|
|
282
|
+
// NOTE: Because we uproot shared region elements, too, we might hit an
|
|
283
|
+
// element here that has no parent because we've already processed it.
|
|
284
|
+
if (element.parentElement) {
|
|
285
|
+
element.parentElement.removeChild(element);
|
|
286
|
+
}
|
|
274
287
|
}
|
|
275
288
|
toPlant.sort((a, b) => {
|
|
276
289
|
if (a.startTime != b.startTime) {
|
|
@@ -282,7 +295,12 @@ shaka.text.UITextDisplayer = class {
|
|
|
282
295
|
for (const cue of toPlant) {
|
|
283
296
|
const cueRegistry = this.currentCuesMap_.get(cue);
|
|
284
297
|
goog.asserts.assert(cueRegistry, 'cueRegistry should exist.');
|
|
285
|
-
|
|
298
|
+
if (cueRegistry.regionElement) {
|
|
299
|
+
container.appendChild(cueRegistry.regionElement);
|
|
300
|
+
cueRegistry.regionElement.appendChild(cueRegistry.cueElement);
|
|
301
|
+
} else {
|
|
302
|
+
container.appendChild(cueRegistry.cueElement);
|
|
303
|
+
}
|
|
286
304
|
}
|
|
287
305
|
}
|
|
288
306
|
}
|
|
@@ -299,11 +317,15 @@ shaka.text.UITextDisplayer = class {
|
|
|
299
317
|
|
|
300
318
|
const currentTime = this.video_.currentTime;
|
|
301
319
|
if (!this.isTextVisible_ || forceUpdate) {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
shaka.util.Dom.removeAllChildren(
|
|
305
|
-
this.currentCuesMap_.clear();
|
|
320
|
+
// Remove child elements from all regions.
|
|
321
|
+
for (const regionElement of this.regionElements_.values()) {
|
|
322
|
+
shaka.util.Dom.removeAllChildren(regionElement);
|
|
306
323
|
}
|
|
324
|
+
// Remove all top-level elements in the text container.
|
|
325
|
+
shaka.util.Dom.removeAllChildren(this.textContainer_);
|
|
326
|
+
// Clear the element maps.
|
|
327
|
+
this.currentCuesMap_.clear();
|
|
328
|
+
this.regionElements_.clear();
|
|
307
329
|
}
|
|
308
330
|
if (this.isTextVisible_) {
|
|
309
331
|
// Log currently attached cue elements for verification, later.
|
|
@@ -333,6 +355,54 @@ shaka.text.UITextDisplayer = class {
|
|
|
333
355
|
}
|
|
334
356
|
}
|
|
335
357
|
|
|
358
|
+
/**
|
|
359
|
+
* Get or create a region element corresponding to the cue region. These are
|
|
360
|
+
* cached by ID.
|
|
361
|
+
*
|
|
362
|
+
* @param {!shaka.extern.Cue} cue
|
|
363
|
+
* @return {!HTMLElement}
|
|
364
|
+
* @private
|
|
365
|
+
*/
|
|
366
|
+
getRegionElement_(cue) {
|
|
367
|
+
const region = cue.region;
|
|
368
|
+
|
|
369
|
+
if (this.regionElements_.has(region.id)) {
|
|
370
|
+
return this.regionElements_.get(region.id);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const regionElement = shaka.util.Dom.createHTMLElement('span');
|
|
374
|
+
|
|
375
|
+
const percentageUnit = shaka.text.CueRegion.units.PERCENTAGE;
|
|
376
|
+
const heightUnit = region.heightUnits == percentageUnit ? '%' : 'px';
|
|
377
|
+
const widthUnit = region.widthUnits == percentageUnit ? '%' : 'px';
|
|
378
|
+
const viewportAnchorUnit =
|
|
379
|
+
region.viewportAnchorUnits == percentageUnit ? '%' : 'px';
|
|
380
|
+
|
|
381
|
+
regionElement.id = 'shaka-text-region---' + region.id;
|
|
382
|
+
regionElement.classList.add('shaka-text-region');
|
|
383
|
+
|
|
384
|
+
regionElement.style.height = region.height + heightUnit;
|
|
385
|
+
regionElement.style.width = region.width + widthUnit;
|
|
386
|
+
regionElement.style.position = 'absolute';
|
|
387
|
+
regionElement.style.top = region.viewportAnchorY + viewportAnchorUnit;
|
|
388
|
+
regionElement.style.left = region.viewportAnchorX + viewportAnchorUnit;
|
|
389
|
+
|
|
390
|
+
regionElement.style.display = 'flex';
|
|
391
|
+
regionElement.style.flexDirection = 'column';
|
|
392
|
+
regionElement.style.alignItems = 'center';
|
|
393
|
+
|
|
394
|
+
if (cue.displayAlign == shaka.text.Cue.displayAlign.BEFORE) {
|
|
395
|
+
regionElement.style.justifyContent = 'flex-start';
|
|
396
|
+
} else if (cue.displayAlign == shaka.text.Cue.displayAlign.CENTER) {
|
|
397
|
+
regionElement.style.justifyContent = 'center';
|
|
398
|
+
} else {
|
|
399
|
+
regionElement.style.justifyContent = 'flex-end';
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
this.regionElements_.set(region.id, regionElement);
|
|
403
|
+
return regionElement;
|
|
404
|
+
}
|
|
405
|
+
|
|
336
406
|
/**
|
|
337
407
|
* Creates the object for a cue.
|
|
338
408
|
*
|
|
@@ -360,6 +430,11 @@ shaka.text.UITextDisplayer = class {
|
|
|
360
430
|
this.setCaptionStyles_(cueElement, cue, parents, needWrapper);
|
|
361
431
|
}
|
|
362
432
|
|
|
433
|
+
let regionElement = null;
|
|
434
|
+
if (cue.region && cue.region.id) {
|
|
435
|
+
regionElement = this.getRegionElement_(cue);
|
|
436
|
+
}
|
|
437
|
+
|
|
363
438
|
let wrapper = cueElement;
|
|
364
439
|
if (needWrapper) {
|
|
365
440
|
// Create a wrapper element which will serve to contain all children into
|
|
@@ -371,7 +446,7 @@ shaka.text.UITextDisplayer = class {
|
|
|
371
446
|
cueElement.appendChild(wrapper);
|
|
372
447
|
}
|
|
373
448
|
|
|
374
|
-
this.currentCuesMap_.set(cue, {cueElement, wrapper});
|
|
449
|
+
this.currentCuesMap_.set(cue, {cueElement, wrapper, regionElement});
|
|
375
450
|
}
|
|
376
451
|
|
|
377
452
|
/**
|
|
@@ -531,17 +606,6 @@ shaka.text.UITextDisplayer = class {
|
|
|
531
606
|
}
|
|
532
607
|
}
|
|
533
608
|
}
|
|
534
|
-
} else if (cue.region && cue.region.id) {
|
|
535
|
-
const percentageUnit = shaka.text.CueRegion.units.PERCENTAGE;
|
|
536
|
-
const heightUnit = cue.region.heightUnits == percentageUnit ? '%' : 'px';
|
|
537
|
-
const widthUnit = cue.region.widthUnits == percentageUnit ? '%' : 'px';
|
|
538
|
-
const viewportAnchorUnit =
|
|
539
|
-
cue.region.viewportAnchorUnits == percentageUnit ? '%' : 'px';
|
|
540
|
-
style.height = cue.region.height + heightUnit;
|
|
541
|
-
style.width = cue.region.width + widthUnit;
|
|
542
|
-
style.position = 'absolute';
|
|
543
|
-
style.top = cue.region.viewportAnchorY + viewportAnchorUnit;
|
|
544
|
-
style.left = cue.region.viewportAnchorX + viewportAnchorUnit;
|
|
545
609
|
}
|
|
546
610
|
|
|
547
611
|
style.lineHeight = cue.lineHeight;
|
package/lib/util/buffer_utils.js
CHANGED
|
@@ -20,6 +20,7 @@ shaka.util.BufferUtils = class {
|
|
|
20
20
|
* @param {?BufferSource} arr2
|
|
21
21
|
* @return {boolean}
|
|
22
22
|
* @export
|
|
23
|
+
* @suppress {strictMissingProperties}
|
|
23
24
|
*/
|
|
24
25
|
static equal(arr1, arr2) {
|
|
25
26
|
const BufferUtils = shaka.util.BufferUtils;
|
|
@@ -135,8 +136,10 @@ shaka.util.BufferUtils = class {
|
|
|
135
136
|
static view_(data, offset, length, Type) {
|
|
136
137
|
const buffer = shaka.util.BufferUtils.unsafeGetArrayBuffer_(data);
|
|
137
138
|
// Absolute end of the |data| view within |buffer|.
|
|
139
|
+
/** @suppress {strictMissingProperties} */
|
|
138
140
|
const dataEnd = (data.byteOffset || 0) + data.byteLength;
|
|
139
141
|
// Absolute start of the result within |buffer|.
|
|
142
|
+
/** @suppress {strictMissingProperties} */
|
|
140
143
|
const rawStart = (data.byteOffset || 0) + offset;
|
|
141
144
|
const start = Math.max(0, Math.min(rawStart, dataEnd));
|
|
142
145
|
// Absolute end of the result within |buffer|.
|
package/lib/util/object_utils.js
CHANGED
|
@@ -22,6 +22,7 @@ shaka.util.ObjectUtils = class {
|
|
|
22
22
|
const seenObjects = new Set();
|
|
23
23
|
// This recursively clones the value |val|, using the captured variable
|
|
24
24
|
// |seenObjects| to track the objects we have already cloned.
|
|
25
|
+
/** @suppress {strictMissingProperties} */
|
|
25
26
|
const clone = (val) => {
|
|
26
27
|
switch (typeof val) {
|
|
27
28
|
case 'undefined':
|
package/lib/util/platform.js
CHANGED
|
@@ -142,6 +142,18 @@ shaka.util.Platform = class {
|
|
|
142
142
|
return shaka.util.Platform.userAgentContains_('Web0S');
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
+
/**
|
|
146
|
+
* Check if the current platform is a WebOS 3.
|
|
147
|
+
*
|
|
148
|
+
* @return {boolean}
|
|
149
|
+
*/
|
|
150
|
+
static isWebOS3() {
|
|
151
|
+
// See: http://webostv.developer.lge.com/discover/specifications/web-engine/
|
|
152
|
+
return shaka.util.Platform.userAgentContains_('Web0S') &&
|
|
153
|
+
shaka.util.Platform.userAgentContains_(
|
|
154
|
+
'Chrome/38.0.2125.122 Safari/537.36');
|
|
155
|
+
}
|
|
156
|
+
|
|
145
157
|
/**
|
|
146
158
|
* Check if the current platform is a Google Chromecast.
|
|
147
159
|
*
|
|
@@ -175,7 +187,9 @@ shaka.util.Platform = class {
|
|
|
175
187
|
*/
|
|
176
188
|
static isApple() {
|
|
177
189
|
return !!navigator.vendor && navigator.vendor.includes('Apple') &&
|
|
178
|
-
!shaka.util.Platform.isTizen()
|
|
190
|
+
!shaka.util.Platform.isTizen() &&
|
|
191
|
+
!shaka.util.Platform.isEOS() &&
|
|
192
|
+
!shaka.util.Platform.isPS4();
|
|
179
193
|
}
|
|
180
194
|
|
|
181
195
|
/**
|
|
@@ -191,6 +205,13 @@ shaka.util.Platform = class {
|
|
|
191
205
|
return shaka.util.Platform.userAgentContains_('PlayStation 5');
|
|
192
206
|
}
|
|
193
207
|
|
|
208
|
+
/**
|
|
209
|
+
* Check if the current platform is Playstation 4.
|
|
210
|
+
*/
|
|
211
|
+
static isPS4() {
|
|
212
|
+
return shaka.util.Platform.userAgentContains_('PlayStation 4');
|
|
213
|
+
}
|
|
214
|
+
|
|
194
215
|
/**
|
|
195
216
|
* Returns a major version number for Safari, or Safari-based iOS browsers.
|
|
196
217
|
*
|
|
@@ -228,6 +249,25 @@ shaka.util.Platform = class {
|
|
|
228
249
|
return null;
|
|
229
250
|
}
|
|
230
251
|
|
|
252
|
+
/**
|
|
253
|
+
* Check if the current platform is Apple Safari
|
|
254
|
+
* or Safari-based iOS browsers.
|
|
255
|
+
*
|
|
256
|
+
* @return {boolean}
|
|
257
|
+
*/
|
|
258
|
+
static isSafari() {
|
|
259
|
+
return !!shaka.util.Platform.safariVersion();
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Check if the current platform is an EOS set-top box.
|
|
264
|
+
*
|
|
265
|
+
* @return {boolean}
|
|
266
|
+
*/
|
|
267
|
+
static isEOS() {
|
|
268
|
+
return shaka.util.Platform.userAgentContains_('PC=EOS');
|
|
269
|
+
}
|
|
270
|
+
|
|
231
271
|
/**
|
|
232
272
|
* Guesses if the platform is a mobile one (iOS or Android).
|
|
233
273
|
*
|
package/lib/util/stream_utils.js
CHANGED
|
@@ -578,8 +578,16 @@ shaka.util.StreamUtils = class {
|
|
|
578
578
|
// VideoConfiguration
|
|
579
579
|
mediaDecodingConfig.video = {
|
|
580
580
|
contentType: fullType,
|
|
581
|
-
|
|
582
|
-
|
|
581
|
+
|
|
582
|
+
// NOTE: Some decoders strictly check the width and height fields and
|
|
583
|
+
// won't decode smaller than 64x64. So if we don't have this info (as
|
|
584
|
+
// is the case in some of our simpler tests), assume a 64x64 resolution
|
|
585
|
+
// to fill in this required field for MediaCapabilities.
|
|
586
|
+
//
|
|
587
|
+
// This became an issue specifically on Firefox on M1 Macs.
|
|
588
|
+
width: video.width || 64,
|
|
589
|
+
height: video.height || 64,
|
|
590
|
+
|
|
583
591
|
bitrate: video.bandwidth || variant.bandwidth || 1,
|
|
584
592
|
// framerate must be greater than 0, otherwise the config is invalid.
|
|
585
593
|
framerate: video.frameRate || 1,
|
|
@@ -742,7 +750,19 @@ shaka.util.StreamUtils = class {
|
|
|
742
750
|
*/
|
|
743
751
|
static patchVp9(codec) {
|
|
744
752
|
if (codec == 'vp9') {
|
|
745
|
-
|
|
753
|
+
// This means profile 0, level 4.1, 8-bit color. This supports 1080p @
|
|
754
|
+
// 60Hz. See https://en.wikipedia.org/wiki/VP9#Levels
|
|
755
|
+
//
|
|
756
|
+
// If we don't have more detailed codec info, assume this profile and
|
|
757
|
+
// level because it's high enough to likely accommodate the parameters we
|
|
758
|
+
// do have, such as width and height. If an implementation is checking
|
|
759
|
+
// the profile and level very strictly, we want older VP9 content to
|
|
760
|
+
// still work to some degree. But we don't want to set a level so high
|
|
761
|
+
// that it is rejected by a hardware decoder that can't handle the
|
|
762
|
+
// maximum requirements of the level.
|
|
763
|
+
//
|
|
764
|
+
// This became an issue specifically on Firefox on M1 Macs.
|
|
765
|
+
return 'vp09.00.41.08';
|
|
746
766
|
}
|
|
747
767
|
return codec;
|
|
748
768
|
}
|
|
@@ -981,6 +1001,7 @@ shaka.util.StreamUtils = class {
|
|
|
981
1001
|
track.channelsCount = audio.channelsCount;
|
|
982
1002
|
track.audioSamplingRate = audio.audioSamplingRate;
|
|
983
1003
|
track.audioBandwidth = audio.bandwidth || null;
|
|
1004
|
+
track.spatialAudio = audio.spatialAudio;
|
|
984
1005
|
track.label = audio.label;
|
|
985
1006
|
track.audioRoles = audio.roles;
|
|
986
1007
|
}
|