shaka-player 4.8.8 → 4.9.0
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/README.md +5 -0
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/deps.js +5 -5
- package/dist/locales.js +33 -33
- package/dist/shaka-player.compiled.d.ts +39 -17
- package/dist/shaka-player.compiled.debug.d.ts +39 -17
- package/dist/shaka-player.compiled.debug.externs.js +32 -11
- package/dist/shaka-player.compiled.debug.js +574 -516
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +32 -11
- package/dist/shaka-player.compiled.js +1270 -1236
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +39 -17
- package/dist/shaka-player.ui.debug.d.ts +39 -17
- package/dist/shaka-player.ui.debug.externs.js +43 -22
- package/dist/shaka-player.ui.debug.js +601 -543
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +43 -22
- package/dist/shaka-player.ui.js +1483 -1448
- package/dist/shaka-player.ui.map +4 -4
- package/externs/shaka/manifest.js +11 -1
- package/externs/shaka/offline.js +3 -0
- package/externs/shaka/player.js +105 -12
- package/externs/tizen.js +1 -1
- package/lib/abr/simple_abr_manager.js +5 -0
- package/lib/ads/media_tailor_ad.js +11 -0
- package/lib/ads/media_tailor_ad_manager.js +37 -3
- package/lib/cea/cea608_data_channel.js +9 -0
- package/lib/cea/cea_decoder.js +6 -2
- package/lib/dash/dash_parser.js +655 -46
- package/lib/dash/mpd_utils.js +7 -8
- package/lib/dash/segment_template.js +65 -10
- package/lib/hls/hls_parser.js +92 -34
- package/lib/media/drm_engine.js +274 -40
- package/lib/media/manifest_filterer.js +10 -14
- package/lib/media/preload_manager.js +3 -10
- package/lib/media/segment_utils.js +14 -3
- package/lib/mss/mss_parser.js +2 -0
- package/lib/net/http_plugin_utils.js +2 -1
- package/lib/net/networking_engine.js +27 -0
- package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
- package/lib/offline/manifest_converter.js +2 -0
- package/lib/offline/storage.js +1 -0
- package/lib/player.js +221 -14
- package/lib/polyfill/media_capabilities.js +10 -35
- package/lib/util/config_utils.js +74 -6
- package/lib/util/error.js +7 -0
- package/lib/util/mp4_box_parsers.js +23 -2
- package/lib/util/periods.js +51 -28
- package/lib/util/platform.js +3 -1
- package/lib/util/player_configuration.js +20 -8
- package/lib/util/stream_utils.js +62 -30
- package/lib/util/tXml.js +74 -6
- package/package.json +2 -2
- package/support.html +1 -0
- package/ui/controls.js +4 -0
- package/ui/less/ad_controls.less +2 -1
- package/ui/resolution_selection.js +12 -3
package/lib/media/drm_engine.js
CHANGED
|
@@ -21,6 +21,7 @@ goog.require('shaka.util.Lazy');
|
|
|
21
21
|
goog.require('shaka.util.ManifestParserUtils');
|
|
22
22
|
goog.require('shaka.util.MapUtils');
|
|
23
23
|
goog.require('shaka.util.MimeUtils');
|
|
24
|
+
goog.require('shaka.util.ObjectUtils');
|
|
24
25
|
goog.require('shaka.util.Platform');
|
|
25
26
|
goog.require('shaka.util.Pssh');
|
|
26
27
|
goog.require('shaka.util.PublicPromise');
|
|
@@ -1492,6 +1493,13 @@ shaka.media.DrmEngine = class {
|
|
|
1492
1493
|
request.initData = metadata.initData;
|
|
1493
1494
|
request.initDataType = metadata.initDataType;
|
|
1494
1495
|
}
|
|
1496
|
+
if (advancedConfig && advancedConfig.headers) {
|
|
1497
|
+
// Add these to the existing headers. Do not clobber them!
|
|
1498
|
+
// For PlayReady, there will already be headers in the request.
|
|
1499
|
+
for (const header in advancedConfig.headers) {
|
|
1500
|
+
request.headers[header] = advancedConfig.headers[header];
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1495
1503
|
// NOTE: allowCrossSiteCredentials can be set in a request filter.
|
|
1496
1504
|
|
|
1497
1505
|
if (shaka.media.DrmEngine.isPlayReadyKeySystem(
|
|
@@ -1801,33 +1809,200 @@ shaka.media.DrmEngine = class {
|
|
|
1801
1809
|
'com.widevine.alpha',
|
|
1802
1810
|
'com.microsoft.playready',
|
|
1803
1811
|
'com.microsoft.playready.recommendation',
|
|
1812
|
+
'com.chromecast.playready',
|
|
1804
1813
|
'com.apple.fps.1_0',
|
|
1805
1814
|
'com.apple.fps',
|
|
1806
1815
|
];
|
|
1807
1816
|
|
|
1817
|
+
const widevineRobustness = [
|
|
1818
|
+
'SW_SECURE_CRYPTO',
|
|
1819
|
+
'SW_SECURE_DECODE',
|
|
1820
|
+
'HW_SECURE_CRYPTO',
|
|
1821
|
+
'HW_SECURE_DECODE',
|
|
1822
|
+
'HW_SECURE_ALL',
|
|
1823
|
+
];
|
|
1824
|
+
|
|
1825
|
+
const playreadyRobustness = [
|
|
1826
|
+
'150',
|
|
1827
|
+
'2000',
|
|
1828
|
+
'3000',
|
|
1829
|
+
];
|
|
1830
|
+
|
|
1831
|
+
const testRobustness = {
|
|
1832
|
+
'com.widevine.alpha': widevineRobustness,
|
|
1833
|
+
'com.microsoft.playready': playreadyRobustness,
|
|
1834
|
+
'com.microsoft.playready.recommendation': playreadyRobustness,
|
|
1835
|
+
'com.chromecast.playready': playreadyRobustness,
|
|
1836
|
+
};
|
|
1837
|
+
|
|
1808
1838
|
const basicVideoCapabilities = [
|
|
1809
1839
|
{contentType: 'video/mp4; codecs="avc1.42E01E"'},
|
|
1810
1840
|
{contentType: 'video/webm; codecs="vp8"'},
|
|
1811
1841
|
];
|
|
1812
1842
|
|
|
1813
|
-
const
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1843
|
+
const basicAudioCapabilities = [
|
|
1844
|
+
{contentType: 'audio/mp4; codecs="mp4a.40.2"'},
|
|
1845
|
+
{contentType: 'audio/webm; codecs="opus"'},
|
|
1846
|
+
];
|
|
1847
|
+
|
|
1848
|
+
const basicConfigTemplate = {
|
|
1818
1849
|
videoCapabilities: basicVideoCapabilities,
|
|
1819
|
-
|
|
1820
|
-
|
|
1850
|
+
audioCapabilities: basicAudioCapabilities,
|
|
1851
|
+
initDataTypes: ['cenc', 'sinf', 'skd', 'keyids'],
|
|
1821
1852
|
};
|
|
1822
1853
|
|
|
1823
|
-
|
|
1824
|
-
|
|
1854
|
+
const testEncryptionSchemes = [
|
|
1855
|
+
null,
|
|
1856
|
+
'cenc',
|
|
1857
|
+
'cbcs',
|
|
1858
|
+
'cbcs-1-9',
|
|
1859
|
+
];
|
|
1825
1860
|
|
|
1826
1861
|
/** @type {!Map.<string, ?shaka.extern.DrmSupportType>} */
|
|
1827
1862
|
const support = new Map();
|
|
1828
1863
|
|
|
1829
|
-
|
|
1864
|
+
/**
|
|
1865
|
+
* @param {string} keySystem
|
|
1866
|
+
* @param {MediaKeySystemAccess} access
|
|
1867
|
+
* @return {!Promise}
|
|
1868
|
+
*/
|
|
1869
|
+
const processMediaKeySystemAccess = async (keySystem, access) => {
|
|
1870
|
+
try {
|
|
1871
|
+
await access.createMediaKeys();
|
|
1872
|
+
} catch (error) {
|
|
1873
|
+
// In some cases, we can get a successful access object but fail to
|
|
1874
|
+
// create a MediaKeys instance. When this happens, don't update the
|
|
1875
|
+
// support structure. If a previous test succeeded, we won't overwrite
|
|
1876
|
+
// any of the results.
|
|
1877
|
+
return;
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
// If sessionTypes is missing, assume no support for persistent-license.
|
|
1881
|
+
const sessionTypes = access.getConfiguration().sessionTypes;
|
|
1882
|
+
let persistentState = sessionTypes ?
|
|
1883
|
+
sessionTypes.includes('persistent-license') : false;
|
|
1884
|
+
|
|
1885
|
+
// Tizen 3.0 doesn't support persistent licenses, but reports that it
|
|
1886
|
+
// does. It doesn't fail until you call update() with a license
|
|
1887
|
+
// response, which is way too late.
|
|
1888
|
+
// This is a work-around for #894.
|
|
1889
|
+
if (shaka.util.Platform.isTizen3()) {
|
|
1890
|
+
persistentState = false;
|
|
1891
|
+
}
|
|
1892
|
+
|
|
1893
|
+
const videoCapabilities = access.getConfiguration().videoCapabilities;
|
|
1894
|
+
const audioCapabilities = access.getConfiguration().audioCapabilities;
|
|
1895
|
+
|
|
1896
|
+
let supportValue = {
|
|
1897
|
+
persistentState,
|
|
1898
|
+
encryptionSchemes: [],
|
|
1899
|
+
videoRobustnessLevels: [],
|
|
1900
|
+
audioRobustnessLevels: [],
|
|
1901
|
+
};
|
|
1902
|
+
if (support.has(keySystem) && support.get(keySystem)) {
|
|
1903
|
+
// Update the existing non-null value.
|
|
1904
|
+
supportValue = support.get(keySystem);
|
|
1905
|
+
} else {
|
|
1906
|
+
// Set a new one.
|
|
1907
|
+
support.set(keySystem, supportValue);
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
// If the returned config doesn't mention encryptionScheme, the field
|
|
1911
|
+
// is not supported. If installed, our polyfills should make sure this
|
|
1912
|
+
// doesn't happen.
|
|
1913
|
+
const returnedScheme = videoCapabilities[0].encryptionScheme;
|
|
1914
|
+
if (returnedScheme &&
|
|
1915
|
+
!supportValue.encryptionSchemes.includes(returnedScheme)) {
|
|
1916
|
+
supportValue.encryptionSchemes.push(returnedScheme);
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
const videoRobustness = videoCapabilities[0].robustness;
|
|
1920
|
+
if (videoRobustness &&
|
|
1921
|
+
!supportValue.videoRobustnessLevels.includes(videoRobustness)) {
|
|
1922
|
+
supportValue.videoRobustnessLevels.push(videoRobustness);
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
const audioRobustness = audioCapabilities[0].robustness;
|
|
1926
|
+
if (audioRobustness &&
|
|
1927
|
+
!supportValue.audioRobustnessLevels.includes(audioRobustness)) {
|
|
1928
|
+
supportValue.audioRobustnessLevels.push(audioRobustness);
|
|
1929
|
+
}
|
|
1930
|
+
};
|
|
1931
|
+
|
|
1932
|
+
const testSystemEme = async (keySystem, encryptionScheme,
|
|
1933
|
+
videoRobustness, audioRobustness) => {
|
|
1934
|
+
try {
|
|
1935
|
+
const basicConfig =
|
|
1936
|
+
shaka.util.ObjectUtils.cloneObject(basicConfigTemplate);
|
|
1937
|
+
for (const cap of basicConfig.videoCapabilities) {
|
|
1938
|
+
cap.encryptionScheme = encryptionScheme;
|
|
1939
|
+
cap.robustness = videoRobustness;
|
|
1940
|
+
}
|
|
1941
|
+
for (const cap of basicConfig.audioCapabilities) {
|
|
1942
|
+
cap.encryptionScheme = encryptionScheme;
|
|
1943
|
+
cap.robustness = audioRobustness;
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
const offlineConfig = shaka.util.ObjectUtils.cloneObject(basicConfig);
|
|
1947
|
+
offlineConfig.persistentState = 'required';
|
|
1948
|
+
offlineConfig.sessionTypes = ['persistent-license'];
|
|
1949
|
+
|
|
1950
|
+
const configs = [offlineConfig, basicConfig];
|
|
1951
|
+
|
|
1952
|
+
const access = await navigator.requestMediaKeySystemAccess(
|
|
1953
|
+
keySystem, configs);
|
|
1954
|
+
await processMediaKeySystemAccess(keySystem, access);
|
|
1955
|
+
} catch (error) {} // Ignore errors.
|
|
1956
|
+
};
|
|
1957
|
+
|
|
1958
|
+
const testSystemMcap = async (keySystem, encryptionScheme,
|
|
1959
|
+
videoRobustness, audioRobustness) => {
|
|
1830
1960
|
try {
|
|
1961
|
+
const decodingConfig = {
|
|
1962
|
+
type: 'media-source',
|
|
1963
|
+
video: {
|
|
1964
|
+
contentType: basicVideoCapabilities[0].contentType,
|
|
1965
|
+
width: 640,
|
|
1966
|
+
height: 480,
|
|
1967
|
+
bitrate: 1,
|
|
1968
|
+
framerate: 1,
|
|
1969
|
+
},
|
|
1970
|
+
audio: {
|
|
1971
|
+
contentType: basicAudioCapabilities[0].contentType,
|
|
1972
|
+
channels: 2,
|
|
1973
|
+
bitrate: 1,
|
|
1974
|
+
samplerate: 1,
|
|
1975
|
+
},
|
|
1976
|
+
keySystemConfiguration: {
|
|
1977
|
+
keySystem,
|
|
1978
|
+
video: {
|
|
1979
|
+
encryptionScheme,
|
|
1980
|
+
robustness: videoRobustness,
|
|
1981
|
+
},
|
|
1982
|
+
audio: {
|
|
1983
|
+
encryptionScheme,
|
|
1984
|
+
robustness: audioRobustness,
|
|
1985
|
+
},
|
|
1986
|
+
},
|
|
1987
|
+
};
|
|
1988
|
+
|
|
1989
|
+
const decodingInfo =
|
|
1990
|
+
await navigator.mediaCapabilities.decodingInfo(decodingConfig);
|
|
1991
|
+
|
|
1992
|
+
const access = decodingInfo.keySystemAccess;
|
|
1993
|
+
await processMediaKeySystemAccess(keySystem, access);
|
|
1994
|
+
} catch (error) {} // Ignore errors.
|
|
1995
|
+
};
|
|
1996
|
+
|
|
1997
|
+
// Initialize the support structure for each key system.
|
|
1998
|
+
for (const keySystem of testKeySystems) {
|
|
1999
|
+
support.set(keySystem, null);
|
|
2000
|
+
}
|
|
2001
|
+
|
|
2002
|
+
// Test each key system and encryption scheme.
|
|
2003
|
+
const tests = [];
|
|
2004
|
+
for (const encryptionScheme of testEncryptionSchemes) {
|
|
2005
|
+
for (const keySystem of testKeySystems) {
|
|
1831
2006
|
// Our Polyfill will reject anything apart com.apple.fps key systems.
|
|
1832
2007
|
// It seems the Safari modern EME API will allow to request a
|
|
1833
2008
|
// MediaKeySystemAccess for the ClearKey CDM, create and update a key
|
|
@@ -1835,40 +2010,22 @@ shaka.media.DrmEngine = class {
|
|
|
1835
2010
|
// Safari bug: https://bugs.webkit.org/show_bug.cgi?id=231006
|
|
1836
2011
|
if (keySystem === 'org.w3.clearkey' &&
|
|
1837
2012
|
shaka.util.Platform.isSafari()) {
|
|
1838
|
-
|
|
1839
|
-
}
|
|
1840
|
-
|
|
1841
|
-
const access = await navigator.requestMediaKeySystemAccess(
|
|
1842
|
-
keySystem, configs);
|
|
1843
|
-
|
|
1844
|
-
// Edge doesn't return supported session types, but current versions
|
|
1845
|
-
// do not support persistent-license. If sessionTypes is missing,
|
|
1846
|
-
// assume no support for persistent-license.
|
|
1847
|
-
// TODO: Polyfill Edge to return known supported session types.
|
|
1848
|
-
// Edge bug: https://bit.ly/2IeKzho
|
|
1849
|
-
const sessionTypes = access.getConfiguration().sessionTypes;
|
|
1850
|
-
let persistentState = sessionTypes ?
|
|
1851
|
-
sessionTypes.includes('persistent-license') : false;
|
|
1852
|
-
|
|
1853
|
-
// Tizen 3.0 doesn't support persistent licenses, but reports that it
|
|
1854
|
-
// does. It doesn't fail until you call update() with a license
|
|
1855
|
-
// response, which is way too late.
|
|
1856
|
-
// This is a work-around for #894.
|
|
1857
|
-
if (shaka.util.Platform.isTizen3()) {
|
|
1858
|
-
persistentState = false;
|
|
2013
|
+
continue;
|
|
1859
2014
|
}
|
|
2015
|
+
tests.push(testSystemEme(keySystem, encryptionScheme, '', ''));
|
|
2016
|
+
tests.push(testSystemMcap(keySystem, encryptionScheme, '', ''));
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
1860
2019
|
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
2020
|
+
for (const keySystem of testKeySystems) {
|
|
2021
|
+
for (const robustness of (testRobustness[keySystem] || [])) {
|
|
2022
|
+
tests.push(testSystemEme(keySystem, null, robustness, ''));
|
|
2023
|
+
tests.push(testSystemEme(keySystem, null, '', robustness));
|
|
2024
|
+
tests.push(testSystemMcap(keySystem, null, robustness, ''));
|
|
2025
|
+
tests.push(testSystemMcap(keySystem, null, '', robustness));
|
|
1867
2026
|
}
|
|
1868
|
-
}
|
|
2027
|
+
}
|
|
1869
2028
|
|
|
1870
|
-
// Test each key system.
|
|
1871
|
-
const tests = testKeySystems.map((keySystem) => testSystem(keySystem));
|
|
1872
2029
|
await Promise.all(tests);
|
|
1873
2030
|
return shaka.util.MapUtils.asObject(support);
|
|
1874
2031
|
}
|
|
@@ -2562,6 +2719,73 @@ shaka.media.DrmEngine = class {
|
|
|
2562
2719
|
this.newInitData('cenc', combinedData);
|
|
2563
2720
|
return this.allSessionsLoaded_;
|
|
2564
2721
|
}
|
|
2722
|
+
|
|
2723
|
+
/**
|
|
2724
|
+
* A method for generating a key for the MediaKeySystemAccessRequests cache.
|
|
2725
|
+
*
|
|
2726
|
+
* @param {string} videoCodec
|
|
2727
|
+
* @param {string} audioCodec
|
|
2728
|
+
* @param {string} keySystem
|
|
2729
|
+
* @return {string}
|
|
2730
|
+
* @private
|
|
2731
|
+
*/
|
|
2732
|
+
static generateKeySystemCacheKey_(videoCodec, audioCodec, keySystem) {
|
|
2733
|
+
return `${videoCodec}#${audioCodec}#${keySystem}`;
|
|
2734
|
+
}
|
|
2735
|
+
|
|
2736
|
+
/**
|
|
2737
|
+
* Check does MediaKeySystemAccess cache contains something for following
|
|
2738
|
+
* attributes.
|
|
2739
|
+
*
|
|
2740
|
+
* @param {string} videoCodec
|
|
2741
|
+
* @param {string} audioCodec
|
|
2742
|
+
* @param {string} keySystem
|
|
2743
|
+
* @return {boolean}
|
|
2744
|
+
*/
|
|
2745
|
+
static hasMediaKeySystemAccess(videoCodec, audioCodec, keySystem) {
|
|
2746
|
+
const DrmEngine = shaka.media.DrmEngine;
|
|
2747
|
+
const key = DrmEngine.generateKeySystemCacheKey_(
|
|
2748
|
+
videoCodec, audioCodec, keySystem);
|
|
2749
|
+
return DrmEngine.memoizedMediaKeySystemAccessRequests_.has(key);
|
|
2750
|
+
}
|
|
2751
|
+
|
|
2752
|
+
/**
|
|
2753
|
+
* Get MediaKeySystemAccess object for following attributes.
|
|
2754
|
+
*
|
|
2755
|
+
* @param {string} videoCodec
|
|
2756
|
+
* @param {string} audioCodec
|
|
2757
|
+
* @param {string} keySystem
|
|
2758
|
+
* @return {?MediaKeySystemAccess}
|
|
2759
|
+
*/
|
|
2760
|
+
static getMediaKeySystemAccess(videoCodec, audioCodec, keySystem) {
|
|
2761
|
+
const DrmEngine = shaka.media.DrmEngine;
|
|
2762
|
+
const key = DrmEngine.generateKeySystemCacheKey_(
|
|
2763
|
+
videoCodec, audioCodec, keySystem);
|
|
2764
|
+
return DrmEngine.memoizedMediaKeySystemAccessRequests_.get(key) || null;
|
|
2765
|
+
}
|
|
2766
|
+
|
|
2767
|
+
/**
|
|
2768
|
+
* Store MediaKeySystemAccess object associated with specified attributes.
|
|
2769
|
+
*
|
|
2770
|
+
* @param {string} videoCodec
|
|
2771
|
+
* @param {string} audioCodec
|
|
2772
|
+
* @param {string} keySystem
|
|
2773
|
+
* @param {!MediaKeySystemAccess} mksa
|
|
2774
|
+
*/
|
|
2775
|
+
static setMediaKeySystemAccess(videoCodec, audioCodec, keySystem, mksa) {
|
|
2776
|
+
const DrmEngine = shaka.media.DrmEngine;
|
|
2777
|
+
const key = DrmEngine.generateKeySystemCacheKey_(
|
|
2778
|
+
videoCodec, audioCodec, keySystem);
|
|
2779
|
+
return DrmEngine.memoizedMediaKeySystemAccessRequests_.set(key, mksa);
|
|
2780
|
+
}
|
|
2781
|
+
|
|
2782
|
+
/**
|
|
2783
|
+
* Clears underlying cache.
|
|
2784
|
+
*/
|
|
2785
|
+
static clearMediaKeySystemAccessMap() {
|
|
2786
|
+
const DrmEngine = shaka.media.DrmEngine;
|
|
2787
|
+
DrmEngine.memoizedMediaKeySystemAccessRequests_.clear();
|
|
2788
|
+
}
|
|
2565
2789
|
};
|
|
2566
2790
|
|
|
2567
2791
|
|
|
@@ -2655,3 +2879,13 @@ shaka.media.DrmEngine.KEY_STATUS_BATCH_TIME = 0.5;
|
|
|
2655
2879
|
*/
|
|
2656
2880
|
shaka.media.DrmEngine.DUMMY_KEY_ID = new shaka.util.Lazy(
|
|
2657
2881
|
() => shaka.util.BufferUtils.toArrayBuffer(new Uint8Array([0])));
|
|
2882
|
+
|
|
2883
|
+
|
|
2884
|
+
/**
|
|
2885
|
+
* A cache that stores the MediaKeySystemAccess result of calling
|
|
2886
|
+
* `navigator.requestMediaKeySystemAccess` by a key combination of
|
|
2887
|
+
* video/audio codec and key system string.
|
|
2888
|
+
*
|
|
2889
|
+
* @private {!Map<string, !MediaKeySystemAccess>}
|
|
2890
|
+
*/
|
|
2891
|
+
shaka.media.DrmEngine.memoizedMediaKeySystemAccessRequests_ = new Map();
|
|
@@ -19,7 +19,7 @@ goog.require('shaka.util.Error');
|
|
|
19
19
|
shaka.media.ManifestFilterer = class {
|
|
20
20
|
/**
|
|
21
21
|
* @param {?shaka.extern.PlayerConfiguration} config
|
|
22
|
-
* @param {
|
|
22
|
+
* @param {shaka.extern.Resolution} maxHwRes
|
|
23
23
|
* @param {?shaka.media.DrmEngine} drmEngine
|
|
24
24
|
*/
|
|
25
25
|
constructor(config, maxHwRes, drmEngine) {
|
|
@@ -28,7 +28,7 @@ shaka.media.ManifestFilterer = class {
|
|
|
28
28
|
/** @private {!shaka.extern.PlayerConfiguration} */
|
|
29
29
|
this.config_ = config;
|
|
30
30
|
|
|
31
|
-
/** @private {
|
|
31
|
+
/** @private {shaka.extern.Resolution} */
|
|
32
32
|
this.maxHwRes_ = maxHwRes;
|
|
33
33
|
|
|
34
34
|
/** @private {?shaka.media.DrmEngine} drmEngine */
|
|
@@ -41,27 +41,23 @@ shaka.media.ManifestFilterer = class {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
|
-
* Filters a manifest, removing unplayable streams/variants
|
|
44
|
+
* Filters a manifest, removing unplayable streams/variants and choosing
|
|
45
|
+
* the codecs.
|
|
45
46
|
*
|
|
46
47
|
* @param {?shaka.extern.Manifest} manifest
|
|
47
48
|
* @return {!Promise.<boolean>} tracksChanged
|
|
48
49
|
*/
|
|
49
50
|
async filterManifest(manifest) {
|
|
50
|
-
await this.filterManifestWithStreamUtils_(manifest);
|
|
51
|
-
return this.filterManifestWithRestrictions(manifest);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Filters a manifest, removing unplayable streams/variants.
|
|
56
|
-
*
|
|
57
|
-
* @param {?shaka.extern.Manifest} manifest
|
|
58
|
-
* @private
|
|
59
|
-
*/
|
|
60
|
-
async filterManifestWithStreamUtils_(manifest) {
|
|
61
51
|
goog.asserts.assert(manifest, 'Manifest should exist!');
|
|
62
52
|
await shaka.util.StreamUtils.filterManifest(this.drmEngine_, manifest,
|
|
63
53
|
this.config_.drm.preferredKeySystems);
|
|
54
|
+
shaka.util.StreamUtils.chooseCodecsAndFilterManifest(
|
|
55
|
+
manifest,
|
|
56
|
+
this.config_.preferredVideoCodecs,
|
|
57
|
+
this.config_.preferredAudioCodecs,
|
|
58
|
+
this.config_.preferredDecodingAttributes);
|
|
64
59
|
this.checkPlayableVariants_(manifest);
|
|
60
|
+
return this.filterManifestWithRestrictions(manifest);
|
|
65
61
|
}
|
|
66
62
|
|
|
67
63
|
|
|
@@ -553,7 +553,9 @@ shaka.media.PreloadManager = class extends shaka.util.FakeEventTarget {
|
|
|
553
553
|
|
|
554
554
|
const tracksChangedInitial = this.manifestFilterer_.applyRestrictions(
|
|
555
555
|
this.manifest_);
|
|
556
|
-
|
|
556
|
+
const tracksChangedBefore = await this.manifestFilterer_.filterManifest(
|
|
557
|
+
this.manifest_);
|
|
558
|
+
if (tracksChangedInitial || tracksChangedBefore) {
|
|
557
559
|
const event = this.makeEvent_(
|
|
558
560
|
shaka.util.FakeEvent.EventName.TracksChanged);
|
|
559
561
|
await Promise.resolve();
|
|
@@ -568,7 +570,6 @@ shaka.media.PreloadManager = class extends shaka.util.FakeEventTarget {
|
|
|
568
570
|
|
|
569
571
|
// Now that we have drm information, filter the manifest (again) so that
|
|
570
572
|
// we can ensure we only use variants with the selected key system.
|
|
571
|
-
// const tracksChanged =
|
|
572
573
|
const tracksChangedAfter = await this.manifestFilterer_.filterManifest(
|
|
573
574
|
this.manifest_);
|
|
574
575
|
if (tracksChangedAfter) {
|
|
@@ -630,14 +631,6 @@ shaka.media.PreloadManager = class extends shaka.util.FakeEventTarget {
|
|
|
630
631
|
this.config_.preferredVideoLabel,
|
|
631
632
|
this.config_.mediaSource.codecSwitchingStrategy,
|
|
632
633
|
this.config_.manifest.dash.enableAudioGroups);
|
|
633
|
-
|
|
634
|
-
// If the content is multi-codec and the browser can play more than one of
|
|
635
|
-
// them, choose codecs now before we initialize streaming.
|
|
636
|
-
shaka.util.StreamUtils.chooseCodecsAndFilterManifest(
|
|
637
|
-
this.manifest_,
|
|
638
|
-
this.config_.preferredVideoCodecs,
|
|
639
|
-
this.config_.preferredAudioCodecs,
|
|
640
|
-
this.config_.preferredDecodingAttributes);
|
|
641
634
|
}
|
|
642
635
|
|
|
643
636
|
// Make the ABR manager.
|
|
@@ -41,6 +41,7 @@ shaka.media.SegmentUtils = class {
|
|
|
41
41
|
sampleRate: null,
|
|
42
42
|
closedCaptions: new Map(),
|
|
43
43
|
videoRange: null,
|
|
44
|
+
colorGamut: null,
|
|
44
45
|
};
|
|
45
46
|
}
|
|
46
47
|
|
|
@@ -125,6 +126,7 @@ shaka.media.SegmentUtils = class {
|
|
|
125
126
|
sampleRate: null,
|
|
126
127
|
closedCaptions: closedCaptions,
|
|
127
128
|
videoRange: null,
|
|
129
|
+
colorGamut: null,
|
|
128
130
|
};
|
|
129
131
|
}
|
|
130
132
|
|
|
@@ -199,6 +201,8 @@ shaka.media.SegmentUtils = class {
|
|
|
199
201
|
let sampleRate = null;
|
|
200
202
|
/** @type {?string} */
|
|
201
203
|
let realVideoRange = null;
|
|
204
|
+
/** @type {?string} */
|
|
205
|
+
let realColorGamut = null;
|
|
202
206
|
|
|
203
207
|
/** @type {?string} */
|
|
204
208
|
let baseBox;
|
|
@@ -371,8 +375,10 @@ shaka.media.SegmentUtils = class {
|
|
|
371
375
|
})
|
|
372
376
|
|
|
373
377
|
.box('colr', (box) => {
|
|
374
|
-
const {videoRange} =
|
|
378
|
+
const {videoRange, colorGamut} =
|
|
379
|
+
shaka.util.Mp4BoxParsers.parseCOLR(box.reader);
|
|
375
380
|
realVideoRange = videoRange;
|
|
381
|
+
realColorGamut = colorGamut;
|
|
376
382
|
})
|
|
377
383
|
|
|
378
384
|
.parse(initData || data, /* partialOkay= */ true);
|
|
@@ -404,6 +410,7 @@ shaka.media.SegmentUtils = class {
|
|
|
404
410
|
sampleRate: sampleRate,
|
|
405
411
|
closedCaptions: closedCaptions,
|
|
406
412
|
videoRange: realVideoRange,
|
|
413
|
+
colorGamut: realColorGamut,
|
|
407
414
|
};
|
|
408
415
|
}
|
|
409
416
|
|
|
@@ -465,7 +472,9 @@ shaka.media.SegmentUtils = class {
|
|
|
465
472
|
return codecs;
|
|
466
473
|
}
|
|
467
474
|
const dolbyVision = codecs.find((codec) => {
|
|
468
|
-
return codec.startsWith('dvh1.') ||
|
|
475
|
+
return codec.startsWith('dvh1.') ||
|
|
476
|
+
codec.startsWith('dvhe.') ||
|
|
477
|
+
codec.startsWith('dav1.');
|
|
469
478
|
});
|
|
470
479
|
if (!dolbyVision) {
|
|
471
480
|
return codecs;
|
|
@@ -518,7 +527,8 @@ shaka.media.SegmentUtils = class {
|
|
|
518
527
|
* channelCount: ?number,
|
|
519
528
|
* sampleRate: ?number,
|
|
520
529
|
* closedCaptions: Map.<string, string>,
|
|
521
|
-
* videoRange: ?string
|
|
530
|
+
* videoRange: ?string,
|
|
531
|
+
* colorGamut: ?string
|
|
522
532
|
* }}
|
|
523
533
|
*
|
|
524
534
|
* @property {string} type
|
|
@@ -531,5 +541,6 @@ shaka.media.SegmentUtils = class {
|
|
|
531
541
|
* @property {?number} sampleRate
|
|
532
542
|
* @property {Map.<string, string>} closedCaptions
|
|
533
543
|
* @property {?string} videoRange
|
|
544
|
+
* @property {?string} colorGamut
|
|
534
545
|
*/
|
|
535
546
|
shaka.media.SegmentUtils.BasicInfo;
|
package/lib/mss/mss_parser.js
CHANGED
|
@@ -419,6 +419,7 @@ shaka.mss.MssParser = class {
|
|
|
419
419
|
ignoreManifestTimestampsInSegmentsMode: false,
|
|
420
420
|
type: shaka.media.ManifestParser.MSS,
|
|
421
421
|
serviceDescription: null,
|
|
422
|
+
nextUrl: null,
|
|
422
423
|
};
|
|
423
424
|
|
|
424
425
|
// This is the first point where we have a meaningful presentation start
|
|
@@ -570,6 +571,7 @@ shaka.mss.MssParser = class {
|
|
|
570
571
|
spatialAudio: false,
|
|
571
572
|
closedCaptions: null,
|
|
572
573
|
hdr: undefined,
|
|
574
|
+
colorGamut: undefined,
|
|
573
575
|
videoLayout: undefined,
|
|
574
576
|
tilesLayout: undefined,
|
|
575
577
|
matchedStreams: [],
|
|
@@ -96,10 +96,21 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
|
|
|
96
96
|
/** @private {?shaka.net.NetworkingEngine.OnResponse} */
|
|
97
97
|
this.onResponse_ = onResponse || null;
|
|
98
98
|
|
|
99
|
+
/** @private {boolean} */
|
|
100
|
+
this.forceHTTP_ = false;
|
|
101
|
+
|
|
99
102
|
/** @private {boolean} */
|
|
100
103
|
this.forceHTTPS_ = false;
|
|
101
104
|
}
|
|
102
105
|
|
|
106
|
+
/**
|
|
107
|
+
* @param {boolean} forceHTTP
|
|
108
|
+
* @export
|
|
109
|
+
*/
|
|
110
|
+
setForceHTTP(forceHTTP) {
|
|
111
|
+
this.forceHTTP_ = forceHTTP;
|
|
112
|
+
}
|
|
113
|
+
|
|
103
114
|
/**
|
|
104
115
|
* @param {boolean} forceHTTPS
|
|
105
116
|
* @export
|
|
@@ -146,6 +157,19 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
|
|
|
146
157
|
delete shaka.net.NetworkingEngine.schemes_[scheme];
|
|
147
158
|
}
|
|
148
159
|
|
|
160
|
+
/**
|
|
161
|
+
* Copies all of the filters from this networking engine into another.
|
|
162
|
+
* @param {!shaka.net.NetworkingEngine} other
|
|
163
|
+
*/
|
|
164
|
+
copyFiltersInto(other) {
|
|
165
|
+
for (const filter of this.requestFilters_) {
|
|
166
|
+
other.requestFilters_.add(filter);
|
|
167
|
+
}
|
|
168
|
+
for (const filter of this.responseFilters_) {
|
|
169
|
+
other.responseFilters_.add(filter);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
149
173
|
/**
|
|
150
174
|
* Registers a new request filter. All filters are applied in the order they
|
|
151
175
|
* are registered.
|
|
@@ -450,6 +474,9 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
|
|
|
450
474
|
*/
|
|
451
475
|
send_(type, request, context, backoff, index, lastError,
|
|
452
476
|
numBytesRemainingObj) {
|
|
477
|
+
if (this.forceHTTP_) {
|
|
478
|
+
request.uris[index] = request.uris[index].replace('https://', 'http://');
|
|
479
|
+
}
|
|
453
480
|
if (this.forceHTTPS_) {
|
|
454
481
|
request.uris[index] = request.uris[index].replace('http://', 'https://');
|
|
455
482
|
}
|
|
@@ -93,6 +93,7 @@ shaka.offline.ManifestConverter = class {
|
|
|
93
93
|
ignoreManifestTimestampsInSegmentsMode: false,
|
|
94
94
|
type: manifestDB.type || shaka.media.ManifestParser.UNKNOWN,
|
|
95
95
|
serviceDescription: null,
|
|
96
|
+
nextUrl: null,
|
|
96
97
|
};
|
|
97
98
|
}
|
|
98
99
|
|
|
@@ -191,6 +192,7 @@ shaka.offline.ManifestConverter = class {
|
|
|
191
192
|
frameRate: streamDB.frameRate,
|
|
192
193
|
pixelAspectRatio: streamDB.pixelAspectRatio,
|
|
193
194
|
hdr: streamDB.hdr,
|
|
195
|
+
colorGamut: streamDB.colorGamut,
|
|
194
196
|
videoLayout: streamDB.videoLayout,
|
|
195
197
|
kind: streamDB.kind,
|
|
196
198
|
encrypted: streamDB.encrypted,
|
package/lib/offline/storage.js
CHANGED
|
@@ -1316,6 +1316,7 @@ shaka.offline.Storage = class {
|
|
|
1316
1316
|
frameRate: stream.frameRate,
|
|
1317
1317
|
pixelAspectRatio: stream.pixelAspectRatio,
|
|
1318
1318
|
hdr: stream.hdr,
|
|
1319
|
+
colorGamut: stream.colorGamut,
|
|
1319
1320
|
videoLayout: stream.videoLayout,
|
|
1320
1321
|
kind: stream.kind,
|
|
1321
1322
|
language: stream.language,
|