shaka-player 3.3.5 → 4.0.2
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/config.yml +1 -0
- package/.github/workflows/demo-version-index.yaml +8 -0
- package/.github/workflows/release-please.yaml +18 -2
- package/.github/workflows/sync-labels.yaml +33 -0
- package/.github/workflows/update-issues.yaml +29 -0
- package/.github/workflows/validate-pr-title.yaml +35 -0
- package/AUTHORS +1 -0
- package/CHANGELOG.md +215 -41
- package/CONTRIBUTORS +1 -0
- package/README.md +14 -11
- package/app-engine/demo-version-index/README.md +3 -3
- package/app-engine/demo-version-index/app.yaml +27 -1
- package/app-engine/demo-version-index/generate.py +164 -0
- package/app-engine/demo-version-index/main.py +4 -155
- package/app-engine/demo-version-index/requirements.txt +0 -1
- package/build/checkversion.py +1 -1
- package/build/compiler.py +1 -1
- package/build/misspellings.txt +1 -0
- package/build/shaka-lab.yaml +0 -2
- package/build/types/polyfill +0 -3
- package/demo/common/asset.js +17 -1
- package/demo/common/assets.js +29 -0
- package/demo/common/message_ids.js +6 -3
- package/demo/config.js +10 -11
- package/demo/custom.js +39 -0
- package/demo/demo.less +0 -1
- package/demo/demo_utils.js +0 -1
- package/demo/locales/en.json +6 -3
- package/demo/locales/source.json +22 -10
- package/demo/main.js +9 -6
- package/demo/search.js +2 -1
- package/dist/controls.css +3 -3
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +71 -64
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +71 -64
- package/dist/demo.compiled.map +3 -3
- package/dist/demo.css +1 -1
- package/dist/demo.css.map +1 -1
- package/dist/deps.js +17 -20
- package/dist/locales.js +33 -31
- package/dist/receiver.compiled.debug.js +32 -28
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +32 -28
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +311 -314
- package/dist/shaka-player.compiled.debug.d.ts +311 -314
- package/dist/shaka-player.compiled.debug.externs.js +126 -126
- package/dist/shaka-player.compiled.debug.js +430 -484
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +126 -126
- package/dist/shaka-player.compiled.js +829 -845
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +357 -358
- package/dist/shaka-player.ui.debug.d.ts +357 -358
- package/dist/shaka-player.ui.debug.externs.js +134 -126
- package/dist/shaka-player.ui.debug.js +489 -541
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +134 -126
- package/dist/shaka-player.ui.js +988 -1000
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/config.md +0 -2
- package/docs/tutorials/drm-config.md +5 -0
- package/docs/tutorials/fairplay.md +7 -22
- package/docs/tutorials/faq.md +0 -11
- package/docs/tutorials/index.json +2 -8
- package/docs/tutorials/plugins.md +1 -3
- package/docs/tutorials/upgrade.md +85 -11
- package/externs/polyfill.js +15 -0
- package/externs/shaka/manifest.js +5 -1
- package/externs/shaka/net.js +12 -0
- package/externs/shaka/offline.js +5 -1
- package/externs/shaka/player.js +39 -21
- package/externs/shaka/text.js +12 -12
- package/externs/sourcebuffer.js +15 -0
- package/lib/abr/simple_abr_manager.js +2 -1
- package/lib/ads/client_side_ad.js +13 -2
- package/lib/ads/client_side_ad_manager.js +22 -4
- package/lib/cast/cast_utils.js +0 -1
- package/lib/dash/content_protection.js +85 -5
- package/lib/dash/dash_parser.js +1 -0
- package/lib/hls/hls_parser.js +390 -747
- package/lib/hls/manifest_text_parser.js +2 -3
- package/lib/media/drm_engine.js +105 -37
- package/lib/media/gap_jumping_controller.js +10 -45
- package/lib/media/media_source_engine.js +150 -30
- package/lib/media/playhead.js +2 -5
- package/lib/media/presentation_timeline.js +1 -2
- package/lib/media/segment_index.js +13 -46
- package/lib/media/segment_reference.js +47 -1
- package/lib/media/streaming_engine.js +28 -11
- package/lib/media/time_ranges_utils.js +4 -9
- package/lib/net/networking_engine.js +3 -0
- package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
- package/lib/offline/manifest_converter.js +1 -0
- package/lib/offline/storage.js +8 -41
- package/lib/player.js +17 -201
- package/lib/polyfill/media_capabilities.js +12 -6
- package/lib/polyfill/mediasource.js +0 -28
- package/lib/polyfill/patchedmediakeys_nop.js +2 -0
- package/lib/polyfill/patchedmediakeys_webkit.js +2 -0
- package/lib/text/cue.js +0 -6
- package/lib/text/lrc_text_parser.js +8 -0
- package/lib/text/mp4_ttml_parser.js +8 -0
- package/lib/text/mp4_vtt_parser.js +8 -0
- package/lib/text/sbv_text_parser.js +8 -0
- package/lib/text/simple_text_displayer.js +1 -7
- package/lib/text/srt_text_parser.js +8 -0
- package/lib/text/ssa_text_parser.js +8 -0
- package/lib/text/text_engine.js +19 -3
- package/lib/text/ttml_text_parser.js +8 -0
- package/lib/text/ui_text_displayer.js +1 -7
- package/lib/text/vtt_text_parser.js +27 -5
- package/lib/text/web_vtt_generator.js +1 -7
- package/lib/util/error.js +9 -13
- package/lib/util/fairplay_utils.js +109 -0
- package/lib/util/functional.js +0 -42
- package/lib/util/mime_utils.js +16 -5
- package/lib/util/platform.js +45 -0
- package/lib/util/player_configuration.js +17 -6
- package/lib/util/pssh.js +23 -4
- package/lib/util/stream_utils.js +92 -22
- package/lib/util/uint8array_utils.js +0 -16
- package/lib/util/xml_utils.js +1 -1
- package/package.json +5 -2
- package/roadmap.md +19 -19
- package/shaka-player.uncompiled.js +0 -3
- package/test/dash/dash_parser_content_protection_unit.js +44 -0
- package/test/dash/dash_parser_segment_template_unit.js +3 -4
- package/test/demo/demo_unit.js +2 -1
- package/test/hls/hls_live_unit.js +155 -230
- package/test/hls/hls_parser_unit.js +515 -432
- package/test/media/drm_engine_unit.js +86 -120
- package/test/media/media_source_engine_integration.js +25 -3
- package/test/media/media_source_engine_unit.js +3 -2
- package/test/media/playhead_unit.js +27 -191
- package/test/media/segment_index_unit.js +15 -25
- package/test/media/streaming_engine_integration.js +2 -39
- package/test/media/streaming_engine_unit.js +3 -2
- package/test/media/time_ranges_utils_unit.js +0 -5
- package/test/offline/manifest_convert_unit.js +34 -4
- package/test/offline/offline_manifest_parser_unit.js +1 -0
- package/test/offline/storage_integration.js +5 -4
- package/test/player_external.js +0 -6
- package/test/player_integration.js +16 -0
- package/test/player_unit.js +26 -0
- package/test/test/util/fake_media_source_engine.js +11 -4
- package/test/test/util/manifest_generator.js +3 -1
- package/test/test/util/manifest_parser_util.js +4 -1
- package/test/test/util/offline_utils.js +1 -0
- package/test/test/util/streaming_engine_util.js +1 -0
- package/test/test/util/test_scheme.js +24 -1
- package/test/test/util/util.js +4 -4
- package/test/text/cue_integration.js +2 -2
- package/test/text/lrc_text_parser_unit.js +6 -7
- package/test/text/mp4_ttml_parser_unit.js +6 -4
- package/test/text/mp4_vtt_parser_unit.js +6 -5
- package/test/text/sbv_text_parser_unit.js +5 -6
- package/test/text/srt_text_parser_unit.js +5 -6
- package/test/text/ssa_text_parser_unit.js +17 -29
- package/test/text/text_engine_unit.js +45 -5
- package/test/text/ttml_text_parser_unit.js +77 -77
- package/test/text/vtt_text_parser_unit.js +116 -59
- package/test/ui/ui_integration.js +0 -16
- package/test/ui/ui_unit.js +27 -0
- package/test/util/cmcd_manager_unit.js +3 -0
- package/test/util/stream_utils_unit.js +23 -7
- package/ui/controls.js +65 -40
- package/ui/fullscreen_button.js +26 -6
- package/ui/less/containers.less +4 -4
- package/ui/less/general.less +1 -1
- package/ui/less/range_elements.less +1 -0
- package/ui/locales/en.json +1 -0
- package/ui/locales/source.json +5 -0
- package/ui/resolution_selection.js +31 -33
- package/ui/ui.js +0 -17
- package/.github/pull_request_template.md +0 -10
- package/docs/tutorials/upgrade-v2-5.md +0 -441
- package/docs/tutorials/upgrade-v3.md +0 -38
- package/lib/polyfill/mathround.js +0 -49
- package/lib/polyfill/patchedmediakeys_apple.js +0 -744
- package/lib/polyfill/patchedmediakeys_ms.js +0 -698
- package/test/util/functional_unit.js +0 -82
|
@@ -22,6 +22,12 @@ goog.require('shaka.util.XmlUtils');
|
|
|
22
22
|
* @export
|
|
23
23
|
*/
|
|
24
24
|
shaka.text.VttTextParser = class {
|
|
25
|
+
/** Constructs a VTT parser. */
|
|
26
|
+
constructor() {
|
|
27
|
+
/** @private {boolean} */
|
|
28
|
+
this.sequenceMode_ = false;
|
|
29
|
+
}
|
|
30
|
+
|
|
25
31
|
/**
|
|
26
32
|
* @override
|
|
27
33
|
* @export
|
|
@@ -30,6 +36,14 @@ shaka.text.VttTextParser = class {
|
|
|
30
36
|
goog.asserts.assert(false, 'VTT does not have init segments');
|
|
31
37
|
}
|
|
32
38
|
|
|
39
|
+
/**
|
|
40
|
+
* @override
|
|
41
|
+
* @export
|
|
42
|
+
*/
|
|
43
|
+
setSequenceMode(sequenceMode) {
|
|
44
|
+
this.sequenceMode_ = sequenceMode;
|
|
45
|
+
}
|
|
46
|
+
|
|
33
47
|
/**
|
|
34
48
|
* @override
|
|
35
49
|
* @export
|
|
@@ -48,11 +62,21 @@ shaka.text.VttTextParser = class {
|
|
|
48
62
|
shaka.util.Error.Code.INVALID_TEXT_HEADER);
|
|
49
63
|
}
|
|
50
64
|
|
|
65
|
+
// Depending on "segmentRelativeVttTiming" configuration,
|
|
66
|
+
// "vttOffset" will correspond to either "periodStart" (default)
|
|
67
|
+
// or "segmentStart", for segmented VTT where timings are relative
|
|
68
|
+
// to the beginning of each segment.
|
|
51
69
|
// NOTE: "periodStart" is the timestamp offset applied via TextEngine.
|
|
52
70
|
// It is no longer closely tied to periods, but the name stuck around.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
71
|
+
// NOTE: This offset and the flag choosing its meaning have no effect on
|
|
72
|
+
// HLS content, which should use X-TIMESTAMP-MAP and periodStart instead.
|
|
73
|
+
let offset = time.vttOffset;
|
|
74
|
+
|
|
75
|
+
// Only use 'X-TIMESTAMP-MAP' in sequence mode, as that is currently
|
|
76
|
+
// shorthand for HLS. Note that an offset based on the first video
|
|
77
|
+
// timestamp has already been extracted, and appears in periodStart.
|
|
78
|
+
// The relative offset from X-TIMESTAMP-MAP will be added to that for HLS.
|
|
79
|
+
if (blocks[0].includes('X-TIMESTAMP-MAP') && this.sequenceMode_) {
|
|
56
80
|
// https://bit.ly/2K92l7y
|
|
57
81
|
// The 'X-TIMESTAMP-MAP' header is used in HLS to align text with
|
|
58
82
|
// the rest of the media.
|
|
@@ -87,8 +111,6 @@ shaka.text.VttTextParser = class {
|
|
|
87
111
|
mpegTime += shaka.text.VttTextParser.TS_ROLLOVER_;
|
|
88
112
|
}
|
|
89
113
|
|
|
90
|
-
// Apple-encoded HLS content uses absolute timestamps, so assume the
|
|
91
|
-
// presence of the map tag means the content uses absolute timestamps.
|
|
92
114
|
offset = time.periodStart + mpegTime / mpegTimescale - cueTime;
|
|
93
115
|
}
|
|
94
116
|
}
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
|
|
7
7
|
goog.provide('shaka.text.WebVttGenerator');
|
|
8
8
|
|
|
9
|
-
goog.require('shaka.Deprecate');
|
|
10
9
|
goog.require('shaka.text.Cue');
|
|
11
10
|
|
|
12
11
|
|
|
@@ -49,12 +48,7 @@ shaka.text.WebVttGenerator = class {
|
|
|
49
48
|
return `${acc}</${tag}>`;
|
|
50
49
|
}, '');
|
|
51
50
|
|
|
52
|
-
if (cue.lineBreak
|
|
53
|
-
if (cue.spacer) {
|
|
54
|
-
shaka.Deprecate.deprecateFeature(4,
|
|
55
|
-
'shaka.text.Cue',
|
|
56
|
-
'Please use lineBreak instead of spacer.');
|
|
57
|
-
}
|
|
51
|
+
if (cue.lineBreak) {
|
|
58
52
|
// This is a vertical lineBreak, so insert a newline.
|
|
59
53
|
return '\n';
|
|
60
54
|
} else if (cue.nestedCues.length) {
|
package/lib/util/error.js
CHANGED
|
@@ -588,13 +588,7 @@ shaka.util.Error.Code = {
|
|
|
588
588
|
|
|
589
589
|
// RETIRED: 'HLS_COULD_NOT_GUESS_MIME_TYPE': 4021,
|
|
590
590
|
|
|
591
|
-
|
|
592
|
-
* No Master Playlist has been provided. Master playlist provides
|
|
593
|
-
* vital information about the streams (like codecs) that is
|
|
594
|
-
* required for MediaSource. We don't support directly providing
|
|
595
|
-
* a Media Playlist.
|
|
596
|
-
*/
|
|
597
|
-
'HLS_MASTER_PLAYLIST_NOT_PROVIDED': 4022,
|
|
591
|
+
// RETIRED: 'HLS_MASTER_PLAYLIST_NOT_PROVIDED': 4022,
|
|
598
592
|
|
|
599
593
|
/**
|
|
600
594
|
* One of the required attributes was not provided, so the
|
|
@@ -634,12 +628,7 @@ shaka.util.Error.Code = {
|
|
|
634
628
|
|
|
635
629
|
// RETIRED: 'HLS_LIVE_CONTENT_NOT_SUPPORTED': 4029,
|
|
636
630
|
|
|
637
|
-
|
|
638
|
-
* The HLS parser was unable to parse segment start time from the media.
|
|
639
|
-
* <br> error.data[0] is the failed media playlist URI.
|
|
640
|
-
* <br> error.data[1] is the failed media segment URI (if any).
|
|
641
|
-
*/
|
|
642
|
-
'HLS_COULD_NOT_PARSE_SEGMENT_START_TIME': 4030,
|
|
631
|
+
// RETIRED: 'HLS_COULD_NOT_PARSE_SEGMENT_START_TIME': 4030,
|
|
643
632
|
|
|
644
633
|
// RETIRED: 'HLS_MEDIA_SEQUENCE_REQUIRED_IN_LIVE_STREAMS': 4031,
|
|
645
634
|
|
|
@@ -693,6 +682,13 @@ shaka.util.Error.Code = {
|
|
|
693
682
|
*/
|
|
694
683
|
'HLS_VARIABLE_NOT_FOUND': 4039,
|
|
695
684
|
|
|
685
|
+
/**
|
|
686
|
+
* We do not support playing encrypted mp2t with MSE
|
|
687
|
+
*/
|
|
688
|
+
'HLS_MSE_ENCRYPTED_MP2T_NOT_SUPPORTED': 4040,
|
|
689
|
+
|
|
690
|
+
// RETIRED: 'HLS_MSE_ENCRYPTED_LEGACY_APPLE_MEDIA_KEYS_NOT_SUPPORTED': 4041,
|
|
691
|
+
|
|
696
692
|
|
|
697
693
|
// RETIRED: 'INCONSISTENT_BUFFER_STATE': 5000,
|
|
698
694
|
// RETIRED: 'INVALID_SEGMENT_INDEX': 5001,
|
|
@@ -8,9 +8,11 @@ goog.provide('shaka.util.FairPlayUtils');
|
|
|
8
8
|
|
|
9
9
|
goog.require('goog.Uri');
|
|
10
10
|
goog.require('goog.asserts');
|
|
11
|
+
goog.require('shaka.net.NetworkingEngine');
|
|
11
12
|
goog.require('shaka.util.BufferUtils');
|
|
12
13
|
goog.require('shaka.util.Error');
|
|
13
14
|
goog.require('shaka.util.StringUtils');
|
|
15
|
+
goog.require('shaka.util.Uint8ArrayUtils');
|
|
14
16
|
|
|
15
17
|
|
|
16
18
|
/**
|
|
@@ -18,6 +20,29 @@ goog.require('shaka.util.StringUtils');
|
|
|
18
20
|
* @export
|
|
19
21
|
*/
|
|
20
22
|
shaka.util.FairPlayUtils = class {
|
|
23
|
+
/**
|
|
24
|
+
* Check if FairPlay is supported.
|
|
25
|
+
*
|
|
26
|
+
* @return {!Promise.<boolean>}
|
|
27
|
+
* @export
|
|
28
|
+
*/
|
|
29
|
+
static async isFairPlaySupported() {
|
|
30
|
+
const config = {
|
|
31
|
+
initDataTypes: ['cenc', 'sinf', 'skd'],
|
|
32
|
+
videoCapabilities: [
|
|
33
|
+
{
|
|
34
|
+
contentType: 'video/mp4; codecs="avc1.42E01E"',
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
};
|
|
38
|
+
try {
|
|
39
|
+
await navigator.requestMediaKeySystemAccess('com.apple.fps', [config]);
|
|
40
|
+
return true;
|
|
41
|
+
} catch (err) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
21
46
|
/**
|
|
22
47
|
* Using the default method, extract a content ID from the init data. This is
|
|
23
48
|
* based on the FairPlay example documentation.
|
|
@@ -106,4 +131,88 @@ shaka.util.FairPlayUtils = class {
|
|
|
106
131
|
offset == rebuiltInitData.length, 'Inconsistent init data length');
|
|
107
132
|
return rebuiltInitData;
|
|
108
133
|
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* SPC FairPlay request.
|
|
137
|
+
*
|
|
138
|
+
* @param {shaka.net.NetworkingEngine.RequestType} type
|
|
139
|
+
* @param {shaka.extern.Request} request
|
|
140
|
+
* @export
|
|
141
|
+
*/
|
|
142
|
+
static spcFairPlayRequest(type, request) {
|
|
143
|
+
if (type !== shaka.net.NetworkingEngine.RequestType.LICENSE) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const body = /** @type {!(ArrayBuffer|ArrayBufferView)} */(request.body);
|
|
147
|
+
const originalPayload = shaka.util.BufferUtils.toUint8(body);
|
|
148
|
+
const base64Payload = shaka.util.Uint8ArrayUtils.toBase64(originalPayload);
|
|
149
|
+
request.headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
|
150
|
+
request.body = shaka.util.StringUtils.toUTF8('spc=' + base64Payload);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Common FairPlay response transform for some DRMs providers.
|
|
155
|
+
*
|
|
156
|
+
* @param {shaka.net.NetworkingEngine.RequestType} type
|
|
157
|
+
* @param {shaka.extern.Response} response
|
|
158
|
+
* @export
|
|
159
|
+
*/
|
|
160
|
+
static commonFairPlayResponse(type, response) {
|
|
161
|
+
if (type !== shaka.net.NetworkingEngine.RequestType.LICENSE) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// In Apple's docs, responses can be of the form:
|
|
166
|
+
// '\n<ckc>base64encoded</ckc>\n' or 'base64encoded'
|
|
167
|
+
// We have also seen responses in JSON format from some of our partners.
|
|
168
|
+
// In all of these text-based formats, the CKC data is base64-encoded.
|
|
169
|
+
|
|
170
|
+
let responseText;
|
|
171
|
+
try {
|
|
172
|
+
// Convert it to text for further processing.
|
|
173
|
+
responseText = shaka.util.StringUtils.fromUTF8(response.data);
|
|
174
|
+
} catch (error) {
|
|
175
|
+
// Assume it's not a text format of any kind and leave it alone.
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
let licenseProcessing = false;
|
|
180
|
+
|
|
181
|
+
// Trim whitespace.
|
|
182
|
+
responseText = responseText.trim();
|
|
183
|
+
|
|
184
|
+
// Look for <ckc> wrapper and remove it.
|
|
185
|
+
if (responseText.substr(0, 5) === '<ckc>' &&
|
|
186
|
+
responseText.substr(-6) === '</ckc>') {
|
|
187
|
+
responseText = responseText.slice(5, -6);
|
|
188
|
+
licenseProcessing = true;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Look for a JSON wrapper and remove it.
|
|
192
|
+
try {
|
|
193
|
+
const responseObject = /** @type {!Object} */(JSON.parse(responseText));
|
|
194
|
+
if (responseObject['ckc']) {
|
|
195
|
+
responseText = responseObject['ckc'];
|
|
196
|
+
licenseProcessing = true;
|
|
197
|
+
}
|
|
198
|
+
if (responseObject['CkcMessage']) {
|
|
199
|
+
responseText = responseObject['CkcMessage'];
|
|
200
|
+
licenseProcessing = true;
|
|
201
|
+
}
|
|
202
|
+
if (responseObject['License']) {
|
|
203
|
+
responseText = responseObject['License'];
|
|
204
|
+
licenseProcessing = true;
|
|
205
|
+
}
|
|
206
|
+
} catch (err) {
|
|
207
|
+
// It wasn't JSON. Fall through with other transformations.
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (licenseProcessing) {
|
|
211
|
+
// Decode the base64-encoded data into the format the browser expects.
|
|
212
|
+
// It's not clear why FairPlay license servers don't just serve this
|
|
213
|
+
// directly.
|
|
214
|
+
response.data = shaka.util.BufferUtils.toArrayBuffer(
|
|
215
|
+
shaka.util.Uint8ArrayUtils.fromBase64(responseText));
|
|
216
|
+
}
|
|
217
|
+
}
|
|
109
218
|
};
|
package/lib/util/functional.js
CHANGED
|
@@ -6,9 +6,6 @@
|
|
|
6
6
|
|
|
7
7
|
goog.provide('shaka.util.Functional');
|
|
8
8
|
|
|
9
|
-
goog.require('shaka.Deprecate');
|
|
10
|
-
|
|
11
|
-
|
|
12
9
|
/**
|
|
13
10
|
* @summary A set of functional utility functions.
|
|
14
11
|
*/
|
|
@@ -70,43 +67,4 @@ shaka.util.Functional = class {
|
|
|
70
67
|
static isNotNull(value) {
|
|
71
68
|
return value != null;
|
|
72
69
|
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Calls a factory function while allowing it to be a constructor for
|
|
76
|
-
* reverse-compatibility.
|
|
77
|
-
*
|
|
78
|
-
* @param {function():!T} factory
|
|
79
|
-
* @return {!T}
|
|
80
|
-
* @template T
|
|
81
|
-
*/
|
|
82
|
-
static callFactory(factory) {
|
|
83
|
-
// See https://stackoverflow.com/q/10428603/1208502
|
|
84
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
85
|
-
const obj = Object.create(factory.prototype || Object.prototype);
|
|
86
|
-
// If this is a constructor, call it with our newly created object to
|
|
87
|
-
// initialize it; if this isn't a constructor, the "this" shouldn't be used
|
|
88
|
-
// since it should be "undefined".
|
|
89
|
-
let ret;
|
|
90
|
-
try {
|
|
91
|
-
ret = factory.call(obj); // eslint-disable-line no-restricted-syntax
|
|
92
|
-
|
|
93
|
-
// If it didn't return anything, assume it is a constructor and return our
|
|
94
|
-
// "this" value instead.
|
|
95
|
-
if (!ret) {
|
|
96
|
-
shaka.Deprecate.deprecateFeature(4,
|
|
97
|
-
'Factories requiring new',
|
|
98
|
-
'Factories should be plain functions');
|
|
99
|
-
ret = obj;
|
|
100
|
-
}
|
|
101
|
-
} catch (e) {
|
|
102
|
-
// This was an ES6 class, so it threw a TypeError because we didn't use
|
|
103
|
-
// "new". Fall back to actually using "new".
|
|
104
|
-
shaka.Deprecate.deprecateFeature(4,
|
|
105
|
-
'Factories requiring new',
|
|
106
|
-
'Factories should be plain functions');
|
|
107
|
-
const FactoryAsClass = /** @type {function(new: T)} */(factory);
|
|
108
|
-
ret = new FactoryAsClass();
|
|
109
|
-
}
|
|
110
|
-
return ret;
|
|
111
|
-
}
|
|
112
70
|
};
|
package/lib/util/mime_utils.js
CHANGED
|
@@ -8,9 +8,11 @@ goog.provide('shaka.util.MimeUtils');
|
|
|
8
8
|
|
|
9
9
|
goog.require('shaka.dependencies');
|
|
10
10
|
goog.require('shaka.media.Transmuxer');
|
|
11
|
+
goog.require('shaka.util.ManifestParserUtils');
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* @summary A set of utility functions for dealing with MIME types.
|
|
15
|
+
* @export
|
|
14
16
|
*/
|
|
15
17
|
shaka.util.MimeUtils = class {
|
|
16
18
|
/**
|
|
@@ -20,6 +22,7 @@ shaka.util.MimeUtils = class {
|
|
|
20
22
|
* @param {string} mimeType
|
|
21
23
|
* @param {string=} codecs
|
|
22
24
|
* @return {string}
|
|
25
|
+
* @export
|
|
23
26
|
*/
|
|
24
27
|
static getFullType(mimeType, codecs) {
|
|
25
28
|
let fullMimeType = mimeType;
|
|
@@ -32,6 +35,8 @@ shaka.util.MimeUtils = class {
|
|
|
32
35
|
/**
|
|
33
36
|
* Takes a MIME type and a codecs string and produces the full MIME
|
|
34
37
|
* type. If it's a transport stream, convert its codecs to MP4 codecs.
|
|
38
|
+
* Otherwise for multiplexed content, convert the video MIME types to
|
|
39
|
+
* their audio equivalents if the content type is audio.
|
|
35
40
|
*
|
|
36
41
|
* @param {string} mimeType
|
|
37
42
|
* @param {string} codecs
|
|
@@ -40,13 +45,19 @@ shaka.util.MimeUtils = class {
|
|
|
40
45
|
*/
|
|
41
46
|
static getFullOrConvertedType(mimeType, codecs, contentType) {
|
|
42
47
|
const fullMimeType = shaka.util.MimeUtils.getFullType(mimeType, codecs);
|
|
48
|
+
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
43
49
|
|
|
44
|
-
if (
|
|
45
|
-
|
|
46
|
-
|
|
50
|
+
if (shaka.media.Transmuxer.isTsContainer(fullMimeType)) {
|
|
51
|
+
if (shaka.dependencies.muxjs()) {
|
|
52
|
+
return shaka.media.Transmuxer.convertTsCodecs(
|
|
53
|
+
contentType, fullMimeType);
|
|
54
|
+
}
|
|
55
|
+
} else if (contentType == ContentType.AUDIO) {
|
|
56
|
+
// video/mp2t is the correct mime type for TS audio, so only replace the
|
|
57
|
+
// word "video" with "audio" for non-TS audio content.
|
|
58
|
+
return fullMimeType.replace('video', 'audio');
|
|
47
59
|
}
|
|
48
|
-
|
|
49
|
-
return shaka.media.Transmuxer.convertTsCodecs(contentType, fullMimeType);
|
|
60
|
+
return fullMimeType;
|
|
50
61
|
}
|
|
51
62
|
|
|
52
63
|
|
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
|
*
|
|
@@ -151,6 +163,16 @@ shaka.util.Platform = class {
|
|
|
151
163
|
return shaka.util.Platform.userAgentContains_('CrKey');
|
|
152
164
|
}
|
|
153
165
|
|
|
166
|
+
/**
|
|
167
|
+
* Check if the current platform is a Android-based Cast devices.
|
|
168
|
+
*
|
|
169
|
+
* @return {boolean}
|
|
170
|
+
*/
|
|
171
|
+
static isAndroidCastDevice() {
|
|
172
|
+
return shaka.util.Platform.isChromecast() &&
|
|
173
|
+
shaka.util.Platform.userAgentContains_('Android');
|
|
174
|
+
}
|
|
175
|
+
|
|
154
176
|
/**
|
|
155
177
|
* Check if the current platform is Google Chrome.
|
|
156
178
|
*
|
|
@@ -228,6 +250,16 @@ shaka.util.Platform = class {
|
|
|
228
250
|
return null;
|
|
229
251
|
}
|
|
230
252
|
|
|
253
|
+
/**
|
|
254
|
+
* Check if the current platform is Apple Safari
|
|
255
|
+
* or Safari-based iOS browsers.
|
|
256
|
+
*
|
|
257
|
+
* @return {boolean}
|
|
258
|
+
*/
|
|
259
|
+
static isSafari() {
|
|
260
|
+
return !!shaka.util.Platform.safariVersion();
|
|
261
|
+
}
|
|
262
|
+
|
|
231
263
|
/**
|
|
232
264
|
* Guesses if the platform is a mobile one (iOS or Android).
|
|
233
265
|
*
|
|
@@ -318,6 +350,19 @@ shaka.util.Platform = class {
|
|
|
318
350
|
const Platform = shaka.util.Platform;
|
|
319
351
|
return Platform.isTizen() || Platform.isXboxOne();
|
|
320
352
|
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Returns true if MediaKeys is polyfilled
|
|
356
|
+
*
|
|
357
|
+
* @return {boolean}
|
|
358
|
+
*/
|
|
359
|
+
static isMediaKeysPolyfilled() {
|
|
360
|
+
if (window.shakaMediaKeysPolyfill) {
|
|
361
|
+
return true;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return false;
|
|
365
|
+
}
|
|
321
366
|
};
|
|
322
367
|
|
|
323
368
|
/** @private {shaka.util.Timer} */
|
|
@@ -9,7 +9,6 @@ goog.provide('shaka.util.PlayerConfiguration');
|
|
|
9
9
|
goog.require('goog.asserts');
|
|
10
10
|
goog.require('shaka.abr.SimpleAbrManager');
|
|
11
11
|
goog.require('shaka.log');
|
|
12
|
-
goog.require('shaka.media.DrmEngine');
|
|
13
12
|
goog.require('shaka.net.NetworkingEngine');
|
|
14
13
|
goog.require('shaka.util.ConfigUtils');
|
|
15
14
|
goog.require('shaka.util.LanguageUtils');
|
|
@@ -22,7 +21,10 @@ goog.require('shaka.util.Platform');
|
|
|
22
21
|
* @export
|
|
23
22
|
*/
|
|
24
23
|
shaka.util.PlayerConfiguration = class {
|
|
25
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* @return {shaka.extern.PlayerConfiguration}
|
|
26
|
+
* @export
|
|
27
|
+
*/
|
|
26
28
|
static createDefault() {
|
|
27
29
|
// This is a relatively safe default in the absence of clues from the
|
|
28
30
|
// browser. For slower connections, the default estimate may be too high.
|
|
@@ -64,7 +66,11 @@ shaka.util.PlayerConfiguration = class {
|
|
|
64
66
|
clearKeys: {}, // key is arbitrary key system ID, value must be string
|
|
65
67
|
advanced: {}, // key is arbitrary key system ID, value is a record type
|
|
66
68
|
delayLicenseRequestUntilPlayed: false,
|
|
67
|
-
initDataTransform:
|
|
69
|
+
initDataTransform: (initData, initDataType, drmInfo) => {
|
|
70
|
+
return shaka.util.ConfigUtils.referenceParametersAndReturn(
|
|
71
|
+
[initData, initDataType, drmInfo],
|
|
72
|
+
initData);
|
|
73
|
+
},
|
|
68
74
|
logLicenseExchange: false,
|
|
69
75
|
updateExpirationTime: 1,
|
|
70
76
|
preferredKeySystems: [],
|
|
@@ -78,6 +84,7 @@ shaka.util.PlayerConfiguration = class {
|
|
|
78
84
|
disableText: false,
|
|
79
85
|
disableThumbnails: false,
|
|
80
86
|
defaultPresentationDelay: 0,
|
|
87
|
+
segmentRelativeVttTiming: false,
|
|
81
88
|
dash: {
|
|
82
89
|
clockSyncUri: '',
|
|
83
90
|
ignoreDrmInfo: false,
|
|
@@ -92,6 +99,8 @@ shaka.util.PlayerConfiguration = class {
|
|
|
92
99
|
keySystemsByURI: {
|
|
93
100
|
'urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b':
|
|
94
101
|
'org.w3.clearkey',
|
|
102
|
+
'urn:uuid:e2719d58-a985-b3c9-781a-b030af78d30e':
|
|
103
|
+
'org.w3.clearkey',
|
|
95
104
|
'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed':
|
|
96
105
|
'com.widevine.alpha',
|
|
97
106
|
'urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95':
|
|
@@ -110,9 +119,11 @@ shaka.util.PlayerConfiguration = class {
|
|
|
110
119
|
hls: {
|
|
111
120
|
ignoreTextStreamFailures: false,
|
|
112
121
|
ignoreImageStreamFailures: false,
|
|
113
|
-
useFullSegmentsForStartTime: false,
|
|
114
122
|
defaultAudioCodec: 'mp4a.40.2',
|
|
115
123
|
defaultVideoCodec: 'avc1.42E01E',
|
|
124
|
+
ignoreManifestProgramDateTime: false,
|
|
125
|
+
mediaPlaylistFullMimeType:
|
|
126
|
+
'video/mp2t; codecs="avc1.42E01E, mp4a.40.2"',
|
|
116
127
|
},
|
|
117
128
|
};
|
|
118
129
|
|
|
@@ -136,8 +147,6 @@ shaka.util.PlayerConfiguration = class {
|
|
|
136
147
|
alwaysStreamText: false,
|
|
137
148
|
startAtSegmentBoundary: false,
|
|
138
149
|
gapDetectionThreshold: 0.1,
|
|
139
|
-
smallGapLimit: 0.5,
|
|
140
|
-
jumpLargeGaps: false,
|
|
141
150
|
durationBackoff: 1,
|
|
142
151
|
forceTransmuxTS: false,
|
|
143
152
|
// Offset by 5 seconds since Chromecast takes a few seconds to start
|
|
@@ -213,6 +222,8 @@ shaka.util.PlayerConfiguration = class {
|
|
|
213
222
|
// unexpected behaviours when someone tries to plays downloaded content
|
|
214
223
|
// without a persistent license.
|
|
215
224
|
usePersistentLicense: true,
|
|
225
|
+
|
|
226
|
+
numberOfParallelDownloads: 5,
|
|
216
227
|
};
|
|
217
228
|
|
|
218
229
|
const abr = {
|
package/lib/util/pssh.js
CHANGED
|
@@ -90,16 +90,21 @@ shaka.util.Pssh = class {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
/**
|
|
93
|
-
* Creates a pssh blob from the given system ID and
|
|
93
|
+
* Creates a pssh blob from the given system ID, data, keyIds and version.
|
|
94
94
|
*
|
|
95
95
|
* @param {!Uint8Array} data
|
|
96
96
|
* @param {!Uint8Array} systemId
|
|
97
|
+
* @param {!Set.<string>} keyIds
|
|
98
|
+
* @param {number} version
|
|
97
99
|
* @return {!Uint8Array}
|
|
98
100
|
*/
|
|
99
|
-
static createPssh(data, systemId) {
|
|
101
|
+
static createPssh(data, systemId, keyIds, version) {
|
|
100
102
|
goog.asserts.assert(systemId.byteLength == 16, 'Invalid system ID length');
|
|
101
103
|
const dataLength = data.length;
|
|
102
|
-
|
|
104
|
+
let psshSize = 0x4 + 0x4 + 0x4 + systemId.length + 0x4 + dataLength;
|
|
105
|
+
if (version > 0) {
|
|
106
|
+
psshSize += 0x4 + (16 * keyIds.size);
|
|
107
|
+
}
|
|
103
108
|
|
|
104
109
|
/** @type {!Uint8Array} */
|
|
105
110
|
const psshBox = new Uint8Array(psshSize);
|
|
@@ -111,10 +116,24 @@ shaka.util.Pssh = class {
|
|
|
111
116
|
byteCursor += 0x4;
|
|
112
117
|
psshData.setUint32(byteCursor, 0x70737368); // 'pssh'
|
|
113
118
|
byteCursor += 0x4;
|
|
114
|
-
psshData.setUint32(byteCursor, 0)
|
|
119
|
+
(version < 1) ? psshData.setUint32(byteCursor, 0) :
|
|
120
|
+
psshData.setUint32(byteCursor, 0x01000000); // version + flags
|
|
115
121
|
byteCursor += 0x4;
|
|
116
122
|
psshBox.set(systemId, byteCursor);
|
|
117
123
|
byteCursor += systemId.length;
|
|
124
|
+
|
|
125
|
+
// if version > 0, add KID count and kid values.
|
|
126
|
+
if (version > 0) {
|
|
127
|
+
psshData.setUint32(byteCursor, keyIds.size); // KID_count
|
|
128
|
+
byteCursor += 0x4;
|
|
129
|
+
const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils;
|
|
130
|
+
for (const keyId of keyIds) {
|
|
131
|
+
const KID = Uint8ArrayUtils.fromHex(keyId);
|
|
132
|
+
psshBox.set(KID, byteCursor);
|
|
133
|
+
byteCursor += KID.length;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
118
137
|
psshData.setUint32(byteCursor, dataLength);
|
|
119
138
|
byteCursor += 0x4;
|
|
120
139
|
psshBox.set(data, byteCursor);
|