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.
@@ -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();
@@ -6319,10 +6319,9 @@ function getVideoSelectionOptions(currentVideoRange, videoPreference) {
6319
6319
  }
6320
6320
  if (videoPreference) {
6321
6321
  allowedVideoRanges = videoPreference.allowedVideoRanges || VideoRangeValues.slice(0);
6322
- preferHDR = videoPreference.preferHDR !== undefined ? videoPreference.preferHDR : isHdrSupported();
6323
- if (preferHDR) {
6324
- allowedVideoRanges = allowedVideoRanges.filter(range => range !== 'SDR');
6325
- } else {
6322
+ const allowAutoPreferHDR = allowedVideoRanges.join('') !== 'SDR' && !videoPreference.videoCodec;
6323
+ preferHDR = videoPreference.preferHDR !== undefined ? videoPreference.preferHDR : allowAutoPreferHDR && isHdrSupported();
6324
+ if (!preferHDR) {
6326
6325
  allowedVideoRanges = ['SDR'];
6327
6326
  }
6328
6327
  }
@@ -6336,13 +6335,15 @@ function getStartCodecTier(codecTiers, currentVideoRange, currentBw, audioPrefer
6336
6335
  const codecSets = Object.keys(codecTiers);
6337
6336
  const channelsPreference = audioPreference == null ? void 0 : audioPreference.channels;
6338
6337
  const audioCodecPreference = audioPreference == null ? void 0 : audioPreference.audioCodec;
6338
+ const videoCodecPreference = videoPreference == null ? void 0 : videoPreference.videoCodec;
6339
6339
  const preferStereo = channelsPreference && parseInt(channelsPreference) === 2;
6340
6340
  // Use first level set to determine stereo, and minimum resolution and framerate
6341
- let hasStereo = true;
6341
+ let hasStereo = false;
6342
6342
  let hasCurrentVideoRange = false;
6343
6343
  let minHeight = Infinity;
6344
6344
  let minFramerate = Infinity;
6345
6345
  let minBitrate = Infinity;
6346
+ let minIndex = Infinity;
6346
6347
  let selectedScore = 0;
6347
6348
  let videoRanges = [];
6348
6349
  const {
@@ -6351,14 +6352,13 @@ function getStartCodecTier(codecTiers, currentVideoRange, currentBw, audioPrefer
6351
6352
  } = getVideoSelectionOptions(currentVideoRange, videoPreference);
6352
6353
  for (let i = codecSets.length; i--;) {
6353
6354
  const tier = codecTiers[codecSets[i]];
6354
- hasStereo = tier.channels[2] > 0;
6355
+ hasStereo || (hasStereo = tier.channels[2] > 0);
6355
6356
  minHeight = Math.min(minHeight, tier.minHeight);
6356
6357
  minFramerate = Math.min(minFramerate, tier.minFramerate);
6357
6358
  minBitrate = Math.min(minBitrate, tier.minBitrate);
6358
6359
  const matchingVideoRanges = allowedVideoRanges.filter(range => tier.videoRanges[range] > 0);
6359
6360
  if (matchingVideoRanges.length > 0) {
6360
6361
  hasCurrentVideoRange = true;
6361
- videoRanges = matchingVideoRanges;
6362
6362
  }
6363
6363
  }
6364
6364
  minHeight = isFiniteNumber(minHeight) ? minHeight : 0;
@@ -6370,7 +6370,6 @@ function getStartCodecTier(codecTiers, currentVideoRange, currentBw, audioPrefer
6370
6370
  // If there are no variants with matching preference, set currentVideoRange to undefined
6371
6371
  if (!hasCurrentVideoRange) {
6372
6372
  currentVideoRange = undefined;
6373
- videoRanges = [];
6374
6373
  }
6375
6374
  const codecSet = codecSets.reduce((selected, candidate) => {
6376
6375
  // 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
@@ -6378,6 +6377,7 @@ function getStartCodecTier(codecTiers, currentVideoRange, currentBw, audioPrefer
6378
6377
  if (candidate === selected) {
6379
6378
  return selected;
6380
6379
  }
6380
+ videoRanges = hasCurrentVideoRange ? allowedVideoRanges.filter(range => candidateTier.videoRanges[range] > 0) : [];
6381
6381
  if (candidateTier.minBitrate > currentBw) {
6382
6382
  logStartCodecCandidateIgnored(candidate, `min bitrate of ${candidateTier.minBitrate} > current estimate of ${currentBw}`);
6383
6383
  return selected;
@@ -6411,6 +6411,10 @@ function getStartCodecTier(codecTiers, currentVideoRange, currentBw, audioPrefer
6411
6411
  logStartCodecCandidateIgnored(candidate, `no variants with VIDEO-RANGE of ${JSON.stringify(videoRanges)} found`);
6412
6412
  return selected;
6413
6413
  }
6414
+ if (videoCodecPreference && candidate.indexOf(videoCodecPreference.substring(0, 4)) % 5 !== 0) {
6415
+ logStartCodecCandidateIgnored(candidate, `video codec preference "${videoCodecPreference}" not found`);
6416
+ return selected;
6417
+ }
6414
6418
  if (candidateTier.maxScore < selectedScore) {
6415
6419
  logStartCodecCandidateIgnored(candidate, `max score of ${candidateTier.maxScore} < selected max of ${selectedScore}`);
6416
6420
  return selected;
@@ -6419,6 +6423,7 @@ function getStartCodecTier(codecTiers, currentVideoRange, currentBw, audioPrefer
6419
6423
  if (selected && (codecsSetSelectionPreferenceValue(candidate) >= codecsSetSelectionPreferenceValue(selected) || candidateTier.fragmentError > codecTiers[selected].fragmentError)) {
6420
6424
  return selected;
6421
6425
  }
6426
+ minIndex = candidateTier.minIndex;
6422
6427
  selectedScore = candidateTier.maxScore;
6423
6428
  return candidate;
6424
6429
  }, undefined);
@@ -6427,7 +6432,8 @@ function getStartCodecTier(codecTiers, currentVideoRange, currentBw, audioPrefer
6427
6432
  videoRanges,
6428
6433
  preferHDR,
6429
6434
  minFramerate,
6430
- minBitrate
6435
+ minBitrate,
6436
+ minIndex
6431
6437
  };
6432
6438
  }
6433
6439
  function logStartCodecCandidateIgnored(codeSet, reason) {
@@ -6465,7 +6471,7 @@ function getAudioTracksByGroup(allAudioTracks) {
6465
6471
  });
6466
6472
  }
6467
6473
  function getCodecTiers(levels, audioTracksByGroup, minAutoLevel, maxAutoLevel) {
6468
- return levels.slice(minAutoLevel, maxAutoLevel + 1).reduce((tiers, level) => {
6474
+ return levels.slice(minAutoLevel, maxAutoLevel + 1).reduce((tiers, level, index) => {
6469
6475
  if (!level.codecSet) {
6470
6476
  return tiers;
6471
6477
  }
@@ -6476,6 +6482,7 @@ function getCodecTiers(levels, audioTracksByGroup, minAutoLevel, maxAutoLevel) {
6476
6482
  minBitrate: Infinity,
6477
6483
  minHeight: Infinity,
6478
6484
  minFramerate: Infinity,
6485
+ minIndex: index,
6479
6486
  maxScore: 0,
6480
6487
  videoRanges: {
6481
6488
  SDR: 0
@@ -6491,6 +6498,7 @@ function getCodecTiers(levels, audioTracksByGroup, minAutoLevel, maxAutoLevel) {
6491
6498
  const lesserWidthOrHeight = Math.min(level.height, level.width);
6492
6499
  tier.minHeight = Math.min(tier.minHeight, lesserWidthOrHeight);
6493
6500
  tier.minFramerate = Math.min(tier.minFramerate, level.frameRate);
6501
+ tier.minIndex = Math.min(tier.minIndex, index);
6494
6502
  tier.maxScore = Math.max(tier.maxScore, level.score);
6495
6503
  tier.fragmentError += level.fragmentError;
6496
6504
  tier.videoRanges[level.videoRange] = (tier.videoRanges[level.videoRange] || 0) + 1;
@@ -7010,6 +7018,7 @@ class AbrController extends Logger {
7010
7018
  videoPreference
7011
7019
  } = config;
7012
7020
  const audioTracksByGroup = this.audioTracksByGroup || (this.audioTracksByGroup = getAudioTracksByGroup(allAudioTracks));
7021
+ let minStartIndex = -1;
7013
7022
  if (firstSelection) {
7014
7023
  if (this.firstSelection !== -1) {
7015
7024
  return this.firstSelection;
@@ -7021,8 +7030,10 @@ class AbrController extends Logger {
7021
7030
  videoRanges,
7022
7031
  minFramerate,
7023
7032
  minBitrate,
7033
+ minIndex,
7024
7034
  preferHDR
7025
7035
  } = startTier;
7036
+ minStartIndex = minIndex;
7026
7037
  currentCodecSet = codecSet;
7027
7038
  currentVideoRange = preferHDR ? videoRanges[videoRanges.length - 1] : videoRanges[0];
7028
7039
  currentFrameRate = minFramerate;
@@ -7046,8 +7057,10 @@ class AbrController extends Logger {
7046
7057
  // skip candidates which change codec-family or video-range,
7047
7058
  // and which decrease or increase frame-rate for up and down-switch respectfully
7048
7059
  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)) {
7049
- levelsSkipped.push(i);
7050
- continue;
7060
+ if (firstSelection && i !== minStartIndex) {
7061
+ levelsSkipped.push(i);
7062
+ continue;
7063
+ }
7051
7064
  }
7052
7065
  const levelDetails = levelInfo.details;
7053
7066
  const avgDuration = (partCurrent ? levelDetails == null ? void 0 : levelDetails.partTarget : levelDetails == null ? void 0 : levelDetails.averagetargetduration) || currentFragDuration;
@@ -7082,7 +7095,7 @@ class AbrController extends Logger {
7082
7095
  if (levelsSkipped.length) {
7083
7096
  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}`);
7084
7097
  }
7085
- 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}`);
7098
+ 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}`);
7086
7099
  }
7087
7100
  if (firstSelection) {
7088
7101
  this.firstSelection = i;
@@ -14669,6 +14682,20 @@ class BaseVideoParser {
14669
14682
  length: 0
14670
14683
  };
14671
14684
  }
14685
+ getLastNalUnit(samples) {
14686
+ var _VideoSample;
14687
+ let VideoSample = this.VideoSample;
14688
+ let lastUnit;
14689
+ // try to fallback to previous sample if current one is empty
14690
+ if (!VideoSample || VideoSample.units.length === 0) {
14691
+ VideoSample = samples[samples.length - 1];
14692
+ }
14693
+ if ((_VideoSample = VideoSample) != null && _VideoSample.units) {
14694
+ const units = VideoSample.units;
14695
+ lastUnit = units[units.length - 1];
14696
+ }
14697
+ return lastUnit;
14698
+ }
14672
14699
  pushAccessUnit(VideoSample, videoTrack) {
14673
14700
  if (VideoSample.units.length && VideoSample.frame) {
14674
14701
  // if sample does not have PTS/DTS, patch with last sample PTS/DTS
@@ -14691,7 +14718,7 @@ class BaseVideoParser {
14691
14718
  logger.log(VideoSample.pts + '/' + VideoSample.dts + ':' + VideoSample.debug);
14692
14719
  }
14693
14720
  }
14694
- parseNALu(track, array, last) {
14721
+ parseNALu(track, array, endOfSegment) {
14695
14722
  const len = array.byteLength;
14696
14723
  let state = track.naluState || 0;
14697
14724
  const lastState = state;
@@ -14733,10 +14760,6 @@ class BaseVideoParser {
14733
14760
  data: array.subarray(lastUnitStart, overflow),
14734
14761
  type: lastUnitType
14735
14762
  };
14736
- if (track.lastNalu) {
14737
- units.push(track.lastNalu);
14738
- track.lastNalu = null;
14739
- }
14740
14763
  // logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
14741
14764
  units.push(unit);
14742
14765
  } else {
@@ -14744,7 +14767,7 @@ class BaseVideoParser {
14744
14767
  // first check if start code delimiter is overlapping between 2 PES packets,
14745
14768
  // ie it started in last packet (lastState not zero)
14746
14769
  // and ended at the beginning of this PES packet (i <= 4 - lastState)
14747
- const lastUnit = track.lastNalu;
14770
+ const lastUnit = this.getLastNalUnit(track.samples);
14748
14771
  if (lastUnit) {
14749
14772
  if (lastState && i <= 4 - lastState) {
14750
14773
  // start delimiter overlapping between PES packets
@@ -14761,8 +14784,6 @@ class BaseVideoParser {
14761
14784
  // logger.log('first NALU found with overflow:' + overflow);
14762
14785
  lastUnit.data = appendUint8Array(lastUnit.data, array.subarray(0, overflow));
14763
14786
  lastUnit.state = 0;
14764
- units.push(lastUnit);
14765
- track.lastNalu = null;
14766
14787
  }
14767
14788
  }
14768
14789
  }
@@ -14787,21 +14808,15 @@ class BaseVideoParser {
14787
14808
  type: lastUnitType,
14788
14809
  state: state
14789
14810
  };
14790
- if (!last) {
14791
- track.lastNalu = unit;
14792
- // logger.log('store NALu to push it on next PES');
14793
- } else {
14794
- units.push(unit);
14795
- // logger.log('pushing NALU, type/size/state:' + unit.type + '/' + unit.data.byteLength + '/' + state);
14796
- }
14797
- } else if (units.length === 0) {
14798
- // no NALu found
14811
+ units.push(unit);
14812
+ // logger.log('pushing NALU, type/size/state:' + unit.type + '/' + unit.data.byteLength + '/' + state);
14813
+ }
14814
+ // no NALu found
14815
+ if (units.length === 0) {
14799
14816
  // append pes.data to previous NAL unit
14800
- const lastUnit = track.lastNalu;
14817
+ const lastUnit = this.getLastNalUnit(track.samples);
14801
14818
  if (lastUnit) {
14802
14819
  lastUnit.data = appendUint8Array(lastUnit.data, array);
14803
- units.push(lastUnit);
14804
- track.lastNalu = null;
14805
14820
  }
14806
14821
  }
14807
14822
  track.naluState = state;
@@ -14952,8 +14967,8 @@ class ExpGolomb {
14952
14967
  }
14953
14968
 
14954
14969
  class AvcVideoParser extends BaseVideoParser {
14955
- parsePES(track, textTrack, pes, last, duration) {
14956
- const units = this.parseNALu(track, pes.data, last);
14970
+ parsePES(track, textTrack, pes, endOfSegment, duration) {
14971
+ const units = this.parseNALu(track, pes.data, endOfSegment);
14957
14972
  let VideoSample = this.VideoSample;
14958
14973
  let push;
14959
14974
  let spsfound = false;
@@ -15083,7 +15098,7 @@ class AvcVideoParser extends BaseVideoParser {
15083
15098
  }
15084
15099
  });
15085
15100
  // if last PES packet, push samples
15086
- if (last && VideoSample) {
15101
+ if (endOfSegment && VideoSample) {
15087
15102
  this.pushAccessUnit(VideoSample, track);
15088
15103
  this.VideoSample = null;
15089
15104
  }
@@ -20563,7 +20578,7 @@ class Hls {
20563
20578
  * Get the video-dev/hls.js package version.
20564
20579
  */
20565
20580
  static get version() {
20566
- return "1.5.12-0.canary.10351";
20581
+ return "1.5.12-0.canary.10353";
20567
20582
  }
20568
20583
 
20569
20584
  /**
@@ -21213,7 +21228,7 @@ class Hls {
21213
21228
  */
21214
21229
  setAudioOption(audioOption) {
21215
21230
  var _this$audioTrackContr;
21216
- return (_this$audioTrackContr = this.audioTrackController) == null ? void 0 : _this$audioTrackContr.setAudioOption(audioOption);
21231
+ return ((_this$audioTrackContr = this.audioTrackController) == null ? void 0 : _this$audioTrackContr.setAudioOption(audioOption)) || null;
21217
21232
  }
21218
21233
  /**
21219
21234
  * Find and select the best matching subtitle track, making a level switch when a Group change is necessary.
@@ -21221,8 +21236,7 @@ class Hls {
21221
21236
  */
21222
21237
  setSubtitleOption(subtitleOption) {
21223
21238
  var _this$subtitleTrackCo;
21224
- (_this$subtitleTrackCo = this.subtitleTrackController) == null ? void 0 : _this$subtitleTrackCo.setSubtitleOption(subtitleOption);
21225
- return null;
21239
+ return ((_this$subtitleTrackCo = this.subtitleTrackController) == null ? void 0 : _this$subtitleTrackCo.setSubtitleOption(subtitleOption)) || null;
21226
21240
  }
21227
21241
 
21228
21242
  /**