shaka-player 4.7.12 → 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 +36 -25
- package/dist/locales.js +40 -30
- package/dist/shaka-player.compiled.d.ts +196 -46
- package/dist/shaka-player.compiled.debug.d.ts +196 -46
- package/dist/shaka-player.compiled.debug.externs.js +474 -337
- package/dist/shaka-player.compiled.debug.js +992 -871
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +474 -337
- package/dist/shaka-player.compiled.js +1248 -1174
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +259 -49
- package/dist/shaka-player.ui.debug.d.ts +259 -49
- package/dist/shaka-player.ui.debug.externs.js +591 -376
- package/dist/shaka-player.ui.debug.js +1208 -1003
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +591 -376
- package/dist/shaka-player.ui.js +1533 -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 +69 -7
- package/externs/shaka/net.js +13 -1
- package/externs/shaka/offline.js +7 -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 +240 -179
- package/lib/dash/mpd_utils.js +72 -65
- package/lib/dash/segment_base.js +35 -22
- package/lib/dash/segment_list.js +39 -31
- package/lib/dash/segment_template.js +47 -23
- package/lib/hls/hls_parser.js +376 -165
- 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 +108 -29
- package/lib/media/playhead.js +3 -3
- package/lib/media/preload_manager.js +827 -0
- package/lib/media/presentation_timeline.js +11 -0
- package/lib/media/segment_index.js +60 -49
- 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 +321 -77
- package/lib/mss/content_protection.js +31 -25
- package/lib/mss/mss_parser.js +78 -55
- package/lib/net/networking_engine.js +49 -4
- package/lib/offline/indexeddb/v1_storage_cell.js +2 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +2 -0
- package/lib/offline/manifest_converter.js +10 -3
- package/lib/offline/storage.js +5 -3
- package/lib/player.js +896 -674
- 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/mime_utils.js +10 -5
- package/lib/util/mp4_box_parsers.js +346 -17
- package/lib/util/mp4_generator.js +23 -0
- package/lib/util/periods.js +24 -37
- 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 +350 -277
- 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/lib/dash/dash_parser.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
goog.provide('shaka.dash.DashParser');
|
|
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.dash.ContentProtection');
|
|
12
13
|
goog.require('shaka.dash.MpdUtils');
|
|
@@ -31,6 +32,7 @@ goog.require('shaka.util.OperationManager');
|
|
|
31
32
|
goog.require('shaka.util.PeriodCombiner');
|
|
32
33
|
goog.require('shaka.util.StringUtils');
|
|
33
34
|
goog.require('shaka.util.Timer');
|
|
35
|
+
goog.require('shaka.util.TXml');
|
|
34
36
|
goog.require('shaka.util.XmlUtils');
|
|
35
37
|
|
|
36
38
|
|
|
@@ -129,9 +131,14 @@ shaka.dash.DashParser = class {
|
|
|
129
131
|
configure(config) {
|
|
130
132
|
goog.asserts.assert(config.dash != null,
|
|
131
133
|
'DashManifestConfiguration should not be null!');
|
|
132
|
-
|
|
134
|
+
const needFireUpdate = this.playerInterface_ &&
|
|
135
|
+
config.dash.updatePeriod != this.config_.dash.updatePeriod &&
|
|
136
|
+
config.dash.updatePeriod >= 0;
|
|
133
137
|
this.config_ = config;
|
|
134
|
-
|
|
138
|
+
if (needFireUpdate && this.manifest_ &&
|
|
139
|
+
this.manifest_.presentationTimeline.isLive()) {
|
|
140
|
+
this.updateNow_();
|
|
141
|
+
}
|
|
135
142
|
if (this.contentSteeringManager_) {
|
|
136
143
|
this.contentSteeringManager_.configure(this.config_);
|
|
137
144
|
}
|
|
@@ -140,6 +147,8 @@ shaka.dash.DashParser = class {
|
|
|
140
147
|
this.periodCombiner_.setAllowMultiTypeVariants(
|
|
141
148
|
this.config_.dash.multiTypeVariantsAllowed &&
|
|
142
149
|
shaka.media.Capabilities.isChangeTypeSupported());
|
|
150
|
+
this.periodCombiner_.setUseStreamOnce(
|
|
151
|
+
this.config_.dash.useStreamOnceInPeriodFlattening);
|
|
143
152
|
}
|
|
144
153
|
}
|
|
145
154
|
|
|
@@ -327,15 +336,38 @@ shaka.dash.DashParser = class {
|
|
|
327
336
|
* @private
|
|
328
337
|
*/
|
|
329
338
|
async parseManifest_(data, finalManifestUri) {
|
|
330
|
-
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
|
|
339
|
+
let manifestData = data;
|
|
340
|
+
const manifestPreprocessor = this.config_.dash.manifestPreprocessor;
|
|
341
|
+
if (manifestPreprocessor) {
|
|
342
|
+
shaka.Deprecate.deprecateFeature(5,
|
|
343
|
+
'manifest.dash.manifestPreprocessor configuration',
|
|
344
|
+
'Please Use manifest.dash.manifestPreprocessorTXml instead.');
|
|
345
|
+
const mpdElement =
|
|
346
|
+
shaka.util.XmlUtils.parseXml(manifestData, 'MPD');
|
|
347
|
+
if (!mpdElement) {
|
|
348
|
+
throw new shaka.util.Error(
|
|
349
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
350
|
+
shaka.util.Error.Category.MANIFEST,
|
|
351
|
+
shaka.util.Error.Code.DASH_INVALID_XML,
|
|
352
|
+
finalManifestUri);
|
|
353
|
+
}
|
|
354
|
+
manifestPreprocessor(mpdElement);
|
|
355
|
+
manifestData = shaka.util.XmlUtils.toArrayBuffer(mpdElement);
|
|
356
|
+
}
|
|
357
|
+
const mpd = shaka.util.TXml.parseXml(manifestData, 'MPD');
|
|
334
358
|
if (!mpd) {
|
|
335
|
-
throw new Error(
|
|
336
|
-
Error.Severity.CRITICAL,
|
|
337
|
-
Error.
|
|
359
|
+
throw new shaka.util.Error(
|
|
360
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
361
|
+
shaka.util.Error.Category.MANIFEST,
|
|
362
|
+
shaka.util.Error.Code.DASH_INVALID_XML,
|
|
363
|
+
finalManifestUri);
|
|
338
364
|
}
|
|
365
|
+
const manifestPreprocessorTXml =
|
|
366
|
+
this.config_.dash.manifestPreprocessorTXml;
|
|
367
|
+
if (manifestPreprocessorTXml) {
|
|
368
|
+
manifestPreprocessorTXml(mpd);
|
|
369
|
+
}
|
|
370
|
+
|
|
339
371
|
const disableXlinkProcessing = this.config_.dash.disableXlinkProcessing;
|
|
340
372
|
if (disableXlinkProcessing) {
|
|
341
373
|
return this.processManifest_(mpd, finalManifestUri);
|
|
@@ -343,7 +375,7 @@ shaka.dash.DashParser = class {
|
|
|
343
375
|
|
|
344
376
|
// Process the mpd to account for xlink connections.
|
|
345
377
|
const failGracefully = this.config_.dash.xlinkFailGracefully;
|
|
346
|
-
const xlinkOperation = MpdUtils.processXlinks(
|
|
378
|
+
const xlinkOperation = shaka.dash.MpdUtils.processXlinks(
|
|
347
379
|
mpd, this.config_.retryParameters, failGracefully, finalManifestUri,
|
|
348
380
|
this.playerInterface_.networkingEngine);
|
|
349
381
|
this.operationManager_.manage(xlinkOperation);
|
|
@@ -355,19 +387,17 @@ shaka.dash.DashParser = class {
|
|
|
355
387
|
/**
|
|
356
388
|
* Takes a formatted MPD and converts it into a manifest.
|
|
357
389
|
*
|
|
358
|
-
* @param {!
|
|
390
|
+
* @param {!shaka.extern.xml.Node} mpd
|
|
359
391
|
* @param {string} finalManifestUri The final manifest URI, which may
|
|
360
392
|
* differ from this.manifestUri_ if there has been a redirect.
|
|
361
393
|
* @return {!Promise}
|
|
362
394
|
* @private
|
|
363
395
|
*/
|
|
364
396
|
async processManifest_(mpd, finalManifestUri) {
|
|
365
|
-
const
|
|
397
|
+
const TXml = shaka.util.TXml;
|
|
366
398
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
manifestPreprocessor(mpd);
|
|
370
|
-
}
|
|
399
|
+
goog.asserts.assert(this.config_,
|
|
400
|
+
'Must call configure() before processManifest_()!');
|
|
371
401
|
|
|
372
402
|
if (this.contentSteeringManager_) {
|
|
373
403
|
this.contentSteeringManager_.clearPreviousLocations();
|
|
@@ -381,10 +411,10 @@ shaka.dash.DashParser = class {
|
|
|
381
411
|
const locations = [];
|
|
382
412
|
/** @type {!Map.<string, string>} */
|
|
383
413
|
const locationsMapping = new Map();
|
|
384
|
-
const locationsObjs =
|
|
414
|
+
const locationsObjs = TXml.findChildren(mpd, 'Location');
|
|
385
415
|
for (const locationsObj of locationsObjs) {
|
|
386
|
-
const serviceLocation = locationsObj.
|
|
387
|
-
const uri =
|
|
416
|
+
const serviceLocation = locationsObj.attributes['serviceLocation'];
|
|
417
|
+
const uri = TXml.getContents(locationsObj);
|
|
388
418
|
if (!uri) {
|
|
389
419
|
continue;
|
|
390
420
|
}
|
|
@@ -414,10 +444,10 @@ shaka.dash.DashParser = class {
|
|
|
414
444
|
|
|
415
445
|
let contentSteeringPromise = Promise.resolve();
|
|
416
446
|
|
|
417
|
-
const contentSteering =
|
|
447
|
+
const contentSteering = TXml.findChild(mpd, 'ContentSteering');
|
|
418
448
|
if (contentSteering && this.playerInterface_) {
|
|
419
449
|
const defaultPathwayId =
|
|
420
|
-
contentSteering.
|
|
450
|
+
contentSteering.attributes['defaultServiceLocation'];
|
|
421
451
|
if (!this.contentSteeringManager_) {
|
|
422
452
|
this.contentSteeringManager_ =
|
|
423
453
|
new shaka.util.ContentSteeringManager(this.playerInterface_);
|
|
@@ -426,11 +456,11 @@ shaka.dash.DashParser = class {
|
|
|
426
456
|
shaka.media.ManifestParser.DASH);
|
|
427
457
|
this.contentSteeringManager_.setBaseUris(manifestBaseUris);
|
|
428
458
|
this.contentSteeringManager_.setDefaultPathwayId(defaultPathwayId);
|
|
429
|
-
const uri =
|
|
459
|
+
const uri = TXml.getContents(contentSteering);
|
|
430
460
|
if (uri) {
|
|
431
461
|
const queryBeforeStart =
|
|
432
|
-
|
|
433
|
-
|
|
462
|
+
TXml.parseAttr(contentSteering, 'queryBeforeStart',
|
|
463
|
+
TXml.parseBoolean, /* defaultValue= */ false);
|
|
434
464
|
if (queryBeforeStart) {
|
|
435
465
|
contentSteeringPromise =
|
|
436
466
|
this.contentSteeringManager_.requestInfo(uri);
|
|
@@ -449,13 +479,13 @@ shaka.dash.DashParser = class {
|
|
|
449
479
|
}
|
|
450
480
|
}
|
|
451
481
|
|
|
452
|
-
const uriObjs =
|
|
482
|
+
const uriObjs = TXml.findChildren(mpd, 'BaseURL');
|
|
453
483
|
let calculatedBaseUris;
|
|
454
484
|
let someLocationValid = false;
|
|
455
485
|
if (this.contentSteeringManager_) {
|
|
456
486
|
for (const uriObj of uriObjs) {
|
|
457
|
-
const serviceLocation = uriObj.
|
|
458
|
-
const uri =
|
|
487
|
+
const serviceLocation = uriObj.attributes['serviceLocation'];
|
|
488
|
+
const uri = TXml.getContents(uriObj);
|
|
459
489
|
if (serviceLocation && uri) {
|
|
460
490
|
this.contentSteeringManager_.addLocation(
|
|
461
491
|
'BaseURL', serviceLocation, uri);
|
|
@@ -464,7 +494,7 @@ shaka.dash.DashParser = class {
|
|
|
464
494
|
}
|
|
465
495
|
}
|
|
466
496
|
if (!someLocationValid || !this.contentSteeringManager_) {
|
|
467
|
-
const uris = uriObjs.map(
|
|
497
|
+
const uris = uriObjs.map(TXml.getContents);
|
|
468
498
|
calculatedBaseUris = shaka.util.ManifestParserUtils.resolveUris(
|
|
469
499
|
manifestBaseUris, uris);
|
|
470
500
|
}
|
|
@@ -481,41 +511,41 @@ shaka.dash.DashParser = class {
|
|
|
481
511
|
|
|
482
512
|
let availabilityTimeOffset = 0;
|
|
483
513
|
if (uriObjs && uriObjs.length) {
|
|
484
|
-
availabilityTimeOffset =
|
|
485
|
-
|
|
514
|
+
availabilityTimeOffset = TXml.parseAttr(uriObjs[0],
|
|
515
|
+
'availabilityTimeOffset', TXml.parseFloat) || 0;
|
|
486
516
|
}
|
|
487
517
|
|
|
488
518
|
const ignoreMinBufferTime = this.config_.dash.ignoreMinBufferTime;
|
|
489
519
|
let minBufferTime = 0;
|
|
490
520
|
if (!ignoreMinBufferTime) {
|
|
491
521
|
minBufferTime =
|
|
492
|
-
|
|
522
|
+
TXml.parseAttr(mpd, 'minBufferTime', TXml.parseDuration) || 0;
|
|
493
523
|
}
|
|
494
524
|
|
|
495
|
-
this.updatePeriod_ = /** @type {number} */ (
|
|
496
|
-
mpd, 'minimumUpdatePeriod',
|
|
525
|
+
this.updatePeriod_ = /** @type {number} */ (TXml.parseAttr(
|
|
526
|
+
mpd, 'minimumUpdatePeriod', TXml.parseDuration, -1));
|
|
497
527
|
|
|
498
|
-
const presentationStartTime =
|
|
499
|
-
mpd, 'availabilityStartTime',
|
|
500
|
-
let segmentAvailabilityDuration =
|
|
501
|
-
mpd, 'timeShiftBufferDepth',
|
|
528
|
+
const presentationStartTime = TXml.parseAttr(
|
|
529
|
+
mpd, 'availabilityStartTime', TXml.parseDate);
|
|
530
|
+
let segmentAvailabilityDuration = TXml.parseAttr(
|
|
531
|
+
mpd, 'timeShiftBufferDepth', TXml.parseDuration);
|
|
502
532
|
|
|
503
533
|
const ignoreSuggestedPresentationDelay =
|
|
504
534
|
this.config_.dash.ignoreSuggestedPresentationDelay;
|
|
505
535
|
let suggestedPresentationDelay = null;
|
|
506
536
|
if (!ignoreSuggestedPresentationDelay) {
|
|
507
|
-
suggestedPresentationDelay =
|
|
508
|
-
mpd, 'suggestedPresentationDelay',
|
|
537
|
+
suggestedPresentationDelay = TXml.parseAttr(
|
|
538
|
+
mpd, 'suggestedPresentationDelay', TXml.parseDuration);
|
|
509
539
|
}
|
|
510
540
|
|
|
511
541
|
const ignoreMaxSegmentDuration =
|
|
512
542
|
this.config_.dash.ignoreMaxSegmentDuration;
|
|
513
543
|
let maxSegmentDuration = null;
|
|
514
544
|
if (!ignoreMaxSegmentDuration) {
|
|
515
|
-
maxSegmentDuration =
|
|
516
|
-
mpd, 'maxSegmentDuration',
|
|
545
|
+
maxSegmentDuration = TXml.parseAttr(
|
|
546
|
+
mpd, 'maxSegmentDuration', TXml.parseDuration);
|
|
517
547
|
}
|
|
518
|
-
const mpdType = mpd.
|
|
548
|
+
const mpdType = mpd.attributes['type'] || 'static';
|
|
519
549
|
|
|
520
550
|
/** @type {!shaka.media.PresentationTimeline} */
|
|
521
551
|
let presentationTimeline;
|
|
@@ -575,7 +605,7 @@ shaka.dash.DashParser = class {
|
|
|
575
605
|
presentationTimeline.setSegmentAvailabilityDuration(
|
|
576
606
|
segmentAvailabilityDuration);
|
|
577
607
|
|
|
578
|
-
const profiles = mpd.
|
|
608
|
+
const profiles = mpd.attributes['profiles'] || '';
|
|
579
609
|
|
|
580
610
|
/** @type {shaka.dash.DashParser.Context} */
|
|
581
611
|
const context = {
|
|
@@ -666,8 +696,8 @@ shaka.dash.DashParser = class {
|
|
|
666
696
|
// We only need to do clock sync when we're using presentation start
|
|
667
697
|
// time. This condition also excludes VOD streams.
|
|
668
698
|
if (presentationTimeline.usingPresentationStartTime()) {
|
|
669
|
-
const
|
|
670
|
-
const timingElements =
|
|
699
|
+
const TXml = shaka.util.TXml;
|
|
700
|
+
const timingElements = TXml.findChildren(mpd, 'UTCTiming');
|
|
671
701
|
const offset = await this.parseUtcTiming_(getBaseUris, timingElements);
|
|
672
702
|
// Detect calls to stop().
|
|
673
703
|
if (!this.playerInterface_) {
|
|
@@ -706,33 +736,33 @@ shaka.dash.DashParser = class {
|
|
|
706
736
|
* Reads maxLatency and maxPlaybackRate properties from service
|
|
707
737
|
* description element.
|
|
708
738
|
*
|
|
709
|
-
* @param {!
|
|
739
|
+
* @param {!shaka.extern.xml.Node} mpd
|
|
710
740
|
* @return {?shaka.extern.ServiceDescription}
|
|
711
741
|
* @private
|
|
712
742
|
*/
|
|
713
743
|
parseServiceDescription_(mpd) {
|
|
714
|
-
const
|
|
715
|
-
const elem =
|
|
744
|
+
const TXml = shaka.util.TXml;
|
|
745
|
+
const elem = TXml.findChild(mpd, 'ServiceDescription');
|
|
716
746
|
|
|
717
747
|
if (!elem ) {
|
|
718
748
|
return null;
|
|
719
749
|
}
|
|
720
750
|
|
|
721
|
-
const latencyNode =
|
|
722
|
-
const playbackRateNode =
|
|
751
|
+
const latencyNode = TXml.findChild(elem, 'Latency');
|
|
752
|
+
const playbackRateNode = TXml.findChild(elem, 'PlaybackRate');
|
|
723
753
|
|
|
724
|
-
if ((latencyNode && latencyNode.
|
|
725
|
-
const maxLatency = latencyNode && latencyNode.
|
|
726
|
-
parseInt(latencyNode.
|
|
754
|
+
if ((latencyNode && latencyNode.attributes['max']) || playbackRateNode) {
|
|
755
|
+
const maxLatency = latencyNode && latencyNode.attributes['max'] ?
|
|
756
|
+
parseInt(latencyNode.attributes['max'], 10) / 1000 :
|
|
727
757
|
null;
|
|
728
758
|
const maxPlaybackRate = playbackRateNode ?
|
|
729
|
-
parseFloat(playbackRateNode.
|
|
759
|
+
parseFloat(playbackRateNode.attributes['max']) :
|
|
730
760
|
null;
|
|
731
|
-
const minLatency = latencyNode && latencyNode.
|
|
732
|
-
parseInt(latencyNode.
|
|
761
|
+
const minLatency = latencyNode && latencyNode.attributes['min'] ?
|
|
762
|
+
parseInt(latencyNode.attributes['min'], 10) / 1000 :
|
|
733
763
|
null;
|
|
734
764
|
const minPlaybackRate = playbackRateNode ?
|
|
735
|
-
parseFloat(playbackRateNode.
|
|
765
|
+
parseFloat(playbackRateNode.attributes['min']) :
|
|
736
766
|
null;
|
|
737
767
|
|
|
738
768
|
return {
|
|
@@ -753,7 +783,7 @@ shaka.dash.DashParser = class {
|
|
|
753
783
|
*
|
|
754
784
|
* @param {shaka.dash.DashParser.Context} context
|
|
755
785
|
* @param {function():!Array.<string>} getBaseUris
|
|
756
|
-
* @param {!
|
|
786
|
+
* @param {!shaka.extern.xml.Node} mpd
|
|
757
787
|
* @return {{
|
|
758
788
|
* periods: !Array.<shaka.extern.Period>,
|
|
759
789
|
* duration: ?number,
|
|
@@ -762,21 +792,21 @@ shaka.dash.DashParser = class {
|
|
|
762
792
|
* @private
|
|
763
793
|
*/
|
|
764
794
|
parsePeriods_(context, getBaseUris, mpd) {
|
|
765
|
-
const
|
|
766
|
-
const presentationDuration =
|
|
767
|
-
mpd, 'mediaPresentationDuration',
|
|
795
|
+
const TXml = shaka.util.TXml;
|
|
796
|
+
const presentationDuration = TXml.parseAttr(
|
|
797
|
+
mpd, 'mediaPresentationDuration', TXml.parseDuration);
|
|
768
798
|
|
|
769
799
|
const periods = [];
|
|
770
800
|
let prevEnd = 0;
|
|
771
|
-
const periodNodes =
|
|
801
|
+
const periodNodes = TXml.findChildren(mpd, 'Period');
|
|
772
802
|
for (let i = 0; i < periodNodes.length; i++) {
|
|
773
803
|
const elem = periodNodes[i];
|
|
774
804
|
const next = periodNodes[i + 1];
|
|
775
805
|
const start = /** @type {number} */ (
|
|
776
|
-
|
|
777
|
-
const periodId = elem.id;
|
|
806
|
+
TXml.parseAttr(elem, 'start', TXml.parseDuration, prevEnd));
|
|
807
|
+
const periodId = elem.attributes['id'];
|
|
778
808
|
const givenDuration =
|
|
779
|
-
|
|
809
|
+
TXml.parseAttr(elem, 'duration', TXml.parseDuration);
|
|
780
810
|
|
|
781
811
|
let periodDuration = null;
|
|
782
812
|
if (next) {
|
|
@@ -784,7 +814,7 @@ shaka.dash.DashParser = class {
|
|
|
784
814
|
// of the following Period is the duration of the media content
|
|
785
815
|
// represented by this Period."
|
|
786
816
|
const nextStart =
|
|
787
|
-
|
|
817
|
+
TXml.parseAttr(next, 'start', TXml.parseDuration);
|
|
788
818
|
if (nextStart != null) {
|
|
789
819
|
periodDuration = nextStart - start;
|
|
790
820
|
}
|
|
@@ -912,7 +942,7 @@ shaka.dash.DashParser = class {
|
|
|
912
942
|
*/
|
|
913
943
|
parsePeriod_(context, getBaseUris, periodInfo) {
|
|
914
944
|
const Functional = shaka.util.Functional;
|
|
915
|
-
const
|
|
945
|
+
const TXml = shaka.util.TXml;
|
|
916
946
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
917
947
|
|
|
918
948
|
context.period = this.createFrame_(periodInfo.node, null, getBaseUris);
|
|
@@ -928,7 +958,7 @@ shaka.dash.DashParser = class {
|
|
|
928
958
|
}
|
|
929
959
|
|
|
930
960
|
const eventStreamNodes =
|
|
931
|
-
|
|
961
|
+
TXml.findChildren(periodInfo.node, 'EventStream');
|
|
932
962
|
const availabilityStart =
|
|
933
963
|
context.presentationTimeline.getSegmentAvailabilityStart();
|
|
934
964
|
|
|
@@ -938,7 +968,7 @@ shaka.dash.DashParser = class {
|
|
|
938
968
|
}
|
|
939
969
|
|
|
940
970
|
const adaptationSetNodes =
|
|
941
|
-
|
|
971
|
+
TXml.findChildren(periodInfo.node, 'AdaptationSet');
|
|
942
972
|
const adaptationSets = adaptationSetNodes
|
|
943
973
|
.map((node) => this.parseAdaptationSet_(context, node))
|
|
944
974
|
.filter(Functional.isNotNull);
|
|
@@ -1047,12 +1077,12 @@ shaka.dash.DashParser = class {
|
|
|
1047
1077
|
* Parses an AdaptationSet XML element.
|
|
1048
1078
|
*
|
|
1049
1079
|
* @param {shaka.dash.DashParser.Context} context
|
|
1050
|
-
* @param {!
|
|
1080
|
+
* @param {!shaka.extern.xml.Node} elem The AdaptationSet element.
|
|
1051
1081
|
* @return {?shaka.dash.DashParser.AdaptationInfo}
|
|
1052
1082
|
* @private
|
|
1053
1083
|
*/
|
|
1054
1084
|
parseAdaptationSet_(context, elem) {
|
|
1055
|
-
const
|
|
1085
|
+
const TXml = shaka.util.TXml;
|
|
1056
1086
|
const Functional = shaka.util.Functional;
|
|
1057
1087
|
const ManifestParserUtils = shaka.util.ManifestParserUtils;
|
|
1058
1088
|
const ContentType = ManifestParserUtils.ContentType;
|
|
@@ -1061,9 +1091,9 @@ shaka.dash.DashParser = class {
|
|
|
1061
1091
|
context.adaptationSet = this.createFrame_(elem, context.period, null);
|
|
1062
1092
|
|
|
1063
1093
|
let main = false;
|
|
1064
|
-
const roleElements =
|
|
1094
|
+
const roleElements = TXml.findChildren(elem, 'Role');
|
|
1065
1095
|
const roleValues = roleElements.map((role) => {
|
|
1066
|
-
return role.
|
|
1096
|
+
return role.attributes['value'];
|
|
1067
1097
|
}).filter(Functional.isNotNull);
|
|
1068
1098
|
|
|
1069
1099
|
// Default kind for text streams is 'subtitle' if unspecified in the
|
|
@@ -1075,12 +1105,12 @@ shaka.dash.DashParser = class {
|
|
|
1075
1105
|
}
|
|
1076
1106
|
|
|
1077
1107
|
for (const roleElement of roleElements) {
|
|
1078
|
-
const scheme = roleElement.
|
|
1108
|
+
const scheme = roleElement.attributes['schemeIdUri'];
|
|
1079
1109
|
if (scheme == null || scheme == 'urn:mpeg:dash:role:2011') {
|
|
1080
1110
|
// These only apply for the given scheme, but allow them to be specified
|
|
1081
1111
|
// if there is no scheme specified.
|
|
1082
1112
|
// See: DASH section 5.8.5.5
|
|
1083
|
-
const value = roleElement.
|
|
1113
|
+
const value = roleElement.attributes['value'];
|
|
1084
1114
|
switch (value) {
|
|
1085
1115
|
case 'main':
|
|
1086
1116
|
main = true;
|
|
@@ -1125,18 +1155,18 @@ shaka.dash.DashParser = class {
|
|
|
1125
1155
|
};
|
|
1126
1156
|
|
|
1127
1157
|
const essentialProperties =
|
|
1128
|
-
|
|
1158
|
+
TXml.findChildren(elem, 'EssentialProperty');
|
|
1129
1159
|
// ID of real AdaptationSet if this is a trick mode set:
|
|
1130
1160
|
let trickModeFor = null;
|
|
1131
1161
|
let isFastSwitching = false;
|
|
1132
1162
|
let unrecognizedEssentialProperty = false;
|
|
1133
1163
|
for (const prop of essentialProperties) {
|
|
1134
|
-
const schemeId = prop.
|
|
1164
|
+
const schemeId = prop.attributes['schemeIdUri'];
|
|
1135
1165
|
if (schemeId == 'http://dashif.org/guidelines/trickmode') {
|
|
1136
|
-
trickModeFor = prop.
|
|
1166
|
+
trickModeFor = prop.attributes['value'];
|
|
1137
1167
|
} else if (schemeId == transferCharacteristicsScheme) {
|
|
1138
1168
|
videoRange = getVideoRangeFromTransferCharacteristicCICP(
|
|
1139
|
-
parseInt(prop.
|
|
1169
|
+
parseInt(prop.attributes['value'], 10),
|
|
1140
1170
|
);
|
|
1141
1171
|
} else if (schemeId == colourPrimariesScheme ||
|
|
1142
1172
|
schemeId == matrixCoefficientsScheme) {
|
|
@@ -1148,25 +1178,29 @@ shaka.dash.DashParser = class {
|
|
|
1148
1178
|
}
|
|
1149
1179
|
}
|
|
1150
1180
|
|
|
1181
|
+
let lastSegmentNumber = null;
|
|
1182
|
+
|
|
1151
1183
|
const supplementalProperties =
|
|
1152
|
-
|
|
1184
|
+
TXml.findChildren(elem, 'SupplementalProperty');
|
|
1153
1185
|
for (const prop of supplementalProperties) {
|
|
1154
|
-
const schemeId = prop.
|
|
1155
|
-
if (schemeId ==
|
|
1186
|
+
const schemeId = prop.attributes['schemeIdUri'];
|
|
1187
|
+
if (schemeId == 'http://dashif.org/guidelines/last-segment-number') {
|
|
1188
|
+
lastSegmentNumber = parseInt(prop.attributes['value'], 10) - 1;
|
|
1189
|
+
} else if (schemeId == transferCharacteristicsScheme) {
|
|
1156
1190
|
videoRange = getVideoRangeFromTransferCharacteristicCICP(
|
|
1157
|
-
parseInt(prop.
|
|
1191
|
+
parseInt(prop.attributes['value'], 10),
|
|
1158
1192
|
);
|
|
1159
1193
|
}
|
|
1160
1194
|
}
|
|
1161
1195
|
|
|
1162
|
-
const accessibilities =
|
|
1196
|
+
const accessibilities = TXml.findChildren(elem, 'Accessibility');
|
|
1163
1197
|
const LanguageUtils = shaka.util.LanguageUtils;
|
|
1164
1198
|
const closedCaptions = new Map();
|
|
1165
1199
|
/** @type {?shaka.media.ManifestParser.AccessibilityPurpose} */
|
|
1166
1200
|
let accessibilityPurpose;
|
|
1167
1201
|
for (const prop of accessibilities) {
|
|
1168
|
-
const schemeId = prop.
|
|
1169
|
-
const value = prop.
|
|
1202
|
+
const schemeId = prop.attributes['schemeIdUri'];
|
|
1203
|
+
const value = prop.attributes['value'];
|
|
1170
1204
|
if (schemeId == 'urn:scte:dash:cc:cea-608:2015' ) {
|
|
1171
1205
|
let channelId = 1;
|
|
1172
1206
|
if (value != null) {
|
|
@@ -1270,7 +1304,7 @@ shaka.dash.DashParser = class {
|
|
|
1270
1304
|
}
|
|
1271
1305
|
|
|
1272
1306
|
const contentProtectionElems =
|
|
1273
|
-
|
|
1307
|
+
TXml.findChildren(elem, 'ContentProtection');
|
|
1274
1308
|
const contentProtection = ContentProtection.parseFromAdaptationSet(
|
|
1275
1309
|
contentProtectionElems,
|
|
1276
1310
|
this.config_.dash.ignoreDrmInfo,
|
|
@@ -1280,24 +1314,26 @@ shaka.dash.DashParser = class {
|
|
|
1280
1314
|
context.adaptationSet.language || 'und');
|
|
1281
1315
|
|
|
1282
1316
|
// This attribute is currently non-standard, but it is supported by Kaltura.
|
|
1283
|
-
let label = elem.
|
|
1317
|
+
let label = elem.attributes['label'];
|
|
1284
1318
|
|
|
1285
1319
|
// See DASH IOP 4.3 here https://dashif.org/docs/DASH-IF-IOP-v4.3.pdf (page 35)
|
|
1286
|
-
const labelElements =
|
|
1320
|
+
const labelElements = TXml.findChildren(elem, 'Label');
|
|
1287
1321
|
if (labelElements && labelElements.length) {
|
|
1288
1322
|
// NOTE: Right now only one label field is supported.
|
|
1289
1323
|
const firstLabelElement = labelElements[0];
|
|
1290
|
-
|
|
1291
|
-
|
|
1324
|
+
const textContent = shaka.util.TXml.getTextContents(firstLabelElement);
|
|
1325
|
+
if (textContent) {
|
|
1326
|
+
label = textContent;
|
|
1292
1327
|
}
|
|
1293
1328
|
}
|
|
1294
1329
|
|
|
1295
1330
|
// Parse Representations into Streams.
|
|
1296
|
-
const representations =
|
|
1331
|
+
const representations = TXml.findChildren(elem, 'Representation');
|
|
1297
1332
|
const streams = representations.map((representation) => {
|
|
1298
1333
|
const parsedRepresentation = this.parseRepresentation_(context,
|
|
1299
1334
|
contentProtection, kind, language, label, main, roleValues,
|
|
1300
|
-
closedCaptions, representation, accessibilityPurpose
|
|
1335
|
+
closedCaptions, representation, accessibilityPurpose,
|
|
1336
|
+
lastSegmentNumber);
|
|
1301
1337
|
if (parsedRepresentation) {
|
|
1302
1338
|
parsedRepresentation.hdr = parsedRepresentation.hdr || videoRange;
|
|
1303
1339
|
parsedRepresentation.fastSwitching = isFastSwitching;
|
|
@@ -1353,7 +1389,7 @@ shaka.dash.DashParser = class {
|
|
|
1353
1389
|
}
|
|
1354
1390
|
|
|
1355
1391
|
const repIds = representations
|
|
1356
|
-
.map((node) => { return node.
|
|
1392
|
+
.map((node) => { return node.attributes['id']; })
|
|
1357
1393
|
.filter(shaka.util.Functional.isNotNull);
|
|
1358
1394
|
|
|
1359
1395
|
return {
|
|
@@ -1379,17 +1415,19 @@ shaka.dash.DashParser = class {
|
|
|
1379
1415
|
* @param {boolean} isPrimary
|
|
1380
1416
|
* @param {!Array.<string>} roles
|
|
1381
1417
|
* @param {Map.<string, string>} closedCaptions
|
|
1382
|
-
* @param {!
|
|
1418
|
+
* @param {!shaka.extern.xml.Node} node
|
|
1383
1419
|
* @param {?shaka.media.ManifestParser.AccessibilityPurpose}
|
|
1384
1420
|
* accessibilityPurpose
|
|
1421
|
+
* @param {?number} lastSegmentNumber
|
|
1385
1422
|
*
|
|
1386
1423
|
* @return {?shaka.extern.Stream} The Stream, or null when there is a
|
|
1387
1424
|
* non-critical parsing error.
|
|
1388
1425
|
* @private
|
|
1389
1426
|
*/
|
|
1390
1427
|
parseRepresentation_(context, contentProtection, kind, language, label,
|
|
1391
|
-
isPrimary, roles, closedCaptions, node, accessibilityPurpose
|
|
1392
|
-
|
|
1428
|
+
isPrimary, roles, closedCaptions, node, accessibilityPurpose,
|
|
1429
|
+
lastSegmentNumber) {
|
|
1430
|
+
const TXml = shaka.util.TXml;
|
|
1393
1431
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
1394
1432
|
|
|
1395
1433
|
context.representation =
|
|
@@ -1411,7 +1449,7 @@ shaka.dash.DashParser = class {
|
|
|
1411
1449
|
// To avoid NaN at the variant level on broken content, fall back to zero.
|
|
1412
1450
|
// https://github.com/shaka-project/shaka-player/issues/938#issuecomment-317278180
|
|
1413
1451
|
context.bandwidth =
|
|
1414
|
-
|
|
1452
|
+
TXml.parseAttr(node, 'bandwidth', TXml.parsePositiveInt) || 0;
|
|
1415
1453
|
|
|
1416
1454
|
/** @type {?shaka.dash.DashParser.StreamInfo} */
|
|
1417
1455
|
let streamInfo;
|
|
@@ -1422,8 +1460,8 @@ shaka.dash.DashParser = class {
|
|
|
1422
1460
|
const isImage = contentType == ContentType.IMAGE;
|
|
1423
1461
|
|
|
1424
1462
|
try {
|
|
1425
|
-
/** @type {shaka.extern.
|
|
1426
|
-
let
|
|
1463
|
+
/** @type {shaka.extern.aesKey|undefined} */
|
|
1464
|
+
let aesKey = undefined;
|
|
1427
1465
|
if (contentProtection.aes128Info) {
|
|
1428
1466
|
const getBaseUris = context.representation.getBaseUris;
|
|
1429
1467
|
const uris = shaka.util.ManifestParserUtils.resolveUris(
|
|
@@ -1432,15 +1470,16 @@ shaka.dash.DashParser = class {
|
|
|
1432
1470
|
const request = shaka.net.NetworkingEngine.makeRequest(
|
|
1433
1471
|
uris, this.config_.retryParameters);
|
|
1434
1472
|
|
|
1435
|
-
|
|
1436
|
-
|
|
1473
|
+
aesKey = {
|
|
1474
|
+
bitsKey: 128,
|
|
1475
|
+
blockCipherMode: 'CBC',
|
|
1437
1476
|
iv: contentProtection.aes128Info.iv,
|
|
1438
1477
|
firstMediaSequenceNumber: 0,
|
|
1439
1478
|
};
|
|
1440
1479
|
|
|
1441
1480
|
// Don't download the key object until the segment is parsed, to
|
|
1442
1481
|
// avoid a startup delay for long manifests with lots of keys.
|
|
1443
|
-
|
|
1482
|
+
aesKey.fetchKey = async () => {
|
|
1444
1483
|
const keyResponse =
|
|
1445
1484
|
await this.makeNetworkRequest_(request, requestType);
|
|
1446
1485
|
|
|
@@ -1456,9 +1495,9 @@ shaka.dash.DashParser = class {
|
|
|
1456
1495
|
const algorithm = {
|
|
1457
1496
|
name: 'AES-CBC',
|
|
1458
1497
|
};
|
|
1459
|
-
|
|
1498
|
+
aesKey.cryptoKey = await window.crypto.subtle.importKey(
|
|
1460
1499
|
'raw', keyResponse.data, algorithm, true, ['decrypt']);
|
|
1461
|
-
|
|
1500
|
+
aesKey.fetchKey = undefined; // No longer needed.
|
|
1462
1501
|
};
|
|
1463
1502
|
}
|
|
1464
1503
|
const requestSegment = (uris, startByte, endByte, isInit) => {
|
|
@@ -1466,17 +1505,17 @@ shaka.dash.DashParser = class {
|
|
|
1466
1505
|
};
|
|
1467
1506
|
if (context.representation.segmentBase) {
|
|
1468
1507
|
streamInfo = shaka.dash.SegmentBase.createStreamInfo(
|
|
1469
|
-
context, requestSegment,
|
|
1508
|
+
context, requestSegment, aesKey);
|
|
1470
1509
|
} else if (context.representation.segmentList) {
|
|
1471
1510
|
streamInfo = shaka.dash.SegmentList.createStreamInfo(
|
|
1472
|
-
context, this.streamMap_,
|
|
1511
|
+
context, this.streamMap_, aesKey);
|
|
1473
1512
|
} else if (context.representation.segmentTemplate) {
|
|
1474
1513
|
const hasManifest = !!this.manifest_;
|
|
1475
1514
|
|
|
1476
1515
|
streamInfo = shaka.dash.SegmentTemplate.createStreamInfo(
|
|
1477
1516
|
context, requestSegment, this.streamMap_, hasManifest,
|
|
1478
1517
|
this.config_.dash.initialSegmentLimit, this.periodDurations_,
|
|
1479
|
-
|
|
1518
|
+
aesKey, lastSegmentNumber);
|
|
1480
1519
|
} else {
|
|
1481
1520
|
goog.asserts.assert(isText,
|
|
1482
1521
|
'Must have Segment* with non-text streams.');
|
|
@@ -1485,8 +1524,13 @@ shaka.dash.DashParser = class {
|
|
|
1485
1524
|
const getBaseUris = context.representation.getBaseUris;
|
|
1486
1525
|
streamInfo = {
|
|
1487
1526
|
generateSegmentIndex: () => {
|
|
1488
|
-
|
|
1489
|
-
periodStart, duration, getBaseUris())
|
|
1527
|
+
const segmentIndex = shaka.media.SegmentIndex.forSingleSegment(
|
|
1528
|
+
periodStart, duration, getBaseUris());
|
|
1529
|
+
segmentIndex.forEachTopLevelReference((ref) => {
|
|
1530
|
+
ref.mimeType = context.representation.mimeType;
|
|
1531
|
+
ref.codecs = context.representation.codecs;
|
|
1532
|
+
});
|
|
1533
|
+
return Promise.resolve(segmentIndex);
|
|
1490
1534
|
},
|
|
1491
1535
|
};
|
|
1492
1536
|
}
|
|
@@ -1503,7 +1547,7 @@ shaka.dash.DashParser = class {
|
|
|
1503
1547
|
}
|
|
1504
1548
|
|
|
1505
1549
|
const contentProtectionElems =
|
|
1506
|
-
|
|
1550
|
+
TXml.findChildren(node, 'ContentProtection');
|
|
1507
1551
|
const keyId = shaka.dash.ContentProtection.parseFromRepresentation(
|
|
1508
1552
|
contentProtectionElems, contentProtection,
|
|
1509
1553
|
this.config_.dash.ignoreDrmInfo,
|
|
@@ -1513,12 +1557,12 @@ shaka.dash.DashParser = class {
|
|
|
1513
1557
|
// Detect the presence of E-AC3 JOC audio content, using DD+JOC signaling.
|
|
1514
1558
|
// See: ETSI TS 103 420 V1.2.1 (2018-10)
|
|
1515
1559
|
const supplementalPropertyElems =
|
|
1516
|
-
|
|
1560
|
+
TXml.findChildren(node, 'SupplementalProperty');
|
|
1517
1561
|
const hasJoc = supplementalPropertyElems.some((element) => {
|
|
1518
1562
|
const expectedUri = 'tag:dolby.com,2018:dash:EC3_ExtensionType:2018';
|
|
1519
1563
|
const expectedValue = 'JOC';
|
|
1520
|
-
return element.
|
|
1521
|
-
element.
|
|
1564
|
+
return element.attributes['schemeIdUri'] == expectedUri &&
|
|
1565
|
+
element.attributes['value'] == expectedValue;
|
|
1522
1566
|
});
|
|
1523
1567
|
let spatialAudio = false;
|
|
1524
1568
|
if (hasJoc) {
|
|
@@ -1536,16 +1580,16 @@ shaka.dash.DashParser = class {
|
|
|
1536
1580
|
let tilesLayout;
|
|
1537
1581
|
if (isImage) {
|
|
1538
1582
|
const essentialPropertyElems =
|
|
1539
|
-
|
|
1583
|
+
TXml.findChildren(node, 'EssentialProperty');
|
|
1540
1584
|
const thumbnailTileElem = essentialPropertyElems.find((element) => {
|
|
1541
1585
|
const expectedUris = [
|
|
1542
1586
|
'http://dashif.org/thumbnail_tile',
|
|
1543
1587
|
'http://dashif.org/guidelines/thumbnail_tile',
|
|
1544
1588
|
];
|
|
1545
|
-
return expectedUris.includes(element.
|
|
1589
|
+
return expectedUris.includes(element.attributes['schemeIdUri']);
|
|
1546
1590
|
});
|
|
1547
1591
|
if (thumbnailTileElem) {
|
|
1548
|
-
tilesLayout = thumbnailTileElem.
|
|
1592
|
+
tilesLayout = thumbnailTileElem.attributes['value'];
|
|
1549
1593
|
}
|
|
1550
1594
|
// Filter image adaptation sets that has no tilesLayout.
|
|
1551
1595
|
if (!tilesLayout) {
|
|
@@ -1585,7 +1629,7 @@ shaka.dash.DashParser = class {
|
|
|
1585
1629
|
},
|
|
1586
1630
|
segmentIndex: null,
|
|
1587
1631
|
mimeType: context.representation.mimeType,
|
|
1588
|
-
codecs
|
|
1632
|
+
codecs,
|
|
1589
1633
|
frameRate: context.representation.frameRate,
|
|
1590
1634
|
pixelAspectRatio: context.representation.pixelAspectRatio,
|
|
1591
1635
|
bandwidth: context.bandwidth,
|
|
@@ -1615,6 +1659,8 @@ shaka.dash.DashParser = class {
|
|
|
1615
1659
|
accessibilityPurpose,
|
|
1616
1660
|
external: false,
|
|
1617
1661
|
fastSwitching: false,
|
|
1662
|
+
fullMimeTypes: new Set([shaka.util.MimeUtils.getFullType(
|
|
1663
|
+
context.representation.mimeType, context.representation.codecs)]),
|
|
1618
1664
|
};
|
|
1619
1665
|
}
|
|
1620
1666
|
|
|
@@ -1675,6 +1721,15 @@ shaka.dash.DashParser = class {
|
|
|
1675
1721
|
this.setUpdateTimer_(updateDelay);
|
|
1676
1722
|
}
|
|
1677
1723
|
|
|
1724
|
+
/**
|
|
1725
|
+
* Update now the manifest
|
|
1726
|
+
*
|
|
1727
|
+
* @private
|
|
1728
|
+
*/
|
|
1729
|
+
updateNow_() {
|
|
1730
|
+
this.updateTimer_.tickNow();
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1678
1733
|
/**
|
|
1679
1734
|
* Sets the update timer. Does nothing if the manifest does not specify an
|
|
1680
1735
|
* update period.
|
|
@@ -1691,9 +1746,13 @@ shaka.dash.DashParser = class {
|
|
|
1691
1746
|
if (this.updatePeriod_ < 0) {
|
|
1692
1747
|
return;
|
|
1693
1748
|
}
|
|
1749
|
+
let updateTime = this.updatePeriod_;
|
|
1750
|
+
if (this.config_.dash.updatePeriod >= 0) {
|
|
1751
|
+
updateTime = this.config_.dash.updatePeriod;
|
|
1752
|
+
}
|
|
1694
1753
|
|
|
1695
1754
|
const finalDelay = Math.max(
|
|
1696
|
-
|
|
1755
|
+
updateTime - offset,
|
|
1697
1756
|
this.averageUpdateDuration_.getEstimate());
|
|
1698
1757
|
|
|
1699
1758
|
// We do not run the timer as repeating because part of update is async and
|
|
@@ -1704,7 +1763,7 @@ shaka.dash.DashParser = class {
|
|
|
1704
1763
|
/**
|
|
1705
1764
|
* Creates a new inheritance frame for the given element.
|
|
1706
1765
|
*
|
|
1707
|
-
* @param {!
|
|
1766
|
+
* @param {!shaka.extern.xml.Node} elem
|
|
1708
1767
|
* @param {?shaka.dash.DashParser.InheritanceFrame} parent
|
|
1709
1768
|
* @param {?function():!Array.<string>} getBaseUris
|
|
1710
1769
|
* @return {shaka.dash.DashParser.InheritanceFrame}
|
|
@@ -1714,7 +1773,7 @@ shaka.dash.DashParser = class {
|
|
|
1714
1773
|
goog.asserts.assert(parent || getBaseUris,
|
|
1715
1774
|
'Must provide either parent or getBaseUris');
|
|
1716
1775
|
const ManifestParserUtils = shaka.util.ManifestParserUtils;
|
|
1717
|
-
const
|
|
1776
|
+
const TXml = shaka.util.TXml;
|
|
1718
1777
|
parent = parent || /** @type {shaka.dash.DashParser.InheritanceFrame} */ ({
|
|
1719
1778
|
contentType: '',
|
|
1720
1779
|
mimeType: '',
|
|
@@ -1729,17 +1788,17 @@ shaka.dash.DashParser = class {
|
|
|
1729
1788
|
});
|
|
1730
1789
|
getBaseUris = getBaseUris || parent.getBaseUris;
|
|
1731
1790
|
|
|
1732
|
-
const parseNumber =
|
|
1733
|
-
const evalDivision =
|
|
1791
|
+
const parseNumber = TXml.parseNonNegativeInt;
|
|
1792
|
+
const evalDivision = TXml.evalDivision;
|
|
1734
1793
|
|
|
1735
|
-
const id = elem.
|
|
1736
|
-
const uriObjs =
|
|
1794
|
+
const id = elem.attributes['id'];
|
|
1795
|
+
const uriObjs = TXml.findChildren(elem, 'BaseURL');
|
|
1737
1796
|
let calculatedBaseUris;
|
|
1738
1797
|
let someLocationValid = false;
|
|
1739
1798
|
if (this.contentSteeringManager_) {
|
|
1740
1799
|
for (const uriObj of uriObjs) {
|
|
1741
|
-
const serviceLocation = uriObj.
|
|
1742
|
-
const uri =
|
|
1800
|
+
const serviceLocation = uriObj.attributes['serviceLocation'];
|
|
1801
|
+
const uri = TXml.getContents(uriObj);
|
|
1743
1802
|
if (serviceLocation && uri) {
|
|
1744
1803
|
this.contentSteeringManager_.addLocation(
|
|
1745
1804
|
id, serviceLocation, uri);
|
|
@@ -1748,7 +1807,7 @@ shaka.dash.DashParser = class {
|
|
|
1748
1807
|
}
|
|
1749
1808
|
}
|
|
1750
1809
|
if (!someLocationValid || !this.contentSteeringManager_) {
|
|
1751
|
-
calculatedBaseUris = uriObjs.map(
|
|
1810
|
+
calculatedBaseUris = uriObjs.map(TXml.getContents);
|
|
1752
1811
|
}
|
|
1753
1812
|
|
|
1754
1813
|
const getFrameUris = () => {
|
|
@@ -1764,55 +1823,55 @@ shaka.dash.DashParser = class {
|
|
|
1764
1823
|
return [];
|
|
1765
1824
|
};
|
|
1766
1825
|
|
|
1767
|
-
let contentType = elem.
|
|
1768
|
-
const mimeType = elem.
|
|
1769
|
-
const codecs = elem.
|
|
1826
|
+
let contentType = elem.attributes['contentType'] || parent.contentType;
|
|
1827
|
+
const mimeType = elem.attributes['mimeType'] || parent.mimeType;
|
|
1828
|
+
const codecs = elem.attributes['codecs'] || parent.codecs;
|
|
1770
1829
|
const frameRate =
|
|
1771
|
-
|
|
1830
|
+
TXml.parseAttr(elem, 'frameRate', evalDivision) || parent.frameRate;
|
|
1772
1831
|
const pixelAspectRatio =
|
|
1773
|
-
elem.
|
|
1832
|
+
elem.attributes['sar'] || parent.pixelAspectRatio;
|
|
1774
1833
|
const emsgSchemeIdUris = this.emsgSchemeIdUris_(
|
|
1775
|
-
|
|
1834
|
+
TXml.findChildren(elem, 'InbandEventStream'),
|
|
1776
1835
|
parent.emsgSchemeIdUris);
|
|
1777
1836
|
const audioChannelConfigs =
|
|
1778
|
-
|
|
1837
|
+
TXml.findChildren(elem, 'AudioChannelConfiguration');
|
|
1779
1838
|
const numChannels =
|
|
1780
1839
|
this.parseAudioChannels_(audioChannelConfigs) || parent.numChannels;
|
|
1781
1840
|
const audioSamplingRate =
|
|
1782
|
-
|
|
1841
|
+
TXml.parseAttr(elem, 'audioSamplingRate', parseNumber) ||
|
|
1783
1842
|
parent.audioSamplingRate;
|
|
1784
1843
|
|
|
1785
1844
|
if (!contentType) {
|
|
1786
1845
|
contentType = shaka.dash.DashParser.guessContentType_(mimeType, codecs);
|
|
1787
1846
|
}
|
|
1788
1847
|
|
|
1789
|
-
const segmentBase =
|
|
1790
|
-
const segmentTemplate =
|
|
1848
|
+
const segmentBase = TXml.findChild(elem, 'SegmentBase');
|
|
1849
|
+
const segmentTemplate = TXml.findChild(elem, 'SegmentTemplate');
|
|
1791
1850
|
|
|
1792
1851
|
// The availabilityTimeOffset is the sum of all @availabilityTimeOffset
|
|
1793
1852
|
// values that apply to the adaptation set, via BaseURL, SegmentBase,
|
|
1794
1853
|
// or SegmentTemplate elements.
|
|
1795
1854
|
const segmentBaseAto = segmentBase ?
|
|
1796
|
-
(
|
|
1797
|
-
|
|
1855
|
+
(TXml.parseAttr(segmentBase, 'availabilityTimeOffset',
|
|
1856
|
+
TXml.parseFloat) || 0) : 0;
|
|
1798
1857
|
const segmentTemplateAto = segmentTemplate ?
|
|
1799
|
-
(
|
|
1800
|
-
|
|
1858
|
+
(TXml.parseAttr(segmentTemplate, 'availabilityTimeOffset',
|
|
1859
|
+
TXml.parseFloat) || 0) : 0;
|
|
1801
1860
|
const baseUriAto = uriObjs && uriObjs.length ?
|
|
1802
|
-
(
|
|
1803
|
-
|
|
1861
|
+
(TXml.parseAttr(uriObjs[0], 'availabilityTimeOffset',
|
|
1862
|
+
TXml.parseFloat) || 0) : 0;
|
|
1804
1863
|
|
|
1805
1864
|
const availabilityTimeOffset = parent.availabilityTimeOffset + baseUriAto +
|
|
1806
1865
|
segmentBaseAto + segmentTemplateAto;
|
|
1807
1866
|
|
|
1808
1867
|
let segmentSequenceCadence = null;
|
|
1809
1868
|
const segmentSequenceProperties =
|
|
1810
|
-
|
|
1869
|
+
TXml.findChild(elem, 'SegmentSequenceProperties');
|
|
1811
1870
|
if (segmentSequenceProperties) {
|
|
1812
|
-
const sap =
|
|
1871
|
+
const sap = TXml.findChild(segmentSequenceProperties, 'SAP');
|
|
1813
1872
|
if (sap) {
|
|
1814
|
-
segmentSequenceCadence =
|
|
1815
|
-
|
|
1873
|
+
segmentSequenceCadence = TXml.parseAttr(sap, 'cadence',
|
|
1874
|
+
TXml.parseInt);
|
|
1816
1875
|
}
|
|
1817
1876
|
}
|
|
1818
1877
|
|
|
@@ -1821,10 +1880,10 @@ shaka.dash.DashParser = class {
|
|
|
1821
1880
|
() => ManifestParserUtils.resolveUris(getBaseUris(), getFrameUris()),
|
|
1822
1881
|
segmentBase: segmentBase || parent.segmentBase,
|
|
1823
1882
|
segmentList:
|
|
1824
|
-
|
|
1883
|
+
TXml.findChild(elem, 'SegmentList') || parent.segmentList,
|
|
1825
1884
|
segmentTemplate: segmentTemplate || parent.segmentTemplate,
|
|
1826
|
-
width:
|
|
1827
|
-
height:
|
|
1885
|
+
width: TXml.parseAttr(elem, 'width', parseNumber) || parent.width,
|
|
1886
|
+
height: TXml.parseAttr(elem, 'height', parseNumber) || parent.height,
|
|
1828
1887
|
contentType: contentType,
|
|
1829
1888
|
mimeType: mimeType,
|
|
1830
1889
|
codecs: codecs,
|
|
@@ -1832,7 +1891,7 @@ shaka.dash.DashParser = class {
|
|
|
1832
1891
|
pixelAspectRatio: pixelAspectRatio,
|
|
1833
1892
|
emsgSchemeIdUris: emsgSchemeIdUris,
|
|
1834
1893
|
id: id,
|
|
1835
|
-
language: elem.
|
|
1894
|
+
language: elem.attributes['lang'],
|
|
1836
1895
|
numChannels: numChannels,
|
|
1837
1896
|
audioSamplingRate: audioSamplingRate,
|
|
1838
1897
|
availabilityTimeOffset: availabilityTimeOffset,
|
|
@@ -1846,7 +1905,8 @@ shaka.dash.DashParser = class {
|
|
|
1846
1905
|
* of the ones parsed from inBandEventStreams and the ones provided in
|
|
1847
1906
|
* emsgSchemeIdUris.
|
|
1848
1907
|
*
|
|
1849
|
-
* @param {!Array.<!
|
|
1908
|
+
* @param {!Array.<!shaka.extern.xml.Node>} inBandEventStreams
|
|
1909
|
+
* Array of InbandEventStream
|
|
1850
1910
|
* elements to parse and add to the returned array.
|
|
1851
1911
|
* @param {!Array.<string>} emsgSchemeIdUris Array of parsed
|
|
1852
1912
|
* InbandEventStream schemeIdUri attributes to add to the returned array.
|
|
@@ -1857,7 +1917,7 @@ shaka.dash.DashParser = class {
|
|
|
1857
1917
|
emsgSchemeIdUris_(inBandEventStreams, emsgSchemeIdUris) {
|
|
1858
1918
|
const schemeIdUris = emsgSchemeIdUris.slice();
|
|
1859
1919
|
for (const event of inBandEventStreams) {
|
|
1860
|
-
const schemeIdUri = event.
|
|
1920
|
+
const schemeIdUri = event.attributes['schemeIdUri'];
|
|
1861
1921
|
if (!schemeIdUris.includes(schemeIdUri)) {
|
|
1862
1922
|
schemeIdUris.push(schemeIdUri);
|
|
1863
1923
|
}
|
|
@@ -1866,19 +1926,19 @@ shaka.dash.DashParser = class {
|
|
|
1866
1926
|
}
|
|
1867
1927
|
|
|
1868
1928
|
/**
|
|
1869
|
-
* @param {!Array.<!
|
|
1929
|
+
* @param {!Array.<!shaka.extern.xml.Node>} audioChannelConfigs An array of
|
|
1870
1930
|
* AudioChannelConfiguration elements.
|
|
1871
1931
|
* @return {?number} The number of audio channels, or null if unknown.
|
|
1872
1932
|
* @private
|
|
1873
1933
|
*/
|
|
1874
1934
|
parseAudioChannels_(audioChannelConfigs) {
|
|
1875
1935
|
for (const elem of audioChannelConfigs) {
|
|
1876
|
-
const scheme = elem.
|
|
1936
|
+
const scheme = elem.attributes['schemeIdUri'];
|
|
1877
1937
|
if (!scheme) {
|
|
1878
1938
|
continue;
|
|
1879
1939
|
}
|
|
1880
1940
|
|
|
1881
|
-
const value = elem.
|
|
1941
|
+
const value = elem.attributes['value'];
|
|
1882
1942
|
if (!value) {
|
|
1883
1943
|
continue;
|
|
1884
1944
|
}
|
|
@@ -2049,15 +2109,15 @@ shaka.dash.DashParser = class {
|
|
|
2049
2109
|
* Parses an array of UTCTiming elements.
|
|
2050
2110
|
*
|
|
2051
2111
|
* @param {function():!Array.<string>} getBaseUris
|
|
2052
|
-
* @param {!Array.<!
|
|
2112
|
+
* @param {!Array.<!shaka.extern.xml.Node>} elems
|
|
2053
2113
|
* @return {!Promise.<number>}
|
|
2054
2114
|
* @private
|
|
2055
2115
|
*/
|
|
2056
2116
|
async parseUtcTiming_(getBaseUris, elems) {
|
|
2057
2117
|
const schemesAndValues = elems.map((elem) => {
|
|
2058
2118
|
return {
|
|
2059
|
-
scheme: elem.
|
|
2060
|
-
value: elem.
|
|
2119
|
+
scheme: elem.attributes['schemeIdUri'],
|
|
2120
|
+
value: elem.attributes['value'],
|
|
2061
2121
|
};
|
|
2062
2122
|
});
|
|
2063
2123
|
|
|
@@ -2121,23 +2181,23 @@ shaka.dash.DashParser = class {
|
|
|
2121
2181
|
*
|
|
2122
2182
|
* @param {number} periodStart
|
|
2123
2183
|
* @param {?number} periodDuration
|
|
2124
|
-
* @param {!
|
|
2184
|
+
* @param {!shaka.extern.xml.Node} elem
|
|
2125
2185
|
* @param {number} availabilityStart
|
|
2126
2186
|
* @private
|
|
2127
2187
|
*/
|
|
2128
2188
|
parseEventStream_(periodStart, periodDuration, elem, availabilityStart) {
|
|
2129
|
-
const
|
|
2130
|
-
const parseNumber =
|
|
2189
|
+
const TXml = shaka.util.TXml;
|
|
2190
|
+
const parseNumber = shaka.util.TXml.parseNonNegativeInt;
|
|
2131
2191
|
|
|
2132
|
-
const schemeIdUri = elem.
|
|
2133
|
-
const value = elem.
|
|
2134
|
-
const timescale =
|
|
2192
|
+
const schemeIdUri = elem.attributes['schemeIdUri'] || '';
|
|
2193
|
+
const value = elem.attributes['value'] || '';
|
|
2194
|
+
const timescale = TXml.parseAttr(elem, 'timescale', parseNumber) || 1;
|
|
2135
2195
|
|
|
2136
|
-
for (const eventNode of
|
|
2196
|
+
for (const eventNode of TXml.findChildren(elem, 'Event')) {
|
|
2137
2197
|
const presentationTime =
|
|
2138
|
-
|
|
2198
|
+
TXml.parseAttr(eventNode, 'presentationTime', parseNumber) || 0;
|
|
2139
2199
|
const duration =
|
|
2140
|
-
|
|
2200
|
+
TXml.parseAttr(eventNode, 'duration', parseNumber) || 0;
|
|
2141
2201
|
|
|
2142
2202
|
let startTime = presentationTime / timescale + periodStart;
|
|
2143
2203
|
let endTime = startTime + (duration / timescale);
|
|
@@ -2159,8 +2219,9 @@ shaka.dash.DashParser = class {
|
|
|
2159
2219
|
value: value,
|
|
2160
2220
|
startTime: startTime,
|
|
2161
2221
|
endTime: endTime,
|
|
2162
|
-
id: eventNode.
|
|
2163
|
-
eventElement: eventNode,
|
|
2222
|
+
id: eventNode.attributes['id'] || '',
|
|
2223
|
+
eventElement: TXml.txmlNodeToDomElement(eventNode),
|
|
2224
|
+
eventNode: eventNode,
|
|
2164
2225
|
};
|
|
2165
2226
|
|
|
2166
2227
|
this.playerInterface_.onTimelineRegionAdded(region);
|
|
@@ -2248,9 +2309,9 @@ shaka.dash.DashParser.RequestSegmentCallback;
|
|
|
2248
2309
|
|
|
2249
2310
|
/**
|
|
2250
2311
|
* @typedef {{
|
|
2251
|
-
* segmentBase:
|
|
2252
|
-
* segmentList:
|
|
2253
|
-
* segmentTemplate:
|
|
2312
|
+
* segmentBase: ?shaka.extern.xml.Node,
|
|
2313
|
+
* segmentList: ?shaka.extern.xml.Node,
|
|
2314
|
+
* segmentTemplate: ?shaka.extern.xml.Node,
|
|
2254
2315
|
* getBaseUris: function():!Array.<string>,
|
|
2255
2316
|
* width: (number|undefined),
|
|
2256
2317
|
* height: (number|undefined),
|
|
@@ -2272,11 +2333,11 @@ shaka.dash.DashParser.RequestSegmentCallback;
|
|
|
2272
2333
|
* A collection of elements and properties which are inherited across levels
|
|
2273
2334
|
* of a DASH manifest.
|
|
2274
2335
|
*
|
|
2275
|
-
* @property {
|
|
2336
|
+
* @property {?shaka.extern.xml.Node} segmentBase
|
|
2276
2337
|
* The XML node for SegmentBase.
|
|
2277
|
-
* @property {
|
|
2338
|
+
* @property {?shaka.extern.xml.Node} segmentList
|
|
2278
2339
|
* The XML node for SegmentList.
|
|
2279
|
-
* @property {
|
|
2340
|
+
* @property {?shaka.extern.xml.Node} segmentTemplate
|
|
2280
2341
|
* The XML node for SegmentTemplate.
|
|
2281
2342
|
* @property {function():!Array.<string>} getBaseUris
|
|
2282
2343
|
* Function than returns an array of absolute base URIs for the frame.
|
|
@@ -2361,7 +2422,7 @@ shaka.dash.DashParser.Context;
|
|
|
2361
2422
|
* @typedef {{
|
|
2362
2423
|
* start: number,
|
|
2363
2424
|
* duration: ?number,
|
|
2364
|
-
* node: !
|
|
2425
|
+
* node: !shaka.extern.xml.Node,
|
|
2365
2426
|
* isLastPeriod: boolean
|
|
2366
2427
|
* }}
|
|
2367
2428
|
*
|
|
@@ -2373,7 +2434,7 @@ shaka.dash.DashParser.Context;
|
|
|
2373
2434
|
* @property {?number} duration
|
|
2374
2435
|
* The duration of the period; or null if the duration is not given. This
|
|
2375
2436
|
* will be non-null for all periods except the last.
|
|
2376
|
-
* @property {!
|
|
2437
|
+
* @property {!shaka.extern.xml.Node} node
|
|
2377
2438
|
* The XML Node for the Period.
|
|
2378
2439
|
* @property {boolean} isLastPeriod
|
|
2379
2440
|
* Whether this Period is the last one in the manifest.
|