mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-14 15:56:38 +03:00
perf: Use Map.getOrInsert/getOrInsertComputed native methods (#9546)
Added polyfills for `Map.getOrInsert()` and `Map.getOrInsertComputed()` from the TC39 upsert proposal and refactor the codebase to use them. These methods replace the common "check if key exists, then set default" pattern with a single atomic operation. This improves code readability and eliminates redundant map lookups throughout the player. --------- Co-authored-by: Álvaro Velad Galván <ladvan91@hotmail.com>
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
+../../lib/polyfill/eme_encryption_scheme.js
|
||||
+../../lib/polyfill/encryption_scheme_media_key_system_access.js
|
||||
+../../lib/polyfill/encryption_scheme_utils.js
|
||||
+../../lib/polyfill/map.js
|
||||
+../../lib/polyfill/mcap_encryption_scheme.js
|
||||
+../../lib/polyfill/mediasource.js
|
||||
+../../lib/polyfill/media_capabilities.js
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*! @license
|
||||
* Shaka Player
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Externs for Map getOrInsert/getOrInsertComputed methods
|
||||
*
|
||||
* @externs
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the value for the given key if present; otherwise inserts
|
||||
* the default value, and returns that.
|
||||
* @param {K} key
|
||||
* @param {V} defaultValue
|
||||
* @return {V}
|
||||
* @this {Map<K, V>}
|
||||
* @template K, V
|
||||
*/
|
||||
// eslint-disable-next-line no-extend-native
|
||||
Map.prototype.getOrInsert = function(key, defaultValue) {};
|
||||
|
||||
/**
|
||||
* Returns the value for the given key if present; otherwise calls
|
||||
* the callback with the key, inserts the returned value, and returns that.
|
||||
* @param {K} key
|
||||
* @param {function(K): V} callbackFunction
|
||||
* @return {V}
|
||||
* @this {Map<K, V>}
|
||||
* @template K, V
|
||||
*/
|
||||
// eslint-disable-next-line no-extend-native
|
||||
Map.prototype.getOrInsertComputed = function(key, callbackFunction) {};
|
||||
|
||||
/**
|
||||
* Returns the value for the given key if present; otherwise inserts
|
||||
* the default value, and returns that.
|
||||
* @param {K} key
|
||||
* @param {V} defaultValue
|
||||
* @return {V}
|
||||
* @this {WeakMap<K, V>}
|
||||
* @template K, V
|
||||
*/
|
||||
// eslint-disable-next-line no-extend-native
|
||||
WeakMap.prototype.getOrInsert = function(key, defaultValue) {};
|
||||
|
||||
/**
|
||||
* Returns the value for the given key if present; otherwise calls
|
||||
* the callback with the key, inserts the returned value, and returns that.
|
||||
* @param {K} key
|
||||
* @param {function(K): V} callbackFunction
|
||||
* @return {V}
|
||||
* @this {WeakMap<K, V>}
|
||||
* @template K, V
|
||||
*/
|
||||
// eslint-disable-next-line no-extend-native
|
||||
WeakMap.prototype.getOrInsertComputed = function(key, callbackFunction) {};
|
||||
@@ -258,8 +258,7 @@ shaka.ads.SvtaAdManager = class {
|
||||
let cuepointsChanged = false;
|
||||
for (const tracking of trackings) {
|
||||
const id = JSON.stringify(tracking);
|
||||
if (!this.trackings_.has(id)) {
|
||||
this.trackings_.set(id, tracking);
|
||||
if (this.trackings_.getOrInsert(id, tracking) === tracking) {
|
||||
cuepointsChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,11 +359,9 @@ shaka.cea.CeaDecoder = class {
|
||||
if (serviceNumber != 0) {
|
||||
this.streams_.add('svc'+ serviceNumber);
|
||||
// If the service doesn't already exist, create it.
|
||||
if (!this.serviceNumberToService_.has(serviceNumber)) {
|
||||
const service = new shaka.cea.Cea708Service(serviceNumber);
|
||||
this.serviceNumberToService_.set(serviceNumber, service);
|
||||
}
|
||||
const service = this.serviceNumberToService_.get(serviceNumber);
|
||||
const service = this.serviceNumberToService_.getOrInsertComputed(
|
||||
serviceNumber,
|
||||
(num) => new shaka.cea.Cea708Service(num));
|
||||
|
||||
// Process all control codes.
|
||||
const startPos = dtvccPacket.getPosition();
|
||||
|
||||
@@ -543,13 +543,12 @@ shaka.dash.ContentProtection = class {
|
||||
try {
|
||||
// Try parsing PSSH data.
|
||||
init = psshs.map((pssh) => {
|
||||
if (!this.psshToInitData_.has(pssh)) {
|
||||
const initData = shaka.util.Uint8ArrayUtils.fromBase64(pssh);
|
||||
this.psshToInitData_.set(pssh, initData);
|
||||
}
|
||||
const initData = this.psshToInitData_.getOrInsertComputed(pssh, () => {
|
||||
return shaka.util.Uint8ArrayUtils.fromBase64(pssh);
|
||||
});
|
||||
return {
|
||||
initDataType: 'cenc',
|
||||
initData: this.psshToInitData_.get(pssh),
|
||||
initData,
|
||||
keyId: null,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -2555,11 +2555,9 @@ shaka.dash.DashParser = class {
|
||||
|
||||
if (contextId && context.dynamic && !this.streamMap_.has(contextId)) {
|
||||
const periodId = context.period.id || '';
|
||||
if (!this.indexStreamMap_.has(periodId)) {
|
||||
this.indexStreamMap_.set(periodId, []);
|
||||
}
|
||||
this.streamMap_.set(contextId, stream);
|
||||
this.indexStreamMap_.get(periodId).push(contextId);
|
||||
this.indexStreamMap_.getOrInsertComputed(periodId, () => [])
|
||||
.push(contextId);
|
||||
}
|
||||
|
||||
return stream;
|
||||
|
||||
@@ -1099,10 +1099,8 @@ shaka.drm.DrmEngine = class {
|
||||
// Get all the key systems in the variant that shouldHaveLicenseServer.
|
||||
const drmInfos = this.getVariantDrmInfos_(variant);
|
||||
for (const info of drmInfos) {
|
||||
if (!drmInfosByKeySystem.has(info.keySystem)) {
|
||||
drmInfosByKeySystem.set(info.keySystem, []);
|
||||
}
|
||||
drmInfosByKeySystem.get(info.keySystem).push(info);
|
||||
drmInfosByKeySystem.getOrInsertComputed(info.keySystem, () => [])
|
||||
.push(info);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+56
-70
@@ -1311,9 +1311,7 @@ shaka.hls.HlsParser = class {
|
||||
const value = variableTag.getAttributeValue('VALUE');
|
||||
const queryParam = variableTag.getAttributeValue('QUERYPARAM');
|
||||
if (name && value) {
|
||||
if (!this.globalVariables_.has(name)) {
|
||||
this.globalVariables_.set(name, value);
|
||||
}
|
||||
this.globalVariables_.getOrInsert(name, value);
|
||||
}
|
||||
if (queryParam) {
|
||||
const queryParamValue = queryParams.get(queryParam)[0];
|
||||
@@ -1340,9 +1338,7 @@ shaka.hls.HlsParser = class {
|
||||
const queryParam = variableTag.getAttributeValue('QUERYPARAM');
|
||||
const mediaImport = variableTag.getAttributeValue('IMPORT');
|
||||
if (name && value) {
|
||||
if (!mediaVariables.has(name)) {
|
||||
mediaVariables.set(name, value);
|
||||
}
|
||||
mediaVariables.getOrInsert(name, value);
|
||||
}
|
||||
if (queryParam) {
|
||||
const queryParamValue = queryParams.get(queryParam)[0];
|
||||
@@ -1652,10 +1648,8 @@ shaka.hls.HlsParser = class {
|
||||
} else if ((i + 1) < chapterList.length) {
|
||||
item.endTime = chapterList[i + 1]['start-time'];
|
||||
}
|
||||
if (!chapterByLanguage.has(title.language)) {
|
||||
chapterByLanguage.set(title.language, []);
|
||||
}
|
||||
chapterByLanguage.get(title.language).push(item);
|
||||
chapterByLanguage.getOrInsertComputed(title.language, () => [])
|
||||
.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1801,14 +1795,12 @@ shaka.hls.HlsParser = class {
|
||||
const keyUris = shaka.hls.Utils.constructSegmentUris(
|
||||
getUris(), drmTag.getRequiredAttrValue('URI'), variables);
|
||||
const keyMapKey = keyUris.sort().join('');
|
||||
if (!this.aesKeyMap_.has(keyMapKey)) {
|
||||
this.aesKeyMap_.getOrInsertComputed(keyMapKey, () => {
|
||||
const requestType = shaka.net.NetworkingEngine.RequestType.KEY;
|
||||
const request = shaka.net.NetworkingEngine.makeRequest(
|
||||
keyUris, this.config_.retryParameters);
|
||||
const keyResponse = this.makeNetworkRequest_(request, requestType)
|
||||
.promise;
|
||||
this.aesKeyMap_.set(keyMapKey, keyResponse);
|
||||
}
|
||||
return this.makeNetworkRequest_(request, requestType).promise;
|
||||
});
|
||||
continue;
|
||||
} else if (keyFormat == 'identity') {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
@@ -3581,7 +3573,7 @@ shaka.hls.HlsParser = class {
|
||||
const keyMapKey = keyUris.sort().join('');
|
||||
const aesKeyInfoKey =
|
||||
`${drmTag.toString()}-${firstMediaSequenceNumber}-${keyMapKey}`;
|
||||
if (!this.aesKeyInfoMap_.has(aesKeyInfoKey)) {
|
||||
return this.aesKeyInfoMap_.getOrInsertComputed(aesKeyInfoKey, () => {
|
||||
// Default AES-128
|
||||
const keyInfo = {
|
||||
bitsKey: 128,
|
||||
@@ -3604,15 +3596,13 @@ shaka.hls.HlsParser = class {
|
||||
// Don't download the key object until the segment is parsed, to avoid a
|
||||
// startup delay for long manifests with lots of keys.
|
||||
keyInfo.fetchKey = async () => {
|
||||
if (!this.aesKeyMap_.has(keyMapKey)) {
|
||||
const requestType = shaka.net.NetworkingEngine.RequestType.KEY;
|
||||
const request = shaka.net.NetworkingEngine.makeRequest(
|
||||
keyUris, this.config_.retryParameters);
|
||||
const keyResponse = this.makeNetworkRequest_(request, requestType)
|
||||
.promise;
|
||||
this.aesKeyMap_.set(keyMapKey, keyResponse);
|
||||
}
|
||||
const keyResponse = await this.aesKeyMap_.get(keyMapKey);
|
||||
const keyResponse = await this.aesKeyMap_.getOrInsertComputed(
|
||||
keyMapKey, () => {
|
||||
const requestType = shaka.net.NetworkingEngine.RequestType.KEY;
|
||||
const request = shaka.net.NetworkingEngine.makeRequest(
|
||||
keyUris, this.config_.retryParameters);
|
||||
return this.makeNetworkRequest_(request, requestType).promise;
|
||||
});
|
||||
|
||||
// keyResponse.status is undefined when URI is "data:text/plain;base64,"
|
||||
if (!keyResponse.data ||
|
||||
@@ -3631,9 +3621,8 @@ shaka.hls.HlsParser = class {
|
||||
'raw', keyResponse.data, algorithm, true, ['decrypt']);
|
||||
keyInfo.fetchKey = undefined; // No longer needed.
|
||||
};
|
||||
this.aesKeyInfoMap_.set(aesKeyInfoKey, keyInfo);
|
||||
}
|
||||
return this.aesKeyInfoMap_.get(aesKeyInfoKey);
|
||||
return keyInfo;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3843,30 +3832,31 @@ shaka.hls.HlsParser = class {
|
||||
absoluteInitSegmentUris.toString(),
|
||||
mapTag.getAttributeValue('BYTERANGE', ''),
|
||||
].join('-');
|
||||
if (!this.mapTagToInitSegmentRefMap_.has(mapTagKey)) {
|
||||
/** @type {shaka.extern.aesKey|undefined} */
|
||||
let aesKey = undefined;
|
||||
let byteRangeTag = null;
|
||||
let encrypted = false;
|
||||
for (const tag of tags) {
|
||||
if (tag.name == 'EXT-X-KEY') {
|
||||
const method = tag.getRequiredAttrValue('METHOD');
|
||||
if (this.isAesMethod_(method) && tag.id < mapTag.id) {
|
||||
encrypted = false;
|
||||
aesKey =
|
||||
this.parseAESDrmTag_(tag, playlist, getUris, variables);
|
||||
} else {
|
||||
encrypted = method != 'NONE';
|
||||
return this.mapTagToInitSegmentRefMap_.getOrInsertComputed(
|
||||
mapTagKey, () => {
|
||||
goog.asserts.assert(mapTag, 'mapTag should be non-null');
|
||||
/** @type {shaka.extern.aesKey|undefined} */
|
||||
let aesKey = undefined;
|
||||
/** @type {shaka.hls.Tag|undefined} */
|
||||
let byteRangeTag = undefined;
|
||||
let encrypted = false;
|
||||
for (const tag of tags) {
|
||||
if (tag.name == 'EXT-X-KEY') {
|
||||
const method = tag.getRequiredAttrValue('METHOD');
|
||||
if (this.isAesMethod_(method) && tag.id < mapTag.id) {
|
||||
encrypted = false;
|
||||
aesKey =
|
||||
this.parseAESDrmTag_(tag, playlist, getUris, variables);
|
||||
} else {
|
||||
encrypted = method != 'NONE';
|
||||
}
|
||||
} else if (tag.name == 'EXT-X-BYTERANGE' && tag.id < mapTag.id) {
|
||||
byteRangeTag = tag;
|
||||
}
|
||||
}
|
||||
} else if (tag.name == 'EXT-X-BYTERANGE' && tag.id < mapTag.id) {
|
||||
byteRangeTag = tag;
|
||||
}
|
||||
}
|
||||
const initSegmentRef = this.createInitSegmentReference_(
|
||||
absoluteInitSegmentUris, mapTag, byteRangeTag, aesKey, encrypted);
|
||||
this.mapTagToInitSegmentRefMap_.set(mapTagKey, initSegmentRef);
|
||||
}
|
||||
return this.mapTagToInitSegmentRefMap_.get(mapTagKey);
|
||||
return this.createInitSegmentReference_(
|
||||
absoluteInitSegmentUris, mapTag, byteRangeTag, aesKey, encrypted);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5224,16 +5214,15 @@ shaka.hls.HlsParser = class {
|
||||
const parsedData = shaka.net.DataUriPlugin.parseRaw(uri.split('?')[0]);
|
||||
|
||||
const psshKey = uri.split('?')[0];
|
||||
if (!this.psshToInitData_.has(psshKey)) {
|
||||
const initData = this.psshToInitData_.getOrInsertComputed(psshKey, () => {
|
||||
// The data encoded in the URI is a PSSH box to be used as init data.
|
||||
const initData = shaka.util.BufferUtils.toUint8(parsedData.data);
|
||||
this.psshToInitData_.set(psshKey, initData);
|
||||
}
|
||||
return shaka.util.BufferUtils.toUint8(parsedData.data);
|
||||
});
|
||||
const drmInfo = shaka.util.ManifestParserUtils.createDrmInfo(
|
||||
'com.widevine.alpha',
|
||||
encryptionScheme,
|
||||
/* initData= */ [
|
||||
{initDataType: 'cenc', initData: this.psshToInitData_.get(psshKey)},
|
||||
{initDataType: 'cenc', initData},
|
||||
],
|
||||
/* keySystemUri= */ undefined,
|
||||
/* mediaTypeList= */ parsedData.typeInfoList);
|
||||
@@ -5333,16 +5322,15 @@ shaka.hls.HlsParser = class {
|
||||
const parsedData = shaka.net.DataUriPlugin.parseRaw(uri.split('?')[0]);
|
||||
|
||||
const psshKey = uri.split('?')[0];
|
||||
if (!this.psshToInitData_.has(psshKey)) {
|
||||
const initData = this.psshToInitData_.getOrInsertComputed(psshKey, () => {
|
||||
// The data encoded in the URI is a PSSH box to be used as init data.
|
||||
const initData = shaka.util.BufferUtils.toUint8(parsedData.data);
|
||||
this.psshToInitData_.set(psshKey, initData);
|
||||
}
|
||||
return shaka.util.BufferUtils.toUint8(parsedData.data);
|
||||
});
|
||||
const drmInfo = shaka.util.ManifestParserUtils.createDrmInfo(
|
||||
/* keySystem= */ 'com.huawei.wiseplay',
|
||||
encryptionScheme,
|
||||
/* initData= */ [
|
||||
{initDataType: 'cenc', initData: this.psshToInitData_.get(psshKey)},
|
||||
{initDataType: 'cenc', initData},
|
||||
],
|
||||
/* keySystemUri= */ undefined,
|
||||
/* mediaTypeList= */ parsedData.typeInfoList);
|
||||
@@ -5405,15 +5393,13 @@ shaka.hls.HlsParser = class {
|
||||
keyUris[0].split('data:text/plain;base64,').pop()));
|
||||
} else {
|
||||
const keyMapKey = keyUris.sort().join('');
|
||||
if (!this.identityKeyMap_.has(keyMapKey)) {
|
||||
const requestType = shaka.net.NetworkingEngine.RequestType.KEY;
|
||||
const request = shaka.net.NetworkingEngine.makeRequest(
|
||||
keyUris, this.config_.retryParameters);
|
||||
const keyResponse = this.makeNetworkRequest_(request, requestType)
|
||||
.promise;
|
||||
this.identityKeyMap_.set(keyMapKey, keyResponse);
|
||||
}
|
||||
const keyResponse = await this.identityKeyMap_.get(keyMapKey);
|
||||
const keyResponse = await this.identityKeyMap_.getOrInsertComputed(
|
||||
keyMapKey, () => {
|
||||
const requestType = shaka.net.NetworkingEngine.RequestType.KEY;
|
||||
const request = shaka.net.NetworkingEngine.makeRequest(
|
||||
keyUris, this.config_.retryParameters);
|
||||
return this.makeNetworkRequest_(request, requestType).promise;
|
||||
});
|
||||
key = shaka.util.Uint8ArrayUtils.toHex(keyResponse.data);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,16 +20,10 @@ shaka.media.Capabilities = class {
|
||||
*/
|
||||
static isTypeSupported(type) {
|
||||
const supportMap = shaka.media.Capabilities.MediaSourceTypeSupportMap;
|
||||
if (supportMap.has(type)) {
|
||||
return supportMap.get(type);
|
||||
}
|
||||
const mediaSource = window.ManagedMediaSource || window.MediaSource;
|
||||
if (mediaSource) {
|
||||
const currentSupport = mediaSource.isTypeSupported(type);
|
||||
supportMap.set(type, currentSupport);
|
||||
return currentSupport;
|
||||
}
|
||||
return false;
|
||||
return supportMap.getOrInsertComputed(type, () => {
|
||||
const mediaSource = window.ManagedMediaSource || window.MediaSource;
|
||||
return mediaSource?.isTypeSupported(type) ?? false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -941,10 +941,8 @@ shaka.media.MediaSourceEngine = class {
|
||||
}
|
||||
} else if (!mimeType.includes('/mp4') && !mimeType.includes('/webm') &&
|
||||
shaka.util.TsParser.probe(uint8ArrayData)) {
|
||||
if (!this.tsParsers_.has(contentType)) {
|
||||
this.tsParsers_.set(contentType, new shaka.util.TsParser());
|
||||
}
|
||||
const tsParser = this.tsParsers_.get(contentType);
|
||||
const tsParser = this.tsParsers_.getOrInsertComputed(
|
||||
contentType, () => new shaka.util.TsParser());
|
||||
tsParser.clearData();
|
||||
tsParser.setDiscontinuitySequence(reference.discontinuitySequence);
|
||||
tsParser.parse(uint8ArrayData);
|
||||
|
||||
@@ -685,17 +685,15 @@ shaka.media.StreamingEngine = class {
|
||||
if (mediaState.performingUpdate) {
|
||||
const oldStreamTag =
|
||||
shaka.media.StreamingEngine.logPrefix_(mediaState);
|
||||
if (!this.deferredCloseSegmentIndex_.has(oldStreamTag)) {
|
||||
// The ongoing update is still using the old stream's segment
|
||||
// reference information.
|
||||
// If we close the old stream now, the update will not complete
|
||||
// correctly.
|
||||
// The next onUpdate_() for this content type will resume the
|
||||
// closeSegmentIndex() operation for the old stream once the ongoing
|
||||
// update has finished, then immediately create a new segment index.
|
||||
this.deferredCloseSegmentIndex_.set(
|
||||
oldStreamTag, mediaState.stream.closeSegmentIndex);
|
||||
}
|
||||
// The ongoing update is still using the old stream's segment
|
||||
// reference information.
|
||||
// If we close the old stream now, the update will not complete
|
||||
// correctly.
|
||||
// The next onUpdate_() for this content type will resume the
|
||||
// closeSegmentIndex() operation for the old stream once the ongoing
|
||||
// update has finished, then immediately create a new segment index.
|
||||
this.deferredCloseSegmentIndex_.getOrInsert(
|
||||
oldStreamTag, mediaState.stream.closeSegmentIndex);
|
||||
} else {
|
||||
mediaState.stream.closeSegmentIndex();
|
||||
}
|
||||
@@ -1117,8 +1115,8 @@ shaka.media.StreamingEngine = class {
|
||||
const stream = streamsByType.get(type);
|
||||
if (!this.mediaStates_.has(type)) {
|
||||
const mediaState = this.createMediaState_(stream);
|
||||
if (segmentPrefetchById.has(stream.id)) {
|
||||
const segmentPrefetch = segmentPrefetchById.get(stream.id);
|
||||
const segmentPrefetch = segmentPrefetchById.get(stream.id);
|
||||
if (segmentPrefetch) {
|
||||
segmentPrefetch.replaceFetchDispatcher(
|
||||
(reference, stream, streamDataCallback) => {
|
||||
return this.dispatchFetch_(
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*! @license
|
||||
* Shaka Player
|
||||
* Copyright 2016 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
goog.provide('shaka.polyfill.Map');
|
||||
|
||||
goog.require('shaka.log');
|
||||
goog.require('shaka.polyfill');
|
||||
|
||||
/**
|
||||
* @summary A polyfill to provide Map.prototype.getOrInsert,
|
||||
* Map.prototype.getOrInsertComputed, WeakMap.prototype.getOrInsert,
|
||||
* and WeakMap.prototype.getOrInsertComputed methods.
|
||||
* @see https://github.com/tc39/proposal-upsert
|
||||
* @export
|
||||
*/
|
||||
shaka.polyfill.Map = class {
|
||||
/**
|
||||
* Install the polyfill if needed.
|
||||
* @export
|
||||
*/
|
||||
static install() {
|
||||
shaka.log.debug('Map.install');
|
||||
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
if (!('getOrInsert' in Map.prototype)) {
|
||||
shaka.log.debug('Map: Installing getOrInsert polyfill.');
|
||||
// eslint-disable-next-line no-extend-native, no-restricted-syntax
|
||||
Map.prototype.getOrInsert = shaka.polyfill.Map.mapGetOrInsert_;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
if (!('getOrInsertComputed' in Map.prototype)) {
|
||||
shaka.log.debug('Map: Installing getOrInsertComputed polyfill.');
|
||||
// eslint-disable-next-line no-extend-native, no-restricted-syntax
|
||||
Map.prototype.getOrInsertComputed =
|
||||
shaka.polyfill.Map.mapGetOrInsertComputed_;
|
||||
}
|
||||
|
||||
shaka.log.debug('WeakMap.install');
|
||||
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
if (!('getOrInsert' in WeakMap.prototype)) {
|
||||
shaka.log.debug('WeakMap: Installing getOrInsert polyfill.');
|
||||
// eslint-disable-next-line no-extend-native, no-restricted-syntax
|
||||
WeakMap.prototype.getOrInsert = shaka.polyfill.Map.mapGetOrInsert_;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
if (!('getOrInsertComputed' in WeakMap.prototype)) {
|
||||
shaka.log.debug('WeakMap: Installing getOrInsertComputed polyfill.');
|
||||
// eslint-disable-next-line no-extend-native, no-restricted-syntax
|
||||
WeakMap.prototype.getOrInsertComputed =
|
||||
shaka.polyfill.Map.mapGetOrInsertComputed_;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value for the given key if present; otherwise inserts
|
||||
* the default value, and returns that.
|
||||
* @param {K} key
|
||||
* @param {V} defaultValue
|
||||
* @return {V}
|
||||
* @this {Map<K, V>|WeakMap<K, V>}
|
||||
* @template K, V
|
||||
* @private
|
||||
*/
|
||||
static mapGetOrInsert_(key, defaultValue) {
|
||||
if (!this.has(key)) {
|
||||
this.set(key, defaultValue);
|
||||
}
|
||||
return this.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value for the given key if present; otherwise calls
|
||||
* the callback with the key, inserts the returned value, and returns that.
|
||||
* @param {K} key
|
||||
* @param {function(K): V} callbackFunction
|
||||
* @return {V}
|
||||
* @this {Map<K, V>|WeakMap<K, V>}
|
||||
* @template K, V
|
||||
* @private
|
||||
*/
|
||||
static mapGetOrInsertComputed_(key, callbackFunction) {
|
||||
if (!this.has(key)) {
|
||||
this.set(key, callbackFunction(key));
|
||||
}
|
||||
return this.get(key);
|
||||
}
|
||||
};
|
||||
|
||||
shaka.polyfill.register(shaka.polyfill.Map.install);
|
||||
+21
-16
@@ -473,23 +473,28 @@ shaka.text.SpeechToText = class {
|
||||
if (!mediaElement) {
|
||||
return null;
|
||||
}
|
||||
if (!shaka.text.SpeechToText.audioObjectMap_.has(mediaElement)) {
|
||||
const AudioContext = window.AudioContext || window.webkitAudioContext;
|
||||
const audioContext = new AudioContext();
|
||||
const sourceNode = audioContext.createMediaElementSource(mediaElement);
|
||||
const destinationNode = audioContext.createMediaStreamDestination();
|
||||
sourceNode.connect(destinationNode);
|
||||
sourceNode.connect(audioContext.destination);
|
||||
const audioTrack = destinationNode.stream.getAudioTracks()[0];
|
||||
shaka.text.SpeechToText.audioObjectMap_.set(mediaElement, {
|
||||
audioContext,
|
||||
sourceNode,
|
||||
destinationNode,
|
||||
audioTrack,
|
||||
});
|
||||
}
|
||||
const audioObject =
|
||||
shaka.text.SpeechToText.audioObjectMap_.get(mediaElement);
|
||||
shaka.text.SpeechToText.audioObjectMap_.getOrInsertComputed(
|
||||
mediaElement,
|
||||
() => {
|
||||
const AudioContext =
|
||||
window.AudioContext || window.webkitAudioContext;
|
||||
const audioContext = new AudioContext();
|
||||
goog.asserts.assert(mediaElement, 'MediaElement should be null');
|
||||
const sourceNode =
|
||||
audioContext.createMediaElementSource(mediaElement);
|
||||
const destinationNode =
|
||||
audioContext.createMediaStreamDestination();
|
||||
sourceNode.connect(destinationNode);
|
||||
sourceNode.connect(audioContext.destination);
|
||||
const audioTrack = destinationNode.stream.getAudioTracks()[0];
|
||||
return {
|
||||
audioContext,
|
||||
sourceNode,
|
||||
destinationNode,
|
||||
audioTrack,
|
||||
};
|
||||
});
|
||||
return audioObject.audioTrack;
|
||||
}
|
||||
|
||||
|
||||
@@ -392,9 +392,7 @@ shaka.text.TextEngine = class {
|
||||
for (const caption of closedCaptions) {
|
||||
const id = caption.stream;
|
||||
const cue = caption.cue;
|
||||
if (!captionsMap.has(id)) {
|
||||
captionsMap.set(id, []);
|
||||
}
|
||||
captionsMap.getOrInsert(id, []);
|
||||
|
||||
// Adjust CEA captions with respect to the timestamp offset of the video
|
||||
// stream in which they were embedded.
|
||||
@@ -414,11 +412,10 @@ shaka.text.TextEngine = class {
|
||||
}
|
||||
|
||||
for (const id of captionsMap.keys()) {
|
||||
if (!this.closedCaptionsMap_.has(id)) {
|
||||
this.closedCaptionsMap_.set(id, []);
|
||||
}
|
||||
const closedCaptions = this.closedCaptionsMap_.getOrInsertComputed(
|
||||
id, () => []);
|
||||
for (const cue of captionsMap.get(id)) {
|
||||
this.closedCaptionsMap_.get(id).push(cue);
|
||||
closedCaptions.push(cue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -207,14 +207,9 @@ shaka.transmuxer.AacTransmuxer = class {
|
||||
stream: stream,
|
||||
};
|
||||
const mp4Generator = new shaka.util.Mp4Generator([streamInfo]);
|
||||
let initSegment;
|
||||
const initSegmentKey = stream.id + '_' + reference.discontinuitySequence;
|
||||
if (!this.initSegments.has(initSegmentKey)) {
|
||||
initSegment = mp4Generator.initSegment();
|
||||
this.initSegments.set(initSegmentKey, initSegment);
|
||||
} else {
|
||||
initSegment = this.initSegments.get(initSegmentKey);
|
||||
}
|
||||
const initSegment = this.initSegments.getOrInsertComputed(
|
||||
initSegmentKey, () => mp4Generator.initSegment());
|
||||
const appendInitSegment = this.lastInitSegment_ !== initSegment;
|
||||
const segmentData = mp4Generator.segmentData();
|
||||
this.lastInitSegment_ = initSegment;
|
||||
|
||||
@@ -201,14 +201,9 @@ shaka.transmuxer.Ac3Transmuxer = class {
|
||||
stream: stream,
|
||||
};
|
||||
const mp4Generator = new shaka.util.Mp4Generator([streamInfo]);
|
||||
let initSegment;
|
||||
const initSegmentKey = stream.id + '_' + reference.discontinuitySequence;
|
||||
if (!this.initSegments.has(initSegmentKey)) {
|
||||
initSegment = mp4Generator.initSegment();
|
||||
this.initSegments.set(initSegmentKey, initSegment);
|
||||
} else {
|
||||
initSegment = this.initSegments.get(initSegmentKey);
|
||||
}
|
||||
const initSegment = this.initSegments.getOrInsertComputed(
|
||||
initSegmentKey, () => mp4Generator.initSegment());
|
||||
const appendInitSegment = this.lastInitSegment_ !== initSegment;
|
||||
const segmentData = mp4Generator.segmentData();
|
||||
this.lastInitSegment_ = initSegment;
|
||||
|
||||
@@ -195,14 +195,9 @@ shaka.transmuxer.Ec3Transmuxer = class {
|
||||
stream: stream,
|
||||
};
|
||||
const mp4Generator = new shaka.util.Mp4Generator([streamInfo]);
|
||||
let initSegment;
|
||||
const initSegmentKey = stream.id + '_' + reference.discontinuitySequence;
|
||||
if (!this.initSegments.has(initSegmentKey)) {
|
||||
initSegment = mp4Generator.initSegment();
|
||||
this.initSegments.set(initSegmentKey, initSegment);
|
||||
} else {
|
||||
initSegment = this.initSegments.get(initSegmentKey);
|
||||
}
|
||||
const initSegment = this.initSegments.getOrInsertComputed(
|
||||
initSegmentKey, () => mp4Generator.initSegment());
|
||||
const appendInitSegment = this.lastInitSegment_ !== initSegment;
|
||||
const segmentData = mp4Generator.segmentData();
|
||||
this.lastInitSegment_ = initSegment;
|
||||
|
||||
@@ -188,14 +188,9 @@ shaka.transmuxer.Mp3Transmuxer = class {
|
||||
stream: stream,
|
||||
};
|
||||
const mp4Generator = new shaka.util.Mp4Generator([streamInfo]);
|
||||
let initSegment;
|
||||
const initSegmentKey = stream.id + '_' + reference.discontinuitySequence;
|
||||
if (!this.initSegments.has(initSegmentKey)) {
|
||||
initSegment = mp4Generator.initSegment();
|
||||
this.initSegments.set(initSegmentKey, initSegment);
|
||||
} else {
|
||||
initSegment = this.initSegments.get(initSegmentKey);
|
||||
}
|
||||
const initSegment = this.initSegments.getOrInsertComputed(
|
||||
initSegmentKey, () => mp4Generator.initSegment());
|
||||
const appendInitSegment = this.lastInitSegment_ !== initSegment;
|
||||
const segmentData = mp4Generator.segmentData();
|
||||
this.lastInitSegment_ = initSegment;
|
||||
|
||||
@@ -288,14 +288,9 @@ shaka.transmuxer.TsTransmuxer = class {
|
||||
}
|
||||
|
||||
const mp4Generator = new shaka.util.Mp4Generator(streamInfos);
|
||||
let initSegment;
|
||||
const initSegmentKey = stream.id + '_' + reference.discontinuitySequence;
|
||||
if (!this.initSegments.has(initSegmentKey)) {
|
||||
initSegment = mp4Generator.initSegment();
|
||||
this.initSegments.set(initSegmentKey, initSegment);
|
||||
} else {
|
||||
initSegment = this.initSegments.get(initSegmentKey);
|
||||
}
|
||||
const initSegment = this.initSegments.getOrInsertComputed(
|
||||
initSegmentKey, () => mp4Generator.initSegment());
|
||||
const appendInitSegment = this.lastInitSegment_ !== initSegment;
|
||||
const segmentData = mp4Generator.segmentData();
|
||||
this.lastInitSegment_ = initSegment;
|
||||
|
||||
@@ -24,11 +24,7 @@ shaka.util.MultiMap = class {
|
||||
* @param {T} value
|
||||
*/
|
||||
push(key, value) {
|
||||
if (this.map_.has(key)) {
|
||||
this.map_.get(key).push(value);
|
||||
} else {
|
||||
this.map_.set(key, [value]);
|
||||
}
|
||||
this.map_.getOrInsertComputed(key, () => []).push(value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+2
-5
@@ -1947,11 +1947,8 @@ shaka.util.PeriodCombiner = class {
|
||||
* @private
|
||||
*/
|
||||
static getCodec_(codecs) {
|
||||
if (!shaka.util.PeriodCombiner.memoizedCodecs.has(codecs)) {
|
||||
const normalizedCodec = shaka.util.MimeUtils.getNormalizedCodec(codecs);
|
||||
shaka.util.PeriodCombiner.memoizedCodecs.set(codecs, normalizedCodec);
|
||||
}
|
||||
return shaka.util.PeriodCombiner.memoizedCodecs.get(codecs);
|
||||
return shaka.util.PeriodCombiner.memoizedCodecs.getOrInsertComputed(
|
||||
codecs, () => shaka.util.MimeUtils.getNormalizedCodec(codecs));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -46,6 +46,7 @@ goog.require('shaka.offline.indexeddb.StorageMechanism');
|
||||
goog.require('shaka.polyfill.Aria');
|
||||
goog.require('shaka.polyfill.EmeEncryptionScheme');
|
||||
goog.require('shaka.polyfill.Fullscreen');
|
||||
goog.require('shaka.polyfill.Map');
|
||||
goog.require('shaka.polyfill.MCapEncryptionScheme');
|
||||
goog.require('shaka.polyfill.MediaSource');
|
||||
goog.require('shaka.polyfill.MediaCapabilities');
|
||||
|
||||
@@ -80,10 +80,7 @@ shaka.ui.LanguageUtils = class {
|
||||
if (!track.codecs) {
|
||||
continue;
|
||||
}
|
||||
if (!codecsByLanguage.has(track.language)) {
|
||||
codecsByLanguage.set(track.language, new Set());
|
||||
}
|
||||
codecsByLanguage.get(track.language).add(
|
||||
codecsByLanguage.getOrInsertComputed(track.language, () => new Set()).add(
|
||||
shaka.util.MimeUtils.getNormalizedCodec(track.codecs));
|
||||
}
|
||||
const hasDifferentAudioCodecs = (language) =>
|
||||
|
||||
+1
-2
@@ -155,7 +155,7 @@ shaka.ui.Localization = class extends shaka.util.FakeEventTarget {
|
||||
|
||||
// Make sure we have an entry for the locale because we are about to
|
||||
// write to it.
|
||||
const table = this.localizations_.get(locale) || new Map();
|
||||
const table = this.localizations_.getOrInsert(locale, new Map());
|
||||
localizations.forEach((value, id) => {
|
||||
// Set the value if we don't have an old value or if we are to replace
|
||||
// the old value with the new value.
|
||||
@@ -163,7 +163,6 @@ shaka.ui.Localization = class extends shaka.util.FakeEventTarget {
|
||||
table.set(id, value);
|
||||
}
|
||||
});
|
||||
this.localizations_.set(locale, table);
|
||||
|
||||
// The data we use to make our map may have changed, update the map we pull
|
||||
// data from.
|
||||
|
||||
Reference in New Issue
Block a user