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
|
@@ -11,8 +11,8 @@ goog.require('shaka.util.BufferUtils');
|
|
|
11
11
|
goog.require('shaka.util.ManifestParserUtils');
|
|
12
12
|
goog.require('shaka.util.Pssh');
|
|
13
13
|
goog.require('shaka.util.StringUtils');
|
|
14
|
+
goog.require('shaka.util.TXml');
|
|
14
15
|
goog.require('shaka.util.Uint8ArrayUtils');
|
|
15
|
-
goog.require('shaka.util.XmlUtils');
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
/**
|
|
@@ -23,19 +23,19 @@ shaka.mss.ContentProtection = class {
|
|
|
23
23
|
/**
|
|
24
24
|
* Parses info from the Protection elements.
|
|
25
25
|
*
|
|
26
|
-
* @param {!Array.<!
|
|
26
|
+
* @param {!Array.<!shaka.extern.xml.Node>} elems
|
|
27
27
|
* @param {!Object.<string, string>} keySystemsBySystemId
|
|
28
28
|
* @return {!Array.<shaka.extern.DrmInfo>}
|
|
29
29
|
*/
|
|
30
30
|
static parseFromProtection(elems, keySystemsBySystemId) {
|
|
31
31
|
const ContentProtection = shaka.mss.ContentProtection;
|
|
32
|
-
const
|
|
32
|
+
const TXml = shaka.util.TXml;
|
|
33
33
|
|
|
34
|
-
/** @type {!Array.<!
|
|
34
|
+
/** @type {!Array.<!shaka.extern.xml.Node>} */
|
|
35
35
|
let protectionHeader = [];
|
|
36
36
|
for (const elem of elems) {
|
|
37
37
|
protectionHeader = protectionHeader.concat(
|
|
38
|
-
|
|
38
|
+
TXml.findChildren(elem, 'ProtectionHeader'));
|
|
39
39
|
}
|
|
40
40
|
if (!protectionHeader.length) {
|
|
41
41
|
return [];
|
|
@@ -123,18 +123,19 @@ shaka.mss.ContentProtection = class {
|
|
|
123
123
|
* Parse a PlayReady Header format: https://goo.gl/dBzxNA
|
|
124
124
|
* a try to find the LA_URL value.
|
|
125
125
|
*
|
|
126
|
-
* @param {!
|
|
126
|
+
* @param {!shaka.extern.xml.Node} xml
|
|
127
127
|
* @return {string}
|
|
128
128
|
* @private
|
|
129
129
|
*/
|
|
130
130
|
static getLaurl_(xml) {
|
|
131
|
+
const TXml = shaka.util.TXml;
|
|
131
132
|
// LA_URL element is optional and no more than one is
|
|
132
133
|
// allowed inside the DATA element. Only absolute URLs are allowed.
|
|
133
134
|
// If the LA_URL element exists, it must not be empty.
|
|
134
|
-
for (const elem of
|
|
135
|
-
const laUrl =
|
|
135
|
+
for (const elem of TXml.getElementsByTagName(xml, 'DATA')) {
|
|
136
|
+
const laUrl = TXml.findChild(elem, 'LA_URL');
|
|
136
137
|
if (laUrl) {
|
|
137
|
-
return laUrl
|
|
138
|
+
return /** @type {string} */ (shaka.util.TXml.getTextContents(laUrl));
|
|
138
139
|
}
|
|
139
140
|
}
|
|
140
141
|
|
|
@@ -148,7 +149,7 @@ shaka.mss.ContentProtection = class {
|
|
|
148
149
|
* Gets a PlayReady license URL from a protection element
|
|
149
150
|
* containing a PlayReady Header Object
|
|
150
151
|
*
|
|
151
|
-
* @param {!
|
|
152
|
+
* @param {!shaka.extern.xml.Node} element
|
|
152
153
|
* @return {string}
|
|
153
154
|
*/
|
|
154
155
|
static getPlayReadyLicenseUrl(element) {
|
|
@@ -165,19 +166,21 @@ shaka.mss.ContentProtection = class {
|
|
|
165
166
|
* Parse a PlayReady Header format: https://goo.gl/dBzxNA
|
|
166
167
|
* a try to find the KID value.
|
|
167
168
|
*
|
|
168
|
-
* @param {!
|
|
169
|
+
* @param {!shaka.extern.xml.Node} xml
|
|
169
170
|
* @return {?string}
|
|
170
171
|
* @private
|
|
171
172
|
*/
|
|
172
173
|
static getKID_(xml) {
|
|
174
|
+
const TXml = shaka.util.TXml;
|
|
173
175
|
// KID element is optional and no more than one is
|
|
174
176
|
// allowed inside the DATA element.
|
|
175
|
-
for (const elem of
|
|
176
|
-
const kid =
|
|
177
|
+
for (const elem of TXml.getElementsByTagName(xml, 'DATA')) {
|
|
178
|
+
const kid = TXml.findChild(elem, 'KID');
|
|
177
179
|
if (kid) {
|
|
178
180
|
// GUID: [DWORD, WORD, WORD, 8-BYTE]
|
|
179
181
|
const guidBytes =
|
|
180
|
-
shaka.util.Uint8ArrayUtils.fromBase64(
|
|
182
|
+
shaka.util.Uint8ArrayUtils.fromBase64(
|
|
183
|
+
/** @type{string} */ (shaka.util.TXml.getTextContents(kid)));
|
|
181
184
|
// Reverse byte order from little-endian to big-endian
|
|
182
185
|
const kidBytes = new Uint8Array([
|
|
183
186
|
guidBytes[3], guidBytes[2], guidBytes[1], guidBytes[0],
|
|
@@ -197,7 +200,7 @@ shaka.mss.ContentProtection = class {
|
|
|
197
200
|
* Gets a PlayReady KID from a protection element
|
|
198
201
|
* containing a PlayReady Header Object
|
|
199
202
|
*
|
|
200
|
-
* @param {!
|
|
203
|
+
* @param {!shaka.extern.xml.Node} element
|
|
201
204
|
* @return {?string}
|
|
202
205
|
* @private
|
|
203
206
|
*/
|
|
@@ -214,15 +217,16 @@ shaka.mss.ContentProtection = class {
|
|
|
214
217
|
/**
|
|
215
218
|
* Gets a PlayReady Header Object from a protection element
|
|
216
219
|
*
|
|
217
|
-
* @param {!
|
|
218
|
-
* @return {?
|
|
220
|
+
* @param {!shaka.extern.xml.Node} element
|
|
221
|
+
* @return {?shaka.extern.xml.Node}
|
|
219
222
|
* @private
|
|
220
223
|
*/
|
|
221
224
|
static getPlayReadyHeaderObject_(element) {
|
|
222
225
|
const ContentProtection = shaka.mss.ContentProtection;
|
|
223
226
|
const PLAYREADY_RECORD_TYPES = ContentProtection.PLAYREADY_RECORD_TYPES;
|
|
224
227
|
|
|
225
|
-
const bytes = shaka.util.Uint8ArrayUtils.fromBase64(
|
|
228
|
+
const bytes = shaka.util.Uint8ArrayUtils.fromBase64(
|
|
229
|
+
/** @type{string} */ (shaka.util.TXml.getTextContents(element)));
|
|
226
230
|
const records = ContentProtection.parseMsPro_(bytes);
|
|
227
231
|
const record = records.filter((record) => {
|
|
228
232
|
return record.type === PLAYREADY_RECORD_TYPES.RIGHTS_MANAGEMENT;
|
|
@@ -233,7 +237,7 @@ shaka.mss.ContentProtection = class {
|
|
|
233
237
|
}
|
|
234
238
|
|
|
235
239
|
const xml = shaka.util.StringUtils.fromUTF16(record.value, true);
|
|
236
|
-
const rootElement = shaka.util.
|
|
240
|
+
const rootElement = shaka.util.TXml.parseXmlString(xml, 'WRMHEADER');
|
|
237
241
|
if (!rootElement) {
|
|
238
242
|
return null;
|
|
239
243
|
}
|
|
@@ -243,7 +247,7 @@ shaka.mss.ContentProtection = class {
|
|
|
243
247
|
/**
|
|
244
248
|
* Gets a initData from a protection element.
|
|
245
249
|
*
|
|
246
|
-
* @param {!
|
|
250
|
+
* @param {!shaka.extern.xml.Node} element
|
|
247
251
|
* @param {string} systemID
|
|
248
252
|
* @param {?string} keyId
|
|
249
253
|
* @return {?Array.<shaka.extern.InitDataOverride>}
|
|
@@ -251,7 +255,8 @@ shaka.mss.ContentProtection = class {
|
|
|
251
255
|
*/
|
|
252
256
|
static getInitDataFromPro_(element, systemID, keyId) {
|
|
253
257
|
const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils;
|
|
254
|
-
const data = Uint8ArrayUtils.fromBase64(
|
|
258
|
+
const data = Uint8ArrayUtils.fromBase64(
|
|
259
|
+
/** @type{string} */ (shaka.util.TXml.getTextContents(element)));
|
|
255
260
|
const systemId = Uint8ArrayUtils.fromHex(systemID.replace(/-/g, ''));
|
|
256
261
|
const keyIds = new Set();
|
|
257
262
|
const psshVersion = 0;
|
|
@@ -269,7 +274,7 @@ shaka.mss.ContentProtection = class {
|
|
|
269
274
|
/**
|
|
270
275
|
* Creates DrmInfo objects from an array of elements.
|
|
271
276
|
*
|
|
272
|
-
* @param {!Array.<!
|
|
277
|
+
* @param {!Array.<!shaka.extern.xml.Node>} elements
|
|
273
278
|
* @param {!Object.<string, string>} keySystemsBySystemId
|
|
274
279
|
* @return {!Array.<shaka.extern.DrmInfo>}
|
|
275
280
|
* @private
|
|
@@ -284,14 +289,15 @@ shaka.mss.ContentProtection = class {
|
|
|
284
289
|
|
|
285
290
|
for (let i = 0; i < elements.length; i++) {
|
|
286
291
|
const element = elements[i];
|
|
287
|
-
const systemID = element.
|
|
292
|
+
const systemID = element.attributes['SystemID'].toLowerCase();
|
|
288
293
|
const keySystem = keySystemsBySystemId[systemID];
|
|
289
294
|
if (keySystem) {
|
|
290
295
|
const KID = ContentProtection.getPlayReadyKID_(element);
|
|
291
296
|
const initData = ContentProtection.getInitDataFromPro_(
|
|
292
297
|
element, systemID, KID);
|
|
293
298
|
|
|
294
|
-
const info = ManifestParserUtils.createDrmInfo(
|
|
299
|
+
const info = ManifestParserUtils.createDrmInfo(
|
|
300
|
+
keySystem, /* encryptionScheme= */ 'cenc', initData);
|
|
295
301
|
if (KID) {
|
|
296
302
|
info.keyIds.add(KID);
|
|
297
303
|
}
|
|
@@ -338,7 +344,7 @@ shaka.mss.ContentProtection.PLAYREADY_RECORD_TYPES = {
|
|
|
338
344
|
/**
|
|
339
345
|
* A map of key system name to license server url parser.
|
|
340
346
|
*
|
|
341
|
-
* @const {!Map.<string, function(!
|
|
347
|
+
* @const {!Map.<string, function(!shaka.extern.xml.Node)>}
|
|
342
348
|
* @private
|
|
343
349
|
*/
|
|
344
350
|
shaka.mss.ContentProtection.licenseUrlParsers_ = new Map()
|
package/lib/mss/mss_parser.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
goog.provide('shaka.mss.MssParser');
|
|
8
8
|
|
|
9
9
|
goog.require('goog.asserts');
|
|
10
|
+
goog.require('shaka.Deprecate');
|
|
10
11
|
goog.require('shaka.abr.Ewma');
|
|
11
12
|
goog.require('shaka.log');
|
|
12
13
|
goog.require('shaka.media.InitSegmentReference');
|
|
@@ -23,6 +24,7 @@ goog.require('shaka.util.MimeUtils');
|
|
|
23
24
|
goog.require('shaka.util.Mp4Generator');
|
|
24
25
|
goog.require('shaka.util.OperationManager');
|
|
25
26
|
goog.require('shaka.util.Timer');
|
|
27
|
+
goog.require('shaka.util.TXml');
|
|
26
28
|
goog.require('shaka.util.XmlUtils');
|
|
27
29
|
|
|
28
30
|
|
|
@@ -278,7 +280,25 @@ shaka.mss.MssParser = class {
|
|
|
278
280
|
* @private
|
|
279
281
|
*/
|
|
280
282
|
parseManifest_(data, finalManifestUri) {
|
|
281
|
-
|
|
283
|
+
let manifestData = data;
|
|
284
|
+
const manifestPreprocessor = this.config_.mss.manifestPreprocessor;
|
|
285
|
+
if (manifestPreprocessor) {
|
|
286
|
+
shaka.Deprecate.deprecateFeature(5,
|
|
287
|
+
'manifest.mss.manifestPreprocessor configuration',
|
|
288
|
+
'Please Use manifest.mss.manifestPreprocessorTXml instead.');
|
|
289
|
+
const mssElement =
|
|
290
|
+
shaka.util.XmlUtils.parseXml(manifestData, 'SmoothStreamingMedia');
|
|
291
|
+
if (!mssElement) {
|
|
292
|
+
throw new shaka.util.Error(
|
|
293
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
294
|
+
shaka.util.Error.Category.MANIFEST,
|
|
295
|
+
shaka.util.Error.Code.MSS_INVALID_XML,
|
|
296
|
+
finalManifestUri);
|
|
297
|
+
}
|
|
298
|
+
manifestPreprocessor(mssElement);
|
|
299
|
+
manifestData = shaka.util.XmlUtils.toArrayBuffer(mssElement);
|
|
300
|
+
}
|
|
301
|
+
const mss = shaka.util.TXml.parseXml(manifestData, 'SmoothStreamingMedia');
|
|
282
302
|
if (!mss) {
|
|
283
303
|
throw new shaka.util.Error(
|
|
284
304
|
shaka.util.Error.Severity.CRITICAL,
|
|
@@ -286,6 +306,10 @@ shaka.mss.MssParser = class {
|
|
|
286
306
|
shaka.util.Error.Code.MSS_INVALID_XML,
|
|
287
307
|
finalManifestUri);
|
|
288
308
|
}
|
|
309
|
+
const manifestPreprocessorTXml = this.config_.mss.manifestPreprocessorTXml;
|
|
310
|
+
if (manifestPreprocessorTXml) {
|
|
311
|
+
manifestPreprocessorTXml(mss);
|
|
312
|
+
}
|
|
289
313
|
this.processManifest_(mss, finalManifestUri);
|
|
290
314
|
return Promise.resolve();
|
|
291
315
|
}
|
|
@@ -294,26 +318,21 @@ shaka.mss.MssParser = class {
|
|
|
294
318
|
/**
|
|
295
319
|
* Takes a formatted MSS and converts it into a manifest.
|
|
296
320
|
*
|
|
297
|
-
* @param {!
|
|
321
|
+
* @param {!shaka.extern.xml.Node} mss
|
|
298
322
|
* @param {string} finalManifestUri The final manifest URI, which may
|
|
299
323
|
* differ from this.manifestUri_ if there has been a redirect.
|
|
300
324
|
* @private
|
|
301
325
|
*/
|
|
302
326
|
processManifest_(mss, finalManifestUri) {
|
|
303
|
-
const
|
|
304
|
-
|
|
305
|
-
const manifestPreprocessor = this.config_.mss.manifestPreprocessor;
|
|
306
|
-
if (manifestPreprocessor) {
|
|
307
|
-
manifestPreprocessor(mss);
|
|
308
|
-
}
|
|
327
|
+
const TXml = shaka.util.TXml;
|
|
309
328
|
|
|
310
329
|
if (!this.presentationTimeline_) {
|
|
311
330
|
this.presentationTimeline_ = new shaka.media.PresentationTimeline(
|
|
312
331
|
/* presentationStartTime= */ null, /* delay= */ 0);
|
|
313
332
|
}
|
|
314
333
|
|
|
315
|
-
const isLive =
|
|
316
|
-
|
|
334
|
+
const isLive = TXml.parseAttr(mss, 'IsLive',
|
|
335
|
+
TXml.parseBoolean, /* defaultValue= */ false);
|
|
317
336
|
|
|
318
337
|
if (isLive) {
|
|
319
338
|
throw new shaka.util.Error(
|
|
@@ -324,21 +343,21 @@ shaka.mss.MssParser = class {
|
|
|
324
343
|
|
|
325
344
|
this.presentationTimeline_.setStatic(!isLive);
|
|
326
345
|
|
|
327
|
-
const timescale =
|
|
328
|
-
|
|
346
|
+
const timescale = TXml.parseAttr(mss, 'TimeScale',
|
|
347
|
+
TXml.parseNonNegativeInt, shaka.mss.MssParser.DEFAULT_TIME_SCALE_);
|
|
329
348
|
goog.asserts.assert(timescale && timescale >= 0,
|
|
330
349
|
'Timescale must be defined!');
|
|
331
350
|
|
|
332
|
-
let dvrWindowLength =
|
|
333
|
-
|
|
351
|
+
let dvrWindowLength = TXml.parseAttr(mss, 'DVRWindowLength',
|
|
352
|
+
TXml.parseNonNegativeInt);
|
|
334
353
|
// If the DVRWindowLength field is omitted for a live presentation or set
|
|
335
354
|
// to 0, the DVR window is effectively infinite
|
|
336
355
|
if (isLive && (dvrWindowLength === 0 || isNaN(dvrWindowLength))) {
|
|
337
356
|
dvrWindowLength = Infinity;
|
|
338
357
|
}
|
|
339
358
|
// Start-over
|
|
340
|
-
const canSeek =
|
|
341
|
-
|
|
359
|
+
const canSeek = TXml.parseAttr(mss, 'CanSeek',
|
|
360
|
+
TXml.parseBoolean, /* defaultValue= */ false);
|
|
342
361
|
if (dvrWindowLength === 0 && canSeek) {
|
|
343
362
|
dvrWindowLength = Infinity;
|
|
344
363
|
}
|
|
@@ -363,8 +382,8 @@ shaka.mss.MssParser = class {
|
|
|
363
382
|
segmentAvailabilityDuration);
|
|
364
383
|
|
|
365
384
|
// Duration in timescale units.
|
|
366
|
-
const duration =
|
|
367
|
-
|
|
385
|
+
const duration = TXml.parseAttr(mss, 'Duration',
|
|
386
|
+
TXml.parseNonNegativeInt, Infinity);
|
|
368
387
|
goog.asserts.assert(duration && duration >= 0,
|
|
369
388
|
'Duration must be defined!');
|
|
370
389
|
|
|
@@ -414,25 +433,25 @@ shaka.mss.MssParser = class {
|
|
|
414
433
|
}
|
|
415
434
|
|
|
416
435
|
/**
|
|
417
|
-
* @param {!
|
|
436
|
+
* @param {!shaka.extern.xml.Node} mss
|
|
418
437
|
* @param {!shaka.mss.MssParser.Context} context
|
|
419
438
|
* @private
|
|
420
439
|
*/
|
|
421
440
|
parseStreamIndexes_(mss, context) {
|
|
422
441
|
const ContentProtection = shaka.mss.ContentProtection;
|
|
423
|
-
const
|
|
442
|
+
const TXml = shaka.util.TXml;
|
|
424
443
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
425
444
|
|
|
426
|
-
const protectionElems =
|
|
445
|
+
const protectionElems = TXml.findChildren(mss, 'Protection');
|
|
427
446
|
const drmInfos = ContentProtection.parseFromProtection(
|
|
428
447
|
protectionElems, this.config_.mss.keySystemsBySystemId);
|
|
429
448
|
|
|
430
449
|
const audioStreams = [];
|
|
431
450
|
const videoStreams = [];
|
|
432
451
|
const textStreams = [];
|
|
433
|
-
const streamIndexes =
|
|
452
|
+
const streamIndexes = TXml.findChildren(mss, 'StreamIndex');
|
|
434
453
|
for (const streamIndex of streamIndexes) {
|
|
435
|
-
const qualityLevels =
|
|
454
|
+
const qualityLevels = TXml.findChildren(streamIndex, 'QualityLevel');
|
|
436
455
|
const timeline = this.createTimeline_(
|
|
437
456
|
streamIndex, context.timescale, context.duration);
|
|
438
457
|
// For each QualityLevel node, create a stream element
|
|
@@ -467,8 +486,8 @@ shaka.mss.MssParser = class {
|
|
|
467
486
|
}
|
|
468
487
|
|
|
469
488
|
/**
|
|
470
|
-
* @param {!
|
|
471
|
-
* @param {!
|
|
489
|
+
* @param {!shaka.extern.xml.Node} streamIndex
|
|
490
|
+
* @param {!shaka.extern.xml.Node} qualityLevel
|
|
472
491
|
* @param {!Array.<shaka.mss.MssParser.TimeRange>} timeline
|
|
473
492
|
* @param {!Array.<shaka.extern.DrmInfo>} drmInfos
|
|
474
493
|
* @param {!shaka.mss.MssParser.Context} context
|
|
@@ -476,11 +495,11 @@ shaka.mss.MssParser = class {
|
|
|
476
495
|
* @private
|
|
477
496
|
*/
|
|
478
497
|
createStream_(streamIndex, qualityLevel, timeline, drmInfos, context) {
|
|
479
|
-
const
|
|
498
|
+
const TXml = shaka.util.TXml;
|
|
480
499
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
481
500
|
const MssParser = shaka.mss.MssParser;
|
|
482
501
|
|
|
483
|
-
const type = streamIndex.
|
|
502
|
+
const type = streamIndex.attributes['Type'];
|
|
484
503
|
const isValidType = type === 'audio' || type === 'video' ||
|
|
485
504
|
type === 'text';
|
|
486
505
|
if (!isValidType) {
|
|
@@ -488,19 +507,19 @@ shaka.mss.MssParser = class {
|
|
|
488
507
|
return null;
|
|
489
508
|
}
|
|
490
509
|
|
|
491
|
-
const lang = streamIndex.
|
|
510
|
+
const lang = streamIndex.attributes['Language'];
|
|
492
511
|
const id = this.globalId_++;
|
|
493
512
|
|
|
494
|
-
const bandwidth =
|
|
495
|
-
qualityLevel, 'Bitrate',
|
|
496
|
-
const width =
|
|
497
|
-
qualityLevel, 'MaxWidth',
|
|
498
|
-
const height =
|
|
499
|
-
qualityLevel, 'MaxHeight',
|
|
500
|
-
const channelsCount =
|
|
501
|
-
qualityLevel, 'Channels',
|
|
502
|
-
const audioSamplingRate =
|
|
503
|
-
qualityLevel, 'SamplingRate',
|
|
513
|
+
const bandwidth = TXml.parseAttr(
|
|
514
|
+
qualityLevel, 'Bitrate', TXml.parsePositiveInt);
|
|
515
|
+
const width = TXml.parseAttr(
|
|
516
|
+
qualityLevel, 'MaxWidth', TXml.parsePositiveInt);
|
|
517
|
+
const height = TXml.parseAttr(
|
|
518
|
+
qualityLevel, 'MaxHeight', TXml.parsePositiveInt);
|
|
519
|
+
const channelsCount = TXml.parseAttr(
|
|
520
|
+
qualityLevel, 'Channels', TXml.parsePositiveInt);
|
|
521
|
+
const audioSamplingRate = TXml.parseAttr(
|
|
522
|
+
qualityLevel, 'SamplingRate', TXml.parsePositiveInt);
|
|
504
523
|
|
|
505
524
|
let duration = context.duration;
|
|
506
525
|
if (timeline.length) {
|
|
@@ -516,7 +535,7 @@ shaka.mss.MssParser = class {
|
|
|
516
535
|
/** @type {!shaka.extern.Stream} */
|
|
517
536
|
const stream = {
|
|
518
537
|
id: id,
|
|
519
|
-
originalId: streamIndex.
|
|
538
|
+
originalId: streamIndex.attributes['Name'] || String(id),
|
|
520
539
|
groupId: null,
|
|
521
540
|
createSegmentIndex: () => Promise.resolve(),
|
|
522
541
|
closeSegmentIndex: () => Promise.resolve(),
|
|
@@ -561,7 +580,7 @@ shaka.mss.MssParser = class {
|
|
|
561
580
|
};
|
|
562
581
|
|
|
563
582
|
// This is specifically for text tracks.
|
|
564
|
-
const subType = streamIndex.
|
|
583
|
+
const subType = streamIndex.attributes['Subtype'];
|
|
565
584
|
if (subType) {
|
|
566
585
|
const role = MssParser.ROLE_MAPPING_[subType];
|
|
567
586
|
if (role) {
|
|
@@ -572,12 +591,12 @@ shaka.mss.MssParser = class {
|
|
|
572
591
|
}
|
|
573
592
|
}
|
|
574
593
|
|
|
575
|
-
let fourCCValue = qualityLevel.
|
|
594
|
+
let fourCCValue = qualityLevel.attributes['FourCC'];
|
|
576
595
|
|
|
577
596
|
// If FourCC not defined at QualityLevel level,
|
|
578
597
|
// then get it from StreamIndex level
|
|
579
598
|
if (fourCCValue === null || fourCCValue === '') {
|
|
580
|
-
fourCCValue = streamIndex.
|
|
599
|
+
fourCCValue = streamIndex.attributes['FourCC'];
|
|
581
600
|
}
|
|
582
601
|
|
|
583
602
|
// If still not defined (optional for audio stream,
|
|
@@ -700,7 +719,7 @@ shaka.mss.MssParser = class {
|
|
|
700
719
|
}
|
|
701
720
|
|
|
702
721
|
/**
|
|
703
|
-
* @param {!
|
|
722
|
+
* @param {!shaka.extern.xml.Node} qualityLevel
|
|
704
723
|
* @param {string} type
|
|
705
724
|
* @param {string} fourCCValue
|
|
706
725
|
* @param {!shaka.extern.Stream} stream
|
|
@@ -708,7 +727,7 @@ shaka.mss.MssParser = class {
|
|
|
708
727
|
* @private
|
|
709
728
|
*/
|
|
710
729
|
getCodecPrivateData_(qualityLevel, type, fourCCValue, stream) {
|
|
711
|
-
const codecPrivateData = qualityLevel.
|
|
730
|
+
const codecPrivateData = qualityLevel.attributes['CodecPrivateData'];
|
|
712
731
|
if (codecPrivateData) {
|
|
713
732
|
return codecPrivateData;
|
|
714
733
|
}
|
|
@@ -786,7 +805,7 @@ shaka.mss.MssParser = class {
|
|
|
786
805
|
}
|
|
787
806
|
|
|
788
807
|
/**
|
|
789
|
-
* @param {!
|
|
808
|
+
* @param {!shaka.extern.xml.Node} qualityLevel
|
|
790
809
|
* @param {string} fourCCValue
|
|
791
810
|
* @param {?string} codecPrivateData
|
|
792
811
|
* @return {string}
|
|
@@ -815,7 +834,7 @@ shaka.mss.MssParser = class {
|
|
|
815
834
|
}
|
|
816
835
|
|
|
817
836
|
/**
|
|
818
|
-
* @param {!
|
|
837
|
+
* @param {!shaka.extern.xml.Node} qualityLevel
|
|
819
838
|
* @param {?string} codecPrivateData
|
|
820
839
|
* @return {string}
|
|
821
840
|
* @private
|
|
@@ -841,14 +860,14 @@ shaka.mss.MssParser = class {
|
|
|
841
860
|
/**
|
|
842
861
|
* @param {!shaka.media.InitSegmentReference} initSegmentRef
|
|
843
862
|
* @param {!shaka.extern.Stream} stream
|
|
844
|
-
* @param {!
|
|
863
|
+
* @param {!shaka.extern.xml.Node} streamIndex
|
|
845
864
|
* @param {!Array.<shaka.mss.MssParser.TimeRange>} timeline
|
|
846
865
|
* @return {!Array.<!shaka.media.SegmentReference>}
|
|
847
866
|
* @private
|
|
848
867
|
*/
|
|
849
868
|
createSegments_(initSegmentRef, stream, streamIndex, timeline) {
|
|
850
869
|
const ManifestParserUtils = shaka.util.ManifestParserUtils;
|
|
851
|
-
const url = streamIndex.
|
|
870
|
+
const url = streamIndex.attributes['Url'];
|
|
852
871
|
goog.asserts.assert(url, 'Missing URL for segments');
|
|
853
872
|
|
|
854
873
|
const mediaUrl = url.replace('{bitrate}', String(stream.bandwidth));
|
|
@@ -877,7 +896,7 @@ shaka.mss.MssParser = class {
|
|
|
877
896
|
* Expands a streamIndex into an array-based timeline. The results are in
|
|
878
897
|
* seconds.
|
|
879
898
|
*
|
|
880
|
-
* @param {!
|
|
899
|
+
* @param {!shaka.extern.xml.Node} streamIndex
|
|
881
900
|
* @param {number} timescale
|
|
882
901
|
* @param {number} duration The duration in seconds.
|
|
883
902
|
* @return {!Array.<shaka.mss.MssParser.TimeRange>}
|
|
@@ -890,9 +909,9 @@ shaka.mss.MssParser = class {
|
|
|
890
909
|
goog.asserts.assert(
|
|
891
910
|
duration > 0, 'duration must be a positive integer');
|
|
892
911
|
|
|
893
|
-
const
|
|
912
|
+
const TXml = shaka.util.TXml;
|
|
894
913
|
|
|
895
|
-
const timePoints =
|
|
914
|
+
const timePoints = TXml.findChildren(streamIndex, 'c');
|
|
896
915
|
|
|
897
916
|
/** @type {!Array.<shaka.mss.MssParser.TimeRange>} */
|
|
898
917
|
const timeline = [];
|
|
@@ -902,10 +921,10 @@ shaka.mss.MssParser = class {
|
|
|
902
921
|
const timePoint = timePoints[i];
|
|
903
922
|
const next = timePoints[i + 1];
|
|
904
923
|
const t =
|
|
905
|
-
|
|
924
|
+
TXml.parseAttr(timePoint, 't', TXml.parseNonNegativeInt);
|
|
906
925
|
const d =
|
|
907
|
-
|
|
908
|
-
const r =
|
|
926
|
+
TXml.parseAttr(timePoint, 'd', TXml.parseNonNegativeInt);
|
|
927
|
+
const r = TXml.parseAttr(timePoint, 'r', TXml.parseInt);
|
|
909
928
|
|
|
910
929
|
if (!d) {
|
|
911
930
|
shaka.log.warning(
|
|
@@ -920,7 +939,7 @@ shaka.mss.MssParser = class {
|
|
|
920
939
|
if (repeat < 0) {
|
|
921
940
|
if (next) {
|
|
922
941
|
const nextStartTime =
|
|
923
|
-
|
|
942
|
+
TXml.parseAttr(next, 't', TXml.parseNonNegativeInt);
|
|
924
943
|
if (nextStartTime == null) {
|
|
925
944
|
shaka.log.warning(
|
|
926
945
|
'An "c" element cannot have a negative repeat',
|
|
@@ -46,7 +46,8 @@ goog.require('shaka.util.Timer');
|
|
|
46
46
|
*/
|
|
47
47
|
shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
|
|
48
48
|
/**
|
|
49
|
-
* @param {
|
|
49
|
+
* @param {shaka.net.NetworkingEngine.onProgressUpdated=} onProgressUpdated
|
|
50
|
+
* Called when
|
|
50
51
|
* a progress event is triggered. Passed the duration, in milliseconds,
|
|
51
52
|
* that the request took, the number of bytes transferred, and the boolean
|
|
52
53
|
* of whether the switching is allowed.
|
|
@@ -58,9 +59,11 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
|
|
|
58
59
|
* Called when a request is made
|
|
59
60
|
* @param {shaka.net.NetworkingEngine.OnRetry=} onRetry
|
|
60
61
|
* Called when a request retry is made
|
|
62
|
+
* @param {shaka.net.NetworkingEngine.OnResponse=} onResponse
|
|
63
|
+
* Called when receive the response
|
|
61
64
|
*/
|
|
62
65
|
constructor(onProgressUpdated, onHeadersReceived, onDownloadFailed,
|
|
63
|
-
onRequest, onRetry) {
|
|
66
|
+
onRequest, onRetry, onResponse) {
|
|
64
67
|
super();
|
|
65
68
|
|
|
66
69
|
/** @private {boolean} */
|
|
@@ -75,7 +78,7 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
|
|
|
75
78
|
/** @private {!Set.<shaka.extern.ResponseFilter>} */
|
|
76
79
|
this.responseFilters_ = new Set();
|
|
77
80
|
|
|
78
|
-
/** @private {?
|
|
81
|
+
/** @private {?shaka.net.NetworkingEngine.onProgressUpdated} */
|
|
79
82
|
this.onProgressUpdated_ = onProgressUpdated || null;
|
|
80
83
|
|
|
81
84
|
/** @private {?shaka.net.NetworkingEngine.OnHeadersReceived} */
|
|
@@ -90,6 +93,9 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
|
|
|
90
93
|
/** @private {?shaka.net.NetworkingEngine.OnRetry} */
|
|
91
94
|
this.onRetry_ = onRetry || null;
|
|
92
95
|
|
|
96
|
+
/** @private {?shaka.net.NetworkingEngine.OnResponse} */
|
|
97
|
+
this.onResponse_ = onResponse || null;
|
|
98
|
+
|
|
93
99
|
/** @private {boolean} */
|
|
94
100
|
this.forceHTTPS_ = false;
|
|
95
101
|
}
|
|
@@ -333,6 +339,9 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
|
|
|
333
339
|
this.onProgressUpdated_(
|
|
334
340
|
response.timeMs, response.data.byteLength, allowSwitch);
|
|
335
341
|
}
|
|
342
|
+
if (this.onResponse_) {
|
|
343
|
+
this.onResponse_(type, response, context);
|
|
344
|
+
}
|
|
336
345
|
return response;
|
|
337
346
|
}, (e) => {
|
|
338
347
|
// Any error thrown from elsewhere should be recategorized as CRITICAL
|
|
@@ -510,6 +519,7 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
|
|
|
510
519
|
|
|
511
520
|
startTimeMs = Date.now();
|
|
512
521
|
const segment = shaka.net.NetworkingEngine.RequestType.SEGMENT;
|
|
522
|
+
let packetNumber = 0;
|
|
513
523
|
|
|
514
524
|
const progressUpdated = (time, bytes, numBytesRemaining) => {
|
|
515
525
|
if (connectionTimer) {
|
|
@@ -519,8 +529,10 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
|
|
|
519
529
|
stallTimer.tickAfter(stallTimeoutMs / 1000);
|
|
520
530
|
}
|
|
521
531
|
if (this.onProgressUpdated_ && type == segment) {
|
|
532
|
+
packetNumber++;
|
|
533
|
+
request.packetNumber = packetNumber;
|
|
522
534
|
const allowSwitch = this.allowSwitch_(context);
|
|
523
|
-
this.onProgressUpdated_(time, bytes, allowSwitch);
|
|
535
|
+
this.onProgressUpdated_(time, bytes, allowSwitch, request);
|
|
524
536
|
gotProgress = true;
|
|
525
537
|
numBytesRemainingObj.setBytes(numBytesRemaining);
|
|
526
538
|
}
|
|
@@ -530,7 +542,11 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
|
|
|
530
542
|
this.onHeadersReceived_(headers, request, type);
|
|
531
543
|
}
|
|
532
544
|
headersReceivedCalled = true;
|
|
545
|
+
request.timeToFirstByte = Date.now() -
|
|
546
|
+
/** @type {number} */ (request.requestStartTime);
|
|
533
547
|
};
|
|
548
|
+
request.requestStartTime = Date.now();
|
|
549
|
+
|
|
534
550
|
const requestPlugin = plugin(
|
|
535
551
|
request.uris[index], request, type, progressUpdated, headersReceived);
|
|
536
552
|
|
|
@@ -899,6 +915,21 @@ shaka.net.NetworkingEngine.ResponseAndGotProgress;
|
|
|
899
915
|
*/
|
|
900
916
|
shaka.net.NetworkingEngine.OnHeadersReceived;
|
|
901
917
|
|
|
918
|
+
/**
|
|
919
|
+
* @typedef {function(
|
|
920
|
+
* number,
|
|
921
|
+
* number,
|
|
922
|
+
* boolean,
|
|
923
|
+
* shaka.extern.Request=)}
|
|
924
|
+
*
|
|
925
|
+
* @description
|
|
926
|
+
* A callback that is passed the duration, in milliseconds,
|
|
927
|
+
* that the request took, the number of bytes transferred, a boolean
|
|
928
|
+
* representing whether the switching is allowed and a ref to the
|
|
929
|
+
* original request.
|
|
930
|
+
* @export
|
|
931
|
+
*/
|
|
932
|
+
shaka.net.NetworkingEngine.onProgressUpdated;
|
|
902
933
|
|
|
903
934
|
/**
|
|
904
935
|
* @typedef {function(
|
|
@@ -941,3 +972,17 @@ shaka.net.NetworkingEngine.OnRequest;
|
|
|
941
972
|
* @export
|
|
942
973
|
*/
|
|
943
974
|
shaka.net.NetworkingEngine.OnRetry;
|
|
975
|
+
|
|
976
|
+
|
|
977
|
+
/**
|
|
978
|
+
* @typedef {function(
|
|
979
|
+
* !shaka.net.NetworkingEngine.RequestType,
|
|
980
|
+
* !shaka.extern.Response,
|
|
981
|
+
* (shaka.extern.RequestContext|undefined))}
|
|
982
|
+
*
|
|
983
|
+
* @description
|
|
984
|
+
* A callback function called on every request
|
|
985
|
+
* @export
|
|
986
|
+
*/
|
|
987
|
+
shaka.net.NetworkingEngine.OnResponse;
|
|
988
|
+
|
package/lib/offline/storage.js
CHANGED
|
@@ -664,7 +664,8 @@ shaka.offline.Storage = class {
|
|
|
664
664
|
// Filter the manifest based on what we know MediaCapabilities will be able
|
|
665
665
|
// to play later (no point storing something we can't play).
|
|
666
666
|
await shaka.util.StreamUtils.filterManifestByMediaCapabilities(
|
|
667
|
-
drmEngine, manifest, config.offline.usePersistentLicense
|
|
667
|
+
drmEngine, manifest, config.offline.usePersistentLicense,
|
|
668
|
+
config.drm.preferredKeySystems);
|
|
668
669
|
|
|
669
670
|
// Gather all tracks.
|
|
670
671
|
const allTracks = [];
|
|
@@ -1656,7 +1657,6 @@ shaka.offline.Storage.defaultSystemIds_ = new Map()
|
|
|
1656
1657
|
.set('com.microsoft.playready.software',
|
|
1657
1658
|
'9a04f07998404286ab92e65be0885f95')
|
|
1658
1659
|
.set('com.microsoft.playready.hardware',
|
|
1659
|
-
'9a04f07998404286ab92e65be0885f95')
|
|
1660
|
-
.set('com.adobe.primetime', 'f239e769efa348509c16a903c6932efb');
|
|
1660
|
+
'9a04f07998404286ab92e65be0885f95');
|
|
1661
1661
|
|
|
1662
1662
|
shaka.Player.registerSupportPlugin('offline', shaka.offline.Storage.support);
|