shaka-player 4.4.3 → 4.6.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/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
- package/.github/workflows/release-please.yaml +2 -27
- package/AUTHORS +2 -0
- package/CHANGELOG.md +156 -39
- package/CODE_OF_CONDUCT.md +1 -1
- package/CONTRIBUTORS +2 -0
- package/README.md +54 -42
- package/demo/asset_card.js +18 -21
- package/demo/cast_receiver/index.html +0 -1
- package/demo/close_button.js +0 -3
- package/demo/common/asset.js +33 -22
- package/demo/common/assets.js +249 -60
- package/demo/config.js +219 -253
- package/demo/custom.js +88 -133
- package/demo/front.js +7 -10
- package/demo/index.html +19 -22
- package/demo/input.js +6 -11
- package/demo/input_container.js +8 -9
- package/demo/main.js +62 -126
- package/demo/search.js +29 -34
- package/demo/service_worker.js +0 -3
- package/demo/tooltip.js +3 -5
- package/demo/visualizer.js +3 -5
- package/demo/visualizer_button.js +1 -20
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +211 -228
- package/dist/demo.compiled.debug.map +4 -4
- package/dist/demo.compiled.js +211 -228
- package/dist/demo.compiled.map +4 -4
- package/dist/deps.js +42 -37
- package/dist/locales.js +34 -30
- package/dist/receiver.compiled.debug.js +64 -77
- package/dist/receiver.compiled.debug.map +4 -4
- package/dist/receiver.compiled.js +64 -77
- package/dist/receiver.compiled.map +4 -4
- package/dist/shaka-player.compiled.d.ts +343 -151
- package/dist/shaka-player.compiled.debug.d.ts +343 -151
- package/dist/shaka-player.compiled.debug.externs.js +356 -117
- package/dist/shaka-player.compiled.debug.js +952 -811
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +356 -117
- package/dist/shaka-player.compiled.js +1165 -1078
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +359 -153
- package/dist/shaka-player.ui.debug.d.ts +359 -153
- package/dist/shaka-player.ui.debug.externs.js +382 -117
- package/dist/shaka-player.ui.debug.js +1084 -918
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +382 -117
- package/dist/shaka-player.ui.js +1377 -1274
- package/dist/shaka-player.ui.map +4 -4
- package/docs/design/lcevc-integration.md +14 -14
- 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/faq.md +27 -55
- package/docs/tutorials/index.json +2 -1
- package/docs/tutorials/lcevc.md +118 -0
- package/docs/tutorials/offline.md +10 -8
- package/docs/tutorials/plugins.md +5 -0
- package/docs/tutorials/ui-customization.md +17 -0
- package/docs/tutorials/ui.md +2 -1
- package/docs/tutorials/upgrade.md +3 -0
- package/externs/css_style_declaration.js +19 -0
- package/externs/lcevc.js +37 -13
- package/externs/managedmediasource.js +24 -0
- package/externs/media_remote.js +68 -0
- package/externs/mediatailor.js +193 -0
- package/externs/pictureinpicture.js +11 -0
- package/externs/shaka/abr_manager.js +6 -2
- package/externs/shaka/ads.js +27 -0
- package/externs/shaka/cea.js +7 -0
- package/externs/shaka/codecs.js +5 -3
- package/externs/shaka/manifest.js +31 -10
- package/externs/shaka/manifest_parser.js +24 -1
- package/externs/shaka/net.js +2 -2
- package/externs/shaka/offline.js +13 -2
- package/externs/shaka/player.js +65 -8
- package/externs/shaka/text.js +3 -1
- package/externs/shaka/transmuxer.js +1 -1
- package/karma.conf.js +7 -3
- package/lib/abr/simple_abr_manager.js +66 -9
- package/lib/ads/ad_manager.js +104 -50
- package/lib/ads/media_tailor_ad.js +297 -0
- package/lib/ads/media_tailor_ad_manager.js +839 -0
- 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/cea/ts_cea_parser.js +15 -2
- package/lib/config/codec_switching_strategy.js +24 -0
- package/lib/dash/content_protection.js +120 -2
- package/lib/dash/dash_parser.js +322 -93
- package/lib/dash/mpd_utils.js +62 -37
- package/lib/dash/segment_base.js +17 -10
- package/lib/dash/segment_list.js +18 -9
- package/lib/dash/segment_template.js +122 -107
- package/lib/dependencies/all.js +8 -7
- package/lib/hls/hls_classes.js +28 -43
- package/lib/hls/hls_parser.js +798 -658
- package/lib/hls/hls_utils.js +64 -5
- package/lib/hls/manifest_text_parser.js +7 -11
- package/lib/lcevc/lcevc_dec.js +220 -0
- package/lib/media/adaptation_set.js +32 -14
- package/lib/media/adaptation_set_criteria.js +86 -16
- 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 +286 -44
- 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 +6 -6
- package/lib/media/segment_prefetch.js +92 -24
- package/lib/media/segment_reference.js +73 -7
- package/lib/media/segment_utils.js +343 -0
- package/lib/media/stall_detector.js +0 -3
- package/lib/media/streaming_engine.js +73 -38
- package/lib/mss/mss_parser.js +19 -2
- package/lib/net/networking_engine.js +67 -12
- package/lib/net/networking_utils.js +95 -0
- package/lib/offline/indexeddb/v1_storage_cell.js +3 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +3 -0
- package/lib/offline/manifest_converter.js +3 -0
- package/lib/offline/offline_manifest_parser.js +10 -0
- package/lib/offline/storage.js +14 -7
- package/lib/player.js +1098 -1537
- package/lib/polyfill/mediasource.js +22 -1
- package/lib/text/cue.js +15 -0
- 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 +45 -5
- package/lib/text/ui_text_displayer.js +8 -0
- package/lib/text/vtt_text_parser.js +40 -22
- 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 +863 -0
- package/lib/transmuxer/mp3_transmuxer.js +1 -1
- package/lib/transmuxer/mpeg_ts_transmuxer.js +4 -3
- package/lib/transmuxer/mss_transmuxer.js +1 -1
- package/lib/transmuxer/ts_transmuxer.js +187 -22
- package/lib/util/buffer_utils.js +26 -4
- package/lib/util/content_steering_manager.js +358 -0
- package/lib/util/error.js +30 -15
- package/lib/util/exp_golomb.js +30 -2
- package/lib/util/fairplay_utils.js +1 -1
- package/lib/util/fake_event.js +8 -1
- package/lib/util/id3_utils.js +50 -1
- package/lib/util/manifest_parser_utils.js +12 -8
- package/lib/util/mp4_generator.js +6 -8
- package/lib/util/mutex.js +59 -0
- package/lib/util/object_utils.js +1 -1
- package/lib/util/periods.js +156 -179
- package/lib/util/platform.js +44 -3
- package/lib/util/player_configuration.js +43 -6
- package/lib/util/state_history.js +6 -2
- package/lib/util/stream_utils.js +206 -283
- package/lib/util/ts_parser.js +335 -98
- package/lib/util/uint8array_utils.js +5 -1
- package/lib/util/xml_utils.js +5 -0
- package/maintained-branches.md +3 -2
- package/package.json +4 -6
- package/roadmap.md +25 -5
- package/shaka-player.uncompiled.js +2 -2
- package/support.html +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 +50 -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 +182 -0
- package/test/dash/dash_parser_content_protection_unit.js +2 -0
- package/test/dash/dash_parser_integration.js +74 -0
- package/test/dash/dash_parser_live_unit.js +2 -19
- package/test/dash/dash_parser_manifest_unit.js +536 -2
- package/test/dash/dash_parser_segment_base_unit.js +2 -0
- package/test/dash/dash_parser_segment_list_unit.js +2 -0
- package/test/dash/dash_parser_segment_template_unit.js +2 -0
- package/test/dash/mpd_utils_unit.js +61 -30
- package/test/demo/demo_unit.js +0 -16
- package/test/hls/hls_live_unit.js +14 -3
- package/test/hls/hls_parser_unit.js +385 -33
- package/test/hls/manifest_text_parser_unit.js +32 -99
- package/test/media/adaptation_set_criteria_unit.js +284 -15
- package/test/media/adaptation_set_unit.js +2 -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 +166 -2
- package/test/media/play_rate_controller_unit.js +0 -48
- package/test/media/segment_index_unit.js +5 -4
- package/test/media/segment_prefetch_unit.js +1 -1
- package/test/media/streaming_engine_unit.js +17 -17
- package/test/mss/mss_parser_unit.js +2 -0
- 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 +14 -0
- package/test/offline/offline_integration.js +2 -1
- package/test/offline/storage_integration.js +22 -13
- 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 +182 -158
- package/test/test/assets/dash-aes-128/Fragments(video=0,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=20000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=40000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=60000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=i,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/dash.mpd +18 -0
- package/test/test/assets/dash-aes-128/license +1 -0
- package/test/test/assets/dash-multi-codec/audio_en_2c_128k_aac.mp4 +0 -0
- package/test/test/assets/dash-multi-codec/audio_es_2c_64k_opus.webm +0 -0
- package/test/test/assets/dash-multi-codec/dash.mpd +32 -0
- package/test/test/assets/dash-multi-codec/video_144p_108k_h264.mp4 +0 -0
- package/test/test/assets/hls-ts-h265/0.ts +0 -0
- package/test/test/assets/hls-ts-h265/hevc.m3u8 +6 -0
- package/test/test/assets/hls-ts-h265/index.m3u8 +7 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/0.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 +9 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/media.m3u8 +24 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00000.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00001.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00002.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00003.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00004.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00005.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0000.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0001.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0002.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0003.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/prog_index.m3u8 +14 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/index.m3u8 +23 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-1-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-2-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-3-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-4-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-5-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-6-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-7-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-8-v1-a1.ts +0 -0
- package/test/test/util/dash_parser_util.js +4 -0
- package/test/test/util/fake_ad_manager.js +20 -0
- package/test/test/util/fake_media_source_engine.js +13 -2
- 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 +11 -3
- package/test/test/util/manifest_parser_util.js +14 -2
- package/test/test/util/mss_parser_util.js +4 -0
- package/test/test/util/offline_utils.js +2 -0
- package/test/test/util/simple_fakes.js +2 -2
- package/test/test/util/streaming_engine_util.js +10 -4
- 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 +85 -2
- package/test/text/vtt_text_parser_unit.js +103 -31
- package/test/transmuxer/transmuxer_engine_integration.js +9 -0
- package/test/transmuxer/transmuxer_integration.js +150 -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 +28 -29
- 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 +207 -169
- 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/controls.js +125 -0
- package/ui/externs/ui.js +24 -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/pip_button.js +22 -120
- package/ui/remote_button.js +203 -0
- 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 +11 -4
- package/demo/common/message_ids.js +0 -309
- package/demo/locales/en.json +0 -288
- package/demo/locales/source.json +0 -1146
- package/externs/mux.js +0 -69
- package/lib/lcevc/lcevc_dil.js +0 -152
- package/lib/routing/node.js +0 -23
- package/lib/routing/payload.js +0 -43
- package/lib/routing/walker.js +0 -587
- package/lib/transmuxer/muxjs_transmuxer.js +0 -242
- package/test/routing/walker_unit.js +0 -504
- package/test/transmuxer/muxjs_transmuxer_integration.js +0 -177
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
|
*
|
|
@@ -224,12 +273,10 @@ shaka.dash.DashParser = class {
|
|
|
224
273
|
const type = shaka.net.NetworkingEngine.AdvancedRequestType.MPD;
|
|
225
274
|
const request = shaka.net.NetworkingEngine.makeRequest(
|
|
226
275
|
this.manifestUris_, this.config_.retryParameters);
|
|
227
|
-
const networkingEngine = this.playerInterface_.networkingEngine;
|
|
228
276
|
const startTime = Date.now();
|
|
229
|
-
const operation = networkingEngine.request(requestType, request, {type});
|
|
230
|
-
this.operationManager_.manage(operation);
|
|
231
277
|
|
|
232
|
-
const response = await
|
|
278
|
+
const response = await this.makeNetworkRequest_(
|
|
279
|
+
request, requestType, {type});
|
|
233
280
|
|
|
234
281
|
// Detect calls to stop().
|
|
235
282
|
if (!this.playerInterface_) {
|
|
@@ -322,10 +369,68 @@ shaka.dash.DashParser = class {
|
|
|
322
369
|
manifestBaseUris = absoluteLocations;
|
|
323
370
|
}
|
|
324
371
|
|
|
372
|
+
let contentSteeringPromise = Promise.resolve();
|
|
373
|
+
|
|
374
|
+
const contentSteering = XmlUtils.findChild(mpd, 'ContentSteering');
|
|
375
|
+
if (contentSteering && this.playerInterface_) {
|
|
376
|
+
const hasPrevContentSteeringManager = !!this.contentSteeringManager_;
|
|
377
|
+
if (!this.contentSteeringManager_) {
|
|
378
|
+
this.contentSteeringManager_ =
|
|
379
|
+
new shaka.util.ContentSteeringManager(this.playerInterface_);
|
|
380
|
+
}
|
|
381
|
+
this.contentSteeringManager_.configure(this.config_);
|
|
382
|
+
this.contentSteeringManager_.setBaseUris(manifestBaseUris);
|
|
383
|
+
this.contentSteeringManager_.setManifestType(
|
|
384
|
+
shaka.media.ManifestParser.DASH);
|
|
385
|
+
const defaultPathwayId =
|
|
386
|
+
contentSteering.getAttribute('defaultServiceLocation');
|
|
387
|
+
this.contentSteeringManager_.setDefaultPathwayId(defaultPathwayId);
|
|
388
|
+
if (!hasPrevContentSteeringManager) {
|
|
389
|
+
const uri = XmlUtils.getContents(contentSteering);
|
|
390
|
+
if (uri) {
|
|
391
|
+
const queryBeforeStart =
|
|
392
|
+
XmlUtils.parseAttr(contentSteering, 'queryBeforeStart',
|
|
393
|
+
XmlUtils.parseBoolean, /* defaultValue= */ false);
|
|
394
|
+
if (queryBeforeStart) {
|
|
395
|
+
contentSteeringPromise =
|
|
396
|
+
this.contentSteeringManager_.requestInfo(uri);
|
|
397
|
+
} else {
|
|
398
|
+
this.contentSteeringManager_.requestInfo(uri);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
325
404
|
const uriObjs = XmlUtils.findChildren(mpd, 'BaseURL');
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
405
|
+
let calculatedBaseUris;
|
|
406
|
+
let someLocationValid = false;
|
|
407
|
+
if (this.contentSteeringManager_) {
|
|
408
|
+
this.contentSteeringManager_.clearPreviousLocations();
|
|
409
|
+
for (const uriObj of uriObjs) {
|
|
410
|
+
const serviceLocation = uriObj.getAttribute('serviceLocation');
|
|
411
|
+
const uri = XmlUtils.getContents(uriObj);
|
|
412
|
+
if (serviceLocation && uri) {
|
|
413
|
+
this.contentSteeringManager_.addLocation(
|
|
414
|
+
'BaseURL', serviceLocation, uri);
|
|
415
|
+
someLocationValid = true;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
if (!someLocationValid || !this.contentSteeringManager_) {
|
|
420
|
+
const uris = uriObjs.map(XmlUtils.getContents);
|
|
421
|
+
calculatedBaseUris = shaka.util.ManifestParserUtils.resolveUris(
|
|
422
|
+
manifestBaseUris, uris);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const getBaseUris = () => {
|
|
426
|
+
if (this.contentSteeringManager_ && someLocationValid) {
|
|
427
|
+
return this.contentSteeringManager_.getLocations('BaseURL');
|
|
428
|
+
}
|
|
429
|
+
if (calculatedBaseUris) {
|
|
430
|
+
return calculatedBaseUris;
|
|
431
|
+
}
|
|
432
|
+
return [];
|
|
433
|
+
};
|
|
329
434
|
|
|
330
435
|
let availabilityTimeOffset = 0;
|
|
331
436
|
if (uriObjs && uriObjs.length) {
|
|
@@ -441,7 +546,7 @@ shaka.dash.DashParser = class {
|
|
|
441
546
|
profiles: profiles.split(','),
|
|
442
547
|
};
|
|
443
548
|
|
|
444
|
-
const periodsAndDuration = this.parsePeriods_(context,
|
|
549
|
+
const periodsAndDuration = this.parsePeriods_(context, getBaseUris, mpd);
|
|
445
550
|
const duration = periodsAndDuration.duration;
|
|
446
551
|
const periods = periodsAndDuration.periods;
|
|
447
552
|
|
|
@@ -485,18 +590,14 @@ shaka.dash.DashParser = class {
|
|
|
485
590
|
|
|
486
591
|
await this.periodCombiner_.combinePeriods(periods, context.dynamic);
|
|
487
592
|
|
|
593
|
+
await contentSteeringPromise;
|
|
594
|
+
|
|
488
595
|
// Set minBufferTime to 0 for low-latency DASH live stream to achieve the
|
|
489
596
|
// best latency
|
|
490
597
|
if (this.lowLatencyMode_) {
|
|
491
598
|
minBufferTime = 0;
|
|
492
599
|
}
|
|
493
600
|
|
|
494
|
-
// Set updatePeriod_ to minTotalAvailabilityTimeOffset_ to achieve the best
|
|
495
|
-
// latency in LL streams
|
|
496
|
-
if (this.lowLatencyMode_ && this.minTotalAvailabilityTimeOffset_) {
|
|
497
|
-
this.updatePeriod_ = this.minTotalAvailabilityTimeOffset_;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
601
|
// These steps are not done on manifest update.
|
|
501
602
|
if (!this.manifest_) {
|
|
502
603
|
this.manifest_ = {
|
|
@@ -517,7 +618,7 @@ shaka.dash.DashParser = class {
|
|
|
517
618
|
if (presentationTimeline.usingPresentationStartTime()) {
|
|
518
619
|
const XmlUtils = shaka.util.XmlUtils;
|
|
519
620
|
const timingElements = XmlUtils.findChildren(mpd, 'UTCTiming');
|
|
520
|
-
const offset = await this.parseUtcTiming_(
|
|
621
|
+
const offset = await this.parseUtcTiming_(getBaseUris, timingElements);
|
|
521
622
|
// Detect calls to stop().
|
|
522
623
|
if (!this.playerInterface_) {
|
|
523
624
|
return;
|
|
@@ -577,8 +678,19 @@ shaka.dash.DashParser = class {
|
|
|
577
678
|
const maxPlaybackRate = playbackRateNode ?
|
|
578
679
|
parseFloat(playbackRateNode.getAttribute('max')) :
|
|
579
680
|
null;
|
|
681
|
+
const minLatency = latencyNode && latencyNode.getAttribute('min') ?
|
|
682
|
+
parseInt(latencyNode.getAttribute('min'), 10) / 1000 :
|
|
683
|
+
null;
|
|
684
|
+
const minPlaybackRate = playbackRateNode ?
|
|
685
|
+
parseFloat(playbackRateNode.getAttribute('min')) :
|
|
686
|
+
null;
|
|
580
687
|
|
|
581
|
-
return {
|
|
688
|
+
return {
|
|
689
|
+
maxLatency,
|
|
690
|
+
maxPlaybackRate,
|
|
691
|
+
minLatency,
|
|
692
|
+
minPlaybackRate,
|
|
693
|
+
};
|
|
582
694
|
}
|
|
583
695
|
|
|
584
696
|
return null;
|
|
@@ -590,7 +702,7 @@ shaka.dash.DashParser = class {
|
|
|
590
702
|
* children.
|
|
591
703
|
*
|
|
592
704
|
* @param {shaka.dash.DashParser.Context} context
|
|
593
|
-
* @param {
|
|
705
|
+
* @param {function():!Array.<string>} getBaseUris
|
|
594
706
|
* @param {!Element} mpd
|
|
595
707
|
* @return {{
|
|
596
708
|
* periods: !Array.<shaka.extern.Period>,
|
|
@@ -599,7 +711,7 @@ shaka.dash.DashParser = class {
|
|
|
599
711
|
* }}
|
|
600
712
|
* @private
|
|
601
713
|
*/
|
|
602
|
-
parsePeriods_(context,
|
|
714
|
+
parsePeriods_(context, getBaseUris, mpd) {
|
|
603
715
|
const XmlUtils = shaka.util.XmlUtils;
|
|
604
716
|
const presentationDuration = XmlUtils.parseAttr(
|
|
605
717
|
mpd, 'mediaPresentationDuration', XmlUtils.parseDuration);
|
|
@@ -689,7 +801,7 @@ shaka.dash.DashParser = class {
|
|
|
689
801
|
node: elem,
|
|
690
802
|
isLastPeriod: periodDuration == null || !next,
|
|
691
803
|
};
|
|
692
|
-
const period = this.parsePeriod_(context,
|
|
804
|
+
const period = this.parsePeriod_(context, getBaseUris, info);
|
|
693
805
|
periods.push(period);
|
|
694
806
|
|
|
695
807
|
if (context.period.id && periodDuration) {
|
|
@@ -743,17 +855,17 @@ shaka.dash.DashParser = class {
|
|
|
743
855
|
* was done before this was called so start and duration are valid.
|
|
744
856
|
*
|
|
745
857
|
* @param {shaka.dash.DashParser.Context} context
|
|
746
|
-
* @param {
|
|
858
|
+
* @param {function():!Array.<string>} getBaseUris
|
|
747
859
|
* @param {shaka.dash.DashParser.PeriodInfo} periodInfo
|
|
748
860
|
* @return {shaka.extern.Period}
|
|
749
861
|
* @private
|
|
750
862
|
*/
|
|
751
|
-
parsePeriod_(context,
|
|
863
|
+
parsePeriod_(context, getBaseUris, periodInfo) {
|
|
752
864
|
const Functional = shaka.util.Functional;
|
|
753
865
|
const XmlUtils = shaka.util.XmlUtils;
|
|
754
866
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
755
867
|
|
|
756
|
-
context.period = this.createFrame_(periodInfo.node, null,
|
|
868
|
+
context.period = this.createFrame_(periodInfo.node, null, getBaseUris);
|
|
757
869
|
context.periodInfo = periodInfo;
|
|
758
870
|
context.period.availabilityTimeOffset = context.availabilityTimeOffset;
|
|
759
871
|
|
|
@@ -824,40 +936,29 @@ shaka.dash.DashParser = class {
|
|
|
824
936
|
}
|
|
825
937
|
}
|
|
826
938
|
|
|
827
|
-
const
|
|
828
|
-
this.
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
const
|
|
832
|
-
this.
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
939
|
+
const audioStreams = this.getStreamsFromSets_(
|
|
940
|
+
this.config_.disableAudio,
|
|
941
|
+
normalAdaptationSets,
|
|
942
|
+
ContentType.AUDIO);
|
|
943
|
+
const videoStreams = this.getStreamsFromSets_(
|
|
944
|
+
this.config_.disableVideo,
|
|
945
|
+
normalAdaptationSets,
|
|
946
|
+
ContentType.VIDEO);
|
|
947
|
+
const textStreams = this.getStreamsFromSets_(
|
|
948
|
+
this.config_.disableText,
|
|
949
|
+
normalAdaptationSets,
|
|
950
|
+
ContentType.TEXT);
|
|
951
|
+
const imageStreams = this.getStreamsFromSets_(
|
|
952
|
+
this.config_.disableThumbnails,
|
|
953
|
+
normalAdaptationSets,
|
|
954
|
+
ContentType.IMAGE);
|
|
955
|
+
|
|
956
|
+
if (videoStreams.length === 0 && audioStreams.length === 0) {
|
|
837
957
|
throw new shaka.util.Error(
|
|
838
958
|
shaka.util.Error.Severity.CRITICAL,
|
|
839
959
|
shaka.util.Error.Category.MANIFEST,
|
|
840
|
-
shaka.util.Error.Code.DASH_EMPTY_PERIOD
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
const audioStreams = [];
|
|
844
|
-
for (const audioSet of audioSets) {
|
|
845
|
-
audioStreams.push(...audioSet.streams);
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
const videoStreams = [];
|
|
849
|
-
for (const videoSet of videoSets) {
|
|
850
|
-
videoStreams.push(...videoSet.streams);
|
|
851
|
-
}
|
|
852
|
-
|
|
853
|
-
const textStreams = [];
|
|
854
|
-
for (const textSet of textSets) {
|
|
855
|
-
textStreams.push(...textSet.streams);
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
const imageStreams = [];
|
|
859
|
-
for (const imageSet of imageSets) {
|
|
860
|
-
imageStreams.push(...imageSet.streams);
|
|
960
|
+
shaka.util.Error.Code.DASH_EMPTY_PERIOD,
|
|
961
|
+
);
|
|
861
962
|
}
|
|
862
963
|
|
|
863
964
|
return {
|
|
@@ -870,15 +971,26 @@ shaka.dash.DashParser = class {
|
|
|
870
971
|
}
|
|
871
972
|
|
|
872
973
|
/**
|
|
974
|
+
* Gets the streams from the given sets or returns an empty array if disabled
|
|
975
|
+
* or no streams are found.
|
|
976
|
+
* @param {boolean} disabled
|
|
873
977
|
* @param {!Array.<!shaka.dash.DashParser.AdaptationInfo>} adaptationSets
|
|
874
|
-
* @param {string}
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
978
|
+
* @param {string} contentType
|
|
979
|
+
@private
|
|
980
|
+
*/
|
|
981
|
+
getStreamsFromSets_(disabled, adaptationSets, contentType) {
|
|
982
|
+
if (disabled || !adaptationSets.length) {
|
|
983
|
+
return [];
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
return adaptationSets.reduce((all, part) => {
|
|
987
|
+
if (part.contentType != contentType) {
|
|
988
|
+
return all;
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
all.push(...part.streams);
|
|
992
|
+
return all;
|
|
993
|
+
}, []);
|
|
882
994
|
}
|
|
883
995
|
|
|
884
996
|
/**
|
|
@@ -966,6 +1078,7 @@ shaka.dash.DashParser = class {
|
|
|
966
1078
|
XmlUtils.findChildren(elem, 'EssentialProperty');
|
|
967
1079
|
// ID of real AdaptationSet if this is a trick mode set:
|
|
968
1080
|
let trickModeFor = null;
|
|
1081
|
+
let isFastSwitching = false;
|
|
969
1082
|
let unrecognizedEssentialProperty = false;
|
|
970
1083
|
for (const prop of essentialProperties) {
|
|
971
1084
|
const schemeId = prop.getAttribute('schemeIdUri');
|
|
@@ -978,6 +1091,8 @@ shaka.dash.DashParser = class {
|
|
|
978
1091
|
} else if (schemeId == colourPrimariesScheme ||
|
|
979
1092
|
schemeId == matrixCoefficientsScheme) {
|
|
980
1093
|
continue;
|
|
1094
|
+
} else if (schemeId == 'urn:mpeg:dash:ssr:2023') {
|
|
1095
|
+
isFastSwitching = true;
|
|
981
1096
|
} else {
|
|
982
1097
|
unrecognizedEssentialProperty = true;
|
|
983
1098
|
}
|
|
@@ -1135,6 +1250,7 @@ shaka.dash.DashParser = class {
|
|
|
1135
1250
|
closedCaptions, representation, accessibilityPurpose);
|
|
1136
1251
|
if (parsedRepresentation) {
|
|
1137
1252
|
parsedRepresentation.hdr = parsedRepresentation.hdr || videoRange;
|
|
1253
|
+
parsedRepresentation.fastSwitching = isFastSwitching;
|
|
1138
1254
|
}
|
|
1139
1255
|
return parsedRepresentation;
|
|
1140
1256
|
}).filter((s) => !!s);
|
|
@@ -1169,6 +1285,9 @@ shaka.dash.DashParser = class {
|
|
|
1169
1285
|
}
|
|
1170
1286
|
}
|
|
1171
1287
|
|
|
1288
|
+
const adaptationId = context.adaptationSet.id ||
|
|
1289
|
+
('__fake__' + this.globalId_++);
|
|
1290
|
+
|
|
1172
1291
|
for (const stream of streams) {
|
|
1173
1292
|
// Some DRM license providers require that we have a default
|
|
1174
1293
|
// key ID from the manifest in the wrapped license request.
|
|
@@ -1178,6 +1297,9 @@ shaka.dash.DashParser = class {
|
|
|
1178
1297
|
new Set([...drmInfo.keyIds, ...stream.keyIds]) :
|
|
1179
1298
|
drmInfo.keyIds || stream.keyIds;
|
|
1180
1299
|
}
|
|
1300
|
+
if (this.config_.dash.enableAudioGroups) {
|
|
1301
|
+
stream.groupId = adaptationId;
|
|
1302
|
+
}
|
|
1181
1303
|
}
|
|
1182
1304
|
|
|
1183
1305
|
const repIds = representations
|
|
@@ -1185,7 +1307,7 @@ shaka.dash.DashParser = class {
|
|
|
1185
1307
|
.filter(shaka.util.Functional.isNotNull);
|
|
1186
1308
|
|
|
1187
1309
|
return {
|
|
1188
|
-
id:
|
|
1310
|
+
id: adaptationId,
|
|
1189
1311
|
contentType: context.adaptationSet.contentType,
|
|
1190
1312
|
language: language,
|
|
1191
1313
|
main: main,
|
|
@@ -1250,29 +1372,69 @@ shaka.dash.DashParser = class {
|
|
|
1250
1372
|
const isImage = contentType == ContentType.IMAGE;
|
|
1251
1373
|
|
|
1252
1374
|
try {
|
|
1375
|
+
/** @type {shaka.extern.aes128Key|undefined} */
|
|
1376
|
+
let aes128Key = undefined;
|
|
1377
|
+
if (contentProtection.aes128Info) {
|
|
1378
|
+
const getBaseUris = context.representation.getBaseUris;
|
|
1379
|
+
const uris = shaka.util.ManifestParserUtils.resolveUris(
|
|
1380
|
+
getBaseUris(), [contentProtection.aes128Info.keyUri]);
|
|
1381
|
+
const requestType = shaka.net.NetworkingEngine.RequestType.KEY;
|
|
1382
|
+
const request = shaka.net.NetworkingEngine.makeRequest(
|
|
1383
|
+
uris, this.config_.retryParameters);
|
|
1384
|
+
|
|
1385
|
+
aes128Key = {
|
|
1386
|
+
method: 'AES-128',
|
|
1387
|
+
iv: contentProtection.aes128Info.iv,
|
|
1388
|
+
firstMediaSequenceNumber: 0,
|
|
1389
|
+
};
|
|
1390
|
+
|
|
1391
|
+
// Don't download the key object until the segment is parsed, to
|
|
1392
|
+
// avoid a startup delay for long manifests with lots of keys.
|
|
1393
|
+
aes128Key.fetchKey = async () => {
|
|
1394
|
+
const keyResponse =
|
|
1395
|
+
await this.makeNetworkRequest_(request, requestType);
|
|
1396
|
+
|
|
1397
|
+
// keyResponse.status is undefined when URI is
|
|
1398
|
+
// "data:text/plain;base64,"
|
|
1399
|
+
if (!keyResponse.data || keyResponse.data.byteLength != 16) {
|
|
1400
|
+
throw new shaka.util.Error(
|
|
1401
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
1402
|
+
shaka.util.Error.Category.MANIFEST,
|
|
1403
|
+
shaka.util.Error.Code.AES_128_INVALID_KEY_LENGTH);
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
const algorithm = {
|
|
1407
|
+
name: 'AES-CBC',
|
|
1408
|
+
};
|
|
1409
|
+
aes128Key.cryptoKey = await window.crypto.subtle.importKey(
|
|
1410
|
+
'raw', keyResponse.data, algorithm, true, ['decrypt']);
|
|
1411
|
+
aes128Key.fetchKey = undefined; // No longer needed.
|
|
1412
|
+
};
|
|
1413
|
+
}
|
|
1253
1414
|
const requestSegment = (uris, startByte, endByte, isInit) => {
|
|
1254
1415
|
return this.requestSegment_(uris, startByte, endByte, isInit);
|
|
1255
1416
|
};
|
|
1256
1417
|
if (context.representation.segmentBase) {
|
|
1257
1418
|
streamInfo = shaka.dash.SegmentBase.createStreamInfo(
|
|
1258
|
-
context, requestSegment);
|
|
1419
|
+
context, requestSegment, aes128Key);
|
|
1259
1420
|
} else if (context.representation.segmentList) {
|
|
1260
1421
|
streamInfo = shaka.dash.SegmentList.createStreamInfo(
|
|
1261
|
-
context, this.streamMap_);
|
|
1422
|
+
context, this.streamMap_, aes128Key);
|
|
1262
1423
|
} else if (context.representation.segmentTemplate) {
|
|
1263
1424
|
const hasManifest = !!this.manifest_;
|
|
1264
1425
|
|
|
1265
1426
|
streamInfo = shaka.dash.SegmentTemplate.createStreamInfo(
|
|
1266
1427
|
context, requestSegment, this.streamMap_, hasManifest,
|
|
1267
|
-
this.config_.dash.initialSegmentLimit, this.periodDurations_
|
|
1428
|
+
this.config_.dash.initialSegmentLimit, this.periodDurations_,
|
|
1429
|
+
aes128Key);
|
|
1268
1430
|
} else {
|
|
1269
1431
|
goog.asserts.assert(isText,
|
|
1270
1432
|
'Must have Segment* with non-text streams.');
|
|
1271
1433
|
|
|
1272
|
-
const baseUris = context.representation.baseUris;
|
|
1273
1434
|
const duration = context.periodInfo.duration || 0;
|
|
1274
1435
|
streamInfo = {
|
|
1275
1436
|
generateSegmentIndex: () => {
|
|
1437
|
+
const baseUris = context.representation.getBaseUris();
|
|
1276
1438
|
return Promise.resolve(shaka.media.SegmentIndex.forSingleSegment(
|
|
1277
1439
|
periodStart, duration, baseUris));
|
|
1278
1440
|
},
|
|
@@ -1363,6 +1525,7 @@ shaka.dash.DashParser = class {
|
|
|
1363
1525
|
stream = {
|
|
1364
1526
|
id: this.globalId_++,
|
|
1365
1527
|
originalId: context.representation.id,
|
|
1528
|
+
groupId: null,
|
|
1366
1529
|
createSegmentIndex: () => Promise.resolve(),
|
|
1367
1530
|
closeSegmentIndex: () => {
|
|
1368
1531
|
if (stream.segmentIndex) {
|
|
@@ -1397,10 +1560,12 @@ shaka.dash.DashParser = class {
|
|
|
1397
1560
|
spatialAudio,
|
|
1398
1561
|
closedCaptions,
|
|
1399
1562
|
hdr,
|
|
1563
|
+
videoLayout: undefined,
|
|
1400
1564
|
tilesLayout,
|
|
1401
1565
|
matchedStreams: [],
|
|
1402
1566
|
accessibilityPurpose,
|
|
1403
1567
|
external: false,
|
|
1568
|
+
fastSwitching: false,
|
|
1404
1569
|
};
|
|
1405
1570
|
}
|
|
1406
1571
|
|
|
@@ -1456,6 +1621,8 @@ shaka.dash.DashParser = class {
|
|
|
1456
1621
|
return;
|
|
1457
1622
|
}
|
|
1458
1623
|
|
|
1624
|
+
this.playerInterface_.onManifestUpdated();
|
|
1625
|
+
|
|
1459
1626
|
this.setUpdateTimer_(updateDelay);
|
|
1460
1627
|
}
|
|
1461
1628
|
|
|
@@ -1471,8 +1638,8 @@ shaka.dash.DashParser = class {
|
|
|
1471
1638
|
// NOTE: An updatePeriod_ of -1 means the attribute was missing.
|
|
1472
1639
|
// An attribute which is present and set to 0 should still result in
|
|
1473
1640
|
// periodic updates. For more, see:
|
|
1474
|
-
// https://github.com/
|
|
1475
|
-
if (this.updatePeriod_
|
|
1641
|
+
// https://github.com/Dash-Industry-Forum/Guidelines-TimingModel/issues/48
|
|
1642
|
+
if (this.updatePeriod_ <= 0) {
|
|
1476
1643
|
return;
|
|
1477
1644
|
}
|
|
1478
1645
|
|
|
@@ -1490,13 +1657,13 @@ shaka.dash.DashParser = class {
|
|
|
1490
1657
|
*
|
|
1491
1658
|
* @param {!Element} elem
|
|
1492
1659
|
* @param {?shaka.dash.DashParser.InheritanceFrame} parent
|
|
1493
|
-
* @param {Array.<string>}
|
|
1660
|
+
* @param {?function():!Array.<string>} getBaseUris
|
|
1494
1661
|
* @return {shaka.dash.DashParser.InheritanceFrame}
|
|
1495
1662
|
* @private
|
|
1496
1663
|
*/
|
|
1497
|
-
createFrame_(elem, parent,
|
|
1498
|
-
goog.asserts.assert(parent ||
|
|
1499
|
-
'Must provide either parent or
|
|
1664
|
+
createFrame_(elem, parent, getBaseUris) {
|
|
1665
|
+
goog.asserts.assert(parent || getBaseUris,
|
|
1666
|
+
'Must provide either parent or getBaseUris');
|
|
1500
1667
|
const ManifestParserUtils = shaka.util.ManifestParserUtils;
|
|
1501
1668
|
const XmlUtils = shaka.util.XmlUtils;
|
|
1502
1669
|
parent = parent || /** @type {shaka.dash.DashParser.InheritanceFrame} */ ({
|
|
@@ -1509,14 +1676,44 @@ shaka.dash.DashParser = class {
|
|
|
1509
1676
|
numChannels: null,
|
|
1510
1677
|
audioSamplingRate: null,
|
|
1511
1678
|
availabilityTimeOffset: 0,
|
|
1679
|
+
segmentSequenceCadence: 0,
|
|
1512
1680
|
});
|
|
1513
|
-
|
|
1681
|
+
getBaseUris = getBaseUris || parent.getBaseUris;
|
|
1514
1682
|
|
|
1515
1683
|
const parseNumber = XmlUtils.parseNonNegativeInt;
|
|
1516
1684
|
const evalDivision = XmlUtils.evalDivision;
|
|
1517
1685
|
|
|
1686
|
+
const id = elem.getAttribute('id');
|
|
1518
1687
|
const uriObjs = XmlUtils.findChildren(elem, 'BaseURL');
|
|
1519
|
-
|
|
1688
|
+
let calculatedBaseUris;
|
|
1689
|
+
let someLocationValid = false;
|
|
1690
|
+
if (this.contentSteeringManager_) {
|
|
1691
|
+
for (const uriObj of uriObjs) {
|
|
1692
|
+
const serviceLocation = uriObj.getAttribute('serviceLocation');
|
|
1693
|
+
const uri = XmlUtils.getContents(uriObj);
|
|
1694
|
+
if (serviceLocation && uri) {
|
|
1695
|
+
this.contentSteeringManager_.addLocation(
|
|
1696
|
+
id, serviceLocation, uri);
|
|
1697
|
+
someLocationValid = true;
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
if (!someLocationValid || !this.contentSteeringManager_) {
|
|
1702
|
+
calculatedBaseUris = uriObjs.map(XmlUtils.getContents);
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
const getFrameUris = () => {
|
|
1706
|
+
if (!uriObjs.length) {
|
|
1707
|
+
return [];
|
|
1708
|
+
}
|
|
1709
|
+
if (this.contentSteeringManager_ && someLocationValid) {
|
|
1710
|
+
return this.contentSteeringManager_.getLocations(id);
|
|
1711
|
+
}
|
|
1712
|
+
if (calculatedBaseUris) {
|
|
1713
|
+
return calculatedBaseUris;
|
|
1714
|
+
}
|
|
1715
|
+
return [];
|
|
1716
|
+
};
|
|
1520
1717
|
|
|
1521
1718
|
let contentType = elem.getAttribute('contentType') || parent.contentType;
|
|
1522
1719
|
const mimeType = elem.getAttribute('mimeType') || parent.mimeType;
|
|
@@ -1559,8 +1756,20 @@ shaka.dash.DashParser = class {
|
|
|
1559
1756
|
const availabilityTimeOffset = parent.availabilityTimeOffset + baseUriAto +
|
|
1560
1757
|
segmentBaseAto + segmentTemplateAto;
|
|
1561
1758
|
|
|
1759
|
+
let segmentSequenceCadence = null;
|
|
1760
|
+
const segmentSequenceProperties =
|
|
1761
|
+
XmlUtils.findChild(elem, 'SegmentSequenceProperties');
|
|
1762
|
+
if (segmentSequenceProperties) {
|
|
1763
|
+
const sap = XmlUtils.findChild(segmentSequenceProperties, 'SAP');
|
|
1764
|
+
if (sap) {
|
|
1765
|
+
segmentSequenceCadence = XmlUtils.parseAttr(sap, 'cadence',
|
|
1766
|
+
XmlUtils.parseInt);
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1562
1770
|
return {
|
|
1563
|
-
|
|
1771
|
+
getBaseUris:
|
|
1772
|
+
() => ManifestParserUtils.resolveUris(getBaseUris(), getFrameUris()),
|
|
1564
1773
|
segmentBase: segmentBase || parent.segmentBase,
|
|
1565
1774
|
segmentList:
|
|
1566
1775
|
XmlUtils.findChild(elem, 'SegmentList') || parent.segmentList,
|
|
@@ -1573,11 +1782,13 @@ shaka.dash.DashParser = class {
|
|
|
1573
1782
|
frameRate: frameRate,
|
|
1574
1783
|
pixelAspectRatio: pixelAspectRatio,
|
|
1575
1784
|
emsgSchemeIdUris: emsgSchemeIdUris,
|
|
1576
|
-
id:
|
|
1785
|
+
id: id,
|
|
1577
1786
|
language: elem.getAttribute('lang'),
|
|
1578
1787
|
numChannels: numChannels,
|
|
1579
1788
|
audioSamplingRate: audioSamplingRate,
|
|
1580
1789
|
availabilityTimeOffset: availabilityTimeOffset,
|
|
1790
|
+
segmentSequenceCadence:
|
|
1791
|
+
segmentSequenceCadence || parent.segmentSequenceCadence,
|
|
1581
1792
|
};
|
|
1582
1793
|
}
|
|
1583
1794
|
|
|
@@ -1747,15 +1958,15 @@ shaka.dash.DashParser = class {
|
|
|
1747
1958
|
/**
|
|
1748
1959
|
* Makes a request to the given URI and calculates the clock offset.
|
|
1749
1960
|
*
|
|
1750
|
-
* @param {
|
|
1961
|
+
* @param {function():!Array.<string>} getBaseUris
|
|
1751
1962
|
* @param {string} uri
|
|
1752
1963
|
* @param {string} method
|
|
1753
1964
|
* @return {!Promise.<number>}
|
|
1754
1965
|
* @private
|
|
1755
1966
|
*/
|
|
1756
|
-
async requestForTiming_(
|
|
1967
|
+
async requestForTiming_(getBaseUris, uri, method) {
|
|
1757
1968
|
const requestUris =
|
|
1758
|
-
shaka.util.ManifestParserUtils.resolveUris(
|
|
1969
|
+
shaka.util.ManifestParserUtils.resolveUris(getBaseUris(), [uri]);
|
|
1759
1970
|
const request = shaka.net.NetworkingEngine.makeRequest(
|
|
1760
1971
|
requestUris, this.config_.retryParameters);
|
|
1761
1972
|
request.method = method;
|
|
@@ -1788,12 +1999,12 @@ shaka.dash.DashParser = class {
|
|
|
1788
1999
|
/**
|
|
1789
2000
|
* Parses an array of UTCTiming elements.
|
|
1790
2001
|
*
|
|
1791
|
-
* @param {
|
|
2002
|
+
* @param {function():!Array.<string>} getBaseUris
|
|
1792
2003
|
* @param {!Array.<!Element>} elems
|
|
1793
2004
|
* @return {!Promise.<number>}
|
|
1794
2005
|
* @private
|
|
1795
2006
|
*/
|
|
1796
|
-
async parseUtcTiming_(
|
|
2007
|
+
async parseUtcTiming_(getBaseUris, elems) {
|
|
1797
2008
|
const schemesAndValues = elems.map((elem) => {
|
|
1798
2009
|
return {
|
|
1799
2010
|
scheme: elem.getAttribute('schemeIdUri'),
|
|
@@ -1822,13 +2033,13 @@ shaka.dash.DashParser = class {
|
|
|
1822
2033
|
case 'urn:mpeg:dash:utc:http-head:2014':
|
|
1823
2034
|
case 'urn:mpeg:dash:utc:http-head:2012':
|
|
1824
2035
|
// eslint-disable-next-line no-await-in-loop
|
|
1825
|
-
return await this.requestForTiming_(
|
|
2036
|
+
return await this.requestForTiming_(getBaseUris, value, 'HEAD');
|
|
1826
2037
|
case 'urn:mpeg:dash:utc:http-xsdate:2014':
|
|
1827
2038
|
case 'urn:mpeg:dash:utc:http-iso:2014':
|
|
1828
2039
|
case 'urn:mpeg:dash:utc:http-xsdate:2012':
|
|
1829
2040
|
case 'urn:mpeg:dash:utc:http-iso:2012':
|
|
1830
2041
|
// eslint-disable-next-line no-await-in-loop
|
|
1831
|
-
return await this.requestForTiming_(
|
|
2042
|
+
return await this.requestForTiming_(getBaseUris, value, 'GET');
|
|
1832
2043
|
case 'urn:mpeg:dash:utc:direct:2014':
|
|
1833
2044
|
case 'urn:mpeg:dash:utc:direct:2012': {
|
|
1834
2045
|
const date = Date.parse(value);
|
|
@@ -1929,10 +2140,8 @@ shaka.dash.DashParser = class {
|
|
|
1929
2140
|
endByte,
|
|
1930
2141
|
this.config_.retryParameters);
|
|
1931
2142
|
|
|
1932
|
-
const
|
|
1933
|
-
|
|
1934
|
-
this.operationManager_.manage(operation);
|
|
1935
|
-
const response = await operation.promise;
|
|
2143
|
+
const response = await this.makeNetworkRequest_(
|
|
2144
|
+
request, requestType, {type});
|
|
1936
2145
|
return response.data;
|
|
1937
2146
|
}
|
|
1938
2147
|
|
|
@@ -1958,6 +2167,24 @@ shaka.dash.DashParser = class {
|
|
|
1958
2167
|
// types well.
|
|
1959
2168
|
return mimeType.split('/')[0];
|
|
1960
2169
|
}
|
|
2170
|
+
|
|
2171
|
+
|
|
2172
|
+
/**
|
|
2173
|
+
* Create a networking request. This will manage the request using the
|
|
2174
|
+
* parser's operation manager.
|
|
2175
|
+
*
|
|
2176
|
+
* @param {shaka.extern.Request} request
|
|
2177
|
+
* @param {shaka.net.NetworkingEngine.RequestType} type
|
|
2178
|
+
* @param {shaka.extern.RequestContext=} context
|
|
2179
|
+
* @return {!Promise.<shaka.extern.Response>}
|
|
2180
|
+
* @private
|
|
2181
|
+
*/
|
|
2182
|
+
makeNetworkRequest_(request, type, context) {
|
|
2183
|
+
const op = this.playerInterface_.networkingEngine.request(
|
|
2184
|
+
type, request, context);
|
|
2185
|
+
this.operationManager_.manage(op);
|
|
2186
|
+
return op.promise;
|
|
2187
|
+
}
|
|
1961
2188
|
};
|
|
1962
2189
|
|
|
1963
2190
|
|
|
@@ -1975,7 +2202,7 @@ shaka.dash.DashParser.RequestSegmentCallback;
|
|
|
1975
2202
|
* segmentBase: Element,
|
|
1976
2203
|
* segmentList: Element,
|
|
1977
2204
|
* segmentTemplate: Element,
|
|
1978
|
-
*
|
|
2205
|
+
* getBaseUris: function():!Array.<string>,
|
|
1979
2206
|
* width: (number|undefined),
|
|
1980
2207
|
* height: (number|undefined),
|
|
1981
2208
|
* contentType: string,
|
|
@@ -1988,7 +2215,8 @@ shaka.dash.DashParser.RequestSegmentCallback;
|
|
|
1988
2215
|
* language: ?string,
|
|
1989
2216
|
* numChannels: ?number,
|
|
1990
2217
|
* audioSamplingRate: ?number,
|
|
1991
|
-
* availabilityTimeOffset: number
|
|
2218
|
+
* availabilityTimeOffset: number,
|
|
2219
|
+
* segmentSequenceCadence: number
|
|
1992
2220
|
* }}
|
|
1993
2221
|
*
|
|
1994
2222
|
* @description
|
|
@@ -2001,8 +2229,8 @@ shaka.dash.DashParser.RequestSegmentCallback;
|
|
|
2001
2229
|
* The XML node for SegmentList.
|
|
2002
2230
|
* @property {Element} segmentTemplate
|
|
2003
2231
|
* The XML node for SegmentTemplate.
|
|
2004
|
-
* @property {
|
|
2005
|
-
*
|
|
2232
|
+
* @property {function():!Array.<string>} getBaseUris
|
|
2233
|
+
* Function than returns an array of absolute base URIs for the frame.
|
|
2006
2234
|
* @property {(number|undefined)} width
|
|
2007
2235
|
* The inherited width value.
|
|
2008
2236
|
* @property {(number|undefined)} height
|
|
@@ -2029,6 +2257,9 @@ shaka.dash.DashParser.RequestSegmentCallback;
|
|
|
2029
2257
|
* Specifies the maximum sampling rate of the content, or null if unknown.
|
|
2030
2258
|
* @property {number} availabilityTimeOffset
|
|
2031
2259
|
* Specifies the total availabilityTimeOffset of the segment, or 0 if unknown.
|
|
2260
|
+
* @property {number} segmentSequenceCadence
|
|
2261
|
+
* Specifies the cadence of independent segments in Segment Sequence
|
|
2262
|
+
* Representation.
|
|
2032
2263
|
*/
|
|
2033
2264
|
shaka.dash.DashParser.InheritanceFrame;
|
|
2034
2265
|
|
|
@@ -2162,8 +2393,6 @@ shaka.dash.DashParser.GenerateSegmentIndexFunction;
|
|
|
2162
2393
|
shaka.dash.DashParser.StreamInfo;
|
|
2163
2394
|
|
|
2164
2395
|
|
|
2165
|
-
shaka.media.ManifestParser.registerParserByExtension(
|
|
2166
|
-
'mpd', () => new shaka.dash.DashParser());
|
|
2167
2396
|
shaka.media.ManifestParser.registerParserByMime(
|
|
2168
2397
|
'application/dash+xml', () => new shaka.dash.DashParser());
|
|
2169
2398
|
shaka.media.ManifestParser.registerParserByMime(
|