shaka-player 4.7.13 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AUTHORS +1 -0
- package/CONTRIBUTORS +1 -0
- package/LICENSE +54 -0
- package/README.md +22 -1
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/deps.js +34 -23
- package/dist/locales.js +44 -34
- package/dist/shaka-player.compiled.d.ts +194 -44
- package/dist/shaka-player.compiled.debug.d.ts +194 -44
- package/dist/shaka-player.compiled.debug.externs.js +474 -337
- package/dist/shaka-player.compiled.debug.js +949 -832
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +474 -337
- package/dist/shaka-player.compiled.js +1237 -1171
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +257 -47
- package/dist/shaka-player.ui.debug.d.ts +257 -47
- package/dist/shaka-player.ui.debug.externs.js +591 -376
- package/dist/shaka-player.ui.debug.js +1165 -965
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +591 -376
- package/dist/shaka-player.ui.js +1521 -1404
- package/dist/shaka-player.ui.map +4 -4
- package/externs/device_sensor_event.js +18 -0
- package/externs/hisense.js +16 -0
- package/externs/playstation.js +31 -0
- package/externs/shaka/abr_manager.js +3 -1
- package/externs/shaka/ads.js +5 -0
- package/externs/shaka/codecs.js +13 -0
- package/externs/shaka/manifest.js +58 -6
- package/externs/shaka/net.js +13 -1
- package/externs/shaka/player.js +184 -13
- package/externs/shaka/text.js +19 -0
- package/externs/tizen.js +41 -0
- package/externs/webos.js +19 -0
- package/externs/xbox.js +43 -0
- package/lib/abr/simple_abr_manager.js +9 -1
- package/lib/ads/ad_manager.js +19 -2
- package/lib/ads/client_side_ad_manager.js +5 -3
- package/lib/ads/media_tailor_ad_manager.js +9 -0
- package/lib/cast/cast_receiver.js +0 -14
- package/lib/cast/cast_utils.js +1 -0
- package/lib/cea/mp4_cea_parser.js +6 -1
- package/lib/dash/content_protection.js +97 -53
- package/lib/dash/dash_parser.js +230 -176
- package/lib/dash/mpd_utils.js +72 -65
- package/lib/dash/segment_base.js +27 -21
- package/lib/dash/segment_list.js +18 -16
- package/lib/dash/segment_template.js +26 -21
- package/lib/hls/hls_parser.js +358 -164
- package/lib/media/buffering_observer.js +25 -1
- package/lib/media/drm_engine.js +91 -71
- package/lib/media/manifest_filterer.js +220 -0
- package/lib/media/media_source_engine.js +34 -5
- package/lib/media/preload_manager.js +827 -0
- package/lib/media/presentation_timeline.js +11 -0
- package/lib/media/segment_index.js +40 -30
- package/lib/media/segment_prefetch.js +140 -43
- package/lib/media/segment_reference.js +31 -8
- package/lib/media/segment_utils.js +208 -25
- package/lib/media/streaming_engine.js +319 -63
- package/lib/mss/content_protection.js +31 -25
- package/lib/mss/mss_parser.js +74 -55
- package/lib/net/networking_engine.js +49 -4
- package/lib/offline/storage.js +3 -3
- package/lib/player.js +882 -673
- package/lib/polyfill/media_capabilities.js +16 -1
- package/lib/text/simple_text_displayer.js +9 -0
- package/lib/text/stub_text_displayer.js +7 -0
- package/lib/text/text_engine.js +16 -3
- package/lib/text/ttml_text_parser.js +116 -114
- package/lib/text/ui_text_displayer.js +28 -11
- package/lib/text/vtt_text_parser.js +54 -115
- package/lib/transmuxer/opus.js +91 -0
- package/lib/transmuxer/ts_transmuxer.js +115 -0
- package/lib/util/cmcd_manager.js +152 -3
- package/lib/util/dom_utils.js +11 -0
- package/lib/util/error.js +5 -0
- package/lib/util/fake_event.js +2 -0
- package/lib/util/manifest_parser_utils.js +97 -3
- package/lib/util/mp4_box_parsers.js +346 -17
- package/lib/util/mp4_generator.js +23 -0
- package/lib/util/periods.js +19 -0
- package/lib/util/platform.js +161 -9
- package/lib/util/player_configuration.js +61 -3
- package/lib/util/stats.js +16 -0
- package/lib/util/stream_utils.js +16 -6
- package/lib/util/string_utils.js +36 -0
- package/lib/util/tXml.js +814 -0
- package/lib/util/ts_parser.js +50 -0
- package/lib/util/xml_utils.js +10 -338
- package/package.json +2 -2
- package/shaka-player.uncompiled.js +8 -0
- package/ui/controls.js +187 -5
- package/ui/enums.js +2 -0
- package/ui/externs/ui.js +30 -3
- package/ui/gl_matrix/matrix_4x4.js +568 -0
- package/ui/gl_matrix/matrix_quaternion.js +45 -0
- package/ui/less/containers.less +11 -0
- package/ui/locales/en-GB.json +2 -0
- package/ui/locales/en.json +2 -0
- package/ui/locales/es-419.json +2 -0
- package/ui/locales/es.json +2 -0
- package/ui/locales/source.json +8 -0
- package/ui/recenter_vr.js +126 -0
- package/ui/resolution_selection.js +25 -5
- package/ui/statistics_button.js +12 -0
- package/ui/text_selection.js +1 -1
- package/ui/toggle_stereoscopic.js +127 -0
- package/ui/ui.js +74 -38
- package/ui/vr_manager.js +557 -0
- package/ui/vr_utils.js +232 -0
- package/ui/vr_webgl.js +697 -0
package/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.');
|
|
@@ -1508,7 +1547,7 @@ shaka.dash.DashParser = class {
|
|
|
1508
1547
|
}
|
|
1509
1548
|
|
|
1510
1549
|
const contentProtectionElems =
|
|
1511
|
-
|
|
1550
|
+
TXml.findChildren(node, 'ContentProtection');
|
|
1512
1551
|
const keyId = shaka.dash.ContentProtection.parseFromRepresentation(
|
|
1513
1552
|
contentProtectionElems, contentProtection,
|
|
1514
1553
|
this.config_.dash.ignoreDrmInfo,
|
|
@@ -1518,12 +1557,12 @@ shaka.dash.DashParser = class {
|
|
|
1518
1557
|
// Detect the presence of E-AC3 JOC audio content, using DD+JOC signaling.
|
|
1519
1558
|
// See: ETSI TS 103 420 V1.2.1 (2018-10)
|
|
1520
1559
|
const supplementalPropertyElems =
|
|
1521
|
-
|
|
1560
|
+
TXml.findChildren(node, 'SupplementalProperty');
|
|
1522
1561
|
const hasJoc = supplementalPropertyElems.some((element) => {
|
|
1523
1562
|
const expectedUri = 'tag:dolby.com,2018:dash:EC3_ExtensionType:2018';
|
|
1524
1563
|
const expectedValue = 'JOC';
|
|
1525
|
-
return element.
|
|
1526
|
-
element.
|
|
1564
|
+
return element.attributes['schemeIdUri'] == expectedUri &&
|
|
1565
|
+
element.attributes['value'] == expectedValue;
|
|
1527
1566
|
});
|
|
1528
1567
|
let spatialAudio = false;
|
|
1529
1568
|
if (hasJoc) {
|
|
@@ -1541,16 +1580,16 @@ shaka.dash.DashParser = class {
|
|
|
1541
1580
|
let tilesLayout;
|
|
1542
1581
|
if (isImage) {
|
|
1543
1582
|
const essentialPropertyElems =
|
|
1544
|
-
|
|
1583
|
+
TXml.findChildren(node, 'EssentialProperty');
|
|
1545
1584
|
const thumbnailTileElem = essentialPropertyElems.find((element) => {
|
|
1546
1585
|
const expectedUris = [
|
|
1547
1586
|
'http://dashif.org/thumbnail_tile',
|
|
1548
1587
|
'http://dashif.org/guidelines/thumbnail_tile',
|
|
1549
1588
|
];
|
|
1550
|
-
return expectedUris.includes(element.
|
|
1589
|
+
return expectedUris.includes(element.attributes['schemeIdUri']);
|
|
1551
1590
|
});
|
|
1552
1591
|
if (thumbnailTileElem) {
|
|
1553
|
-
tilesLayout = thumbnailTileElem.
|
|
1592
|
+
tilesLayout = thumbnailTileElem.attributes['value'];
|
|
1554
1593
|
}
|
|
1555
1594
|
// Filter image adaptation sets that has no tilesLayout.
|
|
1556
1595
|
if (!tilesLayout) {
|
|
@@ -1682,6 +1721,15 @@ shaka.dash.DashParser = class {
|
|
|
1682
1721
|
this.setUpdateTimer_(updateDelay);
|
|
1683
1722
|
}
|
|
1684
1723
|
|
|
1724
|
+
/**
|
|
1725
|
+
* Update now the manifest
|
|
1726
|
+
*
|
|
1727
|
+
* @private
|
|
1728
|
+
*/
|
|
1729
|
+
updateNow_() {
|
|
1730
|
+
this.updateTimer_.tickNow();
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1685
1733
|
/**
|
|
1686
1734
|
* Sets the update timer. Does nothing if the manifest does not specify an
|
|
1687
1735
|
* update period.
|
|
@@ -1698,9 +1746,13 @@ shaka.dash.DashParser = class {
|
|
|
1698
1746
|
if (this.updatePeriod_ < 0) {
|
|
1699
1747
|
return;
|
|
1700
1748
|
}
|
|
1749
|
+
let updateTime = this.updatePeriod_;
|
|
1750
|
+
if (this.config_.dash.updatePeriod >= 0) {
|
|
1751
|
+
updateTime = this.config_.dash.updatePeriod;
|
|
1752
|
+
}
|
|
1701
1753
|
|
|
1702
1754
|
const finalDelay = Math.max(
|
|
1703
|
-
|
|
1755
|
+
updateTime - offset,
|
|
1704
1756
|
this.averageUpdateDuration_.getEstimate());
|
|
1705
1757
|
|
|
1706
1758
|
// We do not run the timer as repeating because part of update is async and
|
|
@@ -1711,7 +1763,7 @@ shaka.dash.DashParser = class {
|
|
|
1711
1763
|
/**
|
|
1712
1764
|
* Creates a new inheritance frame for the given element.
|
|
1713
1765
|
*
|
|
1714
|
-
* @param {!
|
|
1766
|
+
* @param {!shaka.extern.xml.Node} elem
|
|
1715
1767
|
* @param {?shaka.dash.DashParser.InheritanceFrame} parent
|
|
1716
1768
|
* @param {?function():!Array.<string>} getBaseUris
|
|
1717
1769
|
* @return {shaka.dash.DashParser.InheritanceFrame}
|
|
@@ -1721,7 +1773,7 @@ shaka.dash.DashParser = class {
|
|
|
1721
1773
|
goog.asserts.assert(parent || getBaseUris,
|
|
1722
1774
|
'Must provide either parent or getBaseUris');
|
|
1723
1775
|
const ManifestParserUtils = shaka.util.ManifestParserUtils;
|
|
1724
|
-
const
|
|
1776
|
+
const TXml = shaka.util.TXml;
|
|
1725
1777
|
parent = parent || /** @type {shaka.dash.DashParser.InheritanceFrame} */ ({
|
|
1726
1778
|
contentType: '',
|
|
1727
1779
|
mimeType: '',
|
|
@@ -1736,17 +1788,17 @@ shaka.dash.DashParser = class {
|
|
|
1736
1788
|
});
|
|
1737
1789
|
getBaseUris = getBaseUris || parent.getBaseUris;
|
|
1738
1790
|
|
|
1739
|
-
const parseNumber =
|
|
1740
|
-
const evalDivision =
|
|
1791
|
+
const parseNumber = TXml.parseNonNegativeInt;
|
|
1792
|
+
const evalDivision = TXml.evalDivision;
|
|
1741
1793
|
|
|
1742
|
-
const id = elem.
|
|
1743
|
-
const uriObjs =
|
|
1794
|
+
const id = elem.attributes['id'];
|
|
1795
|
+
const uriObjs = TXml.findChildren(elem, 'BaseURL');
|
|
1744
1796
|
let calculatedBaseUris;
|
|
1745
1797
|
let someLocationValid = false;
|
|
1746
1798
|
if (this.contentSteeringManager_) {
|
|
1747
1799
|
for (const uriObj of uriObjs) {
|
|
1748
|
-
const serviceLocation = uriObj.
|
|
1749
|
-
const uri =
|
|
1800
|
+
const serviceLocation = uriObj.attributes['serviceLocation'];
|
|
1801
|
+
const uri = TXml.getContents(uriObj);
|
|
1750
1802
|
if (serviceLocation && uri) {
|
|
1751
1803
|
this.contentSteeringManager_.addLocation(
|
|
1752
1804
|
id, serviceLocation, uri);
|
|
@@ -1755,7 +1807,7 @@ shaka.dash.DashParser = class {
|
|
|
1755
1807
|
}
|
|
1756
1808
|
}
|
|
1757
1809
|
if (!someLocationValid || !this.contentSteeringManager_) {
|
|
1758
|
-
calculatedBaseUris = uriObjs.map(
|
|
1810
|
+
calculatedBaseUris = uriObjs.map(TXml.getContents);
|
|
1759
1811
|
}
|
|
1760
1812
|
|
|
1761
1813
|
const getFrameUris = () => {
|
|
@@ -1771,55 +1823,55 @@ shaka.dash.DashParser = class {
|
|
|
1771
1823
|
return [];
|
|
1772
1824
|
};
|
|
1773
1825
|
|
|
1774
|
-
let contentType = elem.
|
|
1775
|
-
const mimeType = elem.
|
|
1776
|
-
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;
|
|
1777
1829
|
const frameRate =
|
|
1778
|
-
|
|
1830
|
+
TXml.parseAttr(elem, 'frameRate', evalDivision) || parent.frameRate;
|
|
1779
1831
|
const pixelAspectRatio =
|
|
1780
|
-
elem.
|
|
1832
|
+
elem.attributes['sar'] || parent.pixelAspectRatio;
|
|
1781
1833
|
const emsgSchemeIdUris = this.emsgSchemeIdUris_(
|
|
1782
|
-
|
|
1834
|
+
TXml.findChildren(elem, 'InbandEventStream'),
|
|
1783
1835
|
parent.emsgSchemeIdUris);
|
|
1784
1836
|
const audioChannelConfigs =
|
|
1785
|
-
|
|
1837
|
+
TXml.findChildren(elem, 'AudioChannelConfiguration');
|
|
1786
1838
|
const numChannels =
|
|
1787
1839
|
this.parseAudioChannels_(audioChannelConfigs) || parent.numChannels;
|
|
1788
1840
|
const audioSamplingRate =
|
|
1789
|
-
|
|
1841
|
+
TXml.parseAttr(elem, 'audioSamplingRate', parseNumber) ||
|
|
1790
1842
|
parent.audioSamplingRate;
|
|
1791
1843
|
|
|
1792
1844
|
if (!contentType) {
|
|
1793
1845
|
contentType = shaka.dash.DashParser.guessContentType_(mimeType, codecs);
|
|
1794
1846
|
}
|
|
1795
1847
|
|
|
1796
|
-
const segmentBase =
|
|
1797
|
-
const segmentTemplate =
|
|
1848
|
+
const segmentBase = TXml.findChild(elem, 'SegmentBase');
|
|
1849
|
+
const segmentTemplate = TXml.findChild(elem, 'SegmentTemplate');
|
|
1798
1850
|
|
|
1799
1851
|
// The availabilityTimeOffset is the sum of all @availabilityTimeOffset
|
|
1800
1852
|
// values that apply to the adaptation set, via BaseURL, SegmentBase,
|
|
1801
1853
|
// or SegmentTemplate elements.
|
|
1802
1854
|
const segmentBaseAto = segmentBase ?
|
|
1803
|
-
(
|
|
1804
|
-
|
|
1855
|
+
(TXml.parseAttr(segmentBase, 'availabilityTimeOffset',
|
|
1856
|
+
TXml.parseFloat) || 0) : 0;
|
|
1805
1857
|
const segmentTemplateAto = segmentTemplate ?
|
|
1806
|
-
(
|
|
1807
|
-
|
|
1858
|
+
(TXml.parseAttr(segmentTemplate, 'availabilityTimeOffset',
|
|
1859
|
+
TXml.parseFloat) || 0) : 0;
|
|
1808
1860
|
const baseUriAto = uriObjs && uriObjs.length ?
|
|
1809
|
-
(
|
|
1810
|
-
|
|
1861
|
+
(TXml.parseAttr(uriObjs[0], 'availabilityTimeOffset',
|
|
1862
|
+
TXml.parseFloat) || 0) : 0;
|
|
1811
1863
|
|
|
1812
1864
|
const availabilityTimeOffset = parent.availabilityTimeOffset + baseUriAto +
|
|
1813
1865
|
segmentBaseAto + segmentTemplateAto;
|
|
1814
1866
|
|
|
1815
1867
|
let segmentSequenceCadence = null;
|
|
1816
1868
|
const segmentSequenceProperties =
|
|
1817
|
-
|
|
1869
|
+
TXml.findChild(elem, 'SegmentSequenceProperties');
|
|
1818
1870
|
if (segmentSequenceProperties) {
|
|
1819
|
-
const sap =
|
|
1871
|
+
const sap = TXml.findChild(segmentSequenceProperties, 'SAP');
|
|
1820
1872
|
if (sap) {
|
|
1821
|
-
segmentSequenceCadence =
|
|
1822
|
-
|
|
1873
|
+
segmentSequenceCadence = TXml.parseAttr(sap, 'cadence',
|
|
1874
|
+
TXml.parseInt);
|
|
1823
1875
|
}
|
|
1824
1876
|
}
|
|
1825
1877
|
|
|
@@ -1828,10 +1880,10 @@ shaka.dash.DashParser = class {
|
|
|
1828
1880
|
() => ManifestParserUtils.resolveUris(getBaseUris(), getFrameUris()),
|
|
1829
1881
|
segmentBase: segmentBase || parent.segmentBase,
|
|
1830
1882
|
segmentList:
|
|
1831
|
-
|
|
1883
|
+
TXml.findChild(elem, 'SegmentList') || parent.segmentList,
|
|
1832
1884
|
segmentTemplate: segmentTemplate || parent.segmentTemplate,
|
|
1833
|
-
width:
|
|
1834
|
-
height:
|
|
1885
|
+
width: TXml.parseAttr(elem, 'width', parseNumber) || parent.width,
|
|
1886
|
+
height: TXml.parseAttr(elem, 'height', parseNumber) || parent.height,
|
|
1835
1887
|
contentType: contentType,
|
|
1836
1888
|
mimeType: mimeType,
|
|
1837
1889
|
codecs: codecs,
|
|
@@ -1839,7 +1891,7 @@ shaka.dash.DashParser = class {
|
|
|
1839
1891
|
pixelAspectRatio: pixelAspectRatio,
|
|
1840
1892
|
emsgSchemeIdUris: emsgSchemeIdUris,
|
|
1841
1893
|
id: id,
|
|
1842
|
-
language: elem.
|
|
1894
|
+
language: elem.attributes['lang'],
|
|
1843
1895
|
numChannels: numChannels,
|
|
1844
1896
|
audioSamplingRate: audioSamplingRate,
|
|
1845
1897
|
availabilityTimeOffset: availabilityTimeOffset,
|
|
@@ -1853,7 +1905,8 @@ shaka.dash.DashParser = class {
|
|
|
1853
1905
|
* of the ones parsed from inBandEventStreams and the ones provided in
|
|
1854
1906
|
* emsgSchemeIdUris.
|
|
1855
1907
|
*
|
|
1856
|
-
* @param {!Array.<!
|
|
1908
|
+
* @param {!Array.<!shaka.extern.xml.Node>} inBandEventStreams
|
|
1909
|
+
* Array of InbandEventStream
|
|
1857
1910
|
* elements to parse and add to the returned array.
|
|
1858
1911
|
* @param {!Array.<string>} emsgSchemeIdUris Array of parsed
|
|
1859
1912
|
* InbandEventStream schemeIdUri attributes to add to the returned array.
|
|
@@ -1864,7 +1917,7 @@ shaka.dash.DashParser = class {
|
|
|
1864
1917
|
emsgSchemeIdUris_(inBandEventStreams, emsgSchemeIdUris) {
|
|
1865
1918
|
const schemeIdUris = emsgSchemeIdUris.slice();
|
|
1866
1919
|
for (const event of inBandEventStreams) {
|
|
1867
|
-
const schemeIdUri = event.
|
|
1920
|
+
const schemeIdUri = event.attributes['schemeIdUri'];
|
|
1868
1921
|
if (!schemeIdUris.includes(schemeIdUri)) {
|
|
1869
1922
|
schemeIdUris.push(schemeIdUri);
|
|
1870
1923
|
}
|
|
@@ -1873,19 +1926,19 @@ shaka.dash.DashParser = class {
|
|
|
1873
1926
|
}
|
|
1874
1927
|
|
|
1875
1928
|
/**
|
|
1876
|
-
* @param {!Array.<!
|
|
1929
|
+
* @param {!Array.<!shaka.extern.xml.Node>} audioChannelConfigs An array of
|
|
1877
1930
|
* AudioChannelConfiguration elements.
|
|
1878
1931
|
* @return {?number} The number of audio channels, or null if unknown.
|
|
1879
1932
|
* @private
|
|
1880
1933
|
*/
|
|
1881
1934
|
parseAudioChannels_(audioChannelConfigs) {
|
|
1882
1935
|
for (const elem of audioChannelConfigs) {
|
|
1883
|
-
const scheme = elem.
|
|
1936
|
+
const scheme = elem.attributes['schemeIdUri'];
|
|
1884
1937
|
if (!scheme) {
|
|
1885
1938
|
continue;
|
|
1886
1939
|
}
|
|
1887
1940
|
|
|
1888
|
-
const value = elem.
|
|
1941
|
+
const value = elem.attributes['value'];
|
|
1889
1942
|
if (!value) {
|
|
1890
1943
|
continue;
|
|
1891
1944
|
}
|
|
@@ -2056,15 +2109,15 @@ shaka.dash.DashParser = class {
|
|
|
2056
2109
|
* Parses an array of UTCTiming elements.
|
|
2057
2110
|
*
|
|
2058
2111
|
* @param {function():!Array.<string>} getBaseUris
|
|
2059
|
-
* @param {!Array.<!
|
|
2112
|
+
* @param {!Array.<!shaka.extern.xml.Node>} elems
|
|
2060
2113
|
* @return {!Promise.<number>}
|
|
2061
2114
|
* @private
|
|
2062
2115
|
*/
|
|
2063
2116
|
async parseUtcTiming_(getBaseUris, elems) {
|
|
2064
2117
|
const schemesAndValues = elems.map((elem) => {
|
|
2065
2118
|
return {
|
|
2066
|
-
scheme: elem.
|
|
2067
|
-
value: elem.
|
|
2119
|
+
scheme: elem.attributes['schemeIdUri'],
|
|
2120
|
+
value: elem.attributes['value'],
|
|
2068
2121
|
};
|
|
2069
2122
|
});
|
|
2070
2123
|
|
|
@@ -2128,23 +2181,23 @@ shaka.dash.DashParser = class {
|
|
|
2128
2181
|
*
|
|
2129
2182
|
* @param {number} periodStart
|
|
2130
2183
|
* @param {?number} periodDuration
|
|
2131
|
-
* @param {!
|
|
2184
|
+
* @param {!shaka.extern.xml.Node} elem
|
|
2132
2185
|
* @param {number} availabilityStart
|
|
2133
2186
|
* @private
|
|
2134
2187
|
*/
|
|
2135
2188
|
parseEventStream_(periodStart, periodDuration, elem, availabilityStart) {
|
|
2136
|
-
const
|
|
2137
|
-
const parseNumber =
|
|
2189
|
+
const TXml = shaka.util.TXml;
|
|
2190
|
+
const parseNumber = shaka.util.TXml.parseNonNegativeInt;
|
|
2138
2191
|
|
|
2139
|
-
const schemeIdUri = elem.
|
|
2140
|
-
const value = elem.
|
|
2141
|
-
const timescale =
|
|
2192
|
+
const schemeIdUri = elem.attributes['schemeIdUri'] || '';
|
|
2193
|
+
const value = elem.attributes['value'] || '';
|
|
2194
|
+
const timescale = TXml.parseAttr(elem, 'timescale', parseNumber) || 1;
|
|
2142
2195
|
|
|
2143
|
-
for (const eventNode of
|
|
2196
|
+
for (const eventNode of TXml.findChildren(elem, 'Event')) {
|
|
2144
2197
|
const presentationTime =
|
|
2145
|
-
|
|
2198
|
+
TXml.parseAttr(eventNode, 'presentationTime', parseNumber) || 0;
|
|
2146
2199
|
const duration =
|
|
2147
|
-
|
|
2200
|
+
TXml.parseAttr(eventNode, 'duration', parseNumber) || 0;
|
|
2148
2201
|
|
|
2149
2202
|
let startTime = presentationTime / timescale + periodStart;
|
|
2150
2203
|
let endTime = startTime + (duration / timescale);
|
|
@@ -2166,8 +2219,9 @@ shaka.dash.DashParser = class {
|
|
|
2166
2219
|
value: value,
|
|
2167
2220
|
startTime: startTime,
|
|
2168
2221
|
endTime: endTime,
|
|
2169
|
-
id: eventNode.
|
|
2170
|
-
eventElement: eventNode,
|
|
2222
|
+
id: eventNode.attributes['id'] || '',
|
|
2223
|
+
eventElement: TXml.txmlNodeToDomElement(eventNode),
|
|
2224
|
+
eventNode: eventNode,
|
|
2171
2225
|
};
|
|
2172
2226
|
|
|
2173
2227
|
this.playerInterface_.onTimelineRegionAdded(region);
|
|
@@ -2255,9 +2309,9 @@ shaka.dash.DashParser.RequestSegmentCallback;
|
|
|
2255
2309
|
|
|
2256
2310
|
/**
|
|
2257
2311
|
* @typedef {{
|
|
2258
|
-
* segmentBase:
|
|
2259
|
-
* segmentList:
|
|
2260
|
-
* segmentTemplate:
|
|
2312
|
+
* segmentBase: ?shaka.extern.xml.Node,
|
|
2313
|
+
* segmentList: ?shaka.extern.xml.Node,
|
|
2314
|
+
* segmentTemplate: ?shaka.extern.xml.Node,
|
|
2261
2315
|
* getBaseUris: function():!Array.<string>,
|
|
2262
2316
|
* width: (number|undefined),
|
|
2263
2317
|
* height: (number|undefined),
|
|
@@ -2279,11 +2333,11 @@ shaka.dash.DashParser.RequestSegmentCallback;
|
|
|
2279
2333
|
* A collection of elements and properties which are inherited across levels
|
|
2280
2334
|
* of a DASH manifest.
|
|
2281
2335
|
*
|
|
2282
|
-
* @property {
|
|
2336
|
+
* @property {?shaka.extern.xml.Node} segmentBase
|
|
2283
2337
|
* The XML node for SegmentBase.
|
|
2284
|
-
* @property {
|
|
2338
|
+
* @property {?shaka.extern.xml.Node} segmentList
|
|
2285
2339
|
* The XML node for SegmentList.
|
|
2286
|
-
* @property {
|
|
2340
|
+
* @property {?shaka.extern.xml.Node} segmentTemplate
|
|
2287
2341
|
* The XML node for SegmentTemplate.
|
|
2288
2342
|
* @property {function():!Array.<string>} getBaseUris
|
|
2289
2343
|
* Function than returns an array of absolute base URIs for the frame.
|
|
@@ -2368,7 +2422,7 @@ shaka.dash.DashParser.Context;
|
|
|
2368
2422
|
* @typedef {{
|
|
2369
2423
|
* start: number,
|
|
2370
2424
|
* duration: ?number,
|
|
2371
|
-
* node: !
|
|
2425
|
+
* node: !shaka.extern.xml.Node,
|
|
2372
2426
|
* isLastPeriod: boolean
|
|
2373
2427
|
* }}
|
|
2374
2428
|
*
|
|
@@ -2380,7 +2434,7 @@ shaka.dash.DashParser.Context;
|
|
|
2380
2434
|
* @property {?number} duration
|
|
2381
2435
|
* The duration of the period; or null if the duration is not given. This
|
|
2382
2436
|
* will be non-null for all periods except the last.
|
|
2383
|
-
* @property {!
|
|
2437
|
+
* @property {!shaka.extern.xml.Node} node
|
|
2384
2438
|
* The XML Node for the Period.
|
|
2385
2439
|
* @property {boolean} isLastPeriod
|
|
2386
2440
|
* Whether this Period is the last one in the manifest.
|