shaka-player 3.2.1 → 3.3.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/.github/ISSUE_TEMPLATE/feature_request.md +1 -1
- package/.github/ISSUE_TEMPLATE/question.md +1 -1
- package/AUTHORS +9 -5
- package/CHANGELOG.md +358 -0
- package/CONTRIBUTORS +7 -2
- package/build/conformance.textproto +183 -169
- package/build/generateExterns.js +1 -1
- package/build/types/core +3 -0
- package/build/types/offline +1 -0
- package/build/types/polyfill +1 -0
- package/build/types/ui +2 -0
- package/demo/common/assets.js +19 -1
- package/demo/common/message_ids.js +13 -1
- package/demo/config.js +31 -1
- package/demo/index.html +1 -1
- package/demo/locales/en.json +12 -0
- package/demo/locales/source.json +48 -0
- package/dist/controls.css +26 -2
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +20 -17
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +20 -17
- package/dist/demo.compiled.map +3 -3
- package/dist/deps.js +19 -12
- package/dist/locales.js +39 -37
- package/dist/receiver.compiled.debug.js +12 -10
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +12 -10
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +231 -18
- package/dist/shaka-player.compiled.debug.d.ts +231 -18
- package/dist/shaka-player.compiled.debug.externs.js +279 -8
- package/dist/shaka-player.compiled.debug.js +512 -449
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +279 -8
- package/dist/shaka-player.compiled.js +854 -821
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +247 -19
- package/dist/shaka-player.ui.debug.d.ts +247 -19
- package/dist/shaka-player.ui.debug.externs.js +307 -9
- package/dist/shaka-player.ui.debug.js +662 -580
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +307 -9
- package/dist/shaka-player.ui.js +1047 -1000
- package/dist/shaka-player.ui.map +4 -4
- package/docs/design/bg-fetch-after.gv +29 -0
- package/docs/design/bg-fetch-after.gv.png +0 -0
- package/docs/design/bg-fetch-before.gv +18 -0
- package/docs/design/bg-fetch-before.gv.png +0 -0
- package/docs/design/bg-fetch.md +134 -0
- package/docs/tutorials/blob-url.md +15 -0
- package/docs/tutorials/fairplay.md +1 -1
- package/docs/tutorials/index.json +1 -0
- package/docs/tutorials/ui-customization.md +66 -0
- package/docs/tutorials/ui.md +5 -5
- package/externs/cmcd.js +186 -0
- package/externs/ima.js +3 -0
- package/externs/shaka/ads.js +5 -0
- package/externs/shaka/manifest.js +12 -1
- package/externs/shaka/manifest_parser.js +10 -1
- package/externs/shaka/net.js +20 -4
- package/externs/shaka/offline.js +31 -2
- package/externs/shaka/player.js +138 -5
- package/externs/shaka/text.js +24 -0
- package/externs/webcrypto.js +18 -0
- package/karma.conf.js +1 -0
- package/lib/abr/ewma.js +14 -0
- package/lib/abr/ewma_bandwidth_estimator.js +16 -2
- package/lib/abr/simple_abr_manager.js +6 -0
- package/lib/ads/client_side_ad.js +8 -0
- package/lib/ads/client_side_ad_manager.js +54 -90
- package/lib/ads/server_side_ad.js +7 -0
- package/lib/ads/server_side_ad_manager.js +7 -10
- package/lib/cast/cast_proxy.js +3 -2
- package/lib/cast/cast_receiver.js +2 -1
- package/lib/cast/cast_sender.js +2 -2
- package/lib/cast/cast_utils.js +1 -0
- package/lib/dash/dash_parser.js +141 -16
- package/lib/dash/segment_base.js +25 -1
- package/lib/dash/segment_list.js +19 -10
- package/lib/dash/segment_template.js +24 -11
- package/lib/hls/hls_parser.js +146 -40
- package/lib/media/drm_engine.js +7 -0
- package/lib/media/gap_jumping_controller.js +4 -2
- package/lib/media/media_source_engine.js +1 -2
- package/lib/media/quality_observer.js +291 -0
- package/lib/media/segment_index.js +8 -1
- package/lib/media/segment_reference.js +37 -4
- package/lib/media/streaming_engine.js +49 -7
- package/lib/net/http_fetch_plugin.js +31 -11
- package/lib/net/http_plugin_utils.js +1 -0
- package/lib/net/http_xhr_plugin.js +40 -14
- package/lib/net/networking_engine.js +83 -19
- package/lib/offline/download_info.js +68 -0
- package/lib/offline/download_manager.js +13 -5
- package/lib/offline/indexeddb/base_storage_cell.js +35 -0
- package/lib/offline/indexeddb/storage_mechanism.js +1 -1
- package/lib/offline/indexeddb/v5_storage_cell.js +5 -0
- package/lib/offline/storage.js +393 -284
- package/lib/offline/stored_content_utils.js +2 -0
- package/lib/player.js +249 -43
- package/lib/polyfill/media_capabilities.js +36 -15
- package/lib/polyfill/mediasource.js +6 -0
- package/lib/polyfill/orientation.js +1 -1
- package/lib/polyfill/patchedmediakeys_apple.js +4 -4
- package/lib/polyfill/patchedmediakeys_ms.js +4 -4
- package/lib/polyfill/patchedmediakeys_webkit.js +4 -4
- package/lib/polyfill/random_uuid.js +52 -0
- package/lib/text/cue.js +18 -0
- package/lib/text/mp4_ttml_parser.js +3 -0
- package/lib/text/text_engine.js +14 -2
- package/lib/text/ttml_text_parser.js +114 -60
- package/lib/text/ui_text_displayer.js +95 -41
- package/lib/util/cmcd_manager.js +672 -0
- package/lib/util/error.js +6 -0
- package/lib/util/fake_event.js +53 -7
- package/lib/util/language_utils.js +12 -0
- package/lib/util/mutex.js +52 -0
- package/lib/util/periods.js +102 -65
- package/lib/util/platform.js +13 -1
- package/lib/util/player_configuration.js +18 -0
- package/lib/util/stream_utils.js +99 -10
- package/lib/util/xml_utils.js +19 -0
- package/package.json +2 -2
- package/shaka-player.uncompiled.js +3 -0
- package/test/cast/cast_proxy_unit.js +12 -6
- package/test/cast/cast_utils_unit.js +1 -1
- package/test/dash/dash_parser_content_protection_unit.js +2 -0
- package/test/dash/dash_parser_live_unit.js +101 -1
- package/test/dash/dash_parser_manifest_unit.js +222 -2
- package/test/dash/dash_parser_segment_base_unit.js +2 -0
- package/test/dash/dash_parser_segment_list_unit.js +2 -1
- package/test/dash/dash_parser_segment_template_unit.js +2 -1
- package/test/hls/hls_live_unit.js +2 -0
- package/test/hls/hls_parser_unit.js +7 -1
- package/test/media/closed_caption_parser_unit.js +6 -1
- package/test/media/drm_engine_unit.js +47 -3
- package/test/media/quality_observer_unit.js +139 -0
- package/test/media/segment_reference_unit.js +16 -1
- package/test/media/streaming_engine_integration.js +4 -2
- package/test/media/streaming_engine_unit.js +147 -0
- package/test/net/http_plugin_unit.js +20 -15
- package/test/offline/storage_integration.js +108 -4
- package/test/player_integration.js +178 -8
- package/test/player_src_equals_integration.js +41 -8
- package/test/player_unit.js +19 -9
- package/test/test/assets/3675/chunk-stream0-00001.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00002.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00003.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00004.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00005.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00006.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00007.m4s +0 -0
- package/test/test/assets/3675/dash_0.mpd +30 -0
- package/test/test/assets/3675/dash_1.mpd +30 -0
- package/test/test/assets/3675/dash_2.mpd +30 -0
- package/test/test/assets/3675/dash_3.mpd +30 -0
- package/test/test/assets/3675/dash_4.mpd +30 -0
- package/test/test/assets/3675/dash_5.mpd +26 -0
- package/test/test/assets/3675/init-stream0.m4s +0 -0
- package/test/test/assets/chapters.vtt +2 -2
- package/test/test/assets/chapters2.vtt +10 -0
- package/test/test/util/dash_parser_util.js +4 -0
- package/test/test/util/fake_ad.js +7 -0
- package/test/test/util/fake_ad_manager.js +1 -1
- package/test/test/util/fake_drm_engine.js +9 -2
- package/test/test/util/manifest_generator.js +3 -2
- package/test/test/util/test_scheme.js +14 -1
- package/test/test/util/ttml_utils.js +81 -0
- package/test/text/mp4_ttml_parser_unit.js +11 -18
- package/test/text/ttml_text_parser_unit.js +552 -227
- package/test/text/ui_text_displayer_unit.js +29 -17
- package/test/ui/localization_unit.js +15 -14
- package/test/ui/text_displayer_layout_unit.js +13 -1
- package/test/ui/ui_unit.js +250 -0
- package/test/util/cmcd_manager_unit.js +291 -0
- package/test/util/stream_utils_unit.js +45 -4
- package/third_party/closure-uri/uri.js +21 -0
- package/ui/airplay_button.js +1 -0
- package/ui/audio_language_selection.js +7 -0
- package/ui/cast_button.js +3 -3
- package/ui/context_menu.js +109 -0
- package/ui/controls.js +45 -13
- package/ui/controls.less +1 -0
- package/ui/enums.js +4 -0
- package/ui/externs/ui.js +28 -1
- package/ui/fast_forward_button.js +14 -5
- package/ui/fullscreen_button.js +1 -0
- package/ui/less/buttons.less +0 -4
- package/ui/less/containers.less +77 -7
- package/ui/less/overflow_menu.less +0 -10
- package/ui/less/tooltip.less +97 -0
- package/ui/locales/en.json +1 -0
- package/ui/locales/ru.json +6 -6
- package/ui/locales/source.json +4 -0
- package/ui/localization.js +28 -51
- package/ui/loop_button.js +5 -0
- package/ui/mute_button.js +2 -1
- package/ui/overflow_menu.js +5 -25
- package/ui/pip_button.js +7 -3
- package/ui/play_button.js +2 -2
- package/ui/playback_rate_selection.js +8 -9
- package/ui/resolution_selection.js +7 -0
- package/ui/rewind_button.js +15 -6
- package/ui/seek_bar.js +4 -2
- package/ui/settings_menu.js +36 -4
- package/ui/small_play_button.js +1 -0
- package/ui/statistics_button.js +253 -0
- package/ui/text_selection.js +12 -4
- package/ui/ui.js +30 -0
- package/ui/volume_bar.js +1 -1
- package/externs/media_capabilities.js +0 -16
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.CmcdManager');
|
|
22
23
|
goog.require('shaka.util.Error');
|
|
23
24
|
goog.require('shaka.util.Functional');
|
|
24
25
|
goog.require('shaka.util.Iterables');
|
|
@@ -58,12 +59,12 @@ shaka.dash.DashParser = class {
|
|
|
58
59
|
this.globalId_ = 1;
|
|
59
60
|
|
|
60
61
|
/**
|
|
61
|
-
* A map of IDs to
|
|
62
|
+
* A map of IDs to Stream objects.
|
|
62
63
|
* ID: Period@id,AdaptationSet@id,@Representation@id
|
|
63
64
|
* e.g.: '1,5,23'
|
|
64
|
-
* @private {!Object.<string, !shaka.
|
|
65
|
+
* @private {!Object.<string, !shaka.extern.Stream>}
|
|
65
66
|
*/
|
|
66
|
-
this.
|
|
67
|
+
this.streamMap_ = {};
|
|
67
68
|
|
|
68
69
|
/**
|
|
69
70
|
* A map of period ids to their durations
|
|
@@ -95,6 +96,18 @@ shaka.dash.DashParser = class {
|
|
|
95
96
|
/** @private {!shaka.util.OperationManager} */
|
|
96
97
|
this.operationManager_ = new shaka.util.OperationManager();
|
|
97
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Largest period start time seen.
|
|
101
|
+
* @private {?number}
|
|
102
|
+
*/
|
|
103
|
+
this.largestPeriodStartTime_ = null;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Period IDs seen in previous manifest.
|
|
107
|
+
* @private {!Array.<number>}
|
|
108
|
+
*/
|
|
109
|
+
this.lastManifestUpdatePeriodIds_ = [];
|
|
110
|
+
|
|
98
111
|
/**
|
|
99
112
|
* The minimum of the availabilityTimeOffset values among the adaptation
|
|
100
113
|
* sets.
|
|
@@ -152,8 +165,10 @@ shaka.dash.DashParser = class {
|
|
|
152
165
|
stop() {
|
|
153
166
|
// When the parser stops, release all segment indexes, which stops their
|
|
154
167
|
// timers, as well.
|
|
155
|
-
for (const
|
|
156
|
-
segmentIndex
|
|
168
|
+
for (const stream of Object.values(this.streamMap_)) {
|
|
169
|
+
if (stream.segmentIndex) {
|
|
170
|
+
stream.segmentIndex.release();
|
|
171
|
+
}
|
|
157
172
|
}
|
|
158
173
|
|
|
159
174
|
if (this.periodCombiner_) {
|
|
@@ -164,7 +179,7 @@ shaka.dash.DashParser = class {
|
|
|
164
179
|
this.config_ = null;
|
|
165
180
|
this.manifestUris_ = [];
|
|
166
181
|
this.manifest_ = null;
|
|
167
|
-
this.
|
|
182
|
+
this.streamMap_ = {};
|
|
168
183
|
this.periodCombiner_ = null;
|
|
169
184
|
|
|
170
185
|
if (this.updateTimer_ != null) {
|
|
@@ -212,6 +227,9 @@ shaka.dash.DashParser = class {
|
|
|
212
227
|
this.manifestUris_, this.config_.retryParameters);
|
|
213
228
|
const networkingEngine = this.playerInterface_.networkingEngine;
|
|
214
229
|
|
|
230
|
+
const format = shaka.util.CmcdManager.StreamingFormat.DASH;
|
|
231
|
+
this.playerInterface_.modifyManifestRequest(request, {format: format});
|
|
232
|
+
|
|
215
233
|
const startTime = Date.now();
|
|
216
234
|
const operation = networkingEngine.request(requestType, request);
|
|
217
235
|
this.operationManager_.manage(operation);
|
|
@@ -366,8 +384,11 @@ shaka.dash.DashParser = class {
|
|
|
366
384
|
// that the complex logic of multi-Period eviction and period-flattening
|
|
367
385
|
// is correct. See also:
|
|
368
386
|
// https://github.com/google/shaka-player/issues/3169#issuecomment-823580634
|
|
369
|
-
for (const
|
|
370
|
-
|
|
387
|
+
for (const stream of Object.values(this.streamMap_)) {
|
|
388
|
+
if (stream.segmentIndex) {
|
|
389
|
+
stream.segmentIndex.evict(
|
|
390
|
+
presentationTimeline.getSegmentAvailabilityStart());
|
|
391
|
+
}
|
|
371
392
|
}
|
|
372
393
|
} else {
|
|
373
394
|
// DASH IOP v3.0 suggests using a default delay between minBufferTime
|
|
@@ -538,6 +559,7 @@ shaka.dash.DashParser = class {
|
|
|
538
559
|
for (const {i, item: elem, next} of enumerate(periodNodes)) {
|
|
539
560
|
const start = /** @type {number} */ (
|
|
540
561
|
XmlUtils.parseAttr(elem, 'start', XmlUtils.parseDuration, prevEnd));
|
|
562
|
+
const periodId = elem.id;
|
|
541
563
|
const givenDuration =
|
|
542
564
|
XmlUtils.parseAttr(elem, 'duration', XmlUtils.parseDuration);
|
|
543
565
|
|
|
@@ -571,6 +593,42 @@ shaka.dash.DashParser = class {
|
|
|
571
593
|
periodDuration = givenDuration;
|
|
572
594
|
}
|
|
573
595
|
|
|
596
|
+
/**
|
|
597
|
+
* This is to improve robustness when the player observes manifest with
|
|
598
|
+
* past periods that are inconsistent to previous ones.
|
|
599
|
+
*
|
|
600
|
+
* This may happen when a CDN or proxy server switches its upstream from
|
|
601
|
+
* one encoder to another redundant encoder.
|
|
602
|
+
*
|
|
603
|
+
* Skip periods that match all of the following criteria:
|
|
604
|
+
* - Start time is earlier than latest period start time ever seen
|
|
605
|
+
* - Period ID is never seen in the previous manifest
|
|
606
|
+
* - Not the last period in the manifest
|
|
607
|
+
*
|
|
608
|
+
* Periods that meet the aforementioned criteria are considered invalid
|
|
609
|
+
* and should be safe to discard.
|
|
610
|
+
*/
|
|
611
|
+
|
|
612
|
+
if (this.largestPeriodStartTime_ !== null &&
|
|
613
|
+
periodId !== null && start !== null &&
|
|
614
|
+
start < this.largestPeriodStartTime_ &&
|
|
615
|
+
!this.lastManifestUpdatePeriodIds_.includes(periodId) &&
|
|
616
|
+
i + 1 != periodNodes.length) {
|
|
617
|
+
shaka.log.debug(
|
|
618
|
+
`Skipping Period with ID ${periodId} as its start time is smaller` +
|
|
619
|
+
' than the largest period start time that has been seen, and ID ' +
|
|
620
|
+
'is unseen before');
|
|
621
|
+
continue;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
// Save maximum period start time if it is the last period
|
|
626
|
+
if (start !== null &&
|
|
627
|
+
(this.largestPeriodStartTime_ === null ||
|
|
628
|
+
start > this.largestPeriodStartTime_)) {
|
|
629
|
+
this.largestPeriodStartTime_ = start;
|
|
630
|
+
}
|
|
631
|
+
|
|
574
632
|
// Parse child nodes.
|
|
575
633
|
const info = {
|
|
576
634
|
start: start,
|
|
@@ -602,6 +660,9 @@ shaka.dash.DashParser = class {
|
|
|
602
660
|
prevEnd = start + periodDuration;
|
|
603
661
|
} // end of period parsing loop
|
|
604
662
|
|
|
663
|
+
// Replace previous seen periods with the current one.
|
|
664
|
+
this.lastManifestUpdatePeriodIds_ = periods.map((el) => el.id);
|
|
665
|
+
|
|
605
666
|
if (presentationDuration != null) {
|
|
606
667
|
if (prevEnd != presentationDuration) {
|
|
607
668
|
shaka.log.warning(
|
|
@@ -813,6 +874,25 @@ shaka.dash.DashParser = class {
|
|
|
813
874
|
}
|
|
814
875
|
}
|
|
815
876
|
|
|
877
|
+
// Parallel for HLS VIDEO-RANGE as defined in DASH-IF IOP v4.3 6.2.5.1.
|
|
878
|
+
let videoRange;
|
|
879
|
+
const videoRangeScheme = 'urn:mpeg:mpegB:cicp:TransferCharacteristics';
|
|
880
|
+
const getVideoRangeFromTransferCharacteristicCICP = (cicp) => {
|
|
881
|
+
switch (cicp) {
|
|
882
|
+
case 1:
|
|
883
|
+
case 6:
|
|
884
|
+
case 13:
|
|
885
|
+
case 14:
|
|
886
|
+
case 15:
|
|
887
|
+
return 'SDR';
|
|
888
|
+
case 16:
|
|
889
|
+
return 'PQ';
|
|
890
|
+
case 18:
|
|
891
|
+
return 'HLG';
|
|
892
|
+
}
|
|
893
|
+
return undefined;
|
|
894
|
+
};
|
|
895
|
+
|
|
816
896
|
const essentialProperties =
|
|
817
897
|
XmlUtils.findChildren(elem, 'EssentialProperty');
|
|
818
898
|
// ID of real AdaptationSet if this is a trick mode set:
|
|
@@ -822,11 +902,26 @@ shaka.dash.DashParser = class {
|
|
|
822
902
|
const schemeId = prop.getAttribute('schemeIdUri');
|
|
823
903
|
if (schemeId == 'http://dashif.org/guidelines/trickmode') {
|
|
824
904
|
trickModeFor = prop.getAttribute('value');
|
|
905
|
+
} else if (schemeId == videoRangeScheme) {
|
|
906
|
+
videoRange = getVideoRangeFromTransferCharacteristicCICP(
|
|
907
|
+
parseInt(prop.getAttribute('value'), 10),
|
|
908
|
+
);
|
|
825
909
|
} else {
|
|
826
910
|
unrecognizedEssentialProperty = true;
|
|
827
911
|
}
|
|
828
912
|
}
|
|
829
913
|
|
|
914
|
+
const supplementalProperties =
|
|
915
|
+
XmlUtils.findChildren(elem, 'SupplementalProperty');
|
|
916
|
+
for (const prop of supplementalProperties) {
|
|
917
|
+
const schemeId = prop.getAttribute('schemeIdUri');
|
|
918
|
+
if (schemeId == videoRangeScheme) {
|
|
919
|
+
videoRange = getVideoRangeFromTransferCharacteristicCICP(
|
|
920
|
+
parseInt(prop.getAttribute('value'), 10),
|
|
921
|
+
);
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
|
|
830
925
|
const accessibilities = XmlUtils.findChildren(elem, 'Accessibility');
|
|
831
926
|
const LanguageUtils = shaka.util.LanguageUtils;
|
|
832
927
|
const closedCaptions = new Map();
|
|
@@ -952,8 +1047,13 @@ shaka.dash.DashParser = class {
|
|
|
952
1047
|
// Parse Representations into Streams.
|
|
953
1048
|
const representations = XmlUtils.findChildren(elem, 'Representation');
|
|
954
1049
|
const streams = representations.map((representation) => {
|
|
955
|
-
|
|
956
|
-
language, label, main, roleValues,
|
|
1050
|
+
const parsedRepresentation = this.parseRepresentation_(context,
|
|
1051
|
+
contentProtection, kind, language, label, main, roleValues,
|
|
1052
|
+
closedCaptions, representation);
|
|
1053
|
+
if (parsedRepresentation) {
|
|
1054
|
+
parsedRepresentation.hdr = parsedRepresentation.hdr || videoRange;
|
|
1055
|
+
}
|
|
1056
|
+
return parsedRepresentation;
|
|
957
1057
|
}).filter((s) => !!s);
|
|
958
1058
|
|
|
959
1059
|
if (streams.length == 0) {
|
|
@@ -1072,11 +1172,12 @@ shaka.dash.DashParser = class {
|
|
|
1072
1172
|
context, requestInitSegment);
|
|
1073
1173
|
} else if (context.representation.segmentList) {
|
|
1074
1174
|
streamInfo = shaka.dash.SegmentList.createStreamInfo(
|
|
1075
|
-
context, this.
|
|
1175
|
+
context, this.streamMap_);
|
|
1076
1176
|
} else if (context.representation.segmentTemplate) {
|
|
1077
1177
|
const hasManifest = !!this.manifest_;
|
|
1178
|
+
|
|
1078
1179
|
streamInfo = shaka.dash.SegmentTemplate.createStreamInfo(
|
|
1079
|
-
context, requestInitSegment, this.
|
|
1180
|
+
context, requestInitSegment, this.streamMap_, hasManifest,
|
|
1080
1181
|
this.config_.dash.initialSegmentLimit, this.periodDurations_);
|
|
1081
1182
|
} else {
|
|
1082
1183
|
goog.asserts.assert(isText,
|
|
@@ -1129,8 +1230,10 @@ shaka.dash.DashParser = class {
|
|
|
1129
1230
|
|
|
1130
1231
|
let forced = false;
|
|
1131
1232
|
if (isText) {
|
|
1132
|
-
// See: https://github.com/google/shaka-player/issues/2122
|
|
1133
|
-
|
|
1233
|
+
// See: https://github.com/google/shaka-player/issues/2122 and
|
|
1234
|
+
// https://github.com/Dash-Industry-Forum/DASH-IF-IOP/issues/165
|
|
1235
|
+
forced = roles.includes('forced_subtitle') ||
|
|
1236
|
+
roles.includes('forced-subtitle');
|
|
1134
1237
|
}
|
|
1135
1238
|
|
|
1136
1239
|
let tilesLayout;
|
|
@@ -1163,13 +1266,29 @@ shaka.dash.DashParser = class {
|
|
|
1163
1266
|
hdr = 'PQ';
|
|
1164
1267
|
}
|
|
1165
1268
|
|
|
1269
|
+
const contextId = context.representation.id ?
|
|
1270
|
+
context.period.id + ',' + context.representation.id : '';
|
|
1271
|
+
|
|
1166
1272
|
/** @type {shaka.extern.Stream} */
|
|
1167
1273
|
const stream = {
|
|
1168
1274
|
id: this.globalId_++,
|
|
1169
1275
|
originalId: context.representation.id,
|
|
1170
1276
|
createSegmentIndex: async () => {
|
|
1171
|
-
|
|
1172
|
-
|
|
1277
|
+
// If we have a stream with the same context id stored in the map
|
|
1278
|
+
// that has no segmentIndex, we should set the segmentIndex for it.
|
|
1279
|
+
const storedInMap = contextId && context.dynamic &&
|
|
1280
|
+
this.streamMap_[contextId];
|
|
1281
|
+
|
|
1282
|
+
const currentStream = storedInMap ? this.streamMap_[contextId] : stream;
|
|
1283
|
+
if (!currentStream.segmentIndex) {
|
|
1284
|
+
currentStream.segmentIndex = await streamInfo.generateSegmentIndex();
|
|
1285
|
+
}
|
|
1286
|
+
},
|
|
1287
|
+
|
|
1288
|
+
closeSegmentIndex: () => {
|
|
1289
|
+
if (stream.segmentIndex) {
|
|
1290
|
+
stream.segmentIndex.release();
|
|
1291
|
+
stream.segmentIndex = null;
|
|
1173
1292
|
}
|
|
1174
1293
|
},
|
|
1175
1294
|
segmentIndex: null,
|
|
@@ -1199,7 +1318,13 @@ shaka.dash.DashParser = class {
|
|
|
1199
1318
|
closedCaptions,
|
|
1200
1319
|
hdr,
|
|
1201
1320
|
tilesLayout,
|
|
1321
|
+
matchedStreams: [],
|
|
1202
1322
|
};
|
|
1323
|
+
|
|
1324
|
+
if (contextId && context.dynamic && !this.streamMap_[contextId]) {
|
|
1325
|
+
this.streamMap_[contextId] = stream;
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1203
1328
|
return stream;
|
|
1204
1329
|
}
|
|
1205
1330
|
|
package/lib/dash/segment_base.js
CHANGED
|
@@ -61,7 +61,9 @@ shaka.dash.SegmentBase = class {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
const getUris = () => resolvedUris;
|
|
64
|
-
|
|
64
|
+
const qualityInfo = shaka.dash.SegmentBase.createQualityInfo(context);
|
|
65
|
+
return new shaka.media.InitSegmentReference(
|
|
66
|
+
getUris, startByte, endByte, qualityInfo);
|
|
65
67
|
}
|
|
66
68
|
|
|
67
69
|
/**
|
|
@@ -346,4 +348,26 @@ shaka.dash.SegmentBase = class {
|
|
|
346
348
|
indexRange.start, indexRange.end,
|
|
347
349
|
scaledPresentationTimeOffset);
|
|
348
350
|
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Create a MediaQualityInfo object from a Context object.
|
|
354
|
+
*
|
|
355
|
+
* @param {!shaka.dash.DashParser.Context} context
|
|
356
|
+
* @return {!shaka.extern.MediaQualityInfo}
|
|
357
|
+
*/
|
|
358
|
+
static createQualityInfo(context) {
|
|
359
|
+
const representation = context.representation;
|
|
360
|
+
return {
|
|
361
|
+
bandwidth: context.bandwidth,
|
|
362
|
+
audioSamplingRate: representation.audioSamplingRate,
|
|
363
|
+
codecs: representation.codecs,
|
|
364
|
+
contentType: representation.contentType,
|
|
365
|
+
frameRate: representation.frameRate || null,
|
|
366
|
+
height: representation.height || null,
|
|
367
|
+
mimeType: representation.mimeType,
|
|
368
|
+
channelsCount: representation.numChannels,
|
|
369
|
+
pixelAspectRatio: representation.pixelAspectRatio || null,
|
|
370
|
+
width: representation.width || null,
|
|
371
|
+
};
|
|
372
|
+
}
|
|
349
373
|
};
|
package/lib/dash/segment_list.js
CHANGED
|
@@ -30,10 +30,10 @@ shaka.dash.SegmentList = class {
|
|
|
30
30
|
* Updates the existing SegmentIndex, if any.
|
|
31
31
|
*
|
|
32
32
|
* @param {shaka.dash.DashParser.Context} context
|
|
33
|
-
* @param {!Object.<string, !shaka.
|
|
33
|
+
* @param {!Object.<string, !shaka.extern.Stream>} streamMap
|
|
34
34
|
* @return {shaka.dash.DashParser.StreamInfo}
|
|
35
35
|
*/
|
|
36
|
-
static createStreamInfo(context,
|
|
36
|
+
static createStreamInfo(context, streamMap) {
|
|
37
37
|
goog.asserts.assert(context.representation.segmentList,
|
|
38
38
|
'Should only be called with SegmentList');
|
|
39
39
|
const SegmentList = shaka.dash.SegmentList;
|
|
@@ -46,11 +46,14 @@ shaka.dash.SegmentList = class {
|
|
|
46
46
|
|
|
47
47
|
/** @type {shaka.media.SegmentIndex} */
|
|
48
48
|
let segmentIndex = null;
|
|
49
|
-
let
|
|
49
|
+
let stream = null;
|
|
50
50
|
if (context.period.id && context.representation.id) {
|
|
51
51
|
// Only check/store the index if period and representation IDs are set.
|
|
52
|
-
id = context.period.id + ',' + context.representation.id;
|
|
53
|
-
|
|
52
|
+
const id = context.period.id + ',' + context.representation.id;
|
|
53
|
+
stream = streamMap[id];
|
|
54
|
+
if (stream) {
|
|
55
|
+
segmentIndex = stream.segmentIndex;
|
|
56
|
+
}
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
const references = SegmentList.createSegmentReferences_(
|
|
@@ -63,12 +66,9 @@ shaka.dash.SegmentList = class {
|
|
|
63
66
|
const start = context.presentationTimeline.getSegmentAvailabilityStart();
|
|
64
67
|
segmentIndex.mergeAndEvict(references, start);
|
|
65
68
|
} else {
|
|
66
|
-
context.presentationTimeline.notifySegments(references);
|
|
67
69
|
segmentIndex = new shaka.media.SegmentIndex(references);
|
|
68
|
-
if (id && context.dynamic) {
|
|
69
|
-
segmentIndexMap[id] = segmentIndex;
|
|
70
|
-
}
|
|
71
70
|
}
|
|
71
|
+
context.presentationTimeline.notifySegments(references);
|
|
72
72
|
|
|
73
73
|
if (!context.dynamic || !context.periodInfo.isLastPeriod) {
|
|
74
74
|
const periodStart = context.periodInfo.start;
|
|
@@ -77,8 +77,17 @@ shaka.dash.SegmentList = class {
|
|
|
77
77
|
segmentIndex.fit(periodStart, periodEnd, isNew);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
if (stream) {
|
|
81
|
+
stream.segmentIndex = segmentIndex;
|
|
82
|
+
}
|
|
83
|
+
|
|
80
84
|
return {
|
|
81
|
-
generateSegmentIndex: () =>
|
|
85
|
+
generateSegmentIndex: () => {
|
|
86
|
+
if (!segmentIndex || segmentIndex.isEmpty()) {
|
|
87
|
+
segmentIndex.merge(references);
|
|
88
|
+
}
|
|
89
|
+
return Promise.resolve(segmentIndex);
|
|
90
|
+
},
|
|
82
91
|
};
|
|
83
92
|
}
|
|
84
93
|
|
|
@@ -31,7 +31,7 @@ shaka.dash.SegmentTemplate = class {
|
|
|
31
31
|
* @param {shaka.dash.DashParser.Context} context
|
|
32
32
|
* @param {shaka.dash.DashParser.RequestInitSegmentCallback}
|
|
33
33
|
* requestInitSegment
|
|
34
|
-
* @param {!Object.<string, !shaka.
|
|
34
|
+
* @param {!Object.<string, !shaka.extern.Stream>} streamMap
|
|
35
35
|
* @param {boolean} isUpdate True if the manifest is being updated.
|
|
36
36
|
* @param {number} segmentLimit The maximum number of segments to generate for
|
|
37
37
|
* a SegmentTemplate with fixed duration.
|
|
@@ -39,8 +39,8 @@ shaka.dash.SegmentTemplate = class {
|
|
|
39
39
|
* @return {shaka.dash.DashParser.StreamInfo}
|
|
40
40
|
*/
|
|
41
41
|
static createStreamInfo(
|
|
42
|
-
context, requestInitSegment,
|
|
43
|
-
|
|
42
|
+
context, requestInitSegment, streamMap, isUpdate, segmentLimit,
|
|
43
|
+
periodDurationMap) {
|
|
44
44
|
goog.asserts.assert(context.representation.segmentTemplate,
|
|
45
45
|
'Should only be called with SegmentTemplate');
|
|
46
46
|
const SegmentTemplate = shaka.dash.SegmentTemplate;
|
|
@@ -86,10 +86,14 @@ shaka.dash.SegmentTemplate = class {
|
|
|
86
86
|
/** @type {shaka.media.SegmentIndex} */
|
|
87
87
|
let segmentIndex = null;
|
|
88
88
|
let id = null;
|
|
89
|
+
let stream = null;
|
|
89
90
|
if (context.period.id && context.representation.id) {
|
|
90
91
|
// Only check/store the index if period and representation IDs are set.
|
|
91
92
|
id = context.period.id + ',' + context.representation.id;
|
|
92
|
-
|
|
93
|
+
stream = streamMap[id];
|
|
94
|
+
if (stream) {
|
|
95
|
+
segmentIndex = stream.segmentIndex;
|
|
96
|
+
}
|
|
93
97
|
}
|
|
94
98
|
|
|
95
99
|
const references = SegmentTemplate.createFromTimeline_(
|
|
@@ -116,19 +120,28 @@ shaka.dash.SegmentTemplate = class {
|
|
|
116
120
|
segmentIndex.mergeAndEvict(references,
|
|
117
121
|
context.presentationTimeline.getSegmentAvailabilityStart());
|
|
118
122
|
} else {
|
|
119
|
-
context.presentationTimeline.notifySegments(references);
|
|
120
123
|
segmentIndex = new shaka.media.SegmentIndex(references);
|
|
121
|
-
if (id && context.dynamic) {
|
|
122
|
-
segmentIndexMap[id] = segmentIndex;
|
|
123
|
-
}
|
|
124
124
|
}
|
|
125
|
+
context.presentationTimeline.notifySegments(references);
|
|
125
126
|
|
|
126
127
|
if (shouldFit) {
|
|
127
128
|
segmentIndex.fit(periodStart, periodEnd);
|
|
128
129
|
}
|
|
129
130
|
|
|
131
|
+
if (stream && context.dynamic) {
|
|
132
|
+
stream.segmentIndex = segmentIndex;
|
|
133
|
+
}
|
|
134
|
+
|
|
130
135
|
return {
|
|
131
|
-
generateSegmentIndex: () =>
|
|
136
|
+
generateSegmentIndex: () => {
|
|
137
|
+
// If segmentIndex is deleted, or segmentIndex's references are
|
|
138
|
+
// released by closeSegmentIndex(), we should set the value of
|
|
139
|
+
// segmentIndex again.
|
|
140
|
+
if (!segmentIndex || segmentIndex.isEmpty()) {
|
|
141
|
+
segmentIndex.merge(references);
|
|
142
|
+
}
|
|
143
|
+
return Promise.resolve(segmentIndex);
|
|
144
|
+
},
|
|
132
145
|
};
|
|
133
146
|
}
|
|
134
147
|
}
|
|
@@ -569,8 +582,8 @@ shaka.dash.SegmentTemplate = class {
|
|
|
569
582
|
baseUris, [filledTemplate]);
|
|
570
583
|
return resolvedUris;
|
|
571
584
|
};
|
|
572
|
-
|
|
573
|
-
return new shaka.media.InitSegmentReference(getUris, 0, null);
|
|
585
|
+
const qualityInfo = shaka.dash.SegmentBase.createQualityInfo(context);
|
|
586
|
+
return new shaka.media.InitSegmentReference(getUris, 0, null, qualityInfo);
|
|
574
587
|
}
|
|
575
588
|
};
|
|
576
589
|
|