shaka-player 4.10.0 → 4.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/deps.js +9 -9
- package/dist/locales.js +36 -36
- package/dist/shaka-player.compiled.d.ts +2 -2
- package/dist/shaka-player.compiled.debug.d.ts +2 -2
- package/dist/shaka-player.compiled.debug.externs.js +1 -1
- package/dist/shaka-player.compiled.debug.js +140 -139
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +1 -1
- package/dist/shaka-player.compiled.js +1169 -1163
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +2 -2
- package/dist/shaka-player.ui.debug.d.ts +2 -2
- package/dist/shaka-player.ui.debug.externs.js +1 -1
- package/dist/shaka-player.ui.debug.js +167 -165
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +1 -1
- package/dist/shaka-player.ui.js +1396 -1391
- package/dist/shaka-player.ui.map +4 -4
- package/externs/shaka/player.js +7 -1
- package/lib/abr/simple_abr_manager.js +11 -8
- package/lib/hls/hls_parser.js +7 -6
- package/lib/media/drm_engine.js +9 -197
- package/lib/media/presentation_timeline.js +13 -5
- package/lib/player.js +20 -12
- package/lib/polyfill/media_capabilities.js +4 -4
- package/lib/polyfill/patchedmediakeys_apple.js +3 -3
- package/lib/polyfill/patchedmediakeys_webkit.js +3 -3
- package/lib/text/simple_text_displayer.js +3 -0
- package/lib/text/ssa_text_parser.js +22 -7
- package/lib/text/text_utils.js +17 -1
- package/lib/text/ttml_text_parser.js +5 -3
- package/lib/text/ui_text_displayer.js +6 -1
- package/lib/util/config_utils.js +5 -0
- package/lib/util/drm_utils.js +191 -0
- package/lib/util/periods.js +4 -4
- package/lib/util/player_configuration.js +1 -0
- package/lib/util/ts_parser.js +4 -4
- package/package.json +1 -1
- package/ui/locales/fr.json +1 -1
- package/ui/statistics_button.js +10 -3
package/externs/shaka/player.js
CHANGED
|
@@ -1707,7 +1707,8 @@ shaka.extern.AdsConfiguration;
|
|
|
1707
1707
|
* ignoreDevicePixelRatio: boolean,
|
|
1708
1708
|
* clearBufferSwitch: boolean,
|
|
1709
1709
|
* safeMarginSwitch: number,
|
|
1710
|
-
* cacheLoadThreshold: number
|
|
1710
|
+
* cacheLoadThreshold: number,
|
|
1711
|
+
* minTimeToSwitch: number
|
|
1711
1712
|
* }}
|
|
1712
1713
|
*
|
|
1713
1714
|
* @property {boolean} enabled
|
|
@@ -1769,6 +1770,11 @@ shaka.extern.AdsConfiguration;
|
|
|
1769
1770
|
* Indicates the value in milliseconds from which a request is not
|
|
1770
1771
|
* considered cached.
|
|
1771
1772
|
* Defaults to <code>20</code>.
|
|
1773
|
+
* @property {number} minTimeToSwitch
|
|
1774
|
+
* Indicates the minimum time to change quality once the real bandwidth is
|
|
1775
|
+
* available, in seconds. This time is only used on the first load.
|
|
1776
|
+
* Defaults to <code>0</code> seconds except in Apple browsers whose default
|
|
1777
|
+
* value is <code>0.5</code> seconds.
|
|
1772
1778
|
* @exportDoc
|
|
1773
1779
|
*/
|
|
1774
1780
|
shaka.extern.AbrConfiguration;
|
|
@@ -433,14 +433,17 @@ shaka.abr.SimpleAbrManager = class {
|
|
|
433
433
|
return;
|
|
434
434
|
}
|
|
435
435
|
this.startupComplete_ = true;
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
436
|
+
|
|
437
|
+
this.lastTimeChosenMs_ -=
|
|
438
|
+
(this.config_.switchInterval - this.config_.minTimeToSwitch) * 1000;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Check if we've left the switch interval.
|
|
442
|
+
const now = Date.now();
|
|
443
|
+
const delta = now - this.lastTimeChosenMs_;
|
|
444
|
+
if (delta < this.config_.switchInterval * 1000) {
|
|
445
|
+
shaka.log.v2('Still within switch interval...');
|
|
446
|
+
return;
|
|
444
447
|
}
|
|
445
448
|
|
|
446
449
|
const chosenVariant = this.chooseVariant();
|
package/lib/hls/hls_parser.js
CHANGED
|
@@ -16,7 +16,6 @@ goog.require('shaka.hls.PlaylistType');
|
|
|
16
16
|
goog.require('shaka.hls.Tag');
|
|
17
17
|
goog.require('shaka.hls.Utils');
|
|
18
18
|
goog.require('shaka.log');
|
|
19
|
-
goog.require('shaka.media.DrmEngine');
|
|
20
19
|
goog.require('shaka.media.InitSegmentReference');
|
|
21
20
|
goog.require('shaka.media.ManifestParser');
|
|
22
21
|
goog.require('shaka.media.PresentationTimeline');
|
|
@@ -27,6 +26,7 @@ goog.require('shaka.net.DataUriPlugin');
|
|
|
27
26
|
goog.require('shaka.net.NetworkingEngine');
|
|
28
27
|
goog.require('shaka.util.ArrayUtils');
|
|
29
28
|
goog.require('shaka.util.BufferUtils');
|
|
29
|
+
goog.require('shaka.util.DrmUtils');
|
|
30
30
|
goog.require('shaka.util.ContentSteeringManager');
|
|
31
31
|
goog.require('shaka.util.Error');
|
|
32
32
|
goog.require('shaka.util.EventManager');
|
|
@@ -635,9 +635,10 @@ shaka.hls.HlsParser = class {
|
|
|
635
635
|
if (goog.DEBUG) {
|
|
636
636
|
const firstSequenceStartTime =
|
|
637
637
|
mediaSequenceToStartTime.values().next().value;
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
638
|
+
if (firstSequenceStartTime != segment0.startTime) {
|
|
639
|
+
shaka.log.warning(
|
|
640
|
+
'Sequence number map is not ordered as expected!');
|
|
641
|
+
}
|
|
641
642
|
}
|
|
642
643
|
for (const [sequence, start] of mediaSequenceToStartTime) {
|
|
643
644
|
if (start == segment0.startTime) {
|
|
@@ -1936,7 +1937,7 @@ shaka.hls.HlsParser = class {
|
|
|
1936
1937
|
audioInfos, videoInfos, bandwidth, width, height, frameRate, videoRange,
|
|
1937
1938
|
videoLayout, drmInfos, keyIds) {
|
|
1938
1939
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
1939
|
-
const
|
|
1940
|
+
const DrmUtils = shaka.util.DrmUtils;
|
|
1940
1941
|
|
|
1941
1942
|
for (const info of videoInfos) {
|
|
1942
1943
|
this.addVideoAttributes_(
|
|
@@ -1979,7 +1980,7 @@ shaka.hls.HlsParser = class {
|
|
|
1979
1980
|
const variantUriKey = videoStreamUri + ' - ' + audioStreamUri;
|
|
1980
1981
|
|
|
1981
1982
|
if (audioStream && videoStream) {
|
|
1982
|
-
if (!
|
|
1983
|
+
if (!DrmUtils.areDrmCompatible(audioDrmInfos, videoDrmInfos)) {
|
|
1983
1984
|
shaka.log.warning(
|
|
1984
1985
|
'Incompatible DRM info in HLS variant. Skipping.');
|
|
1985
1986
|
continue;
|
package/lib/media/drm_engine.js
CHANGED
|
@@ -18,7 +18,6 @@ goog.require('shaka.util.EventManager');
|
|
|
18
18
|
goog.require('shaka.util.FakeEvent');
|
|
19
19
|
goog.require('shaka.util.IDestroyable');
|
|
20
20
|
goog.require('shaka.util.Iterables');
|
|
21
|
-
goog.require('shaka.util.Lazy');
|
|
22
21
|
goog.require('shaka.util.ManifestParserUtils');
|
|
23
22
|
goog.require('shaka.util.MapUtils');
|
|
24
23
|
goog.require('shaka.util.MimeUtils');
|
|
@@ -736,12 +735,13 @@ shaka.media.DrmEngine = class {
|
|
|
736
735
|
// Note that some init data are extremely large and can't portably be used
|
|
737
736
|
// as keys in a dictionary.
|
|
738
737
|
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
738
|
+
if (this.config_.ignoreDuplicateInitData) {
|
|
739
|
+
const metadatas = this.activeSessions_.values();
|
|
740
|
+
for (const metadata of metadatas) {
|
|
741
|
+
if (shaka.util.BufferUtils.equal(initData, metadata.initData)) {
|
|
742
|
+
shaka.log.debug('Ignoring duplicate init data.');
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
745
|
}
|
|
746
746
|
}
|
|
747
747
|
|
|
@@ -762,13 +762,6 @@ shaka.media.DrmEngine = class {
|
|
|
762
762
|
return this.initialized_;
|
|
763
763
|
}
|
|
764
764
|
|
|
765
|
-
/**
|
|
766
|
-
* @param {?shaka.extern.DrmInfo} drmInfo
|
|
767
|
-
* @return {string} */
|
|
768
|
-
static keySystem(drmInfo) {
|
|
769
|
-
return drmInfo ? drmInfo.keySystem : '';
|
|
770
|
-
}
|
|
771
|
-
|
|
772
765
|
/**
|
|
773
766
|
* Check if DrmEngine (as initialized) will likely be able to support the
|
|
774
767
|
* given content type.
|
|
@@ -1763,30 +1756,13 @@ shaka.media.DrmEngine = class {
|
|
|
1763
1756
|
this.playerInterface_.onKeyStatus(shaka.util.MapUtils.asObject(publicMap));
|
|
1764
1757
|
}
|
|
1765
1758
|
|
|
1766
|
-
/**
|
|
1767
|
-
* Returns true if the browser has recent EME APIs.
|
|
1768
|
-
*
|
|
1769
|
-
* @return {boolean}
|
|
1770
|
-
*/
|
|
1771
|
-
static isBrowserSupported() {
|
|
1772
|
-
const basic =
|
|
1773
|
-
!!window.MediaKeys &&
|
|
1774
|
-
!!window.navigator &&
|
|
1775
|
-
!!window.navigator.requestMediaKeySystemAccess &&
|
|
1776
|
-
!!window.MediaKeySystemAccess &&
|
|
1777
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
1778
|
-
!!window.MediaKeySystemAccess.prototype.getConfiguration;
|
|
1779
|
-
|
|
1780
|
-
return basic;
|
|
1781
|
-
}
|
|
1782
|
-
|
|
1783
1759
|
/**
|
|
1784
1760
|
* Returns a Promise to a map of EME support for well-known key systems.
|
|
1785
1761
|
*
|
|
1786
1762
|
* @return {!Promise.<!Object.<string, ?shaka.extern.DrmSupportType>>}
|
|
1787
1763
|
*/
|
|
1788
1764
|
static async probeSupport() {
|
|
1789
|
-
goog.asserts.assert(shaka.
|
|
1765
|
+
goog.asserts.assert(shaka.util.DrmUtils.isBrowserSupported(),
|
|
1790
1766
|
'Must have basic EME support');
|
|
1791
1767
|
|
|
1792
1768
|
const testKeySystems = [
|
|
@@ -2115,91 +2091,13 @@ shaka.media.DrmEngine = class {
|
|
|
2115
2091
|
}
|
|
2116
2092
|
}
|
|
2117
2093
|
|
|
2118
|
-
const keySystem = shaka.
|
|
2094
|
+
const keySystem = shaka.util.DrmUtils.keySystem(this.currentDrmInfo_);
|
|
2119
2095
|
const drmInfos = this.getVariantDrmInfos_(variant);
|
|
2120
2096
|
|
|
2121
2097
|
return drmInfos.length == 0 ||
|
|
2122
2098
|
drmInfos.some((drmInfo) => drmInfo.keySystem == keySystem);
|
|
2123
2099
|
}
|
|
2124
2100
|
|
|
2125
|
-
/**
|
|
2126
|
-
* Checks if two DrmInfos can be decrypted using the same key system.
|
|
2127
|
-
* Clear content is considered compatible with every key system.
|
|
2128
|
-
*
|
|
2129
|
-
* @param {!Array.<!shaka.extern.DrmInfo>} drms1
|
|
2130
|
-
* @param {!Array.<!shaka.extern.DrmInfo>} drms2
|
|
2131
|
-
* @return {boolean}
|
|
2132
|
-
*/
|
|
2133
|
-
static areDrmCompatible(drms1, drms2) {
|
|
2134
|
-
if (!drms1.length || !drms2.length) {
|
|
2135
|
-
return true;
|
|
2136
|
-
}
|
|
2137
|
-
|
|
2138
|
-
if (drms1 === drms2) {
|
|
2139
|
-
return true;
|
|
2140
|
-
}
|
|
2141
|
-
|
|
2142
|
-
return shaka.media.DrmEngine.getCommonDrmInfos(
|
|
2143
|
-
drms1, drms2).length > 0;
|
|
2144
|
-
}
|
|
2145
|
-
|
|
2146
|
-
/**
|
|
2147
|
-
* Returns an array of drm infos that are present in both input arrays.
|
|
2148
|
-
* If one of the arrays is empty, returns the other one since clear
|
|
2149
|
-
* content is considered compatible with every drm info.
|
|
2150
|
-
*
|
|
2151
|
-
* @param {!Array.<!shaka.extern.DrmInfo>} drms1
|
|
2152
|
-
* @param {!Array.<!shaka.extern.DrmInfo>} drms2
|
|
2153
|
-
* @return {!Array.<!shaka.extern.DrmInfo>}
|
|
2154
|
-
*/
|
|
2155
|
-
static getCommonDrmInfos(drms1, drms2) {
|
|
2156
|
-
if (!drms1.length) {
|
|
2157
|
-
return drms2;
|
|
2158
|
-
}
|
|
2159
|
-
if (!drms2.length) {
|
|
2160
|
-
return drms1;
|
|
2161
|
-
}
|
|
2162
|
-
|
|
2163
|
-
const commonDrms = [];
|
|
2164
|
-
|
|
2165
|
-
for (const drm1 of drms1) {
|
|
2166
|
-
for (const drm2 of drms2) {
|
|
2167
|
-
if (drm1.keySystem == drm2.keySystem) {
|
|
2168
|
-
const initDataMap = new Map();
|
|
2169
|
-
const bothInitDatas = (drm1.initData || [])
|
|
2170
|
-
.concat(drm2.initData || []);
|
|
2171
|
-
for (const d of bothInitDatas) {
|
|
2172
|
-
initDataMap.set(d.keyId, d);
|
|
2173
|
-
}
|
|
2174
|
-
const initData = Array.from(initDataMap.values());
|
|
2175
|
-
|
|
2176
|
-
const keyIds = drm1.keyIds && drm2.keyIds ?
|
|
2177
|
-
new Set([...drm1.keyIds, ...drm2.keyIds]) :
|
|
2178
|
-
drm1.keyIds || drm2.keyIds;
|
|
2179
|
-
const mergedDrm = {
|
|
2180
|
-
keySystem: drm1.keySystem,
|
|
2181
|
-
licenseServerUri: drm1.licenseServerUri || drm2.licenseServerUri,
|
|
2182
|
-
distinctiveIdentifierRequired: drm1.distinctiveIdentifierRequired ||
|
|
2183
|
-
drm2.distinctiveIdentifierRequired,
|
|
2184
|
-
persistentStateRequired: drm1.persistentStateRequired ||
|
|
2185
|
-
drm2.persistentStateRequired,
|
|
2186
|
-
videoRobustness: drm1.videoRobustness || drm2.videoRobustness,
|
|
2187
|
-
audioRobustness: drm1.audioRobustness || drm2.audioRobustness,
|
|
2188
|
-
serverCertificate: drm1.serverCertificate || drm2.serverCertificate,
|
|
2189
|
-
serverCertificateUri: drm1.serverCertificateUri ||
|
|
2190
|
-
drm2.serverCertificateUri,
|
|
2191
|
-
initData,
|
|
2192
|
-
keyIds,
|
|
2193
|
-
};
|
|
2194
|
-
commonDrms.push(mergedDrm);
|
|
2195
|
-
break;
|
|
2196
|
-
}
|
|
2197
|
-
}
|
|
2198
|
-
}
|
|
2199
|
-
|
|
2200
|
-
return commonDrms;
|
|
2201
|
-
}
|
|
2202
|
-
|
|
2203
2101
|
/**
|
|
2204
2102
|
* Concat the audio and video drmInfos in a variant.
|
|
2205
2103
|
* @param {shaka.extern.Variant} variant
|
|
@@ -2717,73 +2615,6 @@ shaka.media.DrmEngine = class {
|
|
|
2717
2615
|
this.newInitData('cenc', combinedData);
|
|
2718
2616
|
return this.allSessionsLoaded_;
|
|
2719
2617
|
}
|
|
2720
|
-
|
|
2721
|
-
/**
|
|
2722
|
-
* A method for generating a key for the MediaKeySystemAccessRequests cache.
|
|
2723
|
-
*
|
|
2724
|
-
* @param {string} videoCodec
|
|
2725
|
-
* @param {string} audioCodec
|
|
2726
|
-
* @param {string} keySystem
|
|
2727
|
-
* @return {string}
|
|
2728
|
-
* @private
|
|
2729
|
-
*/
|
|
2730
|
-
static generateKeySystemCacheKey_(videoCodec, audioCodec, keySystem) {
|
|
2731
|
-
return `${videoCodec}#${audioCodec}#${keySystem}`;
|
|
2732
|
-
}
|
|
2733
|
-
|
|
2734
|
-
/**
|
|
2735
|
-
* Check does MediaKeySystemAccess cache contains something for following
|
|
2736
|
-
* attributes.
|
|
2737
|
-
*
|
|
2738
|
-
* @param {string} videoCodec
|
|
2739
|
-
* @param {string} audioCodec
|
|
2740
|
-
* @param {string} keySystem
|
|
2741
|
-
* @return {boolean}
|
|
2742
|
-
*/
|
|
2743
|
-
static hasMediaKeySystemAccess(videoCodec, audioCodec, keySystem) {
|
|
2744
|
-
const DrmEngine = shaka.media.DrmEngine;
|
|
2745
|
-
const key = DrmEngine.generateKeySystemCacheKey_(
|
|
2746
|
-
videoCodec, audioCodec, keySystem);
|
|
2747
|
-
return DrmEngine.memoizedMediaKeySystemAccessRequests_.has(key);
|
|
2748
|
-
}
|
|
2749
|
-
|
|
2750
|
-
/**
|
|
2751
|
-
* Get MediaKeySystemAccess object for following attributes.
|
|
2752
|
-
*
|
|
2753
|
-
* @param {string} videoCodec
|
|
2754
|
-
* @param {string} audioCodec
|
|
2755
|
-
* @param {string} keySystem
|
|
2756
|
-
* @return {?MediaKeySystemAccess}
|
|
2757
|
-
*/
|
|
2758
|
-
static getMediaKeySystemAccess(videoCodec, audioCodec, keySystem) {
|
|
2759
|
-
const DrmEngine = shaka.media.DrmEngine;
|
|
2760
|
-
const key = DrmEngine.generateKeySystemCacheKey_(
|
|
2761
|
-
videoCodec, audioCodec, keySystem);
|
|
2762
|
-
return DrmEngine.memoizedMediaKeySystemAccessRequests_.get(key) || null;
|
|
2763
|
-
}
|
|
2764
|
-
|
|
2765
|
-
/**
|
|
2766
|
-
* Store MediaKeySystemAccess object associated with specified attributes.
|
|
2767
|
-
*
|
|
2768
|
-
* @param {string} videoCodec
|
|
2769
|
-
* @param {string} audioCodec
|
|
2770
|
-
* @param {string} keySystem
|
|
2771
|
-
* @param {!MediaKeySystemAccess} mksa
|
|
2772
|
-
*/
|
|
2773
|
-
static setMediaKeySystemAccess(videoCodec, audioCodec, keySystem, mksa) {
|
|
2774
|
-
const DrmEngine = shaka.media.DrmEngine;
|
|
2775
|
-
const key = DrmEngine.generateKeySystemCacheKey_(
|
|
2776
|
-
videoCodec, audioCodec, keySystem);
|
|
2777
|
-
return DrmEngine.memoizedMediaKeySystemAccessRequests_.set(key, mksa);
|
|
2778
|
-
}
|
|
2779
|
-
|
|
2780
|
-
/**
|
|
2781
|
-
* Clears underlying cache.
|
|
2782
|
-
*/
|
|
2783
|
-
static clearMediaKeySystemAccessMap() {
|
|
2784
|
-
const DrmEngine = shaka.media.DrmEngine;
|
|
2785
|
-
DrmEngine.memoizedMediaKeySystemAccessRequests_.clear();
|
|
2786
|
-
}
|
|
2787
2618
|
};
|
|
2788
2619
|
|
|
2789
2620
|
|
|
@@ -2868,22 +2699,3 @@ shaka.media.DrmEngine.SESSION_LOAD_TIMEOUT_ = 5;
|
|
|
2868
2699
|
* @type {number}
|
|
2869
2700
|
*/
|
|
2870
2701
|
shaka.media.DrmEngine.KEY_STATUS_BATCH_TIME = 0.5;
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
/**
|
|
2874
|
-
* Contains the suggested "default" key ID used by EME polyfills that do not
|
|
2875
|
-
* have a per-key key status. See w3c/encrypted-media#32.
|
|
2876
|
-
* @type {!shaka.util.Lazy.<!ArrayBuffer>}
|
|
2877
|
-
*/
|
|
2878
|
-
shaka.media.DrmEngine.DUMMY_KEY_ID = new shaka.util.Lazy(
|
|
2879
|
-
() => shaka.util.BufferUtils.toArrayBuffer(new Uint8Array([0])));
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
/**
|
|
2883
|
-
* A cache that stores the MediaKeySystemAccess result of calling
|
|
2884
|
-
* `navigator.requestMediaKeySystemAccess` by a key combination of
|
|
2885
|
-
* video/audio codec and key system string.
|
|
2886
|
-
*
|
|
2887
|
-
* @private {!Map<string, !MediaKeySystemAccess>}
|
|
2888
|
-
*/
|
|
2889
|
-
shaka.media.DrmEngine.memoizedMediaKeySystemAccessRequests_ = new Map();
|
|
@@ -247,12 +247,22 @@ shaka.media.PresentationTimeline = class {
|
|
|
247
247
|
return;
|
|
248
248
|
}
|
|
249
249
|
|
|
250
|
-
|
|
251
|
-
const
|
|
250
|
+
// Date.now() is in milliseconds, from which we compute "now" in seconds.
|
|
251
|
+
const now = (Date.now() + this.clockOffset_) / 1000.0;
|
|
252
|
+
// Exclude time ranges that are in the "future".
|
|
253
|
+
const timelineForStart = timeline.filter((timeRange) =>
|
|
254
|
+
timeRange.start + startOffset < now);
|
|
255
|
+
if (timelineForStart.length == 0) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const firstStartTime = timelineForStart[0].start + startOffset;
|
|
260
|
+
const lastEndTime = timelineForStart[timelineForStart.length - 1].end +
|
|
261
|
+
startOffset;
|
|
252
262
|
|
|
253
263
|
this.notifyMinSegmentStartTime(firstStartTime);
|
|
254
264
|
|
|
255
|
-
this.maxSegmentDuration_ =
|
|
265
|
+
this.maxSegmentDuration_ = timelineForStart.reduce(
|
|
256
266
|
(max, r) => { return Math.max(max, r.end - r.start); },
|
|
257
267
|
this.maxSegmentDuration_);
|
|
258
268
|
|
|
@@ -263,8 +273,6 @@ shaka.media.PresentationTimeline = class {
|
|
|
263
273
|
!this.startTimeLocked_) {
|
|
264
274
|
// Since we have explicit segment end times, calculate a presentation
|
|
265
275
|
// start based on them. This start time accounts for drift.
|
|
266
|
-
// Date.now() is in milliseconds, from which we compute "now" in seconds.
|
|
267
|
-
const now = (Date.now() + this.clockOffset_) / 1000.0;
|
|
268
276
|
this.presentationStartTime_ =
|
|
269
277
|
now - this.maxSegmentEndTime_ - this.maxSegmentDuration_;
|
|
270
278
|
}
|
package/lib/player.js
CHANGED
|
@@ -45,6 +45,7 @@ goog.require('shaka.util.CmcdManager');
|
|
|
45
45
|
goog.require('shaka.util.CmsdManager');
|
|
46
46
|
goog.require('shaka.util.ConfigUtils');
|
|
47
47
|
goog.require('shaka.util.Dom');
|
|
48
|
+
goog.require('shaka.util.DrmUtils');
|
|
48
49
|
goog.require('shaka.util.Error');
|
|
49
50
|
goog.require('shaka.util.EventManager');
|
|
50
51
|
goog.require('shaka.util.FakeEvent');
|
|
@@ -108,8 +109,8 @@ goog.requireType('shaka.media.PresentationTimeline');
|
|
|
108
109
|
* 'downloadfailed'
|
|
109
110
|
* @property {!shaka.extern.Request} request
|
|
110
111
|
* @property {?shaka.util.Error} error
|
|
111
|
-
* @
|
|
112
|
-
* @
|
|
112
|
+
* @property {number} httpResponseCode
|
|
113
|
+
* @property {boolean} aborted
|
|
113
114
|
* @exportDoc
|
|
114
115
|
*/
|
|
115
116
|
|
|
@@ -1072,7 +1073,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1072
1073
|
// DRM support is not strictly necessary, but the APIs at least need to be
|
|
1073
1074
|
// there. Our no-op DRM polyfill should handle that.
|
|
1074
1075
|
// TODO(#1017): Consider making even DrmEngine optional.
|
|
1075
|
-
const drmSupport = shaka.
|
|
1076
|
+
const drmSupport = shaka.util.DrmUtils.isBrowserSupported();
|
|
1076
1077
|
if (!drmSupport) {
|
|
1077
1078
|
return false;
|
|
1078
1079
|
}
|
|
@@ -1469,7 +1470,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1469
1470
|
// each playback.
|
|
1470
1471
|
if (this.config_.streaming.clearDecodingCache) {
|
|
1471
1472
|
shaka.util.StreamUtils.clearDecodingConfigCache();
|
|
1472
|
-
shaka.
|
|
1473
|
+
shaka.util.DrmUtils.clearMediaKeySystemAccessMap();
|
|
1473
1474
|
}
|
|
1474
1475
|
|
|
1475
1476
|
this.manifest_ = null;
|
|
@@ -4330,7 +4331,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4330
4331
|
* @export
|
|
4331
4332
|
*/
|
|
4332
4333
|
keySystem() {
|
|
4333
|
-
return shaka.
|
|
4334
|
+
return shaka.util.DrmUtils.keySystem(this.drmInfo());
|
|
4334
4335
|
}
|
|
4335
4336
|
|
|
4336
4337
|
/**
|
|
@@ -4995,9 +4996,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4995
4996
|
Math.abs((a.video.width || 0) - (b.video.width || 0));
|
|
4996
4997
|
}
|
|
4997
4998
|
};
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
4999
|
+
// Find the variant whose size is closest to the active variant. This
|
|
5000
|
+
// ensures we stay at about the same resolution when just changing the
|
|
5001
|
+
// language/role.
|
|
5001
5002
|
const active = this.streamingEngine_.getCurrentVariant();
|
|
5002
5003
|
const set =
|
|
5003
5004
|
this.currentAdaptationSetCriteria_.create(this.manifest_.variants);
|
|
@@ -5011,6 +5012,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5011
5012
|
bestVariant = curVariant;
|
|
5012
5013
|
}
|
|
5013
5014
|
}
|
|
5015
|
+
if (bestVariant == active) {
|
|
5016
|
+
shaka.log.debug('Audio already selected.');
|
|
5017
|
+
return;
|
|
5018
|
+
}
|
|
5014
5019
|
if (bestVariant) {
|
|
5015
5020
|
const track = shaka.util.StreamUtils.variantToTrack(bestVariant);
|
|
5016
5021
|
this.selectVariantTrack(track, /* clearBuffer= */ true, safeMargin);
|
|
@@ -5475,7 +5480,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5475
5480
|
const element = /** @type {!HTMLVideoElement} */ (this.video_);
|
|
5476
5481
|
|
|
5477
5482
|
const completionRatio = element.currentTime / element.duration;
|
|
5478
|
-
if (!isNaN(completionRatio)) {
|
|
5483
|
+
if (!isNaN(completionRatio) && !this.isLive()) {
|
|
5479
5484
|
this.stats_.setCompletionPercent(Math.round(100 * completionRatio));
|
|
5480
5485
|
}
|
|
5481
5486
|
|
|
@@ -6926,7 +6931,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
6926
6931
|
// Check if we should show text (based on difference between audio and text
|
|
6927
6932
|
// languages).
|
|
6928
6933
|
if (initialTextStream) {
|
|
6929
|
-
if (
|
|
6934
|
+
if (this.shouldInitiallyShowText_(
|
|
6930
6935
|
initialVariant.audio, initialTextStream)) {
|
|
6931
6936
|
this.isTextVisible_ = true;
|
|
6932
6937
|
}
|
|
@@ -6946,7 +6951,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
6946
6951
|
/**
|
|
6947
6952
|
* Check if we should show text on screen automatically.
|
|
6948
6953
|
*
|
|
6949
|
-
* @param {shaka.extern.Stream} audioStream
|
|
6954
|
+
* @param {?shaka.extern.Stream} audioStream
|
|
6950
6955
|
* @param {shaka.extern.Stream} textStream
|
|
6951
6956
|
* @return {boolean}
|
|
6952
6957
|
* @private
|
|
@@ -6977,6 +6982,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
6977
6982
|
}
|
|
6978
6983
|
|
|
6979
6984
|
if (this.config_.autoShowText == AutoShowText.IF_SUBTITLES_MAY_BE_NEEDED) {
|
|
6985
|
+
if (!audioStream) {
|
|
6986
|
+
return false;
|
|
6987
|
+
}
|
|
6980
6988
|
/* The text should automatically be shown if the text is
|
|
6981
6989
|
* language-compatible with the user's text language preference, but not
|
|
6982
6990
|
* compatible with the audio. These are cases where we deduce that
|
|
@@ -7801,7 +7809,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
7801
7809
|
* @export
|
|
7802
7810
|
*/
|
|
7803
7811
|
// eslint-disable-next-line no-useless-concat
|
|
7804
|
-
shaka.Player.version = 'v4.10.
|
|
7812
|
+
shaka.Player.version = 'v4.10.2' + '-uncompiled'; // x-release-please-version
|
|
7805
7813
|
|
|
7806
7814
|
// Initialize the deprecation system using the version string we just set
|
|
7807
7815
|
// on the player.
|
|
@@ -8,8 +8,8 @@ goog.provide('shaka.polyfill.MediaCapabilities');
|
|
|
8
8
|
|
|
9
9
|
goog.require('shaka.log');
|
|
10
10
|
goog.require('shaka.media.Capabilities');
|
|
11
|
-
goog.require('shaka.media.DrmEngine');
|
|
12
11
|
goog.require('shaka.polyfill');
|
|
12
|
+
goog.require('shaka.util.DrmUtils');
|
|
13
13
|
goog.require('shaka.util.Platform');
|
|
14
14
|
|
|
15
15
|
|
|
@@ -284,14 +284,14 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
284
284
|
/** @type {MediaKeySystemAccess} */
|
|
285
285
|
let keySystemAccess = null;
|
|
286
286
|
try {
|
|
287
|
-
if (shaka.
|
|
287
|
+
if (shaka.util.DrmUtils.hasMediaKeySystemAccess(
|
|
288
288
|
videoCodec, audioCodec, keySystem)) {
|
|
289
|
-
keySystemAccess = shaka.
|
|
289
|
+
keySystemAccess = shaka.util.DrmUtils.getMediaKeySystemAccess(
|
|
290
290
|
videoCodec, audioCodec, keySystem);
|
|
291
291
|
} else {
|
|
292
292
|
keySystemAccess = await navigator.requestMediaKeySystemAccess(
|
|
293
293
|
mcapKeySystemConfig.keySystem, [mediaKeySystemConfig]);
|
|
294
|
-
shaka.
|
|
294
|
+
shaka.util.DrmUtils.setMediaKeySystemAccess(
|
|
295
295
|
videoCodec, audioCodec, keySystem, keySystemAccess);
|
|
296
296
|
}
|
|
297
297
|
} catch (e) {
|
|
@@ -8,9 +8,9 @@ goog.provide('shaka.polyfill.PatchedMediaKeysApple');
|
|
|
8
8
|
|
|
9
9
|
goog.require('goog.asserts');
|
|
10
10
|
goog.require('shaka.log');
|
|
11
|
-
goog.require('shaka.media.DrmEngine');
|
|
12
11
|
goog.require('shaka.polyfill');
|
|
13
12
|
goog.require('shaka.util.BufferUtils');
|
|
13
|
+
goog.require('shaka.util.DrmUtils');
|
|
14
14
|
goog.require('shaka.util.EventManager');
|
|
15
15
|
goog.require('shaka.util.FakeEvent');
|
|
16
16
|
goog.require('shaka.util.FakeEventTarget');
|
|
@@ -746,7 +746,7 @@ shaka.polyfill.PatchedMediaKeysApple.MediaKeyStatusMap = class {
|
|
|
746
746
|
/** @override */
|
|
747
747
|
forEach(fn) {
|
|
748
748
|
if (this.status_) {
|
|
749
|
-
fn(this.status_, shaka.
|
|
749
|
+
fn(this.status_, shaka.util.DrmUtils.DUMMY_KEY_ID.value());
|
|
750
750
|
}
|
|
751
751
|
}
|
|
752
752
|
|
|
@@ -760,7 +760,7 @@ shaka.polyfill.PatchedMediaKeysApple.MediaKeyStatusMap = class {
|
|
|
760
760
|
|
|
761
761
|
/** @override */
|
|
762
762
|
has(keyId) {
|
|
763
|
-
const fakeKeyId = shaka.
|
|
763
|
+
const fakeKeyId = shaka.util.DrmUtils.DUMMY_KEY_ID.value();
|
|
764
764
|
if (this.status_ && shaka.util.BufferUtils.equal(keyId, fakeKeyId)) {
|
|
765
765
|
return true;
|
|
766
766
|
}
|
|
@@ -8,9 +8,9 @@ goog.provide('shaka.polyfill.PatchedMediaKeysWebkit');
|
|
|
8
8
|
|
|
9
9
|
goog.require('goog.asserts');
|
|
10
10
|
goog.require('shaka.log');
|
|
11
|
-
goog.require('shaka.media.DrmEngine');
|
|
12
11
|
goog.require('shaka.polyfill');
|
|
13
12
|
goog.require('shaka.util.BufferUtils');
|
|
13
|
+
goog.require('shaka.util.DrmUtils');
|
|
14
14
|
goog.require('shaka.util.EventManager');
|
|
15
15
|
goog.require('shaka.util.FakeEvent');
|
|
16
16
|
goog.require('shaka.util.FakeEventTarget');
|
|
@@ -924,7 +924,7 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeyStatusMap = class {
|
|
|
924
924
|
/** @override */
|
|
925
925
|
forEach(fn) {
|
|
926
926
|
if (this.status_) {
|
|
927
|
-
fn(this.status_, shaka.
|
|
927
|
+
fn(this.status_, shaka.util.DrmUtils.DUMMY_KEY_ID.value());
|
|
928
928
|
}
|
|
929
929
|
}
|
|
930
930
|
|
|
@@ -938,7 +938,7 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeyStatusMap = class {
|
|
|
938
938
|
|
|
939
939
|
/** @override */
|
|
940
940
|
has(keyId) {
|
|
941
|
-
const fakeKeyId = shaka.
|
|
941
|
+
const fakeKeyId = shaka.util.DrmUtils.DUMMY_KEY_ID.value();
|
|
942
942
|
if (this.status_ && shaka.util.BufferUtils.equal(keyId, fakeKeyId)) {
|
|
943
943
|
return true;
|
|
944
944
|
}
|
|
@@ -37,6 +37,9 @@ shaka.text.SimpleTextDisplayer = class {
|
|
|
37
37
|
// If the video element has TextTracks, disable them. If we see one that
|
|
38
38
|
// was created by a previous instance of Shaka Player, reuse it.
|
|
39
39
|
for (const track of Array.from(video.textTracks)) {
|
|
40
|
+
if (track.kind === 'metadata' || track.kind === 'chapters') {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
40
43
|
// NOTE: There is no API available to remove a TextTrack from a video
|
|
41
44
|
// element.
|
|
42
45
|
track.mode = 'disabled';
|
|
@@ -60,24 +60,39 @@ shaka.text.SsaTextParser = class {
|
|
|
60
60
|
events: '',
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
+
let tag = null;
|
|
64
|
+
let lines = null;
|
|
63
65
|
const parts = str.split(/\r?\n\s*\r?\n/);
|
|
64
66
|
for (const part of parts) {
|
|
67
|
+
lines = part;
|
|
65
68
|
// SSA content
|
|
66
69
|
const match = SsaTextParser.ssaContent_.exec(part);
|
|
67
70
|
if (match) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
tag = match[1];
|
|
72
|
+
lines = match[2];
|
|
73
|
+
}
|
|
74
|
+
if (tag == 'V4 Styles' || tag == 'V4+ Styles') {
|
|
75
|
+
section.styles = lines;
|
|
76
|
+
if (section.events) {
|
|
77
|
+
section.styles += '\n' + lines;
|
|
78
|
+
} else {
|
|
71
79
|
section.styles = lines;
|
|
72
|
-
continue;
|
|
73
80
|
}
|
|
74
|
-
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (tag == 'Events') {
|
|
84
|
+
if (section.events) {
|
|
85
|
+
section.events += '\n' + lines;
|
|
86
|
+
} else {
|
|
75
87
|
section.events = lines;
|
|
76
|
-
continue;
|
|
77
88
|
}
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (tag == 'Script Info') {
|
|
92
|
+
continue;
|
|
78
93
|
}
|
|
79
94
|
shaka.log.warning('SsaTextParser parser encountered an unknown part.',
|
|
80
|
-
|
|
95
|
+
lines);
|
|
81
96
|
}
|
|
82
97
|
|
|
83
98
|
// Process styles
|
package/lib/text/text_utils.js
CHANGED
|
@@ -148,7 +148,7 @@ shaka.text.Utils = class {
|
|
|
148
148
|
*/
|
|
149
149
|
static getCuesToFlatten(cues, parentCue) {
|
|
150
150
|
const result = [];
|
|
151
|
-
for (const cue of cues) {
|
|
151
|
+
for (const cue of shaka.text.Utils.removeDuplicates(cues)) {
|
|
152
152
|
if (cue.isContainer) {
|
|
153
153
|
// Recurse to find the actual text payload cues.
|
|
154
154
|
result.push(...shaka.text.Utils.getCuesToFlatten(cue.nestedCues, cue));
|
|
@@ -162,4 +162,20 @@ shaka.text.Utils = class {
|
|
|
162
162
|
}
|
|
163
163
|
return result;
|
|
164
164
|
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @param {!Array.<!shaka.text.Cue>} cues
|
|
168
|
+
* @return {!Array.<!shaka.text.Cue>}
|
|
169
|
+
*/
|
|
170
|
+
static removeDuplicates(cues) {
|
|
171
|
+
const uniqueCues = [];
|
|
172
|
+
for (const cue of cues) {
|
|
173
|
+
const isValid = !uniqueCues.some(
|
|
174
|
+
(existingCue) => shaka.text.Cue.equal(cue, existingCue));
|
|
175
|
+
if (isValid) {
|
|
176
|
+
uniqueCues.push(cue);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return uniqueCues;
|
|
180
|
+
}
|
|
165
181
|
};
|