hls.js 1.5.14-0.canary.10666 → 1.5.14-0.canary.10669
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 +8 -4
- package/dist/hls.d.ts +8 -4
- package/dist/hls.js +134 -57
- package/dist/hls.js.d.ts +8 -4
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +212 -36
- 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 +191 -28
- 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 +120 -48
- package/dist/hls.mjs.map +1 -1
- package/dist/hls.worker.js +1 -1
- package/dist/hls.worker.js.map +1 -1
- package/package.json +2 -2
- package/src/controller/buffer-controller.ts +2 -2
- package/src/controller/level-controller.ts +44 -21
- package/src/controller/stream-controller.ts +30 -3
- package/src/hls.ts +24 -4
- package/src/remux/passthrough-remuxer.ts +7 -15
- package/src/utils/codecs.ts +36 -6
- package/src/utils/mediacapabilities-helper.ts +30 -23
- package/src/utils/mediakeys-helper.ts +2 -2
package/dist/hls.light.mjs
CHANGED
@@ -440,7 +440,7 @@ function enableLogs(debugConfig, context, id) {
|
|
440
440
|
// Some browsers don't allow to use bind on console object anyway
|
441
441
|
// fallback to default if needed
|
442
442
|
try {
|
443
|
-
newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.5.14-0.canary.
|
443
|
+
newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.5.14-0.canary.10669"}`);
|
444
444
|
} catch (e) {
|
445
445
|
/* log fn threw an exception. All logger methods are no-ops. */
|
446
446
|
return createLogger();
|
@@ -2490,7 +2490,7 @@ function isCodecMediaSourceSupported(codec, type, preferManagedMediaSource = tru
|
|
2490
2490
|
return (_MediaSource$isTypeSu = MediaSource == null ? void 0 : MediaSource.isTypeSupported(mimeTypeForCodec(codec, type))) != null ? _MediaSource$isTypeSu : false;
|
2491
2491
|
}
|
2492
2492
|
function mimeTypeForCodec(codec, type) {
|
2493
|
-
return `${type}/mp4;codecs
|
2493
|
+
return `${type}/mp4;codecs=${codec}`;
|
2494
2494
|
}
|
2495
2495
|
function videoCodecPreferenceValue(videoCodec) {
|
2496
2496
|
if (videoCodec) {
|
@@ -2541,15 +2541,28 @@ function getCodecCompatibleName(codec, preferManagedMediaSource = true) {
|
|
2541
2541
|
function pickMostCompleteCodecName(parsedCodec, levelCodec) {
|
2542
2542
|
// Parsing of mp4a codecs strings in mp4-tools from media is incomplete as of d8c6c7a
|
2543
2543
|
// so use level codec is parsed codec is unavailable or incomplete
|
2544
|
-
if (parsedCodec && parsedCodec
|
2544
|
+
if (parsedCodec && (parsedCodec.length > 4 || ['ac-3', 'ec-3', 'alac', 'fLaC', 'Opus'].indexOf(parsedCodec) !== -1)) {
|
2545
2545
|
return parsedCodec;
|
2546
2546
|
}
|
2547
|
-
|
2547
|
+
if (levelCodec) {
|
2548
|
+
const levelCodecs = levelCodec.split(',');
|
2549
|
+
if (levelCodecs.length > 1) {
|
2550
|
+
if (parsedCodec) {
|
2551
|
+
for (let i = levelCodecs.length; i--;) {
|
2552
|
+
if (levelCodecs[i].substring(0, 4) === parsedCodec.substring(0, 4)) {
|
2553
|
+
return levelCodecs[i];
|
2554
|
+
}
|
2555
|
+
}
|
2556
|
+
}
|
2557
|
+
return levelCodecs[0];
|
2558
|
+
}
|
2559
|
+
}
|
2560
|
+
return levelCodec || parsedCodec;
|
2548
2561
|
}
|
2549
|
-
function convertAVC1ToAVCOTI(
|
2562
|
+
function convertAVC1ToAVCOTI(videoCodecs) {
|
2550
2563
|
// Convert avc1 codec string from RFC-4281 to RFC-6381 for MediaSource.isTypeSupported
|
2551
2564
|
// Examples: avc1.66.30 to avc1.42001e and avc1.77.30,avc1.66.30 to avc1.4d001e,avc1.42001e.
|
2552
|
-
const codecs =
|
2565
|
+
const codecs = videoCodecs.split(',');
|
2553
2566
|
for (let i = 0; i < codecs.length; i++) {
|
2554
2567
|
const avcdata = codecs[i].split('.');
|
2555
2568
|
if (avcdata.length > 2) {
|
@@ -2561,6 +2574,18 @@ function convertAVC1ToAVCOTI(codec) {
|
|
2561
2574
|
}
|
2562
2575
|
return codecs.join(',');
|
2563
2576
|
}
|
2577
|
+
function fillInMissingAV01Params(videoCodec) {
|
2578
|
+
// Used to fill in incomplete AV1 playlist CODECS strings for mediaCapabilities.decodingInfo queries
|
2579
|
+
if (videoCodec.startsWith('av01.')) {
|
2580
|
+
const av1params = videoCodec.split('.');
|
2581
|
+
const placeholders = ['0', '111', '01', '01', '01', '0'];
|
2582
|
+
for (let i = av1params.length; i > 4 && i < 10; i++) {
|
2583
|
+
av1params[i] = placeholders[i - 4];
|
2584
|
+
}
|
2585
|
+
return av1params.join('.');
|
2586
|
+
}
|
2587
|
+
return videoCodec;
|
2588
|
+
}
|
2564
2589
|
function getM2TSSupportedAudioTypes(preferManagedMediaSource) {
|
2565
2590
|
const MediaSource = getMediaSource(preferManagedMediaSource) || {
|
2566
2591
|
isTypeSupported: () => false
|
@@ -6375,10 +6400,27 @@ class LevelController extends BasePlaylistController {
|
|
6375
6400
|
height,
|
6376
6401
|
unknownCodecs
|
6377
6402
|
} = levelParsed;
|
6403
|
+
let unknownUnsupportedCodecCount = unknownCodecs ? unknownCodecs.length : 0;
|
6404
|
+
if (unknownCodecs) {
|
6405
|
+
// Treat unknown codec as audio or video codec based on passing `isTypeSupported` check
|
6406
|
+
// (allows for playback of any supported codec even if not indexed in utils/codecs)
|
6407
|
+
for (let i = unknownUnsupportedCodecCount; i--;) {
|
6408
|
+
const unknownCodec = unknownCodecs[i];
|
6409
|
+
if (this.isAudioSupported(unknownCodec)) {
|
6410
|
+
levelParsed.audioCodec = audioCodec = audioCodec ? `${audioCodec},${unknownCodec}` : unknownCodec;
|
6411
|
+
unknownUnsupportedCodecCount--;
|
6412
|
+
sampleEntryCodesISO.audio[audioCodec.substring(0, 4)] = 2;
|
6413
|
+
} else if (this.isVideoSupported(unknownCodec)) {
|
6414
|
+
levelParsed.videoCodec = videoCodec = videoCodec ? `${videoCodec},${unknownCodec}` : unknownCodec;
|
6415
|
+
unknownUnsupportedCodecCount--;
|
6416
|
+
sampleEntryCodesISO.video[videoCodec.substring(0, 4)] = 2;
|
6417
|
+
}
|
6418
|
+
}
|
6419
|
+
}
|
6378
6420
|
resolutionFound || (resolutionFound = !!(width && height));
|
6379
6421
|
videoCodecFound || (videoCodecFound = !!videoCodec);
|
6380
6422
|
audioCodecFound || (audioCodecFound = !!audioCodec);
|
6381
|
-
if (
|
6423
|
+
if (unknownUnsupportedCodecCount || audioCodec && !this.isAudioSupported(audioCodec) || videoCodec && !this.isVideoSupported(videoCodec)) {
|
6382
6424
|
return;
|
6383
6425
|
}
|
6384
6426
|
const {
|
@@ -6411,6 +6453,12 @@ class LevelController extends BasePlaylistController {
|
|
6411
6453
|
});
|
6412
6454
|
this.filterAndSortMediaOptions(levels, data, resolutionFound, videoCodecFound, audioCodecFound);
|
6413
6455
|
}
|
6456
|
+
isAudioSupported(codec) {
|
6457
|
+
return areCodecsMediaSourceSupported(codec, 'audio', this.hls.config.preferManagedMediaSource);
|
6458
|
+
}
|
6459
|
+
isVideoSupported(codec) {
|
6460
|
+
return areCodecsMediaSourceSupported(codec, 'video', this.hls.config.preferManagedMediaSource);
|
6461
|
+
}
|
6414
6462
|
filterAndSortMediaOptions(filteredLevels, data, resolutionFound, videoCodecFound, audioCodecFound) {
|
6415
6463
|
let audioTracks = [];
|
6416
6464
|
let subtitleTracks = [];
|
@@ -6446,10 +6494,7 @@ class LevelController extends BasePlaylistController {
|
|
6446
6494
|
return;
|
6447
6495
|
}
|
6448
6496
|
if (data.audioTracks) {
|
6449
|
-
|
6450
|
-
preferManagedMediaSource
|
6451
|
-
} = this.hls.config;
|
6452
|
-
audioTracks = data.audioTracks.filter(track => !track.audioCodec || areCodecsMediaSourceSupported(track.audioCodec, 'audio', preferManagedMediaSource));
|
6497
|
+
audioTracks = data.audioTracks.filter(track => !track.audioCodec || this.isAudioSupported(track.audioCodec));
|
6453
6498
|
// Assign ids after filtering as array indices by group-id
|
6454
6499
|
assignTrackIdsByGroup(audioTracks);
|
6455
6500
|
}
|
@@ -10153,7 +10198,7 @@ function changeTypeSupported() {
|
|
10153
10198
|
return typeof (sourceBuffer == null ? void 0 : (_sourceBuffer$prototy = sourceBuffer.prototype) == null ? void 0 : _sourceBuffer$prototy.changeType) === 'function';
|
10154
10199
|
}
|
10155
10200
|
|
10156
|
-
const version = "1.5.14-0.canary.
|
10201
|
+
const version = "1.5.14-0.canary.10669";
|
10157
10202
|
|
10158
10203
|
// ensure the worker ends up in the bundle
|
10159
10204
|
// If the worker should not be included this gets aliased to empty.js
|
@@ -14235,7 +14280,7 @@ class PassThroughRemuxer {
|
|
14235
14280
|
}
|
14236
14281
|
const initData = this.initData = parseInitSegment(initSegment);
|
14237
14282
|
|
14238
|
-
// Get codec from initSegment
|
14283
|
+
// Get codec from initSegment
|
14239
14284
|
if (initData.audio) {
|
14240
14285
|
audioCodec = getParsedTrackCodec(initData.audio, ElementaryStreamTypes.AUDIO);
|
14241
14286
|
}
|
@@ -14390,20 +14435,13 @@ function getParsedTrackCodec(track, type) {
|
|
14390
14435
|
const preferManagedMediaSource = false;
|
14391
14436
|
return getCodecCompatibleName(parsedCodec, preferManagedMediaSource);
|
14392
14437
|
}
|
14393
|
-
|
14394
|
-
|
14395
|
-
return result;
|
14438
|
+
logger.warn(`Unhandled audio codec "${parsedCodec}" in mp4 MAP`);
|
14439
|
+
return parsedCodec || 'mp4a';
|
14396
14440
|
}
|
14397
14441
|
// Provide defaults based on codec type
|
14398
14442
|
// This allows for some playback of some fmp4 playlists without CODECS defined in manifest
|
14399
|
-
|
14400
|
-
|
14401
|
-
return 'hvc1.1.6.L120.90';
|
14402
|
-
}
|
14403
|
-
if (parsedCodec === 'av01') {
|
14404
|
-
return 'av01.0.04M.08';
|
14405
|
-
}
|
14406
|
-
return 'avc1.42e01e';
|
14443
|
+
logger.warn(`Unhandled video codec "${parsedCodec}" in mp4 MAP`);
|
14444
|
+
return parsedCodec || 'avc1';
|
14407
14445
|
}
|
14408
14446
|
|
14409
14447
|
let now;
|
@@ -16863,7 +16901,13 @@ class StreamController extends BaseStreamController {
|
|
16863
16901
|
audiovideo
|
16864
16902
|
} = tracks;
|
16865
16903
|
if (audio) {
|
16866
|
-
let audioCodec = currentLevel.audioCodec;
|
16904
|
+
let audioCodec = pickMostCompleteCodecName(audio.codec, currentLevel.audioCodec);
|
16905
|
+
// Add level and profile to make up for passthrough-remuxer not being able to parse full codec
|
16906
|
+
// (logger warning "Unhandled audio codec...")
|
16907
|
+
if (audioCodec === 'mp4a') {
|
16908
|
+
audioCodec = 'mp4a.40.5';
|
16909
|
+
}
|
16910
|
+
// Handle `audioCodecSwitch`
|
16867
16911
|
const ua = navigator.userAgent.toLowerCase();
|
16868
16912
|
if (this.audioCodecSwitch) {
|
16869
16913
|
if (audioCodec) {
|
@@ -16898,7 +16942,24 @@ class StreamController extends BaseStreamController {
|
|
16898
16942
|
if (video) {
|
16899
16943
|
video.levelCodec = currentLevel.videoCodec;
|
16900
16944
|
video.id = 'main';
|
16901
|
-
|
16945
|
+
const parsedVideoCodec = video.codec;
|
16946
|
+
if ((parsedVideoCodec == null ? void 0 : parsedVideoCodec.length) === 4) {
|
16947
|
+
// Make up for passthrough-remuxer not being able to parse full codec
|
16948
|
+
// (logger warning "Unhandled video codec...")
|
16949
|
+
switch (parsedVideoCodec) {
|
16950
|
+
case 'hvc1':
|
16951
|
+
case 'hev1':
|
16952
|
+
video.codec = 'hvc1.1.6.L120.90';
|
16953
|
+
break;
|
16954
|
+
case 'av01':
|
16955
|
+
video.codec = 'av01.0.04M.08';
|
16956
|
+
break;
|
16957
|
+
case 'avc1':
|
16958
|
+
video.codec = 'avc1.42e01e';
|
16959
|
+
break;
|
16960
|
+
}
|
16961
|
+
}
|
16962
|
+
this.log(`Init video buffer, container:${video.container}, codecs[level/parsed]=[${currentLevel.videoCodec || ''}/${parsedVideoCodec}${video.codec !== parsedVideoCodec ? ' parsed-corrected=' + video.codec : ''}}]`);
|
16902
16963
|
delete tracks.audiovideo;
|
16903
16964
|
}
|
16904
16965
|
if (audiovideo) {
|
@@ -18685,7 +18746,7 @@ transfer tracks: ${JSON.stringify(transferredTracks, (key, value) => key === 'in
|
|
18685
18746
|
if (trackName.slice(0, 5) === 'audio') {
|
18686
18747
|
trackCodec = getCodecCompatibleName(trackCodec, this.appendSource);
|
18687
18748
|
}
|
18688
|
-
this.log(`switching codec ${sbCodec} to ${
|
18749
|
+
this.log(`switching codec ${sbCodec} to ${trackCodec}`);
|
18689
18750
|
if (trackCodec !== (track.pendingCodec || track.codec)) {
|
18690
18751
|
track.pendingCodec = trackCodec;
|
18691
18752
|
}
|
@@ -19368,7 +19429,7 @@ transfer tracks: ${JSON.stringify(transferredTracks, (key, value) => key === 'in
|
|
19368
19429
|
}
|
19369
19430
|
}
|
19370
19431
|
getTrackCodec(track, trackName) {
|
19371
|
-
const codec = track.codec
|
19432
|
+
const codec = pickMostCompleteCodecName(track.codec, track.levelCodec);
|
19372
19433
|
if (codec) {
|
19373
19434
|
if (trackName.slice(0, 5) === 'audio') {
|
19374
19435
|
return getCodecCompatibleName(codec, this.appendSource);
|
@@ -21319,6 +21380,100 @@ function enableStreamingMode(config, logger) {
|
|
21319
21380
|
}
|
21320
21381
|
}
|
21321
21382
|
|
21383
|
+
const SUPPORTED_INFO_DEFAULT = {
|
21384
|
+
supported: true,
|
21385
|
+
configurations: [],
|
21386
|
+
decodingInfoResults: [{
|
21387
|
+
supported: true,
|
21388
|
+
powerEfficient: true,
|
21389
|
+
smooth: true
|
21390
|
+
}]
|
21391
|
+
};
|
21392
|
+
const SUPPORTED_INFO_CACHE = {};
|
21393
|
+
function getMediaDecodingInfoPromise(level, audioTracksByGroup, mediaCapabilities) {
|
21394
|
+
const videoCodecs = level.videoCodec;
|
21395
|
+
const audioCodecs = level.audioCodec;
|
21396
|
+
if (!videoCodecs && !audioCodecs || !mediaCapabilities) {
|
21397
|
+
return Promise.resolve(SUPPORTED_INFO_DEFAULT);
|
21398
|
+
}
|
21399
|
+
const configurations = [];
|
21400
|
+
if (videoCodecs) {
|
21401
|
+
const baseVideoConfiguration = {
|
21402
|
+
width: level.width,
|
21403
|
+
height: level.height,
|
21404
|
+
bitrate: Math.ceil(Math.max(level.bitrate * 0.9, level.averageBitrate)),
|
21405
|
+
// Assume a framerate of 30fps since MediaCapabilities will not accept Level default of 0.
|
21406
|
+
framerate: level.frameRate || 30
|
21407
|
+
};
|
21408
|
+
const videoRange = level.videoRange;
|
21409
|
+
if (videoRange !== 'SDR') {
|
21410
|
+
baseVideoConfiguration.transferFunction = videoRange.toLowerCase();
|
21411
|
+
}
|
21412
|
+
configurations.push.apply(configurations, videoCodecs.split(',').map(videoCodec => ({
|
21413
|
+
type: 'media-source',
|
21414
|
+
video: _objectSpread2(_objectSpread2({}, baseVideoConfiguration), {}, {
|
21415
|
+
contentType: mimeTypeForCodec(fillInMissingAV01Params(videoCodec), 'video')
|
21416
|
+
})
|
21417
|
+
})));
|
21418
|
+
}
|
21419
|
+
if (audioCodecs && level.audioGroups) {
|
21420
|
+
level.audioGroups.forEach(audioGroupId => {
|
21421
|
+
var _audioTracksByGroup$g;
|
21422
|
+
if (!audioGroupId) {
|
21423
|
+
return;
|
21424
|
+
}
|
21425
|
+
(_audioTracksByGroup$g = audioTracksByGroup.groups[audioGroupId]) == null ? void 0 : _audioTracksByGroup$g.tracks.forEach(audioTrack => {
|
21426
|
+
if (audioTrack.groupId === audioGroupId) {
|
21427
|
+
const channels = audioTrack.channels || '';
|
21428
|
+
const channelsNumber = parseFloat(channels);
|
21429
|
+
if (isFiniteNumber(channelsNumber) && channelsNumber > 2) {
|
21430
|
+
configurations.push.apply(configurations, audioCodecs.split(',').map(audioCodec => ({
|
21431
|
+
type: 'media-source',
|
21432
|
+
audio: {
|
21433
|
+
contentType: mimeTypeForCodec(audioCodec, 'audio'),
|
21434
|
+
channels: '' + channelsNumber
|
21435
|
+
// spatialRendering:
|
21436
|
+
// audioCodec === 'ec-3' && channels.indexOf('JOC'),
|
21437
|
+
}
|
21438
|
+
})));
|
21439
|
+
}
|
21440
|
+
}
|
21441
|
+
});
|
21442
|
+
});
|
21443
|
+
}
|
21444
|
+
return Promise.all(configurations.map(configuration => {
|
21445
|
+
// Cache MediaCapabilities promises
|
21446
|
+
const decodingInfoKey = getMediaDecodingInfoKey(configuration);
|
21447
|
+
return SUPPORTED_INFO_CACHE[decodingInfoKey] || (SUPPORTED_INFO_CACHE[decodingInfoKey] = mediaCapabilities.decodingInfo(configuration));
|
21448
|
+
})).then(decodingInfoResults => ({
|
21449
|
+
supported: !decodingInfoResults.some(info => !info.supported),
|
21450
|
+
configurations,
|
21451
|
+
decodingInfoResults
|
21452
|
+
})).catch(error => ({
|
21453
|
+
supported: false,
|
21454
|
+
configurations,
|
21455
|
+
decodingInfoResults: [],
|
21456
|
+
error
|
21457
|
+
}));
|
21458
|
+
}
|
21459
|
+
function getMediaDecodingInfoKey(config) {
|
21460
|
+
const {
|
21461
|
+
audio,
|
21462
|
+
video
|
21463
|
+
} = config;
|
21464
|
+
const mediaConfig = video || audio;
|
21465
|
+
if (mediaConfig) {
|
21466
|
+
const codec = mediaConfig.contentType.split('"')[1];
|
21467
|
+
if (video) {
|
21468
|
+
return `r${video.height}x${video.width}f${Math.ceil(video.framerate)}${video.transferFunction || 'sd'}_${codec}_${Math.ceil(video.bitrate / 1e5)}`;
|
21469
|
+
}
|
21470
|
+
if (audio) {
|
21471
|
+
return `c${audio.channels}${audio.spatialRendering ? 's' : 'n'}_${codec}`;
|
21472
|
+
}
|
21473
|
+
}
|
21474
|
+
return '';
|
21475
|
+
}
|
21476
|
+
|
21322
21477
|
/**
|
21323
21478
|
* The `Hls` class is the core of the HLS.js library used to instantiate player instances.
|
21324
21479
|
* @public
|
@@ -22264,6 +22419,14 @@ class Hls {
|
|
22264
22419
|
var _this$interstitialsCo;
|
22265
22420
|
return ((_this$interstitialsCo = this.interstitialsController) == null ? void 0 : _this$interstitialsCo.interstitialsManager) || null;
|
22266
22421
|
}
|
22422
|
+
|
22423
|
+
/**
|
22424
|
+
* returns mediaCapabilities.decodingInfo for a variant/rendition
|
22425
|
+
*/
|
22426
|
+
getMediaDecodingInfo(level, audioTracks = this.allAudioTracks) {
|
22427
|
+
const audioTracksByGroup = getAudioTracksByGroup(audioTracks);
|
22428
|
+
return getMediaDecodingInfoPromise(level, audioTracksByGroup, navigator.mediaCapabilities);
|
22429
|
+
}
|
22267
22430
|
}
|
22268
22431
|
Hls.defaultConfig = void 0;
|
22269
22432
|
|