shaka-player 4.2.5 → 4.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/workflows/build-and-test.yaml +7 -0
- package/.github/workflows/sync-labels.yaml +1 -1
- package/.github/workflows/update-issues.yaml +1 -1
- package/AUTHORS +4 -0
- package/CHANGELOG.md +114 -74
- package/CONTRIBUTORS +4 -0
- package/README.md +14 -0
- package/conditional/dummy_cast_proxy.js +120 -0
- package/demo/common/assets.js +58 -0
- package/demo/common/message_ids.js +22 -1
- package/demo/config.js +89 -5
- package/demo/demo.less +7 -1
- package/demo/index.html +8 -1
- package/demo/locales/en.json +21 -1
- package/demo/locales/source.json +82 -2
- package/demo/main.js +57 -1
- package/demo/search.js +2 -0
- package/demo/visualizer.js +337 -0
- package/demo/visualizer_button.js +103 -0
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +107 -88
- package/dist/demo.compiled.debug.map +4 -4
- package/dist/demo.compiled.js +107 -88
- package/dist/demo.compiled.map +4 -4
- package/dist/demo.css +1 -1
- package/dist/demo.css.map +1 -1
- package/dist/deps.js +21 -13
- package/dist/locales.js +31 -31
- package/dist/receiver.compiled.debug.js +75 -77
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +75 -77
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +181 -27
- package/dist/shaka-player.compiled.debug.d.ts +181 -27
- package/dist/shaka-player.compiled.debug.externs.js +169 -31
- package/dist/shaka-player.compiled.debug.js +510 -450
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +169 -31
- package/dist/shaka-player.compiled.js +912 -874
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +181 -27
- package/dist/shaka-player.ui.debug.d.ts +181 -27
- package/dist/shaka-player.ui.debug.externs.js +169 -31
- package/dist/shaka-player.ui.debug.js +533 -471
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +169 -31
- package/dist/shaka-player.ui.js +1073 -1036
- package/dist/shaka-player.ui.map +4 -4
- package/docs/design/lcevc-architecture.png +0 -0
- package/docs/design/lcevc-demo.png +0 -0
- package/docs/design/lcevc-integration.md +72 -0
- package/docs/tutorials/fairplay.md +7 -0
- package/docs/tutorials/faq.md +1 -1
- package/docs/tutorials/ui.md +7 -7
- package/docs/tutorials/upgrade.md +6 -0
- package/externs/ima.js +13 -1
- package/externs/lcevc.js +81 -0
- package/externs/mux.js +1 -42
- package/externs/shaka/ads.js +11 -1
- package/externs/shaka/manifest_parser.js +5 -1
- package/externs/shaka/mp4_parser.js +3 -0
- package/externs/shaka/player.js +178 -15
- package/lib/abr/simple_abr_manager.js +7 -0
- package/lib/ads/ad_manager.js +0 -8
- package/lib/ads/client_side_ad.js +15 -0
- package/lib/ads/client_side_ad_manager.js +21 -8
- package/lib/ads/server_side_ad.js +15 -0
- package/lib/ads/server_side_ad_manager.js +3 -3
- package/lib/cast/cast_utils.js +2 -0
- package/lib/cea/dummy_cea_parser.js +28 -0
- package/lib/cea/i_cea_parser.js +14 -2
- package/lib/cea/mp4_cea_parser.js +108 -5
- package/lib/config/auto_show_text.js +33 -0
- package/lib/dash/dash_parser.js +1 -1
- package/lib/hls/hls_parser.js +808 -384
- package/lib/lcevc/lcevc_dil.js +152 -0
- package/lib/media/closed_caption_parser.js +9 -6
- package/lib/media/drm_engine.js +14 -6
- package/lib/media/media_source_capabilities.js +36 -0
- package/lib/media/media_source_engine.js +113 -28
- package/lib/media/presentation_timeline.js +26 -11
- package/lib/media/segment_reference.js +49 -1
- package/lib/media/streaming_engine.js +142 -12
- package/lib/media/transmuxer.js +78 -21
- package/lib/offline/storage.js +1 -0
- package/lib/player.js +456 -77
- package/lib/polyfill/media_capabilities.js +9 -5
- package/lib/polyfill/patchedmediakeys_apple.js +63 -4
- package/lib/text/vtt_text_parser.js +35 -1
- package/lib/util/dom_utils.js +0 -1
- package/lib/util/error.js +17 -0
- package/lib/util/fake_event.js +2 -0
- package/lib/util/id3_utils.js +300 -0
- package/lib/util/mime_utils.js +3 -6
- package/lib/util/mp4_box_parsers.js +39 -5
- package/lib/util/mp4_parser.js +35 -0
- package/lib/util/player_configuration.js +23 -1
- package/lib/util/stream_utils.js +5 -3
- package/lib/util/ts_parser.js +499 -0
- package/maintained-branches.md +2 -2
- package/package.json +7 -4
- package/roadmap.md +5 -3
- package/test/ads/ad_manager_unit.js +182 -29
- package/test/cast/cast_utils_unit.js +3 -1
- package/test/dash/dash_parser_content_protection_unit.js +1 -0
- package/test/dash/dash_parser_live_unit.js +1 -0
- package/test/dash/dash_parser_manifest_unit.js +93 -1
- package/test/dash/dash_parser_segment_base_unit.js +1 -0
- package/test/dash/dash_parser_segment_list_unit.js +1 -0
- package/test/dash/dash_parser_segment_template_unit.js +1 -0
- package/test/demo/demo_unit.js +2 -1
- package/test/hls/hls_live_unit.js +253 -19
- package/test/hls/hls_parser_unit.js +631 -12
- package/test/media/closed_caption_parser_unit.js +2 -1
- package/test/media/drm_engine_integration.js +3 -1
- package/test/media/media_source_engine_integration.js +71 -6
- package/test/media/media_source_engine_unit.js +10 -5
- package/test/media/streaming_engine_integration.js +4 -1
- package/test/media/streaming_engine_unit.js +144 -1
- package/test/media/transmuxer_integration.js +21 -10
- package/test/player_integration.js +224 -82
- package/test/player_unit.js +5 -2
- package/test/polyfill/media_capabilities_unit.js +21 -23
- package/test/polyfill/patchedmediakeys_apple_unit.js +130 -0
- package/test/test/assets/id3-metadata.aac +0 -0
- package/test/test/assets/id3-metadata.ts +0 -0
- package/test/test/assets/thumbnails-sprites.vtt +10 -0
- package/test/test/assets/thumbnails.vtt +10 -0
- package/test/test/util/dash_parser_util.js +2 -0
- package/test/test/util/fake_ad.js +21 -0
- package/test/test/util/fake_media_source_engine.js +7 -0
- package/test/test/util/id3_generator.js +100 -0
- package/test/test/util/manifest_generator.js +3 -6
- package/test/test/util/simple_fakes.js +4 -0
- package/test/test/util/stream_generator.js +38 -0
- package/test/test/util/test_scheme.js +43 -14
- package/test/text/vtt_text_parser_unit.js +11 -0
- package/test/util/id3_utils_unit.js +116 -0
- package/test/util/ts_parser_unit.js +77 -0
- package/third_party/closure-uri/uri.js +1 -1
- package/ui/less/containers.less +7 -0
- package/ui/ui.js +43 -4
package/lib/player.js
CHANGED
|
@@ -8,6 +8,7 @@ goog.provide('shaka.Player');
|
|
|
8
8
|
|
|
9
9
|
goog.require('goog.asserts');
|
|
10
10
|
goog.require('shaka.Deprecate');
|
|
11
|
+
goog.require('shaka.config.AutoShowText');
|
|
11
12
|
goog.require('shaka.log');
|
|
12
13
|
goog.require('shaka.media.AdaptationSetCriteria');
|
|
13
14
|
goog.require('shaka.media.BufferingObserver');
|
|
@@ -17,7 +18,6 @@ goog.require('shaka.media.ManifestParser');
|
|
|
17
18
|
goog.require('shaka.media.MediaSourceEngine');
|
|
18
19
|
goog.require('shaka.media.MediaSourcePlayhead');
|
|
19
20
|
goog.require('shaka.media.MetaSegmentIndex');
|
|
20
|
-
goog.require('shaka.media.ClosedCaptionParser');
|
|
21
21
|
goog.require('shaka.media.PlayRateController');
|
|
22
22
|
goog.require('shaka.media.Playhead');
|
|
23
23
|
goog.require('shaka.media.PlayheadObserverManager');
|
|
@@ -26,6 +26,7 @@ goog.require('shaka.media.QualityObserver');
|
|
|
26
26
|
goog.require('shaka.media.RegionObserver');
|
|
27
27
|
goog.require('shaka.media.RegionTimeline');
|
|
28
28
|
goog.require('shaka.media.SegmentIndex');
|
|
29
|
+
goog.require('shaka.media.SegmentReference');
|
|
29
30
|
goog.require('shaka.media.SrcEqualsPlayhead');
|
|
30
31
|
goog.require('shaka.media.StreamingEngine');
|
|
31
32
|
goog.require('shaka.media.TimeRangesUtils');
|
|
@@ -55,7 +56,7 @@ goog.require('shaka.util.PublicPromise');
|
|
|
55
56
|
goog.require('shaka.util.Stats');
|
|
56
57
|
goog.require('shaka.util.StreamUtils');
|
|
57
58
|
goog.require('shaka.util.Timer');
|
|
58
|
-
goog.
|
|
59
|
+
goog.require('shaka.lcevc.Dil');
|
|
59
60
|
goog.requireType('shaka.media.PresentationTimeline');
|
|
60
61
|
goog.requireType('shaka.routing.Node');
|
|
61
62
|
goog.requireType('shaka.routing.Payload');
|
|
@@ -325,7 +326,7 @@ goog.requireType('shaka.routing.Payload');
|
|
|
325
326
|
* the cue applies.
|
|
326
327
|
* @property {string} metadataType
|
|
327
328
|
* Type of metadata. Eg: org.id3 or org.mp4ra
|
|
328
|
-
* @property {shaka.extern.
|
|
329
|
+
* @property {shaka.extern.MetadataFrame} payload
|
|
329
330
|
* The metadata itself
|
|
330
331
|
* @exportDoc
|
|
331
332
|
*/
|
|
@@ -367,6 +368,21 @@ goog.requireType('shaka.routing.Payload');
|
|
|
367
368
|
*/
|
|
368
369
|
|
|
369
370
|
|
|
371
|
+
/**
|
|
372
|
+
* @event shaka.Player.SegmentAppended
|
|
373
|
+
* @description Fired when a segment is appended to the media element.
|
|
374
|
+
* @property {string} type
|
|
375
|
+
* 'segmentappended'
|
|
376
|
+
* @property {number} start
|
|
377
|
+
* The start time of the segment.
|
|
378
|
+
* @property {number} end
|
|
379
|
+
* The end time of the segment.
|
|
380
|
+
* @property {string} contentType
|
|
381
|
+
* The content type of the segment. E.g. 'video', 'audio', or 'text'.
|
|
382
|
+
* @exportDoc
|
|
383
|
+
*/
|
|
384
|
+
|
|
385
|
+
|
|
370
386
|
/**
|
|
371
387
|
* @event shaka.Player.SessionDataEvent
|
|
372
388
|
* @description Fired when the manifest parser find info about session data.
|
|
@@ -505,6 +521,15 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
505
521
|
/** @private {shaka.util.CmcdManager} */
|
|
506
522
|
this.cmcdManager_ = null;
|
|
507
523
|
|
|
524
|
+
// This is the canvas element that will be used for rendering LCEVC
|
|
525
|
+
// enhanced frames.
|
|
526
|
+
/** @private {?HTMLCanvasElement} */
|
|
527
|
+
this.lcevcCanvas_ = null;
|
|
528
|
+
|
|
529
|
+
// This is the LCEVC Dil object to decode LCEVC.
|
|
530
|
+
/** @private {?shaka.lcevc.Dil} */
|
|
531
|
+
this.lcevcDil_ = null;
|
|
532
|
+
|
|
508
533
|
/** @private {shaka.media.QualityObserver} */
|
|
509
534
|
this.qualityObserver_ = null;
|
|
510
535
|
|
|
@@ -523,6 +548,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
523
548
|
/** @private {?string} */
|
|
524
549
|
this.assetUri_ = null;
|
|
525
550
|
|
|
551
|
+
/** @private {boolean} */
|
|
552
|
+
this.fullyLoaded_ = false;
|
|
553
|
+
|
|
526
554
|
/** @private {shaka.extern.AbrManager} */
|
|
527
555
|
this.abrManager_ = null;
|
|
528
556
|
|
|
@@ -726,6 +754,66 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
726
754
|
}
|
|
727
755
|
}
|
|
728
756
|
|
|
757
|
+
/**
|
|
758
|
+
* Create a shaka.lcevc.Dil object
|
|
759
|
+
* @param {shaka.extern.LcevcConfiguration} config
|
|
760
|
+
* @private
|
|
761
|
+
*/
|
|
762
|
+
createLcevcDil_(config) {
|
|
763
|
+
if (this.lcevcDil_ == null) {
|
|
764
|
+
this.lcevcDil_ = new shaka.lcevc.Dil(
|
|
765
|
+
/** @type {HTMLVideoElement} */ (this.video_),
|
|
766
|
+
this.lcevcCanvas_,
|
|
767
|
+
config,
|
|
768
|
+
);
|
|
769
|
+
if (this.mediaSourceEngine_) {
|
|
770
|
+
this.mediaSourceEngine_.updateLcevcDil(this.lcevcDil_);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
/**
|
|
776
|
+
* Close a shaka.lcevc.Dil object if present and hide the canvas.
|
|
777
|
+
* @private
|
|
778
|
+
*/
|
|
779
|
+
closeLcevcDil_() {
|
|
780
|
+
if (this.lcevcDil_ != null) {
|
|
781
|
+
this.lcevcDil_.release();
|
|
782
|
+
this.lcevcDil_ = null;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
/**
|
|
787
|
+
* Setup shaka.lcevc.Dil object
|
|
788
|
+
* @param {?shaka.extern.PlayerConfiguration} config
|
|
789
|
+
* @private
|
|
790
|
+
*/
|
|
791
|
+
setupLcevc_(config) {
|
|
792
|
+
if (config.lcevc.enabled) {
|
|
793
|
+
const tracks = this.getVariantTracks();
|
|
794
|
+
if (tracks && tracks[0] &&
|
|
795
|
+
tracks[0].videoMimeType ==
|
|
796
|
+
shaka.Player.SRC_EQUAL_EXTENSIONS_TO_MIME_TYPES_['ts']) {
|
|
797
|
+
const edge = shaka.util.Platform.isEdge() ||
|
|
798
|
+
shaka.util.Platform.isLegacyEdge();
|
|
799
|
+
if (edge) {
|
|
800
|
+
if (!config.streaming.forceTransmux) {
|
|
801
|
+
// If forceTransmux is disabled for Microsoft Edge, LCEVC data
|
|
802
|
+
// is stripped out in case of a MPEG-2 TS container.
|
|
803
|
+
// Hence the warning for Microsoft Edge when playing content with
|
|
804
|
+
// MPEG-2 TS container.
|
|
805
|
+
shaka.log.alwaysWarn('LCEVC Warning: For MPEG-2 TS decoding '+
|
|
806
|
+
'the config.streaming.forceTransmux must be enabled.');
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
this.closeLcevcDil_();
|
|
811
|
+
this.createLcevcDil_(config.lcevc);
|
|
812
|
+
} else {
|
|
813
|
+
this.closeLcevcDil_();
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
729
817
|
/**
|
|
730
818
|
* @param {!shaka.util.FakeEvent.EventName} name
|
|
731
819
|
* @param {Map.<string, Object>=} data
|
|
@@ -748,6 +836,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
748
836
|
return;
|
|
749
837
|
}
|
|
750
838
|
|
|
839
|
+
// If LCEVC Dil exists close it.
|
|
840
|
+
this.closeLcevcDil_();
|
|
841
|
+
|
|
751
842
|
// Mark as "dead". This should stop external-facing calls from changing our
|
|
752
843
|
// internal state any more. This will stop calls to |attach|, |detach|, etc.
|
|
753
844
|
// from interrupting our final move to the detached state.
|
|
@@ -985,6 +1076,18 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
985
1076
|
return this.wrapWalkerListenersWithPromise_(events);
|
|
986
1077
|
}
|
|
987
1078
|
|
|
1079
|
+
|
|
1080
|
+
/**
|
|
1081
|
+
* Calling <code>attachCanvas</code> will tell the player to set canvas
|
|
1082
|
+
* element for LCEVC decoding.
|
|
1083
|
+
*
|
|
1084
|
+
* @param {HTMLCanvasElement} canvas
|
|
1085
|
+
* @export
|
|
1086
|
+
*/
|
|
1087
|
+
attachCanvas(canvas) {
|
|
1088
|
+
this.lcevcCanvas_ = canvas;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
988
1091
|
/**
|
|
989
1092
|
* Tell the player to stop using its current media element. If the player is:
|
|
990
1093
|
* <ul>
|
|
@@ -1050,12 +1153,17 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1050
1153
|
return Promise.reject(this.createAbortLoadError_());
|
|
1051
1154
|
}
|
|
1052
1155
|
|
|
1156
|
+
this.fullyLoaded_ = false;
|
|
1157
|
+
|
|
1053
1158
|
// If the platform does not support media source, we will never want to
|
|
1054
1159
|
// initialize media source.
|
|
1055
1160
|
if (!shaka.util.Platform.supportsMediaSource()) {
|
|
1056
1161
|
initializeMediaSource = false;
|
|
1057
1162
|
}
|
|
1058
1163
|
|
|
1164
|
+
// If LCEVC Dil exists close it.
|
|
1165
|
+
this.closeLcevcDil_();
|
|
1166
|
+
|
|
1059
1167
|
// Since we are going either to attached or detached (through unloaded), we
|
|
1060
1168
|
// can't allow it to be interrupted or else we could lose track of what
|
|
1061
1169
|
// media element we are suppose to use.
|
|
@@ -1141,6 +1249,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1141
1249
|
load(assetUri, startTime, mimeType) {
|
|
1142
1250
|
this.updatedStartTime_ = null;
|
|
1143
1251
|
|
|
1252
|
+
this.fullyLoaded_ = false;
|
|
1253
|
+
|
|
1144
1254
|
// Do not allow the player to be used after |destroy| is called.
|
|
1145
1255
|
if (this.loadMode_ == shaka.Player.LoadMode.DESTROYED) {
|
|
1146
1256
|
return Promise.reject(this.createAbortLoadError_());
|
|
@@ -1578,8 +1688,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1578
1688
|
this.mediaSourceEngine_ == null,
|
|
1579
1689
|
'We should not have a media source engine yet.');
|
|
1580
1690
|
|
|
1581
|
-
const closedCaptionsParser = new shaka.media.ClosedCaptionParser();
|
|
1582
|
-
|
|
1583
1691
|
// When changing text visibility we need to update both the text displayer
|
|
1584
1692
|
// and streaming engine because we don't always stream text. To ensure that
|
|
1585
1693
|
// text displayer and streaming engine are always in sync, wait until they
|
|
@@ -1590,11 +1698,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1590
1698
|
|
|
1591
1699
|
const mediaSourceEngine = this.createMediaSourceEngine(
|
|
1592
1700
|
has.mediaElement,
|
|
1593
|
-
closedCaptionsParser,
|
|
1594
1701
|
textDisplayer,
|
|
1595
1702
|
(metadata, offset, endTime) => {
|
|
1596
1703
|
this.processTimedMetadataMediaSrc_(metadata, offset, endTime);
|
|
1597
|
-
}
|
|
1704
|
+
},
|
|
1705
|
+
this.lcevcDil_);
|
|
1706
|
+
mediaSourceEngine.configure(this.config_.mediaSource);
|
|
1598
1707
|
const {segmentRelativeVttTiming} = this.config_.manifest;
|
|
1599
1708
|
mediaSourceEngine.setSegmentRelativeVttTiming(segmentRelativeVttTiming);
|
|
1600
1709
|
|
|
@@ -1775,6 +1884,15 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1775
1884
|
this.streamingEngine_.updateDuration();
|
|
1776
1885
|
}
|
|
1777
1886
|
},
|
|
1887
|
+
newDrmInfo: (stream) => {
|
|
1888
|
+
// We may need to create new sessions for any new init data.
|
|
1889
|
+
const currentDrmInfo =
|
|
1890
|
+
this.drmEngine_ ? this.drmEngine_.getDrmInfo() : null;
|
|
1891
|
+
// DrmEngine.newInitData() requires mediaKeys to be available.
|
|
1892
|
+
if (currentDrmInfo && this.drmEngine_.getMediaKeys()) {
|
|
1893
|
+
this.processDrmInfos_(currentDrmInfo.keySystem, stream);
|
|
1894
|
+
}
|
|
1895
|
+
},
|
|
1778
1896
|
};
|
|
1779
1897
|
|
|
1780
1898
|
const startTime = Date.now() / 1000;
|
|
@@ -1865,6 +1983,15 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1865
1983
|
const now = Date.now() / 1000;
|
|
1866
1984
|
const delta = now - startTime;
|
|
1867
1985
|
this.stats_.setDrmTime(delta);
|
|
1986
|
+
// LCEVC data by itself is not encrypted in DRM protected streams and
|
|
1987
|
+
// can therefore be accessed and decoded as normal. However, the LCEVC
|
|
1988
|
+
// decoder needs access to the VideoElement output in order to apply
|
|
1989
|
+
// the enhancement. In DRM contexts where the browser CDM restricts
|
|
1990
|
+
// access from our decoder, the enhancement cannot be applied and
|
|
1991
|
+
// therefore the LCEVC output canvas is hidden accordingly.
|
|
1992
|
+
if (this.lcevcDil_) {
|
|
1993
|
+
this.lcevcDil_.hideCanvas();
|
|
1994
|
+
}
|
|
1868
1995
|
}
|
|
1869
1996
|
},
|
|
1870
1997
|
});
|
|
@@ -1949,6 +2076,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1949
2076
|
this.loadEventManager_.listen(mediaElement, 'ended', updateStateHistory);
|
|
1950
2077
|
this.loadEventManager_.listen(mediaElement, 'ratechange', onRateChange);
|
|
1951
2078
|
|
|
2079
|
+
// Check status of the LCEVC DIL Object and reset or
|
|
2080
|
+
// create or close based on config
|
|
2081
|
+
this.setupLcevc_(this.config_);
|
|
2082
|
+
|
|
1952
2083
|
const abrFactory = this.config_.abrFactory;
|
|
1953
2084
|
if (!this.abrManager_ || this.abrManagerFactory_ != abrFactory) {
|
|
1954
2085
|
this.abrManagerFactory_ = abrFactory;
|
|
@@ -1983,16 +2114,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1983
2114
|
});
|
|
1984
2115
|
this.abrManager_.setMediaElement(mediaElement);
|
|
1985
2116
|
|
|
1986
|
-
this.playhead_ = this.createPlayhead(has.startTime);
|
|
1987
|
-
this.playheadObservers_ = this.createPlayheadObserversForMSE_();
|
|
1988
|
-
|
|
1989
|
-
// We need to start the buffer management code near the end because it will
|
|
1990
|
-
// set the initial buffering state and that depends on other components
|
|
1991
|
-
// being initialized.
|
|
1992
|
-
const rebufferThreshold = Math.max(
|
|
1993
|
-
this.manifest_.minBufferTime, this.config_.streaming.rebufferingGoal);
|
|
1994
|
-
this.startBufferManagement_(rebufferThreshold);
|
|
1995
|
-
|
|
1996
2117
|
// If the content is multi-codec and the browser can play more than one of
|
|
1997
2118
|
// them, choose codecs now before we initialize streaming.
|
|
1998
2119
|
shaka.util.StreamUtils.chooseCodecsAndFilterManifest(
|
|
@@ -2036,14 +2157,42 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2036
2157
|
this.makeEvent_(shaka.util.FakeEvent.EventName.Streaming));
|
|
2037
2158
|
|
|
2038
2159
|
// Pick the initial streams to play.
|
|
2039
|
-
//
|
|
2040
|
-
//
|
|
2160
|
+
// Unless the user has already picked a variant, anyway, by calling
|
|
2161
|
+
// selectVariantTrack before this loading stage.
|
|
2041
2162
|
let initialVariant = null;
|
|
2042
|
-
const
|
|
2043
|
-
|
|
2044
|
-
if (!activeVariantTrack) {
|
|
2163
|
+
const activeVariant = this.streamingEngine_.getCurrentVariant();
|
|
2164
|
+
if (!activeVariant) {
|
|
2045
2165
|
initialVariant = this.chooseVariant_();
|
|
2046
2166
|
goog.asserts.assert(initialVariant, 'Must choose an initial variant!');
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
// Lazy-load the stream, so we will have enough info to make the playhead.
|
|
2170
|
+
const createSegmentIndexPromises = [];
|
|
2171
|
+
const toLazyLoad = activeVariant || initialVariant;
|
|
2172
|
+
for (const stream of [toLazyLoad.video, toLazyLoad.audio]) {
|
|
2173
|
+
if (stream && !stream.segmentIndex) {
|
|
2174
|
+
createSegmentIndexPromises.push(stream.createSegmentIndex());
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
2177
|
+
if (createSegmentIndexPromises.length > 0) {
|
|
2178
|
+
await Promise.all(createSegmentIndexPromises);
|
|
2179
|
+
}
|
|
2180
|
+
|
|
2181
|
+
this.playhead_ = this.createPlayhead(has.startTime);
|
|
2182
|
+
this.playheadObservers_ = this.createPlayheadObserversForMSE_();
|
|
2183
|
+
|
|
2184
|
+
// We need to start the buffer management code near the end because it will
|
|
2185
|
+
// set the initial buffering state and that depends on other components
|
|
2186
|
+
// being initialized.
|
|
2187
|
+
const rebufferThreshold = Math.max(
|
|
2188
|
+
this.manifest_.minBufferTime, this.config_.streaming.rebufferingGoal);
|
|
2189
|
+
this.startBufferManagement_(rebufferThreshold);
|
|
2190
|
+
|
|
2191
|
+
// Now we can switch to the initial variant.
|
|
2192
|
+
if (!activeVariant) {
|
|
2193
|
+
goog.asserts.assert(initialVariant,
|
|
2194
|
+
'Must have choosen an initial variant!');
|
|
2195
|
+
|
|
2047
2196
|
this.switchVariant_(initialVariant, /* fromAdaptation= */ true,
|
|
2048
2197
|
/* clearBuffer= */ false, /* safeMargin= */ 0);
|
|
2049
2198
|
|
|
@@ -2117,6 +2266,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2117
2266
|
'arbitrary language initially');
|
|
2118
2267
|
}
|
|
2119
2268
|
|
|
2269
|
+
this.fullyLoaded_ = true;
|
|
2270
|
+
|
|
2120
2271
|
// Wait for the 'loadedmetadata' event to measure load() latency.
|
|
2121
2272
|
this.loadEventManager_.listenOnce(mediaElement, 'loadedmetadata', () => {
|
|
2122
2273
|
const now = Date.now() / 1000;
|
|
@@ -2463,6 +2614,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2463
2614
|
shaka.util.Error.Code.OPERATION_ABORTED);
|
|
2464
2615
|
fullyLoaded.reject(abortedError);
|
|
2465
2616
|
return Promise.resolve(); // Abort complete.
|
|
2617
|
+
}).chain(() => {
|
|
2618
|
+
this.fullyLoaded_ = true;
|
|
2466
2619
|
});
|
|
2467
2620
|
}
|
|
2468
2621
|
|
|
@@ -2575,11 +2728,15 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2575
2728
|
*/
|
|
2576
2729
|
processTimedMetadataMediaSrc_(metadata, offset, segmentEndTime) {
|
|
2577
2730
|
for (const sample of metadata) {
|
|
2578
|
-
if (sample
|
|
2579
|
-
const start = sample
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2731
|
+
if (sample.data && sample.cueTime && sample.frames) {
|
|
2732
|
+
const start = sample.cueTime + offset;
|
|
2733
|
+
let end = segmentEndTime;
|
|
2734
|
+
// This can happen when the ID3 info arrives in a previous segment.
|
|
2735
|
+
if (end && start > end) {
|
|
2736
|
+
end = start;
|
|
2737
|
+
}
|
|
2738
|
+
const metadataType = 'org.id3';
|
|
2739
|
+
for (const frame of sample.frames) {
|
|
2583
2740
|
const payload = frame;
|
|
2584
2741
|
this.dispatchMetadataEvent_(start, end, metadataType, payload);
|
|
2585
2742
|
}
|
|
@@ -2598,7 +2755,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2598
2755
|
* @param {number} startTime
|
|
2599
2756
|
* @param {?number} endTime
|
|
2600
2757
|
* @param {string} metadataType
|
|
2601
|
-
* @param {shaka.extern.
|
|
2758
|
+
* @param {shaka.extern.MetadataFrame} payload
|
|
2602
2759
|
* @private
|
|
2603
2760
|
*/
|
|
2604
2761
|
dispatchMetadataEvent_(startTime, endTime, metadataType, payload) {
|
|
@@ -2896,17 +3053,19 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2896
3053
|
* way to inject fake media source engine instances.
|
|
2897
3054
|
*
|
|
2898
3055
|
* @param {!HTMLMediaElement} mediaElement
|
|
2899
|
-
* @param {!shaka.media.IClosedCaptionParser} closedCaptionsParser
|
|
2900
3056
|
* @param {!shaka.extern.TextDisplayer} textDisplayer
|
|
2901
3057
|
* @param {!function(!Array.<shaka.extern.ID3Metadata>, number, ?number)}
|
|
2902
3058
|
* onMetadata
|
|
3059
|
+
* @param {shaka.lcevc.Dil} lcevcDil
|
|
2903
3060
|
*
|
|
2904
3061
|
* @return {!shaka.media.MediaSourceEngine}
|
|
2905
3062
|
*/
|
|
2906
|
-
createMediaSourceEngine(mediaElement,
|
|
2907
|
-
onMetadata) {
|
|
3063
|
+
createMediaSourceEngine(mediaElement, textDisplayer, onMetadata, lcevcDil) {
|
|
2908
3064
|
return new shaka.media.MediaSourceEngine(
|
|
2909
|
-
mediaElement,
|
|
3065
|
+
mediaElement,
|
|
3066
|
+
textDisplayer,
|
|
3067
|
+
onMetadata,
|
|
3068
|
+
lcevcDil);
|
|
2910
3069
|
}
|
|
2911
3070
|
|
|
2912
3071
|
/**
|
|
@@ -2937,13 +3096,13 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2937
3096
|
*/
|
|
2938
3097
|
createStreamingEngine() {
|
|
2939
3098
|
goog.asserts.assert(
|
|
2940
|
-
this.
|
|
3099
|
+
this.abrManager_ && this.mediaSourceEngine_ &&
|
|
2941
3100
|
this.cmcdManager_ && this.manifest_,
|
|
2942
3101
|
'Must not be destroyed');
|
|
2943
3102
|
|
|
2944
3103
|
/** @type {shaka.media.StreamingEngine.PlayerInterface} */
|
|
2945
3104
|
const playerInterface = {
|
|
2946
|
-
getPresentationTime: () => this.playhead_.getTime(),
|
|
3105
|
+
getPresentationTime: () => this.playhead_ ? this.playhead_.getTime() : 0,
|
|
2947
3106
|
getBandwidthEstimate: () => this.abrManager_.getBandwidthEstimate(),
|
|
2948
3107
|
modifySegmentRequest: (request, segmentInfo) => {
|
|
2949
3108
|
this.cmcdManager_.applySegmentData(request, segmentInfo);
|
|
@@ -2953,7 +3112,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2953
3112
|
onError: (error) => this.onError_(error),
|
|
2954
3113
|
onEvent: (event) => this.dispatchEvent(event),
|
|
2955
3114
|
onManifestUpdate: () => this.onManifestUpdate_(),
|
|
2956
|
-
onSegmentAppended: () =>
|
|
3115
|
+
onSegmentAppended: (start, end, contentType) => {
|
|
3116
|
+
this.onSegmentAppended_(start, end, contentType);
|
|
3117
|
+
},
|
|
2957
3118
|
onInitSegmentAppended: (position, initSegment) => {
|
|
2958
3119
|
const mediaQuality = initSegment.getMediaQuality();
|
|
2959
3120
|
if (mediaQuality && this.qualityObserver_) {
|
|
@@ -2963,6 +3124,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2963
3124
|
beforeAppendSegment: (contentType, segment) => {
|
|
2964
3125
|
return this.drmEngine_.parseInbandPssh(contentType, segment);
|
|
2965
3126
|
},
|
|
3127
|
+
onMetadata: (metadata, offset, endTime) => {
|
|
3128
|
+
this.processTimedMetadataMediaSrc_(metadata, offset, endTime);
|
|
3129
|
+
},
|
|
2966
3130
|
};
|
|
2967
3131
|
|
|
2968
3132
|
return new shaka.media.StreamingEngine(this.manifest_, playerInterface);
|
|
@@ -3006,6 +3170,16 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3006
3170
|
|
|
3007
3171
|
goog.asserts.assert(typeof(config) == 'object', 'Should be an object!');
|
|
3008
3172
|
|
|
3173
|
+
// Deprecate 'streaming.forceTransmuxTS' configuration.
|
|
3174
|
+
if (config['streaming'] && 'forceTransmuxTS' in config['streaming']) {
|
|
3175
|
+
shaka.Deprecate.deprecateFeature(5,
|
|
3176
|
+
'streaming.forceTransmuxTS configuration',
|
|
3177
|
+
'Please Use streaming.forceTransmux instead.');
|
|
3178
|
+
config['streaming']['forceTransmux'] =
|
|
3179
|
+
config['streaming']['forceTransmuxTS'];
|
|
3180
|
+
delete config['streaming']['forceTransmuxTS'];
|
|
3181
|
+
}
|
|
3182
|
+
|
|
3009
3183
|
// If lowLatencyMode is enabled, and inaccurateManifestTolerance and
|
|
3010
3184
|
// rebufferingGoal are not specified, set inaccurateManifestTolerance to 0
|
|
3011
3185
|
// and rebufferingGoal to 0.01 by default for low latency streaming.
|
|
@@ -3072,6 +3246,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3072
3246
|
}
|
|
3073
3247
|
|
|
3074
3248
|
if (this.mediaSourceEngine_) {
|
|
3249
|
+
this.mediaSourceEngine_.configure(this.config_.mediaSource);
|
|
3075
3250
|
const {segmentRelativeVttTiming} = this.config_.manifest;
|
|
3076
3251
|
this.mediaSourceEngine_.setSegmentRelativeVttTiming(
|
|
3077
3252
|
segmentRelativeVttTiming);
|
|
@@ -3359,6 +3534,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3359
3534
|
* @export
|
|
3360
3535
|
*/
|
|
3361
3536
|
seekRange() {
|
|
3537
|
+
if (!this.fullyLoaded_) {
|
|
3538
|
+
return {'start': 0, 'end': 0};
|
|
3539
|
+
}
|
|
3540
|
+
|
|
3362
3541
|
if (this.manifest_) {
|
|
3363
3542
|
const timeline = this.manifest_.presentationTimeline;
|
|
3364
3543
|
|
|
@@ -3701,8 +3880,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3701
3880
|
const fullImageHeight = imageStream.height || 0;
|
|
3702
3881
|
const columns = parseInt(match[1], 10);
|
|
3703
3882
|
const rows = parseInt(match[2], 10);
|
|
3704
|
-
|
|
3705
|
-
|
|
3883
|
+
let width = fullImageWidth / columns;
|
|
3884
|
+
let height = fullImageHeight / rows;
|
|
3706
3885
|
const totalImages = columns * rows;
|
|
3707
3886
|
const segmentDuration = reference.trueEndTime - reference.startTime;
|
|
3708
3887
|
const thumbnailDuration =
|
|
@@ -3728,6 +3907,15 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3728
3907
|
positionX = (thumbnailPosition % columns) * width;
|
|
3729
3908
|
positionY = Math.floor(thumbnailPosition / columns) * height;
|
|
3730
3909
|
}
|
|
3910
|
+
let sprite = false;
|
|
3911
|
+
const thumbnailSprite = reference.getThumbnailSprite();
|
|
3912
|
+
if (thumbnailSprite) {
|
|
3913
|
+
sprite = true;
|
|
3914
|
+
height = thumbnailSprite.height;
|
|
3915
|
+
positionX = thumbnailSprite.positionX;
|
|
3916
|
+
positionY = thumbnailSprite.positionY;
|
|
3917
|
+
width = thumbnailSprite.width;
|
|
3918
|
+
}
|
|
3731
3919
|
return {
|
|
3732
3920
|
imageHeight: fullImageHeight,
|
|
3733
3921
|
imageWidth: fullImageWidth,
|
|
@@ -3738,6 +3926,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3738
3926
|
duration: thumbnailDuration,
|
|
3739
3927
|
uris: reference.getUris(),
|
|
3740
3928
|
width: width,
|
|
3929
|
+
sprite: sprite,
|
|
3741
3930
|
};
|
|
3742
3931
|
}
|
|
3743
3932
|
return null;
|
|
@@ -3921,20 +4110,21 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3921
4110
|
|
|
3922
4111
|
/**
|
|
3923
4112
|
* Sets the current audio language and current variant role to the selected
|
|
3924
|
-
* language and
|
|
3925
|
-
* not loaded any content, this will be a no-op.
|
|
4113
|
+
* language, role and channel count, and chooses a new variant if need be.
|
|
4114
|
+
* If the player has not loaded any content, this will be a no-op.
|
|
3926
4115
|
*
|
|
3927
4116
|
* @param {string} language
|
|
3928
4117
|
* @param {string=} role
|
|
4118
|
+
* @param {number=} channelsCount
|
|
3929
4119
|
* @export
|
|
3930
4120
|
*/
|
|
3931
|
-
selectAudioLanguage(language, role) {
|
|
4121
|
+
selectAudioLanguage(language, role, channelsCount = 0) {
|
|
3932
4122
|
const LanguageUtils = shaka.util.LanguageUtils;
|
|
3933
4123
|
|
|
3934
4124
|
if (this.manifest_ && this.playhead_) {
|
|
3935
4125
|
this.currentAdaptationSetCriteria_ =
|
|
3936
4126
|
new shaka.media.PreferenceBasedCriteria(language, role || '',
|
|
3937
|
-
|
|
4127
|
+
channelsCount, /* label= */ '');
|
|
3938
4128
|
|
|
3939
4129
|
const diff = (a, b) => {
|
|
3940
4130
|
if (!a.video && !b.video) {
|
|
@@ -4613,6 +4803,146 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4613
4803
|
return shaka.util.StreamUtils.textStreamToTrack(stream);
|
|
4614
4804
|
}
|
|
4615
4805
|
|
|
4806
|
+
/**
|
|
4807
|
+
* Adds the given thumbnails track to the loaded manifest.
|
|
4808
|
+
* <code>load()</code> must resolve before calling. The presentation must
|
|
4809
|
+
* have a duration.
|
|
4810
|
+
*
|
|
4811
|
+
* This returns the created track, which can immediately be used by the
|
|
4812
|
+
* application.
|
|
4813
|
+
*
|
|
4814
|
+
* @param {string} uri
|
|
4815
|
+
* @param {string=} mimeType
|
|
4816
|
+
* @return {!Promise.<shaka.extern.Track>}
|
|
4817
|
+
* @export
|
|
4818
|
+
*/
|
|
4819
|
+
async addThumbnailsTrack(uri, mimeType) {
|
|
4820
|
+
if (this.loadMode_ != shaka.Player.LoadMode.MEDIA_SOURCE &&
|
|
4821
|
+
this.loadMode_ != shaka.Player.LoadMode.SRC_EQUALS) {
|
|
4822
|
+
shaka.log.error(
|
|
4823
|
+
'Must call load() and wait for it to resolve before adding image ' +
|
|
4824
|
+
'tracks.');
|
|
4825
|
+
throw new shaka.util.Error(
|
|
4826
|
+
shaka.util.Error.Severity.RECOVERABLE,
|
|
4827
|
+
shaka.util.Error.Category.PLAYER,
|
|
4828
|
+
shaka.util.Error.Code.CONTENT_NOT_LOADED);
|
|
4829
|
+
}
|
|
4830
|
+
|
|
4831
|
+
if (this.loadMode_ == shaka.Player.LoadMode.SRC_EQUALS) {
|
|
4832
|
+
shaka.log.error('Cannot add this thumbnail track when loaded with src=');
|
|
4833
|
+
throw new shaka.util.Error(
|
|
4834
|
+
shaka.util.Error.Severity.RECOVERABLE,
|
|
4835
|
+
shaka.util.Error.Category.TEXT,
|
|
4836
|
+
shaka.util.Error.Code.CANNOT_ADD_EXTERNAL_THUMBNAILS_TO_SRC_EQUALS);
|
|
4837
|
+
}
|
|
4838
|
+
|
|
4839
|
+
if (!mimeType) {
|
|
4840
|
+
mimeType = await this.getTextMimetype_(uri);
|
|
4841
|
+
}
|
|
4842
|
+
|
|
4843
|
+
if (mimeType != 'text/vtt') {
|
|
4844
|
+
throw new shaka.util.Error(
|
|
4845
|
+
shaka.util.Error.Severity.RECOVERABLE,
|
|
4846
|
+
shaka.util.Error.Category.TEXT,
|
|
4847
|
+
shaka.util.Error.Code.UNSUPPORTED_EXTERNAL_THUMBNAILS_URI,
|
|
4848
|
+
uri);
|
|
4849
|
+
}
|
|
4850
|
+
|
|
4851
|
+
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
4852
|
+
|
|
4853
|
+
const duration = this.manifest_.presentationTimeline.getDuration();
|
|
4854
|
+
if (duration == Infinity) {
|
|
4855
|
+
throw new shaka.util.Error(
|
|
4856
|
+
shaka.util.Error.Severity.RECOVERABLE,
|
|
4857
|
+
shaka.util.Error.Category.MANIFEST,
|
|
4858
|
+
shaka.util.Error.Code.CANNOT_ADD_EXTERNAL_THUMBNAILS_TO_LIVE_STREAM);
|
|
4859
|
+
}
|
|
4860
|
+
|
|
4861
|
+
goog.asserts.assert(
|
|
4862
|
+
this.networkingEngine_, 'Need networking engine.');
|
|
4863
|
+
const buffer = await this.getTextData_(uri,
|
|
4864
|
+
this.networkingEngine_,
|
|
4865
|
+
this.config_.streaming.retryParameters);
|
|
4866
|
+
|
|
4867
|
+
const factory = shaka.text.TextEngine.findParser(mimeType);
|
|
4868
|
+
if (!factory) {
|
|
4869
|
+
throw new shaka.util.Error(
|
|
4870
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
4871
|
+
shaka.util.Error.Category.TEXT,
|
|
4872
|
+
shaka.util.Error.Code.MISSING_TEXT_PLUGIN,
|
|
4873
|
+
mimeType);
|
|
4874
|
+
}
|
|
4875
|
+
const TextParser = factory();
|
|
4876
|
+
const time = {
|
|
4877
|
+
periodStart: 0,
|
|
4878
|
+
segmentStart: 0,
|
|
4879
|
+
segmentEnd: duration,
|
|
4880
|
+
vttOffset: 0,
|
|
4881
|
+
};
|
|
4882
|
+
const data = shaka.util.BufferUtils.toUint8(buffer);
|
|
4883
|
+
const cues = TextParser.parseMedia(data, time);
|
|
4884
|
+
|
|
4885
|
+
const references = [];
|
|
4886
|
+
for (const cue of cues) {
|
|
4887
|
+
const imageUri = shaka.util.ManifestParserUtils.resolveUris(
|
|
4888
|
+
[uri], [cue.payload])[0];
|
|
4889
|
+
const reference = new shaka.media.SegmentReference(
|
|
4890
|
+
cue.startTime,
|
|
4891
|
+
cue.endTime,
|
|
4892
|
+
() => [imageUri],
|
|
4893
|
+
/* startByte= */ 0,
|
|
4894
|
+
/* endByte= */ null,
|
|
4895
|
+
/* initSegmentReference= */ null,
|
|
4896
|
+
/* timestampOffset= */ 0,
|
|
4897
|
+
/* appendWindowStart= */ 0,
|
|
4898
|
+
/* appendWindowEnd= */ Infinity,
|
|
4899
|
+
);
|
|
4900
|
+
if (imageUri.includes('#xywh')) {
|
|
4901
|
+
const spriteInfo = imageUri.split('#xywh=')[1].split(',');
|
|
4902
|
+
if (spriteInfo.length === 4) {
|
|
4903
|
+
reference.setThumbnailSprite({
|
|
4904
|
+
height: parseInt(spriteInfo[3], 10),
|
|
4905
|
+
positionX: parseInt(spriteInfo[0], 10),
|
|
4906
|
+
positionY: parseInt(spriteInfo[1], 10),
|
|
4907
|
+
width: parseInt(spriteInfo[2], 10),
|
|
4908
|
+
});
|
|
4909
|
+
}
|
|
4910
|
+
}
|
|
4911
|
+
references.push(reference);
|
|
4912
|
+
}
|
|
4913
|
+
|
|
4914
|
+
/** @type {shaka.extern.Stream} */
|
|
4915
|
+
const stream = {
|
|
4916
|
+
id: this.nextExternalStreamId_++,
|
|
4917
|
+
originalId: null,
|
|
4918
|
+
createSegmentIndex: () => Promise.resolve(),
|
|
4919
|
+
segmentIndex: new shaka.media.SegmentIndex(references),
|
|
4920
|
+
mimeType: mimeType || '',
|
|
4921
|
+
codecs: '',
|
|
4922
|
+
kind: '',
|
|
4923
|
+
encrypted: false,
|
|
4924
|
+
drmInfos: [],
|
|
4925
|
+
keyIds: new Set(),
|
|
4926
|
+
language: 'und',
|
|
4927
|
+
label: null,
|
|
4928
|
+
type: ContentType.IMAGE,
|
|
4929
|
+
primary: false,
|
|
4930
|
+
trickModeVideo: null,
|
|
4931
|
+
emsgSchemeIdUris: null,
|
|
4932
|
+
roles: [],
|
|
4933
|
+
forced: false,
|
|
4934
|
+
channelsCount: null,
|
|
4935
|
+
audioSamplingRate: null,
|
|
4936
|
+
spatialAudio: false,
|
|
4937
|
+
closedCaptions: null,
|
|
4938
|
+
tilesLayout: '1x1',
|
|
4939
|
+
};
|
|
4940
|
+
|
|
4941
|
+
this.manifest_.imageStreams.push(stream);
|
|
4942
|
+
this.onTracksChanged_();
|
|
4943
|
+
return shaka.util.StreamUtils.imageStreamToTrack(stream);
|
|
4944
|
+
}
|
|
4945
|
+
|
|
4616
4946
|
/**
|
|
4617
4947
|
* Adds the given chapters track to the loaded manifest. <code>load()</code>
|
|
4618
4948
|
* must resolve before calling. The presentation must have a duration.
|
|
@@ -5084,28 +5414,39 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5084
5414
|
}
|
|
5085
5415
|
|
|
5086
5416
|
// We may need to create new sessions for any new init data.
|
|
5087
|
-
const
|
|
5417
|
+
const currentDrmInfo =
|
|
5418
|
+
this.drmEngine_ ? this.drmEngine_.getDrmInfo() : null;
|
|
5088
5419
|
// DrmEngine.newInitData() requires mediaKeys to be available.
|
|
5089
|
-
if (
|
|
5420
|
+
if (currentDrmInfo && this.drmEngine_.getMediaKeys()) {
|
|
5090
5421
|
for (const variant of manifest.variants) {
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
const drmInfos = videoDrmInfos.concat(audioDrmInfos);
|
|
5094
|
-
for (const drmInfo of drmInfos) {
|
|
5095
|
-
// Ignore any data for different key systems.
|
|
5096
|
-
if (drmInfo.keySystem == curDrmInfo.keySystem) {
|
|
5097
|
-
for (const initData of (drmInfo.initData || [])) {
|
|
5098
|
-
this.drmEngine_.newInitData(
|
|
5099
|
-
initData.initDataType, initData.initData);
|
|
5100
|
-
}
|
|
5101
|
-
}
|
|
5102
|
-
}
|
|
5422
|
+
this.processDrmInfos_(currentDrmInfo.keySystem, variant.video);
|
|
5423
|
+
this.processDrmInfos_(currentDrmInfo.keySystem, variant.audio);
|
|
5103
5424
|
}
|
|
5104
5425
|
}
|
|
5105
|
-
|
|
5106
5426
|
this.checkRestrictedVariants_(manifest);
|
|
5107
5427
|
}
|
|
5108
5428
|
|
|
5429
|
+
/**
|
|
5430
|
+
* @param {string} keySystem
|
|
5431
|
+
* @param {?shaka.extern.Stream} stream
|
|
5432
|
+
* @private
|
|
5433
|
+
*/
|
|
5434
|
+
processDrmInfos_(keySystem, stream) {
|
|
5435
|
+
if (!stream) {
|
|
5436
|
+
return;
|
|
5437
|
+
}
|
|
5438
|
+
|
|
5439
|
+
for (const drmInfo of stream.drmInfos) {
|
|
5440
|
+
// Ignore any data for different key systems.
|
|
5441
|
+
if (drmInfo.keySystem == keySystem) {
|
|
5442
|
+
for (const initData of (drmInfo.initData || [])) {
|
|
5443
|
+
this.drmEngine_.newInitData(
|
|
5444
|
+
initData.initDataType, initData.initData);
|
|
5445
|
+
}
|
|
5446
|
+
}
|
|
5447
|
+
}
|
|
5448
|
+
}
|
|
5449
|
+
|
|
5109
5450
|
/**
|
|
5110
5451
|
* @private
|
|
5111
5452
|
*/
|
|
@@ -5481,38 +5822,62 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5481
5822
|
/**
|
|
5482
5823
|
* Check if we should show text on screen automatically.
|
|
5483
5824
|
*
|
|
5484
|
-
* The text should automatically be shown if the text is language-compatible
|
|
5485
|
-
* with the user's text language preference, but not compatible with the
|
|
5486
|
-
* audio.
|
|
5487
|
-
*
|
|
5488
|
-
* For example:
|
|
5489
|
-
* preferred | chosen | chosen |
|
|
5490
|
-
* text | text | audio | show
|
|
5491
|
-
* -----------------------------------
|
|
5492
|
-
* en-CA | en | jp | true
|
|
5493
|
-
* en | en-US | fr | true
|
|
5494
|
-
* fr-CA | en-US | jp | false
|
|
5495
|
-
* en-CA | en-US | en-US | false
|
|
5496
|
-
*
|
|
5497
5825
|
* @param {shaka.extern.Stream} audioStream
|
|
5498
5826
|
* @param {shaka.extern.Stream} textStream
|
|
5499
5827
|
* @return {boolean}
|
|
5500
5828
|
* @private
|
|
5501
5829
|
*/
|
|
5502
5830
|
shouldInitiallyShowText_(audioStream, textStream) {
|
|
5831
|
+
const AutoShowText = shaka.config.AutoShowText;
|
|
5832
|
+
|
|
5833
|
+
if (this.config_.autoShowText == AutoShowText.NEVER) {
|
|
5834
|
+
return false;
|
|
5835
|
+
}
|
|
5836
|
+
if (this.config_.autoShowText == AutoShowText.ALWAYS) {
|
|
5837
|
+
return true;
|
|
5838
|
+
}
|
|
5839
|
+
|
|
5503
5840
|
const LanguageUtils = shaka.util.LanguageUtils;
|
|
5504
5841
|
|
|
5505
5842
|
/** @type {string} */
|
|
5506
5843
|
const preferredTextLocale =
|
|
5507
5844
|
LanguageUtils.normalize(this.config_.preferredTextLanguage);
|
|
5508
5845
|
/** @type {string} */
|
|
5509
|
-
const audioLocale = LanguageUtils.normalize(audioStream.language);
|
|
5510
|
-
/** @type {string} */
|
|
5511
5846
|
const textLocale = LanguageUtils.normalize(textStream.language);
|
|
5512
5847
|
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5848
|
+
if (this.config_.autoShowText == AutoShowText.IF_PREFERRED_TEXT_LANGUAGE) {
|
|
5849
|
+
// Only the text language match matters.
|
|
5850
|
+
return LanguageUtils.areLanguageCompatible(
|
|
5851
|
+
textLocale,
|
|
5852
|
+
preferredTextLocale);
|
|
5853
|
+
}
|
|
5854
|
+
|
|
5855
|
+
if (this.config_.autoShowText == AutoShowText.IF_SUBTITLES_MAY_BE_NEEDED) {
|
|
5856
|
+
/* The text should automatically be shown if the text is
|
|
5857
|
+
* language-compatible with the user's text language preference, but not
|
|
5858
|
+
* compatible with the audio. These are cases where we deduce that
|
|
5859
|
+
* subtitles may be needed.
|
|
5860
|
+
*
|
|
5861
|
+
* For example:
|
|
5862
|
+
* preferred | chosen | chosen |
|
|
5863
|
+
* text | text | audio | show
|
|
5864
|
+
* -----------------------------------
|
|
5865
|
+
* en-CA | en | jp | true
|
|
5866
|
+
* en | en-US | fr | true
|
|
5867
|
+
* fr-CA | en-US | jp | false
|
|
5868
|
+
* en-CA | en-US | en-US | false
|
|
5869
|
+
*
|
|
5870
|
+
*/
|
|
5871
|
+
/** @type {string} */
|
|
5872
|
+
const audioLocale = LanguageUtils.normalize(audioStream.language);
|
|
5873
|
+
|
|
5874
|
+
return (
|
|
5875
|
+
LanguageUtils.areLanguageCompatible(textLocale, preferredTextLocale) &&
|
|
5876
|
+
!LanguageUtils.areLanguageCompatible(audioLocale, textLocale));
|
|
5877
|
+
}
|
|
5878
|
+
|
|
5879
|
+
shaka.log.alwaysWarn('Invalid autoShowText setting!');
|
|
5880
|
+
return false;
|
|
5516
5881
|
}
|
|
5517
5882
|
|
|
5518
5883
|
/**
|
|
@@ -5531,7 +5896,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5531
5896
|
*
|
|
5532
5897
|
* @private
|
|
5533
5898
|
*/
|
|
5534
|
-
onSegmentAppended_() {
|
|
5899
|
+
onSegmentAppended_(start, end, contentType) {
|
|
5535
5900
|
// When we append a segment to media source (via streaming engine) we are
|
|
5536
5901
|
// changing what data we have buffered, so notify the playhead of the
|
|
5537
5902
|
// change.
|
|
@@ -5539,6 +5904,14 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5539
5904
|
this.playhead_.notifyOfBufferingChange();
|
|
5540
5905
|
}
|
|
5541
5906
|
this.pollBufferState_();
|
|
5907
|
+
|
|
5908
|
+
// Dispatch an event for users to consume, too.
|
|
5909
|
+
const data = new Map()
|
|
5910
|
+
.set('start', start)
|
|
5911
|
+
.set('end', end)
|
|
5912
|
+
.set('contentType', contentType);
|
|
5913
|
+
this.dispatchEvent(this.makeEvent_(
|
|
5914
|
+
shaka.util.FakeEvent.EventName.SegmentAppended, data));
|
|
5542
5915
|
}
|
|
5543
5916
|
|
|
5544
5917
|
/**
|
|
@@ -5584,6 +5957,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5584
5957
|
const data = new Map()
|
|
5585
5958
|
.set('oldTrack', from)
|
|
5586
5959
|
.set('newTrack', to);
|
|
5960
|
+
if (this.lcevcDil_) {
|
|
5961
|
+
this.lcevcDil_.updateVariant(to);
|
|
5962
|
+
}
|
|
5587
5963
|
const event =
|
|
5588
5964
|
this.makeEvent_(shaka.util.FakeEvent.EventName.Adaptation, data);
|
|
5589
5965
|
this.delayDispatchEvent_(event);
|
|
@@ -5612,6 +5988,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5612
5988
|
const data = new Map()
|
|
5613
5989
|
.set('oldTrack', from)
|
|
5614
5990
|
.set('newTrack', to);
|
|
5991
|
+
if (this.lcevcDil_) {
|
|
5992
|
+
this.lcevcDil_.updateVariant(to);
|
|
5993
|
+
}
|
|
5994
|
+
|
|
5615
5995
|
const event =
|
|
5616
5996
|
this.makeEvent_(shaka.util.FakeEvent.EventName.VariantChanged, data);
|
|
5617
5997
|
this.delayDispatchEvent_(event);
|
|
@@ -6556,7 +6936,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
6556
6936
|
}
|
|
6557
6937
|
};
|
|
6558
6938
|
|
|
6559
|
-
|
|
6560
6939
|
/**
|
|
6561
6940
|
* In order to know what method of loading the player used for some content, we
|
|
6562
6941
|
* have this enum. It lets us know if content has not been loaded, loaded with
|
|
@@ -6595,7 +6974,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6595
6974
|
* @define {string} A version number taken from git at compile time.
|
|
6596
6975
|
* @export
|
|
6597
6976
|
*/
|
|
6598
|
-
shaka.Player.version = 'v4.
|
|
6977
|
+
shaka.Player.version = 'v4.3.1-uncompiled';
|
|
6599
6978
|
|
|
6600
6979
|
// Initialize the deprecation system using the version string we just set
|
|
6601
6980
|
// on the player.
|