hls.js 1.6.6-0.canary.11352 → 1.6.6-0.canary.11353
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/hls.d.mts +1 -0
- package/dist/hls.d.ts +1 -0
- package/dist/hls.js +126 -72
- package/dist/hls.js.d.ts +1 -0
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +135 -89
- package/dist/hls.light.js.map +1 -1
- package/dist/hls.light.min.js +1 -1
- package/dist/hls.light.min.js.map +1 -1
- package/dist/hls.light.mjs +125 -80
- package/dist/hls.light.mjs.map +1 -1
- package/dist/hls.min.js +1 -1
- package/dist/hls.min.js.map +1 -1
- package/dist/hls.mjs +117 -68
- package/dist/hls.mjs.map +1 -1
- package/dist/hls.worker.js +1 -1
- package/package.json +1 -1
- package/src/controller/abr-controller.ts +21 -7
- package/src/utils/mediacapabilities-helper.ts +135 -81
package/dist/hls.mjs
CHANGED
@@ -523,7 +523,7 @@ function enableLogs(debugConfig, context, id) {
|
|
523
523
|
// Some browsers don't allow to use bind on console object anyway
|
524
524
|
// fallback to default if needed
|
525
525
|
try {
|
526
|
-
newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.6.6-0.canary.
|
526
|
+
newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.6.6-0.canary.11353"}`);
|
527
527
|
} catch (e) {
|
528
528
|
/* log fn threw an exception. All logger methods are no-ops. */
|
529
529
|
return createLogger();
|
@@ -2630,9 +2630,9 @@ function getUnsupportedResult(error, configurations) {
|
|
2630
2630
|
error
|
2631
2631
|
};
|
2632
2632
|
}
|
2633
|
-
const SUPPORTED_INFO_CACHE = {};
|
2634
2633
|
function requiresMediaCapabilitiesDecodingInfo(level, audioTracksByGroup, currentVideoRange, currentFrameRate, currentBw, audioPreference) {
|
2635
2634
|
// Only test support when configuration is exceeds minimum options
|
2635
|
+
const videoCodecs = level.videoCodec;
|
2636
2636
|
const audioGroups = level.audioCodec ? level.audioGroups : null;
|
2637
2637
|
const audioCodecPreference = audioPreference == null ? void 0 : audioPreference.audioCodec;
|
2638
2638
|
const channelsPreference = audioPreference == null ? void 0 : audioPreference.channels;
|
@@ -2663,69 +2663,47 @@ function requiresMediaCapabilitiesDecodingInfo(level, audioTracksByGroup, curren
|
|
2663
2663
|
return true;
|
2664
2664
|
}
|
2665
2665
|
}
|
2666
|
-
return
|
2666
|
+
return videoCodecs !== undefined && (
|
2667
|
+
// Force media capabilities check for HEVC to avoid failure on Windows
|
2668
|
+
videoCodecs.split(',').some(videoCodec => isHEVC(videoCodec)) || level.width > 1920 && level.height > 1088 || level.height > 1920 && level.width > 1088 || level.frameRate > Math.max(currentFrameRate, 30) || level.videoRange !== 'SDR' && level.videoRange !== currentVideoRange || level.bitrate > Math.max(currentBw, 8e6)) || !!audioChannels && isFiniteNumber(maxChannels) && Object.keys(audioChannels).some(channels => parseInt(channels) > maxChannels);
|
2667
2669
|
}
|
2668
|
-
function getMediaDecodingInfoPromise(level, audioTracksByGroup, mediaCapabilities) {
|
2670
|
+
function getMediaDecodingInfoPromise(level, audioTracksByGroup, mediaCapabilities, cache = {}) {
|
2669
2671
|
const videoCodecs = level.videoCodec;
|
2670
|
-
|
2671
|
-
if (!videoCodecs && !audioCodecs || !mediaCapabilities) {
|
2672
|
+
if (!videoCodecs && !level.audioCodec || !mediaCapabilities) {
|
2672
2673
|
return Promise.resolve(SUPPORTED_INFO_DEFAULT);
|
2673
2674
|
}
|
2674
2675
|
const configurations = [];
|
2675
|
-
|
2676
|
-
|
2677
|
-
|
2678
|
-
|
2679
|
-
|
2680
|
-
|
2681
|
-
|
2676
|
+
const videoDecodeList = makeVideoConfigurations(level);
|
2677
|
+
const videoCount = videoDecodeList.length;
|
2678
|
+
const audioDecodeList = makeAudioConfigurations(level, audioTracksByGroup, videoCount > 0);
|
2679
|
+
const audioCount = audioDecodeList.length;
|
2680
|
+
for (let i = videoCount || 1 * audioCount || 1; i--;) {
|
2681
|
+
const configuration = {
|
2682
|
+
type: 'media-source'
|
2682
2683
|
};
|
2683
|
-
|
2684
|
-
|
2685
|
-
|
2684
|
+
if (videoCount) {
|
2685
|
+
configuration.video = videoDecodeList[i % videoCount];
|
2686
|
+
}
|
2687
|
+
if (audioCount) {
|
2688
|
+
configuration.audio = audioDecodeList[i % audioCount];
|
2689
|
+
const audioBitrate = configuration.audio.bitrate;
|
2690
|
+
if (configuration.video && audioBitrate) {
|
2691
|
+
configuration.video.bitrate -= audioBitrate;
|
2692
|
+
}
|
2686
2693
|
}
|
2687
|
-
|
2694
|
+
configurations.push(configuration);
|
2695
|
+
}
|
2696
|
+
if (videoCodecs) {
|
2688
2697
|
// Override Windows Firefox HEVC MediaCapabilities result (https://github.com/video-dev/hls.js/issues/7046)
|
2689
2698
|
const ua = navigator.userAgent;
|
2690
|
-
if (
|
2691
|
-
return Promise.resolve(getUnsupportedResult(new Error(`Overriding Windows Firefox HEVC MediaCapabilities result based on user-agent
|
2699
|
+
if (videoCodecs.split(',').some(videoCodec => isHEVC(videoCodec)) && userAgentHevcSupportIsInaccurate()) {
|
2700
|
+
return Promise.resolve(getUnsupportedResult(new Error(`Overriding Windows Firefox HEVC MediaCapabilities result based on user-agent string: (${ua})`), configurations));
|
2692
2701
|
}
|
2693
|
-
configurations.push.apply(configurations, videoCodecsArray.map(videoCodec => ({
|
2694
|
-
type: 'media-source',
|
2695
|
-
video: _objectSpread2(_objectSpread2({}, baseVideoConfiguration), {}, {
|
2696
|
-
contentType: mimeTypeForCodec(fillInMissingAV01Params(videoCodec), 'video')
|
2697
|
-
})
|
2698
|
-
})));
|
2699
|
-
}
|
2700
|
-
if (audioCodecs && level.audioGroups) {
|
2701
|
-
level.audioGroups.forEach(audioGroupId => {
|
2702
|
-
var _audioTracksByGroup$g;
|
2703
|
-
if (!audioGroupId) {
|
2704
|
-
return;
|
2705
|
-
}
|
2706
|
-
(_audioTracksByGroup$g = audioTracksByGroup.groups[audioGroupId]) == null ? void 0 : _audioTracksByGroup$g.tracks.forEach(audioTrack => {
|
2707
|
-
if (audioTrack.groupId === audioGroupId) {
|
2708
|
-
const channels = audioTrack.channels || '';
|
2709
|
-
const channelsNumber = parseFloat(channels);
|
2710
|
-
if (isFiniteNumber(channelsNumber) && channelsNumber > 2) {
|
2711
|
-
configurations.push.apply(configurations, audioCodecs.split(',').map(audioCodec => ({
|
2712
|
-
type: 'media-source',
|
2713
|
-
audio: {
|
2714
|
-
contentType: mimeTypeForCodec(audioCodec, 'audio'),
|
2715
|
-
channels: '' + channelsNumber
|
2716
|
-
// spatialRendering:
|
2717
|
-
// audioCodec === 'ec-3' && channels.indexOf('JOC'),
|
2718
|
-
}
|
2719
|
-
})));
|
2720
|
-
}
|
2721
|
-
}
|
2722
|
-
});
|
2723
|
-
});
|
2724
2702
|
}
|
2725
2703
|
return Promise.all(configurations.map(configuration => {
|
2726
2704
|
// Cache MediaCapabilities promises
|
2727
2705
|
const decodingInfoKey = getMediaDecodingInfoKey(configuration);
|
2728
|
-
return
|
2706
|
+
return cache[decodingInfoKey] || (cache[decodingInfoKey] = mediaCapabilities.decodingInfo(configuration));
|
2729
2707
|
})).then(decodingInfoResults => ({
|
2730
2708
|
supported: !decodingInfoResults.some(info => !info.supported),
|
2731
2709
|
configurations,
|
@@ -2737,22 +2715,90 @@ function getMediaDecodingInfoPromise(level, audioTracksByGroup, mediaCapabilitie
|
|
2737
2715
|
error
|
2738
2716
|
}));
|
2739
2717
|
}
|
2718
|
+
function makeVideoConfigurations(level) {
|
2719
|
+
var _level$videoCodec;
|
2720
|
+
const videoCodecs = (_level$videoCodec = level.videoCodec) == null ? void 0 : _level$videoCodec.split(',');
|
2721
|
+
const bitrate = getVariantDecodingBitrate(level);
|
2722
|
+
const width = level.width || 640;
|
2723
|
+
const height = level.height || 480;
|
2724
|
+
// Assume a framerate of 30fps since MediaCapabilities will not accept Level default of 0.
|
2725
|
+
const framerate = level.frameRate || 30;
|
2726
|
+
const videoRange = level.videoRange.toLowerCase();
|
2727
|
+
return videoCodecs ? videoCodecs.map(videoCodec => {
|
2728
|
+
const videoConfiguration = {
|
2729
|
+
contentType: mimeTypeForCodec(fillInMissingAV01Params(videoCodec), 'video'),
|
2730
|
+
width,
|
2731
|
+
height,
|
2732
|
+
bitrate,
|
2733
|
+
framerate
|
2734
|
+
};
|
2735
|
+
if (videoRange !== 'sdr') {
|
2736
|
+
videoConfiguration.transferFunction = videoRange;
|
2737
|
+
}
|
2738
|
+
return videoConfiguration;
|
2739
|
+
}) : [];
|
2740
|
+
}
|
2741
|
+
function makeAudioConfigurations(level, audioTracksByGroup, hasVideo) {
|
2742
|
+
var _level$audioCodec;
|
2743
|
+
const audioCodecs = (_level$audioCodec = level.audioCodec) == null ? void 0 : _level$audioCodec.split(',');
|
2744
|
+
const combinedBitrate = getVariantDecodingBitrate(level);
|
2745
|
+
if (audioCodecs && level.audioGroups) {
|
2746
|
+
return level.audioGroups.reduce((configurations, audioGroupId) => {
|
2747
|
+
var _audioTracksByGroup$g;
|
2748
|
+
const tracks = audioGroupId ? (_audioTracksByGroup$g = audioTracksByGroup.groups[audioGroupId]) == null ? void 0 : _audioTracksByGroup$g.tracks : null;
|
2749
|
+
if (tracks) {
|
2750
|
+
return tracks.reduce((configs, audioTrack) => {
|
2751
|
+
if (audioTrack.groupId === audioGroupId) {
|
2752
|
+
const channelsNumber = parseFloat(audioTrack.channels || '');
|
2753
|
+
audioCodecs.forEach(audioCodec => {
|
2754
|
+
const audioConfiguration = {
|
2755
|
+
contentType: mimeTypeForCodec(audioCodec, 'audio'),
|
2756
|
+
bitrate: hasVideo ? estimatedAudioBitrate(audioCodec, combinedBitrate) : combinedBitrate
|
2757
|
+
};
|
2758
|
+
if (channelsNumber) {
|
2759
|
+
audioConfiguration.channels = '' + channelsNumber;
|
2760
|
+
}
|
2761
|
+
configs.push(audioConfiguration);
|
2762
|
+
});
|
2763
|
+
}
|
2764
|
+
return configs;
|
2765
|
+
}, configurations);
|
2766
|
+
}
|
2767
|
+
return configurations;
|
2768
|
+
}, []);
|
2769
|
+
}
|
2770
|
+
return [];
|
2771
|
+
}
|
2772
|
+
function estimatedAudioBitrate(audioCodec, levelBitrate) {
|
2773
|
+
if (levelBitrate <= 1) {
|
2774
|
+
return 1;
|
2775
|
+
}
|
2776
|
+
let audioBitrate = 128000;
|
2777
|
+
if (audioCodec === 'ec-3') {
|
2778
|
+
audioBitrate = 768000;
|
2779
|
+
} else if (audioCodec === 'ac-3') {
|
2780
|
+
audioBitrate = 640000;
|
2781
|
+
}
|
2782
|
+
return Math.min(levelBitrate / 2, audioBitrate); // Don't exceed some % of level bitrate
|
2783
|
+
}
|
2784
|
+
function getVariantDecodingBitrate(level) {
|
2785
|
+
return Math.ceil(Math.max(level.bitrate * 0.9, level.averageBitrate) / 1000) * 1000 || 1;
|
2786
|
+
}
|
2740
2787
|
function getMediaDecodingInfoKey(config) {
|
2788
|
+
let key = '';
|
2741
2789
|
const {
|
2742
2790
|
audio,
|
2743
2791
|
video
|
2744
2792
|
} = config;
|
2745
|
-
|
2746
|
-
|
2747
|
-
|
2748
|
-
|
2749
|
-
|
2750
|
-
|
2751
|
-
|
2752
|
-
return `c${audio.channels}${audio.spatialRendering ? 's' : 'n'}_${codec}`;
|
2753
|
-
}
|
2793
|
+
if (video) {
|
2794
|
+
const codec = getCodecsForMimeType(video.contentType);
|
2795
|
+
key += `${codec}_r${video.height}x${video.width}f${Math.ceil(video.framerate)}${video.transferFunction || 'sd'}_${Math.ceil(video.bitrate / 1e5)}`;
|
2796
|
+
}
|
2797
|
+
if (audio) {
|
2798
|
+
const codec = getCodecsForMimeType(audio.contentType);
|
2799
|
+
key += `${video ? '_' : ''}${codec}_c${audio.channels}`;
|
2754
2800
|
}
|
2755
|
-
return
|
2801
|
+
return key;
|
2756
2802
|
}
|
2757
2803
|
|
2758
2804
|
const HdcpLevels = ['NONE', 'TYPE-0', 'TYPE-1', null];
|
@@ -3345,6 +3391,7 @@ class AbrController extends Logger {
|
|
3345
3391
|
this.partCurrent = null;
|
3346
3392
|
this.bitrateTestDelay = 0;
|
3347
3393
|
this.rebufferNotice = -1;
|
3394
|
+
this.supportedCache = {};
|
3348
3395
|
this.bwEstimator = void 0;
|
3349
3396
|
/*
|
3350
3397
|
This method monitors the download rate of the current fragment, and will downswitch if that fragment will not load
|
@@ -3555,13 +3602,14 @@ class AbrController extends Logger {
|
|
3555
3602
|
this.unregisterListeners();
|
3556
3603
|
this.clearTimer();
|
3557
3604
|
// @ts-ignore
|
3558
|
-
this.hls = this._abandonRulesCheck = null;
|
3605
|
+
this.hls = this._abandonRulesCheck = this.supportedCache = null;
|
3559
3606
|
this.fragCurrent = this.partCurrent = null;
|
3560
3607
|
}
|
3561
3608
|
onManifestLoading(event, data) {
|
3562
3609
|
this.lastLoadedFragLevel = -1;
|
3563
3610
|
this.firstSelection = -1;
|
3564
3611
|
this.lastLevelLoadSec = 0;
|
3612
|
+
this.supportedCache = {};
|
3565
3613
|
this.fragCurrent = this.partCurrent = null;
|
3566
3614
|
this.onLevelsUpdated();
|
3567
3615
|
this.clearTimer();
|
@@ -3922,7 +3970,7 @@ class AbrController extends Logger {
|
|
3922
3970
|
const ttfbEstimateSec = this.bwEstimator.getEstimateTTFB() / 1000;
|
3923
3971
|
const levelsSkipped = [];
|
3924
3972
|
for (let i = maxAutoLevel; i >= minAutoLevel; i--) {
|
3925
|
-
var _levelInfo$supportedR;
|
3973
|
+
var _levelInfo$supportedR, _levelInfo$supportedR2;
|
3926
3974
|
const levelInfo = levels[i];
|
3927
3975
|
const upSwitch = i > selectionBaseLevel;
|
3928
3976
|
if (!levelInfo) {
|
@@ -3930,9 +3978,8 @@ class AbrController extends Logger {
|
|
3930
3978
|
}
|
3931
3979
|
if (config.useMediaCapabilities && !levelInfo.supportedResult && !levelInfo.supportedPromise) {
|
3932
3980
|
const mediaCapabilities = navigator.mediaCapabilities;
|
3933
|
-
if (typeof (mediaCapabilities == null ? void 0 : mediaCapabilities.decodingInfo) === 'function' &&
|
3934
|
-
|
3935
|
-
levelInfo.supportedPromise = getMediaDecodingInfoPromise(levelInfo, audioTracksByGroup, mediaCapabilities);
|
3981
|
+
if (typeof (mediaCapabilities == null ? void 0 : mediaCapabilities.decodingInfo) === 'function' && requiresMediaCapabilitiesDecodingInfo(levelInfo, audioTracksByGroup, currentVideoRange, currentFrameRate, currentBw, audioPreference)) {
|
3982
|
+
levelInfo.supportedPromise = getMediaDecodingInfoPromise(levelInfo, audioTracksByGroup, mediaCapabilities, this.supportedCache);
|
3936
3983
|
levelInfo.supportedPromise.then(decodingInfo => {
|
3937
3984
|
if (!this.hls) {
|
3938
3985
|
return;
|
@@ -3951,6 +3998,8 @@ class AbrController extends Logger {
|
|
3951
3998
|
this.hls.nextLoadLevel = 0;
|
3952
3999
|
}
|
3953
4000
|
}
|
4001
|
+
} else if (decodingInfo.decodingInfoResults.some(info => info.smooth === false || info.powerEfficient === false)) {
|
4002
|
+
this.log(`MediaCapabilities decodingInfo for level ${index} not smooth or powerEfficient: ${stringify(decodingInfo)}`);
|
3954
4003
|
}
|
3955
4004
|
});
|
3956
4005
|
} else {
|
@@ -3960,7 +4009,7 @@ class AbrController extends Logger {
|
|
3960
4009
|
|
3961
4010
|
// skip candidates which change codec-family or video-range,
|
3962
4011
|
// and which decrease or increase frame-rate for up and down-switch respectfully
|
3963
|
-
if (currentCodecSet && levelInfo.codecSet !== currentCodecSet || currentVideoRange && levelInfo.videoRange !== currentVideoRange || upSwitch && currentFrameRate > levelInfo.frameRate || !upSwitch && currentFrameRate > 0 && currentFrameRate < levelInfo.frameRate || levelInfo.supportedResult &&
|
4012
|
+
if (currentCodecSet && levelInfo.codecSet !== currentCodecSet || currentVideoRange && levelInfo.videoRange !== currentVideoRange || upSwitch && currentFrameRate > levelInfo.frameRate || !upSwitch && currentFrameRate > 0 && currentFrameRate < levelInfo.frameRate || (_levelInfo$supportedR = levelInfo.supportedResult) != null && (_levelInfo$supportedR2 = _levelInfo$supportedR.decodingInfoResults) != null && _levelInfo$supportedR2.some(info => info.smooth === false)) {
|
3964
4013
|
if (!firstSelection || i !== minStartIndex) {
|
3965
4014
|
levelsSkipped.push(i);
|
3966
4015
|
continue;
|
@@ -10218,7 +10267,7 @@ function requireEventemitter3 () {
|
|
10218
10267
|
var eventemitter3Exports = requireEventemitter3();
|
10219
10268
|
var EventEmitter = /*@__PURE__*/getDefaultExportFromCjs(eventemitter3Exports);
|
10220
10269
|
|
10221
|
-
const version = "1.6.6-0.canary.
|
10270
|
+
const version = "1.6.6-0.canary.11353";
|
10222
10271
|
|
10223
10272
|
// ensure the worker ends up in the bundle
|
10224
10273
|
// If the worker should not be included this gets aliased to empty.js
|