shaka-player 4.7.13 → 4.8.1
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 +2 -0
- package/CONTRIBUTORS +2 -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 +41 -31
- package/dist/shaka-player.compiled.d.ts +196 -45
- package/dist/shaka-player.compiled.debug.d.ts +196 -45
- package/dist/shaka-player.compiled.debug.externs.js +491 -348
- package/dist/shaka-player.compiled.debug.js +969 -847
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +491 -348
- package/dist/shaka-player.compiled.js +1238 -1171
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +259 -48
- package/dist/shaka-player.ui.debug.d.ts +259 -48
- package/dist/shaka-player.ui.debug.externs.js +598 -377
- package/dist/shaka-player.ui.debug.js +1185 -980
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +598 -377
- package/dist/shaka-player.ui.js +1526 -1408
- 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 +237 -177
- 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 +45 -22
- 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 +93 -47
- package/lib/media/segment_prefetch.js +140 -43
- package/lib/media/segment_reference.js +43 -8
- package/lib/media/segment_utils.js +208 -25
- package/lib/media/streaming_engine.js +355 -66
- package/lib/mss/content_protection.js +31 -25
- package/lib/mss/mss_parser.js +79 -55
- package/lib/net/networking_engine.js +49 -4
- package/lib/offline/storage.js +3 -3
- package/lib/player.js +882 -672
- 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 +153 -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 +79 -13
- package/lib/util/stats.js +16 -0
- package/lib/util/stream_utils.js +22 -8
- 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');
|
|
@@ -22,7 +23,9 @@ goog.require('shaka.util.ManifestParserUtils');
|
|
|
22
23
|
goog.require('shaka.util.MimeUtils');
|
|
23
24
|
goog.require('shaka.util.Mp4Generator');
|
|
24
25
|
goog.require('shaka.util.OperationManager');
|
|
26
|
+
goog.require('shaka.util.PlayerConfiguration');
|
|
25
27
|
goog.require('shaka.util.Timer');
|
|
28
|
+
goog.require('shaka.util.TXml');
|
|
26
29
|
goog.require('shaka.util.XmlUtils');
|
|
27
30
|
|
|
28
31
|
|
|
@@ -278,7 +281,27 @@ shaka.mss.MssParser = class {
|
|
|
278
281
|
* @private
|
|
279
282
|
*/
|
|
280
283
|
parseManifest_(data, finalManifestUri) {
|
|
281
|
-
|
|
284
|
+
let manifestData = data;
|
|
285
|
+
const manifestPreprocessor = this.config_.mss.manifestPreprocessor;
|
|
286
|
+
const defaultManifestPreprocessor =
|
|
287
|
+
shaka.util.PlayerConfiguration.defaultManifestPreprocessor;
|
|
288
|
+
if (manifestPreprocessor != defaultManifestPreprocessor) {
|
|
289
|
+
shaka.Deprecate.deprecateFeature(5,
|
|
290
|
+
'manifest.mss.manifestPreprocessor configuration',
|
|
291
|
+
'Please Use manifest.mss.manifestPreprocessorTXml instead.');
|
|
292
|
+
const mssElement =
|
|
293
|
+
shaka.util.XmlUtils.parseXml(manifestData, 'SmoothStreamingMedia');
|
|
294
|
+
if (!mssElement) {
|
|
295
|
+
throw new shaka.util.Error(
|
|
296
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
297
|
+
shaka.util.Error.Category.MANIFEST,
|
|
298
|
+
shaka.util.Error.Code.MSS_INVALID_XML,
|
|
299
|
+
finalManifestUri);
|
|
300
|
+
}
|
|
301
|
+
manifestPreprocessor(mssElement);
|
|
302
|
+
manifestData = shaka.util.XmlUtils.toArrayBuffer(mssElement);
|
|
303
|
+
}
|
|
304
|
+
const mss = shaka.util.TXml.parseXml(manifestData, 'SmoothStreamingMedia');
|
|
282
305
|
if (!mss) {
|
|
283
306
|
throw new shaka.util.Error(
|
|
284
307
|
shaka.util.Error.Severity.CRITICAL,
|
|
@@ -286,6 +309,12 @@ shaka.mss.MssParser = class {
|
|
|
286
309
|
shaka.util.Error.Code.MSS_INVALID_XML,
|
|
287
310
|
finalManifestUri);
|
|
288
311
|
}
|
|
312
|
+
const manifestPreprocessorTXml = this.config_.mss.manifestPreprocessorTXml;
|
|
313
|
+
const defaultManifestPreprocessorTXml =
|
|
314
|
+
shaka.util.PlayerConfiguration.defaultManifestPreprocessorTXml;
|
|
315
|
+
if (manifestPreprocessorTXml != defaultManifestPreprocessorTXml) {
|
|
316
|
+
manifestPreprocessorTXml(mss);
|
|
317
|
+
}
|
|
289
318
|
this.processManifest_(mss, finalManifestUri);
|
|
290
319
|
return Promise.resolve();
|
|
291
320
|
}
|
|
@@ -294,26 +323,21 @@ shaka.mss.MssParser = class {
|
|
|
294
323
|
/**
|
|
295
324
|
* Takes a formatted MSS and converts it into a manifest.
|
|
296
325
|
*
|
|
297
|
-
* @param {!
|
|
326
|
+
* @param {!shaka.extern.xml.Node} mss
|
|
298
327
|
* @param {string} finalManifestUri The final manifest URI, which may
|
|
299
328
|
* differ from this.manifestUri_ if there has been a redirect.
|
|
300
329
|
* @private
|
|
301
330
|
*/
|
|
302
331
|
processManifest_(mss, finalManifestUri) {
|
|
303
|
-
const
|
|
304
|
-
|
|
305
|
-
const manifestPreprocessor = this.config_.mss.manifestPreprocessor;
|
|
306
|
-
if (manifestPreprocessor) {
|
|
307
|
-
manifestPreprocessor(mss);
|
|
308
|
-
}
|
|
332
|
+
const TXml = shaka.util.TXml;
|
|
309
333
|
|
|
310
334
|
if (!this.presentationTimeline_) {
|
|
311
335
|
this.presentationTimeline_ = new shaka.media.PresentationTimeline(
|
|
312
336
|
/* presentationStartTime= */ null, /* delay= */ 0);
|
|
313
337
|
}
|
|
314
338
|
|
|
315
|
-
const isLive =
|
|
316
|
-
|
|
339
|
+
const isLive = TXml.parseAttr(mss, 'IsLive',
|
|
340
|
+
TXml.parseBoolean, /* defaultValue= */ false);
|
|
317
341
|
|
|
318
342
|
if (isLive) {
|
|
319
343
|
throw new shaka.util.Error(
|
|
@@ -324,21 +348,21 @@ shaka.mss.MssParser = class {
|
|
|
324
348
|
|
|
325
349
|
this.presentationTimeline_.setStatic(!isLive);
|
|
326
350
|
|
|
327
|
-
const timescale =
|
|
328
|
-
|
|
351
|
+
const timescale = TXml.parseAttr(mss, 'TimeScale',
|
|
352
|
+
TXml.parseNonNegativeInt, shaka.mss.MssParser.DEFAULT_TIME_SCALE_);
|
|
329
353
|
goog.asserts.assert(timescale && timescale >= 0,
|
|
330
354
|
'Timescale must be defined!');
|
|
331
355
|
|
|
332
|
-
let dvrWindowLength =
|
|
333
|
-
|
|
356
|
+
let dvrWindowLength = TXml.parseAttr(mss, 'DVRWindowLength',
|
|
357
|
+
TXml.parseNonNegativeInt);
|
|
334
358
|
// If the DVRWindowLength field is omitted for a live presentation or set
|
|
335
359
|
// to 0, the DVR window is effectively infinite
|
|
336
360
|
if (isLive && (dvrWindowLength === 0 || isNaN(dvrWindowLength))) {
|
|
337
361
|
dvrWindowLength = Infinity;
|
|
338
362
|
}
|
|
339
363
|
// Start-over
|
|
340
|
-
const canSeek =
|
|
341
|
-
|
|
364
|
+
const canSeek = TXml.parseAttr(mss, 'CanSeek',
|
|
365
|
+
TXml.parseBoolean, /* defaultValue= */ false);
|
|
342
366
|
if (dvrWindowLength === 0 && canSeek) {
|
|
343
367
|
dvrWindowLength = Infinity;
|
|
344
368
|
}
|
|
@@ -363,8 +387,8 @@ shaka.mss.MssParser = class {
|
|
|
363
387
|
segmentAvailabilityDuration);
|
|
364
388
|
|
|
365
389
|
// Duration in timescale units.
|
|
366
|
-
const duration =
|
|
367
|
-
|
|
390
|
+
const duration = TXml.parseAttr(mss, 'Duration',
|
|
391
|
+
TXml.parseNonNegativeInt, Infinity);
|
|
368
392
|
goog.asserts.assert(duration && duration >= 0,
|
|
369
393
|
'Duration must be defined!');
|
|
370
394
|
|
|
@@ -414,25 +438,25 @@ shaka.mss.MssParser = class {
|
|
|
414
438
|
}
|
|
415
439
|
|
|
416
440
|
/**
|
|
417
|
-
* @param {!
|
|
441
|
+
* @param {!shaka.extern.xml.Node} mss
|
|
418
442
|
* @param {!shaka.mss.MssParser.Context} context
|
|
419
443
|
* @private
|
|
420
444
|
*/
|
|
421
445
|
parseStreamIndexes_(mss, context) {
|
|
422
446
|
const ContentProtection = shaka.mss.ContentProtection;
|
|
423
|
-
const
|
|
447
|
+
const TXml = shaka.util.TXml;
|
|
424
448
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
425
449
|
|
|
426
|
-
const protectionElems =
|
|
450
|
+
const protectionElems = TXml.findChildren(mss, 'Protection');
|
|
427
451
|
const drmInfos = ContentProtection.parseFromProtection(
|
|
428
452
|
protectionElems, this.config_.mss.keySystemsBySystemId);
|
|
429
453
|
|
|
430
454
|
const audioStreams = [];
|
|
431
455
|
const videoStreams = [];
|
|
432
456
|
const textStreams = [];
|
|
433
|
-
const streamIndexes =
|
|
457
|
+
const streamIndexes = TXml.findChildren(mss, 'StreamIndex');
|
|
434
458
|
for (const streamIndex of streamIndexes) {
|
|
435
|
-
const qualityLevels =
|
|
459
|
+
const qualityLevels = TXml.findChildren(streamIndex, 'QualityLevel');
|
|
436
460
|
const timeline = this.createTimeline_(
|
|
437
461
|
streamIndex, context.timescale, context.duration);
|
|
438
462
|
// For each QualityLevel node, create a stream element
|
|
@@ -467,8 +491,8 @@ shaka.mss.MssParser = class {
|
|
|
467
491
|
}
|
|
468
492
|
|
|
469
493
|
/**
|
|
470
|
-
* @param {!
|
|
471
|
-
* @param {!
|
|
494
|
+
* @param {!shaka.extern.xml.Node} streamIndex
|
|
495
|
+
* @param {!shaka.extern.xml.Node} qualityLevel
|
|
472
496
|
* @param {!Array.<shaka.mss.MssParser.TimeRange>} timeline
|
|
473
497
|
* @param {!Array.<shaka.extern.DrmInfo>} drmInfos
|
|
474
498
|
* @param {!shaka.mss.MssParser.Context} context
|
|
@@ -476,11 +500,11 @@ shaka.mss.MssParser = class {
|
|
|
476
500
|
* @private
|
|
477
501
|
*/
|
|
478
502
|
createStream_(streamIndex, qualityLevel, timeline, drmInfos, context) {
|
|
479
|
-
const
|
|
503
|
+
const TXml = shaka.util.TXml;
|
|
480
504
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
481
505
|
const MssParser = shaka.mss.MssParser;
|
|
482
506
|
|
|
483
|
-
const type = streamIndex.
|
|
507
|
+
const type = streamIndex.attributes['Type'];
|
|
484
508
|
const isValidType = type === 'audio' || type === 'video' ||
|
|
485
509
|
type === 'text';
|
|
486
510
|
if (!isValidType) {
|
|
@@ -488,19 +512,19 @@ shaka.mss.MssParser = class {
|
|
|
488
512
|
return null;
|
|
489
513
|
}
|
|
490
514
|
|
|
491
|
-
const lang = streamIndex.
|
|
515
|
+
const lang = streamIndex.attributes['Language'];
|
|
492
516
|
const id = this.globalId_++;
|
|
493
517
|
|
|
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',
|
|
518
|
+
const bandwidth = TXml.parseAttr(
|
|
519
|
+
qualityLevel, 'Bitrate', TXml.parsePositiveInt);
|
|
520
|
+
const width = TXml.parseAttr(
|
|
521
|
+
qualityLevel, 'MaxWidth', TXml.parsePositiveInt);
|
|
522
|
+
const height = TXml.parseAttr(
|
|
523
|
+
qualityLevel, 'MaxHeight', TXml.parsePositiveInt);
|
|
524
|
+
const channelsCount = TXml.parseAttr(
|
|
525
|
+
qualityLevel, 'Channels', TXml.parsePositiveInt);
|
|
526
|
+
const audioSamplingRate = TXml.parseAttr(
|
|
527
|
+
qualityLevel, 'SamplingRate', TXml.parsePositiveInt);
|
|
504
528
|
|
|
505
529
|
let duration = context.duration;
|
|
506
530
|
if (timeline.length) {
|
|
@@ -516,7 +540,7 @@ shaka.mss.MssParser = class {
|
|
|
516
540
|
/** @type {!shaka.extern.Stream} */
|
|
517
541
|
const stream = {
|
|
518
542
|
id: id,
|
|
519
|
-
originalId: streamIndex.
|
|
543
|
+
originalId: streamIndex.attributes['Name'] || String(id),
|
|
520
544
|
groupId: null,
|
|
521
545
|
createSegmentIndex: () => Promise.resolve(),
|
|
522
546
|
closeSegmentIndex: () => Promise.resolve(),
|
|
@@ -561,7 +585,7 @@ shaka.mss.MssParser = class {
|
|
|
561
585
|
};
|
|
562
586
|
|
|
563
587
|
// This is specifically for text tracks.
|
|
564
|
-
const subType = streamIndex.
|
|
588
|
+
const subType = streamIndex.attributes['Subtype'];
|
|
565
589
|
if (subType) {
|
|
566
590
|
const role = MssParser.ROLE_MAPPING_[subType];
|
|
567
591
|
if (role) {
|
|
@@ -572,12 +596,12 @@ shaka.mss.MssParser = class {
|
|
|
572
596
|
}
|
|
573
597
|
}
|
|
574
598
|
|
|
575
|
-
let fourCCValue = qualityLevel.
|
|
599
|
+
let fourCCValue = qualityLevel.attributes['FourCC'];
|
|
576
600
|
|
|
577
601
|
// If FourCC not defined at QualityLevel level,
|
|
578
602
|
// then get it from StreamIndex level
|
|
579
603
|
if (fourCCValue === null || fourCCValue === '') {
|
|
580
|
-
fourCCValue = streamIndex.
|
|
604
|
+
fourCCValue = streamIndex.attributes['FourCC'];
|
|
581
605
|
}
|
|
582
606
|
|
|
583
607
|
// If still not defined (optional for audio stream,
|
|
@@ -700,7 +724,7 @@ shaka.mss.MssParser = class {
|
|
|
700
724
|
}
|
|
701
725
|
|
|
702
726
|
/**
|
|
703
|
-
* @param {!
|
|
727
|
+
* @param {!shaka.extern.xml.Node} qualityLevel
|
|
704
728
|
* @param {string} type
|
|
705
729
|
* @param {string} fourCCValue
|
|
706
730
|
* @param {!shaka.extern.Stream} stream
|
|
@@ -708,7 +732,7 @@ shaka.mss.MssParser = class {
|
|
|
708
732
|
* @private
|
|
709
733
|
*/
|
|
710
734
|
getCodecPrivateData_(qualityLevel, type, fourCCValue, stream) {
|
|
711
|
-
const codecPrivateData = qualityLevel.
|
|
735
|
+
const codecPrivateData = qualityLevel.attributes['CodecPrivateData'];
|
|
712
736
|
if (codecPrivateData) {
|
|
713
737
|
return codecPrivateData;
|
|
714
738
|
}
|
|
@@ -786,7 +810,7 @@ shaka.mss.MssParser = class {
|
|
|
786
810
|
}
|
|
787
811
|
|
|
788
812
|
/**
|
|
789
|
-
* @param {!
|
|
813
|
+
* @param {!shaka.extern.xml.Node} qualityLevel
|
|
790
814
|
* @param {string} fourCCValue
|
|
791
815
|
* @param {?string} codecPrivateData
|
|
792
816
|
* @return {string}
|
|
@@ -815,7 +839,7 @@ shaka.mss.MssParser = class {
|
|
|
815
839
|
}
|
|
816
840
|
|
|
817
841
|
/**
|
|
818
|
-
* @param {!
|
|
842
|
+
* @param {!shaka.extern.xml.Node} qualityLevel
|
|
819
843
|
* @param {?string} codecPrivateData
|
|
820
844
|
* @return {string}
|
|
821
845
|
* @private
|
|
@@ -841,14 +865,14 @@ shaka.mss.MssParser = class {
|
|
|
841
865
|
/**
|
|
842
866
|
* @param {!shaka.media.InitSegmentReference} initSegmentRef
|
|
843
867
|
* @param {!shaka.extern.Stream} stream
|
|
844
|
-
* @param {!
|
|
868
|
+
* @param {!shaka.extern.xml.Node} streamIndex
|
|
845
869
|
* @param {!Array.<shaka.mss.MssParser.TimeRange>} timeline
|
|
846
870
|
* @return {!Array.<!shaka.media.SegmentReference>}
|
|
847
871
|
* @private
|
|
848
872
|
*/
|
|
849
873
|
createSegments_(initSegmentRef, stream, streamIndex, timeline) {
|
|
850
874
|
const ManifestParserUtils = shaka.util.ManifestParserUtils;
|
|
851
|
-
const url = streamIndex.
|
|
875
|
+
const url = streamIndex.attributes['Url'];
|
|
852
876
|
goog.asserts.assert(url, 'Missing URL for segments');
|
|
853
877
|
|
|
854
878
|
const mediaUrl = url.replace('{bitrate}', String(stream.bandwidth));
|
|
@@ -877,7 +901,7 @@ shaka.mss.MssParser = class {
|
|
|
877
901
|
* Expands a streamIndex into an array-based timeline. The results are in
|
|
878
902
|
* seconds.
|
|
879
903
|
*
|
|
880
|
-
* @param {!
|
|
904
|
+
* @param {!shaka.extern.xml.Node} streamIndex
|
|
881
905
|
* @param {number} timescale
|
|
882
906
|
* @param {number} duration The duration in seconds.
|
|
883
907
|
* @return {!Array.<shaka.mss.MssParser.TimeRange>}
|
|
@@ -890,9 +914,9 @@ shaka.mss.MssParser = class {
|
|
|
890
914
|
goog.asserts.assert(
|
|
891
915
|
duration > 0, 'duration must be a positive integer');
|
|
892
916
|
|
|
893
|
-
const
|
|
917
|
+
const TXml = shaka.util.TXml;
|
|
894
918
|
|
|
895
|
-
const timePoints =
|
|
919
|
+
const timePoints = TXml.findChildren(streamIndex, 'c');
|
|
896
920
|
|
|
897
921
|
/** @type {!Array.<shaka.mss.MssParser.TimeRange>} */
|
|
898
922
|
const timeline = [];
|
|
@@ -902,10 +926,10 @@ shaka.mss.MssParser = class {
|
|
|
902
926
|
const timePoint = timePoints[i];
|
|
903
927
|
const next = timePoints[i + 1];
|
|
904
928
|
const t =
|
|
905
|
-
|
|
929
|
+
TXml.parseAttr(timePoint, 't', TXml.parseNonNegativeInt);
|
|
906
930
|
const d =
|
|
907
|
-
|
|
908
|
-
const r =
|
|
931
|
+
TXml.parseAttr(timePoint, 'd', TXml.parseNonNegativeInt);
|
|
932
|
+
const r = TXml.parseAttr(timePoint, 'r', TXml.parseInt);
|
|
909
933
|
|
|
910
934
|
if (!d) {
|
|
911
935
|
shaka.log.warning(
|
|
@@ -920,7 +944,7 @@ shaka.mss.MssParser = class {
|
|
|
920
944
|
if (repeat < 0) {
|
|
921
945
|
if (next) {
|
|
922
946
|
const nextStartTime =
|
|
923
|
-
|
|
947
|
+
TXml.parseAttr(next, 't', TXml.parseNonNegativeInt);
|
|
924
948
|
if (nextStartTime == null) {
|
|
925
949
|
shaka.log.warning(
|
|
926
950
|
'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);
|