shaka-player 4.7.13 → 4.8.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/AUTHORS +1 -0
- package/CONTRIBUTORS +1 -0
- package/LICENSE +54 -0
- package/README.md +22 -1
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/deps.js +34 -23
- package/dist/locales.js +44 -34
- package/dist/shaka-player.compiled.d.ts +194 -44
- package/dist/shaka-player.compiled.debug.d.ts +194 -44
- package/dist/shaka-player.compiled.debug.externs.js +474 -337
- package/dist/shaka-player.compiled.debug.js +949 -832
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +474 -337
- package/dist/shaka-player.compiled.js +1237 -1171
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +257 -47
- package/dist/shaka-player.ui.debug.d.ts +257 -47
- package/dist/shaka-player.ui.debug.externs.js +591 -376
- package/dist/shaka-player.ui.debug.js +1165 -965
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +591 -376
- package/dist/shaka-player.ui.js +1521 -1404
- package/dist/shaka-player.ui.map +4 -4
- package/externs/device_sensor_event.js +18 -0
- package/externs/hisense.js +16 -0
- package/externs/playstation.js +31 -0
- package/externs/shaka/abr_manager.js +3 -1
- package/externs/shaka/ads.js +5 -0
- package/externs/shaka/codecs.js +13 -0
- package/externs/shaka/manifest.js +58 -6
- package/externs/shaka/net.js +13 -1
- package/externs/shaka/player.js +184 -13
- package/externs/shaka/text.js +19 -0
- package/externs/tizen.js +41 -0
- package/externs/webos.js +19 -0
- package/externs/xbox.js +43 -0
- package/lib/abr/simple_abr_manager.js +9 -1
- package/lib/ads/ad_manager.js +19 -2
- package/lib/ads/client_side_ad_manager.js +5 -3
- package/lib/ads/media_tailor_ad_manager.js +9 -0
- package/lib/cast/cast_receiver.js +0 -14
- package/lib/cast/cast_utils.js +1 -0
- package/lib/cea/mp4_cea_parser.js +6 -1
- package/lib/dash/content_protection.js +97 -53
- package/lib/dash/dash_parser.js +230 -176
- package/lib/dash/mpd_utils.js +72 -65
- package/lib/dash/segment_base.js +27 -21
- package/lib/dash/segment_list.js +18 -16
- package/lib/dash/segment_template.js +26 -21
- package/lib/hls/hls_parser.js +358 -164
- package/lib/media/buffering_observer.js +25 -1
- package/lib/media/drm_engine.js +91 -71
- package/lib/media/manifest_filterer.js +220 -0
- package/lib/media/media_source_engine.js +34 -5
- package/lib/media/preload_manager.js +827 -0
- package/lib/media/presentation_timeline.js +11 -0
- package/lib/media/segment_index.js +40 -30
- package/lib/media/segment_prefetch.js +140 -43
- package/lib/media/segment_reference.js +31 -8
- package/lib/media/segment_utils.js +208 -25
- package/lib/media/streaming_engine.js +319 -63
- package/lib/mss/content_protection.js +31 -25
- package/lib/mss/mss_parser.js +74 -55
- package/lib/net/networking_engine.js +49 -4
- package/lib/offline/storage.js +3 -3
- package/lib/player.js +882 -673
- package/lib/polyfill/media_capabilities.js +16 -1
- package/lib/text/simple_text_displayer.js +9 -0
- package/lib/text/stub_text_displayer.js +7 -0
- package/lib/text/text_engine.js +16 -3
- package/lib/text/ttml_text_parser.js +116 -114
- package/lib/text/ui_text_displayer.js +28 -11
- package/lib/text/vtt_text_parser.js +54 -115
- package/lib/transmuxer/opus.js +91 -0
- package/lib/transmuxer/ts_transmuxer.js +115 -0
- package/lib/util/cmcd_manager.js +152 -3
- package/lib/util/dom_utils.js +11 -0
- package/lib/util/error.js +5 -0
- package/lib/util/fake_event.js +2 -0
- package/lib/util/manifest_parser_utils.js +97 -3
- package/lib/util/mp4_box_parsers.js +346 -17
- package/lib/util/mp4_generator.js +23 -0
- package/lib/util/periods.js +19 -0
- package/lib/util/platform.js +161 -9
- package/lib/util/player_configuration.js +61 -3
- package/lib/util/stats.js +16 -0
- package/lib/util/stream_utils.js +16 -6
- package/lib/util/string_utils.js +36 -0
- package/lib/util/tXml.js +814 -0
- package/lib/util/ts_parser.js +50 -0
- package/lib/util/xml_utils.js +10 -338
- package/package.json +2 -2
- package/shaka-player.uncompiled.js +8 -0
- package/ui/controls.js +187 -5
- package/ui/enums.js +2 -0
- package/ui/externs/ui.js +30 -3
- package/ui/gl_matrix/matrix_4x4.js +568 -0
- package/ui/gl_matrix/matrix_quaternion.js +45 -0
- package/ui/less/containers.less +11 -0
- package/ui/locales/en-GB.json +2 -0
- package/ui/locales/en.json +2 -0
- package/ui/locales/es-419.json +2 -0
- package/ui/locales/es.json +2 -0
- package/ui/locales/source.json +8 -0
- package/ui/recenter_vr.js +126 -0
- package/ui/resolution_selection.js +25 -5
- package/ui/statistics_button.js +12 -0
- package/ui/text_selection.js +1 -1
- package/ui/toggle_stereoscopic.js +127 -0
- package/ui/ui.js +74 -38
- package/ui/vr_manager.js +557 -0
- package/ui/vr_utils.js +232 -0
- package/ui/vr_webgl.js +697 -0
package/externs/shaka/text.js
CHANGED
|
@@ -85,6 +85,18 @@ shaka.extern.TextParser = class {
|
|
|
85
85
|
shaka.extern.TextParser.TimeContext;
|
|
86
86
|
|
|
87
87
|
|
|
88
|
+
/**
|
|
89
|
+
* A callback used for editing cues before appending.
|
|
90
|
+
* Provides the cue, the URI of the captions file the cue was parsed from, and
|
|
91
|
+
* the time context that was used when generating that cue.
|
|
92
|
+
* You can edit the cue object passed in.
|
|
93
|
+
* @typedef {function(!shaka.text.Cue, ?string,
|
|
94
|
+
* !shaka.extern.TextParser.TimeContext)}
|
|
95
|
+
* @exportDoc
|
|
96
|
+
*/
|
|
97
|
+
shaka.extern.TextParser.ModifyCueCallback;
|
|
98
|
+
|
|
99
|
+
|
|
88
100
|
/**
|
|
89
101
|
* @typedef {function():!shaka.extern.TextParser}
|
|
90
102
|
* @exportDoc
|
|
@@ -120,6 +132,13 @@ shaka.extern.TextDisplayer = class {
|
|
|
120
132
|
*/
|
|
121
133
|
destroy() {}
|
|
122
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Sets the TextDisplayer configuration.
|
|
137
|
+
*
|
|
138
|
+
* @param {shaka.extern.TextDisplayerConfiguration} config
|
|
139
|
+
*/
|
|
140
|
+
configure(config) {}
|
|
141
|
+
|
|
123
142
|
/**
|
|
124
143
|
* Append given text cues to the list of cues to be displayed.
|
|
125
144
|
*
|
package/externs/tizen.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @fileoverview Externs for Tizen
|
|
9
|
+
* @externs
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/** @const */
|
|
14
|
+
var webapis = {};
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
/** @const */
|
|
18
|
+
webapis.systeminfo = {};
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @return {{width: number, height: number}}
|
|
23
|
+
*/
|
|
24
|
+
webapis.systeminfo.getMaxVideoResolution = function() {};
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
/** @const */
|
|
28
|
+
webapis.productinfo = {};
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @return {boolean}
|
|
33
|
+
*/
|
|
34
|
+
webapis.productinfo.is8KPanelSupported = function() {};
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @return {boolean}
|
|
39
|
+
*/
|
|
40
|
+
webapis.productinfo.isUdPanelSupported = function() {};
|
|
41
|
+
|
package/externs/webos.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @fileoverview Externs for WebOS
|
|
9
|
+
*
|
|
10
|
+
* @externs
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
/** @const */
|
|
15
|
+
var PalmSystem = {};
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
/** @type {string} */
|
|
19
|
+
PalmSystem.deviceInfo;
|
package/externs/xbox.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @fileoverview Externs for Xbox
|
|
9
|
+
*
|
|
10
|
+
* @externs
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
/** @const */
|
|
15
|
+
var Windows = {};
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
/** @const */
|
|
19
|
+
Windows.Media = {};
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
/** @const */
|
|
23
|
+
Windows.Media.Protection = {};
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
/** @const */
|
|
27
|
+
Windows.Media.Protection.ProtectionCapabilities = class {
|
|
28
|
+
/**
|
|
29
|
+
* @param {string} type
|
|
30
|
+
* @param {string} keySystem
|
|
31
|
+
* @return {!Windows.Media.Protection.ProtectionCapabilityResult}
|
|
32
|
+
*/
|
|
33
|
+
isTypeSupported(type, keySystem) {}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @enum {string}
|
|
38
|
+
*/
|
|
39
|
+
Windows.Media.Protection.ProtectionCapabilityResult = {
|
|
40
|
+
notSupported: 'NotSupported',
|
|
41
|
+
maybe: 'Maybe',
|
|
42
|
+
probably: 'Probably',
|
|
43
|
+
};
|
|
@@ -297,11 +297,19 @@ shaka.abr.SimpleAbrManager = class {
|
|
|
297
297
|
|
|
298
298
|
|
|
299
299
|
/**
|
|
300
|
+
* @param {number} deltaTimeMs The duration, in milliseconds, that the request
|
|
301
|
+
* took to complete.
|
|
302
|
+
* @param {number} numBytes The total number of bytes transferred.
|
|
303
|
+
* @param {boolean} allowSwitch Indicate if the segment is allowed to switch
|
|
304
|
+
* to another stream.
|
|
305
|
+
* @param {shaka.extern.Request=} request
|
|
306
|
+
* A reference to the request
|
|
300
307
|
* @override
|
|
301
308
|
* @export
|
|
302
309
|
*/
|
|
303
|
-
segmentDownloaded(deltaTimeMs, numBytes, allowSwitch) {
|
|
310
|
+
segmentDownloaded(deltaTimeMs, numBytes, allowSwitch, request) {
|
|
304
311
|
shaka.log.v2('Segment downloaded:',
|
|
312
|
+
'contentType=' + (request && request.contentType),
|
|
305
313
|
'deltaTimeMs=' + deltaTimeMs,
|
|
306
314
|
'numBytes=' + numBytes,
|
|
307
315
|
'lastTimeChosenMs=' + this.lastTimeChosenMs_,
|
package/lib/ads/ad_manager.js
CHANGED
|
@@ -560,6 +560,23 @@ shaka.ads.AdManager = class extends shaka.util.FakeEventTarget {
|
|
|
560
560
|
}
|
|
561
561
|
|
|
562
562
|
|
|
563
|
+
/**
|
|
564
|
+
* @param {string} url
|
|
565
|
+
* @override
|
|
566
|
+
* @export
|
|
567
|
+
*/
|
|
568
|
+
addMediaTailorTrackingUrl(url) {
|
|
569
|
+
if (!this.mtAdManager_) {
|
|
570
|
+
throw new shaka.util.Error(
|
|
571
|
+
shaka.util.Error.Severity.RECOVERABLE,
|
|
572
|
+
shaka.util.Error.Category.ADS,
|
|
573
|
+
shaka.util.Error.Code.MT_AD_MANAGER_NOT_INITIALIZED);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
this.mtAdManager_.addTrackingUrl(url);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
|
|
563
580
|
/**
|
|
564
581
|
* @override
|
|
565
582
|
* @export
|
|
@@ -705,8 +722,8 @@ shaka.ads.AdManager = class extends shaka.util.FakeEventTarget {
|
|
|
705
722
|
onDashTimedMetadata(region) {
|
|
706
723
|
if (this.ssAdManager_ && region.schemeIdUri == 'urn:google:dai:2018') {
|
|
707
724
|
const type = region.schemeIdUri;
|
|
708
|
-
const data = region.
|
|
709
|
-
region.
|
|
725
|
+
const data = region.eventNode ?
|
|
726
|
+
region.eventNode.attributes['messageData'] : null;
|
|
710
727
|
const timestamp = region.startTime;
|
|
711
728
|
this.ssAdManager_.onTimedMetadata(type, data, timestamp);
|
|
712
729
|
}
|
|
@@ -308,7 +308,7 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
308
308
|
// seen the ads actually play until requestAds() is called.
|
|
309
309
|
// Note: We listen for a play event to avoid autoplay issues that might
|
|
310
310
|
// crash IMA.
|
|
311
|
-
if (this.videoPlayed_) {
|
|
311
|
+
if (this.videoPlayed_ || this.config_.skipPlayDetection) {
|
|
312
312
|
this.imaAdsManager_.start();
|
|
313
313
|
} else {
|
|
314
314
|
this.eventManager_.listenOnce(this.video_, 'play', () => {
|
|
@@ -533,7 +533,9 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
533
533
|
shaka.ads.AdManager.AD_STARTED, data));
|
|
534
534
|
if (this.ad_.isLinear()) {
|
|
535
535
|
this.adContainer_.setAttribute('ad-active', 'true');
|
|
536
|
-
this.
|
|
536
|
+
if (!this.config_.customPlayheadTracker) {
|
|
537
|
+
this.video_.pause();
|
|
538
|
+
}
|
|
537
539
|
if (this.video_.muted) {
|
|
538
540
|
this.ad_.setInitialMuted(this.video_.volume);
|
|
539
541
|
} else {
|
|
@@ -551,7 +553,7 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
551
553
|
(new Map()).set('originalEvent', e)));
|
|
552
554
|
if (this.ad_ && this.ad_.isLinear()) {
|
|
553
555
|
this.adContainer_.removeAttribute('ad-active');
|
|
554
|
-
if (!this.video_.ended) {
|
|
556
|
+
if (!this.config_.customPlayheadTracker && !this.video_.ended) {
|
|
555
557
|
this.video_.play();
|
|
556
558
|
}
|
|
557
559
|
}
|
|
@@ -130,6 +130,15 @@ shaka.ads.MediaTailorAdManager = class {
|
|
|
130
130
|
return this.streamPromise_;
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
/**
|
|
134
|
+
* @param {string} url
|
|
135
|
+
*/
|
|
136
|
+
addTrackingUrl(url) {
|
|
137
|
+
this.trackingUrl_ = url;
|
|
138
|
+
this.onEvent_(new shaka.util.FakeEvent(shaka.ads.AdManager.ADS_LOADED,
|
|
139
|
+
(new Map()).set('loadTime', 0)));
|
|
140
|
+
}
|
|
141
|
+
|
|
133
142
|
/**
|
|
134
143
|
* Resets the MediaTailor manager and removes any continuous polling.
|
|
135
144
|
*/
|
|
@@ -287,20 +287,6 @@ shaka.cast.CastReceiver = class extends shaka.util.FakeEventTarget {
|
|
|
287
287
|
this.player_, name, (event) => this.proxyEvent_('player', event));
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
-
// In our tests, the original Chromecast seems to have trouble decoding
|
|
291
|
-
// above 1080p. It would be a waste to select a higher res anyway, given
|
|
292
|
-
// that the device only outputs 1080p to begin with.
|
|
293
|
-
|
|
294
|
-
// Chromecast has an extension to query the device/display's resolution.
|
|
295
|
-
if (cast.__platform__ && cast.__platform__.canDisplayType(
|
|
296
|
-
'video/mp4; codecs="avc1.640028"; width=3840; height=2160')) {
|
|
297
|
-
// The device and display can both do 4k. Assume a 4k limit.
|
|
298
|
-
this.player_.setMaxHardwareResolution(3840, 2160);
|
|
299
|
-
} else {
|
|
300
|
-
// Chromecast has always been able to do 1080p. Assume a 1080p limit.
|
|
301
|
-
this.player_.setMaxHardwareResolution(1920, 1080);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
290
|
// Do not start excluding values from update messages until the video is
|
|
305
291
|
// fully loaded.
|
|
306
292
|
this.eventManager_.listen(this.video_, 'loadeddata', () => {
|
package/lib/cast/cast_utils.js
CHANGED
|
@@ -107,6 +107,8 @@ shaka.cea.Mp4CeaParser = class {
|
|
|
107
107
|
.box('avc3', codecBoxParser)
|
|
108
108
|
.box('hev1', codecBoxParser)
|
|
109
109
|
.box('hvc1', codecBoxParser)
|
|
110
|
+
.box('dvav', codecBoxParser)
|
|
111
|
+
.box('dva1', codecBoxParser)
|
|
110
112
|
.box('dvh1', codecBoxParser)
|
|
111
113
|
.box('dvhe', codecBoxParser)
|
|
112
114
|
|
|
@@ -374,7 +376,10 @@ shaka.cea.Mp4CeaParser.CodecBitstreamMap_ = {
|
|
|
374
376
|
'avc3': shaka.cea.Mp4CeaParser.BitstreamFormat.H264,
|
|
375
377
|
'hev1': shaka.cea.Mp4CeaParser.BitstreamFormat.H265,
|
|
376
378
|
'hvc1': shaka.cea.Mp4CeaParser.BitstreamFormat.H265,
|
|
377
|
-
//
|
|
379
|
+
// Dolby Vision based in AVC
|
|
380
|
+
'dvav': shaka.cea.Mp4CeaParser.BitstreamFormat.H264,
|
|
381
|
+
'dva1': shaka.cea.Mp4CeaParser.BitstreamFormat.H264,
|
|
382
|
+
// Dolby Vision based in HEVC
|
|
378
383
|
'dvh1': shaka.cea.Mp4CeaParser.BitstreamFormat.H265,
|
|
379
384
|
'dvhe': shaka.cea.Mp4CeaParser.BitstreamFormat.H265,
|
|
380
385
|
};
|
|
@@ -13,8 +13,8 @@ goog.require('shaka.util.Error');
|
|
|
13
13
|
goog.require('shaka.util.ManifestParserUtils');
|
|
14
14
|
goog.require('shaka.util.Pssh');
|
|
15
15
|
goog.require('shaka.util.StringUtils');
|
|
16
|
+
goog.require('shaka.util.TXml');
|
|
16
17
|
goog.require('shaka.util.Uint8ArrayUtils');
|
|
17
|
-
goog.require('shaka.util.XmlUtils');
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
/**
|
|
@@ -25,7 +25,7 @@ shaka.dash.ContentProtection = class {
|
|
|
25
25
|
/**
|
|
26
26
|
* Parses info from the ContentProtection elements at the AdaptationSet level.
|
|
27
27
|
*
|
|
28
|
-
* @param {!Array.<!
|
|
28
|
+
* @param {!Array.<!shaka.extern.xml.Node>} elems
|
|
29
29
|
* @param {boolean} ignoreDrmInfo
|
|
30
30
|
* @param {!Object.<string, string>} keySystemsByURI
|
|
31
31
|
* @return {shaka.dash.ContentProtection.Context}
|
|
@@ -47,6 +47,8 @@ shaka.dash.ContentProtection = class {
|
|
|
47
47
|
// Remove any possible null value (elements may have no key ids).
|
|
48
48
|
keyIds.delete(null);
|
|
49
49
|
|
|
50
|
+
let encryptionScheme = 'cenc';
|
|
51
|
+
|
|
50
52
|
if (keyIds.size > 1) {
|
|
51
53
|
throw new shaka.util.Error(
|
|
52
54
|
shaka.util.Error.Severity.CRITICAL,
|
|
@@ -70,6 +72,14 @@ shaka.dash.ContentProtection = class {
|
|
|
70
72
|
aes128Info = ContentProtection.parseAes128_(aes128Elements[0]);
|
|
71
73
|
}
|
|
72
74
|
|
|
75
|
+
const mp4ProtectionParsed = parsed.find((elem) => {
|
|
76
|
+
return elem.schemeUri == ContentProtection.MP4Protection_;
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
if (mp4ProtectionParsed && mp4ProtectionParsed.encryptionScheme) {
|
|
80
|
+
encryptionScheme = mp4ProtectionParsed.encryptionScheme;
|
|
81
|
+
}
|
|
82
|
+
|
|
73
83
|
// Find the default key ID and init data. Create a new array of all the
|
|
74
84
|
// non-CENC elements.
|
|
75
85
|
parsedNonCenc = parsed.filter((elem) => {
|
|
@@ -84,13 +94,14 @@ shaka.dash.ContentProtection = class {
|
|
|
84
94
|
});
|
|
85
95
|
|
|
86
96
|
if (parsedNonCenc.length) {
|
|
87
|
-
drmInfos = ContentProtection.convertElements_(
|
|
88
|
-
|
|
97
|
+
drmInfos = ContentProtection.convertElements_(defaultInit,
|
|
98
|
+
encryptionScheme, parsedNonCenc, keySystemsByURI, keyIds);
|
|
89
99
|
|
|
90
100
|
// If there are no drmInfos after parsing, then add a dummy entry.
|
|
91
101
|
// This may be removed in parseKeyIds.
|
|
92
102
|
if (drmInfos.length == 0) {
|
|
93
|
-
drmInfos = [ManifestParserUtils.createDrmInfo(
|
|
103
|
+
drmInfos = [ManifestParserUtils.createDrmInfo(
|
|
104
|
+
'', encryptionScheme, defaultInit)];
|
|
94
105
|
}
|
|
95
106
|
}
|
|
96
107
|
}
|
|
@@ -106,8 +117,8 @@ shaka.dash.ContentProtection = class {
|
|
|
106
117
|
// put clearkey in this list. Otherwise, it may be triggered when
|
|
107
118
|
// a real key system should be used instead.
|
|
108
119
|
if (keySystem != 'org.w3.clearkey') {
|
|
109
|
-
const info =
|
|
110
|
-
|
|
120
|
+
const info = ManifestParserUtils.createDrmInfo(
|
|
121
|
+
keySystem, encryptionScheme, defaultInit);
|
|
111
122
|
drmInfos.push(info);
|
|
112
123
|
}
|
|
113
124
|
}
|
|
@@ -137,7 +148,7 @@ shaka.dash.ContentProtection = class {
|
|
|
137
148
|
* Parses the given ContentProtection elements found at the Representation
|
|
138
149
|
* level. This may update the |context|.
|
|
139
150
|
*
|
|
140
|
-
* @param {!Array.<!
|
|
151
|
+
* @param {!Array.<!shaka.extern.xml.Node>} elems
|
|
141
152
|
* @param {shaka.dash.ContentProtection.Context} context
|
|
142
153
|
* @param {boolean} ignoreDrmInfo
|
|
143
154
|
* @param {!Object.<string, string>} keySystemsByURI
|
|
@@ -191,17 +202,22 @@ shaka.dash.ContentProtection = class {
|
|
|
191
202
|
* @return {string}
|
|
192
203
|
*/
|
|
193
204
|
static getWidevineLicenseUrl(element) {
|
|
194
|
-
const
|
|
205
|
+
const StringUtils = shaka.util.StringUtils;
|
|
206
|
+
const dashIfLaurlNode = shaka.util.TXml.findChildNS(
|
|
195
207
|
element.node, shaka.dash.ContentProtection.DashIfNamespaceUri_,
|
|
196
208
|
'Laurl',
|
|
197
209
|
);
|
|
198
|
-
if (dashIfLaurlNode
|
|
199
|
-
|
|
210
|
+
if (dashIfLaurlNode) {
|
|
211
|
+
const textContents = shaka.util.TXml.getTextContents(dashIfLaurlNode);
|
|
212
|
+
if (textContents) {
|
|
213
|
+
return textContents;
|
|
214
|
+
}
|
|
200
215
|
}
|
|
201
|
-
const mslaurlNode = shaka.util.
|
|
216
|
+
const mslaurlNode = shaka.util.TXml.findChildNS(
|
|
202
217
|
element.node, 'urn:microsoft', 'laurl');
|
|
203
218
|
if (mslaurlNode) {
|
|
204
|
-
return
|
|
219
|
+
return StringUtils.htmlUnescape(
|
|
220
|
+
mslaurlNode.attributes['licenseUrl']) || '';
|
|
205
221
|
}
|
|
206
222
|
return '';
|
|
207
223
|
}
|
|
@@ -214,21 +230,27 @@ shaka.dash.ContentProtection = class {
|
|
|
214
230
|
* @return {string}
|
|
215
231
|
*/
|
|
216
232
|
static getClearKeyLicenseUrl(element) {
|
|
217
|
-
const dashIfLaurlNode = shaka.util.
|
|
233
|
+
const dashIfLaurlNode = shaka.util.TXml.findChildNS(
|
|
218
234
|
element.node, shaka.dash.ContentProtection.DashIfNamespaceUri_,
|
|
219
235
|
'Laurl',
|
|
220
236
|
);
|
|
221
|
-
if (dashIfLaurlNode
|
|
222
|
-
|
|
237
|
+
if (dashIfLaurlNode) {
|
|
238
|
+
const textContents = shaka.util.TXml.getTextContents(dashIfLaurlNode);
|
|
239
|
+
if (textContents) {
|
|
240
|
+
return textContents;
|
|
241
|
+
}
|
|
223
242
|
}
|
|
224
|
-
const clearKeyLaurlNode = shaka.util.
|
|
243
|
+
const clearKeyLaurlNode = shaka.util.TXml.findChildNS(
|
|
225
244
|
element.node, shaka.dash.ContentProtection.ClearKeyNamespaceUri_,
|
|
226
245
|
'Laurl',
|
|
227
246
|
);
|
|
228
247
|
if (clearKeyLaurlNode &&
|
|
229
|
-
|
|
230
|
-
if (clearKeyLaurlNode
|
|
231
|
-
|
|
248
|
+
clearKeyLaurlNode.attributes['Lic_type'] === 'EME-1.0') {
|
|
249
|
+
if (clearKeyLaurlNode) {
|
|
250
|
+
const textContents = shaka.util.TXml.getTextContents(clearKeyLaurlNode);
|
|
251
|
+
if (textContents) {
|
|
252
|
+
return textContents;
|
|
253
|
+
}
|
|
232
254
|
}
|
|
233
255
|
}
|
|
234
256
|
return '';
|
|
@@ -312,18 +334,21 @@ shaka.dash.ContentProtection = class {
|
|
|
312
334
|
/**
|
|
313
335
|
* PlayReady Header format: https://goo.gl/dBzxNA
|
|
314
336
|
*
|
|
315
|
-
* @param {!
|
|
337
|
+
* @param {!shaka.extern.xml.Node} xml
|
|
316
338
|
* @return {string}
|
|
317
339
|
* @private
|
|
318
340
|
*/
|
|
319
341
|
static getLaurl_(xml) {
|
|
342
|
+
const TXml = shaka.util.TXml;
|
|
320
343
|
// LA_URL element is optional and no more than one is
|
|
321
344
|
// allowed inside the DATA element. Only absolute URLs are allowed.
|
|
322
345
|
// If the LA_URL element exists, it must not be empty.
|
|
323
|
-
for (const elem of
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
346
|
+
for (const elem of TXml.getElementsByTagName(xml, 'DATA')) {
|
|
347
|
+
if (elem.children) {
|
|
348
|
+
for (const child of elem.children) {
|
|
349
|
+
if (child.tagName == 'LA_URL') {
|
|
350
|
+
return /** @type{string} */(shaka.util.TXml.getTextContents(child));
|
|
351
|
+
}
|
|
327
352
|
}
|
|
328
353
|
}
|
|
329
354
|
}
|
|
@@ -340,25 +365,30 @@ shaka.dash.ContentProtection = class {
|
|
|
340
365
|
* @return {string}
|
|
341
366
|
*/
|
|
342
367
|
static getPlayReadyLicenseUrl(element) {
|
|
343
|
-
const dashIfLaurlNode = shaka.util.
|
|
368
|
+
const dashIfLaurlNode = shaka.util.TXml.findChildNS(
|
|
344
369
|
element.node, shaka.dash.ContentProtection.DashIfNamespaceUri_,
|
|
345
370
|
'Laurl',
|
|
346
371
|
);
|
|
347
|
-
if (dashIfLaurlNode
|
|
348
|
-
|
|
372
|
+
if (dashIfLaurlNode) {
|
|
373
|
+
const textContents = shaka.util.TXml.getTextContents(dashIfLaurlNode);
|
|
374
|
+
if (textContents) {
|
|
375
|
+
return textContents;
|
|
376
|
+
}
|
|
349
377
|
}
|
|
350
378
|
|
|
351
|
-
const proNode = shaka.util.
|
|
379
|
+
const proNode = shaka.util.TXml.findChildNS(
|
|
352
380
|
element.node, 'urn:microsoft:playready', 'pro');
|
|
353
381
|
|
|
354
|
-
if (!proNode) {
|
|
382
|
+
if (!proNode || !shaka.util.TXml.getTextContents(proNode)) {
|
|
355
383
|
return '';
|
|
356
384
|
}
|
|
357
385
|
|
|
358
386
|
const ContentProtection = shaka.dash.ContentProtection;
|
|
359
387
|
const PLAYREADY_RECORD_TYPES = ContentProtection.PLAYREADY_RECORD_TYPES;
|
|
360
388
|
|
|
361
|
-
const
|
|
389
|
+
const textContent =
|
|
390
|
+
/** @type {string} */ (shaka.util.TXml.getTextContents(proNode));
|
|
391
|
+
const bytes = shaka.util.Uint8ArrayUtils.fromBase64(textContent);
|
|
362
392
|
const records = ContentProtection.parseMsPro_(bytes);
|
|
363
393
|
const record = records.filter((record) => {
|
|
364
394
|
return record.type === PLAYREADY_RECORD_TYPES.RIGHTS_MANAGEMENT;
|
|
@@ -369,7 +399,7 @@ shaka.dash.ContentProtection = class {
|
|
|
369
399
|
}
|
|
370
400
|
|
|
371
401
|
const xml = shaka.util.StringUtils.fromUTF16(record.value, true);
|
|
372
|
-
const rootElement = shaka.util.
|
|
402
|
+
const rootElement = shaka.util.TXml.parseXmlString(xml, 'WRMHEADER');
|
|
373
403
|
if (!rootElement) {
|
|
374
404
|
return '';
|
|
375
405
|
}
|
|
@@ -386,13 +416,16 @@ shaka.dash.ContentProtection = class {
|
|
|
386
416
|
* @private
|
|
387
417
|
*/
|
|
388
418
|
static getInitDataFromPro_(element) {
|
|
389
|
-
const proNode = shaka.util.
|
|
419
|
+
const proNode = shaka.util.TXml.findChildNS(
|
|
390
420
|
element.node, 'urn:microsoft:playready', 'pro');
|
|
391
|
-
if (!proNode) {
|
|
421
|
+
if (!proNode || !shaka.util.TXml.getTextContents(proNode)) {
|
|
392
422
|
return null;
|
|
393
423
|
}
|
|
424
|
+
|
|
394
425
|
const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils;
|
|
395
|
-
const
|
|
426
|
+
const textContent =
|
|
427
|
+
/** @type{string} */ (shaka.util.TXml.getTextContents(proNode));
|
|
428
|
+
const data = Uint8ArrayUtils.fromBase64(textContent);
|
|
396
429
|
const systemId = new Uint8Array([
|
|
397
430
|
0x9a, 0x04, 0xf0, 0x79, 0x98, 0x40, 0x42, 0x86,
|
|
398
431
|
0xab, 0x92, 0xe6, 0x5b, 0xe0, 0x88, 0x5f, 0x95,
|
|
@@ -445,13 +478,15 @@ shaka.dash.ContentProtection = class {
|
|
|
445
478
|
* Creates DrmInfo objects from the given element.
|
|
446
479
|
*
|
|
447
480
|
* @param {Array.<shaka.extern.InitDataOverride>} defaultInit
|
|
481
|
+
* @param {string} encryptionScheme
|
|
448
482
|
* @param {!Array.<shaka.dash.ContentProtection.Element>} elements
|
|
449
483
|
* @param {!Object.<string, string>} keySystemsByURI
|
|
450
484
|
* @param {!Set.<string>} keyIds
|
|
451
485
|
* @return {!Array.<shaka.extern.DrmInfo>}
|
|
452
486
|
* @private
|
|
453
487
|
*/
|
|
454
|
-
static convertElements_(defaultInit,
|
|
488
|
+
static convertElements_(defaultInit, encryptionScheme, elements,
|
|
489
|
+
keySystemsByURI, keyIds) {
|
|
455
490
|
const ContentProtection = shaka.dash.ContentProtection;
|
|
456
491
|
const ManifestParserUtils = shaka.util.ManifestParserUtils;
|
|
457
492
|
const licenseUrlParsers = ContentProtection.licenseUrlParsers_;
|
|
@@ -475,7 +510,8 @@ shaka.dash.ContentProtection = class {
|
|
|
475
510
|
}
|
|
476
511
|
const initData = element.init || defaultInit || proInitData ||
|
|
477
512
|
clearKeyInitData;
|
|
478
|
-
const info = ManifestParserUtils.createDrmInfo(
|
|
513
|
+
const info = ManifestParserUtils.createDrmInfo(
|
|
514
|
+
keySystem, encryptionScheme, initData);
|
|
479
515
|
const licenseParser = licenseUrlParsers.get(keySystem);
|
|
480
516
|
if (licenseParser) {
|
|
481
517
|
info.licenseServerUri = licenseParser(element);
|
|
@@ -492,7 +528,7 @@ shaka.dash.ContentProtection = class {
|
|
|
492
528
|
* Parses the given ContentProtection elements. If there is an error, it
|
|
493
529
|
* removes those elements.
|
|
494
530
|
*
|
|
495
|
-
* @param {!Array.<!
|
|
531
|
+
* @param {!Array.<!shaka.extern.xml.Node>} elems
|
|
496
532
|
* @return {!Array.<shaka.dash.ContentProtection.Element>}
|
|
497
533
|
* @private
|
|
498
534
|
*/
|
|
@@ -513,20 +549,23 @@ shaka.dash.ContentProtection = class {
|
|
|
513
549
|
/**
|
|
514
550
|
* Parses the given ContentProtection element.
|
|
515
551
|
*
|
|
516
|
-
* @param {!
|
|
552
|
+
* @param {!shaka.extern.xml.Node} elem
|
|
517
553
|
* @return {?shaka.dash.ContentProtection.Element}
|
|
518
554
|
* @private
|
|
519
555
|
*/
|
|
520
556
|
static parseElement_(elem) {
|
|
521
557
|
const NS = shaka.dash.ContentProtection.CencNamespaceUri_;
|
|
558
|
+
const TXml = shaka.util.TXml;
|
|
522
559
|
|
|
523
560
|
/** @type {?string} */
|
|
524
|
-
let schemeUri = elem.
|
|
561
|
+
let schemeUri = elem.attributes['schemeIdUri'];
|
|
525
562
|
/** @type {?string} */
|
|
526
|
-
let keyId =
|
|
563
|
+
let keyId = TXml.getAttributeNS(elem, NS, 'default_KID');
|
|
527
564
|
/** @type {!Array.<string>} */
|
|
528
|
-
const psshs =
|
|
529
|
-
.map(
|
|
565
|
+
const psshs = TXml.findChildrenNS(elem, NS, 'pssh')
|
|
566
|
+
.map(TXml.getContents);
|
|
567
|
+
|
|
568
|
+
const encryptionScheme = elem.attributes['value'];
|
|
530
569
|
|
|
531
570
|
if (!schemeUri) {
|
|
532
571
|
shaka.log.error('Missing required schemeIdUri attribute on',
|
|
@@ -565,9 +604,10 @@ shaka.dash.ContentProtection = class {
|
|
|
565
604
|
|
|
566
605
|
return {
|
|
567
606
|
node: elem,
|
|
568
|
-
schemeUri
|
|
569
|
-
keyId
|
|
607
|
+
schemeUri,
|
|
608
|
+
keyId,
|
|
570
609
|
init: (init.length > 0 ? init : null),
|
|
610
|
+
encryptionScheme,
|
|
571
611
|
};
|
|
572
612
|
}
|
|
573
613
|
|
|
@@ -590,7 +630,7 @@ shaka.dash.ContentProtection = class {
|
|
|
590
630
|
}
|
|
591
631
|
|
|
592
632
|
const namespace = 'urn:mpeg:dash:schema:sea:2012';
|
|
593
|
-
const segmentEncryption = shaka.util.
|
|
633
|
+
const segmentEncryption = shaka.util.TXml.findChildNS(
|
|
594
634
|
element.node, namespace, 'SegmentEncryption');
|
|
595
635
|
|
|
596
636
|
if (!segmentEncryption) {
|
|
@@ -602,7 +642,7 @@ shaka.dash.ContentProtection = class {
|
|
|
602
642
|
|
|
603
643
|
const aesSchemeIdUri = 'urn:mpeg:dash:sea:aes128-cbc:2013';
|
|
604
644
|
const segmentEncryptionSchemeIdUri =
|
|
605
|
-
segmentEncryption.
|
|
645
|
+
segmentEncryption.attributes['schemeIdUri'];
|
|
606
646
|
if (segmentEncryptionSchemeIdUri != aesSchemeIdUri) {
|
|
607
647
|
throw new shaka.util.Error(
|
|
608
648
|
shaka.util.Error.Severity.CRITICAL,
|
|
@@ -610,7 +650,7 @@ shaka.dash.ContentProtection = class {
|
|
|
610
650
|
shaka.util.Error.Code.DASH_UNSUPPORTED_AES_128);
|
|
611
651
|
}
|
|
612
652
|
|
|
613
|
-
const cryptoPeriod = shaka.util.
|
|
653
|
+
const cryptoPeriod = shaka.util.TXml.findChildNS(
|
|
614
654
|
element.node, namespace, 'CryptoPeriod');
|
|
615
655
|
|
|
616
656
|
if (!cryptoPeriod) {
|
|
@@ -620,8 +660,9 @@ shaka.dash.ContentProtection = class {
|
|
|
620
660
|
shaka.util.Error.Code.DASH_UNSUPPORTED_AES_128);
|
|
621
661
|
}
|
|
622
662
|
|
|
623
|
-
const ivHex = cryptoPeriod.
|
|
624
|
-
const keyUri =
|
|
663
|
+
const ivHex = cryptoPeriod.attributes['IV'];
|
|
664
|
+
const keyUri = shaka.util.StringUtils.htmlUnescape(
|
|
665
|
+
cryptoPeriod.attributes['keyUriTemplate']);
|
|
625
666
|
if (!ivHex || !keyUri) {
|
|
626
667
|
throw new shaka.util.Error(
|
|
627
668
|
shaka.util.Error.Severity.CRITICAL,
|
|
@@ -721,16 +762,17 @@ shaka.dash.ContentProtection.Aes128Info;
|
|
|
721
762
|
|
|
722
763
|
/**
|
|
723
764
|
* @typedef {{
|
|
724
|
-
* node: !
|
|
765
|
+
* node: !shaka.extern.xml.Node,
|
|
725
766
|
* schemeUri: string,
|
|
726
767
|
* keyId: ?string,
|
|
727
|
-
* init: Array.<shaka.extern.InitDataOverride
|
|
768
|
+
* init: Array.<shaka.extern.InitDataOverride>,
|
|
769
|
+
* encryptionScheme: ?string
|
|
728
770
|
* }}
|
|
729
771
|
*
|
|
730
772
|
* @description
|
|
731
773
|
* The parsed result of a single ContentProtection element.
|
|
732
774
|
*
|
|
733
|
-
* @property {!
|
|
775
|
+
* @property {!shaka.extern.xml.Node} node
|
|
734
776
|
* The ContentProtection XML element.
|
|
735
777
|
* @property {string} schemeUri
|
|
736
778
|
* The scheme URI.
|
|
@@ -739,6 +781,8 @@ shaka.dash.ContentProtection.Aes128Info;
|
|
|
739
781
|
* @property {Array.<shaka.extern.InitDataOverride>} init
|
|
740
782
|
* The init data, if present. If there is no init data, it will be null. If
|
|
741
783
|
* this is non-null, there is at least one element.
|
|
784
|
+
* @property {?string} encryptionScheme
|
|
785
|
+
* The encryption scheme, if present.
|
|
742
786
|
*/
|
|
743
787
|
shaka.dash.ContentProtection.Element;
|
|
744
788
|
|