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.
@@ -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) {
@@ -2236,6 +2254,7 @@ const sampleEntryCodesISO = {
2236
2254
  avc4: 1,
2237
2255
  avcp: 1,
2238
2256
  av01: 0.8,
2257
+ dav1: 0.8,
2239
2258
  drac: 1,
2240
2259
  dva1: 1,
2241
2260
  dvav: 1,
@@ -2454,6 +2473,7 @@ class Level {
2454
2473
  this.height = void 0;
2455
2474
  this.id = void 0;
2456
2475
  this.name = void 0;
2476
+ this.supplemental = void 0;
2457
2477
  this.videoCodec = void 0;
2458
2478
  this.width = void 0;
2459
2479
  this.details = void 0;
@@ -2483,6 +2503,14 @@ class Level {
2483
2503
  this.audioCodec = data.audioCodec;
2484
2504
  this.videoCodec = data.videoCodec;
2485
2505
  this.codecSet = [data.videoCodec, data.audioCodec].filter(c => !!c).map(s => s.substring(0, 4)).join(',');
2506
+ if ('supplemental' in data) {
2507
+ var _data$supplemental;
2508
+ this.supplemental = data.supplemental;
2509
+ const supplementalVideo = (_data$supplemental = data.supplemental) == null ? void 0 : _data$supplemental.videoCodec;
2510
+ if (supplementalVideo && supplementalVideo !== data.videoCodec) {
2511
+ this.codecSet += `,${supplementalVideo.substring(0, 4)}`;
2512
+ }
2513
+ }
2486
2514
  this.addGroupId('audio', data.attrs.AUDIO);
2487
2515
  this.addGroupId('text', data.attrs.SUBTITLES);
2488
2516
  }
@@ -4665,6 +4693,11 @@ class M3U8Parser {
4665
4693
  level.height = resolution.height;
4666
4694
  }
4667
4695
  setCodecs(attrs.CODECS, level);
4696
+ const supplementalCodecs = attrs['SUPPLEMENTAL-CODECS'];
4697
+ if (supplementalCodecs) {
4698
+ level.supplemental = {};
4699
+ setCodecs(supplementalCodecs, level.supplemental);
4700
+ }
4668
4701
  if (!((_level$unknownCodecs = level.unknownCodecs) != null && _level$unknownCodecs.length)) {
4669
4702
  levelsWithKnownCodecs.push(level);
4670
4703
  }
@@ -5233,7 +5266,7 @@ function setCodecs(codecsAttributeValue, level) {
5233
5266
  const filtered = codecs.filter(codec => isCodecType(codec, type));
5234
5267
  if (filtered.length) {
5235
5268
  // Comma separated list of all codecs for type
5236
- level[`${type}Codec`] = filtered.join(',');
5269
+ level[`${type}Codec`] = filtered.map(c => c.split('/')[0]).join(',');
5237
5270
  // Remove known codecs so that only unknownCodecs are left after iterating through each type
5238
5271
  codecs = codecs.filter(codec => filtered.indexOf(codec) === -1);
5239
5272
  }
@@ -9671,7 +9704,8 @@ transfer tracks: ${stringify(transferredTracks, (key, value) => key === 'initSeg
9671
9704
  codec,
9672
9705
  levelCodec,
9673
9706
  container,
9674
- metadata
9707
+ metadata,
9708
+ supplemental
9675
9709
  } = parsedTrack;
9676
9710
  let track = tracks[trackName];
9677
9711
  const transferredTrack = (_this$transferData3 = this.transferData) == null ? void 0 : (_this$transferData3$t = _this$transferData3.tracks) == null ? void 0 : _this$transferData3$t[trackName];
@@ -9683,6 +9717,7 @@ transfer tracks: ${stringify(transferredTracks, (key, value) => key === 'initSeg
9683
9717
  buffer: undefined,
9684
9718
  listeners: [],
9685
9719
  codec,
9720
+ supplemental,
9686
9721
  container,
9687
9722
  levelCodec,
9688
9723
  metadata,
@@ -10313,6 +10348,7 @@ transfer tracks: ${stringify(transferredTracks, (key, value) => key === 'initSeg
10313
10348
  buffer,
10314
10349
  container: track.container,
10315
10350
  codec: track.codec,
10351
+ supplemental: track.supplemental,
10316
10352
  levelCodec: track.levelCodec,
10317
10353
  id: track.id,
10318
10354
  metadata: track.metadata
@@ -10384,6 +10420,11 @@ transfer tracks: ${stringify(transferredTracks, (key, value) => key === 'initSeg
10384
10420
  this.bufferCreated();
10385
10421
  }
10386
10422
  getTrackCodec(track, trackName) {
10423
+ // Use supplemental video codec when supported when adding SourceBuffer (#5558)
10424
+ const supplementalCodec = track.supplemental;
10425
+ if (supplementalCodec && trackName === 'video' && areCodecsMediaSourceSupported(supplementalCodec, trackName)) {
10426
+ return supplementalCodec;
10427
+ }
10387
10428
  const codec = pickMostCompleteCodecName(track.codec, track.levelCodec);
10388
10429
  if (codec) {
10389
10430
  if (trackName.slice(0, 5) === 'audio') {
@@ -10404,6 +10445,7 @@ transfer tracks: ${stringify(transferredTracks, (key, value) => key === 'initSeg
10404
10445
  codec,
10405
10446
  container: track.container,
10406
10447
  levelCodec: track.levelCodec,
10448
+ supplemental: track.supplemental,
10407
10449
  metadata: track.metadata,
10408
10450
  id: track.id,
10409
10451
  listeners: []
@@ -13002,11 +13044,13 @@ class MP4Demuxer {
13002
13044
  const {
13003
13045
  id,
13004
13046
  timescale,
13005
- codec
13047
+ codec,
13048
+ supplemental
13006
13049
  } = initData.video;
13007
13050
  videoTrack.id = id;
13008
13051
  videoTrack.timescale = captionTrack.timescale = timescale;
13009
13052
  videoTrack.codec = codec;
13053
+ videoTrack.supplemental = supplemental;
13010
13054
  }
13011
13055
  if (initData.audio) {
13012
13056
  const {
@@ -16227,6 +16271,7 @@ class PassThroughRemuxer {
16227
16271
  tracks.video = {
16228
16272
  container: 'video/mp4',
16229
16273
  codec: videoCodec,
16274
+ supplemental: initData.video.supplemental,
16230
16275
  initSegment,
16231
16276
  id: 'main'
16232
16277
  };
@@ -18994,6 +19039,7 @@ class LevelController extends BasePlaylistController {
18994
19039
  videoCodecFound || (videoCodecFound = !!videoCodec);
18995
19040
  audioCodecFound || (audioCodecFound = !!audioCodec);
18996
19041
  if (unknownUnsupportedCodecCount || audioCodec && !this.isAudioSupported(audioCodec) || videoCodec && !this.isVideoSupported(videoCodec)) {
19042
+ this.log(`Some or all CODECS not supported "${attributes.CODECS}"`);
18997
19043
  return;
18998
19044
  }
18999
19045
  const {
@@ -19007,7 +19053,7 @@ class LevelController extends BasePlaylistController {
19007
19053
  const contentSteeringPrefix = `${PATHWAY || '.'}-`;
19008
19054
  const levelKey = `${contentSteeringPrefix}${levelParsed.bitrate}-${RESOLUTION}-${FRAMERATE}-${CODECS}-${VIDEO_RANGE}-${HDCP}`;
19009
19055
  if (!redundantSet[levelKey]) {
19010
- const level = new Level(levelParsed);
19056
+ const level = this.createLevel(levelParsed);
19011
19057
  redundantSet[levelKey] = level;
19012
19058
  generatePathwaySet[levelKey] = 1;
19013
19059
  levels.push(level);
@@ -19016,7 +19062,7 @@ class LevelController extends BasePlaylistController {
19016
19062
  // Content Steering controller to handles Pathway fallback on error
19017
19063
  const pathwayCount = generatePathwaySet[levelKey] += 1;
19018
19064
  levelParsed.attrs['PATHWAY-ID'] = new Array(pathwayCount + 1).join('.');
19019
- const level = new Level(levelParsed);
19065
+ const level = this.createLevel(levelParsed);
19020
19066
  redundantSet[levelKey] = level;
19021
19067
  levels.push(level);
19022
19068
  } else {
@@ -19026,6 +19072,16 @@ class LevelController extends BasePlaylistController {
19026
19072
  });
19027
19073
  this.filterAndSortMediaOptions(levels, data, resolutionFound, videoCodecFound, audioCodecFound);
19028
19074
  }
19075
+ createLevel(levelParsed) {
19076
+ const level = new Level(levelParsed);
19077
+ const supplemental = levelParsed.supplemental;
19078
+ if (supplemental != null && supplemental.videoCodec && !this.isVideoSupported(supplemental.videoCodec)) {
19079
+ const error = new Error(`SUPPLEMENTAL-CODECS not supported "${supplemental.videoCodec}"`);
19080
+ this.log(error.message);
19081
+ level.supportedResult = emptyEsExports.getUnsupportedResult(error, []);
19082
+ }
19083
+ return level;
19084
+ }
19029
19085
  isAudioSupported(codec) {
19030
19086
  return areCodecsMediaSourceSupported(codec, 'audio', this.hls.config.preferManagedMediaSource);
19031
19087
  }
@@ -19050,17 +19106,21 @@ class LevelController extends BasePlaylistController {
19050
19106
  // Dispatch error after MANIFEST_LOADED is done propagating
19051
19107
  Promise.resolve().then(() => {
19052
19108
  if (this.hls) {
19109
+ let message = 'no level with compatible codecs found in manifest';
19110
+ let reason = message;
19053
19111
  if (data.levels.length) {
19054
- this.warn(`One or more CODECS in variant not supported: ${stringify(data.levels[0].attrs)}`);
19112
+ 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))}`;
19113
+ this.warn(reason);
19114
+ message += ` (${reason})`;
19055
19115
  }
19056
- const error = new Error('no level with compatible codecs found in manifest');
19116
+ const error = new Error(message);
19057
19117
  this.hls.trigger(Events.ERROR, {
19058
19118
  type: ErrorTypes.MEDIA_ERROR,
19059
19119
  details: ErrorDetails.MANIFEST_INCOMPATIBLE_CODECS_ERROR,
19060
19120
  fatal: true,
19061
19121
  url: data.url,
19062
19122
  error,
19063
- reason: error.message
19123
+ reason
19064
19124
  });
19065
19125
  }
19066
19126
  });
@@ -19464,7 +19524,7 @@ function assignTrackIdsByGroup(tracks) {
19464
19524
  });
19465
19525
  }
19466
19526
 
19467
- const version = "1.6.0-beta.4.0.canary.11068";
19527
+ const version = "1.6.0-beta.4.0.canary.11069";
19468
19528
 
19469
19529
  // ensure the worker ends up in the bundle
19470
19530
  // If the worker should not be included this gets aliased to empty.js
@@ -20981,7 +21041,7 @@ class StreamController extends BaseStreamController {
20981
21041
  break;
20982
21042
  }
20983
21043
  }
20984
- this.log(`Init video buffer, container:${video.container}, codecs[level/parsed]=[${currentLevel.videoCodec || ''}/${parsedVideoCodec}${video.codec !== parsedVideoCodec ? ' parsed-corrected=' + video.codec : ''}}]`);
21044
+ 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 : ''}`);
20985
21045
  delete tracks.audiovideo;
20986
21046
  }
20987
21047
  if (audiovideo) {
@@ -21957,6 +22017,18 @@ const SUPPORTED_INFO_DEFAULT = {
21957
22017
  smooth: true
21958
22018
  }]
21959
22019
  };
22020
+ function getUnsupportedResult(error, configurations) {
22021
+ return {
22022
+ supported: false,
22023
+ configurations,
22024
+ decodingInfoResults: [{
22025
+ supported: false,
22026
+ smooth: false,
22027
+ powerEfficient: false
22028
+ }],
22029
+ error
22030
+ };
22031
+ }
21960
22032
  const SUPPORTED_INFO_CACHE = {};
21961
22033
  function getMediaDecodingInfoPromise(level, audioTracksByGroup, mediaCapabilities) {
21962
22034
  const videoCodecs = level.videoCodec;
@@ -21981,16 +22053,7 @@ function getMediaDecodingInfoPromise(level, audioTracksByGroup, mediaCapabilitie
21981
22053
  // Override Windows Firefox HEVC MediaCapabilities result (https://github.com/video-dev/hls.js/issues/7046)
21982
22054
  const ua = navigator.userAgent;
21983
22055
  if (videoCodecsArray.some(videoCodec => isHEVC(videoCodec)) && userAgentHevcSupportIsInaccurate()) {
21984
- return Promise.resolve({
21985
- supported: false,
21986
- configurations,
21987
- decodingInfoResults: [{
21988
- supported: false,
21989
- smooth: false,
21990
- powerEfficient: false
21991
- }],
21992
- error: new Error(`Overriding Windows Firefox HEVC MediaCapabilities result based on user-agent sting: (${ua})`)
21993
- });
22056
+ return Promise.resolve(getUnsupportedResult(new Error(`Overriding Windows Firefox HEVC MediaCapabilities result based on user-agent sting: (${ua})`), configurations));
21994
22057
  }
21995
22058
  configurations.push.apply(configurations, videoCodecsArray.map(videoCodec => ({
21996
22059
  type: 'media-source',