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.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.10668"}`);
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="${codec}"`,
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="${codec}"`,
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="${codec}"`;
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 !== 'mp4a') {
2980
+ if (parsedCodec && (parsedCodec.length > 4 || ['ac-3', 'ec-3', 'alac', 'fLaC', 'Opus'].indexOf(parsedCodec) !== -1)) {
2981
2981
  return parsedCodec;
2982
2982
  }
2983
- return levelCodec ? levelCodec.split(',')[0] : levelCodec;
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(codec) {
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 = codec.split(',');
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 (unknownCodecs != null && unknownCodecs.length || audioCodec && !areCodecsMediaSourceSupported(audioCodec, 'audio', preferManagedMediaSource) || videoCodec && !areCodecsMediaSourceSupported(videoCodec, 'video', preferManagedMediaSource)) {
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
- const {
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.10668";
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 (this.initVPS !== null || track.pps.length === 0) {
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 or fallback to default
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
- const result = 'mp4a.40.5';
15769
- this.logger.info(`Parsed audio codec "${parsedCodec}" or audio object type not handled. Using "${result}"`);
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
- this.logger.warn(`Unhandled video codec "${parsedCodec}"`);
15775
- if (parsedCodec === 'hvc1' || parsedCodec === 'hev1') {
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
- this.log(`Init video buffer, container:${video.container}, codecs[level/parsed]=[${currentLevel.videoCodec || ''}/${video.codec}]`);
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 || !audioCodecs || !mediaCapabilities) {
18671
+ if (!videoCodecs && !audioCodecs || !mediaCapabilities) {
18605
18672
  return Promise.resolve(SUPPORTED_INFO_DEFAULT);
18606
18673
  }
18607
- const baseVideoConfiguration = {
18608
- width: level.width,
18609
- height: level.height,
18610
- bitrate: Math.ceil(Math.max(level.bitrate * 0.9, level.averageBitrate)),
18611
- // Assume a framerate of 30fps since MediaCapabilities will not accept Level default of 0.
18612
- framerate: level.frameRate || 30
18613
- };
18614
- const videoRange = level.videoRange;
18615
- if (videoRange !== 'SDR') {
18616
- baseVideoConfiguration.transferFunction = videoRange.toLowerCase();
18617
- }
18618
- const configurations = videoCodecs.split(',').map(videoCodec => ({
18619
- type: 'media-source',
18620
- video: _objectSpread2(_objectSpread2({}, baseVideoConfiguration), {}, {
18621
- contentType: mimeTypeForCodec(videoCodec, 'video')
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 ${codec}`);
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 || track.levelCodec;
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