hls.js 1.5.14-0.canary.10668 → 1.5.14-0.canary.10670
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 +141 -58
- 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 +127 -49
- 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 +1 -1
- 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/demux/video/hevc-video-parser.ts +12 -1
- 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.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.10670"}`);
|
444
444
|
} catch (e) {
|
445
445
|
/* log fn threw an exception. All logger methods are no-ops. */
|
446
446
|
return createLogger();
|
@@ -1391,12 +1391,12 @@ function createMediaKeySystemConfigurations(initDataTypes, audioCodecs, videoCod
|
|
1391
1391
|
distinctiveIdentifier: drmSystemOptions.distinctiveIdentifier || 'optional',
|
1392
1392
|
sessionTypes: drmSystemOptions.sessionTypes || [drmSystemOptions.sessionType || 'temporary'],
|
1393
1393
|
audioCapabilities: audioCodecs.map(codec => ({
|
1394
|
-
contentType: `audio/mp4; codecs
|
1394
|
+
contentType: `audio/mp4; codecs=${codec}`,
|
1395
1395
|
robustness: drmSystemOptions.audioRobustness || '',
|
1396
1396
|
encryptionScheme: drmSystemOptions.audioEncryptionScheme || null
|
1397
1397
|
})),
|
1398
1398
|
videoCapabilities: videoCodecs.map(codec => ({
|
1399
|
-
contentType: `video/mp4; codecs
|
1399
|
+
contentType: `video/mp4; codecs=${codec}`,
|
1400
1400
|
robustness: drmSystemOptions.videoRobustness || '',
|
1401
1401
|
encryptionScheme: drmSystemOptions.videoEncryptionScheme || null
|
1402
1402
|
}))
|
@@ -2926,7 +2926,7 @@ function isCodecMediaSourceSupported(codec, type, preferManagedMediaSource = tru
|
|
2926
2926
|
return (_MediaSource$isTypeSu = MediaSource == null ? void 0 : MediaSource.isTypeSupported(mimeTypeForCodec(codec, type))) != null ? _MediaSource$isTypeSu : false;
|
2927
2927
|
}
|
2928
2928
|
function mimeTypeForCodec(codec, type) {
|
2929
|
-
return `${type}/mp4;codecs
|
2929
|
+
return `${type}/mp4;codecs=${codec}`;
|
2930
2930
|
}
|
2931
2931
|
function videoCodecPreferenceValue(videoCodec) {
|
2932
2932
|
if (videoCodec) {
|
@@ -2977,15 +2977,28 @@ function getCodecCompatibleName(codec, preferManagedMediaSource = true) {
|
|
2977
2977
|
function pickMostCompleteCodecName(parsedCodec, levelCodec) {
|
2978
2978
|
// Parsing of mp4a codecs strings in mp4-tools from media is incomplete as of d8c6c7a
|
2979
2979
|
// so use level codec is parsed codec is unavailable or incomplete
|
2980
|
-
if (parsedCodec && parsedCodec
|
2980
|
+
if (parsedCodec && (parsedCodec.length > 4 || ['ac-3', 'ec-3', 'alac', 'fLaC', 'Opus'].indexOf(parsedCodec) !== -1)) {
|
2981
2981
|
return parsedCodec;
|
2982
2982
|
}
|
2983
|
-
|
2983
|
+
if (levelCodec) {
|
2984
|
+
const levelCodecs = levelCodec.split(',');
|
2985
|
+
if (levelCodecs.length > 1) {
|
2986
|
+
if (parsedCodec) {
|
2987
|
+
for (let i = levelCodecs.length; i--;) {
|
2988
|
+
if (levelCodecs[i].substring(0, 4) === parsedCodec.substring(0, 4)) {
|
2989
|
+
return levelCodecs[i];
|
2990
|
+
}
|
2991
|
+
}
|
2992
|
+
}
|
2993
|
+
return levelCodecs[0];
|
2994
|
+
}
|
2995
|
+
}
|
2996
|
+
return levelCodec || parsedCodec;
|
2984
2997
|
}
|
2985
|
-
function convertAVC1ToAVCOTI(
|
2998
|
+
function convertAVC1ToAVCOTI(videoCodecs) {
|
2986
2999
|
// Convert avc1 codec string from RFC-4281 to RFC-6381 for MediaSource.isTypeSupported
|
2987
3000
|
// Examples: avc1.66.30 to avc1.42001e and avc1.77.30,avc1.66.30 to avc1.4d001e,avc1.42001e.
|
2988
|
-
const codecs =
|
3001
|
+
const codecs = videoCodecs.split(',');
|
2989
3002
|
for (let i = 0; i < codecs.length; i++) {
|
2990
3003
|
const avcdata = codecs[i].split('.');
|
2991
3004
|
if (avcdata.length > 2) {
|
@@ -2997,6 +3010,18 @@ function convertAVC1ToAVCOTI(codec) {
|
|
2997
3010
|
}
|
2998
3011
|
return codecs.join(',');
|
2999
3012
|
}
|
3013
|
+
function fillInMissingAV01Params(videoCodec) {
|
3014
|
+
// Used to fill in incomplete AV1 playlist CODECS strings for mediaCapabilities.decodingInfo queries
|
3015
|
+
if (videoCodec.startsWith('av01.')) {
|
3016
|
+
const av1params = videoCodec.split('.');
|
3017
|
+
const placeholders = ['0', '111', '01', '01', '01', '0'];
|
3018
|
+
for (let i = av1params.length; i > 4 && i < 10; i++) {
|
3019
|
+
av1params[i] = placeholders[i - 4];
|
3020
|
+
}
|
3021
|
+
return av1params.join('.');
|
3022
|
+
}
|
3023
|
+
return videoCodec;
|
3024
|
+
}
|
3000
3025
|
function getM2TSSupportedAudioTypes(preferManagedMediaSource) {
|
3001
3026
|
const MediaSource = getMediaSource(preferManagedMediaSource) || {
|
3002
3027
|
isTypeSupported: () => false
|
@@ -6965,10 +6990,27 @@ class LevelController extends BasePlaylistController {
|
|
6965
6990
|
height,
|
6966
6991
|
unknownCodecs
|
6967
6992
|
} = levelParsed;
|
6993
|
+
let unknownUnsupportedCodecCount = unknownCodecs ? unknownCodecs.length : 0;
|
6994
|
+
if (unknownCodecs) {
|
6995
|
+
// Treat unknown codec as audio or video codec based on passing `isTypeSupported` check
|
6996
|
+
// (allows for playback of any supported codec even if not indexed in utils/codecs)
|
6997
|
+
for (let i = unknownUnsupportedCodecCount; i--;) {
|
6998
|
+
const unknownCodec = unknownCodecs[i];
|
6999
|
+
if (this.isAudioSupported(unknownCodec)) {
|
7000
|
+
levelParsed.audioCodec = audioCodec = audioCodec ? `${audioCodec},${unknownCodec}` : unknownCodec;
|
7001
|
+
unknownUnsupportedCodecCount--;
|
7002
|
+
sampleEntryCodesISO.audio[audioCodec.substring(0, 4)] = 2;
|
7003
|
+
} else if (this.isVideoSupported(unknownCodec)) {
|
7004
|
+
levelParsed.videoCodec = videoCodec = videoCodec ? `${videoCodec},${unknownCodec}` : unknownCodec;
|
7005
|
+
unknownUnsupportedCodecCount--;
|
7006
|
+
sampleEntryCodesISO.video[videoCodec.substring(0, 4)] = 2;
|
7007
|
+
}
|
7008
|
+
}
|
7009
|
+
}
|
6968
7010
|
resolutionFound || (resolutionFound = !!(width && height));
|
6969
7011
|
videoCodecFound || (videoCodecFound = !!videoCodec);
|
6970
7012
|
audioCodecFound || (audioCodecFound = !!audioCodec);
|
6971
|
-
if (
|
7013
|
+
if (unknownUnsupportedCodecCount || audioCodec && !this.isAudioSupported(audioCodec) || videoCodec && !this.isVideoSupported(videoCodec)) {
|
6972
7014
|
return;
|
6973
7015
|
}
|
6974
7016
|
const {
|
@@ -7001,6 +7043,12 @@ class LevelController extends BasePlaylistController {
|
|
7001
7043
|
});
|
7002
7044
|
this.filterAndSortMediaOptions(levels, data, resolutionFound, videoCodecFound, audioCodecFound);
|
7003
7045
|
}
|
7046
|
+
isAudioSupported(codec) {
|
7047
|
+
return areCodecsMediaSourceSupported(codec, 'audio', this.hls.config.preferManagedMediaSource);
|
7048
|
+
}
|
7049
|
+
isVideoSupported(codec) {
|
7050
|
+
return areCodecsMediaSourceSupported(codec, 'video', this.hls.config.preferManagedMediaSource);
|
7051
|
+
}
|
7004
7052
|
filterAndSortMediaOptions(filteredLevels, data, resolutionFound, videoCodecFound, audioCodecFound) {
|
7005
7053
|
let audioTracks = [];
|
7006
7054
|
let subtitleTracks = [];
|
@@ -7036,10 +7084,7 @@ class LevelController extends BasePlaylistController {
|
|
7036
7084
|
return;
|
7037
7085
|
}
|
7038
7086
|
if (data.audioTracks) {
|
7039
|
-
|
7040
|
-
preferManagedMediaSource
|
7041
|
-
} = this.hls.config;
|
7042
|
-
audioTracks = data.audioTracks.filter(track => !track.audioCodec || areCodecsMediaSourceSupported(track.audioCodec, 'audio', preferManagedMediaSource));
|
7087
|
+
audioTracks = data.audioTracks.filter(track => !track.audioCodec || this.isAudioSupported(track.audioCodec));
|
7043
7088
|
// Assign ids after filtering as array indices by group-id
|
7044
7089
|
assignTrackIdsByGroup(audioTracks);
|
7045
7090
|
}
|
@@ -10768,7 +10813,7 @@ function changeTypeSupported() {
|
|
10768
10813
|
return typeof (sourceBuffer == null ? void 0 : (_sourceBuffer$prototy = sourceBuffer.prototype) == null ? void 0 : _sourceBuffer$prototy.changeType) === 'function';
|
10769
10814
|
}
|
10770
10815
|
|
10771
|
-
const version = "1.5.14-0.canary.
|
10816
|
+
const version = "1.5.14-0.canary.10670";
|
10772
10817
|
|
10773
10818
|
// ensure the worker ends up in the bundle
|
10774
10819
|
// If the worker should not be included this gets aliased to empty.js
|
@@ -12521,7 +12566,7 @@ class HevcVideoParser extends BaseVideoParser {
|
|
12521
12566
|
track.params[prop] = config[prop];
|
12522
12567
|
}
|
12523
12568
|
}
|
12524
|
-
if (
|
12569
|
+
if (track.vps !== undefined && track.vps[0] === this.initVPS) {
|
12525
12570
|
track.pps.push(unit.data);
|
12526
12571
|
}
|
12527
12572
|
}
|
@@ -12572,6 +12617,12 @@ class HevcVideoParser extends BaseVideoParser {
|
|
12572
12617
|
}
|
12573
12618
|
return new Uint8Array(dst.buffer, 0, dstIdx);
|
12574
12619
|
}
|
12620
|
+
pushAccessUnit(VideoSample, videoTrack) {
|
12621
|
+
super.pushAccessUnit(VideoSample, videoTrack);
|
12622
|
+
if (this.initVPS) {
|
12623
|
+
this.initVPS = null; // null initVPS to prevent possible track's sps/pps growth until next VPS
|
12624
|
+
}
|
12625
|
+
}
|
12575
12626
|
readVPS(vps) {
|
12576
12627
|
const eg = new ExpGolomb(vps);
|
12577
12628
|
// remove header
|
@@ -15610,7 +15661,7 @@ class PassThroughRemuxer {
|
|
15610
15661
|
}
|
15611
15662
|
const initData = this.initData = parseInitSegment(initSegment);
|
15612
15663
|
|
15613
|
-
// Get codec from initSegment
|
15664
|
+
// Get codec from initSegment
|
15614
15665
|
if (initData.audio) {
|
15615
15666
|
audioCodec = getParsedTrackCodec(initData.audio, ElementaryStreamTypes.AUDIO);
|
15616
15667
|
}
|
@@ -15765,20 +15816,13 @@ function getParsedTrackCodec(track, type) {
|
|
15765
15816
|
const preferManagedMediaSource = false;
|
15766
15817
|
return getCodecCompatibleName(parsedCodec, preferManagedMediaSource);
|
15767
15818
|
}
|
15768
|
-
|
15769
|
-
|
15770
|
-
return result;
|
15819
|
+
logger.warn(`Unhandled audio codec "${parsedCodec}" in mp4 MAP`);
|
15820
|
+
return parsedCodec || 'mp4a';
|
15771
15821
|
}
|
15772
15822
|
// Provide defaults based on codec type
|
15773
15823
|
// This allows for some playback of some fmp4 playlists without CODECS defined in manifest
|
15774
|
-
|
15775
|
-
|
15776
|
-
return 'hvc1.1.6.L120.90';
|
15777
|
-
}
|
15778
|
-
if (parsedCodec === 'av01') {
|
15779
|
-
return 'av01.0.04M.08';
|
15780
|
-
}
|
15781
|
-
return 'avc1.42e01e';
|
15824
|
+
logger.warn(`Unhandled video codec "${parsedCodec}" in mp4 MAP`);
|
15825
|
+
return parsedCodec || 'avc1';
|
15782
15826
|
}
|
15783
15827
|
|
15784
15828
|
let now;
|
@@ -18244,7 +18288,13 @@ class StreamController extends BaseStreamController {
|
|
18244
18288
|
audiovideo
|
18245
18289
|
} = tracks;
|
18246
18290
|
if (audio) {
|
18247
|
-
let audioCodec = currentLevel.audioCodec;
|
18291
|
+
let audioCodec = pickMostCompleteCodecName(audio.codec, currentLevel.audioCodec);
|
18292
|
+
// Add level and profile to make up for passthrough-remuxer not being able to parse full codec
|
18293
|
+
// (logger warning "Unhandled audio codec...")
|
18294
|
+
if (audioCodec === 'mp4a') {
|
18295
|
+
audioCodec = 'mp4a.40.5';
|
18296
|
+
}
|
18297
|
+
// Handle `audioCodecSwitch`
|
18248
18298
|
const ua = navigator.userAgent.toLowerCase();
|
18249
18299
|
if (this.audioCodecSwitch) {
|
18250
18300
|
if (audioCodec) {
|
@@ -18279,7 +18329,24 @@ class StreamController extends BaseStreamController {
|
|
18279
18329
|
if (video) {
|
18280
18330
|
video.levelCodec = currentLevel.videoCodec;
|
18281
18331
|
video.id = 'main';
|
18282
|
-
|
18332
|
+
const parsedVideoCodec = video.codec;
|
18333
|
+
if ((parsedVideoCodec == null ? void 0 : parsedVideoCodec.length) === 4) {
|
18334
|
+
// Make up for passthrough-remuxer not being able to parse full codec
|
18335
|
+
// (logger warning "Unhandled video codec...")
|
18336
|
+
switch (parsedVideoCodec) {
|
18337
|
+
case 'hvc1':
|
18338
|
+
case 'hev1':
|
18339
|
+
video.codec = 'hvc1.1.6.L120.90';
|
18340
|
+
break;
|
18341
|
+
case 'av01':
|
18342
|
+
video.codec = 'av01.0.04M.08';
|
18343
|
+
break;
|
18344
|
+
case 'avc1':
|
18345
|
+
video.codec = 'avc1.42e01e';
|
18346
|
+
break;
|
18347
|
+
}
|
18348
|
+
}
|
18349
|
+
this.log(`Init video buffer, container:${video.container}, codecs[level/parsed]=[${currentLevel.videoCodec || ''}/${parsedVideoCodec}${video.codec !== parsedVideoCodec ? ' parsed-corrected=' + video.codec : ''}}]`);
|
18283
18350
|
delete tracks.audiovideo;
|
18284
18351
|
}
|
18285
18352
|
if (audiovideo) {
|
@@ -18601,26 +18668,29 @@ function requiresMediaCapabilitiesDecodingInfo(level, audioTracksByGroup, curren
|
|
18601
18668
|
function getMediaDecodingInfoPromise(level, audioTracksByGroup, mediaCapabilities) {
|
18602
18669
|
const videoCodecs = level.videoCodec;
|
18603
18670
|
const audioCodecs = level.audioCodec;
|
18604
|
-
if (!videoCodecs
|
18671
|
+
if (!videoCodecs && !audioCodecs || !mediaCapabilities) {
|
18605
18672
|
return Promise.resolve(SUPPORTED_INFO_DEFAULT);
|
18606
18673
|
}
|
18607
|
-
const
|
18608
|
-
|
18609
|
-
|
18610
|
-
|
18611
|
-
|
18612
|
-
|
18613
|
-
|
18614
|
-
|
18615
|
-
|
18616
|
-
|
18617
|
-
|
18618
|
-
|
18619
|
-
|
18620
|
-
|
18621
|
-
|
18622
|
-
|
18623
|
-
|
18674
|
+
const configurations = [];
|
18675
|
+
if (videoCodecs) {
|
18676
|
+
const baseVideoConfiguration = {
|
18677
|
+
width: level.width,
|
18678
|
+
height: level.height,
|
18679
|
+
bitrate: Math.ceil(Math.max(level.bitrate * 0.9, level.averageBitrate)),
|
18680
|
+
// Assume a framerate of 30fps since MediaCapabilities will not accept Level default of 0.
|
18681
|
+
framerate: level.frameRate || 30
|
18682
|
+
};
|
18683
|
+
const videoRange = level.videoRange;
|
18684
|
+
if (videoRange !== 'SDR') {
|
18685
|
+
baseVideoConfiguration.transferFunction = videoRange.toLowerCase();
|
18686
|
+
}
|
18687
|
+
configurations.push.apply(configurations, videoCodecs.split(',').map(videoCodec => ({
|
18688
|
+
type: 'media-source',
|
18689
|
+
video: _objectSpread2(_objectSpread2({}, baseVideoConfiguration), {}, {
|
18690
|
+
contentType: mimeTypeForCodec(fillInMissingAV01Params(videoCodec), 'video')
|
18691
|
+
})
|
18692
|
+
})));
|
18693
|
+
}
|
18624
18694
|
if (audioCodecs && level.audioGroups) {
|
18625
18695
|
level.audioGroups.forEach(audioGroupId => {
|
18626
18696
|
var _audioTracksByGroup$g;
|
@@ -22362,7 +22432,7 @@ transfer tracks: ${JSON.stringify(transferredTracks, (key, value) => key === 'in
|
|
22362
22432
|
if (trackName.slice(0, 5) === 'audio') {
|
22363
22433
|
trackCodec = getCodecCompatibleName(trackCodec, this.appendSource);
|
22364
22434
|
}
|
22365
|
-
this.log(`switching codec ${sbCodec} to ${
|
22435
|
+
this.log(`switching codec ${sbCodec} to ${trackCodec}`);
|
22366
22436
|
if (trackCodec !== (track.pendingCodec || track.codec)) {
|
22367
22437
|
track.pendingCodec = trackCodec;
|
22368
22438
|
}
|
@@ -23045,7 +23115,7 @@ transfer tracks: ${JSON.stringify(transferredTracks, (key, value) => key === 'in
|
|
23045
23115
|
}
|
23046
23116
|
}
|
23047
23117
|
getTrackCodec(track, trackName) {
|
23048
|
-
const codec = track.codec
|
23118
|
+
const codec = pickMostCompleteCodecName(track.codec, track.levelCodec);
|
23049
23119
|
if (codec) {
|
23050
23120
|
if (trackName.slice(0, 5) === 'audio') {
|
23051
23121
|
return getCodecCompatibleName(codec, this.appendSource);
|
@@ -33700,6 +33770,14 @@ class Hls {
|
|
33700
33770
|
var _this$interstitialsCo;
|
33701
33771
|
return ((_this$interstitialsCo = this.interstitialsController) == null ? void 0 : _this$interstitialsCo.interstitialsManager) || null;
|
33702
33772
|
}
|
33773
|
+
|
33774
|
+
/**
|
33775
|
+
* returns mediaCapabilities.decodingInfo for a variant/rendition
|
33776
|
+
*/
|
33777
|
+
getMediaDecodingInfo(level, audioTracks = this.allAudioTracks) {
|
33778
|
+
const audioTracksByGroup = getAudioTracksByGroup(audioTracks);
|
33779
|
+
return getMediaDecodingInfoPromise(level, audioTracksByGroup, navigator.mediaCapabilities);
|
33780
|
+
}
|
33703
33781
|
}
|
33704
33782
|
Hls.defaultConfig = void 0;
|
33705
33783
|
|