shaka-player 3.1.5 → 3.2.3
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/CHANGELOG.md +129 -6
- package/README.md +4 -4
- package/build/types/polyfill +1 -0
- package/demo/common/asset.js +9 -7
- package/demo/common/assets.js +10 -1
- 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/demo.compiled.debug.js +14 -14
- package/dist/demo.compiled.debug.map +2 -2
- package/dist/demo.compiled.js +14 -14
- package/dist/demo.compiled.map +2 -2
- package/dist/deps.js +21 -20
- package/dist/locales.js +30 -30
- package/dist/receiver.compiled.debug.js +8 -8
- package/dist/receiver.compiled.debug.map +2 -2
- package/dist/receiver.compiled.js +8 -8
- package/dist/receiver.compiled.map +2 -2
- package/dist/shaka-player.compiled.d.ts +63 -10
- package/dist/shaka-player.compiled.debug.d.ts +63 -10
- package/dist/shaka-player.compiled.debug.externs.js +786 -716
- package/dist/shaka-player.compiled.debug.js +563 -534
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +786 -716
- package/dist/shaka-player.compiled.js +820 -809
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +63 -10
- package/dist/shaka-player.ui.debug.d.ts +63 -10
- package/dist/shaka-player.ui.debug.externs.js +542 -472
- package/dist/shaka-player.ui.debug.js +594 -566
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +542 -472
- package/dist/shaka-player.ui.js +938 -927
- package/dist/shaka-player.ui.map +4 -4
- 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 +61 -9
- package/externs/shaka/text.js +10 -10
- package/externs/texttrack.js +3 -0
- package/lib/ads/ad_manager.js +16 -15
- package/lib/ads/client_side_ad_manager.js +6 -2
- package/lib/ads/server_side_ad_manager.js +19 -2
- package/lib/cast/cast_proxy.js +8 -0
- 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 +5 -0
- package/lib/hls/hls_parser.js +159 -12
- package/lib/media/closed_caption_parser.js +1 -2
- package/lib/media/drm_engine.js +162 -192
- package/lib/media/segment_index.js +4 -1
- package/lib/media/segment_reference.js +37 -2
- package/lib/media/streaming_engine.js +6 -6
- package/lib/net/networking_engine.js +1 -0
- 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 +426 -149
- package/lib/polyfill/aria.js +82 -0
- package/lib/routing/walker.js +2 -3
- package/lib/text/srt_text_parser.js +4 -4
- package/lib/text/text_engine.js +2 -2
- 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/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/player_configuration.js +13 -1
- package/lib/util/stream_utils.js +168 -88
- 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_utils_unit.js +1 -0
- 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 +43 -1
- package/test/hls/hls_parser_unit.js +250 -0
- package/test/media/drm_engine_integration.js +86 -12
- package/test/media/drm_engine_unit.js +310 -450
- package/test/offline/manifest_convert_unit.js +2 -0
- package/test/offline/storage_integration.js +9 -19
- package/test/player_integration.js +85 -0
- package/test/player_src_equals_integration.js +85 -0
- package/test/player_unit.js +25 -37
- package/test/test/assets/chapters.srt +11 -0
- package/test/test/assets/chapters.vtt +10 -0
- package/test/test/assets/chapters2.vtt +10 -0
- package/test/test/util/cea_utils.js +12 -12
- package/test/test/util/fake_ad_manager.js +7 -0
- package/test/test/util/manifest_generator.js +2 -0
- package/test/test/util/manifest_parser_util.js +3 -1
- package/test/text/web_vtt_generator_unit.js +81 -7
- package/test/util/stream_utils_unit.js +118 -10
- package/ui/airplay_button.js +1 -1
- package/ui/audio_language_selection.js +2 -5
- package/ui/cast_button.js +4 -6
- package/ui/constants.js +0 -3
- package/ui/fast_forward_button.js +2 -3
- package/ui/fullscreen_button.js +1 -3
- package/ui/language_utils.js +1 -1
- 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 +5 -7
- 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
|
|
|
@@ -1142,25 +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
|
-
'mpd': 'application/dash+xml',
|
|
1159
|
-
'mp3': 'audio/mpeg',
|
|
1160
|
-
'aac': 'audio/aac',
|
|
1161
|
-
'flac': 'audio/flac',
|
|
1162
|
-
'wav': 'audio/wav',
|
|
1163
|
-
}[extension];
|
|
1147
|
+
mimeType = shaka.Player.SRC_EQUAL_EXTENSIONS_TO_MIME_TYPES_[extension];
|
|
1164
1148
|
}
|
|
1165
1149
|
|
|
1166
1150
|
// TODO: The load graph system has a design limitation that requires routing
|
|
@@ -1634,11 +1618,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1634
1618
|
}
|
|
1635
1619
|
});
|
|
1636
1620
|
|
|
1637
|
-
// TODO (#1391): Once filterManifest_ is async, remove this eslint disable.
|
|
1638
|
-
/* eslint-disable require-await */
|
|
1639
1621
|
const playerInterface = {
|
|
1640
1622
|
networkingEngine: networkingEngine,
|
|
1641
|
-
filter:
|
|
1623
|
+
filter: (manifest) => this.filterManifest_(manifest),
|
|
1642
1624
|
makeTextStreamsForClosedCaptions: (manifest) => {
|
|
1643
1625
|
return this.makeTextStreamsForClosedCaptions_(manifest);
|
|
1644
1626
|
},
|
|
@@ -1656,7 +1638,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1656
1638
|
this.configure('streaming.lowLatencyMode', true);
|
|
1657
1639
|
},
|
|
1658
1640
|
};
|
|
1659
|
-
/* eslint-enable require-await */
|
|
1660
1641
|
|
|
1661
1642
|
const startTime = Date.now() / 1000;
|
|
1662
1643
|
|
|
@@ -1748,17 +1729,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1748
1729
|
},
|
|
1749
1730
|
});
|
|
1750
1731
|
|
|
1751
|
-
// TODO: remove once MediaCap implementation is complete.
|
|
1752
|
-
if (!this.config_.useMediaCapabilities) {
|
|
1753
|
-
shaka.util.StreamUtils.filterManifestByMediaSource(this.manifest_);
|
|
1754
|
-
}
|
|
1755
|
-
|
|
1756
1732
|
this.drmEngine_.configure(this.config_.drm);
|
|
1757
1733
|
|
|
1758
1734
|
await this.drmEngine_.initForPlayback(
|
|
1759
1735
|
this.manifest_.variants,
|
|
1760
|
-
this.manifest_.offlineSessionIds
|
|
1761
|
-
this.config_.useMediaCapabilities);
|
|
1736
|
+
this.manifest_.offlineSessionIds);
|
|
1762
1737
|
|
|
1763
1738
|
await this.drmEngine_.attach(has.mediaElement);
|
|
1764
1739
|
|
|
@@ -1873,7 +1848,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1873
1848
|
// If the content is multi-codec and the browser can play more than one of
|
|
1874
1849
|
// them, choose codecs now before we initialize streaming.
|
|
1875
1850
|
shaka.util.StreamUtils.chooseCodecsAndFilterManifest(
|
|
1876
|
-
this.manifest_,
|
|
1851
|
+
this.manifest_,
|
|
1852
|
+
this.config_.preferredVideoCodecs,
|
|
1853
|
+
this.config_.preferredAudioCodecs,
|
|
1854
|
+
this.config_.preferredAudioChannelCount,
|
|
1855
|
+
this.config_.preferredDecodingAttributes);
|
|
1877
1856
|
|
|
1878
1857
|
this.streamingEngine_ = this.createStreamingEngine();
|
|
1879
1858
|
this.streamingEngine_.configure(this.config_.streaming);
|
|
@@ -1912,7 +1891,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1912
1891
|
}
|
|
1913
1892
|
|
|
1914
1893
|
// Since the first streams just became active, send an adaptation event.
|
|
1915
|
-
this.onAdaptation_(
|
|
1894
|
+
this.onAdaptation_(null,
|
|
1895
|
+
shaka.util.StreamUtils.variantToTrack(initialVariant));
|
|
1916
1896
|
}
|
|
1917
1897
|
|
|
1918
1898
|
// Decide if text should be shown automatically.
|
|
@@ -2025,6 +2005,16 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2025
2005
|
|
|
2026
2006
|
this.drmEngine_.configure(this.config_.drm);
|
|
2027
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
|
+
|
|
2028
2018
|
// TODO: Instead of feeding DrmEngine with Variants, we should refactor
|
|
2029
2019
|
// DrmEngine so that it takes a minimal config derived from Variants. In
|
|
2030
2020
|
// cases like this one or in removal of stored content, the details are
|
|
@@ -2045,7 +2035,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2045
2035
|
createSegmentIndex: () => Promise.resolve(),
|
|
2046
2036
|
segmentIndex: null,
|
|
2047
2037
|
mimeType: wants.mimeType ?
|
|
2048
|
-
shaka.util.MimeUtils.getBasicType(wants.mimeType) :
|
|
2038
|
+
shaka.util.MimeUtils.getBasicType(wants.mimeType) : mimeType,
|
|
2049
2039
|
codecs: wants.mimeType ?
|
|
2050
2040
|
shaka.util.MimeUtils.getCodecs(wants.mimeType) : '',
|
|
2051
2041
|
encrypted: true,
|
|
@@ -2164,8 +2154,22 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2164
2154
|
}
|
|
2165
2155
|
if (this.video_.textTracks) {
|
|
2166
2156
|
this.eventManager_.listen(this.video_.textTracks, 'addtrack', (e) => {
|
|
2167
|
-
|
|
2168
|
-
|
|
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
|
+
}
|
|
2169
2173
|
});
|
|
2170
2174
|
this.eventManager_.listen(
|
|
2171
2175
|
this.video_.textTracks, 'removetrack', () => this.onTracksChanged_());
|
|
@@ -2338,13 +2342,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2338
2342
|
* We're looking for metadata tracks to process id3 tags. One of the uses is
|
|
2339
2343
|
* for ad info on LIVE streams
|
|
2340
2344
|
*
|
|
2341
|
-
* @param {!
|
|
2345
|
+
* @param {!TextTrack} track
|
|
2342
2346
|
* @private
|
|
2343
2347
|
*/
|
|
2344
|
-
processTimedMetadataSrcEqls_(
|
|
2345
|
-
const track = event.track;
|
|
2346
|
-
goog.asserts.assert(track instanceof TextTrack, 'Wrong track type!');
|
|
2347
|
-
|
|
2348
|
+
processTimedMetadataSrcEqls_(track) {
|
|
2348
2349
|
if (track.kind != 'metadata') {
|
|
2349
2350
|
return;
|
|
2350
2351
|
}
|
|
@@ -2424,6 +2425,32 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
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:
|
|
@@ -2482,6 +2509,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2482
2509
|
this.abrManager_.segmentDownloaded(deltaTimeMs, bytesDownloaded);
|
|
2483
2510
|
}
|
|
2484
2511
|
};
|
|
2512
|
+
|
|
2485
2513
|
return new shaka.net.NetworkingEngine(onProgressUpdated_);
|
|
2486
2514
|
}
|
|
2487
2515
|
|
|
@@ -2868,6 +2896,32 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2868
2896
|
return this.config_;
|
|
2869
2897
|
}
|
|
2870
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
|
+
|
|
2871
2925
|
/**
|
|
2872
2926
|
* Reset configuration to default.
|
|
2873
2927
|
* @export
|
|
@@ -3078,6 +3132,19 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3078
3132
|
return {'start': 0, 'end': 0};
|
|
3079
3133
|
}
|
|
3080
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
|
+
|
|
3081
3148
|
/**
|
|
3082
3149
|
* Get the key system currently used by EME. If EME is not being used, this
|
|
3083
3150
|
* will return an empty string. If the player has not loaded content, this
|
|
@@ -3102,6 +3169,19 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3102
3169
|
return this.drmEngine_ ? this.drmEngine_.getDrmInfo() : null;
|
|
3103
3170
|
}
|
|
3104
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
|
+
|
|
3105
3185
|
/**
|
|
3106
3186
|
* Get the next known expiration time for any EME session. If the session
|
|
3107
3187
|
* never expires, this will return <code>Infinity</code>. If there are no EME
|
|
@@ -3356,9 +3436,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3356
3436
|
return null;
|
|
3357
3437
|
}
|
|
3358
3438
|
const reference = imageStream.segmentIndex.get(referencePosition);
|
|
3439
|
+
const tilesLayout =
|
|
3440
|
+
reference.getTilesLayout() || imageStream.tilesLayout;
|
|
3359
3441
|
// This expression is used to detect one or more numbers (0-9) followed
|
|
3360
3442
|
// by an x and after one or more numbers (0-9)
|
|
3361
|
-
const match = /(\d+)x(\d+)/.exec(
|
|
3443
|
+
const match = /(\d+)x(\d+)/.exec(tilesLayout);
|
|
3362
3444
|
if (!match) {
|
|
3363
3445
|
shaka.log.warning('Tiles layout does not contain a valid format ' +
|
|
3364
3446
|
' (columns x rows)');
|
|
@@ -3372,7 +3454,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3372
3454
|
const height = fullImageHeight / rows;
|
|
3373
3455
|
const totalImages = columns * rows;
|
|
3374
3456
|
const segmentDuration = reference.trueEndTime - reference.startTime;
|
|
3375
|
-
const thumbnailDuration =
|
|
3457
|
+
const thumbnailDuration =
|
|
3458
|
+
reference.getTileDuration() || (segmentDuration / totalImages);
|
|
3376
3459
|
let thumbnailTime = reference.startTime;
|
|
3377
3460
|
let positionX = 0;
|
|
3378
3461
|
let positionY = 0;
|
|
@@ -3395,6 +3478,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3395
3478
|
positionY = Math.floor(thumbnailPosition / columns) * height;
|
|
3396
3479
|
}
|
|
3397
3480
|
return {
|
|
3481
|
+
imageHeight: fullImageHeight,
|
|
3482
|
+
imageWidth: fullImageWidth,
|
|
3398
3483
|
height: height,
|
|
3399
3484
|
positionX: positionX,
|
|
3400
3485
|
positionY: positionY,
|
|
@@ -3598,36 +3683,34 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3598
3683
|
new shaka.media.PreferenceBasedCriteria(language, role || '',
|
|
3599
3684
|
/* channelCount= */ 0, /* label= */ '');
|
|
3600
3685
|
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
return Math.abs((a.video.height || 0) - (b.video.height || 0)) +
|
|
3686
|
+
const diff = (a, b) => {
|
|
3687
|
+
if (!a.video && !b.video) {
|
|
3688
|
+
return 0;
|
|
3689
|
+
} else if (!a.video || !b.video) {
|
|
3690
|
+
return Infinity;
|
|
3691
|
+
} else {
|
|
3692
|
+
return Math.abs((a.video.height || 0) - (b.video.height || 0)) +
|
|
3609
3693
|
Math.abs((a.video.width || 0) - (b.video.width || 0));
|
|
3610
|
-
|
|
3611
|
-
|
|
3694
|
+
}
|
|
3695
|
+
};
|
|
3612
3696
|
// Find the variant whose size is closest to the active variant. This
|
|
3613
3697
|
// ensures we stay at about the same resolution when just changing the
|
|
3614
3698
|
// language/role.
|
|
3615
|
-
|
|
3616
|
-
|
|
3699
|
+
const active = this.streamingEngine_.getCurrentVariant();
|
|
3700
|
+
const set =
|
|
3617
3701
|
this.currentAdaptationSetCriteria_.create(this.manifest_.variants);
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3702
|
+
let bestVariant = null;
|
|
3703
|
+
for (const curVariant of set.values()) {
|
|
3704
|
+
if (!bestVariant ||
|
|
3621
3705
|
diff(bestVariant, active) > diff(curVariant, active)) {
|
|
3622
|
-
|
|
3623
|
-
}
|
|
3624
|
-
}
|
|
3625
|
-
if (bestVariant) {
|
|
3626
|
-
const track = shaka.util.StreamUtils.variantToTrack(bestVariant);
|
|
3627
|
-
this.selectVariantTrack(track, /* clearBuffer= */ true);
|
|
3628
|
-
return;
|
|
3706
|
+
bestVariant = curVariant;
|
|
3629
3707
|
}
|
|
3630
3708
|
}
|
|
3709
|
+
if (bestVariant) {
|
|
3710
|
+
const track = shaka.util.StreamUtils.variantToTrack(bestVariant);
|
|
3711
|
+
this.selectVariantTrack(track, /* clearBuffer= */ true);
|
|
3712
|
+
return;
|
|
3713
|
+
}
|
|
3631
3714
|
|
|
3632
3715
|
// If we haven't switched yet, just use ABR to find a new track.
|
|
3633
3716
|
this.chooseVariantAndSwitch_();
|
|
@@ -3771,6 +3854,55 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3771
3854
|
return expected;
|
|
3772
3855
|
}
|
|
3773
3856
|
|
|
3857
|
+
/**
|
|
3858
|
+
* Return a list of chapters tracks.
|
|
3859
|
+
*
|
|
3860
|
+
* @return {!Array.<shaka.extern.Track>}
|
|
3861
|
+
* @export
|
|
3862
|
+
*/
|
|
3863
|
+
getChaptersTracks() {
|
|
3864
|
+
if (this.video_ && this.video_.src && this.video_.textTracks) {
|
|
3865
|
+
const textTracks = this.getChaptersTracks_();
|
|
3866
|
+
const StreamUtils = shaka.util.StreamUtils;
|
|
3867
|
+
return textTracks.map((text) => StreamUtils.html5TextTrackToTrack(text));
|
|
3868
|
+
} else {
|
|
3869
|
+
return [];
|
|
3870
|
+
}
|
|
3871
|
+
}
|
|
3872
|
+
|
|
3873
|
+
/**
|
|
3874
|
+
* This returns the list of chapters.
|
|
3875
|
+
*
|
|
3876
|
+
* @param {string} language
|
|
3877
|
+
* @return {!Array.<shaka.extern.Chapter>}
|
|
3878
|
+
* @export
|
|
3879
|
+
*/
|
|
3880
|
+
getChapters(language) {
|
|
3881
|
+
const LanguageUtils = shaka.util.LanguageUtils;
|
|
3882
|
+
const inputlanguage = LanguageUtils.normalize(language);
|
|
3883
|
+
const chaptersTracks = this.getChaptersTracks_();
|
|
3884
|
+
const chaptersTracksWithLanguage = chaptersTracks
|
|
3885
|
+
.filter((t) => LanguageUtils.normalize(t.language) == inputlanguage);
|
|
3886
|
+
if (!chaptersTracksWithLanguage || !chaptersTracksWithLanguage.length) {
|
|
3887
|
+
return [];
|
|
3888
|
+
}
|
|
3889
|
+
const chapters = [];
|
|
3890
|
+
for (const chaptersTrack of chaptersTracksWithLanguage) {
|
|
3891
|
+
if (chaptersTrack && chaptersTrack.cues) {
|
|
3892
|
+
for (const cue of chaptersTrack.cues) {
|
|
3893
|
+
/** @type {shaka.extern.Chapter} */
|
|
3894
|
+
const chapter = {
|
|
3895
|
+
title: cue.text,
|
|
3896
|
+
startTime: cue.startTime,
|
|
3897
|
+
endTime: cue.endTime,
|
|
3898
|
+
};
|
|
3899
|
+
chapters.push(chapter);
|
|
3900
|
+
}
|
|
3901
|
+
}
|
|
3902
|
+
}
|
|
3903
|
+
return chapters;
|
|
3904
|
+
}
|
|
3905
|
+
|
|
3774
3906
|
/**
|
|
3775
3907
|
* Ignore the TextTracks with the 'metadata' or 'chapters' kind, or the one
|
|
3776
3908
|
* generated by the SimpleTextDisplayer.
|
|
@@ -3799,6 +3931,19 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3799
3931
|
.filter((t) => t.kind == 'metadata');
|
|
3800
3932
|
}
|
|
3801
3933
|
|
|
3934
|
+
/**
|
|
3935
|
+
* Get the TextTracks with the 'chapters' kind.
|
|
3936
|
+
*
|
|
3937
|
+
* @return {!Array.<TextTrack>}
|
|
3938
|
+
* @private
|
|
3939
|
+
*/
|
|
3940
|
+
getChaptersTracks_() {
|
|
3941
|
+
goog.asserts.assert(this.video_.textTracks,
|
|
3942
|
+
'TextTracks should be valid.');
|
|
3943
|
+
return Array.from(this.video_.textTracks)
|
|
3944
|
+
.filter((t) => t.kind == 'chapters');
|
|
3945
|
+
}
|
|
3946
|
+
|
|
3802
3947
|
/**
|
|
3803
3948
|
* Enable or disable the text displayer. If the player is in an unloaded
|
|
3804
3949
|
* state, the request will be applied next time content is loaded.
|
|
@@ -4100,16 +4245,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4100
4245
|
if (!mimeType) {
|
|
4101
4246
|
// Try using the uri extension.
|
|
4102
4247
|
const extension = shaka.media.ManifestParser.getExtension(uri);
|
|
4103
|
-
mimeType =
|
|
4104
|
-
'sbv': 'text/x-subviewer',
|
|
4105
|
-
'srt': 'text/srt',
|
|
4106
|
-
'vtt': 'text/vtt',
|
|
4107
|
-
'webvtt': 'text/vtt',
|
|
4108
|
-
'ttml': 'application/ttml+xml',
|
|
4109
|
-
'lrc': 'application/x-subtitle-lrc',
|
|
4110
|
-
'ssa': 'text/x-ssa',
|
|
4111
|
-
'ass': 'text/x-ssa',
|
|
4112
|
-
}[extension];
|
|
4248
|
+
mimeType = shaka.Player.TEXT_EXTENSIONS_TO_MIME_TYPES_[extension];
|
|
4113
4249
|
|
|
4114
4250
|
if (!mimeType) {
|
|
4115
4251
|
shaka.log.error(
|
|
@@ -4257,74 +4393,23 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4257
4393
|
}
|
|
4258
4394
|
|
|
4259
4395
|
if (!mimeType) {
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
mimeType = {
|
|
4263
|
-
'sbv': 'text/x-subviewer',
|
|
4264
|
-
'srt': 'text/srt',
|
|
4265
|
-
'vtt': 'text/vtt',
|
|
4266
|
-
'webvtt': 'text/vtt',
|
|
4267
|
-
'ttml': 'application/ttml+xml',
|
|
4268
|
-
'lrc': 'application/x-subtitle-lrc',
|
|
4269
|
-
'ssa': 'text/x-ssa',
|
|
4270
|
-
'ass': 'text/x-ssa',
|
|
4271
|
-
}[extension];
|
|
4272
|
-
|
|
4273
|
-
if (!mimeType) {
|
|
4274
|
-
try {
|
|
4275
|
-
goog.asserts.assert(
|
|
4276
|
-
this.networkingEngine_, 'Need networking engine.');
|
|
4277
|
-
// eslint-disable-next-line require-atomic-updates
|
|
4278
|
-
mimeType = await shaka.media.ManifestParser.getMimeType(uri,
|
|
4279
|
-
this.networkingEngine_,
|
|
4280
|
-
this.config_.streaming.retryParameters);
|
|
4281
|
-
} catch (error) {}
|
|
4282
|
-
}
|
|
4396
|
+
mimeType = await this.getTextMimetype_(uri);
|
|
4397
|
+
}
|
|
4283
4398
|
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
shaka.util.Error.Severity.RECOVERABLE,
|
|
4290
|
-
shaka.util.Error.Category.TEXT,
|
|
4291
|
-
shaka.util.Error.Code.TEXT_COULD_NOT_GUESS_MIME_TYPE,
|
|
4292
|
-
extension);
|
|
4293
|
-
}
|
|
4399
|
+
let adCuePoints = [];
|
|
4400
|
+
if (this.adManager_) {
|
|
4401
|
+
try {
|
|
4402
|
+
adCuePoints = this.adManager_.getServerSideCuePoints();
|
|
4403
|
+
} catch (error) {}
|
|
4294
4404
|
}
|
|
4295
4405
|
|
|
4296
4406
|
if (this.loadMode_ == shaka.Player.LoadMode.SRC_EQUALS) {
|
|
4297
|
-
if (mimeType != 'text/vtt') {
|
|
4298
|
-
goog.asserts.assert(
|
|
4299
|
-
this.networkingEngine_, 'Need networking engine.');
|
|
4300
|
-
const data = await this.getTextData_(uri,
|
|
4301
|
-
this.networkingEngine_,
|
|
4302
|
-
this.config_.streaming.retryParameters);
|
|
4303
|
-
const vvtText = this.convertToWebVTT_(data, mimeType);
|
|
4304
|
-
const blob = new Blob([vvtText], {type: 'text/vtt'});
|
|
4305
|
-
uri = shaka.media.MediaSourceEngine.createObjectURL(blob);
|
|
4306
|
-
mimeType = 'text/vtt';
|
|
4307
|
-
}
|
|
4308
4407
|
if (forced) {
|
|
4309
4408
|
// See: https://github.com/whatwg/html/issues/4472
|
|
4310
4409
|
kind = 'forced';
|
|
4311
4410
|
}
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
trackElement.src = uri;
|
|
4315
|
-
trackElement.label = label || '';
|
|
4316
|
-
trackElement.kind = kind;
|
|
4317
|
-
trackElement.srclang = language;
|
|
4318
|
-
// Because we're pulling in the text track file via Javascript, the
|
|
4319
|
-
// same-origin policy applies. If you'd like to have a player served
|
|
4320
|
-
// from one domain, but the text track served from another, you'll
|
|
4321
|
-
// need to enable CORS in order to do so. In addition to enabling CORS
|
|
4322
|
-
// on the server serving the text tracks, you will need to add the
|
|
4323
|
-
// crossorigin attribute to the video element itself.
|
|
4324
|
-
if (!this.video_.getAttribute('crossorigin')) {
|
|
4325
|
-
this.video_.setAttribute('crossorigin', 'anonymous');
|
|
4326
|
-
}
|
|
4327
|
-
this.video_.appendChild(trackElement);
|
|
4411
|
+
await this.addSrcTrackElement_(uri, language, kind, mimeType, label || '',
|
|
4412
|
+
adCuePoints);
|
|
4328
4413
|
const textTracks = this.getTextTracks();
|
|
4329
4414
|
const srcTrack = textTracks.find((t) => {
|
|
4330
4415
|
return t.language == language &&
|
|
@@ -4354,6 +4439,18 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4354
4439
|
shaka.util.Error.Code.CANNOT_ADD_EXTERNAL_TEXT_TO_LIVE_STREAM);
|
|
4355
4440
|
}
|
|
4356
4441
|
|
|
4442
|
+
if (adCuePoints.length) {
|
|
4443
|
+
goog.asserts.assert(
|
|
4444
|
+
this.networkingEngine_, 'Need networking engine.');
|
|
4445
|
+
const data = await this.getTextData_(uri,
|
|
4446
|
+
this.networkingEngine_,
|
|
4447
|
+
this.config_.streaming.retryParameters);
|
|
4448
|
+
const vvtText = this.convertToWebVTT_(data, mimeType, adCuePoints);
|
|
4449
|
+
const blob = new Blob([vvtText], {type: 'text/vtt'});
|
|
4450
|
+
uri = shaka.media.MediaSourceEngine.createObjectURL(blob);
|
|
4451
|
+
mimeType = 'text/vtt';
|
|
4452
|
+
}
|
|
4453
|
+
|
|
4357
4454
|
/** @type {shaka.extern.Stream} */
|
|
4358
4455
|
const stream = {
|
|
4359
4456
|
id: this.nextExternalStreamId_++,
|
|
@@ -4399,6 +4496,138 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4399
4496
|
return shaka.util.StreamUtils.textStreamToTrack(stream);
|
|
4400
4497
|
}
|
|
4401
4498
|
|
|
4499
|
+
/**
|
|
4500
|
+
* Adds the given chapters track to the loaded manifest. <code>load()</code>
|
|
4501
|
+
* must resolve before calling. The presentation must have a duration.
|
|
4502
|
+
*
|
|
4503
|
+
* This returns the created track.
|
|
4504
|
+
*
|
|
4505
|
+
* @param {string} uri
|
|
4506
|
+
* @param {string} language
|
|
4507
|
+
* @param {string=} mimeType
|
|
4508
|
+
* @return {!Promise.<shaka.extern.Track>}
|
|
4509
|
+
* @export
|
|
4510
|
+
*/
|
|
4511
|
+
async addChaptersTrack(uri, language, mimeType) {
|
|
4512
|
+
if (this.loadMode_ != shaka.Player.LoadMode.MEDIA_SOURCE &&
|
|
4513
|
+
this.loadMode_ != shaka.Player.LoadMode.SRC_EQUALS) {
|
|
4514
|
+
shaka.log.error(
|
|
4515
|
+
'Must call load() and wait for it to resolve before adding ' +
|
|
4516
|
+
'chapters tracks.');
|
|
4517
|
+
throw new shaka.util.Error(
|
|
4518
|
+
shaka.util.Error.Severity.RECOVERABLE,
|
|
4519
|
+
shaka.util.Error.Category.PLAYER,
|
|
4520
|
+
shaka.util.Error.Code.CONTENT_NOT_LOADED);
|
|
4521
|
+
}
|
|
4522
|
+
|
|
4523
|
+
if (!mimeType) {
|
|
4524
|
+
mimeType = await this.getTextMimetype_(uri);
|
|
4525
|
+
}
|
|
4526
|
+
let adCuePoints = [];
|
|
4527
|
+
if (this.adManager_) {
|
|
4528
|
+
try {
|
|
4529
|
+
adCuePoints = this.adManager_.getServerSideCuePoints();
|
|
4530
|
+
} catch (error) {}
|
|
4531
|
+
}
|
|
4532
|
+
await this.addSrcTrackElement_(uri, language, /* kind= */ 'chapters',
|
|
4533
|
+
mimeType, /* label= */ '', adCuePoints);
|
|
4534
|
+
const chaptersTracks = this.getChaptersTracks();
|
|
4535
|
+
const chaptersTrack = chaptersTracks.find((t) => {
|
|
4536
|
+
return t.language == language;
|
|
4537
|
+
});
|
|
4538
|
+
if (chaptersTrack) {
|
|
4539
|
+
const html5ChaptersTracks = this.getChaptersTracks_();
|
|
4540
|
+
for (const html5ChaptersTrack of html5ChaptersTracks) {
|
|
4541
|
+
this.processChaptersTrack_(html5ChaptersTrack);
|
|
4542
|
+
}
|
|
4543
|
+
return chaptersTrack;
|
|
4544
|
+
}
|
|
4545
|
+
// This should not happen, but there are browser implementations that may
|
|
4546
|
+
// not support the Track element.
|
|
4547
|
+
shaka.log.error('Cannot add this text when loaded with src=');
|
|
4548
|
+
throw new shaka.util.Error(
|
|
4549
|
+
shaka.util.Error.Severity.RECOVERABLE,
|
|
4550
|
+
shaka.util.Error.Category.TEXT,
|
|
4551
|
+
shaka.util.Error.Code.CANNOT_ADD_EXTERNAL_TEXT_TO_SRC_EQUALS);
|
|
4552
|
+
}
|
|
4553
|
+
|
|
4554
|
+
/**
|
|
4555
|
+
* @param {string} uri
|
|
4556
|
+
* @return {!Promise.<string>}
|
|
4557
|
+
* @private
|
|
4558
|
+
*/
|
|
4559
|
+
async getTextMimetype_(uri) {
|
|
4560
|
+
// Try using the uri extension.
|
|
4561
|
+
const extension = shaka.media.ManifestParser.getExtension(uri);
|
|
4562
|
+
let mimeType = shaka.Player.TEXT_EXTENSIONS_TO_MIME_TYPES_[extension];
|
|
4563
|
+
|
|
4564
|
+
if (mimeType) {
|
|
4565
|
+
return mimeType;
|
|
4566
|
+
}
|
|
4567
|
+
|
|
4568
|
+
try {
|
|
4569
|
+
goog.asserts.assert(
|
|
4570
|
+
this.networkingEngine_, 'Need networking engine.');
|
|
4571
|
+
// eslint-disable-next-line require-atomic-updates
|
|
4572
|
+
mimeType = await shaka.media.ManifestParser.getMimeType(uri,
|
|
4573
|
+
this.networkingEngine_,
|
|
4574
|
+
this.config_.streaming.retryParameters);
|
|
4575
|
+
} catch (error) {}
|
|
4576
|
+
|
|
4577
|
+
if (mimeType) {
|
|
4578
|
+
return mimeType;
|
|
4579
|
+
}
|
|
4580
|
+
|
|
4581
|
+
shaka.log.error(
|
|
4582
|
+
'The mimeType has not been provided and it could not be deduced ' +
|
|
4583
|
+
'from its extension.');
|
|
4584
|
+
throw new shaka.util.Error(
|
|
4585
|
+
shaka.util.Error.Severity.RECOVERABLE,
|
|
4586
|
+
shaka.util.Error.Category.TEXT,
|
|
4587
|
+
shaka.util.Error.Code.TEXT_COULD_NOT_GUESS_MIME_TYPE,
|
|
4588
|
+
extension);
|
|
4589
|
+
}
|
|
4590
|
+
|
|
4591
|
+
/**
|
|
4592
|
+
* @param {string} uri
|
|
4593
|
+
* @param {string} language
|
|
4594
|
+
* @param {string} kind
|
|
4595
|
+
* @param {string} mimeType
|
|
4596
|
+
* @param {string} label
|
|
4597
|
+
* @param {!Array.<!shaka.extern.AdCuePoint>} adCuePoints
|
|
4598
|
+
* @private
|
|
4599
|
+
*/
|
|
4600
|
+
async addSrcTrackElement_(uri, language, kind, mimeType, label,
|
|
4601
|
+
adCuePoints) {
|
|
4602
|
+
if (mimeType != 'text/vtt' || adCuePoints.length) {
|
|
4603
|
+
goog.asserts.assert(
|
|
4604
|
+
this.networkingEngine_, 'Need networking engine.');
|
|
4605
|
+
const data = await this.getTextData_(uri,
|
|
4606
|
+
this.networkingEngine_,
|
|
4607
|
+
this.config_.streaming.retryParameters);
|
|
4608
|
+
const vvtText = this.convertToWebVTT_(data, mimeType, adCuePoints);
|
|
4609
|
+
const blob = new Blob([vvtText], {type: 'text/vtt'});
|
|
4610
|
+
uri = shaka.media.MediaSourceEngine.createObjectURL(blob);
|
|
4611
|
+
mimeType = 'text/vtt';
|
|
4612
|
+
}
|
|
4613
|
+
const trackElement =
|
|
4614
|
+
/** @type {!HTMLTrackElement} */(document.createElement('track'));
|
|
4615
|
+
trackElement.src = uri;
|
|
4616
|
+
trackElement.label = label;
|
|
4617
|
+
trackElement.kind = kind;
|
|
4618
|
+
trackElement.srclang = language;
|
|
4619
|
+
// Because we're pulling in the text track file via Javascript, the
|
|
4620
|
+
// same-origin policy applies. If you'd like to have a player served
|
|
4621
|
+
// from one domain, but the text track served from another, you'll
|
|
4622
|
+
// need to enable CORS in order to do so. In addition to enabling CORS
|
|
4623
|
+
// on the server serving the text tracks, you will need to add the
|
|
4624
|
+
// crossorigin attribute to the video element itself.
|
|
4625
|
+
if (!this.video_.getAttribute('crossorigin')) {
|
|
4626
|
+
this.video_.setAttribute('crossorigin', 'anonymous');
|
|
4627
|
+
}
|
|
4628
|
+
this.video_.appendChild(trackElement);
|
|
4629
|
+
}
|
|
4630
|
+
|
|
4402
4631
|
/**
|
|
4403
4632
|
* @param {string} uri
|
|
4404
4633
|
* @param {!shaka.net.NetworkingEngine} netEngine
|
|
@@ -4423,10 +4652,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4423
4652
|
*
|
|
4424
4653
|
* @param {BufferSource} buffer
|
|
4425
4654
|
* @param {string} mimeType
|
|
4655
|
+
* @param {!Array.<!shaka.extern.AdCuePoint>} adCuePoints
|
|
4426
4656
|
* @return {string}
|
|
4427
4657
|
* @private
|
|
4428
4658
|
*/
|
|
4429
|
-
convertToWebVTT_(buffer, mimeType) {
|
|
4659
|
+
convertToWebVTT_(buffer, mimeType, adCuePoints) {
|
|
4430
4660
|
const factory = shaka.text.TextEngine.findParser(mimeType);
|
|
4431
4661
|
if (factory) {
|
|
4432
4662
|
const obj = factory();
|
|
@@ -4437,7 +4667,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4437
4667
|
};
|
|
4438
4668
|
const data = shaka.util.BufferUtils.toUint8(buffer);
|
|
4439
4669
|
const cues = obj.parseMedia(data, time);
|
|
4440
|
-
return shaka.text.WebVttGenerator.convert(cues);
|
|
4670
|
+
return shaka.text.WebVttGenerator.convert(cues, adCuePoints);
|
|
4441
4671
|
}
|
|
4442
4672
|
throw new shaka.util.Error(
|
|
4443
4673
|
shaka.util.Error.Severity.CRITICAL,
|
|
@@ -4679,8 +4909,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4679
4909
|
this.streamingEngine_.getCurrentVariant() : null;
|
|
4680
4910
|
|
|
4681
4911
|
await shaka.util.StreamUtils.filterManifest(
|
|
4682
|
-
this.drmEngine_, currentVariant, manifest
|
|
4683
|
-
this.config_.useMediaCapabilities);
|
|
4912
|
+
this.drmEngine_, currentVariant, manifest);
|
|
4684
4913
|
this.checkPlayableVariants_(manifest);
|
|
4685
4914
|
}
|
|
4686
4915
|
|
|
@@ -4984,9 +5213,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4984
5213
|
if (chosenVariant) {
|
|
4985
5214
|
this.switchVariant_(chosenVariant, /* fromAdaptation= */ true,
|
|
4986
5215
|
/* clearBuffers= */ true, /* safeMargin= */ 0);
|
|
4987
|
-
// Send an adaptation event so that the UI can show the new
|
|
4988
|
-
// language/tracks.
|
|
4989
|
-
this.onAdaptation_();
|
|
4990
5216
|
}
|
|
4991
5217
|
}
|
|
4992
5218
|
|
|
@@ -5017,8 +5243,14 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5017
5243
|
oldTrack = shaka.util.StreamUtils.variantToTrack(currentVariant);
|
|
5018
5244
|
}
|
|
5019
5245
|
const newTrack = shaka.util.StreamUtils.variantToTrack(variant);
|
|
5020
|
-
|
|
5021
|
-
|
|
5246
|
+
|
|
5247
|
+
if (fromAdaptation) {
|
|
5248
|
+
// Dispatch an 'adaptation' event
|
|
5249
|
+
this.onAdaptation_(oldTrack, newTrack);
|
|
5250
|
+
} else {
|
|
5251
|
+
// Dispatch a 'variantchanged' event
|
|
5252
|
+
this.onVariantChanged_(oldTrack, newTrack);
|
|
5253
|
+
}
|
|
5022
5254
|
}
|
|
5023
5255
|
|
|
5024
5256
|
/**
|
|
@@ -5162,19 +5394,23 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5162
5394
|
return;
|
|
5163
5395
|
}
|
|
5164
5396
|
|
|
5165
|
-
this.
|
|
5166
|
-
|
|
5167
|
-
this.onAdaptation_();
|
|
5397
|
+
this.switchVariant_(variant, /* fromAdaptation= */ true,
|
|
5398
|
+
clearBuffer, safeMargin);
|
|
5168
5399
|
}
|
|
5169
5400
|
|
|
5170
5401
|
/**
|
|
5171
5402
|
* Dispatches an 'adaptation' event.
|
|
5403
|
+
* @param {?shaka.extern.Track} from
|
|
5404
|
+
* @param {shaka.extern.Track} to
|
|
5172
5405
|
* @private
|
|
5173
5406
|
*/
|
|
5174
|
-
onAdaptation_() {
|
|
5407
|
+
onAdaptation_(from, to) {
|
|
5175
5408
|
// Delay the 'adaptation' event so that StreamingEngine has time to absorb
|
|
5176
5409
|
// the changes before the user tries to query it.
|
|
5177
|
-
const
|
|
5410
|
+
const data = new Map()
|
|
5411
|
+
.set('oldTrack', from)
|
|
5412
|
+
.set('newTrack', to);
|
|
5413
|
+
const event = this.makeEvent_(shaka.Player.EventName.Adaptation, data);
|
|
5178
5414
|
this.delayDispatchEvent_(event);
|
|
5179
5415
|
}
|
|
5180
5416
|
|
|
@@ -6102,7 +6338,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6102
6338
|
* @define {string} A version number taken from git at compile time.
|
|
6103
6339
|
* @export
|
|
6104
6340
|
*/
|
|
6105
|
-
shaka.Player.version = 'v3.
|
|
6341
|
+
shaka.Player.version = 'v3.2.3-uncompiled';
|
|
6106
6342
|
|
|
6107
6343
|
// Initialize the deprecation system using the version string we just set
|
|
6108
6344
|
// on the player.
|
|
@@ -6129,6 +6365,47 @@ shaka.Player.supportPlugins_ = {};
|
|
|
6129
6365
|
shaka.Player.adManagerFactory_ = null;
|
|
6130
6366
|
|
|
6131
6367
|
|
|
6368
|
+
/**
|
|
6369
|
+
* @const {!Object.<string, string>}
|
|
6370
|
+
* @private
|
|
6371
|
+
*/
|
|
6372
|
+
shaka.Player.SRC_EQUAL_EXTENSIONS_TO_MIME_TYPES_ = {
|
|
6373
|
+
'mp4': 'video/mp4',
|
|
6374
|
+
'm4v': 'video/mp4',
|
|
6375
|
+
'm4a': 'audio/mp4',
|
|
6376
|
+
'webm': 'video/webm',
|
|
6377
|
+
'weba': 'audio/webm',
|
|
6378
|
+
'mkv': 'video/webm', // Chromium browsers supports it.
|
|
6379
|
+
'ts': 'video/mp2t',
|
|
6380
|
+
'ogv': 'video/ogg',
|
|
6381
|
+
'ogg': 'audio/ogg',
|
|
6382
|
+
'mpg': 'video/mpeg',
|
|
6383
|
+
'mpeg': 'video/mpeg',
|
|
6384
|
+
'm3u8': 'application/x-mpegurl',
|
|
6385
|
+
'mpd': 'application/dash+xml',
|
|
6386
|
+
'mp3': 'audio/mpeg',
|
|
6387
|
+
'aac': 'audio/aac',
|
|
6388
|
+
'flac': 'audio/flac',
|
|
6389
|
+
'wav': 'audio/wav',
|
|
6390
|
+
};
|
|
6391
|
+
|
|
6392
|
+
|
|
6393
|
+
/**
|
|
6394
|
+
* @const {!Object.<string, string>}
|
|
6395
|
+
* @private
|
|
6396
|
+
*/
|
|
6397
|
+
shaka.Player.TEXT_EXTENSIONS_TO_MIME_TYPES_ = {
|
|
6398
|
+
'sbv': 'text/x-subviewer',
|
|
6399
|
+
'srt': 'text/srt',
|
|
6400
|
+
'vtt': 'text/vtt',
|
|
6401
|
+
'webvtt': 'text/vtt',
|
|
6402
|
+
'ttml': 'application/ttml+xml',
|
|
6403
|
+
'lrc': 'application/x-subtitle-lrc',
|
|
6404
|
+
'ssa': 'text/x-ssa',
|
|
6405
|
+
'ass': 'text/x-ssa',
|
|
6406
|
+
};
|
|
6407
|
+
|
|
6408
|
+
|
|
6132
6409
|
/**
|
|
6133
6410
|
* @const {string}
|
|
6134
6411
|
*/
|