hls.js 1.5.12-0.canary.10351 → 1.5.12-0.canary.10353

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
@@ -420,7 +420,7 @@ function enableLogs(debugConfig, context, id) {
420
420
  // Some browsers don't allow to use bind on console object anyway
421
421
  // fallback to default if needed
422
422
  try {
423
- newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.5.12-0.canary.10351"}`);
423
+ newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.5.12-0.canary.10353"}`);
424
424
  } catch (e) {
425
425
  /* log fn threw an exception. All logger methods are no-ops. */
426
426
  return createLogger();
@@ -6990,10 +6990,9 @@ function getVideoSelectionOptions(currentVideoRange, videoPreference) {
6990
6990
  }
6991
6991
  if (videoPreference) {
6992
6992
  allowedVideoRanges = videoPreference.allowedVideoRanges || VideoRangeValues.slice(0);
6993
- preferHDR = videoPreference.preferHDR !== undefined ? videoPreference.preferHDR : isHdrSupported();
6994
- if (preferHDR) {
6995
- allowedVideoRanges = allowedVideoRanges.filter(range => range !== 'SDR');
6996
- } else {
6993
+ const allowAutoPreferHDR = allowedVideoRanges.join('') !== 'SDR' && !videoPreference.videoCodec;
6994
+ preferHDR = videoPreference.preferHDR !== undefined ? videoPreference.preferHDR : allowAutoPreferHDR && isHdrSupported();
6995
+ if (!preferHDR) {
6997
6996
  allowedVideoRanges = ['SDR'];
6998
6997
  }
6999
6998
  }
@@ -7007,13 +7006,15 @@ function getStartCodecTier(codecTiers, currentVideoRange, currentBw, audioPrefer
7007
7006
  const codecSets = Object.keys(codecTiers);
7008
7007
  const channelsPreference = audioPreference == null ? void 0 : audioPreference.channels;
7009
7008
  const audioCodecPreference = audioPreference == null ? void 0 : audioPreference.audioCodec;
7009
+ const videoCodecPreference = videoPreference == null ? void 0 : videoPreference.videoCodec;
7010
7010
  const preferStereo = channelsPreference && parseInt(channelsPreference) === 2;
7011
7011
  // Use first level set to determine stereo, and minimum resolution and framerate
7012
- let hasStereo = true;
7012
+ let hasStereo = false;
7013
7013
  let hasCurrentVideoRange = false;
7014
7014
  let minHeight = Infinity;
7015
7015
  let minFramerate = Infinity;
7016
7016
  let minBitrate = Infinity;
7017
+ let minIndex = Infinity;
7017
7018
  let selectedScore = 0;
7018
7019
  let videoRanges = [];
7019
7020
  const {
@@ -7022,14 +7023,13 @@ function getStartCodecTier(codecTiers, currentVideoRange, currentBw, audioPrefer
7022
7023
  } = getVideoSelectionOptions(currentVideoRange, videoPreference);
7023
7024
  for (let i = codecSets.length; i--;) {
7024
7025
  const tier = codecTiers[codecSets[i]];
7025
- hasStereo = tier.channels[2] > 0;
7026
+ hasStereo || (hasStereo = tier.channels[2] > 0);
7026
7027
  minHeight = Math.min(minHeight, tier.minHeight);
7027
7028
  minFramerate = Math.min(minFramerate, tier.minFramerate);
7028
7029
  minBitrate = Math.min(minBitrate, tier.minBitrate);
7029
7030
  const matchingVideoRanges = allowedVideoRanges.filter(range => tier.videoRanges[range] > 0);
7030
7031
  if (matchingVideoRanges.length > 0) {
7031
7032
  hasCurrentVideoRange = true;
7032
- videoRanges = matchingVideoRanges;
7033
7033
  }
7034
7034
  }
7035
7035
  minHeight = isFiniteNumber(minHeight) ? minHeight : 0;
@@ -7041,7 +7041,6 @@ function getStartCodecTier(codecTiers, currentVideoRange, currentBw, audioPrefer
7041
7041
  // If there are no variants with matching preference, set currentVideoRange to undefined
7042
7042
  if (!hasCurrentVideoRange) {
7043
7043
  currentVideoRange = undefined;
7044
- videoRanges = [];
7045
7044
  }
7046
7045
  const codecSet = codecSets.reduce((selected, candidate) => {
7047
7046
  // Remove candiates which do not meet bitrate, default audio, stereo or channels preference, 1080p or lower, 30fps or lower, or SDR/HDR selection if present
@@ -7049,6 +7048,7 @@ function getStartCodecTier(codecTiers, currentVideoRange, currentBw, audioPrefer
7049
7048
  if (candidate === selected) {
7050
7049
  return selected;
7051
7050
  }
7051
+ videoRanges = hasCurrentVideoRange ? allowedVideoRanges.filter(range => candidateTier.videoRanges[range] > 0) : [];
7052
7052
  if (candidateTier.minBitrate > currentBw) {
7053
7053
  logStartCodecCandidateIgnored(candidate, `min bitrate of ${candidateTier.minBitrate} > current estimate of ${currentBw}`);
7054
7054
  return selected;
@@ -7082,6 +7082,10 @@ function getStartCodecTier(codecTiers, currentVideoRange, currentBw, audioPrefer
7082
7082
  logStartCodecCandidateIgnored(candidate, `no variants with VIDEO-RANGE of ${JSON.stringify(videoRanges)} found`);
7083
7083
  return selected;
7084
7084
  }
7085
+ if (videoCodecPreference && candidate.indexOf(videoCodecPreference.substring(0, 4)) % 5 !== 0) {
7086
+ logStartCodecCandidateIgnored(candidate, `video codec preference "${videoCodecPreference}" not found`);
7087
+ return selected;
7088
+ }
7085
7089
  if (candidateTier.maxScore < selectedScore) {
7086
7090
  logStartCodecCandidateIgnored(candidate, `max score of ${candidateTier.maxScore} < selected max of ${selectedScore}`);
7087
7091
  return selected;
@@ -7090,6 +7094,7 @@ function getStartCodecTier(codecTiers, currentVideoRange, currentBw, audioPrefer
7090
7094
  if (selected && (codecsSetSelectionPreferenceValue(candidate) >= codecsSetSelectionPreferenceValue(selected) || candidateTier.fragmentError > codecTiers[selected].fragmentError)) {
7091
7095
  return selected;
7092
7096
  }
7097
+ minIndex = candidateTier.minIndex;
7093
7098
  selectedScore = candidateTier.maxScore;
7094
7099
  return candidate;
7095
7100
  }, undefined);
@@ -7098,7 +7103,8 @@ function getStartCodecTier(codecTiers, currentVideoRange, currentBw, audioPrefer
7098
7103
  videoRanges,
7099
7104
  preferHDR,
7100
7105
  minFramerate,
7101
- minBitrate
7106
+ minBitrate,
7107
+ minIndex
7102
7108
  };
7103
7109
  }
7104
7110
  function logStartCodecCandidateIgnored(codeSet, reason) {
@@ -7136,7 +7142,7 @@ function getAudioTracksByGroup(allAudioTracks) {
7136
7142
  });
7137
7143
  }
7138
7144
  function getCodecTiers(levels, audioTracksByGroup, minAutoLevel, maxAutoLevel) {
7139
- return levels.slice(minAutoLevel, maxAutoLevel + 1).reduce((tiers, level) => {
7145
+ return levels.slice(minAutoLevel, maxAutoLevel + 1).reduce((tiers, level, index) => {
7140
7146
  if (!level.codecSet) {
7141
7147
  return tiers;
7142
7148
  }
@@ -7147,6 +7153,7 @@ function getCodecTiers(levels, audioTracksByGroup, minAutoLevel, maxAutoLevel) {
7147
7153
  minBitrate: Infinity,
7148
7154
  minHeight: Infinity,
7149
7155
  minFramerate: Infinity,
7156
+ minIndex: index,
7150
7157
  maxScore: 0,
7151
7158
  videoRanges: {
7152
7159
  SDR: 0
@@ -7162,6 +7169,7 @@ function getCodecTiers(levels, audioTracksByGroup, minAutoLevel, maxAutoLevel) {
7162
7169
  const lesserWidthOrHeight = Math.min(level.height, level.width);
7163
7170
  tier.minHeight = Math.min(tier.minHeight, lesserWidthOrHeight);
7164
7171
  tier.minFramerate = Math.min(tier.minFramerate, level.frameRate);
7172
+ tier.minIndex = Math.min(tier.minIndex, index);
7165
7173
  tier.maxScore = Math.max(tier.maxScore, level.score);
7166
7174
  tier.fragmentError += level.fragmentError;
7167
7175
  tier.videoRanges[level.videoRange] = (tier.videoRanges[level.videoRange] || 0) + 1;
@@ -7785,6 +7793,7 @@ class AbrController extends Logger {
7785
7793
  videoPreference
7786
7794
  } = config;
7787
7795
  const audioTracksByGroup = this.audioTracksByGroup || (this.audioTracksByGroup = getAudioTracksByGroup(allAudioTracks));
7796
+ let minStartIndex = -1;
7788
7797
  if (firstSelection) {
7789
7798
  if (this.firstSelection !== -1) {
7790
7799
  return this.firstSelection;
@@ -7796,8 +7805,10 @@ class AbrController extends Logger {
7796
7805
  videoRanges,
7797
7806
  minFramerate,
7798
7807
  minBitrate,
7808
+ minIndex,
7799
7809
  preferHDR
7800
7810
  } = startTier;
7811
+ minStartIndex = minIndex;
7801
7812
  currentCodecSet = codecSet;
7802
7813
  currentVideoRange = preferHDR ? videoRanges[videoRanges.length - 1] : videoRanges[0];
7803
7814
  currentFrameRate = minFramerate;
@@ -7846,8 +7857,10 @@ class AbrController extends Logger {
7846
7857
  // skip candidates which change codec-family or video-range,
7847
7858
  // and which decrease or increase frame-rate for up and down-switch respectfully
7848
7859
  if (currentCodecSet && levelInfo.codecSet !== currentCodecSet || currentVideoRange && levelInfo.videoRange !== currentVideoRange || upSwitch && currentFrameRate > levelInfo.frameRate || !upSwitch && currentFrameRate > 0 && currentFrameRate < levelInfo.frameRate || levelInfo.supportedResult && !((_levelInfo$supportedR = levelInfo.supportedResult.decodingInfoResults) != null && _levelInfo$supportedR[0].smooth)) {
7849
- levelsSkipped.push(i);
7850
- continue;
7860
+ if (firstSelection && i !== minStartIndex) {
7861
+ levelsSkipped.push(i);
7862
+ continue;
7863
+ }
7851
7864
  }
7852
7865
  const levelDetails = levelInfo.details;
7853
7866
  const avgDuration = (partCurrent ? levelDetails == null ? void 0 : levelDetails.partTarget : levelDetails == null ? void 0 : levelDetails.averagetargetduration) || currentFragDuration;
@@ -7882,7 +7895,7 @@ class AbrController extends Logger {
7882
7895
  if (levelsSkipped.length) {
7883
7896
  this.trace(`Skipped level(s) ${levelsSkipped.join(',')} of ${maxAutoLevel} max with CODECS and VIDEO-RANGE:"${levels[levelsSkipped[0]].codecs}" ${levels[levelsSkipped[0]].videoRange}; not compatible with "${level.codecs}" ${currentVideoRange}`);
7884
7897
  }
7885
- this.info(`switch candidate:${selectionBaseLevel}->${i} adjustedbw(${Math.round(adjustedbw)})-bitrate=${Math.round(adjustedbw - bitrate)} ttfb:${ttfbEstimateSec.toFixed(1)} avgDuration:${avgDuration.toFixed(1)} maxFetchDuration:${maxFetchDuration.toFixed(1)} fetchDuration:${fetchDuration.toFixed(1)} firstSelection:${firstSelection} codecSet:${currentCodecSet} videoRange:${currentVideoRange} hls.loadLevel:${loadLevel}`);
7898
+ this.info(`switch candidate:${selectionBaseLevel}->${i} adjustedbw(${Math.round(adjustedbw)})-bitrate=${Math.round(adjustedbw - bitrate)} ttfb:${ttfbEstimateSec.toFixed(1)} avgDuration:${avgDuration.toFixed(1)} maxFetchDuration:${maxFetchDuration.toFixed(1)} fetchDuration:${fetchDuration.toFixed(1)} firstSelection:${firstSelection} codecSet:${level.codecSet} videoRange:${level.videoRange} hls.loadLevel:${loadLevel}`);
7886
7899
  }
7887
7900
  if (firstSelection) {
7888
7901
  this.firstSelection = i;
@@ -11948,6 +11961,20 @@ class BaseVideoParser {
11948
11961
  length: 0
11949
11962
  };
11950
11963
  }
11964
+ getLastNalUnit(samples) {
11965
+ var _VideoSample;
11966
+ let VideoSample = this.VideoSample;
11967
+ let lastUnit;
11968
+ // try to fallback to previous sample if current one is empty
11969
+ if (!VideoSample || VideoSample.units.length === 0) {
11970
+ VideoSample = samples[samples.length - 1];
11971
+ }
11972
+ if ((_VideoSample = VideoSample) != null && _VideoSample.units) {
11973
+ const units = VideoSample.units;
11974
+ lastUnit = units[units.length - 1];
11975
+ }
11976
+ return lastUnit;
11977
+ }
11951
11978
  pushAccessUnit(VideoSample, videoTrack) {
11952
11979
  if (VideoSample.units.length && VideoSample.frame) {
11953
11980
  // if sample does not have PTS/DTS, patch with last sample PTS/DTS
@@ -11970,7 +11997,7 @@ class BaseVideoParser {
11970
11997
  logger.log(VideoSample.pts + '/' + VideoSample.dts + ':' + VideoSample.debug);
11971
11998
  }
11972
11999
  }
11973
- parseNALu(track, array, last) {
12000
+ parseNALu(track, array, endOfSegment) {
11974
12001
  const len = array.byteLength;
11975
12002
  let state = track.naluState || 0;
11976
12003
  const lastState = state;
@@ -12012,10 +12039,6 @@ class BaseVideoParser {
12012
12039
  data: array.subarray(lastUnitStart, overflow),
12013
12040
  type: lastUnitType
12014
12041
  };
12015
- if (track.lastNalu) {
12016
- units.push(track.lastNalu);
12017
- track.lastNalu = null;
12018
- }
12019
12042
  // logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
12020
12043
  units.push(unit);
12021
12044
  } else {
@@ -12023,7 +12046,7 @@ class BaseVideoParser {
12023
12046
  // first check if start code delimiter is overlapping between 2 PES packets,
12024
12047
  // ie it started in last packet (lastState not zero)
12025
12048
  // and ended at the beginning of this PES packet (i <= 4 - lastState)
12026
- const lastUnit = track.lastNalu;
12049
+ const lastUnit = this.getLastNalUnit(track.samples);
12027
12050
  if (lastUnit) {
12028
12051
  if (lastState && i <= 4 - lastState) {
12029
12052
  // start delimiter overlapping between PES packets
@@ -12040,8 +12063,6 @@ class BaseVideoParser {
12040
12063
  // logger.log('first NALU found with overflow:' + overflow);
12041
12064
  lastUnit.data = appendUint8Array(lastUnit.data, array.subarray(0, overflow));
12042
12065
  lastUnit.state = 0;
12043
- units.push(lastUnit);
12044
- track.lastNalu = null;
12045
12066
  }
12046
12067
  }
12047
12068
  }
@@ -12066,21 +12087,15 @@ class BaseVideoParser {
12066
12087
  type: lastUnitType,
12067
12088
  state: state
12068
12089
  };
12069
- if (!last) {
12070
- track.lastNalu = unit;
12071
- // logger.log('store NALu to push it on next PES');
12072
- } else {
12073
- units.push(unit);
12074
- // logger.log('pushing NALU, type/size/state:' + unit.type + '/' + unit.data.byteLength + '/' + state);
12075
- }
12076
- } else if (units.length === 0) {
12077
- // no NALu found
12090
+ units.push(unit);
12091
+ // logger.log('pushing NALU, type/size/state:' + unit.type + '/' + unit.data.byteLength + '/' + state);
12092
+ }
12093
+ // no NALu found
12094
+ if (units.length === 0) {
12078
12095
  // append pes.data to previous NAL unit
12079
- const lastUnit = track.lastNalu;
12096
+ const lastUnit = this.getLastNalUnit(track.samples);
12080
12097
  if (lastUnit) {
12081
12098
  lastUnit.data = appendUint8Array(lastUnit.data, array);
12082
- units.push(lastUnit);
12083
- track.lastNalu = null;
12084
12099
  }
12085
12100
  }
12086
12101
  track.naluState = state;
@@ -12231,8 +12246,8 @@ class ExpGolomb {
12231
12246
  }
12232
12247
 
12233
12248
  class AvcVideoParser extends BaseVideoParser {
12234
- parsePES(track, textTrack, pes, last, duration) {
12235
- const units = this.parseNALu(track, pes.data, last);
12249
+ parsePES(track, textTrack, pes, endOfSegment, duration) {
12250
+ const units = this.parseNALu(track, pes.data, endOfSegment);
12236
12251
  let VideoSample = this.VideoSample;
12237
12252
  let push;
12238
12253
  let spsfound = false;
@@ -12362,7 +12377,7 @@ class AvcVideoParser extends BaseVideoParser {
12362
12377
  }
12363
12378
  });
12364
12379
  // if last PES packet, push samples
12365
- if (last && VideoSample) {
12380
+ if (endOfSegment && VideoSample) {
12366
12381
  this.pushAccessUnit(VideoSample, track);
12367
12382
  this.VideoSample = null;
12368
12383
  }
@@ -12561,8 +12576,8 @@ class HevcVideoParser extends BaseVideoParser {
12561
12576
  super(...args);
12562
12577
  this.initVPS = null;
12563
12578
  }
12564
- parsePES(track, textTrack, pes, last, duration) {
12565
- const units = this.parseNALu(track, pes.data, last);
12579
+ parsePES(track, textTrack, pes, endOfSegment, duration) {
12580
+ const units = this.parseNALu(track, pes.data, endOfSegment);
12566
12581
  let VideoSample = this.VideoSample;
12567
12582
  let push;
12568
12583
  let spsfound = false;
@@ -12724,7 +12739,7 @@ class HevcVideoParser extends BaseVideoParser {
12724
12739
  }
12725
12740
  });
12726
12741
  // if last PES packet, push samples
12727
- if (last && VideoSample) {
12742
+ if (endOfSegment && VideoSample) {
12728
12743
  this.pushAccessUnit(VideoSample, track);
12729
12744
  this.VideoSample = null;
12730
12745
  }
@@ -29156,7 +29171,7 @@ class Hls {
29156
29171
  * Get the video-dev/hls.js package version.
29157
29172
  */
29158
29173
  static get version() {
29159
- return "1.5.12-0.canary.10351";
29174
+ return "1.5.12-0.canary.10353";
29160
29175
  }
29161
29176
 
29162
29177
  /**
@@ -29806,7 +29821,7 @@ class Hls {
29806
29821
  */
29807
29822
  setAudioOption(audioOption) {
29808
29823
  var _this$audioTrackContr;
29809
- return (_this$audioTrackContr = this.audioTrackController) == null ? void 0 : _this$audioTrackContr.setAudioOption(audioOption);
29824
+ return ((_this$audioTrackContr = this.audioTrackController) == null ? void 0 : _this$audioTrackContr.setAudioOption(audioOption)) || null;
29810
29825
  }
29811
29826
  /**
29812
29827
  * Find and select the best matching subtitle track, making a level switch when a Group change is necessary.
@@ -29814,8 +29829,7 @@ class Hls {
29814
29829
  */
29815
29830
  setSubtitleOption(subtitleOption) {
29816
29831
  var _this$subtitleTrackCo;
29817
- (_this$subtitleTrackCo = this.subtitleTrackController) == null ? void 0 : _this$subtitleTrackCo.setSubtitleOption(subtitleOption);
29818
- return null;
29832
+ return ((_this$subtitleTrackCo = this.subtitleTrackController) == null ? void 0 : _this$subtitleTrackCo.setSubtitleOption(subtitleOption)) || null;
29819
29833
  }
29820
29834
 
29821
29835
  /**