shaka-player 3.1.0 → 3.1.4
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 +8 -2
- package/CHANGELOG.md +209 -0
- package/CONTRIBUTORS +10 -3
- package/README.md +3 -0
- package/build/apps.py +2 -2
- package/build/check.py +2 -2
- package/build/conformance.textproto +0 -9
- package/build/generateExterns.js +1 -1
- package/build/misspellings.txt +1 -0
- package/build/shakaBuildHelpers.py +6 -5
- package/build/subprocessWindowsPatch.py +103 -0
- package/demo/common/asset.js +11 -0
- package/demo/common/assets.js +1 -1
- package/demo/common/message_ids.js +5 -0
- package/demo/config.js +2 -1
- package/demo/custom.js +84 -3
- package/demo/demo.less +13 -1
- package/demo/demo_utils.js +1 -0
- package/demo/input.js +31 -12
- package/demo/input_container.js +24 -1
- package/demo/locales/en.json +6 -1
- package/demo/locales/source.json +20 -0
- package/demo/main.js +5 -1
- package/dist/controls.css +2 -2
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +99 -91
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +99 -91
- package/dist/demo.compiled.map +3 -3
- package/dist/demo.css +1 -1
- package/dist/demo.css.map +1 -1
- package/dist/deps.js +9 -9
- package/dist/locales.js +36 -34
- package/dist/receiver.compiled.debug.js +74 -70
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +74 -70
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +165 -9
- package/dist/shaka-player.compiled.debug.d.ts +165 -9
- package/dist/shaka-player.compiled.debug.externs.js +179 -11
- package/dist/shaka-player.compiled.debug.js +367 -339
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +179 -11
- package/dist/shaka-player.compiled.js +818 -807
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +165 -9
- package/dist/shaka-player.ui.debug.d.ts +165 -9
- package/dist/shaka-player.ui.debug.externs.js +181 -13
- package/dist/shaka-player.ui.debug.js +459 -429
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +181 -13
- package/dist/shaka-player.ui.js +973 -961
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/fairplay.md +1 -1
- package/docs/tutorials/faq.md +25 -0
- package/docs/tutorials/index.json +2 -2
- package/docs/tutorials/upgrade-v3.md +38 -0
- package/docs/tutorials/upgrade.md +3 -3
- package/externs/ima.js +4 -0
- package/externs/media_capabilities.js +16 -0
- package/externs/shaka/ads.js +2 -0
- package/externs/shaka/net.js +2 -2
- package/externs/shaka/player.js +6 -0
- package/karma.conf.js +1 -0
- package/lib/abr/simple_abr_manager.js +1 -1
- package/lib/ads/ad_manager.js +29 -11
- package/lib/ads/client_side_ad_manager.js +76 -86
- package/lib/ads/server_side_ad_manager.js +26 -11
- package/lib/cast/cast_proxy.js +3 -2
- package/lib/cast/cast_receiver.js +2 -1
- package/lib/cast/cast_sender.js +2 -2
- package/lib/cea/sei_processor.js +24 -17
- package/lib/dash/dash_parser.js +107 -4
- package/lib/dash/segment_list.js +1 -1
- package/lib/dash/segment_template.js +45 -15
- package/lib/dependencies/all.js +15 -15
- package/lib/hls/hls_parser.js +46 -18
- package/lib/media/closed_caption_parser.js +3 -1
- package/lib/media/content_workarounds.js +18 -0
- package/lib/media/drm_engine.js +20 -1
- package/lib/media/gap_jumping_controller.js +8 -4
- package/lib/media/media_source_engine.js +1 -2
- package/lib/media/playhead.js +1 -1
- package/lib/media/presentation_timeline.js +3 -1
- package/lib/media/segment_index.js +38 -12
- package/lib/media/segment_reference.js +8 -0
- package/lib/media/streaming_engine.js +30 -21
- package/lib/net/http_fetch_plugin.js +2 -2
- package/lib/net/networking_engine.js +3 -2
- package/lib/offline/storage.js +4 -0
- package/lib/player.js +113 -56
- package/lib/polyfill/encryption_scheme.js +2 -0
- package/lib/polyfill/fullscreen.js +2 -0
- package/lib/polyfill/mathround.js +2 -0
- package/lib/polyfill/media_capabilities.js +62 -23
- package/lib/polyfill/mediasource.js +8 -0
- package/lib/polyfill/orientation.js +3 -1
- package/lib/polyfill/patchedmediakeys_apple.js +6 -4
- package/lib/polyfill/patchedmediakeys_ms.js +6 -4
- package/lib/polyfill/patchedmediakeys_nop.js +2 -0
- package/lib/polyfill/patchedmediakeys_webkit.js +6 -4
- package/lib/polyfill/pip_webkit.js +2 -0
- package/lib/polyfill/storage_estimate.js +2 -0
- package/lib/polyfill/video_play_promise.js +2 -0
- package/lib/polyfill/videoplaybackquality.js +2 -0
- package/lib/polyfill/vttcue.js +2 -0
- package/lib/text/cue.js +11 -0
- package/lib/text/mp4_ttml_parser.js +3 -0
- package/lib/text/text_engine.js +14 -2
- package/lib/text/ttml_text_parser.js +52 -30
- package/lib/text/ui_text_displayer.js +255 -82
- package/lib/text/vtt_text_parser.js +4 -2
- package/lib/util/error.js +1 -4
- package/lib/util/fake_event.js +53 -7
- package/lib/util/mime_utils.js +33 -0
- package/lib/util/mp4_box_parsers.js +1 -1
- package/lib/util/mp4_parser.js +14 -0
- package/lib/util/networking.js +1 -1
- package/lib/util/periods.js +132 -37
- package/lib/util/platform.js +13 -1
- package/lib/util/stream_utils.js +46 -7
- package/package.json +3 -3
- package/test/cast/cast_proxy_unit.js +12 -6
- package/test/cast/cast_receiver_integration.js +1 -1
- package/test/cast/cast_utils_unit.js +1 -1
- package/test/cea/mp4_cea_parser_unit.js +26 -0
- package/test/dash/dash_parser_live_unit.js +1 -0
- package/test/dash/dash_parser_manifest_unit.js +187 -1
- package/test/dash/dash_parser_segment_template_unit.js +3 -3
- package/test/demo/demo_unit.js +0 -1
- package/test/hls/hls_parser_unit.js +45 -1
- package/test/media/closed_caption_parser_unit.js +20 -0
- package/test/media/drm_engine_unit.js +59 -3
- package/test/media/playhead_unit.js +27 -1
- package/test/media/presentation_timeline_unit.js +19 -0
- package/test/media/segment_index_unit.js +76 -3
- package/test/media/streaming_engine_unit.js +3 -3
- package/test/player_integration.js +38 -0
- package/test/player_unit.js +125 -6
- 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/empty_caption_video_init.mp4 +0 -0
- package/test/test/assets/empty_caption_video_segment.mp4 +0 -0
- package/test/test/util/fake_ad_manager.js +4 -1
- package/test/test/util/simple_fakes.js +5 -3
- package/test/test/util/waiter.js +36 -2
- package/test/text/ttml_text_parser_unit.js +55 -0
- package/test/text/ui_text_displayer_unit.js +95 -18
- package/test/text/vtt_text_parser_unit.js +17 -1
- package/test/ui/localization_unit.js +15 -14
- package/test/ui/text_displayer_layout_unit.js +52 -1
- package/test/ui/ui_unit.js +4 -0
- package/test/util/mp4_box_parsers_unit.js +28 -0
- package/test/util/periods_unit.js +190 -2
- package/test/util/stream_utils_unit.js +56 -5
- package/ui/airplay_button.js +5 -0
- package/ui/big_play_button.js +10 -0
- package/ui/cast_button.js +2 -3
- package/ui/controls.js +9 -7
- package/ui/less/containers.less +10 -5
- package/ui/locales/en.json +1 -0
- package/ui/locales/ru.json +6 -6
- package/ui/locales/source.json +4 -0
- package/ui/localization.js +28 -51
- package/ui/pip_button.js +2 -3
- package/ui/play_button.js +10 -10
- package/ui/small_play_button.js +12 -0
- package/ui/ui.js +1 -1
- package/docs/tutorials/upgrade-v2-4.md +0 -481
package/lib/player.js
CHANGED
|
@@ -596,7 +596,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
596
596
|
enterNode: (node, has, wants) => {
|
|
597
597
|
this.dispatchEvent(this.makeEvent_(
|
|
598
598
|
/* name= */ shaka.Player.EventName.OnStateChange,
|
|
599
|
-
/* data= */
|
|
599
|
+
/* data= */ (new Map()).set('state', node.name)));
|
|
600
600
|
|
|
601
601
|
const action = actions.get(node);
|
|
602
602
|
return action(has, wants);
|
|
@@ -627,7 +627,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
627
627
|
onIdle: (node) => {
|
|
628
628
|
this.dispatchEvent(this.makeEvent_(
|
|
629
629
|
/* name= */ shaka.Player.EventName.OnStateIdle,
|
|
630
|
-
/* data= */
|
|
630
|
+
/* data= */ (new Map()).set('state', node.name)));
|
|
631
631
|
},
|
|
632
632
|
};
|
|
633
633
|
|
|
@@ -647,7 +647,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
647
647
|
|
|
648
648
|
/**
|
|
649
649
|
* @param {!shaka.Player.EventName} name
|
|
650
|
-
* @param {Object
|
|
650
|
+
* @param {Map.<string, Object>=} data
|
|
651
651
|
* @return {!shaka.util.FakeEvent}
|
|
652
652
|
* @private
|
|
653
653
|
*/
|
|
@@ -1155,6 +1155,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1155
1155
|
'mpg': 'video/mpeg',
|
|
1156
1156
|
'mpeg': 'video/mpeg',
|
|
1157
1157
|
'm3u8': 'application/x-mpegurl',
|
|
1158
|
+
'mpd': 'application/dash+xml',
|
|
1158
1159
|
'mp3': 'audio/mpeg',
|
|
1159
1160
|
'aac': 'audio/aac',
|
|
1160
1161
|
'flac': 'audio/flac',
|
|
@@ -1285,6 +1286,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1285
1286
|
has.mediaElement = null;
|
|
1286
1287
|
}
|
|
1287
1288
|
|
|
1289
|
+
if (this.adManager_) {
|
|
1290
|
+
// The ad manager is specific to the video, so detach it too.
|
|
1291
|
+
this.adManager_.release();
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1288
1294
|
// Clear our cached copy of the media element.
|
|
1289
1295
|
this.video_ = null;
|
|
1290
1296
|
|
|
@@ -1843,6 +1849,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1843
1849
|
this.config_.preferredAudioChannelCount);
|
|
1844
1850
|
|
|
1845
1851
|
this.currentTextLanguage_ = this.config_.preferredTextLanguage;
|
|
1852
|
+
this.currentTextRole_ = this.config_.preferredTextRole;
|
|
1853
|
+
this.currentTextForced_ = this.config_.preferForcedSubs;
|
|
1846
1854
|
|
|
1847
1855
|
shaka.Player.applyPlayRange_(this.manifest_.presentationTimeline,
|
|
1848
1856
|
this.config_.playRangeStart,
|
|
@@ -1882,36 +1890,55 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1882
1890
|
this.dispatchEvent(this.makeEvent_(shaka.Player.EventName.Streaming));
|
|
1883
1891
|
|
|
1884
1892
|
// Pick the initial streams to play.
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1893
|
+
// however, we would skip switch to initial variant
|
|
1894
|
+
// if user already pick variant track (via selectVariantTrack api)
|
|
1895
|
+
let initialVariant = null;
|
|
1896
|
+
const activeVariantTrack = this.getVariantTracks().find((t) => t.active);
|
|
1897
|
+
|
|
1898
|
+
if (!activeVariantTrack) {
|
|
1899
|
+
initialVariant = this.chooseVariant_();
|
|
1900
|
+
goog.asserts.assert(initialVariant, 'Must choose an initial variant!');
|
|
1901
|
+
this.switchVariant_(initialVariant, /* fromAdaptation= */ true,
|
|
1902
|
+
/* clearBuffer= */ false, /* safeMargin= */ 0);
|
|
1903
|
+
|
|
1904
|
+
// Now that we have initial streams, we may adjust the start time to align
|
|
1905
|
+
// to a segment boundary.
|
|
1906
|
+
if (this.config_.streaming.startAtSegmentBoundary) {
|
|
1907
|
+
const startTime = this.playhead_.getTime();
|
|
1908
|
+
const adjustedTime =
|
|
1909
|
+
await this.adjustStartTime_(initialVariant, startTime);
|
|
1910
|
+
|
|
1911
|
+
this.playhead_.setStartTime(adjustedTime);
|
|
1912
|
+
}
|
|
1891
1913
|
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
if (initialTextStream) {
|
|
1895
|
-
this.addTextStreamToSwitchHistory_(
|
|
1896
|
-
initialTextStream, /* fromAdaptation= */ true);
|
|
1914
|
+
// Since the first streams just became active, send an adaptation event.
|
|
1915
|
+
this.onAdaptation_();
|
|
1897
1916
|
}
|
|
1898
1917
|
|
|
1899
|
-
|
|
1900
|
-
//
|
|
1901
|
-
if (
|
|
1902
|
-
|
|
1903
|
-
|
|
1918
|
+
// Decide if text should be shown automatically.
|
|
1919
|
+
// similar to video/audio track, we would skip switch initial text track
|
|
1920
|
+
// if user already pick text track (via selectTextTrack api)
|
|
1921
|
+
const activeTextTrack = this.getTextTracks().find((t) => t.active);
|
|
1922
|
+
|
|
1923
|
+
if (!activeTextTrack) {
|
|
1924
|
+
const initialTextStream = this.chooseTextStream_();
|
|
1904
1925
|
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
const adjustedTime =
|
|
1910
|
-
await this.adjustStartTime_(initialVariant, startTime);
|
|
1926
|
+
if (initialTextStream) {
|
|
1927
|
+
this.addTextStreamToSwitchHistory_(
|
|
1928
|
+
initialTextStream, /* fromAdaptation= */ true);
|
|
1929
|
+
}
|
|
1911
1930
|
|
|
1912
|
-
|
|
1931
|
+
if (initialVariant) {
|
|
1932
|
+
this.setInitialTextState_(initialVariant, initialTextStream);
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1935
|
+
// Don't initialize with a text stream unless we should be streaming text.
|
|
1936
|
+
if (initialTextStream && this.shouldStreamText_()) {
|
|
1937
|
+
this.streamingEngine_.switchTextStream(initialTextStream);
|
|
1938
|
+
}
|
|
1913
1939
|
}
|
|
1914
1940
|
|
|
1941
|
+
|
|
1915
1942
|
// Start streaming content. This will start the flow of content down to
|
|
1916
1943
|
// media source.
|
|
1917
1944
|
await this.streamingEngine_.start();
|
|
@@ -1925,8 +1952,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1925
1952
|
this.filterManifestByCurrentVariant_();
|
|
1926
1953
|
// Dispatch a 'trackschanged' event now that all initial filtering is done.
|
|
1927
1954
|
this.onTracksChanged_();
|
|
1928
|
-
// Since the first streams just became active, send an adaptation event.
|
|
1929
|
-
this.onAdaptation_();
|
|
1930
1955
|
|
|
1931
1956
|
// Now that we've filtered out variants that aren't compatible with the
|
|
1932
1957
|
// active one, update abr manager with filtered variants.
|
|
@@ -2019,8 +2044,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2019
2044
|
originalId: null,
|
|
2020
2045
|
createSegmentIndex: () => Promise.resolve(),
|
|
2021
2046
|
segmentIndex: null,
|
|
2022
|
-
mimeType:
|
|
2023
|
-
|
|
2047
|
+
mimeType: wants.mimeType ?
|
|
2048
|
+
shaka.util.MimeUtils.getBasicType(wants.mimeType) : 'video/mp4',
|
|
2049
|
+
codecs: wants.mimeType ?
|
|
2050
|
+
shaka.util.MimeUtils.getCodecs(wants.mimeType) : '',
|
|
2024
2051
|
encrypted: true,
|
|
2025
2052
|
drmInfos: [], // Filled in by DrmEngine config.
|
|
2026
2053
|
keyIds: new Set(),
|
|
@@ -2043,6 +2070,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2043
2070
|
decodingInfos: [],
|
|
2044
2071
|
};
|
|
2045
2072
|
|
|
2073
|
+
this.drmEngine_.setSrcEquals(/* srcEquals= */ true);
|
|
2046
2074
|
await this.drmEngine_.initForPlayback(
|
|
2047
2075
|
[variant], /* offlineSessionIds= */ []);
|
|
2048
2076
|
await this.drmEngine_.attach(has.mediaElement);
|
|
@@ -2388,12 +2416,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2388
2416
|
goog.asserts.assert(!endTime || startTime <= endTime,
|
|
2389
2417
|
'Metadata start time should be less or equal to the end time!');
|
|
2390
2418
|
const eventName = shaka.Player.EventName.Metadata;
|
|
2391
|
-
const data =
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
};
|
|
2419
|
+
const data = new Map()
|
|
2420
|
+
.set('startTime', startTime)
|
|
2421
|
+
.set('endTime', endTime)
|
|
2422
|
+
.set('metadataType', metadataType)
|
|
2423
|
+
.set('payload', payload);
|
|
2397
2424
|
this.dispatchEvent(this.makeEvent_(eventName, data));
|
|
2398
2425
|
}
|
|
2399
2426
|
|
|
@@ -2455,7 +2482,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2455
2482
|
this.abrManager_.segmentDownloaded(deltaTimeMs, bytesDownloaded);
|
|
2456
2483
|
}
|
|
2457
2484
|
};
|
|
2458
|
-
|
|
2459
2485
|
return new shaka.net.NetworkingEngine(onProgressUpdated_);
|
|
2460
2486
|
}
|
|
2461
2487
|
|
|
@@ -3214,6 +3240,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3214
3240
|
|
|
3215
3241
|
const tracks = [];
|
|
3216
3242
|
|
|
3243
|
+
let activeTracks = 0;
|
|
3244
|
+
|
|
3217
3245
|
// Convert each variant to a track.
|
|
3218
3246
|
for (const variant of this.manifest_.variants) {
|
|
3219
3247
|
if (!shaka.util.StreamUtils.isPlayable(variant)) {
|
|
@@ -3222,10 +3250,22 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3222
3250
|
|
|
3223
3251
|
const track = shaka.util.StreamUtils.variantToTrack(variant);
|
|
3224
3252
|
track.active = variant == currentVariant;
|
|
3253
|
+
if (!track.active && activeTracks != 1 && currentVariant != null &&
|
|
3254
|
+
variant.video == currentVariant.video &&
|
|
3255
|
+
variant.audio == currentVariant.audio) {
|
|
3256
|
+
track.active = true;
|
|
3257
|
+
}
|
|
3258
|
+
|
|
3259
|
+
if (track.active) {
|
|
3260
|
+
activeTracks++;
|
|
3261
|
+
}
|
|
3225
3262
|
|
|
3226
3263
|
tracks.push(track);
|
|
3227
3264
|
}
|
|
3228
3265
|
|
|
3266
|
+
goog.asserts.assert(activeTracks <= 1,
|
|
3267
|
+
'It should only have one active track');
|
|
3268
|
+
|
|
3229
3269
|
return tracks;
|
|
3230
3270
|
} else if (this.video_ && this.video_.audioTracks) {
|
|
3231
3271
|
// Safari's native HLS always shows a single element in videoTracks.
|
|
@@ -3330,9 +3370,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3330
3370
|
const rows = parseInt(match[2], 10);
|
|
3331
3371
|
const width = fullImageWidth / columns;
|
|
3332
3372
|
const height = fullImageHeight / rows;
|
|
3373
|
+
const totalImages = columns * rows;
|
|
3374
|
+
const segmentDuration = reference.trueEndTime - reference.startTime;
|
|
3375
|
+
const thumbnailDuration = segmentDuration / totalImages;
|
|
3376
|
+
let thumbnailTime = reference.startTime;
|
|
3333
3377
|
let positionX = 0;
|
|
3334
3378
|
let positionY = 0;
|
|
3335
|
-
const totalImages = columns * rows;
|
|
3336
3379
|
// If the number of images in the segment is greater than 1, we have to
|
|
3337
3380
|
// find the correct image. For that we will return to the app the
|
|
3338
3381
|
// coordinates of the position of the correct image.
|
|
@@ -3340,21 +3383,23 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3340
3383
|
// Note: The time between images within the segment is always
|
|
3341
3384
|
// equidistant.
|
|
3342
3385
|
//
|
|
3343
|
-
// Eg: Total images 5, tileLayout 5x1,
|
|
3386
|
+
// Eg: Total images 5, tileLayout 5x1, segmentDuration 5, thumbnailTime 2
|
|
3344
3387
|
// positionX = 0.4 * fullImageWidth
|
|
3345
3388
|
// positionY = 0
|
|
3346
3389
|
if (totalImages > 1) {
|
|
3347
|
-
const thumbnailTime = time - reference.startTime;
|
|
3348
|
-
const segmentTime = reference.endTime - reference.startTime;
|
|
3349
3390
|
const thumbnailPosition =
|
|
3350
|
-
Math.floor(
|
|
3351
|
-
|
|
3352
|
-
|
|
3391
|
+
Math.floor((time - reference.startTime) / thumbnailDuration);
|
|
3392
|
+
thumbnailTime = reference.startTime +
|
|
3393
|
+
(thumbnailPosition * thumbnailDuration);
|
|
3394
|
+
positionX = (thumbnailPosition % columns) * width;
|
|
3395
|
+
positionY = Math.floor(thumbnailPosition / columns) * height;
|
|
3353
3396
|
}
|
|
3354
3397
|
return {
|
|
3355
3398
|
height: height,
|
|
3356
3399
|
positionX: positionX,
|
|
3357
3400
|
positionY: positionY,
|
|
3401
|
+
startTime: thumbnailTime,
|
|
3402
|
+
duration: thumbnailDuration,
|
|
3358
3403
|
uris: reference.getUris(),
|
|
3359
3404
|
width: width,
|
|
3360
3405
|
};
|
|
@@ -4770,7 +4815,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4770
4815
|
// Surface the buffering event so that the app knows if/when we are
|
|
4771
4816
|
// buffering.
|
|
4772
4817
|
const eventName = shaka.Player.EventName.Buffering;
|
|
4773
|
-
|
|
4818
|
+
const data = (new Map()).set('buffering', isBuffering);
|
|
4819
|
+
this.dispatchEvent(this.makeEvent_(eventName, data));
|
|
4774
4820
|
}
|
|
4775
4821
|
|
|
4776
4822
|
/**
|
|
@@ -4955,6 +5001,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4955
5001
|
const currentVariant = this.streamingEngine_.getCurrentVariant();
|
|
4956
5002
|
if (variant == currentVariant) {
|
|
4957
5003
|
shaka.log.debug('Variant already selected.');
|
|
5004
|
+
// If you want to clear the buffer, we force to reselect the same variant
|
|
5005
|
+
if (clearBuffer) {
|
|
5006
|
+
this.streamingEngine_.switchVariant(variant, clearBuffer, safeMargin,
|
|
5007
|
+
/* force= */ true);
|
|
5008
|
+
}
|
|
4958
5009
|
return;
|
|
4959
5010
|
}
|
|
4960
5011
|
|
|
@@ -4983,6 +5034,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4983
5034
|
// This will reset the "enabled" of other tracks to false.
|
|
4984
5035
|
track.enabled = true;
|
|
4985
5036
|
|
|
5037
|
+
// AirPlay does not reset the "enabled" of other tracks to false, so
|
|
5038
|
+
// it must be changed by hand.
|
|
5039
|
+
if (track.id !== currentTrack.id) {
|
|
5040
|
+
currentTrack.enabled = false;
|
|
5041
|
+
}
|
|
5042
|
+
|
|
4986
5043
|
const oldTrack =
|
|
4987
5044
|
shaka.util.StreamUtils.html5AudioTrackToTrack(currentTrack);
|
|
4988
5045
|
const newTrack =
|
|
@@ -5141,10 +5198,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5141
5198
|
onVariantChanged_(from, to) {
|
|
5142
5199
|
// Delay the 'variantchanged' event so StreamingEngine has time to absorb
|
|
5143
5200
|
// the changes before the user tries to query it.
|
|
5144
|
-
const
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5201
|
+
const data = new Map()
|
|
5202
|
+
.set('oldTrack', from)
|
|
5203
|
+
.set('newTrack', to);
|
|
5204
|
+
const event = this.makeEvent_(shaka.Player.EventName.VariantChanged, data);
|
|
5148
5205
|
this.delayDispatchEvent_(event);
|
|
5149
5206
|
}
|
|
5150
5207
|
|
|
@@ -5167,10 +5224,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5167
5224
|
|
|
5168
5225
|
/** @private */
|
|
5169
5226
|
onAbrStatusChanged_() {
|
|
5170
|
-
const
|
|
5171
|
-
|
|
5172
|
-
|
|
5173
|
-
this.delayDispatchEvent_(event);
|
|
5227
|
+
const data = (new Map()).set('newStatus', this.config_.abr.enabled);
|
|
5228
|
+
this.delayDispatchEvent_(this.makeEvent_(
|
|
5229
|
+
shaka.Player.EventName.AbrStatusChanged, data));
|
|
5174
5230
|
}
|
|
5175
5231
|
|
|
5176
5232
|
/**
|
|
@@ -5187,7 +5243,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5187
5243
|
}
|
|
5188
5244
|
|
|
5189
5245
|
const eventName = shaka.Player.EventName.Error;
|
|
5190
|
-
const event = this.makeEvent_(eventName,
|
|
5246
|
+
const event = this.makeEvent_(eventName, (new Map()).set('detail', error));
|
|
5191
5247
|
this.dispatchEvent(event);
|
|
5192
5248
|
if (event.defaultPrevented) {
|
|
5193
5249
|
error.handled = true;
|
|
@@ -5216,7 +5272,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5216
5272
|
eventElement: region.eventElement,
|
|
5217
5273
|
};
|
|
5218
5274
|
|
|
5219
|
-
|
|
5275
|
+
const data = (new Map()).set('detail', clone);
|
|
5276
|
+
this.dispatchEvent(this.makeEvent_(eventName, data));
|
|
5220
5277
|
}
|
|
5221
5278
|
|
|
5222
5279
|
/**
|
|
@@ -6045,7 +6102,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6045
6102
|
* @define {string} A version number taken from git at compile time.
|
|
6046
6103
|
* @export
|
|
6047
6104
|
*/
|
|
6048
|
-
shaka.Player.version = 'v3.1.
|
|
6105
|
+
shaka.Player.version = 'v3.1.4-uncompiled';
|
|
6049
6106
|
|
|
6050
6107
|
// Initialize the deprecation system using the version string we just set
|
|
6051
6108
|
// on the player.
|
|
@@ -13,12 +13,14 @@ goog.require('shaka.polyfill');
|
|
|
13
13
|
* @see https://wicg.github.io/encrypted-media-encryption-scheme/
|
|
14
14
|
* @see https://github.com/w3c/encrypted-media/pull/457
|
|
15
15
|
* @see https://github.com/google/eme-encryption-scheme-polyfill
|
|
16
|
+
* @export
|
|
16
17
|
*/
|
|
17
18
|
shaka.polyfill.EncryptionScheme = class {
|
|
18
19
|
/**
|
|
19
20
|
* Install the polyfill if needed.
|
|
20
21
|
*
|
|
21
22
|
* @suppress {missingRequire}
|
|
23
|
+
* @export
|
|
22
24
|
*/
|
|
23
25
|
static install() {
|
|
24
26
|
EncryptionSchemePolyfills.install();
|
|
@@ -14,10 +14,12 @@ goog.require('shaka.polyfill');
|
|
|
14
14
|
* Many browsers have prefixed fullscreen methods on Element and document.
|
|
15
15
|
* See {@link https://mzl.la/2K0xcHo Using fullscreen mode} on MDN for more
|
|
16
16
|
* information.
|
|
17
|
+
* @export
|
|
17
18
|
*/
|
|
18
19
|
shaka.polyfill.Fullscreen = class {
|
|
19
20
|
/**
|
|
20
21
|
* Install the polyfill if needed.
|
|
22
|
+
* @export
|
|
21
23
|
*/
|
|
22
24
|
static install() {
|
|
23
25
|
if (!window.Document) {
|
|
@@ -11,10 +11,12 @@ goog.require('shaka.polyfill');
|
|
|
11
11
|
/**
|
|
12
12
|
* @summary A polyfill to patch math round bug on some browsers.
|
|
13
13
|
* @see https://stackoverflow.com/q/12830742
|
|
14
|
+
* @export
|
|
14
15
|
*/
|
|
15
16
|
shaka.polyfill.MathRound = class {
|
|
16
17
|
/**
|
|
17
18
|
* Install the polyfill if needed.
|
|
19
|
+
* @export
|
|
18
20
|
*/
|
|
19
21
|
static install() {
|
|
20
22
|
shaka.log.debug('mathRound.install');
|
|
@@ -15,10 +15,13 @@ goog.require('shaka.util.Platform');
|
|
|
15
15
|
* @summary A polyfill to provide navigator.mediaCapabilities on all browsers.
|
|
16
16
|
* This is necessary for Tizen 3, Xbox One and possibly others we have yet to
|
|
17
17
|
* discover.
|
|
18
|
+
* @export
|
|
18
19
|
*/
|
|
19
20
|
shaka.polyfill.MediaCapabilities = class {
|
|
20
21
|
/**
|
|
21
22
|
* Install the polyfill if needed.
|
|
23
|
+
* @suppress {const}
|
|
24
|
+
* @export
|
|
22
25
|
*/
|
|
23
26
|
static install() {
|
|
24
27
|
shaka.log.debug('MediaCapabilities: install');
|
|
@@ -26,20 +29,32 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
26
29
|
// Since MediaCapabilities is not fully supported on Chromecast yet, we
|
|
27
30
|
// should always install polyfill for Chromecast.
|
|
28
31
|
// TODO: re-evaluate MediaCapabilities in the future versions of Chromecast.
|
|
29
|
-
|
|
32
|
+
// Since MediaCapabilities implementation is buggy in Apple browsers, we
|
|
33
|
+
// should always install polyfill for Apple browsers.
|
|
34
|
+
// See: https://github.com/google/shaka-player/issues/3530
|
|
35
|
+
// TODO: re-evaluate MediaCapabilities in the future versions of Apple
|
|
36
|
+
// Browsers.
|
|
37
|
+
// Since MediaCapabilities implementation is buggy in PS5 browsers, we
|
|
38
|
+
// should always install polyfill for PS5 browsers.
|
|
39
|
+
// See: https://github.com/google/shaka-player/issues/3582
|
|
40
|
+
// TODO: re-evaluate MediaCapabilities in the future versions of PS5
|
|
41
|
+
// Browsers.
|
|
42
|
+
if (!shaka.util.Platform.isChromecast() &&
|
|
43
|
+
!shaka.util.Platform.isApple() &&
|
|
44
|
+
!shaka.util.Platform.isPS5() &&
|
|
45
|
+
navigator.mediaCapabilities) {
|
|
30
46
|
shaka.log.debug(
|
|
31
47
|
'MediaCapabilities: Native mediaCapabilities support found.');
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
48
|
+
} else {
|
|
49
|
+
if (!navigator.mediaCapabilities) {
|
|
50
|
+
navigator.mediaCapabilities = /** @type {!MediaCapabilities} */ ({});
|
|
51
|
+
}
|
|
52
|
+
navigator.mediaCapabilities.decodingInfo =
|
|
53
|
+
shaka.polyfill.MediaCapabilities.decodingInfo_;
|
|
38
54
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
navigator.mediaCapabilities
|
|
42
|
-
shaka.polyfill.MediaCapabilities.decodingInfo_;
|
|
55
|
+
// Workaround because in Apple browsers there is no way to overwrite
|
|
56
|
+
// MediaCapabilities.
|
|
57
|
+
window.shakaMediaCapabilities = navigator.mediaCapabilities;
|
|
43
58
|
}
|
|
44
59
|
|
|
45
60
|
/**
|
|
@@ -60,21 +75,45 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
60
75
|
return res;
|
|
61
76
|
}
|
|
62
77
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const contentType = mediaDecodingConfig['video'].contentType;
|
|
66
|
-
const isSupported = MediaSource.isTypeSupported(contentType);
|
|
67
|
-
if (!isSupported) {
|
|
78
|
+
if (mediaDecodingConfig.type == 'media-source') {
|
|
79
|
+
if (!shaka.util.Platform.supportsMediaSource()) {
|
|
68
80
|
return res;
|
|
69
81
|
}
|
|
70
|
-
|
|
82
|
+
// Use 'MediaSource.isTypeSupported' to check if the stream is supported.
|
|
83
|
+
if (mediaDecodingConfig['video']) {
|
|
84
|
+
const contentType = mediaDecodingConfig['video'].contentType;
|
|
85
|
+
const isSupported = MediaSource.isTypeSupported(contentType);
|
|
86
|
+
if (!isSupported) {
|
|
87
|
+
return res;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
71
90
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
91
|
+
if (mediaDecodingConfig['audio']) {
|
|
92
|
+
const contentType = mediaDecodingConfig['audio'].contentType;
|
|
93
|
+
const isSupported = MediaSource.isTypeSupported(contentType);
|
|
94
|
+
if (!isSupported) {
|
|
95
|
+
return res;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
} else if (mediaDecodingConfig.type == 'file') {
|
|
99
|
+
if (mediaDecodingConfig['video']) {
|
|
100
|
+
const contentType = mediaDecodingConfig['video'].contentType;
|
|
101
|
+
const isSupported = shaka.util.Platform.supportsMediaType(contentType);
|
|
102
|
+
if (!isSupported) {
|
|
103
|
+
return res;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (mediaDecodingConfig['audio']) {
|
|
108
|
+
const contentType = mediaDecodingConfig['audio'].contentType;
|
|
109
|
+
const isSupported = shaka.util.Platform.supportsMediaType(contentType);
|
|
110
|
+
if (!isSupported) {
|
|
111
|
+
return res;
|
|
112
|
+
}
|
|
77
113
|
}
|
|
114
|
+
} else {
|
|
115
|
+
// Otherwise not supported.
|
|
116
|
+
return res;
|
|
78
117
|
}
|
|
79
118
|
|
|
80
119
|
if (!mediaDecodingConfig.keySystemConfiguration) {
|
|
@@ -116,7 +155,7 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
116
155
|
sessionTypes: mediaCapkeySystemConfig.sessionTypes,
|
|
117
156
|
};
|
|
118
157
|
|
|
119
|
-
// Only add the audio video
|
|
158
|
+
// Only add the audio video capabilities if they have valid data.
|
|
120
159
|
// Otherwise the query will fail.
|
|
121
160
|
if (audioCapabilities.length) {
|
|
122
161
|
mediaKeySystemConfig.audioCapabilities = audioCapabilities;
|
|
@@ -13,10 +13,12 @@ goog.require('shaka.util.Platform');
|
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* @summary A polyfill to patch MSE bugs.
|
|
16
|
+
* @export
|
|
16
17
|
*/
|
|
17
18
|
shaka.polyfill.MediaSource = class {
|
|
18
19
|
/**
|
|
19
20
|
* Install the polyfill if needed.
|
|
21
|
+
* @export
|
|
20
22
|
*/
|
|
21
23
|
static install() {
|
|
22
24
|
shaka.log.debug('MediaSource.install');
|
|
@@ -206,6 +208,12 @@ shaka.polyfill.MediaSource = class {
|
|
|
206
208
|
static patchVp09_() {
|
|
207
209
|
const originalIsTypeSupported = MediaSource.isTypeSupported;
|
|
208
210
|
|
|
211
|
+
if (shaka.util.Platform.isWebOS()) {
|
|
212
|
+
// Don't do this on LG webOS as otherwise it is unable
|
|
213
|
+
// to play vp09 at all.
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
209
217
|
MediaSource.isTypeSupported = (mimeType) => {
|
|
210
218
|
// Split the MIME type into its various parameters.
|
|
211
219
|
const pieces = mimeType.split(/ *; */);
|
|
@@ -15,10 +15,12 @@ goog.require('shaka.polyfill');
|
|
|
15
15
|
* @summary A polyfill for systems that do not implement screen.orientation.
|
|
16
16
|
* For now, this only handles systems that implement the deprecated
|
|
17
17
|
* window.orientation feature... e.g. iPad.
|
|
18
|
+
* @export
|
|
18
19
|
*/
|
|
19
20
|
shaka.polyfill.Orientation = class {
|
|
20
21
|
/**
|
|
21
22
|
* Install the polyfill if needed.
|
|
23
|
+
* @export
|
|
22
24
|
*/
|
|
23
25
|
static install() {
|
|
24
26
|
if (screen.orientation) {
|
|
@@ -90,7 +92,7 @@ class extends shaka.util.FakeEventTarget {
|
|
|
90
92
|
|
|
91
93
|
/** Dispatch a 'change' event. */
|
|
92
94
|
dispatchChangeEvent() {
|
|
93
|
-
const event = new shaka.util.FakeEvent('change'
|
|
95
|
+
const event = new shaka.util.FakeEvent('change');
|
|
94
96
|
this.dispatchEvent(event);
|
|
95
97
|
}
|
|
96
98
|
|
|
@@ -22,10 +22,12 @@ goog.require('shaka.util.StringUtils');
|
|
|
22
22
|
/**
|
|
23
23
|
* @summary A polyfill to implement modern, standardized EME on top of Apple's
|
|
24
24
|
* prefixed EME in Safari.
|
|
25
|
+
* @export
|
|
25
26
|
*/
|
|
26
27
|
shaka.polyfill.PatchedMediaKeysApple = class {
|
|
27
28
|
/**
|
|
28
29
|
* Installs the polyfill if needed.
|
|
30
|
+
* @export
|
|
29
31
|
*/
|
|
30
32
|
static install() {
|
|
31
33
|
if (!window.HTMLVideoElement || !window.WebKitMediaKeys) {
|
|
@@ -565,10 +567,10 @@ class extends shaka.util.FakeEventTarget {
|
|
|
565
567
|
|
|
566
568
|
const isNew = this.keyStatuses.getStatus() == undefined;
|
|
567
569
|
|
|
568
|
-
const
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
570
|
+
const data = new Map()
|
|
571
|
+
.set('messageType', isNew ? 'license-request' : 'license-renewal')
|
|
572
|
+
.set('message', shaka.util.BufferUtils.toArrayBuffer(event.message));
|
|
573
|
+
const event2 = new shaka.util.FakeEvent('message', data);
|
|
572
574
|
|
|
573
575
|
this.dispatchEvent(event2);
|
|
574
576
|
}
|
|
@@ -24,10 +24,12 @@ goog.require('shaka.util.PublicPromise');
|
|
|
24
24
|
* {@link https://bit.ly/EmeMar15 EME draft 12 March 2015}
|
|
25
25
|
* on top of ms-prefixed
|
|
26
26
|
* {@link https://www.w3.org/TR/2014/WD-encrypted-media-20140218/ EME v20140218}
|
|
27
|
+
* @export
|
|
27
28
|
*/
|
|
28
29
|
shaka.polyfill.PatchedMediaKeysMs = class {
|
|
29
30
|
/**
|
|
30
31
|
* Installs the polyfill if needed.
|
|
32
|
+
* @export
|
|
31
33
|
*/
|
|
32
34
|
static install() {
|
|
33
35
|
if (!window.HTMLVideoElement || !window.MSMediaKeys ||
|
|
@@ -510,10 +512,10 @@ class extends shaka.util.FakeEventTarget {
|
|
|
510
512
|
|
|
511
513
|
const isNew = this.keyStatuses.getStatus() == undefined;
|
|
512
514
|
|
|
513
|
-
const
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
515
|
+
const data = new Map()
|
|
516
|
+
.set('messageType', isNew ? 'license-request' : 'license-renewal')
|
|
517
|
+
.set('message', shaka.util.BufferUtils.toArrayBuffer(event.message));
|
|
518
|
+
const event2 = new shaka.util.FakeEvent('message', data);
|
|
517
519
|
|
|
518
520
|
this.dispatchEvent(event2);
|
|
519
521
|
}
|
|
@@ -16,10 +16,12 @@ goog.require('shaka.polyfill');
|
|
|
16
16
|
* {@link https://bit.ly/EmeMar15 EME draft 12 March 2015} on browsers without
|
|
17
17
|
* EME.
|
|
18
18
|
* All methods will fail.
|
|
19
|
+
* @export
|
|
19
20
|
*/
|
|
20
21
|
shaka.polyfill.PatchedMediaKeysNop = class {
|
|
21
22
|
/**
|
|
22
23
|
* Installs the polyfill if needed.
|
|
24
|
+
* @export
|
|
23
25
|
*/
|
|
24
26
|
static install() {
|
|
25
27
|
if (!window.HTMLVideoElement ||
|
|
@@ -24,10 +24,12 @@ goog.require('shaka.util.Uint8ArrayUtils');
|
|
|
24
24
|
* @summary A polyfill to implement
|
|
25
25
|
* {@link https://bit.ly/EmeMar15 EME draft 12 March 2015} on top of
|
|
26
26
|
* webkit-prefixed {@link https://bit.ly/Eme01b EME v0.1b}.
|
|
27
|
+
* @export
|
|
27
28
|
*/
|
|
28
29
|
shaka.polyfill.PatchedMediaKeysWebkit = class {
|
|
29
30
|
/**
|
|
30
31
|
* Installs the polyfill if needed.
|
|
32
|
+
* @export
|
|
31
33
|
*/
|
|
32
34
|
static install() {
|
|
33
35
|
// Alias.
|
|
@@ -449,10 +451,10 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeys = class {
|
|
|
449
451
|
|
|
450
452
|
const isNew = session.keyStatuses.getStatus() == undefined;
|
|
451
453
|
|
|
452
|
-
const
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
454
|
+
const data = new Map()
|
|
455
|
+
.set('messageType', isNew ? 'licenserequest' : 'licenserenewal')
|
|
456
|
+
.set('message', event.message);
|
|
457
|
+
const event2 = new shaka.util.FakeEvent('message', data);
|
|
456
458
|
|
|
457
459
|
session.generated();
|
|
458
460
|
session.dispatchEvent(event2);
|