shaka-player 4.7.13 → 4.7.15
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 +1 -0
- package/CONTRIBUTORS +2 -0
- package/dist/cast-boot.js +37 -0
- package/dist/deps.js +5 -4
- package/dist/locales.js +31 -31
- package/dist/shaka-player.compiled.d.ts +37 -14
- package/dist/shaka-player.compiled.debug.d.ts +37 -14
- package/dist/shaka-player.compiled.debug.externs.js +14 -0
- package/dist/shaka-player.compiled.debug.js +360 -350
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +14 -0
- package/dist/shaka-player.compiled.js +1107 -1105
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +37 -14
- package/dist/shaka-player.ui.debug.d.ts +37 -14
- package/dist/shaka-player.ui.debug.externs.js +14 -0
- package/dist/shaka-player.ui.debug.js +280 -269
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +14 -0
- package/dist/shaka-player.ui.js +1267 -1265
- package/dist/shaka-player.ui.map +4 -4
- package/externs/cast-namespace.js +14 -0
- package/externs/{chromecast.js → cast-sdk-v2.js} +0 -4
- package/externs/cast-sdk-v3.js +35 -0
- package/externs/ima.js +2 -0
- package/externs/mediatailor.js +0 -0
- package/externs/{cast.js → remote-playback.js} +2 -2
- package/externs/shaka/player.js +5 -2
- package/lib/ads/client_side_ad_manager.js +9 -5
- package/lib/cea/cea608_data_channel.js +9 -0
- package/lib/cea/cea_decoder.js +9 -2
- package/lib/dash/segment_template.js +30 -2
- package/lib/hls/hls_parser.js +19 -10
- package/lib/media/closed_caption_parser.js +16 -4
- package/lib/media/drm_engine.js +17 -3
- package/lib/media/gap_jumping_controller.js +9 -1
- package/lib/media/media_source_engine.js +20 -13
- package/lib/media/play_rate_controller.js +36 -8
- package/lib/media/playhead.js +3 -3
- package/lib/media/segment_index.js +10 -0
- package/lib/media/segment_reference.js +12 -0
- package/lib/media/stall_detector.js +3 -0
- package/lib/media/streaming_engine.js +8 -14
- package/lib/net/http_fetch_plugin.js +3 -1
- package/lib/net/http_xhr_plugin.js +6 -1
- package/lib/player.js +111 -53
- package/lib/polyfill/media_capabilities.js +7 -5
- package/lib/polyfill/patchedmediakeys_cert.js +62 -0
- package/lib/text/ui_text_displayer.js +10 -1
- package/lib/transmuxer/ts_transmuxer.js +6 -24
- package/lib/util/object_utils.js +1 -2
- package/lib/util/platform.js +100 -11
- package/lib/util/stream_utils.js +31 -14
- package/package.json +7 -2
- package/support.html +2 -0
- package/ui/audio_language_selection.js +4 -0
- package/ui/range_element.js +8 -2
- package/ui/resolution_selection.js +5 -0
- package/ui/text_selection.js +4 -0
|
@@ -1733,9 +1733,16 @@ shaka.media.StreamingEngine = class {
|
|
|
1733
1733
|
otherState = this.mediaStates_.get(ContentType.VIDEO);
|
|
1734
1734
|
}
|
|
1735
1735
|
if (otherState) {
|
|
1736
|
+
// First, abort all operations in progress on the other stream.
|
|
1737
|
+
await this.abortOperations_(otherState).catch(() => {});
|
|
1738
|
+
// Then clear our cache of the last init segment, since MSE will be
|
|
1739
|
+
// reloaded and no init segment will be there post-reload.
|
|
1736
1740
|
otherState.lastInitSegmentReference = null;
|
|
1741
|
+
// Now force the existing buffer to be cleared. It is not necessary
|
|
1742
|
+
// to perform the MSE clear operation, but this has the side-effect
|
|
1743
|
+
// that our state for that stream will then match MSE's post-reload
|
|
1744
|
+
// state.
|
|
1737
1745
|
this.forceClearBuffer_(otherState);
|
|
1738
|
-
this.abortOperations_(otherState).catch(() => {});
|
|
1739
1746
|
}
|
|
1740
1747
|
}
|
|
1741
1748
|
|
|
@@ -1766,19 +1773,6 @@ shaka.media.StreamingEngine = class {
|
|
|
1766
1773
|
appendWindowEnd, ignoreTimestampOffset,
|
|
1767
1774
|
reference.mimeType || mediaState.stream.mimeType,
|
|
1768
1775
|
reference.codecs || mediaState.stream.codecs, streamsByType);
|
|
1769
|
-
if (isResetMediaSourceNecessary) {
|
|
1770
|
-
let otherState = null;
|
|
1771
|
-
if (mediaState.type === ContentType.VIDEO) {
|
|
1772
|
-
otherState = this.mediaStates_.get(ContentType.AUDIO);
|
|
1773
|
-
} else if (mediaState.type === ContentType.AUDIO) {
|
|
1774
|
-
otherState = this.mediaStates_.get(ContentType.VIDEO);
|
|
1775
|
-
}
|
|
1776
|
-
if (otherState) {
|
|
1777
|
-
otherState.waitingToClearBuffer = false;
|
|
1778
|
-
otherState.performingUpdate = false;
|
|
1779
|
-
this.forceClearBuffer_(otherState);
|
|
1780
|
-
}
|
|
1781
|
-
}
|
|
1782
1776
|
} catch (error) {
|
|
1783
1777
|
mediaState.lastAppendWindowStart = null;
|
|
1784
1778
|
mediaState.lastAppendWindowEnd = null;
|
|
@@ -167,8 +167,10 @@ shaka.net.HttpFetchPlugin = class {
|
|
|
167
167
|
// is long enough, or if a whole segment is downloaded, call
|
|
168
168
|
// progressUpdated().
|
|
169
169
|
if (currentTime - lastTime > 100 || readObj.done) {
|
|
170
|
+
const numBytesRemaining =
|
|
171
|
+
readObj.done ? 0 : contentLength - loaded;
|
|
170
172
|
progressUpdated(currentTime - lastTime, loaded - lastLoaded,
|
|
171
|
-
|
|
173
|
+
numBytesRemaining);
|
|
172
174
|
lastLoaded = loaded;
|
|
173
175
|
lastTime = currentTime;
|
|
174
176
|
}
|
|
@@ -67,6 +67,9 @@ shaka.net.HttpXHRPlugin = class {
|
|
|
67
67
|
const xhrResponse = xhr.response;
|
|
68
68
|
|
|
69
69
|
try {
|
|
70
|
+
const currentTime = Date.now();
|
|
71
|
+
progressUpdated(currentTime - lastTime, event.loaded - lastLoaded,
|
|
72
|
+
/* numBytesRemaining= */ 0);
|
|
70
73
|
const response = shaka.net.HttpPluginUtils.makeResponse(headers,
|
|
71
74
|
xhrResponse, xhr.status, uri, xhr.responseURL, requestType);
|
|
72
75
|
resolve(response);
|
|
@@ -97,8 +100,10 @@ shaka.net.HttpXHRPlugin = class {
|
|
|
97
100
|
// progressUpdated().
|
|
98
101
|
if (currentTime - lastTime > 100 ||
|
|
99
102
|
(event.lengthComputable && event.loaded == event.total)) {
|
|
103
|
+
const numBytesRemaining =
|
|
104
|
+
xhr.readyState == 4 ? 0 : event.total - event.loaded;
|
|
100
105
|
progressUpdated(currentTime - lastTime, event.loaded - lastLoaded,
|
|
101
|
-
|
|
106
|
+
numBytesRemaining);
|
|
102
107
|
lastLoaded = event.loaded;
|
|
103
108
|
lastTime = currentTime;
|
|
104
109
|
}
|
package/lib/player.js
CHANGED
|
@@ -596,6 +596,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
596
596
|
*/
|
|
597
597
|
this.playRateController_ = null;
|
|
598
598
|
|
|
599
|
+
// We use the buffering observer and timer to track when we move from having
|
|
600
|
+
// enough buffered content to not enough. They only exist when content has
|
|
601
|
+
// been loaded and are not re-used between loads.
|
|
602
|
+
/** @private {shaka.util.Timer} */
|
|
603
|
+
this.bufferPoller_ = null;
|
|
604
|
+
|
|
599
605
|
/** @private {shaka.media.BufferingObserver} */
|
|
600
606
|
this.bufferObserver_ = null;
|
|
601
607
|
|
|
@@ -1191,6 +1197,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1191
1197
|
this.playheadObservers_ = null;
|
|
1192
1198
|
}
|
|
1193
1199
|
|
|
1200
|
+
if (this.bufferPoller_) {
|
|
1201
|
+
this.bufferPoller_.stop();
|
|
1202
|
+
this.bufferPoller_ = null;
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1194
1205
|
// Stop the parser early. Since it is at the start of the pipeline, it
|
|
1195
1206
|
// should be start early to avoid is pushing new data downstream.
|
|
1196
1207
|
if (this.parser_) {
|
|
@@ -1977,31 +1988,49 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1977
1988
|
this.config_.playRangeStart,
|
|
1978
1989
|
this.config_.playRangeEnd);
|
|
1979
1990
|
|
|
1980
|
-
this.playhead_ = this.createPlayhead(this.startTime_);
|
|
1981
|
-
this.playheadObservers_ =
|
|
1982
|
-
this.createPlayheadObserversForMSE_(startTimeOfLoad);
|
|
1983
1991
|
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1992
|
+
const setupPlayhead = (startTime) => {
|
|
1993
|
+
this.playhead_ = this.createPlayhead(startTime);
|
|
1994
|
+
this.playheadObservers_ =
|
|
1995
|
+
this.createPlayheadObserversForMSE_(startTime);
|
|
1996
|
+
|
|
1997
|
+
// We need to start the buffer management code near the end because it
|
|
1998
|
+
// will set the initial buffering state and that depends on other
|
|
1999
|
+
// components being initialized.
|
|
2000
|
+
const rebufferThreshold = Math.max(
|
|
2001
|
+
this.manifest_.minBufferTime,
|
|
2002
|
+
this.config_.streaming.rebufferingGoal);
|
|
2003
|
+
this.startBufferManagement_(mediaElement, rebufferThreshold);
|
|
2004
|
+
};
|
|
2005
|
+
|
|
2006
|
+
if (!this.config_.streaming.startAtSegmentBoundary) {
|
|
2007
|
+
setupPlayhead(this.startTime_);
|
|
2008
|
+
}
|
|
1990
2009
|
|
|
1991
2010
|
// Now we can switch to the initial variant.
|
|
1992
2011
|
if (!activeVariant) {
|
|
1993
2012
|
goog.asserts.assert(initialVariant,
|
|
1994
2013
|
'Must have choosen an initial variant!');
|
|
1995
2014
|
|
|
1996
|
-
this.switchVariant_(initialVariant, /* fromAdaptation= */ true,
|
|
1997
|
-
/* clearBuffer= */ false, /* safeMargin= */ 0);
|
|
1998
|
-
|
|
1999
2015
|
// Now that we have initial streams, we may adjust the start time to
|
|
2000
2016
|
// align to a segment boundary.
|
|
2001
2017
|
if (this.config_.streaming.startAtSegmentBoundary) {
|
|
2002
|
-
this.
|
|
2003
|
-
|
|
2018
|
+
const timeline = this.manifest_.presentationTimeline;
|
|
2019
|
+
let initialTime = this.startTime_ || this.video_.currentTime;
|
|
2020
|
+
const seekRangeStart = timeline.getSeekRangeStart();
|
|
2021
|
+
const seekRangeEnd = timeline.getSeekRangeEnd();
|
|
2022
|
+
if (initialTime < seekRangeStart) {
|
|
2023
|
+
initialTime = seekRangeStart;
|
|
2024
|
+
} else if (initialTime > seekRangeEnd) {
|
|
2025
|
+
initialTime = seekRangeEnd;
|
|
2026
|
+
}
|
|
2027
|
+
const startTime = await this.adjustStartTime_(
|
|
2028
|
+
initialVariant, initialTime);
|
|
2029
|
+
setupPlayhead(startTime);
|
|
2004
2030
|
}
|
|
2031
|
+
|
|
2032
|
+
this.switchVariant_(initialVariant, /* fromAdaptation= */ true,
|
|
2033
|
+
/* clearBuffer= */ false, /* safeMargin= */ 0);
|
|
2005
2034
|
}
|
|
2006
2035
|
|
|
2007
2036
|
this.playhead_.ready();
|
|
@@ -2065,7 +2094,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2065
2094
|
this.manifest_.serviceDescription)) {
|
|
2066
2095
|
const onTimeUpdate = () => this.onTimeUpdate_();
|
|
2067
2096
|
this.loadEventManager_.listen(mediaElement, 'timeupdate', onTimeUpdate);
|
|
2068
|
-
}
|
|
2097
|
+
}
|
|
2098
|
+
if (!isLive) {
|
|
2069
2099
|
const onVideoProgress = () => this.onVideoProgress_();
|
|
2070
2100
|
this.loadEventManager_.listen(
|
|
2071
2101
|
mediaElement, 'timeupdate', onVideoProgress);
|
|
@@ -2147,42 +2177,49 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2147
2177
|
disabledUntilTime: 0,
|
|
2148
2178
|
primary: false,
|
|
2149
2179
|
audio: null,
|
|
2150
|
-
video:
|
|
2151
|
-
id: 0,
|
|
2152
|
-
originalId: null,
|
|
2153
|
-
groupId: null,
|
|
2154
|
-
createSegmentIndex: () => Promise.resolve(),
|
|
2155
|
-
segmentIndex: null,
|
|
2156
|
-
mimeType: mimeType ? shaka.util.MimeUtils.getBasicType(mimeType) : '',
|
|
2157
|
-
codecs: mimeType ? shaka.util.MimeUtils.getCodecs(mimeType) : '',
|
|
2158
|
-
encrypted: true,
|
|
2159
|
-
drmInfos: [], // Filled in by DrmEngine config.
|
|
2160
|
-
keyIds: new Set(),
|
|
2161
|
-
language: 'und',
|
|
2162
|
-
originalLanguage: null,
|
|
2163
|
-
label: null,
|
|
2164
|
-
type: ContentType.VIDEO,
|
|
2165
|
-
primary: false,
|
|
2166
|
-
trickModeVideo: null,
|
|
2167
|
-
emsgSchemeIdUris: null,
|
|
2168
|
-
roles: [],
|
|
2169
|
-
forced: false,
|
|
2170
|
-
channelsCount: null,
|
|
2171
|
-
audioSamplingRate: null,
|
|
2172
|
-
spatialAudio: false,
|
|
2173
|
-
closedCaptions: null,
|
|
2174
|
-
accessibilityPurpose: null,
|
|
2175
|
-
external: false,
|
|
2176
|
-
fastSwitching: false,
|
|
2177
|
-
fullMimeTypes: new Set(),
|
|
2178
|
-
},
|
|
2180
|
+
video: null,
|
|
2179
2181
|
bandwidth: 100,
|
|
2180
2182
|
allowedByApplication: true,
|
|
2181
2183
|
allowedByKeySystem: true,
|
|
2182
2184
|
decodingInfos: [],
|
|
2183
2185
|
};
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
+
const stream = {
|
|
2187
|
+
id: 0,
|
|
2188
|
+
originalId: null,
|
|
2189
|
+
groupId: null,
|
|
2190
|
+
createSegmentIndex: () => Promise.resolve(),
|
|
2191
|
+
segmentIndex: null,
|
|
2192
|
+
mimeType: mimeType ? shaka.util.MimeUtils.getBasicType(mimeType) : '',
|
|
2193
|
+
codecs: mimeType ? shaka.util.MimeUtils.getCodecs(mimeType) : '',
|
|
2194
|
+
encrypted: true,
|
|
2195
|
+
drmInfos: [], // Filled in by DrmEngine config.
|
|
2196
|
+
keyIds: new Set(),
|
|
2197
|
+
language: 'und',
|
|
2198
|
+
originalLanguage: null,
|
|
2199
|
+
label: null,
|
|
2200
|
+
type: ContentType.VIDEO,
|
|
2201
|
+
primary: false,
|
|
2202
|
+
trickModeVideo: null,
|
|
2203
|
+
emsgSchemeIdUris: null,
|
|
2204
|
+
roles: [],
|
|
2205
|
+
forced: false,
|
|
2206
|
+
channelsCount: null,
|
|
2207
|
+
audioSamplingRate: null,
|
|
2208
|
+
spatialAudio: false,
|
|
2209
|
+
closedCaptions: null,
|
|
2210
|
+
accessibilityPurpose: null,
|
|
2211
|
+
external: false,
|
|
2212
|
+
fastSwitching: false,
|
|
2213
|
+
fullMimeTypes: new Set(),
|
|
2214
|
+
};
|
|
2215
|
+
stream.fullMimeTypes.add(shaka.util.MimeUtils.getFullType(
|
|
2216
|
+
stream.mimeType, stream.codecs));
|
|
2217
|
+
if (mimeType.startsWith('audio/')) {
|
|
2218
|
+
stream.type = ContentType.AUDIO;
|
|
2219
|
+
variant.audio = stream;
|
|
2220
|
+
} else {
|
|
2221
|
+
variant.video = stream;
|
|
2222
|
+
}
|
|
2186
2223
|
|
|
2187
2224
|
this.drmEngine_.setSrcEquals(/* srcEquals= */ true);
|
|
2188
2225
|
await this.drmEngine_.initForPlayback(
|
|
@@ -2316,6 +2353,15 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2316
2353
|
mediaElement.load();
|
|
2317
2354
|
}
|
|
2318
2355
|
|
|
2356
|
+
// In Safari using HLS won't load anything unless you call load()
|
|
2357
|
+
// explicitly, no matter the value of the preload attribute.
|
|
2358
|
+
// Note: this only happens when there are not autoplay.
|
|
2359
|
+
if (mediaElement.preload != 'none' && !mediaElement.autoplay &&
|
|
2360
|
+
shaka.util.MimeUtils.isHlsType(mimeType) &&
|
|
2361
|
+
shaka.util.Platform.safariVersion()) {
|
|
2362
|
+
mediaElement.load();
|
|
2363
|
+
}
|
|
2364
|
+
|
|
2319
2365
|
// Set the load mode last so that we know that all our components are
|
|
2320
2366
|
// initialized.
|
|
2321
2367
|
this.loadMode_ = shaka.Player.LoadMode.SRC_EQUALS;
|
|
@@ -2399,7 +2445,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2399
2445
|
if (isLive && this.config_.streaming.liveSync) {
|
|
2400
2446
|
const onTimeUpdate = () => this.onTimeUpdate_();
|
|
2401
2447
|
this.loadEventManager_.listen(mediaElement, 'timeupdate', onTimeUpdate);
|
|
2402
|
-
}
|
|
2448
|
+
}
|
|
2449
|
+
if (!isLive) {
|
|
2403
2450
|
const onVideoProgress = () => this.onVideoProgress_();
|
|
2404
2451
|
this.loadEventManager_.listen(
|
|
2405
2452
|
mediaElement, 'timeupdate', onVideoProgress);
|
|
@@ -2717,16 +2764,16 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2717
2764
|
* Create the observers for MSE playback. These observers are responsible for
|
|
2718
2765
|
* notifying the app and player of specific events during MSE playback.
|
|
2719
2766
|
*
|
|
2720
|
-
* @param {number}
|
|
2767
|
+
* @param {number} startTime
|
|
2721
2768
|
* @return {!shaka.media.PlayheadObserverManager}
|
|
2722
2769
|
* @private
|
|
2723
2770
|
*/
|
|
2724
|
-
createPlayheadObserversForMSE_(
|
|
2771
|
+
createPlayheadObserversForMSE_(startTime) {
|
|
2725
2772
|
goog.asserts.assert(this.manifest_, 'Must have manifest');
|
|
2726
2773
|
goog.asserts.assert(this.regionTimeline_, 'Must have region timeline');
|
|
2727
2774
|
goog.asserts.assert(this.video_, 'Must have video element');
|
|
2728
2775
|
|
|
2729
|
-
const startsPastZero = this.isLive() ||
|
|
2776
|
+
const startsPastZero = this.isLive() || startTime > 0;
|
|
2730
2777
|
|
|
2731
2778
|
// Create the region observer. This will allow us to notify the app when we
|
|
2732
2779
|
// move in and out of timeline regions.
|
|
@@ -2784,6 +2831,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2784
2831
|
!this.bufferObserver_,
|
|
2785
2832
|
'No buffering observer should exist before initialization.');
|
|
2786
2833
|
|
|
2834
|
+
goog.asserts.assert(
|
|
2835
|
+
!this.bufferPoller_,
|
|
2836
|
+
'No buffer timer should exist before initialization.');
|
|
2837
|
+
|
|
2787
2838
|
// Give dummy values, will be updated below.
|
|
2788
2839
|
this.bufferObserver_ = new shaka.media.BufferingObserver(1, 2);
|
|
2789
2840
|
|
|
@@ -2793,6 +2844,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2793
2844
|
this.updateBufferingSettings_(rebufferingGoal);
|
|
2794
2845
|
this.updateBufferState_();
|
|
2795
2846
|
|
|
2847
|
+
this.bufferPoller_ = new shaka.util.Timer(() => {
|
|
2848
|
+
this.pollBufferState_();
|
|
2849
|
+
}).tickEvery(/* seconds= */ 0.25);
|
|
2796
2850
|
this.loadEventManager_.listen(mediaElement, 'waiting',
|
|
2797
2851
|
(e) => this.pollBufferState_());
|
|
2798
2852
|
this.loadEventManager_.listen(mediaElement, 'stalled',
|
|
@@ -5556,6 +5610,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5556
5610
|
const loaded = this.stats_ && this.bufferObserver_ && this.playhead_;
|
|
5557
5611
|
|
|
5558
5612
|
if (loaded) {
|
|
5613
|
+
this.playRateController_.setBuffering(isBuffering);
|
|
5559
5614
|
if (this.cmcdManager_) {
|
|
5560
5615
|
this.cmcdManager_.setBuffering(isBuffering);
|
|
5561
5616
|
}
|
|
@@ -6151,8 +6206,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
6151
6206
|
shaka.log.debug('switch_');
|
|
6152
6207
|
goog.asserts.assert(this.config_.abr.enabled,
|
|
6153
6208
|
'AbrManager should not call switch while disabled!');
|
|
6154
|
-
|
|
6155
|
-
|
|
6209
|
+
|
|
6210
|
+
if (!this.manifest_) {
|
|
6211
|
+
// It could come from a preload manager operation.
|
|
6212
|
+
return;
|
|
6213
|
+
}
|
|
6156
6214
|
|
|
6157
6215
|
if (!this.streamingEngine_) {
|
|
6158
6216
|
// There's no way to change it.
|
|
@@ -6960,7 +7018,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6960
7018
|
* @export
|
|
6961
7019
|
*/
|
|
6962
7020
|
// eslint-disable-next-line no-useless-concat
|
|
6963
|
-
shaka.Player.version = 'v4.7.
|
|
7021
|
+
shaka.Player.version = 'v4.7.15' + '-uncompiled'; // x-release-please-version
|
|
6964
7022
|
|
|
6965
7023
|
// Initialize the deprecation system using the version string we just set
|
|
6966
7024
|
// on the player.
|
|
@@ -25,10 +25,8 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
25
25
|
* @export
|
|
26
26
|
*/
|
|
27
27
|
static install() {
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
// we should always install polyfills on all Chromecast models.
|
|
31
|
-
// TODO: re-evaluate MediaCapabilities in the future versions of Chromecast.
|
|
28
|
+
// We can enable MediaCapabilities in Android and Fuchsia devices, but not
|
|
29
|
+
// in Linux devices because the implementation is buggy.
|
|
32
30
|
// Since MediaCapabilities implementation is buggy in Apple browsers, we
|
|
33
31
|
// should always install polyfill for Apple browsers.
|
|
34
32
|
// See: https://github.com/shaka-project/shaka-player/issues/3530
|
|
@@ -50,12 +48,16 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
50
48
|
// Since MediaCapabilities implementation is buggy in Hisense browsers, we
|
|
51
49
|
// should always install polyfill for Hisense browsers.
|
|
52
50
|
let canUseNativeMCap = true;
|
|
51
|
+
if (shaka.util.Platform.isChromecast() &&
|
|
52
|
+
!shaka.util.Platform.isAndroidCastDevice() &&
|
|
53
|
+
!shaka.util.Platform.isFuchsiaCastDevice()) {
|
|
54
|
+
canUseNativeMCap = false;
|
|
55
|
+
}
|
|
53
56
|
if (shaka.util.Platform.isApple() ||
|
|
54
57
|
shaka.util.Platform.isPS5() ||
|
|
55
58
|
shaka.util.Platform.isPS4() ||
|
|
56
59
|
shaka.util.Platform.isWebOS() ||
|
|
57
60
|
shaka.util.Platform.isTizen() ||
|
|
58
|
-
shaka.util.Platform.isChromecast() ||
|
|
59
61
|
shaka.util.Platform.isEOS() ||
|
|
60
62
|
shaka.util.Platform.isHisense()) {
|
|
61
63
|
canUseNativeMCap = false;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
goog.provide('shaka.polyfill.PatchedMediaKeysCert');
|
|
8
|
+
|
|
9
|
+
goog.require('shaka.log');
|
|
10
|
+
goog.require('shaka.polyfill');
|
|
11
|
+
goog.require('shaka.util.Platform');
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @summary A polyfill to fix setServerCertificate implementation on
|
|
16
|
+
* older platforms which claim to support modern EME.
|
|
17
|
+
* @export
|
|
18
|
+
*/
|
|
19
|
+
shaka.polyfill.PatchedMediaKeysCert = class {
|
|
20
|
+
/**
|
|
21
|
+
* Installs the polyfill if needed.
|
|
22
|
+
* @export
|
|
23
|
+
*/
|
|
24
|
+
static install() {
|
|
25
|
+
if (!window.MediaKeys) {
|
|
26
|
+
// No MediaKeys available
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
30
|
+
if (MediaKeys.prototype.setServerCertificate &&
|
|
31
|
+
!shaka.polyfill.PatchedMediaKeysCert.hasInvalidImplementation_()) {
|
|
32
|
+
// setServerCertificate is there and userAgent seems to be valid.
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
shaka.log.info('Patching MediaKeys.setServerCertificate');
|
|
37
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
38
|
+
MediaKeys.prototype.setServerCertificate =
|
|
39
|
+
shaka.polyfill.PatchedMediaKeysCert.setServerCertificate_;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @param {!BufferSource} certificate
|
|
44
|
+
* @return {!Promise<boolean>}
|
|
45
|
+
* @private
|
|
46
|
+
*/
|
|
47
|
+
static setServerCertificate_(certificate) {
|
|
48
|
+
shaka.log.debug('PatchedMediaKeysCert.setServerCertificate');
|
|
49
|
+
return Promise.resolve(false);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @return {boolean}
|
|
54
|
+
* @private
|
|
55
|
+
*/
|
|
56
|
+
static hasInvalidImplementation_() {
|
|
57
|
+
return shaka.util.Platform.isTizen3() || shaka.util.Platform.isTizen4() ||
|
|
58
|
+
shaka.util.Platform.isTizen5_0() || shaka.util.Platform.isWebOS3();
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
shaka.polyfill.register(shaka.polyfill.PatchedMediaKeysCert.install);
|
|
@@ -72,7 +72,9 @@ shaka.text.UITextDisplayer = class {
|
|
|
72
72
|
|
|
73
73
|
/** @private {shaka.util.Timer} */
|
|
74
74
|
this.captionsTimer_ = new shaka.util.Timer(() => {
|
|
75
|
-
this.
|
|
75
|
+
if (!this.video_.paused) {
|
|
76
|
+
this.updateCaptions_();
|
|
77
|
+
}
|
|
76
78
|
}).tickEvery(updatePeriod);
|
|
77
79
|
|
|
78
80
|
/**
|
|
@@ -93,6 +95,10 @@ shaka.text.UITextDisplayer = class {
|
|
|
93
95
|
this.updateCaptions_(/* forceUpdate= */ true);
|
|
94
96
|
});
|
|
95
97
|
|
|
98
|
+
this.eventManager_.listen(this.video_, 'seeking', () => {
|
|
99
|
+
this.updateCaptions_(/* forceUpdate= */ true);
|
|
100
|
+
});
|
|
101
|
+
|
|
96
102
|
// From: https://html.spec.whatwg.org/multipage/media.html#dom-video-videowidth
|
|
97
103
|
// Whenever the natural width or natural height of the video changes
|
|
98
104
|
// (including, for example, because the selected video track was changed),
|
|
@@ -339,6 +345,9 @@ shaka.text.UITextDisplayer = class {
|
|
|
339
345
|
const cueRegistry = this.currentCuesMap_.get(cue);
|
|
340
346
|
goog.asserts.assert(cueRegistry, 'cueRegistry should exist.');
|
|
341
347
|
if (cueRegistry.regionElement) {
|
|
348
|
+
if (cueRegistry.regionElement.contains(container)) {
|
|
349
|
+
cueRegistry.regionElement.removeChild(container);
|
|
350
|
+
}
|
|
342
351
|
container.appendChild(cueRegistry.regionElement);
|
|
343
352
|
cueRegistry.regionElement.appendChild(cueRegistry.cueElement);
|
|
344
353
|
} else {
|
|
@@ -21,6 +21,7 @@ goog.require('shaka.util.Id3Utils');
|
|
|
21
21
|
goog.require('shaka.util.ManifestParserUtils');
|
|
22
22
|
goog.require('shaka.util.MimeUtils');
|
|
23
23
|
goog.require('shaka.util.Mp4Generator');
|
|
24
|
+
goog.require('shaka.util.StreamUtils');
|
|
24
25
|
goog.require('shaka.util.TsParser');
|
|
25
26
|
goog.require('shaka.util.Uint8ArrayUtils');
|
|
26
27
|
|
|
@@ -142,13 +143,17 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
142
143
|
convertCodecs(contentType, mimeType) {
|
|
143
144
|
if (this.isTsContainer_(mimeType)) {
|
|
144
145
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
146
|
+
const StreamUtils = shaka.util.StreamUtils;
|
|
145
147
|
// The replace it's necessary because Firefox(the only browser that
|
|
146
148
|
// supports MP3 in MP4) only support the MP3 codec with the mp3 string.
|
|
147
149
|
// MediaSource.isTypeSupported('audio/mp4; codecs="mp4a.40.34"') -> false
|
|
148
150
|
// MediaSource.isTypeSupported('audio/mp4; codecs="mp3"') -> true
|
|
149
151
|
const codecs = shaka.util.MimeUtils.getCodecs(mimeType)
|
|
150
152
|
.replace('mp4a.40.34', 'mp3').split(',')
|
|
151
|
-
.map(
|
|
153
|
+
.map((codecs) => {
|
|
154
|
+
return StreamUtils.getCorrectAudioCodecs(codecs, 'audio/mp4');
|
|
155
|
+
})
|
|
156
|
+
.map(StreamUtils.getCorrectVideoCodecs).join(',');
|
|
152
157
|
if (contentType == ContentType.AUDIO) {
|
|
153
158
|
return `audio/mp4; codecs="${codecs}"`;
|
|
154
159
|
}
|
|
@@ -158,29 +163,6 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
158
163
|
}
|
|
159
164
|
|
|
160
165
|
|
|
161
|
-
/**
|
|
162
|
-
* @param {string} codec
|
|
163
|
-
* @return {string}
|
|
164
|
-
* @private
|
|
165
|
-
*/
|
|
166
|
-
getCorrectVideoCodecs_(codec) {
|
|
167
|
-
if (codec.includes('avc1')) {
|
|
168
|
-
// Convert avc1 codec string from RFC-4281 to RFC-6381 for
|
|
169
|
-
// MediaSource.isTypeSupported
|
|
170
|
-
// Example, convert avc1.66.30 to avc1.42001e (0x42 == 66 and 0x1e == 30)
|
|
171
|
-
const avcdata = codec.split('.');
|
|
172
|
-
if (avcdata.length == 3) {
|
|
173
|
-
let result = avcdata.shift() + '.';
|
|
174
|
-
result += parseInt(avcdata.shift(), 10).toString(16);
|
|
175
|
-
result +=
|
|
176
|
-
('000' + parseInt(avcdata.shift(), 10).toString(16)).slice(-4);
|
|
177
|
-
return result;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
return codec;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
|
|
184
166
|
/**
|
|
185
167
|
* @override
|
|
186
168
|
* @export
|
package/lib/util/object_utils.js
CHANGED
|
@@ -41,8 +41,7 @@ shaka.util.ObjectUtils = class {
|
|
|
41
41
|
|
|
42
42
|
// This covers Uint8Array and friends, even without a TypedArray
|
|
43
43
|
// base-class constructor.
|
|
44
|
-
const isTypedArray =
|
|
45
|
-
val.buffer && val.buffer.constructor == ArrayBuffer;
|
|
44
|
+
const isTypedArray = val.buffer instanceof ArrayBuffer;
|
|
46
45
|
if (isTypedArray) {
|
|
47
46
|
return val;
|
|
48
47
|
}
|