hls.js 1.6.0-beta.4.0.canary.11068 → 1.6.0-beta.4.0.canary.11069

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
@@ -402,7 +402,7 @@ function enableLogs(debugConfig, context, id) {
402
402
  // Some browsers don't allow to use bind on console object anyway
403
403
  // fallback to default if needed
404
404
  try {
405
- newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.6.0-beta.4.0.canary.11068"}`);
405
+ newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.6.0-beta.4.0.canary.11069"}`);
406
406
  } catch (e) {
407
407
  /* log fn threw an exception. All logger methods are no-ops. */
408
408
  return createLogger();
@@ -1343,6 +1343,7 @@ function parseStsd(stsd) {
1343
1343
  const sampleEntriesEnd = sampleEntries.subarray(8 + 78);
1344
1344
  const fourCC = bin2str(sampleEntries.subarray(4, 8));
1345
1345
  let codec = fourCC;
1346
+ let supplemental;
1346
1347
  const encrypted = fourCC === 'enca' || fourCC === 'encv';
1347
1348
  if (encrypted) {
1348
1349
  const encBox = findBox(sampleEntries, [fourCC])[0];
@@ -1362,6 +1363,7 @@ function parseStsd(stsd) {
1362
1363
  }
1363
1364
  });
1364
1365
  }
1366
+ const codecFourCC = codec;
1365
1367
  switch (codec) {
1366
1368
  case 'avc1':
1367
1369
  case 'avc2':
@@ -1371,6 +1373,7 @@ function parseStsd(stsd) {
1371
1373
  // extract profile + compatibility + level out of avcC box
1372
1374
  const avcCBox = findBox(sampleEntriesEnd, ['avcC'])[0];
1373
1375
  codec += '.' + toHex(avcCBox[1]) + toHex(avcCBox[2]) + toHex(avcCBox[3]);
1376
+ supplemental = parseSupplementalDoViCodec(codecFourCC === 'avc1' ? 'dva1' : 'dvav', sampleEntriesEnd);
1374
1377
  break;
1375
1378
  }
1376
1379
  case 'mp4a':
@@ -1421,35 +1424,39 @@ function parseStsd(stsd) {
1421
1424
  case 'hvc1':
1422
1425
  case 'hev1':
1423
1426
  {
1424
- const hvcCBox = findBox(sampleEntriesEnd, ['hvcC'])[0];
1425
- const profileByte = hvcCBox[1];
1426
- const profileSpace = ['', 'A', 'B', 'C'][profileByte >> 6];
1427
- const generalProfileIdc = profileByte & 0x1f;
1428
- const profileCompat = readUint32(hvcCBox, 2);
1429
- const tierFlag = (profileByte & 0x20) >> 5 ? 'H' : 'L';
1430
- const levelIDC = hvcCBox[12];
1431
- const constraintIndicator = hvcCBox.subarray(6, 12);
1432
- codec += '.' + profileSpace + generalProfileIdc;
1433
- codec += '.' + profileCompat.toString(16).toUpperCase();
1434
- codec += '.' + tierFlag + levelIDC;
1435
- let constraintString = '';
1436
- for (let i = constraintIndicator.length; i--;) {
1437
- const byte = constraintIndicator[i];
1438
- if (byte || constraintString) {
1439
- const encodedByte = byte.toString(16).toUpperCase();
1440
- constraintString = '.' + encodedByte + constraintString;
1427
+ const hvcCBoxes = findBox(sampleEntriesEnd, ['hvcC']);
1428
+ if (hvcCBoxes) {
1429
+ const hvcCBox = hvcCBoxes[0];
1430
+ const profileByte = hvcCBox[1];
1431
+ const profileSpace = ['', 'A', 'B', 'C'][profileByte >> 6];
1432
+ const generalProfileIdc = profileByte & 0x1f;
1433
+ const profileCompat = readUint32(hvcCBox, 2);
1434
+ const tierFlag = (profileByte & 0x20) >> 5 ? 'H' : 'L';
1435
+ const levelIDC = hvcCBox[12];
1436
+ const constraintIndicator = hvcCBox.subarray(6, 12);
1437
+ codec += '.' + profileSpace + generalProfileIdc;
1438
+ codec += '.' + profileCompat.toString(16).toUpperCase();
1439
+ codec += '.' + tierFlag + levelIDC;
1440
+ let constraintString = '';
1441
+ for (let i = constraintIndicator.length; i--;) {
1442
+ const byte = constraintIndicator[i];
1443
+ if (byte || constraintString) {
1444
+ const encodedByte = byte.toString(16).toUpperCase();
1445
+ constraintString = '.' + encodedByte + constraintString;
1446
+ }
1441
1447
  }
1448
+ codec += constraintString;
1442
1449
  }
1443
- codec += constraintString;
1450
+ supplemental = parseSupplementalDoViCodec(codecFourCC == 'hev1' ? 'dvhe' : 'dvh1', sampleEntriesEnd);
1444
1451
  break;
1445
1452
  }
1446
1453
  case 'dvh1':
1447
1454
  case 'dvhe':
1455
+ case 'dvav':
1456
+ case 'dva1':
1457
+ case 'dav1':
1448
1458
  {
1449
- const dvcCBox = findBox(sampleEntriesEnd, ['dvcC'])[0];
1450
- const profile = dvcCBox[2] >> 1 & 0x7f;
1451
- const level = dvcCBox[2] << 5 & 0x20 | dvcCBox[3] >> 3 & 0x1f;
1452
- codec += '.' + addLeadingZero(profile) + '.' + addLeadingZero(level);
1459
+ codec = parseSupplementalDoViCodec(codec, sampleEntriesEnd) || codec;
1453
1460
  break;
1454
1461
  }
1455
1462
  case 'vp09':
@@ -1482,14 +1489,25 @@ function parseStsd(stsd) {
1482
1489
  const matrixCoefficients = 1;
1483
1490
  const videoFullRangeFlag = 0;
1484
1491
  codec += '.' + profile + '.' + addLeadingZero(level) + tierFlag + '.' + addLeadingZero(bitDepth) + '.' + monochrome + '.' + chromaSubsamplingX + chromaSubsamplingY + chromaSamplePosition + '.' + addLeadingZero(colorPrimaries) + '.' + addLeadingZero(transferCharacteristics) + '.' + addLeadingZero(matrixCoefficients) + '.' + videoFullRangeFlag;
1492
+ supplemental = parseSupplementalDoViCodec('dav1', sampleEntriesEnd);
1485
1493
  break;
1486
1494
  }
1487
1495
  }
1488
1496
  return {
1489
1497
  codec,
1490
- encrypted
1498
+ encrypted,
1499
+ supplemental
1491
1500
  };
1492
1501
  }
1502
+ function parseSupplementalDoViCodec(fourCC, sampleEntriesEnd) {
1503
+ const dvvCResult = findBox(sampleEntriesEnd, ['dvvC']); // used by DoVi Profile 8 to 10
1504
+ const dvXCBox = dvvCResult.length ? dvvCResult[0] : findBox(sampleEntriesEnd, ['dvcC'])[0]; // used by DoVi Profiles up to 7 and 20
1505
+ if (dvXCBox) {
1506
+ const doViProfile = dvXCBox[2] >> 1 & 0x7f;
1507
+ const doViLevel = dvXCBox[2] << 5 & 0x20 | dvXCBox[3] >> 3 & 0x1f;
1508
+ return fourCC + '.' + addLeadingZero(doViProfile) + '.' + addLeadingZero(doViLevel);
1509
+ }
1510
+ }
1493
1511
  function skipBERInteger(bytes, i) {
1494
1512
  const limit = i + 5;
1495
1513
  while (bytes[i++] & 0x80 && i < limit) {
@@ -2339,6 +2357,7 @@ const sampleEntryCodesISO = {
2339
2357
  avc4: 1,
2340
2358
  avcp: 1,
2341
2359
  av01: 0.8,
2360
+ dav1: 0.8,
2342
2361
  drac: 1,
2343
2362
  dva1: 1,
2344
2363
  dvav: 1,
@@ -2501,6 +2520,18 @@ const SUPPORTED_INFO_DEFAULT = {
2501
2520
  smooth: true
2502
2521
  }]
2503
2522
  };
2523
+ function getUnsupportedResult(error, configurations) {
2524
+ return {
2525
+ supported: false,
2526
+ configurations,
2527
+ decodingInfoResults: [{
2528
+ supported: false,
2529
+ smooth: false,
2530
+ powerEfficient: false
2531
+ }],
2532
+ error
2533
+ };
2534
+ }
2504
2535
  const SUPPORTED_INFO_CACHE = {};
2505
2536
  function requiresMediaCapabilitiesDecodingInfo(level, audioTracksByGroup, currentVideoRange, currentFrameRate, currentBw, audioPreference) {
2506
2537
  // Only test support when configuration is exceeds minimum options
@@ -2559,16 +2590,7 @@ function getMediaDecodingInfoPromise(level, audioTracksByGroup, mediaCapabilitie
2559
2590
  // Override Windows Firefox HEVC MediaCapabilities result (https://github.com/video-dev/hls.js/issues/7046)
2560
2591
  const ua = navigator.userAgent;
2561
2592
  if (videoCodecsArray.some(videoCodec => isHEVC(videoCodec)) && userAgentHevcSupportIsInaccurate()) {
2562
- return Promise.resolve({
2563
- supported: false,
2564
- configurations,
2565
- decodingInfoResults: [{
2566
- supported: false,
2567
- smooth: false,
2568
- powerEfficient: false
2569
- }],
2570
- error: new Error(`Overriding Windows Firefox HEVC MediaCapabilities result based on user-agent sting: (${ua})`)
2571
- });
2593
+ return Promise.resolve(getUnsupportedResult(new Error(`Overriding Windows Firefox HEVC MediaCapabilities result based on user-agent sting: (${ua})`), configurations));
2572
2594
  }
2573
2595
  configurations.push.apply(configurations, videoCodecsArray.map(videoCodec => ({
2574
2596
  type: 'media-source',
@@ -2700,6 +2722,7 @@ class Level {
2700
2722
  this.height = void 0;
2701
2723
  this.id = void 0;
2702
2724
  this.name = void 0;
2725
+ this.supplemental = void 0;
2703
2726
  this.videoCodec = void 0;
2704
2727
  this.width = void 0;
2705
2728
  this.details = void 0;
@@ -2729,6 +2752,14 @@ class Level {
2729
2752
  this.audioCodec = data.audioCodec;
2730
2753
  this.videoCodec = data.videoCodec;
2731
2754
  this.codecSet = [data.videoCodec, data.audioCodec].filter(c => !!c).map(s => s.substring(0, 4)).join(',');
2755
+ if ('supplemental' in data) {
2756
+ var _data$supplemental;
2757
+ this.supplemental = data.supplemental;
2758
+ const supplementalVideo = (_data$supplemental = data.supplemental) == null ? void 0 : _data$supplemental.videoCodec;
2759
+ if (supplementalVideo && supplementalVideo !== data.videoCodec) {
2760
+ this.codecSet += `,${supplementalVideo.substring(0, 4)}`;
2761
+ }
2762
+ }
2732
2763
  this.addGroupId('audio', data.attrs.AUDIO);
2733
2764
  this.addGroupId('text', data.attrs.SUBTITLES);
2734
2765
  }
@@ -6935,6 +6966,11 @@ class M3U8Parser {
6935
6966
  level.height = resolution.height;
6936
6967
  }
6937
6968
  setCodecs(attrs.CODECS, level);
6969
+ const supplementalCodecs = attrs['SUPPLEMENTAL-CODECS'];
6970
+ if (supplementalCodecs) {
6971
+ level.supplemental = {};
6972
+ setCodecs(supplementalCodecs, level.supplemental);
6973
+ }
6938
6974
  if (!((_level$unknownCodecs = level.unknownCodecs) != null && _level$unknownCodecs.length)) {
6939
6975
  levelsWithKnownCodecs.push(level);
6940
6976
  }
@@ -7516,7 +7552,7 @@ function setCodecs(codecsAttributeValue, level) {
7516
7552
  const filtered = codecs.filter(codec => isCodecType(codec, type));
7517
7553
  if (filtered.length) {
7518
7554
  // Comma separated list of all codecs for type
7519
- level[`${type}Codec`] = filtered.join(',');
7555
+ level[`${type}Codec`] = filtered.map(c => c.split('/')[0]).join(',');
7520
7556
  // Remove known codecs so that only unknownCodecs are left after iterating through each type
7521
7557
  codecs = codecs.filter(codec => filtered.indexOf(codec) === -1);
7522
7558
  }
@@ -9965,7 +10001,7 @@ function requireEventemitter3 () {
9965
10001
  var eventemitter3Exports = requireEventemitter3();
9966
10002
  var EventEmitter = /*@__PURE__*/getDefaultExportFromCjs(eventemitter3Exports);
9967
10003
 
9968
- const version = "1.6.0-beta.4.0.canary.11068";
10004
+ const version = "1.6.0-beta.4.0.canary.11069";
9969
10005
 
9970
10006
  // ensure the worker ends up in the bundle
9971
10007
  // If the worker should not be included this gets aliased to empty.js
@@ -11405,11 +11441,13 @@ class MP4Demuxer {
11405
11441
  const {
11406
11442
  id,
11407
11443
  timescale,
11408
- codec
11444
+ codec,
11445
+ supplemental
11409
11446
  } = initData.video;
11410
11447
  videoTrack.id = id;
11411
11448
  videoTrack.timescale = captionTrack.timescale = timescale;
11412
11449
  videoTrack.codec = codec;
11450
+ videoTrack.supplemental = supplemental;
11413
11451
  }
11414
11452
  if (initData.audio) {
11415
11453
  const {
@@ -15366,6 +15404,7 @@ class PassThroughRemuxer {
15366
15404
  tracks.video = {
15367
15405
  container: 'video/mp4',
15368
15406
  codec: videoCodec,
15407
+ supplemental: initData.video.supplemental,
15369
15408
  initSegment,
15370
15409
  id: 'main'
15371
15410
  };
@@ -18276,7 +18315,8 @@ transfer tracks: ${stringify(transferredTracks, (key, value) => key === 'initSeg
18276
18315
  codec,
18277
18316
  levelCodec,
18278
18317
  container,
18279
- metadata
18318
+ metadata,
18319
+ supplemental
18280
18320
  } = parsedTrack;
18281
18321
  let track = tracks[trackName];
18282
18322
  const transferredTrack = (_this$transferData3 = this.transferData) == null ? void 0 : (_this$transferData3$t = _this$transferData3.tracks) == null ? void 0 : _this$transferData3$t[trackName];
@@ -18288,6 +18328,7 @@ transfer tracks: ${stringify(transferredTracks, (key, value) => key === 'initSeg
18288
18328
  buffer: undefined,
18289
18329
  listeners: [],
18290
18330
  codec,
18331
+ supplemental,
18291
18332
  container,
18292
18333
  levelCodec,
18293
18334
  metadata,
@@ -18918,6 +18959,7 @@ transfer tracks: ${stringify(transferredTracks, (key, value) => key === 'initSeg
18918
18959
  buffer,
18919
18960
  container: track.container,
18920
18961
  codec: track.codec,
18962
+ supplemental: track.supplemental,
18921
18963
  levelCodec: track.levelCodec,
18922
18964
  id: track.id,
18923
18965
  metadata: track.metadata
@@ -18989,6 +19031,11 @@ transfer tracks: ${stringify(transferredTracks, (key, value) => key === 'initSeg
18989
19031
  this.bufferCreated();
18990
19032
  }
18991
19033
  getTrackCodec(track, trackName) {
19034
+ // Use supplemental video codec when supported when adding SourceBuffer (#5558)
19035
+ const supplementalCodec = track.supplemental;
19036
+ if (supplementalCodec && trackName === 'video' && areCodecsMediaSourceSupported(supplementalCodec, trackName)) {
19037
+ return supplementalCodec;
19038
+ }
18992
19039
  const codec = pickMostCompleteCodecName(track.codec, track.levelCodec);
18993
19040
  if (codec) {
18994
19041
  if (trackName.slice(0, 5) === 'audio') {
@@ -19009,6 +19056,7 @@ transfer tracks: ${stringify(transferredTracks, (key, value) => key === 'initSeg
19009
19056
  codec,
19010
19057
  container: track.container,
19011
19058
  levelCodec: track.levelCodec,
19059
+ supplemental: track.supplemental,
19012
19060
  metadata: track.metadata,
19013
19061
  id: track.id,
19014
19062
  listeners: []
@@ -31220,6 +31268,7 @@ class LevelController extends BasePlaylistController {
31220
31268
  videoCodecFound || (videoCodecFound = !!videoCodec);
31221
31269
  audioCodecFound || (audioCodecFound = !!audioCodec);
31222
31270
  if (unknownUnsupportedCodecCount || audioCodec && !this.isAudioSupported(audioCodec) || videoCodec && !this.isVideoSupported(videoCodec)) {
31271
+ this.log(`Some or all CODECS not supported "${attributes.CODECS}"`);
31223
31272
  return;
31224
31273
  }
31225
31274
  const {
@@ -31233,7 +31282,7 @@ class LevelController extends BasePlaylistController {
31233
31282
  const contentSteeringPrefix = `${PATHWAY || '.'}-`;
31234
31283
  const levelKey = `${contentSteeringPrefix}${levelParsed.bitrate}-${RESOLUTION}-${FRAMERATE}-${CODECS}-${VIDEO_RANGE}-${HDCP}`;
31235
31284
  if (!redundantSet[levelKey]) {
31236
- const level = new Level(levelParsed);
31285
+ const level = this.createLevel(levelParsed);
31237
31286
  redundantSet[levelKey] = level;
31238
31287
  generatePathwaySet[levelKey] = 1;
31239
31288
  levels.push(level);
@@ -31242,7 +31291,7 @@ class LevelController extends BasePlaylistController {
31242
31291
  // Content Steering controller to handles Pathway fallback on error
31243
31292
  const pathwayCount = generatePathwaySet[levelKey] += 1;
31244
31293
  levelParsed.attrs['PATHWAY-ID'] = new Array(pathwayCount + 1).join('.');
31245
- const level = new Level(levelParsed);
31294
+ const level = this.createLevel(levelParsed);
31246
31295
  redundantSet[levelKey] = level;
31247
31296
  levels.push(level);
31248
31297
  } else {
@@ -31252,6 +31301,16 @@ class LevelController extends BasePlaylistController {
31252
31301
  });
31253
31302
  this.filterAndSortMediaOptions(levels, data, resolutionFound, videoCodecFound, audioCodecFound);
31254
31303
  }
31304
+ createLevel(levelParsed) {
31305
+ const level = new Level(levelParsed);
31306
+ const supplemental = levelParsed.supplemental;
31307
+ if (supplemental != null && supplemental.videoCodec && !this.isVideoSupported(supplemental.videoCodec)) {
31308
+ const error = new Error(`SUPPLEMENTAL-CODECS not supported "${supplemental.videoCodec}"`);
31309
+ this.log(error.message);
31310
+ level.supportedResult = getUnsupportedResult(error, []);
31311
+ }
31312
+ return level;
31313
+ }
31255
31314
  isAudioSupported(codec) {
31256
31315
  return areCodecsMediaSourceSupported(codec, 'audio', this.hls.config.preferManagedMediaSource);
31257
31316
  }
@@ -31276,17 +31335,21 @@ class LevelController extends BasePlaylistController {
31276
31335
  // Dispatch error after MANIFEST_LOADED is done propagating
31277
31336
  Promise.resolve().then(() => {
31278
31337
  if (this.hls) {
31338
+ let message = 'no level with compatible codecs found in manifest';
31339
+ let reason = message;
31279
31340
  if (data.levels.length) {
31280
- this.warn(`One or more CODECS in variant not supported: ${stringify(data.levels[0].attrs)}`);
31341
+ reason = `one or more CODECS in variant not supported: ${stringify(data.levels.map(level => level.attrs.CODECS).filter((value, index, array) => array.indexOf(value) === index))}`;
31342
+ this.warn(reason);
31343
+ message += ` (${reason})`;
31281
31344
  }
31282
- const error = new Error('no level with compatible codecs found in manifest');
31345
+ const error = new Error(message);
31283
31346
  this.hls.trigger(Events.ERROR, {
31284
31347
  type: ErrorTypes.MEDIA_ERROR,
31285
31348
  details: ErrorDetails.MANIFEST_INCOMPATIBLE_CODECS_ERROR,
31286
31349
  fatal: true,
31287
31350
  url: data.url,
31288
31351
  error,
31289
- reason: error.message
31352
+ reason
31290
31353
  });
31291
31354
  }
31292
31355
  });
@@ -32825,7 +32888,7 @@ class StreamController extends BaseStreamController {
32825
32888
  break;
32826
32889
  }
32827
32890
  }
32828
- this.log(`Init video buffer, container:${video.container}, codecs[level/parsed]=[${currentLevel.videoCodec || ''}/${parsedVideoCodec}${video.codec !== parsedVideoCodec ? ' parsed-corrected=' + video.codec : ''}}]`);
32891
+ this.log(`Init video buffer, container:${video.container}, codecs[level/parsed]=[${currentLevel.videoCodec || ''}/${parsedVideoCodec}]${video.codec !== parsedVideoCodec ? ' parsed-corrected=' + video.codec : ''}${video.supplemental ? ' supplemental=' + video.supplemental : ''}`);
32829
32892
  delete tracks.audiovideo;
32830
32893
  }
32831
32894
  if (audiovideo) {