shaka-player 3.1.3 → 3.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AUTHORS +3 -0
- package/CHANGELOG.md +175 -3
- package/CONTRIBUTORS +3 -0
- package/README.md +4 -4
- package/build/generateExterns.js +1 -1
- package/build/types/polyfill +1 -0
- package/demo/common/asset.js +9 -7
- package/demo/common/assets.js +11 -2
- package/demo/common/message_ids.js +2 -1
- package/demo/config.js +5 -2
- package/demo/index.html +1 -1
- package/demo/locales/en.json +2 -1
- package/demo/locales/source.json +8 -4
- package/demo/main.js +2 -1
- package/dist/controls.css +2 -2
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +15 -15
- package/dist/demo.compiled.debug.map +2 -2
- package/dist/demo.compiled.js +15 -15
- package/dist/demo.compiled.map +2 -2
- package/dist/deps.js +22 -21
- package/dist/locales.js +36 -36
- package/dist/receiver.compiled.debug.js +9 -9
- package/dist/receiver.compiled.debug.map +2 -2
- package/dist/receiver.compiled.js +9 -9
- package/dist/receiver.compiled.map +2 -2
- package/dist/shaka-player.compiled.d.ts +58 -10
- package/dist/shaka-player.compiled.debug.d.ts +58 -10
- package/dist/shaka-player.compiled.debug.externs.js +777 -717
- package/dist/shaka-player.compiled.debug.js +639 -607
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +777 -717
- package/dist/shaka-player.compiled.js +826 -819
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +58 -10
- package/dist/shaka-player.ui.debug.d.ts +58 -10
- package/dist/shaka-player.ui.debug.externs.js +529 -469
- package/dist/shaka-player.ui.debug.js +676 -645
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +529 -469
- package/dist/shaka-player.ui.js +963 -955
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/fairplay.md +1 -1
- package/docs/tutorials/ui.md +5 -5
- package/externs/aria.js +6 -0
- package/externs/shaka/ads.js +24 -1
- package/externs/shaka/manifest.js +6 -1
- package/externs/shaka/offline.js +5 -0
- package/externs/shaka/player.js +53 -9
- package/externs/shaka/text.js +10 -10
- package/externs/texttrack.js +3 -0
- package/karma.conf.js +1 -0
- package/lib/ads/ad_manager.js +16 -15
- package/lib/ads/client_side_ad_manager.js +52 -88
- package/lib/ads/server_side_ad_manager.js +26 -12
- package/lib/cast/cast_proxy.js +11 -2
- package/lib/cast/cast_receiver.js +2 -1
- package/lib/cast/cast_sender.js +2 -2
- package/lib/cast/cast_utils.js +6 -1
- package/lib/cea/cea608_data_channel.js +56 -56
- package/lib/cea/cea608_memory.js +33 -33
- package/lib/cea/cea708_service.js +43 -43
- package/lib/cea/cea708_window.js +38 -38
- package/lib/cea/cea_decoder.js +13 -14
- package/lib/cea/cea_utils.js +23 -23
- package/lib/cea/dtvcc_packet_builder.js +7 -7
- package/lib/cea/i_caption_decoder.js +2 -3
- package/lib/cea/i_cea_parser.js +2 -2
- package/lib/cea/mp4_cea_parser.js +6 -6
- package/lib/dash/dash_parser.js +98 -2
- package/lib/dash/segment_list.js +1 -1
- package/lib/dash/segment_template.js +1 -1
- package/lib/hls/hls_parser.js +159 -29
- package/lib/media/closed_caption_parser.js +1 -2
- package/lib/media/drm_engine.js +169 -192
- package/lib/media/gap_jumping_controller.js +4 -2
- package/lib/media/media_source_engine.js +1 -2
- package/lib/media/segment_index.js +3 -1
- package/lib/media/segment_reference.js +19 -2
- package/lib/media/streaming_engine.js +8 -7
- package/lib/net/networking_engine.js +3 -1
- package/lib/offline/download_manager.js +1 -2
- package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
- package/lib/offline/manifest_converter.js +3 -1
- package/lib/offline/storage.js +12 -14
- package/lib/player.js +437 -167
- package/lib/polyfill/aria.js +82 -0
- package/lib/polyfill/media_capabilities.js +7 -1
- 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/routing/walker.js +2 -3
- package/lib/text/mp4_ttml_parser.js +3 -0
- package/lib/text/srt_text_parser.js +4 -4
- package/lib/text/text_engine.js +16 -4
- package/lib/text/ttml_text_parser.js +5 -0
- package/lib/text/ui_text_displayer.js +85 -37
- package/lib/text/vtt_text_parser.js +2 -2
- package/lib/text/web_vtt_generator.js +55 -12
- package/lib/util/error.js +6 -0
- package/lib/util/fake_event.js +53 -7
- package/lib/util/manifest_parser_utils.js +1 -0
- package/lib/util/mp4_box_parsers.js +20 -20
- package/lib/util/multi_map.js +8 -0
- package/lib/util/periods.js +4 -1
- package/lib/util/platform.js +13 -1
- package/lib/util/player_configuration.js +13 -1
- package/lib/util/stream_utils.js +153 -85
- package/lib/util/xml_utils.js +31 -12
- package/package.json +1 -1
- package/roadmap.md +24 -22
- package/shaka-player.uncompiled.js +1 -0
- package/test/cast/cast_proxy_unit.js +12 -6
- package/test/cast/cast_utils_unit.js +2 -1
- package/test/cea/cea608_memory_unit.js +1 -1
- package/test/cea/cea708_service_unit.js +8 -8
- package/test/cea/cea708_window_unit.js +6 -6
- package/test/cea/cea_decoder_unit.js +1 -1
- package/test/cea/dtvcc_packet_builder_unit.js +2 -2
- package/test/dash/dash_parser_manifest_unit.js +230 -2
- package/test/hls/hls_parser_unit.js +255 -1
- package/test/media/closed_caption_parser_unit.js +6 -1
- package/test/media/drm_engine_integration.js +86 -12
- package/test/media/drm_engine_unit.js +353 -450
- package/test/offline/manifest_convert_unit.js +2 -0
- package/test/offline/storage_integration.js +9 -19
- package/test/player_integration.js +90 -0
- package/test/player_src_equals_integration.js +52 -0
- package/test/player_unit.js +11 -33
- 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.srt +11 -0
- package/test/test/assets/chapters.vtt +10 -0
- package/test/test/util/cea_utils.js +12 -12
- package/test/test/util/fake_ad_manager.js +8 -1
- package/test/test/util/manifest_generator.js +2 -0
- package/test/test/util/manifest_parser_util.js +3 -1
- package/test/text/ttml_text_parser_unit.js +9 -0
- package/test/text/ui_text_displayer_unit.js +29 -17
- package/test/text/web_vtt_generator_unit.js +81 -7
- package/test/ui/localization_unit.js +15 -14
- package/test/ui/text_displayer_layout_unit.js +13 -1
- package/test/util/stream_utils_unit.js +153 -10
- package/ui/airplay_button.js +1 -1
- package/ui/audio_language_selection.js +2 -5
- package/ui/cast_button.js +6 -9
- package/ui/constants.js +0 -3
- package/ui/controls.js +4 -6
- package/ui/fast_forward_button.js +2 -3
- package/ui/fullscreen_button.js +1 -3
- package/ui/language_utils.js +1 -1
- package/ui/less/containers.less +3 -7
- package/ui/locales/ru.json +6 -6
- package/ui/localization.js +28 -51
- package/ui/loop_button.js +1 -3
- package/ui/mute_button.js +1 -3
- package/ui/overflow_menu.js +2 -3
- package/ui/pip_button.js +7 -10
- package/ui/playback_rate_selection.js +3 -6
- package/ui/presentation_time.js +1 -3
- package/ui/resolution_selection.js +4 -7
- package/ui/rewind_button.js +2 -3
- package/ui/seek_bar.js +2 -4
- package/ui/spacer.js +1 -1
- package/ui/text_selection.js +8 -11
- package/ui/ui_utils.js +1 -1
- package/ui/volume_bar.js +1 -3
package/lib/player.js
CHANGED
|
@@ -217,6 +217,8 @@ goog.requireType('shaka.routing.Payload');
|
|
|
217
217
|
* <code>selectAudioLanguage()</code>, or <code>selectTextLanguage()</code>.
|
|
218
218
|
* @property {string} type
|
|
219
219
|
* 'adaptation'
|
|
220
|
+
* @property {shaka.extern.Track} oldTrack
|
|
221
|
+
* @property {shaka.extern.Track} newTrack
|
|
220
222
|
* @exportDoc
|
|
221
223
|
*/
|
|
222
224
|
|
|
@@ -596,7 +598,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
596
598
|
enterNode: (node, has, wants) => {
|
|
597
599
|
this.dispatchEvent(this.makeEvent_(
|
|
598
600
|
/* name= */ shaka.Player.EventName.OnStateChange,
|
|
599
|
-
/* data= */
|
|
601
|
+
/* data= */ (new Map()).set('state', node.name)));
|
|
600
602
|
|
|
601
603
|
const action = actions.get(node);
|
|
602
604
|
return action(has, wants);
|
|
@@ -627,7 +629,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
627
629
|
onIdle: (node) => {
|
|
628
630
|
this.dispatchEvent(this.makeEvent_(
|
|
629
631
|
/* name= */ shaka.Player.EventName.OnStateIdle,
|
|
630
|
-
/* data= */
|
|
632
|
+
/* data= */ (new Map()).set('state', node.name)));
|
|
631
633
|
},
|
|
632
634
|
};
|
|
633
635
|
|
|
@@ -647,7 +649,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
647
649
|
|
|
648
650
|
/**
|
|
649
651
|
* @param {!shaka.Player.EventName} name
|
|
650
|
-
* @param {Object
|
|
652
|
+
* @param {Map.<string, Object>=} data
|
|
651
653
|
* @return {!shaka.util.FakeEvent}
|
|
652
654
|
* @private
|
|
653
655
|
*/
|
|
@@ -1142,24 +1144,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1142
1144
|
if (!mimeType) {
|
|
1143
1145
|
// Try using the uri extension.
|
|
1144
1146
|
const extension = shaka.media.ManifestParser.getExtension(uri);
|
|
1145
|
-
mimeType =
|
|
1146
|
-
'mp4': 'video/mp4',
|
|
1147
|
-
'm4v': 'video/mp4',
|
|
1148
|
-
'm4a': 'audio/mp4',
|
|
1149
|
-
'webm': 'video/webm',
|
|
1150
|
-
'weba': 'audio/webm',
|
|
1151
|
-
'mkv': 'video/webm', // Chromium browsers supports it.
|
|
1152
|
-
'ts': 'video/mp2t',
|
|
1153
|
-
'ogv': 'video/ogg',
|
|
1154
|
-
'ogg': 'audio/ogg',
|
|
1155
|
-
'mpg': 'video/mpeg',
|
|
1156
|
-
'mpeg': 'video/mpeg',
|
|
1157
|
-
'm3u8': 'application/x-mpegurl',
|
|
1158
|
-
'mp3': 'audio/mpeg',
|
|
1159
|
-
'aac': 'audio/aac',
|
|
1160
|
-
'flac': 'audio/flac',
|
|
1161
|
-
'wav': 'audio/wav',
|
|
1162
|
-
}[extension];
|
|
1147
|
+
mimeType = shaka.Player.SRC_EQUAL_EXTENSIONS_TO_MIME_TYPES_[extension];
|
|
1163
1148
|
}
|
|
1164
1149
|
|
|
1165
1150
|
// TODO: The load graph system has a design limitation that requires routing
|
|
@@ -1633,11 +1618,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1633
1618
|
}
|
|
1634
1619
|
});
|
|
1635
1620
|
|
|
1636
|
-
// TODO (#1391): Once filterManifest_ is async, remove this eslint disable.
|
|
1637
|
-
/* eslint-disable require-await */
|
|
1638
1621
|
const playerInterface = {
|
|
1639
1622
|
networkingEngine: networkingEngine,
|
|
1640
|
-
filter:
|
|
1623
|
+
filter: (manifest) => this.filterManifest_(manifest),
|
|
1641
1624
|
makeTextStreamsForClosedCaptions: (manifest) => {
|
|
1642
1625
|
return this.makeTextStreamsForClosedCaptions_(manifest);
|
|
1643
1626
|
},
|
|
@@ -1655,7 +1638,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1655
1638
|
this.configure('streaming.lowLatencyMode', true);
|
|
1656
1639
|
},
|
|
1657
1640
|
};
|
|
1658
|
-
/* eslint-enable require-await */
|
|
1659
1641
|
|
|
1660
1642
|
const startTime = Date.now() / 1000;
|
|
1661
1643
|
|
|
@@ -1747,17 +1729,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1747
1729
|
},
|
|
1748
1730
|
});
|
|
1749
1731
|
|
|
1750
|
-
// TODO: remove once MediaCap implementation is complete.
|
|
1751
|
-
if (!this.config_.useMediaCapabilities) {
|
|
1752
|
-
shaka.util.StreamUtils.filterManifestByMediaSource(this.manifest_);
|
|
1753
|
-
}
|
|
1754
|
-
|
|
1755
1732
|
this.drmEngine_.configure(this.config_.drm);
|
|
1756
1733
|
|
|
1757
1734
|
await this.drmEngine_.initForPlayback(
|
|
1758
1735
|
this.manifest_.variants,
|
|
1759
|
-
this.manifest_.offlineSessionIds
|
|
1760
|
-
this.config_.useMediaCapabilities);
|
|
1736
|
+
this.manifest_.offlineSessionIds);
|
|
1761
1737
|
|
|
1762
1738
|
await this.drmEngine_.attach(has.mediaElement);
|
|
1763
1739
|
|
|
@@ -1872,7 +1848,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1872
1848
|
// If the content is multi-codec and the browser can play more than one of
|
|
1873
1849
|
// them, choose codecs now before we initialize streaming.
|
|
1874
1850
|
shaka.util.StreamUtils.chooseCodecsAndFilterManifest(
|
|
1875
|
-
this.manifest_,
|
|
1851
|
+
this.manifest_,
|
|
1852
|
+
this.config_.preferredVideoCodecs,
|
|
1853
|
+
this.config_.preferredAudioCodecs,
|
|
1854
|
+
this.config_.preferredAudioChannelCount,
|
|
1855
|
+
this.config_.preferredDecodingAttributes);
|
|
1876
1856
|
|
|
1877
1857
|
this.streamingEngine_ = this.createStreamingEngine();
|
|
1878
1858
|
this.streamingEngine_.configure(this.config_.streaming);
|
|
@@ -1911,7 +1891,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1911
1891
|
}
|
|
1912
1892
|
|
|
1913
1893
|
// Since the first streams just became active, send an adaptation event.
|
|
1914
|
-
this.onAdaptation_(
|
|
1894
|
+
this.onAdaptation_(null,
|
|
1895
|
+
shaka.util.StreamUtils.variantToTrack(initialVariant));
|
|
1915
1896
|
}
|
|
1916
1897
|
|
|
1917
1898
|
// Decide if text should be shown automatically.
|
|
@@ -2024,6 +2005,16 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2024
2005
|
|
|
2025
2006
|
this.drmEngine_.configure(this.config_.drm);
|
|
2026
2007
|
|
|
2008
|
+
const uri = wants.uri || '';
|
|
2009
|
+
const extension = shaka.media.ManifestParser.getExtension(uri);
|
|
2010
|
+
let mimeType = shaka.Player.SRC_EQUAL_EXTENSIONS_TO_MIME_TYPES_[extension];
|
|
2011
|
+
if (mimeType == 'application/x-mpegurl' && shaka.util.Platform.isApple()) {
|
|
2012
|
+
mimeType = 'application/vnd.apple.mpegurl';
|
|
2013
|
+
}
|
|
2014
|
+
if (!mimeType) {
|
|
2015
|
+
mimeType = 'video/mp4';
|
|
2016
|
+
}
|
|
2017
|
+
|
|
2027
2018
|
// TODO: Instead of feeding DrmEngine with Variants, we should refactor
|
|
2028
2019
|
// DrmEngine so that it takes a minimal config derived from Variants. In
|
|
2029
2020
|
// cases like this one or in removal of stored content, the details are
|
|
@@ -2044,7 +2035,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2044
2035
|
createSegmentIndex: () => Promise.resolve(),
|
|
2045
2036
|
segmentIndex: null,
|
|
2046
2037
|
mimeType: wants.mimeType ?
|
|
2047
|
-
shaka.util.MimeUtils.getBasicType(wants.mimeType) :
|
|
2038
|
+
shaka.util.MimeUtils.getBasicType(wants.mimeType) : mimeType,
|
|
2048
2039
|
codecs: wants.mimeType ?
|
|
2049
2040
|
shaka.util.MimeUtils.getCodecs(wants.mimeType) : '',
|
|
2050
2041
|
encrypted: true,
|
|
@@ -2163,8 +2154,22 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2163
2154
|
}
|
|
2164
2155
|
if (this.video_.textTracks) {
|
|
2165
2156
|
this.eventManager_.listen(this.video_.textTracks, 'addtrack', (e) => {
|
|
2166
|
-
|
|
2167
|
-
|
|
2157
|
+
const trackEvent = /** @type {!TrackEvent} */(e);
|
|
2158
|
+
if (trackEvent.track) {
|
|
2159
|
+
const track = trackEvent.track;
|
|
2160
|
+
goog.asserts.assert(track instanceof TextTrack, 'Wrong track type!');
|
|
2161
|
+
switch (track.kind) {
|
|
2162
|
+
case 'metadata':
|
|
2163
|
+
this.processTimedMetadataSrcEqls_(track);
|
|
2164
|
+
break;
|
|
2165
|
+
case 'chapters':
|
|
2166
|
+
this.processChaptersTrack_(track);
|
|
2167
|
+
break;
|
|
2168
|
+
default:
|
|
2169
|
+
this.onTracksChanged_();
|
|
2170
|
+
break;
|
|
2171
|
+
}
|
|
2172
|
+
}
|
|
2168
2173
|
});
|
|
2169
2174
|
this.eventManager_.listen(
|
|
2170
2175
|
this.video_.textTracks, 'removetrack', () => this.onTracksChanged_());
|
|
@@ -2337,13 +2342,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2337
2342
|
* We're looking for metadata tracks to process id3 tags. One of the uses is
|
|
2338
2343
|
* for ad info on LIVE streams
|
|
2339
2344
|
*
|
|
2340
|
-
* @param {!
|
|
2345
|
+
* @param {!TextTrack} track
|
|
2341
2346
|
* @private
|
|
2342
2347
|
*/
|
|
2343
|
-
processTimedMetadataSrcEqls_(
|
|
2344
|
-
const track = event.track;
|
|
2345
|
-
goog.asserts.assert(track instanceof TextTrack, 'Wrong track type!');
|
|
2346
|
-
|
|
2348
|
+
processTimedMetadataSrcEqls_(track) {
|
|
2347
2349
|
if (track.kind != 'metadata') {
|
|
2348
2350
|
return;
|
|
2349
2351
|
}
|
|
@@ -2415,15 +2417,40 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2415
2417
|
goog.asserts.assert(!endTime || startTime <= endTime,
|
|
2416
2418
|
'Metadata start time should be less or equal to the end time!');
|
|
2417
2419
|
const eventName = shaka.Player.EventName.Metadata;
|
|
2418
|
-
const data =
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
};
|
|
2420
|
+
const data = new Map()
|
|
2421
|
+
.set('startTime', startTime)
|
|
2422
|
+
.set('endTime', endTime)
|
|
2423
|
+
.set('metadataType', metadataType)
|
|
2424
|
+
.set('payload', payload);
|
|
2424
2425
|
this.dispatchEvent(this.makeEvent_(eventName, data));
|
|
2425
2426
|
}
|
|
2426
2427
|
|
|
2428
|
+
/**
|
|
2429
|
+
* We're looking for chapters tracks to process the chapters.
|
|
2430
|
+
*
|
|
2431
|
+
* @param {?TextTrack} track
|
|
2432
|
+
* @private
|
|
2433
|
+
*/
|
|
2434
|
+
processChaptersTrack_(track) {
|
|
2435
|
+
if (!track || track.kind != 'chapters') {
|
|
2436
|
+
return;
|
|
2437
|
+
}
|
|
2438
|
+
|
|
2439
|
+
// Hidden mode is required for the cuechange event to launch correctly and
|
|
2440
|
+
// get the cues and the activeCues
|
|
2441
|
+
track.mode = 'hidden';
|
|
2442
|
+
|
|
2443
|
+
// In Safari the initial assignment does not always work, so we schedule
|
|
2444
|
+
// this process to be repeated several times to ensure that it has been put
|
|
2445
|
+
// in the correct mode.
|
|
2446
|
+
new shaka.util.Timer(() => {
|
|
2447
|
+
const chaptersTracks = this.getChaptersTracks_();
|
|
2448
|
+
for (const chaptersTrack of chaptersTracks) {
|
|
2449
|
+
chaptersTrack.mode = 'hidden';
|
|
2450
|
+
}
|
|
2451
|
+
}).tickNow().tickAfter(/* seconds= */ 0.5);
|
|
2452
|
+
}
|
|
2453
|
+
|
|
2427
2454
|
/**
|
|
2428
2455
|
* Take a series of variants and ensure that they only contain one type of
|
|
2429
2456
|
* variant. The different options are:
|
|
@@ -2869,6 +2896,32 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2869
2896
|
return this.config_;
|
|
2870
2897
|
}
|
|
2871
2898
|
|
|
2899
|
+
/**
|
|
2900
|
+
* Returns the ratio of video length buffered compared to buffering Goal
|
|
2901
|
+
* @return {number}
|
|
2902
|
+
* @export
|
|
2903
|
+
*/
|
|
2904
|
+
getBufferFullness() {
|
|
2905
|
+
if (this.video_) {
|
|
2906
|
+
const bufferedLength = this.video_.buffered.length;
|
|
2907
|
+
const bufferedEnd =
|
|
2908
|
+
bufferedLength ? this.video_.buffered.end(bufferedLength - 1) : 0;
|
|
2909
|
+
const bufferingGoal = this.getConfiguration().streaming.bufferingGoal;
|
|
2910
|
+
const lengthToBeBuffered = Math.min(this.video_.currentTime +
|
|
2911
|
+
bufferingGoal, this.seekRange().end);
|
|
2912
|
+
|
|
2913
|
+
if (bufferedEnd >= lengthToBeBuffered) {
|
|
2914
|
+
return 1;
|
|
2915
|
+
} else if (bufferedEnd <= this.video_.currentTime) {
|
|
2916
|
+
return 0;
|
|
2917
|
+
} else if (bufferedEnd < lengthToBeBuffered) {
|
|
2918
|
+
return ((bufferedEnd - this.video_.currentTime) /
|
|
2919
|
+
(lengthToBeBuffered - this.video_.currentTime));
|
|
2920
|
+
}
|
|
2921
|
+
}
|
|
2922
|
+
return 0;
|
|
2923
|
+
}
|
|
2924
|
+
|
|
2872
2925
|
/**
|
|
2873
2926
|
* Reset configuration to default.
|
|
2874
2927
|
* @export
|
|
@@ -3079,6 +3132,19 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3079
3132
|
return {'start': 0, 'end': 0};
|
|
3080
3133
|
}
|
|
3081
3134
|
|
|
3135
|
+
/**
|
|
3136
|
+
* Go to live in a live stream.
|
|
3137
|
+
*
|
|
3138
|
+
* @export
|
|
3139
|
+
*/
|
|
3140
|
+
goToLive() {
|
|
3141
|
+
if (this.isLive()) {
|
|
3142
|
+
this.video_.currentTime = this.seekRange().end;
|
|
3143
|
+
} else {
|
|
3144
|
+
shaka.log.warning('goToLive is for live streams!');
|
|
3145
|
+
}
|
|
3146
|
+
}
|
|
3147
|
+
|
|
3082
3148
|
/**
|
|
3083
3149
|
* Get the key system currently used by EME. If EME is not being used, this
|
|
3084
3150
|
* will return an empty string. If the player has not loaded content, this
|
|
@@ -3103,6 +3169,19 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3103
3169
|
return this.drmEngine_ ? this.drmEngine_.getDrmInfo() : null;
|
|
3104
3170
|
}
|
|
3105
3171
|
|
|
3172
|
+
|
|
3173
|
+
/**
|
|
3174
|
+
* Get the drm engine.
|
|
3175
|
+
* This method should only be used for testing. Applications SHOULD NOT
|
|
3176
|
+
* use this in production.
|
|
3177
|
+
*
|
|
3178
|
+
* @return {?shaka.media.DrmEngine}
|
|
3179
|
+
*/
|
|
3180
|
+
getDrmEngine() {
|
|
3181
|
+
return this.drmEngine_;
|
|
3182
|
+
}
|
|
3183
|
+
|
|
3184
|
+
|
|
3106
3185
|
/**
|
|
3107
3186
|
* Get the next known expiration time for any EME session. If the session
|
|
3108
3187
|
* never expires, this will return <code>Infinity</code>. If there are no EME
|
|
@@ -3357,9 +3436,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3357
3436
|
return null;
|
|
3358
3437
|
}
|
|
3359
3438
|
const reference = imageStream.segmentIndex.get(referencePosition);
|
|
3439
|
+
const tilesLayout =
|
|
3440
|
+
reference.getTilesLayout() || imageStream.tilesLayout;
|
|
3360
3441
|
// This expression is used to detect one or more numbers (0-9) followed
|
|
3361
3442
|
// by an x and after one or more numbers (0-9)
|
|
3362
|
-
const match = /(\d+)x(\d+)/.exec(
|
|
3443
|
+
const match = /(\d+)x(\d+)/.exec(tilesLayout);
|
|
3363
3444
|
if (!match) {
|
|
3364
3445
|
shaka.log.warning('Tiles layout does not contain a valid format ' +
|
|
3365
3446
|
' (columns x rows)');
|
|
@@ -3599,36 +3680,34 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3599
3680
|
new shaka.media.PreferenceBasedCriteria(language, role || '',
|
|
3600
3681
|
/* channelCount= */ 0, /* label= */ '');
|
|
3601
3682
|
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
return Math.abs((a.video.height || 0) - (b.video.height || 0)) +
|
|
3683
|
+
const diff = (a, b) => {
|
|
3684
|
+
if (!a.video && !b.video) {
|
|
3685
|
+
return 0;
|
|
3686
|
+
} else if (!a.video || !b.video) {
|
|
3687
|
+
return Infinity;
|
|
3688
|
+
} else {
|
|
3689
|
+
return Math.abs((a.video.height || 0) - (b.video.height || 0)) +
|
|
3610
3690
|
Math.abs((a.video.width || 0) - (b.video.width || 0));
|
|
3611
|
-
|
|
3612
|
-
|
|
3691
|
+
}
|
|
3692
|
+
};
|
|
3613
3693
|
// Find the variant whose size is closest to the active variant. This
|
|
3614
3694
|
// ensures we stay at about the same resolution when just changing the
|
|
3615
3695
|
// language/role.
|
|
3616
|
-
|
|
3617
|
-
|
|
3696
|
+
const active = this.streamingEngine_.getCurrentVariant();
|
|
3697
|
+
const set =
|
|
3618
3698
|
this.currentAdaptationSetCriteria_.create(this.manifest_.variants);
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3699
|
+
let bestVariant = null;
|
|
3700
|
+
for (const curVariant of set.values()) {
|
|
3701
|
+
if (!bestVariant ||
|
|
3622
3702
|
diff(bestVariant, active) > diff(curVariant, active)) {
|
|
3623
|
-
|
|
3624
|
-
}
|
|
3625
|
-
}
|
|
3626
|
-
if (bestVariant) {
|
|
3627
|
-
const track = shaka.util.StreamUtils.variantToTrack(bestVariant);
|
|
3628
|
-
this.selectVariantTrack(track, /* clearBuffer= */ true);
|
|
3629
|
-
return;
|
|
3703
|
+
bestVariant = curVariant;
|
|
3630
3704
|
}
|
|
3631
3705
|
}
|
|
3706
|
+
if (bestVariant) {
|
|
3707
|
+
const track = shaka.util.StreamUtils.variantToTrack(bestVariant);
|
|
3708
|
+
this.selectVariantTrack(track, /* clearBuffer= */ true);
|
|
3709
|
+
return;
|
|
3710
|
+
}
|
|
3632
3711
|
|
|
3633
3712
|
// If we haven't switched yet, just use ABR to find a new track.
|
|
3634
3713
|
this.chooseVariantAndSwitch_();
|
|
@@ -3772,6 +3851,51 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3772
3851
|
return expected;
|
|
3773
3852
|
}
|
|
3774
3853
|
|
|
3854
|
+
/**
|
|
3855
|
+
* Return a list of chapters tracks.
|
|
3856
|
+
*
|
|
3857
|
+
* @return {!Array.<shaka.extern.Track>}
|
|
3858
|
+
* @export
|
|
3859
|
+
*/
|
|
3860
|
+
getChaptersTracks() {
|
|
3861
|
+
if (this.video_ && this.video_.src && this.video_.textTracks) {
|
|
3862
|
+
const textTracks = this.getChaptersTracks_();
|
|
3863
|
+
const StreamUtils = shaka.util.StreamUtils;
|
|
3864
|
+
return textTracks.map((text) => StreamUtils.html5TextTrackToTrack(text));
|
|
3865
|
+
} else {
|
|
3866
|
+
return [];
|
|
3867
|
+
}
|
|
3868
|
+
}
|
|
3869
|
+
|
|
3870
|
+
/**
|
|
3871
|
+
* This returns the list of chapters.
|
|
3872
|
+
*
|
|
3873
|
+
* @param {string} language
|
|
3874
|
+
* @return {!Array.<shaka.extern.Chapter>}
|
|
3875
|
+
* @export
|
|
3876
|
+
*/
|
|
3877
|
+
getChapters(language) {
|
|
3878
|
+
const LanguageUtils = shaka.util.LanguageUtils;
|
|
3879
|
+
const inputlanguage = LanguageUtils.normalize(language);
|
|
3880
|
+
const chaptersTracks = this.getChaptersTracks_();
|
|
3881
|
+
const chaptersTrack = chaptersTracks
|
|
3882
|
+
.find((t) => LanguageUtils.normalize(t.language) == inputlanguage);
|
|
3883
|
+
if (!chaptersTrack || !chaptersTrack.cues) {
|
|
3884
|
+
return [];
|
|
3885
|
+
}
|
|
3886
|
+
const chapters = [];
|
|
3887
|
+
for (const cue of chaptersTrack.cues) {
|
|
3888
|
+
/** @type {shaka.extern.Chapter} */
|
|
3889
|
+
const chapter = {
|
|
3890
|
+
title: cue.text,
|
|
3891
|
+
startTime: cue.startTime,
|
|
3892
|
+
endTime: cue.endTime,
|
|
3893
|
+
};
|
|
3894
|
+
chapters.push(chapter);
|
|
3895
|
+
}
|
|
3896
|
+
return chapters;
|
|
3897
|
+
}
|
|
3898
|
+
|
|
3775
3899
|
/**
|
|
3776
3900
|
* Ignore the TextTracks with the 'metadata' or 'chapters' kind, or the one
|
|
3777
3901
|
* generated by the SimpleTextDisplayer.
|
|
@@ -3800,6 +3924,19 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3800
3924
|
.filter((t) => t.kind == 'metadata');
|
|
3801
3925
|
}
|
|
3802
3926
|
|
|
3927
|
+
/**
|
|
3928
|
+
* Get the TextTracks with the 'chapters' kind.
|
|
3929
|
+
*
|
|
3930
|
+
* @return {!Array.<TextTrack>}
|
|
3931
|
+
* @private
|
|
3932
|
+
*/
|
|
3933
|
+
getChaptersTracks_() {
|
|
3934
|
+
goog.asserts.assert(this.video_.textTracks,
|
|
3935
|
+
'TextTracks should be valid.');
|
|
3936
|
+
return Array.from(this.video_.textTracks)
|
|
3937
|
+
.filter((t) => t.kind == 'chapters');
|
|
3938
|
+
}
|
|
3939
|
+
|
|
3803
3940
|
/**
|
|
3804
3941
|
* Enable or disable the text displayer. If the player is in an unloaded
|
|
3805
3942
|
* state, the request will be applied next time content is loaded.
|
|
@@ -4101,16 +4238,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4101
4238
|
if (!mimeType) {
|
|
4102
4239
|
// Try using the uri extension.
|
|
4103
4240
|
const extension = shaka.media.ManifestParser.getExtension(uri);
|
|
4104
|
-
mimeType =
|
|
4105
|
-
'sbv': 'text/x-subviewer',
|
|
4106
|
-
'srt': 'text/srt',
|
|
4107
|
-
'vtt': 'text/vtt',
|
|
4108
|
-
'webvtt': 'text/vtt',
|
|
4109
|
-
'ttml': 'application/ttml+xml',
|
|
4110
|
-
'lrc': 'application/x-subtitle-lrc',
|
|
4111
|
-
'ssa': 'text/x-ssa',
|
|
4112
|
-
'ass': 'text/x-ssa',
|
|
4113
|
-
}[extension];
|
|
4241
|
+
mimeType = shaka.Player.TEXT_EXTENSIONS_TO_MIME_TYPES_[extension];
|
|
4114
4242
|
|
|
4115
4243
|
if (!mimeType) {
|
|
4116
4244
|
shaka.log.error(
|
|
@@ -4258,74 +4386,23 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4258
4386
|
}
|
|
4259
4387
|
|
|
4260
4388
|
if (!mimeType) {
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
mimeType = {
|
|
4264
|
-
'sbv': 'text/x-subviewer',
|
|
4265
|
-
'srt': 'text/srt',
|
|
4266
|
-
'vtt': 'text/vtt',
|
|
4267
|
-
'webvtt': 'text/vtt',
|
|
4268
|
-
'ttml': 'application/ttml+xml',
|
|
4269
|
-
'lrc': 'application/x-subtitle-lrc',
|
|
4270
|
-
'ssa': 'text/x-ssa',
|
|
4271
|
-
'ass': 'text/x-ssa',
|
|
4272
|
-
}[extension];
|
|
4273
|
-
|
|
4274
|
-
if (!mimeType) {
|
|
4275
|
-
try {
|
|
4276
|
-
goog.asserts.assert(
|
|
4277
|
-
this.networkingEngine_, 'Need networking engine.');
|
|
4278
|
-
// eslint-disable-next-line require-atomic-updates
|
|
4279
|
-
mimeType = await shaka.media.ManifestParser.getMimeType(uri,
|
|
4280
|
-
this.networkingEngine_,
|
|
4281
|
-
this.config_.streaming.retryParameters);
|
|
4282
|
-
} catch (error) {}
|
|
4283
|
-
}
|
|
4389
|
+
mimeType = await this.getTextMimetype_(uri);
|
|
4390
|
+
}
|
|
4284
4391
|
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
shaka.util.Error.Severity.RECOVERABLE,
|
|
4291
|
-
shaka.util.Error.Category.TEXT,
|
|
4292
|
-
shaka.util.Error.Code.TEXT_COULD_NOT_GUESS_MIME_TYPE,
|
|
4293
|
-
extension);
|
|
4294
|
-
}
|
|
4392
|
+
let adCuePoints = [];
|
|
4393
|
+
if (this.adManager_) {
|
|
4394
|
+
try {
|
|
4395
|
+
adCuePoints = this.adManager_.getServerSideCuePoints();
|
|
4396
|
+
} catch (error) {}
|
|
4295
4397
|
}
|
|
4296
4398
|
|
|
4297
4399
|
if (this.loadMode_ == shaka.Player.LoadMode.SRC_EQUALS) {
|
|
4298
|
-
if (mimeType != 'text/vtt') {
|
|
4299
|
-
goog.asserts.assert(
|
|
4300
|
-
this.networkingEngine_, 'Need networking engine.');
|
|
4301
|
-
const data = await this.getTextData_(uri,
|
|
4302
|
-
this.networkingEngine_,
|
|
4303
|
-
this.config_.streaming.retryParameters);
|
|
4304
|
-
const vvtText = this.convertToWebVTT_(data, mimeType);
|
|
4305
|
-
const blob = new Blob([vvtText], {type: 'text/vtt'});
|
|
4306
|
-
uri = shaka.media.MediaSourceEngine.createObjectURL(blob);
|
|
4307
|
-
mimeType = 'text/vtt';
|
|
4308
|
-
}
|
|
4309
4400
|
if (forced) {
|
|
4310
4401
|
// See: https://github.com/whatwg/html/issues/4472
|
|
4311
4402
|
kind = 'forced';
|
|
4312
4403
|
}
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
trackElement.src = uri;
|
|
4316
|
-
trackElement.label = label || '';
|
|
4317
|
-
trackElement.kind = kind;
|
|
4318
|
-
trackElement.srclang = language;
|
|
4319
|
-
// Because we're pulling in the text track file via Javascript, the
|
|
4320
|
-
// same-origin policy applies. If you'd like to have a player served
|
|
4321
|
-
// from one domain, but the text track served from another, you'll
|
|
4322
|
-
// need to enable CORS in order to do so. In addition to enabling CORS
|
|
4323
|
-
// on the server serving the text tracks, you will need to add the
|
|
4324
|
-
// crossorigin attribute to the video element itself.
|
|
4325
|
-
if (!this.video_.getAttribute('crossorigin')) {
|
|
4326
|
-
this.video_.setAttribute('crossorigin', 'anonymous');
|
|
4327
|
-
}
|
|
4328
|
-
this.video_.appendChild(trackElement);
|
|
4404
|
+
await this.addSrcTrackElement_(uri, language, kind, mimeType, label || '',
|
|
4405
|
+
adCuePoints);
|
|
4329
4406
|
const textTracks = this.getTextTracks();
|
|
4330
4407
|
const srcTrack = textTracks.find((t) => {
|
|
4331
4408
|
return t.language == language &&
|
|
@@ -4355,6 +4432,18 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4355
4432
|
shaka.util.Error.Code.CANNOT_ADD_EXTERNAL_TEXT_TO_LIVE_STREAM);
|
|
4356
4433
|
}
|
|
4357
4434
|
|
|
4435
|
+
if (adCuePoints.length) {
|
|
4436
|
+
goog.asserts.assert(
|
|
4437
|
+
this.networkingEngine_, 'Need networking engine.');
|
|
4438
|
+
const data = await this.getTextData_(uri,
|
|
4439
|
+
this.networkingEngine_,
|
|
4440
|
+
this.config_.streaming.retryParameters);
|
|
4441
|
+
const vvtText = this.convertToWebVTT_(data, mimeType, adCuePoints);
|
|
4442
|
+
const blob = new Blob([vvtText], {type: 'text/vtt'});
|
|
4443
|
+
uri = shaka.media.MediaSourceEngine.createObjectURL(blob);
|
|
4444
|
+
mimeType = 'text/vtt';
|
|
4445
|
+
}
|
|
4446
|
+
|
|
4358
4447
|
/** @type {shaka.extern.Stream} */
|
|
4359
4448
|
const stream = {
|
|
4360
4449
|
id: this.nextExternalStreamId_++,
|
|
@@ -4400,6 +4489,138 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4400
4489
|
return shaka.util.StreamUtils.textStreamToTrack(stream);
|
|
4401
4490
|
}
|
|
4402
4491
|
|
|
4492
|
+
/**
|
|
4493
|
+
* Adds the given chapters track to the loaded manifest. <code>load()</code>
|
|
4494
|
+
* must resolve before calling. The presentation must have a duration.
|
|
4495
|
+
*
|
|
4496
|
+
* This returns the created track.
|
|
4497
|
+
*
|
|
4498
|
+
* @param {string} uri
|
|
4499
|
+
* @param {string} language
|
|
4500
|
+
* @param {string=} mimeType
|
|
4501
|
+
* @return {!Promise.<shaka.extern.Track>}
|
|
4502
|
+
* @export
|
|
4503
|
+
*/
|
|
4504
|
+
async addChaptersTrack(uri, language, mimeType) {
|
|
4505
|
+
if (this.loadMode_ != shaka.Player.LoadMode.MEDIA_SOURCE &&
|
|
4506
|
+
this.loadMode_ != shaka.Player.LoadMode.SRC_EQUALS) {
|
|
4507
|
+
shaka.log.error(
|
|
4508
|
+
'Must call load() and wait for it to resolve before adding ' +
|
|
4509
|
+
'chapters tracks.');
|
|
4510
|
+
throw new shaka.util.Error(
|
|
4511
|
+
shaka.util.Error.Severity.RECOVERABLE,
|
|
4512
|
+
shaka.util.Error.Category.PLAYER,
|
|
4513
|
+
shaka.util.Error.Code.CONTENT_NOT_LOADED);
|
|
4514
|
+
}
|
|
4515
|
+
|
|
4516
|
+
if (!mimeType) {
|
|
4517
|
+
mimeType = await this.getTextMimetype_(uri);
|
|
4518
|
+
}
|
|
4519
|
+
let adCuePoints = [];
|
|
4520
|
+
if (this.adManager_) {
|
|
4521
|
+
try {
|
|
4522
|
+
adCuePoints = this.adManager_.getServerSideCuePoints();
|
|
4523
|
+
} catch (error) {}
|
|
4524
|
+
}
|
|
4525
|
+
await this.addSrcTrackElement_(uri, language, /* kind= */ 'chapters',
|
|
4526
|
+
mimeType, /* label= */ '', adCuePoints);
|
|
4527
|
+
const chaptersTracks = this.getChaptersTracks();
|
|
4528
|
+
const chaptersTrack = chaptersTracks.find((t) => {
|
|
4529
|
+
return t.language == language;
|
|
4530
|
+
});
|
|
4531
|
+
if (chaptersTrack) {
|
|
4532
|
+
const html5ChaptersTracks = this.getChaptersTracks_();
|
|
4533
|
+
for (const html5ChaptersTrack of html5ChaptersTracks) {
|
|
4534
|
+
this.processChaptersTrack_(html5ChaptersTrack);
|
|
4535
|
+
}
|
|
4536
|
+
return chaptersTrack;
|
|
4537
|
+
}
|
|
4538
|
+
// This should not happen, but there are browser implementations that may
|
|
4539
|
+
// not support the Track element.
|
|
4540
|
+
shaka.log.error('Cannot add this text when loaded with src=');
|
|
4541
|
+
throw new shaka.util.Error(
|
|
4542
|
+
shaka.util.Error.Severity.RECOVERABLE,
|
|
4543
|
+
shaka.util.Error.Category.TEXT,
|
|
4544
|
+
shaka.util.Error.Code.CANNOT_ADD_EXTERNAL_TEXT_TO_SRC_EQUALS);
|
|
4545
|
+
}
|
|
4546
|
+
|
|
4547
|
+
/**
|
|
4548
|
+
* @param {string} uri
|
|
4549
|
+
* @return {!Promise.<string>}
|
|
4550
|
+
* @private
|
|
4551
|
+
*/
|
|
4552
|
+
async getTextMimetype_(uri) {
|
|
4553
|
+
// Try using the uri extension.
|
|
4554
|
+
const extension = shaka.media.ManifestParser.getExtension(uri);
|
|
4555
|
+
let mimeType = shaka.Player.TEXT_EXTENSIONS_TO_MIME_TYPES_[extension];
|
|
4556
|
+
|
|
4557
|
+
if (mimeType) {
|
|
4558
|
+
return mimeType;
|
|
4559
|
+
}
|
|
4560
|
+
|
|
4561
|
+
try {
|
|
4562
|
+
goog.asserts.assert(
|
|
4563
|
+
this.networkingEngine_, 'Need networking engine.');
|
|
4564
|
+
// eslint-disable-next-line require-atomic-updates
|
|
4565
|
+
mimeType = await shaka.media.ManifestParser.getMimeType(uri,
|
|
4566
|
+
this.networkingEngine_,
|
|
4567
|
+
this.config_.streaming.retryParameters);
|
|
4568
|
+
} catch (error) {}
|
|
4569
|
+
|
|
4570
|
+
if (mimeType) {
|
|
4571
|
+
return mimeType;
|
|
4572
|
+
}
|
|
4573
|
+
|
|
4574
|
+
shaka.log.error(
|
|
4575
|
+
'The mimeType has not been provided and it could not be deduced ' +
|
|
4576
|
+
'from its extension.');
|
|
4577
|
+
throw new shaka.util.Error(
|
|
4578
|
+
shaka.util.Error.Severity.RECOVERABLE,
|
|
4579
|
+
shaka.util.Error.Category.TEXT,
|
|
4580
|
+
shaka.util.Error.Code.TEXT_COULD_NOT_GUESS_MIME_TYPE,
|
|
4581
|
+
extension);
|
|
4582
|
+
}
|
|
4583
|
+
|
|
4584
|
+
/**
|
|
4585
|
+
* @param {string} uri
|
|
4586
|
+
* @param {string} language
|
|
4587
|
+
* @param {string} kind
|
|
4588
|
+
* @param {string} mimeType
|
|
4589
|
+
* @param {string} label
|
|
4590
|
+
* @param {!Array.<!shaka.extern.AdCuePoint>} adCuePoints
|
|
4591
|
+
* @private
|
|
4592
|
+
*/
|
|
4593
|
+
async addSrcTrackElement_(uri, language, kind, mimeType, label,
|
|
4594
|
+
adCuePoints) {
|
|
4595
|
+
if (mimeType != 'text/vtt' || adCuePoints.length) {
|
|
4596
|
+
goog.asserts.assert(
|
|
4597
|
+
this.networkingEngine_, 'Need networking engine.');
|
|
4598
|
+
const data = await this.getTextData_(uri,
|
|
4599
|
+
this.networkingEngine_,
|
|
4600
|
+
this.config_.streaming.retryParameters);
|
|
4601
|
+
const vvtText = this.convertToWebVTT_(data, mimeType, adCuePoints);
|
|
4602
|
+
const blob = new Blob([vvtText], {type: 'text/vtt'});
|
|
4603
|
+
uri = shaka.media.MediaSourceEngine.createObjectURL(blob);
|
|
4604
|
+
mimeType = 'text/vtt';
|
|
4605
|
+
}
|
|
4606
|
+
const trackElement =
|
|
4607
|
+
/** @type {!HTMLTrackElement} */(document.createElement('track'));
|
|
4608
|
+
trackElement.src = uri;
|
|
4609
|
+
trackElement.label = label;
|
|
4610
|
+
trackElement.kind = kind;
|
|
4611
|
+
trackElement.srclang = language;
|
|
4612
|
+
// Because we're pulling in the text track file via Javascript, the
|
|
4613
|
+
// same-origin policy applies. If you'd like to have a player served
|
|
4614
|
+
// from one domain, but the text track served from another, you'll
|
|
4615
|
+
// need to enable CORS in order to do so. In addition to enabling CORS
|
|
4616
|
+
// on the server serving the text tracks, you will need to add the
|
|
4617
|
+
// crossorigin attribute to the video element itself.
|
|
4618
|
+
if (!this.video_.getAttribute('crossorigin')) {
|
|
4619
|
+
this.video_.setAttribute('crossorigin', 'anonymous');
|
|
4620
|
+
}
|
|
4621
|
+
this.video_.appendChild(trackElement);
|
|
4622
|
+
}
|
|
4623
|
+
|
|
4403
4624
|
/**
|
|
4404
4625
|
* @param {string} uri
|
|
4405
4626
|
* @param {!shaka.net.NetworkingEngine} netEngine
|
|
@@ -4424,10 +4645,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4424
4645
|
*
|
|
4425
4646
|
* @param {BufferSource} buffer
|
|
4426
4647
|
* @param {string} mimeType
|
|
4648
|
+
* @param {!Array.<!shaka.extern.AdCuePoint>} adCuePoints
|
|
4427
4649
|
* @return {string}
|
|
4428
4650
|
* @private
|
|
4429
4651
|
*/
|
|
4430
|
-
convertToWebVTT_(buffer, mimeType) {
|
|
4652
|
+
convertToWebVTT_(buffer, mimeType, adCuePoints) {
|
|
4431
4653
|
const factory = shaka.text.TextEngine.findParser(mimeType);
|
|
4432
4654
|
if (factory) {
|
|
4433
4655
|
const obj = factory();
|
|
@@ -4438,7 +4660,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4438
4660
|
};
|
|
4439
4661
|
const data = shaka.util.BufferUtils.toUint8(buffer);
|
|
4440
4662
|
const cues = obj.parseMedia(data, time);
|
|
4441
|
-
return shaka.text.WebVttGenerator.convert(cues);
|
|
4663
|
+
return shaka.text.WebVttGenerator.convert(cues, adCuePoints);
|
|
4442
4664
|
}
|
|
4443
4665
|
throw new shaka.util.Error(
|
|
4444
4666
|
shaka.util.Error.Severity.CRITICAL,
|
|
@@ -4680,8 +4902,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4680
4902
|
this.streamingEngine_.getCurrentVariant() : null;
|
|
4681
4903
|
|
|
4682
4904
|
await shaka.util.StreamUtils.filterManifest(
|
|
4683
|
-
this.drmEngine_, currentVariant, manifest
|
|
4684
|
-
this.config_.useMediaCapabilities);
|
|
4905
|
+
this.drmEngine_, currentVariant, manifest);
|
|
4685
4906
|
this.checkPlayableVariants_(manifest);
|
|
4686
4907
|
}
|
|
4687
4908
|
|
|
@@ -4816,7 +5037,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4816
5037
|
// Surface the buffering event so that the app knows if/when we are
|
|
4817
5038
|
// buffering.
|
|
4818
5039
|
const eventName = shaka.Player.EventName.Buffering;
|
|
4819
|
-
|
|
5040
|
+
const data = (new Map()).set('buffering', isBuffering);
|
|
5041
|
+
this.dispatchEvent(this.makeEvent_(eventName, data));
|
|
4820
5042
|
}
|
|
4821
5043
|
|
|
4822
5044
|
/**
|
|
@@ -4984,9 +5206,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4984
5206
|
if (chosenVariant) {
|
|
4985
5207
|
this.switchVariant_(chosenVariant, /* fromAdaptation= */ true,
|
|
4986
5208
|
/* clearBuffers= */ true, /* safeMargin= */ 0);
|
|
4987
|
-
// Send an adaptation event so that the UI can show the new
|
|
4988
|
-
// language/tracks.
|
|
4989
|
-
this.onAdaptation_();
|
|
4990
5209
|
}
|
|
4991
5210
|
}
|
|
4992
5211
|
|
|
@@ -5017,8 +5236,14 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5017
5236
|
oldTrack = shaka.util.StreamUtils.variantToTrack(currentVariant);
|
|
5018
5237
|
}
|
|
5019
5238
|
const newTrack = shaka.util.StreamUtils.variantToTrack(variant);
|
|
5020
|
-
|
|
5021
|
-
|
|
5239
|
+
|
|
5240
|
+
if (fromAdaptation) {
|
|
5241
|
+
// Dispatch an 'adaptation' event
|
|
5242
|
+
this.onAdaptation_(oldTrack, newTrack);
|
|
5243
|
+
} else {
|
|
5244
|
+
// Dispatch a 'variantchanged' event
|
|
5245
|
+
this.onVariantChanged_(oldTrack, newTrack);
|
|
5246
|
+
}
|
|
5022
5247
|
}
|
|
5023
5248
|
|
|
5024
5249
|
/**
|
|
@@ -5162,19 +5387,23 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5162
5387
|
return;
|
|
5163
5388
|
}
|
|
5164
5389
|
|
|
5165
|
-
this.
|
|
5166
|
-
|
|
5167
|
-
this.onAdaptation_();
|
|
5390
|
+
this.switchVariant_(variant, /* fromAdaptation= */ true,
|
|
5391
|
+
clearBuffer, safeMargin);
|
|
5168
5392
|
}
|
|
5169
5393
|
|
|
5170
5394
|
/**
|
|
5171
5395
|
* Dispatches an 'adaptation' event.
|
|
5396
|
+
* @param {?shaka.extern.Track} from
|
|
5397
|
+
* @param {shaka.extern.Track} to
|
|
5172
5398
|
* @private
|
|
5173
5399
|
*/
|
|
5174
|
-
onAdaptation_() {
|
|
5400
|
+
onAdaptation_(from, to) {
|
|
5175
5401
|
// Delay the 'adaptation' event so that StreamingEngine has time to absorb
|
|
5176
5402
|
// the changes before the user tries to query it.
|
|
5177
|
-
const
|
|
5403
|
+
const data = new Map()
|
|
5404
|
+
.set('oldTrack', from)
|
|
5405
|
+
.set('newTrack', to);
|
|
5406
|
+
const event = this.makeEvent_(shaka.Player.EventName.Adaptation, data);
|
|
5178
5407
|
this.delayDispatchEvent_(event);
|
|
5179
5408
|
}
|
|
5180
5409
|
|
|
@@ -5198,10 +5427,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5198
5427
|
onVariantChanged_(from, to) {
|
|
5199
5428
|
// Delay the 'variantchanged' event so StreamingEngine has time to absorb
|
|
5200
5429
|
// the changes before the user tries to query it.
|
|
5201
|
-
const
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5430
|
+
const data = new Map()
|
|
5431
|
+
.set('oldTrack', from)
|
|
5432
|
+
.set('newTrack', to);
|
|
5433
|
+
const event = this.makeEvent_(shaka.Player.EventName.VariantChanged, data);
|
|
5205
5434
|
this.delayDispatchEvent_(event);
|
|
5206
5435
|
}
|
|
5207
5436
|
|
|
@@ -5224,10 +5453,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5224
5453
|
|
|
5225
5454
|
/** @private */
|
|
5226
5455
|
onAbrStatusChanged_() {
|
|
5227
|
-
const
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
this.delayDispatchEvent_(event);
|
|
5456
|
+
const data = (new Map()).set('newStatus', this.config_.abr.enabled);
|
|
5457
|
+
this.delayDispatchEvent_(this.makeEvent_(
|
|
5458
|
+
shaka.Player.EventName.AbrStatusChanged, data));
|
|
5231
5459
|
}
|
|
5232
5460
|
|
|
5233
5461
|
/**
|
|
@@ -5244,7 +5472,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5244
5472
|
}
|
|
5245
5473
|
|
|
5246
5474
|
const eventName = shaka.Player.EventName.Error;
|
|
5247
|
-
const event = this.makeEvent_(eventName,
|
|
5475
|
+
const event = this.makeEvent_(eventName, (new Map()).set('detail', error));
|
|
5248
5476
|
this.dispatchEvent(event);
|
|
5249
5477
|
if (event.defaultPrevented) {
|
|
5250
5478
|
error.handled = true;
|
|
@@ -5273,7 +5501,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5273
5501
|
eventElement: region.eventElement,
|
|
5274
5502
|
};
|
|
5275
5503
|
|
|
5276
|
-
|
|
5504
|
+
const data = (new Map()).set('detail', clone);
|
|
5505
|
+
this.dispatchEvent(this.makeEvent_(eventName, data));
|
|
5277
5506
|
}
|
|
5278
5507
|
|
|
5279
5508
|
/**
|
|
@@ -6102,7 +6331,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6102
6331
|
* @define {string} A version number taken from git at compile time.
|
|
6103
6332
|
* @export
|
|
6104
6333
|
*/
|
|
6105
|
-
shaka.Player.version = 'v3.
|
|
6334
|
+
shaka.Player.version = 'v3.2.2-uncompiled';
|
|
6106
6335
|
|
|
6107
6336
|
// Initialize the deprecation system using the version string we just set
|
|
6108
6337
|
// on the player.
|
|
@@ -6129,6 +6358,47 @@ shaka.Player.supportPlugins_ = {};
|
|
|
6129
6358
|
shaka.Player.adManagerFactory_ = null;
|
|
6130
6359
|
|
|
6131
6360
|
|
|
6361
|
+
/**
|
|
6362
|
+
* @const {!Object.<string, string>}
|
|
6363
|
+
* @private
|
|
6364
|
+
*/
|
|
6365
|
+
shaka.Player.SRC_EQUAL_EXTENSIONS_TO_MIME_TYPES_ = {
|
|
6366
|
+
'mp4': 'video/mp4',
|
|
6367
|
+
'm4v': 'video/mp4',
|
|
6368
|
+
'm4a': 'audio/mp4',
|
|
6369
|
+
'webm': 'video/webm',
|
|
6370
|
+
'weba': 'audio/webm',
|
|
6371
|
+
'mkv': 'video/webm', // Chromium browsers supports it.
|
|
6372
|
+
'ts': 'video/mp2t',
|
|
6373
|
+
'ogv': 'video/ogg',
|
|
6374
|
+
'ogg': 'audio/ogg',
|
|
6375
|
+
'mpg': 'video/mpeg',
|
|
6376
|
+
'mpeg': 'video/mpeg',
|
|
6377
|
+
'm3u8': 'application/x-mpegurl',
|
|
6378
|
+
'mpd': 'application/dash+xml',
|
|
6379
|
+
'mp3': 'audio/mpeg',
|
|
6380
|
+
'aac': 'audio/aac',
|
|
6381
|
+
'flac': 'audio/flac',
|
|
6382
|
+
'wav': 'audio/wav',
|
|
6383
|
+
};
|
|
6384
|
+
|
|
6385
|
+
|
|
6386
|
+
/**
|
|
6387
|
+
* @const {!Object.<string, string>}
|
|
6388
|
+
* @private
|
|
6389
|
+
*/
|
|
6390
|
+
shaka.Player.TEXT_EXTENSIONS_TO_MIME_TYPES_ = {
|
|
6391
|
+
'sbv': 'text/x-subviewer',
|
|
6392
|
+
'srt': 'text/srt',
|
|
6393
|
+
'vtt': 'text/vtt',
|
|
6394
|
+
'webvtt': 'text/vtt',
|
|
6395
|
+
'ttml': 'application/ttml+xml',
|
|
6396
|
+
'lrc': 'application/x-subtitle-lrc',
|
|
6397
|
+
'ssa': 'text/x-ssa',
|
|
6398
|
+
'ass': 'text/x-ssa',
|
|
6399
|
+
};
|
|
6400
|
+
|
|
6401
|
+
|
|
6132
6402
|
/**
|
|
6133
6403
|
* @const {string}
|
|
6134
6404
|
*/
|