shaka-player 4.5.0 → 4.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
- package/AUTHORS +2 -0
- package/CHANGELOG.md +109 -0
- package/CODE_OF_CONDUCT.md +1 -1
- package/CONTRIBUTORS +2 -0
- package/README.md +38 -32
- package/demo/common/asset.js +11 -17
- package/demo/common/assets.js +117 -11
- package/demo/config.js +28 -1
- package/demo/custom.js +52 -38
- package/demo/main.js +11 -3
- package/demo/search.js +7 -0
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +133 -124
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +133 -124
- package/dist/demo.compiled.map +3 -3
- package/dist/deps.js +20 -18
- package/dist/locales.js +34 -30
- package/dist/receiver.compiled.debug.js +58 -50
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +58 -50
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +440 -390
- package/dist/shaka-player.compiled.debug.d.ts +440 -390
- package/dist/shaka-player.compiled.debug.externs.js +162 -77
- package/dist/shaka-player.compiled.debug.js +789 -738
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +162 -77
- package/dist/shaka-player.compiled.js +1147 -1113
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +491 -437
- package/dist/shaka-player.ui.debug.d.ts +491 -437
- package/dist/shaka-player.ui.debug.externs.js +167 -77
- package/dist/shaka-player.ui.debug.js +857 -791
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +167 -77
- package/dist/shaka-player.ui.js +1359 -1314
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/ad_monetization.md +54 -0
- package/docs/tutorials/basic-usage.md +2 -1
- package/docs/tutorials/errors.md +2 -1
- package/docs/tutorials/offline.md +10 -8
- package/docs/tutorials/plugins.md +5 -0
- package/docs/tutorials/ui-customization.md +13 -0
- package/docs/tutorials/ui.md +2 -1
- package/docs/tutorials/upgrade.md +3 -0
- package/externs/managedmediasource.js +24 -0
- package/externs/shaka/abr_manager.js +6 -2
- package/externs/shaka/cea.js +7 -0
- package/externs/shaka/codecs.js +5 -3
- package/externs/shaka/manifest.js +21 -5
- package/externs/shaka/manifest_parser.js +17 -0
- package/externs/shaka/net.js +2 -2
- package/externs/shaka/offline.js +9 -2
- package/externs/shaka/player.js +53 -7
- package/externs/shaka/text.js +3 -1
- package/externs/shaka/transmuxer.js +1 -1
- package/lib/abr/simple_abr_manager.js +25 -8
- package/lib/ads/media_tailor_ad_manager.js +14 -3
- package/lib/cast/cast_receiver.js +1 -1
- package/lib/cea/cea_decoder.js +28 -0
- package/lib/cea/dummy_caption_decoder.js +5 -0
- package/lib/dash/dash_parser.js +251 -84
- package/lib/dash/mpd_utils.js +52 -31
- package/lib/dash/segment_base.js +4 -5
- package/lib/dash/segment_list.js +5 -4
- package/lib/dash/segment_template.js +92 -29
- package/lib/hls/hls_classes.js +28 -43
- package/lib/hls/hls_parser.js +770 -652
- package/lib/hls/hls_utils.js +64 -5
- package/lib/hls/manifest_text_parser.js +7 -11
- package/lib/media/adaptation_set.js +20 -13
- package/lib/media/adaptation_set_criteria.js +70 -18
- package/lib/media/closed_caption_parser.js +13 -0
- package/lib/media/content_workarounds.js +6 -0
- package/lib/media/drm_engine.js +8 -13
- package/lib/media/manifest_parser.js +8 -113
- package/lib/media/media_source_capabilities.js +10 -3
- package/lib/media/media_source_engine.js +75 -21
- package/lib/media/play_rate_controller.js +8 -38
- package/lib/media/presentation_timeline.js +7 -1
- package/lib/media/quality_observer.js +1 -1
- package/lib/media/segment_index.js +5 -5
- package/lib/media/segment_prefetch.js +92 -24
- package/lib/media/segment_reference.js +67 -1
- package/lib/media/segment_utils.js +343 -0
- package/lib/media/stall_detector.js +0 -3
- package/lib/media/streaming_engine.js +72 -44
- package/lib/mss/mss_parser.js +18 -2
- package/lib/net/networking_engine.js +66 -12
- package/lib/net/networking_utils.js +95 -0
- 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 +2 -0
- package/lib/offline/offline_manifest_parser.js +10 -0
- package/lib/offline/storage.js +11 -7
- package/lib/player.js +998 -1503
- package/lib/polyfill/mediasource.js +22 -1
- package/lib/text/mp4_ttml_parser.js +2 -2
- package/lib/text/srt_text_parser.js +2 -2
- package/lib/text/stub_text_displayer.js +51 -0
- package/lib/text/text_engine.js +3 -2
- package/lib/text/ttml_text_parser.js +28 -5
- package/lib/text/ui_text_displayer.js +4 -0
- package/lib/text/vtt_text_parser.js +7 -2
- package/lib/transmuxer/aac_transmuxer.js +1 -1
- package/lib/transmuxer/ac3_transmuxer.js +1 -1
- package/lib/transmuxer/ec3_transmuxer.js +1 -1
- package/lib/transmuxer/h264.js +5 -4
- package/lib/transmuxer/h265.js +5 -4
- package/lib/transmuxer/mp3_transmuxer.js +1 -1
- package/lib/transmuxer/mpeg_ts_transmuxer.js +1 -1
- package/lib/transmuxer/mss_transmuxer.js +1 -1
- package/lib/transmuxer/ts_transmuxer.js +33 -13
- package/lib/util/buffer_utils.js +26 -4
- package/lib/util/content_steering_manager.js +358 -0
- package/lib/util/error.js +2 -6
- package/lib/util/fairplay_utils.js +1 -1
- package/lib/util/fake_event.js +5 -1
- package/lib/util/id3_utils.js +50 -1
- package/lib/util/manifest_parser_utils.js +12 -8
- package/lib/util/mp4_generator.js +2 -4
- package/lib/util/mutex.js +59 -0
- package/lib/util/object_utils.js +1 -1
- package/lib/util/periods.js +154 -179
- package/lib/util/platform.js +4 -3
- package/lib/util/player_configuration.js +35 -6
- package/lib/util/stream_utils.js +105 -98
- package/lib/util/ts_parser.js +124 -73
- package/lib/util/uint8array_utils.js +5 -1
- package/lib/util/xml_utils.js +5 -0
- package/maintained-branches.md +2 -2
- package/package.json +1 -1
- package/roadmap.md +15 -5
- package/shaka-player.uncompiled.js +0 -1
- package/test/abr/simple_abr_manager_unit.js +33 -33
- package/test/ads/ad_manager_unit.js +3 -2
- package/test/cast/cast_receiver_integration.js +3 -4
- package/test/cast/cast_utils_unit.js +2 -0
- package/test/cea/cea_decoder_unit.js +7 -0
- package/test/codec_switching/codec_switching_integration.js +2 -1
- package/test/dash/dash_parser_integration.js +2 -1
- package/test/dash/dash_parser_live_unit.js +0 -19
- package/test/dash/dash_parser_manifest_unit.js +494 -2
- package/test/dash/mpd_utils_unit.js +61 -30
- package/test/hls/hls_live_unit.js +12 -3
- package/test/hls/hls_parser_unit.js +417 -27
- package/test/hls/manifest_text_parser_unit.js +32 -99
- package/test/media/adaptation_set_criteria_unit.js +172 -21
- package/test/media/adaptation_set_unit.js +1 -0
- package/test/media/content_workarounds_unit.js +1 -1
- package/test/media/drm_engine_unit.js +3 -3
- package/test/media/media_source_engine_unit.js +1 -1
- package/test/media/play_rate_controller_unit.js +0 -48
- package/test/media/segment_index_unit.js +2 -1
- package/test/mss/mss_player_integration.js +3 -2
- package/test/net/networking_engine_unit.js +3 -3
- package/test/{media/manifest_parser_unit.js → net/networking_utils_unit.js} +2 -2
- package/test/offline/manifest_convert_unit.js +9 -0
- package/test/offline/offline_integration.js +2 -1
- package/test/offline/storage_integration.js +21 -9
- package/test/player_external.js +4 -2
- package/test/player_integration.js +15 -4
- package/test/player_load_graph_integration.js +47 -151
- package/test/player_src_equals_external.js +1 -0
- package/test/player_src_equals_integration.js +71 -4
- package/test/player_unit.js +80 -27
- package/test/test/util/fake_media_source_engine.js +5 -0
- package/test/test/util/fake_networking_engine.js +9 -1
- package/test/test/util/fake_segment_prefetch.js +3 -0
- package/test/test/util/manifest_generator.js +4 -0
- package/test/test/util/manifest_parser_util.js +14 -2
- package/test/test/util/offline_utils.js +1 -0
- package/test/test/util/simple_fakes.js +2 -2
- package/test/test/util/streaming_engine_util.js +3 -0
- package/test/test/util/test_scheme.js +6 -0
- package/test/test/util/ui_utils.js +4 -3
- package/test/text/mp4_ttml_parser_unit.js +4 -4
- package/test/text/srt_text_parser_unit.js +1 -1
- package/test/text/text_displayer_layout_unit.js +1 -1
- package/test/text/text_engine_unit.js +6 -0
- package/test/text/ttml_text_parser_unit.js +33 -2
- package/test/transmuxer/transmuxer_engine_integration.js +9 -0
- package/test/transmuxer/transmuxer_integration.js +33 -3
- package/test/ui/ad_ui_unit.js +2 -2
- package/test/ui/ui_customization_unit.js +17 -16
- package/test/ui/ui_integration.js +30 -20
- package/test/ui/ui_unit.js +25 -19
- package/test/util/buffer_utils_unit.js +1 -1
- package/test/util/content_steering_manager_unit.js +427 -0
- package/test/util/id3_utils_unit.js +52 -0
- package/test/util/stream_utils_unit.js +17 -113
- package/test/util/ts_parser_unit.js +3 -3
- package/third_party/closure-uri/uri.js +13 -1
- package/ui/audio_language_selection.js +9 -2
- package/ui/externs/ui.js +17 -2
- package/ui/language_utils.js +43 -8
- package/ui/less/range_elements.less +33 -0
- package/ui/locales/en.json +1 -0
- package/ui/locales/es-419.json +1 -0
- package/ui/locales/es.json +1 -0
- package/ui/locales/source.json +4 -0
- package/ui/localization.js +10 -0
- package/ui/remote_button.js +3 -1
- package/ui/resolution_selection.js +47 -10
- package/ui/seek_bar.js +296 -3
- package/ui/text_selection.js +2 -1
- package/ui/ui.js +6 -2
- package/lib/routing/node.js +0 -23
- package/lib/routing/payload.js +0 -47
- package/lib/routing/walker.js +0 -587
- package/test/routing/walker_unit.js +0 -505
package/lib/dash/dash_parser.js
CHANGED
|
@@ -19,6 +19,7 @@ goog.require('shaka.media.PresentationTimeline');
|
|
|
19
19
|
goog.require('shaka.media.SegmentIndex');
|
|
20
20
|
goog.require('shaka.net.NetworkingEngine');
|
|
21
21
|
goog.require('shaka.text.TextEngine');
|
|
22
|
+
goog.require('shaka.util.ContentSteeringManager');
|
|
22
23
|
goog.require('shaka.util.Error');
|
|
23
24
|
goog.require('shaka.util.Functional');
|
|
24
25
|
goog.require('shaka.util.LanguageUtils');
|
|
@@ -115,6 +116,9 @@ shaka.dash.DashParser = class {
|
|
|
115
116
|
|
|
116
117
|
/** @private {boolean} */
|
|
117
118
|
this.lowLatencyMode_ = false;
|
|
119
|
+
|
|
120
|
+
/** @private {?shaka.util.ContentSteeringManager} */
|
|
121
|
+
this.contentSteeringManager_ = null;
|
|
118
122
|
}
|
|
119
123
|
|
|
120
124
|
/**
|
|
@@ -126,6 +130,10 @@ shaka.dash.DashParser = class {
|
|
|
126
130
|
'DashManifestConfiguration should not be null!');
|
|
127
131
|
|
|
128
132
|
this.config_ = config;
|
|
133
|
+
|
|
134
|
+
if (this.contentSteeringManager_) {
|
|
135
|
+
this.contentSteeringManager_.configure(this.config_);
|
|
136
|
+
}
|
|
129
137
|
}
|
|
130
138
|
|
|
131
139
|
/**
|
|
@@ -185,6 +193,10 @@ shaka.dash.DashParser = class {
|
|
|
185
193
|
this.updateTimer_ = null;
|
|
186
194
|
}
|
|
187
195
|
|
|
196
|
+
if (this.contentSteeringManager_) {
|
|
197
|
+
this.contentSteeringManager_.destroy();
|
|
198
|
+
}
|
|
199
|
+
|
|
188
200
|
return this.operationManager_.destroy();
|
|
189
201
|
}
|
|
190
202
|
|
|
@@ -212,6 +224,43 @@ shaka.dash.DashParser = class {
|
|
|
212
224
|
// No-op
|
|
213
225
|
}
|
|
214
226
|
|
|
227
|
+
/**
|
|
228
|
+
* @override
|
|
229
|
+
* @exportInterface
|
|
230
|
+
*/
|
|
231
|
+
onInitialVariantChosen(variant) {
|
|
232
|
+
// For live it is necessary that the first time we update the manifest with
|
|
233
|
+
// a shorter time than indicated to take into account that the last segment
|
|
234
|
+
// added could be halfway, for example
|
|
235
|
+
if (this.manifest_ && this.manifest_.presentationTimeline.isLive()) {
|
|
236
|
+
const stream = variant.video || variant.audio;
|
|
237
|
+
if (stream && stream.segmentIndex) {
|
|
238
|
+
const availabilityEnd =
|
|
239
|
+
this.manifest_.presentationTimeline.getSegmentAvailabilityEnd();
|
|
240
|
+
const position = stream.segmentIndex.find(availabilityEnd);
|
|
241
|
+
if (position == null) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const reference = stream.segmentIndex.get(position);
|
|
245
|
+
if (!reference) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
this.updatePeriod_ = reference.endTime - availabilityEnd;
|
|
249
|
+
this.setUpdateTimer_(/* offset= */ 0);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* @override
|
|
256
|
+
* @exportInterface
|
|
257
|
+
*/
|
|
258
|
+
banLocation(uri) {
|
|
259
|
+
if (this.contentSteeringManager_) {
|
|
260
|
+
this.contentSteeringManager_.banLocation(uri);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
215
264
|
/**
|
|
216
265
|
* Makes a network request for the manifest and parses the resulting data.
|
|
217
266
|
*
|
|
@@ -236,7 +285,8 @@ shaka.dash.DashParser = class {
|
|
|
236
285
|
|
|
237
286
|
// For redirections add the response uri to the first entry in the
|
|
238
287
|
// Manifest Uris array.
|
|
239
|
-
if (response.uri &&
|
|
288
|
+
if (response.uri && response.uri != response.originalUri &&
|
|
289
|
+
!this.manifestUris_.includes(response.uri)) {
|
|
240
290
|
this.manifestUris_.unshift(response.uri);
|
|
241
291
|
}
|
|
242
292
|
|
|
@@ -320,10 +370,68 @@ shaka.dash.DashParser = class {
|
|
|
320
370
|
manifestBaseUris = absoluteLocations;
|
|
321
371
|
}
|
|
322
372
|
|
|
373
|
+
let contentSteeringPromise = Promise.resolve();
|
|
374
|
+
|
|
375
|
+
const contentSteering = XmlUtils.findChild(mpd, 'ContentSteering');
|
|
376
|
+
if (contentSteering && this.playerInterface_) {
|
|
377
|
+
const defaultPathwayId =
|
|
378
|
+
contentSteering.getAttribute('defaultServiceLocation');
|
|
379
|
+
if (!this.contentSteeringManager_) {
|
|
380
|
+
this.contentSteeringManager_ =
|
|
381
|
+
new shaka.util.ContentSteeringManager(this.playerInterface_);
|
|
382
|
+
this.contentSteeringManager_.configure(this.config_);
|
|
383
|
+
this.contentSteeringManager_.setManifestType(
|
|
384
|
+
shaka.media.ManifestParser.DASH);
|
|
385
|
+
this.contentSteeringManager_.setBaseUris(manifestBaseUris);
|
|
386
|
+
this.contentSteeringManager_.setDefaultPathwayId(defaultPathwayId);
|
|
387
|
+
const uri = XmlUtils.getContents(contentSteering);
|
|
388
|
+
if (uri) {
|
|
389
|
+
const queryBeforeStart =
|
|
390
|
+
XmlUtils.parseAttr(contentSteering, 'queryBeforeStart',
|
|
391
|
+
XmlUtils.parseBoolean, /* defaultValue= */ false);
|
|
392
|
+
if (queryBeforeStart) {
|
|
393
|
+
contentSteeringPromise =
|
|
394
|
+
this.contentSteeringManager_.requestInfo(uri);
|
|
395
|
+
} else {
|
|
396
|
+
this.contentSteeringManager_.requestInfo(uri);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
} else {
|
|
400
|
+
this.contentSteeringManager_.setBaseUris(manifestBaseUris);
|
|
401
|
+
this.contentSteeringManager_.setDefaultPathwayId(defaultPathwayId);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
323
405
|
const uriObjs = XmlUtils.findChildren(mpd, 'BaseURL');
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
406
|
+
let calculatedBaseUris;
|
|
407
|
+
let someLocationValid = false;
|
|
408
|
+
if (this.contentSteeringManager_) {
|
|
409
|
+
this.contentSteeringManager_.clearPreviousLocations();
|
|
410
|
+
for (const uriObj of uriObjs) {
|
|
411
|
+
const serviceLocation = uriObj.getAttribute('serviceLocation');
|
|
412
|
+
const uri = XmlUtils.getContents(uriObj);
|
|
413
|
+
if (serviceLocation && uri) {
|
|
414
|
+
this.contentSteeringManager_.addLocation(
|
|
415
|
+
'BaseURL', serviceLocation, uri);
|
|
416
|
+
someLocationValid = true;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
if (!someLocationValid || !this.contentSteeringManager_) {
|
|
421
|
+
const uris = uriObjs.map(XmlUtils.getContents);
|
|
422
|
+
calculatedBaseUris = shaka.util.ManifestParserUtils.resolveUris(
|
|
423
|
+
manifestBaseUris, uris);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const getBaseUris = () => {
|
|
427
|
+
if (this.contentSteeringManager_ && someLocationValid) {
|
|
428
|
+
return this.contentSteeringManager_.getLocations('BaseURL');
|
|
429
|
+
}
|
|
430
|
+
if (calculatedBaseUris) {
|
|
431
|
+
return calculatedBaseUris;
|
|
432
|
+
}
|
|
433
|
+
return [];
|
|
434
|
+
};
|
|
327
435
|
|
|
328
436
|
let availabilityTimeOffset = 0;
|
|
329
437
|
if (uriObjs && uriObjs.length) {
|
|
@@ -439,7 +547,7 @@ shaka.dash.DashParser = class {
|
|
|
439
547
|
profiles: profiles.split(','),
|
|
440
548
|
};
|
|
441
549
|
|
|
442
|
-
const periodsAndDuration = this.parsePeriods_(context,
|
|
550
|
+
const periodsAndDuration = this.parsePeriods_(context, getBaseUris, mpd);
|
|
443
551
|
const duration = periodsAndDuration.duration;
|
|
444
552
|
const periods = periodsAndDuration.periods;
|
|
445
553
|
|
|
@@ -483,18 +591,14 @@ shaka.dash.DashParser = class {
|
|
|
483
591
|
|
|
484
592
|
await this.periodCombiner_.combinePeriods(periods, context.dynamic);
|
|
485
593
|
|
|
594
|
+
await contentSteeringPromise;
|
|
595
|
+
|
|
486
596
|
// Set minBufferTime to 0 for low-latency DASH live stream to achieve the
|
|
487
597
|
// best latency
|
|
488
598
|
if (this.lowLatencyMode_) {
|
|
489
599
|
minBufferTime = 0;
|
|
490
600
|
}
|
|
491
601
|
|
|
492
|
-
// Set updatePeriod_ to minTotalAvailabilityTimeOffset_ to achieve the best
|
|
493
|
-
// latency in LL streams
|
|
494
|
-
if (this.lowLatencyMode_ && this.minTotalAvailabilityTimeOffset_) {
|
|
495
|
-
this.updatePeriod_ = this.minTotalAvailabilityTimeOffset_;
|
|
496
|
-
}
|
|
497
|
-
|
|
498
602
|
// These steps are not done on manifest update.
|
|
499
603
|
if (!this.manifest_) {
|
|
500
604
|
this.manifest_ = {
|
|
@@ -515,7 +619,7 @@ shaka.dash.DashParser = class {
|
|
|
515
619
|
if (presentationTimeline.usingPresentationStartTime()) {
|
|
516
620
|
const XmlUtils = shaka.util.XmlUtils;
|
|
517
621
|
const timingElements = XmlUtils.findChildren(mpd, 'UTCTiming');
|
|
518
|
-
const offset = await this.parseUtcTiming_(
|
|
622
|
+
const offset = await this.parseUtcTiming_(getBaseUris, timingElements);
|
|
519
623
|
// Detect calls to stop().
|
|
520
624
|
if (!this.playerInterface_) {
|
|
521
625
|
return;
|
|
@@ -575,8 +679,19 @@ shaka.dash.DashParser = class {
|
|
|
575
679
|
const maxPlaybackRate = playbackRateNode ?
|
|
576
680
|
parseFloat(playbackRateNode.getAttribute('max')) :
|
|
577
681
|
null;
|
|
682
|
+
const minLatency = latencyNode && latencyNode.getAttribute('min') ?
|
|
683
|
+
parseInt(latencyNode.getAttribute('min'), 10) / 1000 :
|
|
684
|
+
null;
|
|
685
|
+
const minPlaybackRate = playbackRateNode ?
|
|
686
|
+
parseFloat(playbackRateNode.getAttribute('min')) :
|
|
687
|
+
null;
|
|
578
688
|
|
|
579
|
-
return {
|
|
689
|
+
return {
|
|
690
|
+
maxLatency,
|
|
691
|
+
maxPlaybackRate,
|
|
692
|
+
minLatency,
|
|
693
|
+
minPlaybackRate,
|
|
694
|
+
};
|
|
580
695
|
}
|
|
581
696
|
|
|
582
697
|
return null;
|
|
@@ -588,7 +703,7 @@ shaka.dash.DashParser = class {
|
|
|
588
703
|
* children.
|
|
589
704
|
*
|
|
590
705
|
* @param {shaka.dash.DashParser.Context} context
|
|
591
|
-
* @param {
|
|
706
|
+
* @param {function():!Array.<string>} getBaseUris
|
|
592
707
|
* @param {!Element} mpd
|
|
593
708
|
* @return {{
|
|
594
709
|
* periods: !Array.<shaka.extern.Period>,
|
|
@@ -597,7 +712,7 @@ shaka.dash.DashParser = class {
|
|
|
597
712
|
* }}
|
|
598
713
|
* @private
|
|
599
714
|
*/
|
|
600
|
-
parsePeriods_(context,
|
|
715
|
+
parsePeriods_(context, getBaseUris, mpd) {
|
|
601
716
|
const XmlUtils = shaka.util.XmlUtils;
|
|
602
717
|
const presentationDuration = XmlUtils.parseAttr(
|
|
603
718
|
mpd, 'mediaPresentationDuration', XmlUtils.parseDuration);
|
|
@@ -687,7 +802,7 @@ shaka.dash.DashParser = class {
|
|
|
687
802
|
node: elem,
|
|
688
803
|
isLastPeriod: periodDuration == null || !next,
|
|
689
804
|
};
|
|
690
|
-
const period = this.parsePeriod_(context,
|
|
805
|
+
const period = this.parsePeriod_(context, getBaseUris, info);
|
|
691
806
|
periods.push(period);
|
|
692
807
|
|
|
693
808
|
if (context.period.id && periodDuration) {
|
|
@@ -741,17 +856,17 @@ shaka.dash.DashParser = class {
|
|
|
741
856
|
* was done before this was called so start and duration are valid.
|
|
742
857
|
*
|
|
743
858
|
* @param {shaka.dash.DashParser.Context} context
|
|
744
|
-
* @param {
|
|
859
|
+
* @param {function():!Array.<string>} getBaseUris
|
|
745
860
|
* @param {shaka.dash.DashParser.PeriodInfo} periodInfo
|
|
746
861
|
* @return {shaka.extern.Period}
|
|
747
862
|
* @private
|
|
748
863
|
*/
|
|
749
|
-
parsePeriod_(context,
|
|
864
|
+
parsePeriod_(context, getBaseUris, periodInfo) {
|
|
750
865
|
const Functional = shaka.util.Functional;
|
|
751
866
|
const XmlUtils = shaka.util.XmlUtils;
|
|
752
867
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
753
868
|
|
|
754
|
-
context.period = this.createFrame_(periodInfo.node, null,
|
|
869
|
+
context.period = this.createFrame_(periodInfo.node, null, getBaseUris);
|
|
755
870
|
context.periodInfo = periodInfo;
|
|
756
871
|
context.period.availabilityTimeOffset = context.availabilityTimeOffset;
|
|
757
872
|
|
|
@@ -822,40 +937,29 @@ shaka.dash.DashParser = class {
|
|
|
822
937
|
}
|
|
823
938
|
}
|
|
824
939
|
|
|
825
|
-
const
|
|
826
|
-
this.
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
const
|
|
830
|
-
this.
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
940
|
+
const audioStreams = this.getStreamsFromSets_(
|
|
941
|
+
this.config_.disableAudio,
|
|
942
|
+
normalAdaptationSets,
|
|
943
|
+
ContentType.AUDIO);
|
|
944
|
+
const videoStreams = this.getStreamsFromSets_(
|
|
945
|
+
this.config_.disableVideo,
|
|
946
|
+
normalAdaptationSets,
|
|
947
|
+
ContentType.VIDEO);
|
|
948
|
+
const textStreams = this.getStreamsFromSets_(
|
|
949
|
+
this.config_.disableText,
|
|
950
|
+
normalAdaptationSets,
|
|
951
|
+
ContentType.TEXT);
|
|
952
|
+
const imageStreams = this.getStreamsFromSets_(
|
|
953
|
+
this.config_.disableThumbnails,
|
|
954
|
+
normalAdaptationSets,
|
|
955
|
+
ContentType.IMAGE);
|
|
956
|
+
|
|
957
|
+
if (videoStreams.length === 0 && audioStreams.length === 0) {
|
|
835
958
|
throw new shaka.util.Error(
|
|
836
959
|
shaka.util.Error.Severity.CRITICAL,
|
|
837
960
|
shaka.util.Error.Category.MANIFEST,
|
|
838
|
-
shaka.util.Error.Code.DASH_EMPTY_PERIOD
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
const audioStreams = [];
|
|
842
|
-
for (const audioSet of audioSets) {
|
|
843
|
-
audioStreams.push(...audioSet.streams);
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
const videoStreams = [];
|
|
847
|
-
for (const videoSet of videoSets) {
|
|
848
|
-
videoStreams.push(...videoSet.streams);
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
const textStreams = [];
|
|
852
|
-
for (const textSet of textSets) {
|
|
853
|
-
textStreams.push(...textSet.streams);
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
const imageStreams = [];
|
|
857
|
-
for (const imageSet of imageSets) {
|
|
858
|
-
imageStreams.push(...imageSet.streams);
|
|
961
|
+
shaka.util.Error.Code.DASH_EMPTY_PERIOD,
|
|
962
|
+
);
|
|
859
963
|
}
|
|
860
964
|
|
|
861
965
|
return {
|
|
@@ -868,15 +972,26 @@ shaka.dash.DashParser = class {
|
|
|
868
972
|
}
|
|
869
973
|
|
|
870
974
|
/**
|
|
975
|
+
* Gets the streams from the given sets or returns an empty array if disabled
|
|
976
|
+
* or no streams are found.
|
|
977
|
+
* @param {boolean} disabled
|
|
871
978
|
* @param {!Array.<!shaka.dash.DashParser.AdaptationInfo>} adaptationSets
|
|
872
|
-
* @param {string}
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
979
|
+
* @param {string} contentType
|
|
980
|
+
@private
|
|
981
|
+
*/
|
|
982
|
+
getStreamsFromSets_(disabled, adaptationSets, contentType) {
|
|
983
|
+
if (disabled || !adaptationSets.length) {
|
|
984
|
+
return [];
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
return adaptationSets.reduce((all, part) => {
|
|
988
|
+
if (part.contentType != contentType) {
|
|
989
|
+
return all;
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
all.push(...part.streams);
|
|
993
|
+
return all;
|
|
994
|
+
}, []);
|
|
880
995
|
}
|
|
881
996
|
|
|
882
997
|
/**
|
|
@@ -964,6 +1079,7 @@ shaka.dash.DashParser = class {
|
|
|
964
1079
|
XmlUtils.findChildren(elem, 'EssentialProperty');
|
|
965
1080
|
// ID of real AdaptationSet if this is a trick mode set:
|
|
966
1081
|
let trickModeFor = null;
|
|
1082
|
+
let isFastSwitching = false;
|
|
967
1083
|
let unrecognizedEssentialProperty = false;
|
|
968
1084
|
for (const prop of essentialProperties) {
|
|
969
1085
|
const schemeId = prop.getAttribute('schemeIdUri');
|
|
@@ -976,6 +1092,8 @@ shaka.dash.DashParser = class {
|
|
|
976
1092
|
} else if (schemeId == colourPrimariesScheme ||
|
|
977
1093
|
schemeId == matrixCoefficientsScheme) {
|
|
978
1094
|
continue;
|
|
1095
|
+
} else if (schemeId == 'urn:mpeg:dash:ssr:2023') {
|
|
1096
|
+
isFastSwitching = true;
|
|
979
1097
|
} else {
|
|
980
1098
|
unrecognizedEssentialProperty = true;
|
|
981
1099
|
}
|
|
@@ -1133,6 +1251,7 @@ shaka.dash.DashParser = class {
|
|
|
1133
1251
|
closedCaptions, representation, accessibilityPurpose);
|
|
1134
1252
|
if (parsedRepresentation) {
|
|
1135
1253
|
parsedRepresentation.hdr = parsedRepresentation.hdr || videoRange;
|
|
1254
|
+
parsedRepresentation.fastSwitching = isFastSwitching;
|
|
1136
1255
|
}
|
|
1137
1256
|
return parsedRepresentation;
|
|
1138
1257
|
}).filter((s) => !!s);
|
|
@@ -1257,9 +1376,9 @@ shaka.dash.DashParser = class {
|
|
|
1257
1376
|
/** @type {shaka.extern.aes128Key|undefined} */
|
|
1258
1377
|
let aes128Key = undefined;
|
|
1259
1378
|
if (contentProtection.aes128Info) {
|
|
1260
|
-
const
|
|
1379
|
+
const getBaseUris = context.representation.getBaseUris;
|
|
1261
1380
|
const uris = shaka.util.ManifestParserUtils.resolveUris(
|
|
1262
|
-
|
|
1381
|
+
getBaseUris(), [contentProtection.aes128Info.keyUri]);
|
|
1263
1382
|
const requestType = shaka.net.NetworkingEngine.RequestType.KEY;
|
|
1264
1383
|
const request = shaka.net.NetworkingEngine.makeRequest(
|
|
1265
1384
|
uris, this.config_.retryParameters);
|
|
@@ -1313,10 +1432,10 @@ shaka.dash.DashParser = class {
|
|
|
1313
1432
|
goog.asserts.assert(isText,
|
|
1314
1433
|
'Must have Segment* with non-text streams.');
|
|
1315
1434
|
|
|
1316
|
-
const baseUris = context.representation.baseUris;
|
|
1317
1435
|
const duration = context.periodInfo.duration || 0;
|
|
1318
1436
|
streamInfo = {
|
|
1319
1437
|
generateSegmentIndex: () => {
|
|
1438
|
+
const baseUris = context.representation.getBaseUris();
|
|
1320
1439
|
return Promise.resolve(shaka.media.SegmentIndex.forSingleSegment(
|
|
1321
1440
|
periodStart, duration, baseUris));
|
|
1322
1441
|
},
|
|
@@ -1442,10 +1561,12 @@ shaka.dash.DashParser = class {
|
|
|
1442
1561
|
spatialAudio,
|
|
1443
1562
|
closedCaptions,
|
|
1444
1563
|
hdr,
|
|
1564
|
+
videoLayout: undefined,
|
|
1445
1565
|
tilesLayout,
|
|
1446
1566
|
matchedStreams: [],
|
|
1447
1567
|
accessibilityPurpose,
|
|
1448
1568
|
external: false,
|
|
1569
|
+
fastSwitching: false,
|
|
1449
1570
|
};
|
|
1450
1571
|
}
|
|
1451
1572
|
|
|
@@ -1518,8 +1639,8 @@ shaka.dash.DashParser = class {
|
|
|
1518
1639
|
// NOTE: An updatePeriod_ of -1 means the attribute was missing.
|
|
1519
1640
|
// An attribute which is present and set to 0 should still result in
|
|
1520
1641
|
// periodic updates. For more, see:
|
|
1521
|
-
// https://github.com/
|
|
1522
|
-
if (this.updatePeriod_
|
|
1642
|
+
// https://github.com/Dash-Industry-Forum/Guidelines-TimingModel/issues/48
|
|
1643
|
+
if (this.updatePeriod_ <= 0) {
|
|
1523
1644
|
return;
|
|
1524
1645
|
}
|
|
1525
1646
|
|
|
@@ -1537,13 +1658,13 @@ shaka.dash.DashParser = class {
|
|
|
1537
1658
|
*
|
|
1538
1659
|
* @param {!Element} elem
|
|
1539
1660
|
* @param {?shaka.dash.DashParser.InheritanceFrame} parent
|
|
1540
|
-
* @param {Array.<string>}
|
|
1661
|
+
* @param {?function():!Array.<string>} getBaseUris
|
|
1541
1662
|
* @return {shaka.dash.DashParser.InheritanceFrame}
|
|
1542
1663
|
* @private
|
|
1543
1664
|
*/
|
|
1544
|
-
createFrame_(elem, parent,
|
|
1545
|
-
goog.asserts.assert(parent ||
|
|
1546
|
-
'Must provide either parent or
|
|
1665
|
+
createFrame_(elem, parent, getBaseUris) {
|
|
1666
|
+
goog.asserts.assert(parent || getBaseUris,
|
|
1667
|
+
'Must provide either parent or getBaseUris');
|
|
1547
1668
|
const ManifestParserUtils = shaka.util.ManifestParserUtils;
|
|
1548
1669
|
const XmlUtils = shaka.util.XmlUtils;
|
|
1549
1670
|
parent = parent || /** @type {shaka.dash.DashParser.InheritanceFrame} */ ({
|
|
@@ -1556,14 +1677,44 @@ shaka.dash.DashParser = class {
|
|
|
1556
1677
|
numChannels: null,
|
|
1557
1678
|
audioSamplingRate: null,
|
|
1558
1679
|
availabilityTimeOffset: 0,
|
|
1680
|
+
segmentSequenceCadence: 0,
|
|
1559
1681
|
});
|
|
1560
|
-
|
|
1682
|
+
getBaseUris = getBaseUris || parent.getBaseUris;
|
|
1561
1683
|
|
|
1562
1684
|
const parseNumber = XmlUtils.parseNonNegativeInt;
|
|
1563
1685
|
const evalDivision = XmlUtils.evalDivision;
|
|
1564
1686
|
|
|
1687
|
+
const id = elem.getAttribute('id');
|
|
1565
1688
|
const uriObjs = XmlUtils.findChildren(elem, 'BaseURL');
|
|
1566
|
-
|
|
1689
|
+
let calculatedBaseUris;
|
|
1690
|
+
let someLocationValid = false;
|
|
1691
|
+
if (this.contentSteeringManager_) {
|
|
1692
|
+
for (const uriObj of uriObjs) {
|
|
1693
|
+
const serviceLocation = uriObj.getAttribute('serviceLocation');
|
|
1694
|
+
const uri = XmlUtils.getContents(uriObj);
|
|
1695
|
+
if (serviceLocation && uri) {
|
|
1696
|
+
this.contentSteeringManager_.addLocation(
|
|
1697
|
+
id, serviceLocation, uri);
|
|
1698
|
+
someLocationValid = true;
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
if (!someLocationValid || !this.contentSteeringManager_) {
|
|
1703
|
+
calculatedBaseUris = uriObjs.map(XmlUtils.getContents);
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1706
|
+
const getFrameUris = () => {
|
|
1707
|
+
if (!uriObjs.length) {
|
|
1708
|
+
return [];
|
|
1709
|
+
}
|
|
1710
|
+
if (this.contentSteeringManager_ && someLocationValid) {
|
|
1711
|
+
return this.contentSteeringManager_.getLocations(id);
|
|
1712
|
+
}
|
|
1713
|
+
if (calculatedBaseUris) {
|
|
1714
|
+
return calculatedBaseUris;
|
|
1715
|
+
}
|
|
1716
|
+
return [];
|
|
1717
|
+
};
|
|
1567
1718
|
|
|
1568
1719
|
let contentType = elem.getAttribute('contentType') || parent.contentType;
|
|
1569
1720
|
const mimeType = elem.getAttribute('mimeType') || parent.mimeType;
|
|
@@ -1606,8 +1757,20 @@ shaka.dash.DashParser = class {
|
|
|
1606
1757
|
const availabilityTimeOffset = parent.availabilityTimeOffset + baseUriAto +
|
|
1607
1758
|
segmentBaseAto + segmentTemplateAto;
|
|
1608
1759
|
|
|
1760
|
+
let segmentSequenceCadence = null;
|
|
1761
|
+
const segmentSequenceProperties =
|
|
1762
|
+
XmlUtils.findChild(elem, 'SegmentSequenceProperties');
|
|
1763
|
+
if (segmentSequenceProperties) {
|
|
1764
|
+
const sap = XmlUtils.findChild(segmentSequenceProperties, 'SAP');
|
|
1765
|
+
if (sap) {
|
|
1766
|
+
segmentSequenceCadence = XmlUtils.parseAttr(sap, 'cadence',
|
|
1767
|
+
XmlUtils.parseInt);
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1609
1771
|
return {
|
|
1610
|
-
|
|
1772
|
+
getBaseUris:
|
|
1773
|
+
() => ManifestParserUtils.resolveUris(getBaseUris(), getFrameUris()),
|
|
1611
1774
|
segmentBase: segmentBase || parent.segmentBase,
|
|
1612
1775
|
segmentList:
|
|
1613
1776
|
XmlUtils.findChild(elem, 'SegmentList') || parent.segmentList,
|
|
@@ -1620,11 +1783,13 @@ shaka.dash.DashParser = class {
|
|
|
1620
1783
|
frameRate: frameRate,
|
|
1621
1784
|
pixelAspectRatio: pixelAspectRatio,
|
|
1622
1785
|
emsgSchemeIdUris: emsgSchemeIdUris,
|
|
1623
|
-
id:
|
|
1786
|
+
id: id,
|
|
1624
1787
|
language: elem.getAttribute('lang'),
|
|
1625
1788
|
numChannels: numChannels,
|
|
1626
1789
|
audioSamplingRate: audioSamplingRate,
|
|
1627
1790
|
availabilityTimeOffset: availabilityTimeOffset,
|
|
1791
|
+
segmentSequenceCadence:
|
|
1792
|
+
segmentSequenceCadence || parent.segmentSequenceCadence,
|
|
1628
1793
|
};
|
|
1629
1794
|
}
|
|
1630
1795
|
|
|
@@ -1794,15 +1959,15 @@ shaka.dash.DashParser = class {
|
|
|
1794
1959
|
/**
|
|
1795
1960
|
* Makes a request to the given URI and calculates the clock offset.
|
|
1796
1961
|
*
|
|
1797
|
-
* @param {
|
|
1962
|
+
* @param {function():!Array.<string>} getBaseUris
|
|
1798
1963
|
* @param {string} uri
|
|
1799
1964
|
* @param {string} method
|
|
1800
1965
|
* @return {!Promise.<number>}
|
|
1801
1966
|
* @private
|
|
1802
1967
|
*/
|
|
1803
|
-
async requestForTiming_(
|
|
1968
|
+
async requestForTiming_(getBaseUris, uri, method) {
|
|
1804
1969
|
const requestUris =
|
|
1805
|
-
shaka.util.ManifestParserUtils.resolveUris(
|
|
1970
|
+
shaka.util.ManifestParserUtils.resolveUris(getBaseUris(), [uri]);
|
|
1806
1971
|
const request = shaka.net.NetworkingEngine.makeRequest(
|
|
1807
1972
|
requestUris, this.config_.retryParameters);
|
|
1808
1973
|
request.method = method;
|
|
@@ -1835,12 +2000,12 @@ shaka.dash.DashParser = class {
|
|
|
1835
2000
|
/**
|
|
1836
2001
|
* Parses an array of UTCTiming elements.
|
|
1837
2002
|
*
|
|
1838
|
-
* @param {
|
|
2003
|
+
* @param {function():!Array.<string>} getBaseUris
|
|
1839
2004
|
* @param {!Array.<!Element>} elems
|
|
1840
2005
|
* @return {!Promise.<number>}
|
|
1841
2006
|
* @private
|
|
1842
2007
|
*/
|
|
1843
|
-
async parseUtcTiming_(
|
|
2008
|
+
async parseUtcTiming_(getBaseUris, elems) {
|
|
1844
2009
|
const schemesAndValues = elems.map((elem) => {
|
|
1845
2010
|
return {
|
|
1846
2011
|
scheme: elem.getAttribute('schemeIdUri'),
|
|
@@ -1869,13 +2034,13 @@ shaka.dash.DashParser = class {
|
|
|
1869
2034
|
case 'urn:mpeg:dash:utc:http-head:2014':
|
|
1870
2035
|
case 'urn:mpeg:dash:utc:http-head:2012':
|
|
1871
2036
|
// eslint-disable-next-line no-await-in-loop
|
|
1872
|
-
return await this.requestForTiming_(
|
|
2037
|
+
return await this.requestForTiming_(getBaseUris, value, 'HEAD');
|
|
1873
2038
|
case 'urn:mpeg:dash:utc:http-xsdate:2014':
|
|
1874
2039
|
case 'urn:mpeg:dash:utc:http-iso:2014':
|
|
1875
2040
|
case 'urn:mpeg:dash:utc:http-xsdate:2012':
|
|
1876
2041
|
case 'urn:mpeg:dash:utc:http-iso:2012':
|
|
1877
2042
|
// eslint-disable-next-line no-await-in-loop
|
|
1878
|
-
return await this.requestForTiming_(
|
|
2043
|
+
return await this.requestForTiming_(getBaseUris, value, 'GET');
|
|
1879
2044
|
case 'urn:mpeg:dash:utc:direct:2014':
|
|
1880
2045
|
case 'urn:mpeg:dash:utc:direct:2012': {
|
|
1881
2046
|
const date = Date.parse(value);
|
|
@@ -2038,7 +2203,7 @@ shaka.dash.DashParser.RequestSegmentCallback;
|
|
|
2038
2203
|
* segmentBase: Element,
|
|
2039
2204
|
* segmentList: Element,
|
|
2040
2205
|
* segmentTemplate: Element,
|
|
2041
|
-
*
|
|
2206
|
+
* getBaseUris: function():!Array.<string>,
|
|
2042
2207
|
* width: (number|undefined),
|
|
2043
2208
|
* height: (number|undefined),
|
|
2044
2209
|
* contentType: string,
|
|
@@ -2051,7 +2216,8 @@ shaka.dash.DashParser.RequestSegmentCallback;
|
|
|
2051
2216
|
* language: ?string,
|
|
2052
2217
|
* numChannels: ?number,
|
|
2053
2218
|
* audioSamplingRate: ?number,
|
|
2054
|
-
* availabilityTimeOffset: number
|
|
2219
|
+
* availabilityTimeOffset: number,
|
|
2220
|
+
* segmentSequenceCadence: number
|
|
2055
2221
|
* }}
|
|
2056
2222
|
*
|
|
2057
2223
|
* @description
|
|
@@ -2064,8 +2230,8 @@ shaka.dash.DashParser.RequestSegmentCallback;
|
|
|
2064
2230
|
* The XML node for SegmentList.
|
|
2065
2231
|
* @property {Element} segmentTemplate
|
|
2066
2232
|
* The XML node for SegmentTemplate.
|
|
2067
|
-
* @property {
|
|
2068
|
-
*
|
|
2233
|
+
* @property {function():!Array.<string>} getBaseUris
|
|
2234
|
+
* Function than returns an array of absolute base URIs for the frame.
|
|
2069
2235
|
* @property {(number|undefined)} width
|
|
2070
2236
|
* The inherited width value.
|
|
2071
2237
|
* @property {(number|undefined)} height
|
|
@@ -2092,6 +2258,9 @@ shaka.dash.DashParser.RequestSegmentCallback;
|
|
|
2092
2258
|
* Specifies the maximum sampling rate of the content, or null if unknown.
|
|
2093
2259
|
* @property {number} availabilityTimeOffset
|
|
2094
2260
|
* Specifies the total availabilityTimeOffset of the segment, or 0 if unknown.
|
|
2261
|
+
* @property {number} segmentSequenceCadence
|
|
2262
|
+
* Specifies the cadence of independent segments in Segment Sequence
|
|
2263
|
+
* Representation.
|
|
2095
2264
|
*/
|
|
2096
2265
|
shaka.dash.DashParser.InheritanceFrame;
|
|
2097
2266
|
|
|
@@ -2225,8 +2394,6 @@ shaka.dash.DashParser.GenerateSegmentIndexFunction;
|
|
|
2225
2394
|
shaka.dash.DashParser.StreamInfo;
|
|
2226
2395
|
|
|
2227
2396
|
|
|
2228
|
-
shaka.media.ManifestParser.registerParserByExtension(
|
|
2229
|
-
'mpd', () => new shaka.dash.DashParser());
|
|
2230
2397
|
shaka.media.ManifestParser.registerParserByMime(
|
|
2231
2398
|
'application/dash+xml', () => new shaka.dash.DashParser());
|
|
2232
2399
|
shaka.media.ManifestParser.registerParserByMime(
|