shaka-player 4.1.1 → 4.2.0
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 -0
- package/CHANGELOG.md +36 -8
- package/CONTRIBUTORS +3 -0
- package/README.md +20 -6
- package/demo/common/assets.js +25 -0
- package/demo/common/message_ids.js +2 -0
- package/demo/config.js +5 -1
- package/demo/index.html +1 -3
- package/demo/locales/en.json +2 -0
- package/demo/locales/source.json +8 -0
- package/dist/controls.css +1 -1
- package/dist/demo.compiled.debug.js +25 -23
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +25 -23
- package/dist/demo.compiled.map +3 -3
- package/dist/deps.js +6 -5
- package/dist/locales.js +30 -30
- package/dist/receiver.compiled.debug.js +24 -22
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +24 -22
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +69 -5
- package/dist/shaka-player.compiled.debug.d.ts +69 -5
- package/dist/shaka-player.compiled.debug.externs.js +111 -42
- package/dist/shaka-player.compiled.debug.js +352 -301
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +111 -42
- package/dist/shaka-player.compiled.js +823 -802
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +69 -5
- package/dist/shaka-player.ui.debug.d.ts +69 -5
- package/dist/shaka-player.ui.debug.externs.js +111 -42
- package/dist/shaka-player.ui.debug.js +360 -310
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +111 -42
- package/dist/shaka-player.ui.js +980 -957
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/fairplay.md +149 -0
- package/docs/tutorials/ui.md +6 -6
- package/docs/tutorials/upgrade.md +1 -0
- package/docs/tutorials/welcome.md +6 -3
- package/externs/shaka/abr_manager.js +8 -0
- package/externs/shaka/manifest.js +43 -0
- package/externs/shaka/player.js +13 -2
- package/karma.conf.js +3 -11
- package/lib/abr/simple_abr_manager.js +72 -4
- package/lib/ads/client_side_ad_manager.js +1 -1
- package/lib/dash/dash_parser.js +5 -0
- package/lib/hls/hls_parser.js +123 -27
- package/lib/media/drm_engine.js +1 -3
- package/lib/media/media_source_engine.js +57 -24
- package/lib/media/presentation_timeline.js +24 -1
- package/lib/media/segment_index.js +8 -0
- package/lib/media/segment_reference.js +7 -1
- package/lib/media/streaming_engine.js +42 -6
- package/lib/media/time_ranges_utils.js +46 -0
- package/lib/net/networking_engine.js +1 -0
- package/lib/player.js +8 -6
- package/lib/polyfill/media_capabilities.js +9 -0
- package/lib/polyfill/patchedmediakeys_apple.js +729 -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/text/vtt_text_parser.js +61 -4
- package/lib/util/buffer_utils.js +3 -0
- package/lib/util/error.js +21 -1
- package/lib/util/fairplay_utils.js +100 -2
- package/lib/util/object_utils.js +1 -0
- package/lib/util/platform.js +30 -1
- package/lib/util/player_configuration.js +3 -10
- package/lib/util/stream_utils.js +23 -3
- package/lib/util/string_utils.js +102 -13
- package/maintained-branches.md +15 -0
- package/package.json +3 -5
- package/shaka-player.uncompiled.js +1 -0
- package/test/hls/hls_parser_unit.js +49 -33
- 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 +107 -32
- package/test/test/util/fake_media_source_engine.js +10 -9
- package/test/test/util/simple_fakes.js +4 -0
- package/test/test/util/streaming_engine_util.js +10 -2
- package/test/text/simple_text_displayer_unit.js +27 -0
- package/test/text/ui_text_displayer_unit.js +65 -0
- package/test/text/vtt_text_parser_unit.js +26 -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/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.
|
|
4
|
+
"version": "4.2.0",
|
|
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"
|
|
@@ -38,6 +38,7 @@ goog.require('shaka.polyfill.Fullscreen');
|
|
|
38
38
|
goog.require('shaka.polyfill.MediaSource');
|
|
39
39
|
goog.require('shaka.polyfill.MediaCapabilities');
|
|
40
40
|
goog.require('shaka.polyfill.Orientation');
|
|
41
|
+
goog.require('shaka.polyfill.PatchedMediaKeysApple');
|
|
41
42
|
goog.require('shaka.polyfill.PatchedMediaKeysNop');
|
|
42
43
|
goog.require('shaka.polyfill.PatchedMediaKeysWebkit');
|
|
43
44
|
goog.require('shaka.polyfill.PiPWebkit');
|
|
@@ -33,6 +33,8 @@ describe('HlsParser', () => {
|
|
|
33
33
|
let segmentData;
|
|
34
34
|
/** @type {!Uint8Array} */
|
|
35
35
|
let selfInitializingSegmentData;
|
|
36
|
+
/** @type {!Uint8Array} */
|
|
37
|
+
let aes128Key;
|
|
36
38
|
|
|
37
39
|
afterEach(() => {
|
|
38
40
|
shaka.log.alwaysWarn = originalAlwaysWarn;
|
|
@@ -75,6 +77,11 @@ describe('HlsParser', () => {
|
|
|
75
77
|
selfInitializingSegmentData =
|
|
76
78
|
shaka.util.Uint8ArrayUtils.concat(initSegmentData, segmentData);
|
|
77
79
|
|
|
80
|
+
aes128Key = new Uint8Array([
|
|
81
|
+
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
82
|
+
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
|
83
|
+
]);
|
|
84
|
+
|
|
78
85
|
fakeNetEngine = new shaka.test.FakeNetworkingEngine();
|
|
79
86
|
|
|
80
87
|
config = shaka.util.PlayerConfiguration.createDefault().manifest;
|
|
@@ -2432,7 +2439,7 @@ describe('HlsParser', () => {
|
|
|
2432
2439
|
expect(initSegments[1].getUris()[0]).toBe('test:/init2.mp4');
|
|
2433
2440
|
});
|
|
2434
2441
|
|
|
2435
|
-
it('
|
|
2442
|
+
it('parses variants encrypted with AES-128', async () => {
|
|
2436
2443
|
const master = [
|
|
2437
2444
|
'#EXTM3U\n',
|
|
2438
2445
|
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1,mp4a",',
|
|
@@ -2441,10 +2448,15 @@ describe('HlsParser', () => {
|
|
|
2441
2448
|
'#EXT-X-STREAM-INF:BANDWIDTH=300,CODECS="avc1,mp4a",',
|
|
2442
2449
|
'RESOLUTION=960x540,FRAME-RATE=120,AUDIO="aud2"\n',
|
|
2443
2450
|
'video2\n',
|
|
2451
|
+
'#EXT-X-STREAM-INF:BANDWIDTH=300,CODECS="avc1,mp4a",',
|
|
2452
|
+
'RESOLUTION=960x540,FRAME-RATE=120,AUDIO="aud3"\n',
|
|
2453
|
+
'video3\n',
|
|
2444
2454
|
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="eng",',
|
|
2445
2455
|
'URI="audio"\n',
|
|
2446
2456
|
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud2",LANGUAGE="fr",',
|
|
2447
2457
|
'URI="audio2"\n',
|
|
2458
|
+
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud3",LANGUAGE="de",',
|
|
2459
|
+
'URI="audio3"\n',
|
|
2448
2460
|
].join('');
|
|
2449
2461
|
|
|
2450
2462
|
const media = [
|
|
@@ -2456,17 +2468,26 @@ describe('HlsParser', () => {
|
|
|
2456
2468
|
'main.mp4',
|
|
2457
2469
|
].join('');
|
|
2458
2470
|
|
|
2459
|
-
const
|
|
2471
|
+
const mediaWithMp4AesEncryption = [
|
|
2460
2472
|
'#EXTM3U\n',
|
|
2461
2473
|
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
2462
2474
|
'#EXT-X-KEY:METHOD=AES-128,',
|
|
2463
|
-
'URI="800k.key\n',
|
|
2475
|
+
'URI="800k.key"\n',
|
|
2464
2476
|
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
2465
2477
|
'#EXTINF:5,\n',
|
|
2466
2478
|
'#EXT-X-BYTERANGE:121090@616\n',
|
|
2467
2479
|
'main.mp4',
|
|
2468
2480
|
].join('');
|
|
2469
2481
|
|
|
2482
|
+
const mediaWithTSAesEncryption = [
|
|
2483
|
+
'#EXTM3U\n',
|
|
2484
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
2485
|
+
'#EXT-X-KEY:METHOD=AES-128,',
|
|
2486
|
+
'URI="800k.key"\n',
|
|
2487
|
+
'#EXTINF:5,\n',
|
|
2488
|
+
'main.ts',
|
|
2489
|
+
].join('');
|
|
2490
|
+
|
|
2470
2491
|
const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
2471
2492
|
manifest.anyTimeline();
|
|
2472
2493
|
manifest.addPartialVariant((variant) => {
|
|
@@ -2478,6 +2499,24 @@ describe('HlsParser', () => {
|
|
|
2478
2499
|
stream.language = 'en';
|
|
2479
2500
|
});
|
|
2480
2501
|
});
|
|
2502
|
+
manifest.addPartialVariant((variant) => {
|
|
2503
|
+
variant.bandwidth = 300;
|
|
2504
|
+
variant.addPartialStream(ContentType.VIDEO, (stream) => {
|
|
2505
|
+
stream.size(960, 540);
|
|
2506
|
+
});
|
|
2507
|
+
variant.addPartialStream(ContentType.AUDIO, (stream) => {
|
|
2508
|
+
stream.language = 'fr';
|
|
2509
|
+
});
|
|
2510
|
+
});
|
|
2511
|
+
manifest.addPartialVariant((variant) => {
|
|
2512
|
+
variant.bandwidth = 300;
|
|
2513
|
+
variant.addPartialStream(ContentType.VIDEO, (stream) => {
|
|
2514
|
+
stream.size(960, 540);
|
|
2515
|
+
});
|
|
2516
|
+
variant.addPartialStream(ContentType.AUDIO, (stream) => {
|
|
2517
|
+
stream.language = 'de';
|
|
2518
|
+
});
|
|
2519
|
+
});
|
|
2481
2520
|
manifest.sequenceMode = true;
|
|
2482
2521
|
});
|
|
2483
2522
|
|
|
@@ -2485,12 +2524,15 @@ describe('HlsParser', () => {
|
|
|
2485
2524
|
.setResponseText('test:/master', master)
|
|
2486
2525
|
.setResponseText('test:/audio', media)
|
|
2487
2526
|
.setResponseText('test:/audio2', media)
|
|
2527
|
+
.setResponseText('test:/audio3', media)
|
|
2488
2528
|
.setResponseText('test:/video', media)
|
|
2489
|
-
.setResponseText('test:/video2',
|
|
2529
|
+
.setResponseText('test:/video2', mediaWithMp4AesEncryption)
|
|
2530
|
+
.setResponseText('test:/video3', mediaWithTSAesEncryption)
|
|
2490
2531
|
.setResponseText('test:/main.vtt', vttText)
|
|
2491
2532
|
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
2492
2533
|
.setResponseValue('test:/main.mp4', segmentData)
|
|
2493
2534
|
.setResponseValue('test:/main.test', segmentData)
|
|
2535
|
+
.setResponseValue('test:/800k.key', aes128Key)
|
|
2494
2536
|
.setResponseValue('test:/selfInit.mp4', selfInitializingSegmentData);
|
|
2495
2537
|
|
|
2496
2538
|
const actual = await parser.start('test:/master', playerInterface);
|
|
@@ -2674,7 +2716,9 @@ describe('HlsParser', () => {
|
|
|
2674
2716
|
.setResponseText('test:/video', media)
|
|
2675
2717
|
.setResponseValue('test:/main.exe', segmentData)
|
|
2676
2718
|
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
2677
|
-
.setResponseValue('test:/main.mp4', segmentData)
|
|
2719
|
+
.setResponseValue('test:/main.mp4', segmentData)
|
|
2720
|
+
.setResponseValue('data:text/plain;base64,AAECAwQFBgcICQoLDA0ODw==',
|
|
2721
|
+
aes128Key);
|
|
2678
2722
|
|
|
2679
2723
|
await expectAsync(parser.start('test:/master', playerInterface))
|
|
2680
2724
|
.toBeRejectedWith(Util.jasmineError(error));
|
|
@@ -2708,34 +2752,6 @@ describe('HlsParser', () => {
|
|
|
2708
2752
|
await verifyError(master, media, error);
|
|
2709
2753
|
});
|
|
2710
2754
|
|
|
2711
|
-
it('if all variants are encrypted with AES-128', async () => {
|
|
2712
|
-
const master = [
|
|
2713
|
-
'#EXTM3U\n',
|
|
2714
|
-
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1",',
|
|
2715
|
-
'RESOLUTION=960x540,FRAME-RATE=60\n',
|
|
2716
|
-
'video\n',
|
|
2717
|
-
].join('');
|
|
2718
|
-
|
|
2719
|
-
const media = [
|
|
2720
|
-
'#EXTM3U\n',
|
|
2721
|
-
'#EXT-X-TARGETDURATION:6\n',
|
|
2722
|
-
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
2723
|
-
'#EXT-X-KEY:METHOD=AES-128,',
|
|
2724
|
-
'URI="data:text/plain;base64\n',
|
|
2725
|
-
'#EXT-X-MAP:URI="init.mp4"\n',
|
|
2726
|
-
'#EXTINF:5,\n',
|
|
2727
|
-
'#EXT-X-BYTERANGE:121090@616\n',
|
|
2728
|
-
'main.mp4',
|
|
2729
|
-
].join('');
|
|
2730
|
-
|
|
2731
|
-
const error = new shaka.util.Error(
|
|
2732
|
-
shaka.util.Error.Severity.CRITICAL,
|
|
2733
|
-
shaka.util.Error.Category.MANIFEST,
|
|
2734
|
-
Code.HLS_AES_128_ENCRYPTION_NOT_SUPPORTED);
|
|
2735
|
-
|
|
2736
|
-
await verifyError(master, media, error);
|
|
2737
|
-
});
|
|
2738
|
-
|
|
2739
2755
|
describe('if required attributes are missing', () => {
|
|
2740
2756
|
/**
|
|
2741
2757
|
* @param {string} master
|
|
@@ -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;
|