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.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.10666"}`);
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();
@@ -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.10666";
10816
+ const version = "1.5.14-0.canary.10669";
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
@@ -15610,7 +15655,7 @@ class PassThroughRemuxer {
15610
15655
  }
15611
15656
  const initData = this.initData = parseInitSegment(initSegment);
15612
15657
 
15613
- // Get codec from initSegment or fallback to default
15658
+ // Get codec from initSegment
15614
15659
  if (initData.audio) {
15615
15660
  audioCodec = getParsedTrackCodec(initData.audio, ElementaryStreamTypes.AUDIO);
15616
15661
  }
@@ -15765,20 +15810,13 @@ function getParsedTrackCodec(track, type) {
15765
15810
  const preferManagedMediaSource = false;
15766
15811
  return getCodecCompatibleName(parsedCodec, preferManagedMediaSource);
15767
15812
  }
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;
15813
+ logger.warn(`Unhandled audio codec "${parsedCodec}" in mp4 MAP`);
15814
+ return parsedCodec || 'mp4a';
15771
15815
  }
15772
15816
  // Provide defaults based on codec type
15773
15817
  // 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';
15818
+ logger.warn(`Unhandled video codec "${parsedCodec}" in mp4 MAP`);
15819
+ return parsedCodec || 'avc1';
15782
15820
  }
15783
15821
 
15784
15822
  let now;
@@ -18244,7 +18282,13 @@ class StreamController extends BaseStreamController {
18244
18282
  audiovideo
18245
18283
  } = tracks;
18246
18284
  if (audio) {
18247
- let audioCodec = currentLevel.audioCodec;
18285
+ let audioCodec = pickMostCompleteCodecName(audio.codec, currentLevel.audioCodec);
18286
+ // Add level and profile to make up for passthrough-remuxer not being able to parse full codec
18287
+ // (logger warning "Unhandled audio codec...")
18288
+ if (audioCodec === 'mp4a') {
18289
+ audioCodec = 'mp4a.40.5';
18290
+ }
18291
+ // Handle `audioCodecSwitch`
18248
18292
  const ua = navigator.userAgent.toLowerCase();
18249
18293
  if (this.audioCodecSwitch) {
18250
18294
  if (audioCodec) {
@@ -18279,7 +18323,24 @@ class StreamController extends BaseStreamController {
18279
18323
  if (video) {
18280
18324
  video.levelCodec = currentLevel.videoCodec;
18281
18325
  video.id = 'main';
18282
- this.log(`Init video buffer, container:${video.container}, codecs[level/parsed]=[${currentLevel.videoCodec || ''}/${video.codec}]`);
18326
+ const parsedVideoCodec = video.codec;
18327
+ if ((parsedVideoCodec == null ? void 0 : parsedVideoCodec.length) === 4) {
18328
+ // Make up for passthrough-remuxer not being able to parse full codec
18329
+ // (logger warning "Unhandled video codec...")
18330
+ switch (parsedVideoCodec) {
18331
+ case 'hvc1':
18332
+ case 'hev1':
18333
+ video.codec = 'hvc1.1.6.L120.90';
18334
+ break;
18335
+ case 'av01':
18336
+ video.codec = 'av01.0.04M.08';
18337
+ break;
18338
+ case 'avc1':
18339
+ video.codec = 'avc1.42e01e';
18340
+ break;
18341
+ }
18342
+ }
18343
+ this.log(`Init video buffer, container:${video.container}, codecs[level/parsed]=[${currentLevel.videoCodec || ''}/${parsedVideoCodec}${video.codec !== parsedVideoCodec ? ' parsed-corrected=' + video.codec : ''}}]`);
18283
18344
  delete tracks.audiovideo;
18284
18345
  }
18285
18346
  if (audiovideo) {
@@ -18601,26 +18662,29 @@ function requiresMediaCapabilitiesDecodingInfo(level, audioTracksByGroup, curren
18601
18662
  function getMediaDecodingInfoPromise(level, audioTracksByGroup, mediaCapabilities) {
18602
18663
  const videoCodecs = level.videoCodec;
18603
18664
  const audioCodecs = level.audioCodec;
18604
- if (!videoCodecs || !audioCodecs || !mediaCapabilities) {
18665
+ if (!videoCodecs && !audioCodecs || !mediaCapabilities) {
18605
18666
  return Promise.resolve(SUPPORTED_INFO_DEFAULT);
18606
18667
  }
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
- }));
18668
+ const configurations = [];
18669
+ if (videoCodecs) {
18670
+ const baseVideoConfiguration = {
18671
+ width: level.width,
18672
+ height: level.height,
18673
+ bitrate: Math.ceil(Math.max(level.bitrate * 0.9, level.averageBitrate)),
18674
+ // Assume a framerate of 30fps since MediaCapabilities will not accept Level default of 0.
18675
+ framerate: level.frameRate || 30
18676
+ };
18677
+ const videoRange = level.videoRange;
18678
+ if (videoRange !== 'SDR') {
18679
+ baseVideoConfiguration.transferFunction = videoRange.toLowerCase();
18680
+ }
18681
+ configurations.push.apply(configurations, videoCodecs.split(',').map(videoCodec => ({
18682
+ type: 'media-source',
18683
+ video: _objectSpread2(_objectSpread2({}, baseVideoConfiguration), {}, {
18684
+ contentType: mimeTypeForCodec(fillInMissingAV01Params(videoCodec), 'video')
18685
+ })
18686
+ })));
18687
+ }
18624
18688
  if (audioCodecs && level.audioGroups) {
18625
18689
  level.audioGroups.forEach(audioGroupId => {
18626
18690
  var _audioTracksByGroup$g;
@@ -22362,7 +22426,7 @@ transfer tracks: ${JSON.stringify(transferredTracks, (key, value) => key === 'in
22362
22426
  if (trackName.slice(0, 5) === 'audio') {
22363
22427
  trackCodec = getCodecCompatibleName(trackCodec, this.appendSource);
22364
22428
  }
22365
- this.log(`switching codec ${sbCodec} to ${codec}`);
22429
+ this.log(`switching codec ${sbCodec} to ${trackCodec}`);
22366
22430
  if (trackCodec !== (track.pendingCodec || track.codec)) {
22367
22431
  track.pendingCodec = trackCodec;
22368
22432
  }
@@ -23045,7 +23109,7 @@ transfer tracks: ${JSON.stringify(transferredTracks, (key, value) => key === 'in
23045
23109
  }
23046
23110
  }
23047
23111
  getTrackCodec(track, trackName) {
23048
- const codec = track.codec || track.levelCodec;
23112
+ const codec = pickMostCompleteCodecName(track.codec, track.levelCodec);
23049
23113
  if (codec) {
23050
23114
  if (trackName.slice(0, 5) === 'audio') {
23051
23115
  return getCodecCompatibleName(codec, this.appendSource);
@@ -33700,6 +33764,14 @@ class Hls {
33700
33764
  var _this$interstitialsCo;
33701
33765
  return ((_this$interstitialsCo = this.interstitialsController) == null ? void 0 : _this$interstitialsCo.interstitialsManager) || null;
33702
33766
  }
33767
+
33768
+ /**
33769
+ * returns mediaCapabilities.decodingInfo for a variant/rendition
33770
+ */
33771
+ getMediaDecodingInfo(level, audioTracks = this.allAudioTracks) {
33772
+ const audioTracksByGroup = getAudioTracksByGroup(audioTracks);
33773
+ return getMediaDecodingInfoPromise(level, audioTracksByGroup, navigator.mediaCapabilities);
33774
+ }
33703
33775
  }
33704
33776
  Hls.defaultConfig = void 0;
33705
33777