shaka-player 4.1.0 → 4.1.3
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 +2 -0
- package/CHANGELOG.md +42 -0
- package/CONTRIBUTORS +4 -0
- package/README.md +20 -6
- package/demo/common/assets.js +1 -1
- package/demo/index.html +1 -3
- 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 +3 -3
- 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 +52 -40
- package/dist/shaka-player.compiled.debug.js +270 -257
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +52 -40
- package/dist/shaka-player.compiled.js +754 -746
- 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 +52 -40
- package/dist/shaka-player.ui.debug.js +296 -283
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +52 -40
- package/dist/shaka-player.ui.js +874 -867
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/ui.md +6 -6
- package/docs/tutorials/upgrade.md +1 -0
- package/docs/tutorials/welcome.md +6 -3
- package/externs/shaka/player.js +4 -2
- package/karma.conf.js +3 -11
- package/lib/ads/client_side_ad_manager.js +1 -1
- package/lib/dash/dash_parser.js +5 -0
- package/lib/hls/hls_parser.js +183 -70
- package/lib/media/drm_engine.js +1 -1
- package/lib/media/media_source_engine.js +57 -24
- package/lib/media/presentation_timeline.js +24 -1
- package/lib/media/segment_index.js +26 -1
- package/lib/media/segment_reference.js +10 -3
- package/lib/media/streaming_engine.js +4 -4
- package/lib/media/time_ranges_utils.js +46 -0
- package/lib/player.js +1 -6
- package/lib/polyfill/media_capabilities.js +9 -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 +19 -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 +3 -5
- package/test/hls/hls_parser_unit.js +102 -8
- package/test/media/drm_engine_integration.js +24 -8
- package/test/media/media_source_engine_integration.js +24 -10
- package/test/media/media_source_engine_unit.js +53 -38
- package/test/media/streaming_engine_unit.js +28 -27
- package/test/test/util/fake_media_source_engine.js +10 -9
- 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/ui/text_selection.js +2 -2
- 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 -28
- package/app-engine/demo-version-index/generate.py +0 -164
- package/app-engine/demo-version-index/main.py +0 -11
- package/app-engine/demo-version-index/requirements.txt +0 -5
- 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 -335
- 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 -39
- package/build/pixelsChanged.js +0 -35
- package/build/shaka-lab.yaml +0 -161
- 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 -108
- 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 -22
- package/build/types/polyfill +0 -18
- package/build/types/text +0 -11
- package/build/types/ui +0 -39
- package/build/updateScreenshots.py +0 -85
- package/build/wrapper.template.js +0 -52
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
|
@@ -197,7 +197,9 @@ shaka.util.Platform = class {
|
|
|
197
197
|
*/
|
|
198
198
|
static isApple() {
|
|
199
199
|
return !!navigator.vendor && navigator.vendor.includes('Apple') &&
|
|
200
|
-
!shaka.util.Platform.isTizen()
|
|
200
|
+
!shaka.util.Platform.isTizen() &&
|
|
201
|
+
!shaka.util.Platform.isEOS() &&
|
|
202
|
+
!shaka.util.Platform.isPS4();
|
|
201
203
|
}
|
|
202
204
|
|
|
203
205
|
/**
|
|
@@ -213,6 +215,13 @@ shaka.util.Platform = class {
|
|
|
213
215
|
return shaka.util.Platform.userAgentContains_('PlayStation 5');
|
|
214
216
|
}
|
|
215
217
|
|
|
218
|
+
/**
|
|
219
|
+
* Check if the current platform is Playstation 4.
|
|
220
|
+
*/
|
|
221
|
+
static isPS4() {
|
|
222
|
+
return shaka.util.Platform.userAgentContains_('PlayStation 4');
|
|
223
|
+
}
|
|
224
|
+
|
|
216
225
|
/**
|
|
217
226
|
* Returns a major version number for Safari, or Safari-based iOS browsers.
|
|
218
227
|
*
|
|
@@ -260,6 +269,15 @@ shaka.util.Platform = class {
|
|
|
260
269
|
return !!shaka.util.Platform.safariVersion();
|
|
261
270
|
}
|
|
262
271
|
|
|
272
|
+
/**
|
|
273
|
+
* Check if the current platform is an EOS set-top box.
|
|
274
|
+
*
|
|
275
|
+
* @return {boolean}
|
|
276
|
+
*/
|
|
277
|
+
static isEOS() {
|
|
278
|
+
return shaka.util.Platform.userAgentContains_('PC=EOS');
|
|
279
|
+
}
|
|
280
|
+
|
|
263
281
|
/**
|
|
264
282
|
* Guesses if the platform is a mobile one (iOS or Android).
|
|
265
283
|
*
|
package/lib/util/stream_utils.js
CHANGED
|
@@ -585,8 +585,16 @@ shaka.util.StreamUtils = class {
|
|
|
585
585
|
// VideoConfiguration
|
|
586
586
|
mediaDecodingConfig.video = {
|
|
587
587
|
contentType: fullType,
|
|
588
|
-
|
|
589
|
-
|
|
588
|
+
|
|
589
|
+
// NOTE: Some decoders strictly check the width and height fields and
|
|
590
|
+
// won't decode smaller than 64x64. So if we don't have this info (as
|
|
591
|
+
// is the case in some of our simpler tests), assume a 64x64 resolution
|
|
592
|
+
// to fill in this required field for MediaCapabilities.
|
|
593
|
+
//
|
|
594
|
+
// This became an issue specifically on Firefox on M1 Macs.
|
|
595
|
+
width: video.width || 64,
|
|
596
|
+
height: video.height || 64,
|
|
597
|
+
|
|
590
598
|
bitrate: video.bandwidth || variant.bandwidth || 1,
|
|
591
599
|
// framerate must be greater than 0, otherwise the config is invalid.
|
|
592
600
|
framerate: video.frameRate || 1,
|
|
@@ -749,7 +757,19 @@ shaka.util.StreamUtils = class {
|
|
|
749
757
|
*/
|
|
750
758
|
static patchVp9(codec) {
|
|
751
759
|
if (codec == 'vp9') {
|
|
752
|
-
|
|
760
|
+
// This means profile 0, level 4.1, 8-bit color. This supports 1080p @
|
|
761
|
+
// 60Hz. See https://en.wikipedia.org/wiki/VP9#Levels
|
|
762
|
+
//
|
|
763
|
+
// If we don't have more detailed codec info, assume this profile and
|
|
764
|
+
// level because it's high enough to likely accommodate the parameters we
|
|
765
|
+
// do have, such as width and height. If an implementation is checking
|
|
766
|
+
// the profile and level very strictly, we want older VP9 content to
|
|
767
|
+
// still work to some degree. But we don't want to set a level so high
|
|
768
|
+
// that it is rejected by a hardware decoder that can't handle the
|
|
769
|
+
// maximum requirements of the level.
|
|
770
|
+
//
|
|
771
|
+
// This became an issue specifically on Firefox on M1 Macs.
|
|
772
|
+
return 'vp09.00.41.08';
|
|
753
773
|
}
|
|
754
774
|
return codec;
|
|
755
775
|
}
|
|
@@ -1015,6 +1035,7 @@ shaka.util.StreamUtils = class {
|
|
|
1015
1035
|
track.channelsCount = audio.channelsCount;
|
|
1016
1036
|
track.audioSamplingRate = audio.audioSamplingRate;
|
|
1017
1037
|
track.audioBandwidth = audio.bandwidth || null;
|
|
1038
|
+
track.spatialAudio = audio.spatialAudio;
|
|
1018
1039
|
track.label = audio.label;
|
|
1019
1040
|
track.audioRoles = audio.roles;
|
|
1020
1041
|
}
|
package/lib/util/string_utils.js
CHANGED
|
@@ -11,6 +11,7 @@ goog.require('shaka.log');
|
|
|
11
11
|
goog.require('shaka.util.BufferUtils');
|
|
12
12
|
goog.require('shaka.util.Error');
|
|
13
13
|
goog.require('shaka.util.Lazy');
|
|
14
|
+
goog.require('shaka.util.Platform');
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
/**
|
|
@@ -37,18 +38,84 @@ shaka.util.StringUtils = class {
|
|
|
37
38
|
uint8 = uint8.subarray(3);
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
if (window.TextDecoder && !shaka.util.Platform.isPS4()) {
|
|
42
|
+
// Use the TextDecoder interface to decode the text. This has the
|
|
43
|
+
// advantage compared to the previously-standard decodeUriComponent that
|
|
44
|
+
// it will continue parsing even if it finds an invalid UTF8 character,
|
|
45
|
+
// rather than stop and throw an error.
|
|
46
|
+
const utf8decoder = new TextDecoder();
|
|
47
|
+
const decoded = utf8decoder.decode(uint8);
|
|
48
|
+
if (decoded.includes('\uFFFD')) {
|
|
49
|
+
shaka.log.alwaysError('Decoded string contains an "unknown character' +
|
|
50
|
+
'" codepoint. That probably means the UTF8 ' +
|
|
51
|
+
'encoding was incorrect!');
|
|
52
|
+
}
|
|
53
|
+
return decoded;
|
|
54
|
+
} else {
|
|
55
|
+
// Homebrewed UTF-8 decoder based on
|
|
56
|
+
// https://en.wikipedia.org/wiki/UTF-8#Encoding
|
|
57
|
+
// Unlike decodeURIComponent, won't throw on bad encoding.
|
|
58
|
+
// In this way, it is similar to TextDecoder.
|
|
59
|
+
|
|
60
|
+
let decoded = '';
|
|
61
|
+
for (let i = 0; i < uint8.length; ++i) {
|
|
62
|
+
// By default, the "replacement character" codepoint.
|
|
63
|
+
let codePoint = 0xFFFD;
|
|
64
|
+
|
|
65
|
+
// Top bit is 0, 1-byte encoding.
|
|
66
|
+
if ((uint8[i] & 0x80) == 0) {
|
|
67
|
+
codePoint = uint8[i];
|
|
68
|
+
|
|
69
|
+
// Top 3 bits of byte 0 are 110, top 2 bits of byte 1 are 10,
|
|
70
|
+
// 2-byte encoding.
|
|
71
|
+
} else if (uint8.length >= i + 2 &&
|
|
72
|
+
(uint8[i] & 0xe0) == 0xc0 &&
|
|
73
|
+
(uint8[i + 1] & 0xc0) == 0x80) {
|
|
74
|
+
codePoint = ((uint8[i] & 0x1f) << 6) |
|
|
75
|
+
((uint8[i + 1] & 0x3f));
|
|
76
|
+
i += 1; // Consume one extra byte.
|
|
77
|
+
|
|
78
|
+
// Top 4 bits of byte 0 are 1110, top 2 bits of byte 1 and 2 are 10,
|
|
79
|
+
// 3-byte encoding.
|
|
80
|
+
} else if (uint8.length >= i + 3 &&
|
|
81
|
+
(uint8[i] & 0xf0) == 0xe0 &&
|
|
82
|
+
(uint8[i + 1] & 0xc0) == 0x80 &&
|
|
83
|
+
(uint8[i + 2] & 0xc0) == 0x80) {
|
|
84
|
+
codePoint = ((uint8[i] & 0x0f) << 12) |
|
|
85
|
+
((uint8[i + 1] & 0x3f) << 6) |
|
|
86
|
+
((uint8[i + 2] & 0x3f));
|
|
87
|
+
i += 2; // Consume two extra bytes.
|
|
88
|
+
|
|
89
|
+
// Top 5 bits of byte 0 are 11110, top 2 bits of byte 1, 2 and 3 are 10,
|
|
90
|
+
// 4-byte encoding.
|
|
91
|
+
} else if (uint8.length >= i + 4 &&
|
|
92
|
+
(uint8[i] & 0xf1) == 0xf0 &&
|
|
93
|
+
(uint8[i + 1] & 0xc0) == 0x80 &&
|
|
94
|
+
(uint8[i + 2] & 0xc0) == 0x80 &&
|
|
95
|
+
(uint8[i + 3] & 0xc0) == 0x80) {
|
|
96
|
+
codePoint = ((uint8[i] & 0x07) << 18) |
|
|
97
|
+
((uint8[i + 1] & 0x3f) << 12) |
|
|
98
|
+
((uint8[i + 2] & 0x3f) << 6) |
|
|
99
|
+
((uint8[i + 3] & 0x3f));
|
|
100
|
+
i += 3; // Consume three extra bytes.
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// JavaScript strings are a series of UTF-16 characters.
|
|
104
|
+
if (codePoint <= 0xffff) {
|
|
105
|
+
decoded += String.fromCharCode(codePoint);
|
|
106
|
+
} else {
|
|
107
|
+
// UTF-16 surrogate-pair encoding, based on
|
|
108
|
+
// https://en.wikipedia.org/wiki/UTF-16#Description
|
|
109
|
+
const baseCodePoint = codePoint - 0x10000;
|
|
110
|
+
const highPart = baseCodePoint >> 10;
|
|
111
|
+
const lowPart = baseCodePoint & 0x3ff;
|
|
112
|
+
decoded += String.fromCharCode(0xd800 + highPart);
|
|
113
|
+
decoded += String.fromCharCode(0xdc00 + lowPart);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return decoded;
|
|
50
118
|
}
|
|
51
|
-
return decoded;
|
|
52
119
|
}
|
|
53
120
|
|
|
54
121
|
|
|
@@ -141,8 +208,30 @@ shaka.util.StringUtils = class {
|
|
|
141
208
|
* @export
|
|
142
209
|
*/
|
|
143
210
|
static toUTF8(str) {
|
|
144
|
-
|
|
145
|
-
|
|
211
|
+
if (window.TextEncoder && !shaka.util.Platform.isPS4()) {
|
|
212
|
+
const utf8Encoder = new TextEncoder();
|
|
213
|
+
return shaka.util.BufferUtils.toArrayBuffer(utf8Encoder.encode(str));
|
|
214
|
+
} else {
|
|
215
|
+
// http://stackoverflow.com/a/13691499
|
|
216
|
+
// Converts the given string to a URI encoded string. If a character
|
|
217
|
+
// falls in the ASCII range, it is not converted; otherwise it will be
|
|
218
|
+
// converted to a series of URI escape sequences according to UTF-8.
|
|
219
|
+
// Example: 'g#€' -> 'g#%E3%82%AC'
|
|
220
|
+
const encoded = encodeURIComponent(str);
|
|
221
|
+
// Convert each escape sequence individually into a character. Each
|
|
222
|
+
// escape sequence is interpreted as a code-point, so if an escape
|
|
223
|
+
// sequence happens to be part of a multi-byte sequence, each byte will
|
|
224
|
+
// be converted to a single character.
|
|
225
|
+
// Example: 'g#%E3%82%AC' -> '\x67\x35\xe3\x82\xac'
|
|
226
|
+
const utf8 = unescape(encoded);
|
|
227
|
+
|
|
228
|
+
const result = new Uint8Array(utf8.length);
|
|
229
|
+
for (let i = 0; i < utf8.length; i++) {
|
|
230
|
+
const item = utf8[i];
|
|
231
|
+
result[i] = item.charCodeAt(0);
|
|
232
|
+
}
|
|
233
|
+
return shaka.util.BufferUtils.toArrayBuffer(result);
|
|
234
|
+
}
|
|
146
235
|
}
|
|
147
236
|
|
|
148
237
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Maintained Shaka Player Branches
|
|
2
|
+
|
|
3
|
+
We are currently maintaining the following branches of Shaka Player:
|
|
4
|
+
|
|
5
|
+
- v4.1 (latest)
|
|
6
|
+
- v4.0 (previous)
|
|
7
|
+
- v3.3 (LTS until April 30, 2023)
|
|
8
|
+
- v3.2 (in use by the Cast Application Framework)
|
|
9
|
+
|
|
10
|
+
Other branches are no longer receiving bug fixes, and we recommend you upgrade
|
|
11
|
+
to a maintained branch. For details on upgrading, please see our
|
|
12
|
+
[upgrade guide](https://shaka-player-demo.appspot.com/docs/api/tutorial-upgrade.html).
|
|
13
|
+
|
|
14
|
+
For more information on how these branches are chosen, please refer to our
|
|
15
|
+
[Branch Maintenance Policy](https://shaka-project.github.io/maintenance/shaka-player.html#branch-maintenance-policy).
|
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.1.
|
|
4
|
+
"version": "4.1.3",
|
|
5
5
|
"homepage": "https://github.com/shaka-project/shaka-player",
|
|
6
6
|
"author": "Google",
|
|
7
7
|
"maintainers": [
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
"eslint-config-google": "^0.14.0",
|
|
28
28
|
"eslint-plugin-shaka-rules": "file:./build/eslint-plugin-shaka-rules",
|
|
29
29
|
"esprima": "^4.0.1",
|
|
30
|
-
"fastestsmallesttextencoderdecoder": "^1.0.22",
|
|
31
30
|
"fontfaceonload": "^1.0.2",
|
|
32
31
|
"google-closure-compiler-java": "^20220301.0.0",
|
|
33
32
|
"google-closure-deps": "https://gitpkg.now.sh/google/closure-library/closure-deps?d7736da6",
|
|
@@ -50,7 +49,7 @@
|
|
|
50
49
|
"less": "https://gitpkg.now.sh/joeyparrish/less.js/packages/less?28c63a43",
|
|
51
50
|
"less-plugin-clean-css": "github:austingardner/less-plugin-clean-css#4e9e77bf",
|
|
52
51
|
"material-design-lite": "^1.3.0",
|
|
53
|
-
"mux.js": "^6.
|
|
52
|
+
"mux.js": "^6.2.0",
|
|
54
53
|
"open-sans-fonts": "^1.6.2",
|
|
55
54
|
"postcss-less": "^6.0.0",
|
|
56
55
|
"pwacompat": "^2.0.17",
|
|
@@ -71,7 +70,6 @@
|
|
|
71
70
|
"dialog-polyfill/dist/dialog-polyfill.js",
|
|
72
71
|
"eme-encryption-scheme-polyfill/index.js",
|
|
73
72
|
"es6-promise-polyfill/promise.min.js",
|
|
74
|
-
"fastestsmallesttextencoderdecoder/EncoderDecoderTogether.min.js",
|
|
75
73
|
"google-closure-library/closure/goog/base.js",
|
|
76
74
|
"less/dist/less.js",
|
|
77
75
|
"material-design-lite/dist/material.indigo-blue.min.css",
|
|
@@ -96,7 +94,7 @@
|
|
|
96
94
|
"prepublishOnly": "python build/checkversion.py && python build/all.py --force"
|
|
97
95
|
},
|
|
98
96
|
"dependencies": {
|
|
99
|
-
"eme-encryption-scheme-polyfill": "^2.
|
|
97
|
+
"eme-encryption-scheme-polyfill": "^2.1.1"
|
|
100
98
|
},
|
|
101
99
|
"engines": {
|
|
102
100
|
"node": ">=14"
|
|
@@ -2021,6 +2021,10 @@ describe('HlsParser', () => {
|
|
|
2021
2021
|
});
|
|
2022
2022
|
|
|
2023
2023
|
describe('produces syncTime', () => {
|
|
2024
|
+
// Corresponds to "2000-01-01T00:00:00.00Z".
|
|
2025
|
+
// All the PROGRAM-DATE-TIME values in the tests below are at or after this.
|
|
2026
|
+
const syncTimeBase = 946684800;
|
|
2027
|
+
|
|
2024
2028
|
/**
|
|
2025
2029
|
* @param {number} startTime
|
|
2026
2030
|
* @param {number} endTime
|
|
@@ -2039,9 +2043,10 @@ describe('HlsParser', () => {
|
|
|
2039
2043
|
/**
|
|
2040
2044
|
* @param {string} media
|
|
2041
2045
|
* @param {!Array.<number>} startTimes
|
|
2046
|
+
* @param {number} syncTimeOffset
|
|
2042
2047
|
* @param {(function(!shaka.media.SegmentReference))=} modifyFn
|
|
2043
2048
|
*/
|
|
2044
|
-
async function test(media, startTimes, modifyFn) {
|
|
2049
|
+
async function test(media, startTimes, syncTimeOffset, modifyFn) {
|
|
2045
2050
|
const master = [
|
|
2046
2051
|
'#EXTM3U\n',
|
|
2047
2052
|
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1,vtt",',
|
|
@@ -2053,7 +2058,8 @@ describe('HlsParser', () => {
|
|
|
2053
2058
|
for (let i = 0; i < startTimes.length - 1; i++) {
|
|
2054
2059
|
const startTime = startTimes[i];
|
|
2055
2060
|
const endTime = startTimes[i + 1];
|
|
2056
|
-
const reference = makeReference(
|
|
2061
|
+
const reference = makeReference(
|
|
2062
|
+
startTime, endTime, syncTimeOffset + startTime);
|
|
2057
2063
|
if (modifyFn) {
|
|
2058
2064
|
modifyFn(reference);
|
|
2059
2065
|
}
|
|
@@ -2100,7 +2106,7 @@ describe('HlsParser', () => {
|
|
|
2100
2106
|
'#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:25.00Z\n',
|
|
2101
2107
|
'#EXTINF:5,\n',
|
|
2102
2108
|
'main.mp4',
|
|
2103
|
-
].join(''), [0, 5, 10, 15, 20, 25]);
|
|
2109
|
+
].join(''), [0, 5, 10, 15, 20, 25], syncTimeBase + 5);
|
|
2104
2110
|
});
|
|
2105
2111
|
|
|
2106
2112
|
it('when some EXT-X-PROGRAM-DATE-TIME values are missing', async () => {
|
|
@@ -2122,7 +2128,7 @@ describe('HlsParser', () => {
|
|
|
2122
2128
|
'main.mp4\n',
|
|
2123
2129
|
'#EXTINF:4,\n',
|
|
2124
2130
|
'main.mp4',
|
|
2125
|
-
].join(''), [0, 2, 7, 12, 17, 19, 23]);
|
|
2131
|
+
].join(''), [0, 2, 7, 12, 17, 19, 23], syncTimeBase + 8);
|
|
2126
2132
|
});
|
|
2127
2133
|
|
|
2128
2134
|
it('except when ignoreManifestProgramDateTime is set', async () => {
|
|
@@ -2148,7 +2154,7 @@ describe('HlsParser', () => {
|
|
|
2148
2154
|
'#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:25.00Z\n',
|
|
2149
2155
|
'#EXTINF:5,\n',
|
|
2150
2156
|
'main.mp4',
|
|
2151
|
-
].join(''), [0, 5, 10, 15, 20, 25], (reference) => {
|
|
2157
|
+
].join(''), [0, 5, 10, 15, 20, 25], syncTimeBase + 5, (reference) => {
|
|
2152
2158
|
reference.syncTime = null;
|
|
2153
2159
|
});
|
|
2154
2160
|
});
|
|
@@ -2176,11 +2182,11 @@ describe('HlsParser', () => {
|
|
|
2176
2182
|
'#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:25.00Z\n',
|
|
2177
2183
|
'#EXTINF:5,\n',
|
|
2178
2184
|
'main.mp4',
|
|
2179
|
-
].join(''), [0, 5, 10, 15, 20, 25], (reference) => {
|
|
2185
|
+
].join(''), [0, 5, 10, 15, 20, 25], syncTimeBase + 5, (reference) => {
|
|
2180
2186
|
if (reference.startTime == 10) {
|
|
2181
2187
|
reference.partialReferences = [
|
|
2182
|
-
makeReference(10, 12.5,
|
|
2183
|
-
makeReference(12.5, 15,
|
|
2188
|
+
makeReference(10, 12.5, syncTimeBase + 15),
|
|
2189
|
+
makeReference(12.5, 15, syncTimeBase + 17.5),
|
|
2184
2190
|
];
|
|
2185
2191
|
}
|
|
2186
2192
|
});
|
|
@@ -3555,4 +3561,92 @@ describe('HlsParser', () => {
|
|
|
3555
3561
|
|
|
3556
3562
|
await testHlsParser(media, '', manifest);
|
|
3557
3563
|
});
|
|
3564
|
+
|
|
3565
|
+
it('syncs on sequence with ignoreManifestProgramDateTime', async () => {
|
|
3566
|
+
const config = shaka.util.PlayerConfiguration.createDefault().manifest;
|
|
3567
|
+
config.hls.ignoreManifestProgramDateTime = true;
|
|
3568
|
+
parser.configure(config);
|
|
3569
|
+
|
|
3570
|
+
const master = [
|
|
3571
|
+
'#EXTM3U\n',
|
|
3572
|
+
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="eng",URI="audio"\n',
|
|
3573
|
+
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1,mp4a",',
|
|
3574
|
+
'RESOLUTION=960x540,FRAME-RATE=60,AUDIO="aud1"\n',
|
|
3575
|
+
'video\n',
|
|
3576
|
+
].join('');
|
|
3577
|
+
|
|
3578
|
+
const video = [
|
|
3579
|
+
'#EXTM3U\n',
|
|
3580
|
+
'#EXT-X-TARGETDURATION:5\n',
|
|
3581
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
3582
|
+
'#EXT-X-MEDIA-SEQUENCE:1\n',
|
|
3583
|
+
'#EXTINF:5,\n',
|
|
3584
|
+
'video1.mp4\n',
|
|
3585
|
+
'#EXTINF:5,\n',
|
|
3586
|
+
'video2.mp4\n',
|
|
3587
|
+
'#EXTINF:5,\n',
|
|
3588
|
+
'video3.mp4\n',
|
|
3589
|
+
].join('');
|
|
3590
|
+
|
|
3591
|
+
const audio = [
|
|
3592
|
+
'#EXTM3U\n',
|
|
3593
|
+
'#EXT-X-TARGETDURATION:5\n',
|
|
3594
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
3595
|
+
'#EXT-X-MEDIA-SEQUENCE:3\n',
|
|
3596
|
+
'#EXTINF:5,\n',
|
|
3597
|
+
'audio3.mp4\n',
|
|
3598
|
+
'#EXTINF:5,\n',
|
|
3599
|
+
'audio4.mp4\n',
|
|
3600
|
+
].join('');
|
|
3601
|
+
|
|
3602
|
+
const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
3603
|
+
manifest.sequenceMode = true;
|
|
3604
|
+
manifest.anyTimeline();
|
|
3605
|
+
manifest.addPartialVariant((variant) => {
|
|
3606
|
+
variant.language = 'en';
|
|
3607
|
+
variant.bandwidth = 200;
|
|
3608
|
+
variant.addPartialStream(ContentType.VIDEO, (stream) => {
|
|
3609
|
+
stream.mime('video/mp4', 'avc1');
|
|
3610
|
+
stream.size(960, 540);
|
|
3611
|
+
stream.frameRate = 60;
|
|
3612
|
+
});
|
|
3613
|
+
variant.addPartialStream(ContentType.AUDIO, (stream) => {
|
|
3614
|
+
stream.language = 'en';
|
|
3615
|
+
stream.mime('audio/mp4', 'mp4a');
|
|
3616
|
+
});
|
|
3617
|
+
});
|
|
3618
|
+
});
|
|
3619
|
+
|
|
3620
|
+
fakeNetEngine
|
|
3621
|
+
.setResponseText('test:/master', master)
|
|
3622
|
+
.setResponseText('test:/audio', audio)
|
|
3623
|
+
.setResponseText('test:/video', video)
|
|
3624
|
+
.setResponseValue('test:/init.mp4', initSegmentData);
|
|
3625
|
+
|
|
3626
|
+
const actualManifest = await parser.start('test:/master', playerInterface);
|
|
3627
|
+
expect(actualManifest).toEqual(manifest);
|
|
3628
|
+
|
|
3629
|
+
const actualVideo = actualManifest.variants[0].video;
|
|
3630
|
+
await actualVideo.createSegmentIndex();
|
|
3631
|
+
goog.asserts.assert(actualVideo.segmentIndex != null, 'Null segmentIndex!');
|
|
3632
|
+
|
|
3633
|
+
const actualAudio = actualManifest.variants[0].audio;
|
|
3634
|
+
await actualAudio.createSegmentIndex();
|
|
3635
|
+
goog.asserts.assert(actualAudio.segmentIndex != null, 'Null segmentIndex!');
|
|
3636
|
+
|
|
3637
|
+
// Verify that the references are aligned on sequence number.
|
|
3638
|
+
const videoSegments = Array.from(actualVideo.segmentIndex);
|
|
3639
|
+
const audioSegments = Array.from(actualAudio.segmentIndex);
|
|
3640
|
+
|
|
3641
|
+
// The first two were dropped to align with the audio.
|
|
3642
|
+
expect(videoSegments.map((ref) => ref.getUris()[0])).toEqual([
|
|
3643
|
+
'test:/video3.mp4',
|
|
3644
|
+
]);
|
|
3645
|
+
// Audio has a 4th segment that video doesn't, but that doesn't get clipped
|
|
3646
|
+
// or used as the base. Alignment is truly based on media sequence number.
|
|
3647
|
+
expect(audioSegments.map((ref) => ref.getUris()[0])).toEqual([
|
|
3648
|
+
'test:/audio3.mp4',
|
|
3649
|
+
'test:/audio4.mp4',
|
|
3650
|
+
]);
|
|
3651
|
+
});
|
|
3558
3652
|
});
|
|
@@ -209,10 +209,10 @@ describe('DrmEngine', () => {
|
|
|
209
209
|
await drmEngine.initForPlayback(variants, manifest.offlineSessionIds);
|
|
210
210
|
await drmEngine.attach(video);
|
|
211
211
|
await mediaSourceEngine.appendBuffer(
|
|
212
|
-
ContentType.VIDEO, videoInitSegment, null,
|
|
212
|
+
ContentType.VIDEO, videoInitSegment, null,
|
|
213
213
|
/* hasClosedCaptions= */ false);
|
|
214
214
|
await mediaSourceEngine.appendBuffer(
|
|
215
|
-
ContentType.AUDIO, audioInitSegment, null,
|
|
215
|
+
ContentType.AUDIO, audioInitSegment, null,
|
|
216
216
|
/* hasClosedCaptions= */ false);
|
|
217
217
|
await encryptedEventSeen;
|
|
218
218
|
// With PlayReady, a persistent license policy can cause a different
|
|
@@ -245,11 +245,13 @@ describe('DrmEngine', () => {
|
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
+
const reference = dummyReference(0, 10);
|
|
249
|
+
|
|
248
250
|
await mediaSourceEngine.appendBuffer(
|
|
249
|
-
ContentType.VIDEO, videoSegment,
|
|
251
|
+
ContentType.VIDEO, videoSegment, reference,
|
|
250
252
|
/* hasClosedCaptions= */ false);
|
|
251
253
|
await mediaSourceEngine.appendBuffer(
|
|
252
|
-
ContentType.AUDIO, audioSegment,
|
|
254
|
+
ContentType.AUDIO, audioSegment, reference,
|
|
253
255
|
/* hasClosedCaptions= */ false);
|
|
254
256
|
|
|
255
257
|
expect(video.buffered.end(0)).toBeGreaterThan(0);
|
|
@@ -305,10 +307,10 @@ describe('DrmEngine', () => {
|
|
|
305
307
|
await drmEngine.initForPlayback(variants, manifest.offlineSessionIds);
|
|
306
308
|
await drmEngine.attach(video);
|
|
307
309
|
await mediaSourceEngine.appendBuffer(
|
|
308
|
-
ContentType.VIDEO, videoInitSegment, null,
|
|
310
|
+
ContentType.VIDEO, videoInitSegment, null,
|
|
309
311
|
/* hasClosedCaptions= */ false);
|
|
310
312
|
await mediaSourceEngine.appendBuffer(
|
|
311
|
-
ContentType.AUDIO, audioInitSegment, null,
|
|
313
|
+
ContentType.AUDIO, audioInitSegment, null,
|
|
312
314
|
/* hasClosedCaptions= */ false);
|
|
313
315
|
await encryptedEventSeen;
|
|
314
316
|
|
|
@@ -326,11 +328,13 @@ describe('DrmEngine', () => {
|
|
|
326
328
|
}
|
|
327
329
|
}
|
|
328
330
|
|
|
331
|
+
const reference = dummyReference(0, 10);
|
|
332
|
+
|
|
329
333
|
await mediaSourceEngine.appendBuffer(
|
|
330
|
-
ContentType.VIDEO, videoSegment,
|
|
334
|
+
ContentType.VIDEO, videoSegment, reference,
|
|
331
335
|
/* hasClosedCaptions= */ false);
|
|
332
336
|
await mediaSourceEngine.appendBuffer(
|
|
333
|
-
ContentType.AUDIO, audioSegment,
|
|
337
|
+
ContentType.AUDIO, audioSegment, reference,
|
|
334
338
|
/* hasClosedCaptions= */ false);
|
|
335
339
|
|
|
336
340
|
expect(video.buffered.end(0)).toBeGreaterThan(0);
|
|
@@ -345,4 +349,16 @@ describe('DrmEngine', () => {
|
|
|
345
349
|
expect(video.currentTime).toBeGreaterThan(0);
|
|
346
350
|
});
|
|
347
351
|
}); // describe('ClearKey')
|
|
352
|
+
|
|
353
|
+
function dummyReference(startTime, endTime) {
|
|
354
|
+
return new shaka.media.SegmentReference(
|
|
355
|
+
startTime, endTime,
|
|
356
|
+
/* uris= */ () => ['foo://bar'],
|
|
357
|
+
/* startByte= */ 0,
|
|
358
|
+
/* endByte= */ null,
|
|
359
|
+
/* initSegmentReference= */ null,
|
|
360
|
+
/* timestampOffset= */ 0,
|
|
361
|
+
/* appendWindowStart= */ 0,
|
|
362
|
+
/* appendWindowEnd= */ Infinity);
|
|
363
|
+
}
|
|
348
364
|
});
|
|
@@ -57,32 +57,32 @@ describe('MediaSourceEngine', () => {
|
|
|
57
57
|
|
|
58
58
|
function appendInit(type) {
|
|
59
59
|
const segment = generators[type].getInitSegment(Date.now() / 1000);
|
|
60
|
+
const reference = null;
|
|
60
61
|
return mediaSourceEngine.appendBuffer(
|
|
61
|
-
type, segment,
|
|
62
|
+
type, segment, reference, /* hasClosedCaptions= */ false);
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
function append(type, segmentNumber) {
|
|
65
66
|
const segment = generators[type]
|
|
66
67
|
.getSegment(segmentNumber, Date.now() / 1000);
|
|
68
|
+
const reference = dummyReference(type, segmentNumber);
|
|
67
69
|
return mediaSourceEngine.appendBuffer(
|
|
68
|
-
type, segment,
|
|
70
|
+
type, segment, reference, /* hasClosedCaptions= */ false);
|
|
69
71
|
}
|
|
70
72
|
|
|
71
|
-
// The start time and end time should be null for init segment with closed
|
|
72
|
-
// captions.
|
|
73
73
|
function appendInitWithClosedCaptions(type) {
|
|
74
74
|
const segment = generators[type].getInitSegment(Date.now() / 1000);
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
const reference = null;
|
|
76
|
+
return mediaSourceEngine.appendBuffer(
|
|
77
|
+
type, segment, reference, /* hasClosedCaptions= */ true);
|
|
77
78
|
}
|
|
78
79
|
|
|
79
|
-
// The start time and end time should be valid for the segments with closed
|
|
80
|
-
// captions.
|
|
81
80
|
function appendWithClosedCaptions(type, segmentNumber) {
|
|
82
81
|
const segment = generators[type]
|
|
83
82
|
.getSegment(segmentNumber, Date.now() / 1000);
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
const reference = dummyReference(type, segmentNumber);
|
|
84
|
+
return mediaSourceEngine.appendBuffer(
|
|
85
|
+
type, segment, reference, /* hasClosedCaptions= */ true);
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
function buffered(type, time) {
|
|
@@ -93,6 +93,20 @@ describe('MediaSourceEngine', () => {
|
|
|
93
93
|
return mediaSourceEngine.bufferStart(type);
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
function dummyReference(type, segmentNumber) {
|
|
97
|
+
const start = segmentNumber * metadata[type].segmentDuration;
|
|
98
|
+
const end = (segmentNumber + 1) * metadata[type].segmentDuration;
|
|
99
|
+
return new shaka.media.SegmentReference(
|
|
100
|
+
start, end,
|
|
101
|
+
/* uris= */ () => ['foo://bar'],
|
|
102
|
+
/* startByte= */ 0,
|
|
103
|
+
/* endByte= */ null,
|
|
104
|
+
/* initSegmentReference= */ null,
|
|
105
|
+
/* timestampOffset= */ 0,
|
|
106
|
+
/* appendWindowStart= */ 0,
|
|
107
|
+
/* appendWindowEnd= */ Infinity);
|
|
108
|
+
}
|
|
109
|
+
|
|
96
110
|
function remove(type, segmentNumber) {
|
|
97
111
|
const start = segmentNumber * metadata[type].segmentDuration;
|
|
98
112
|
const end = (segmentNumber + 1) * metadata[type].segmentDuration;
|