hls.js 1.5.14-0.canary.10668 → 1.5.14-0.canary.10670

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.
@@ -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.10668"}`);
443
+ newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.5.14-0.canary.10670"}`);
444
444
  } catch (e) {
445
445
  /* log fn threw an exception. All logger methods are no-ops. */
446
446
  return createLogger();
@@ -2490,7 +2490,7 @@ function isCodecMediaSourceSupported(codec, type, preferManagedMediaSource = tru
2490
2490
  return (_MediaSource$isTypeSu = MediaSource == null ? void 0 : MediaSource.isTypeSupported(mimeTypeForCodec(codec, type))) != null ? _MediaSource$isTypeSu : false;
2491
2491
  }
2492
2492
  function mimeTypeForCodec(codec, type) {
2493
- return `${type}/mp4;codecs="${codec}"`;
2493
+ return `${type}/mp4;codecs=${codec}`;
2494
2494
  }
2495
2495
  function videoCodecPreferenceValue(videoCodec) {
2496
2496
  if (videoCodec) {
@@ -2541,15 +2541,28 @@ function getCodecCompatibleName(codec, preferManagedMediaSource = true) {
2541
2541
  function pickMostCompleteCodecName(parsedCodec, levelCodec) {
2542
2542
  // Parsing of mp4a codecs strings in mp4-tools from media is incomplete as of d8c6c7a
2543
2543
  // so use level codec is parsed codec is unavailable or incomplete
2544
- if (parsedCodec && parsedCodec !== 'mp4a') {
2544
+ if (parsedCodec && (parsedCodec.length > 4 || ['ac-3', 'ec-3', 'alac', 'fLaC', 'Opus'].indexOf(parsedCodec) !== -1)) {
2545
2545
  return parsedCodec;
2546
2546
  }
2547
- return levelCodec ? levelCodec.split(',')[0] : levelCodec;
2547
+ if (levelCodec) {
2548
+ const levelCodecs = levelCodec.split(',');
2549
+ if (levelCodecs.length > 1) {
2550
+ if (parsedCodec) {
2551
+ for (let i = levelCodecs.length; i--;) {
2552
+ if (levelCodecs[i].substring(0, 4) === parsedCodec.substring(0, 4)) {
2553
+ return levelCodecs[i];
2554
+ }
2555
+ }
2556
+ }
2557
+ return levelCodecs[0];
2558
+ }
2559
+ }
2560
+ return levelCodec || parsedCodec;
2548
2561
  }
2549
- function convertAVC1ToAVCOTI(codec) {
2562
+ function convertAVC1ToAVCOTI(videoCodecs) {
2550
2563
  // Convert avc1 codec string from RFC-4281 to RFC-6381 for MediaSource.isTypeSupported
2551
2564
  // Examples: avc1.66.30 to avc1.42001e and avc1.77.30,avc1.66.30 to avc1.4d001e,avc1.42001e.
2552
- const codecs = codec.split(',');
2565
+ const codecs = videoCodecs.split(',');
2553
2566
  for (let i = 0; i < codecs.length; i++) {
2554
2567
  const avcdata = codecs[i].split('.');
2555
2568
  if (avcdata.length > 2) {
@@ -2561,6 +2574,18 @@ function convertAVC1ToAVCOTI(codec) {
2561
2574
  }
2562
2575
  return codecs.join(',');
2563
2576
  }
2577
+ function fillInMissingAV01Params(videoCodec) {
2578
+ // Used to fill in incomplete AV1 playlist CODECS strings for mediaCapabilities.decodingInfo queries
2579
+ if (videoCodec.startsWith('av01.')) {
2580
+ const av1params = videoCodec.split('.');
2581
+ const placeholders = ['0', '111', '01', '01', '01', '0'];
2582
+ for (let i = av1params.length; i > 4 && i < 10; i++) {
2583
+ av1params[i] = placeholders[i - 4];
2584
+ }
2585
+ return av1params.join('.');
2586
+ }
2587
+ return videoCodec;
2588
+ }
2564
2589
  function getM2TSSupportedAudioTypes(preferManagedMediaSource) {
2565
2590
  const MediaSource = getMediaSource(preferManagedMediaSource) || {
2566
2591
  isTypeSupported: () => false
@@ -6375,10 +6400,27 @@ class LevelController extends BasePlaylistController {
6375
6400
  height,
6376
6401
  unknownCodecs
6377
6402
  } = levelParsed;
6403
+ let unknownUnsupportedCodecCount = unknownCodecs ? unknownCodecs.length : 0;
6404
+ if (unknownCodecs) {
6405
+ // Treat unknown codec as audio or video codec based on passing `isTypeSupported` check
6406
+ // (allows for playback of any supported codec even if not indexed in utils/codecs)
6407
+ for (let i = unknownUnsupportedCodecCount; i--;) {
6408
+ const unknownCodec = unknownCodecs[i];
6409
+ if (this.isAudioSupported(unknownCodec)) {
6410
+ levelParsed.audioCodec = audioCodec = audioCodec ? `${audioCodec},${unknownCodec}` : unknownCodec;
6411
+ unknownUnsupportedCodecCount--;
6412
+ sampleEntryCodesISO.audio[audioCodec.substring(0, 4)] = 2;
6413
+ } else if (this.isVideoSupported(unknownCodec)) {
6414
+ levelParsed.videoCodec = videoCodec = videoCodec ? `${videoCodec},${unknownCodec}` : unknownCodec;
6415
+ unknownUnsupportedCodecCount--;
6416
+ sampleEntryCodesISO.video[videoCodec.substring(0, 4)] = 2;
6417
+ }
6418
+ }
6419
+ }
6378
6420
  resolutionFound || (resolutionFound = !!(width && height));
6379
6421
  videoCodecFound || (videoCodecFound = !!videoCodec);
6380
6422
  audioCodecFound || (audioCodecFound = !!audioCodec);
6381
- if (unknownCodecs != null && unknownCodecs.length || audioCodec && !areCodecsMediaSourceSupported(audioCodec, 'audio', preferManagedMediaSource) || videoCodec && !areCodecsMediaSourceSupported(videoCodec, 'video', preferManagedMediaSource)) {
6423
+ if (unknownUnsupportedCodecCount || audioCodec && !this.isAudioSupported(audioCodec) || videoCodec && !this.isVideoSupported(videoCodec)) {
6382
6424
  return;
6383
6425
  }
6384
6426
  const {
@@ -6411,6 +6453,12 @@ class LevelController extends BasePlaylistController {
6411
6453
  });
6412
6454
  this.filterAndSortMediaOptions(levels, data, resolutionFound, videoCodecFound, audioCodecFound);
6413
6455
  }
6456
+ isAudioSupported(codec) {
6457
+ return areCodecsMediaSourceSupported(codec, 'audio', this.hls.config.preferManagedMediaSource);
6458
+ }
6459
+ isVideoSupported(codec) {
6460
+ return areCodecsMediaSourceSupported(codec, 'video', this.hls.config.preferManagedMediaSource);
6461
+ }
6414
6462
  filterAndSortMediaOptions(filteredLevels, data, resolutionFound, videoCodecFound, audioCodecFound) {
6415
6463
  let audioTracks = [];
6416
6464
  let subtitleTracks = [];
@@ -6446,10 +6494,7 @@ class LevelController extends BasePlaylistController {
6446
6494
  return;
6447
6495
  }
6448
6496
  if (data.audioTracks) {
6449
- const {
6450
- preferManagedMediaSource
6451
- } = this.hls.config;
6452
- audioTracks = data.audioTracks.filter(track => !track.audioCodec || areCodecsMediaSourceSupported(track.audioCodec, 'audio', preferManagedMediaSource));
6497
+ audioTracks = data.audioTracks.filter(track => !track.audioCodec || this.isAudioSupported(track.audioCodec));
6453
6498
  // Assign ids after filtering as array indices by group-id
6454
6499
  assignTrackIdsByGroup(audioTracks);
6455
6500
  }
@@ -10153,7 +10198,7 @@ function changeTypeSupported() {
10153
10198
  return typeof (sourceBuffer == null ? void 0 : (_sourceBuffer$prototy = sourceBuffer.prototype) == null ? void 0 : _sourceBuffer$prototy.changeType) === 'function';
10154
10199
  }
10155
10200
 
10156
- const version = "1.5.14-0.canary.10668";
10201
+ const version = "1.5.14-0.canary.10670";
10157
10202
 
10158
10203
  // ensure the worker ends up in the bundle
10159
10204
  // If the worker should not be included this gets aliased to empty.js
@@ -14235,7 +14280,7 @@ class PassThroughRemuxer {
14235
14280
  }
14236
14281
  const initData = this.initData = parseInitSegment(initSegment);
14237
14282
 
14238
- // Get codec from initSegment or fallback to default
14283
+ // Get codec from initSegment
14239
14284
  if (initData.audio) {
14240
14285
  audioCodec = getParsedTrackCodec(initData.audio, ElementaryStreamTypes.AUDIO);
14241
14286
  }
@@ -14390,20 +14435,13 @@ function getParsedTrackCodec(track, type) {
14390
14435
  const preferManagedMediaSource = false;
14391
14436
  return getCodecCompatibleName(parsedCodec, preferManagedMediaSource);
14392
14437
  }
14393
- const result = 'mp4a.40.5';
14394
- this.logger.info(`Parsed audio codec "${parsedCodec}" or audio object type not handled. Using "${result}"`);
14395
- return result;
14438
+ logger.warn(`Unhandled audio codec "${parsedCodec}" in mp4 MAP`);
14439
+ return parsedCodec || 'mp4a';
14396
14440
  }
14397
14441
  // Provide defaults based on codec type
14398
14442
  // This allows for some playback of some fmp4 playlists without CODECS defined in manifest
14399
- this.logger.warn(`Unhandled video codec "${parsedCodec}"`);
14400
- if (parsedCodec === 'hvc1' || parsedCodec === 'hev1') {
14401
- return 'hvc1.1.6.L120.90';
14402
- }
14403
- if (parsedCodec === 'av01') {
14404
- return 'av01.0.04M.08';
14405
- }
14406
- return 'avc1.42e01e';
14443
+ logger.warn(`Unhandled video codec "${parsedCodec}" in mp4 MAP`);
14444
+ return parsedCodec || 'avc1';
14407
14445
  }
14408
14446
 
14409
14447
  let now;
@@ -16863,7 +16901,13 @@ class StreamController extends BaseStreamController {
16863
16901
  audiovideo
16864
16902
  } = tracks;
16865
16903
  if (audio) {
16866
- let audioCodec = currentLevel.audioCodec;
16904
+ let audioCodec = pickMostCompleteCodecName(audio.codec, currentLevel.audioCodec);
16905
+ // Add level and profile to make up for passthrough-remuxer not being able to parse full codec
16906
+ // (logger warning "Unhandled audio codec...")
16907
+ if (audioCodec === 'mp4a') {
16908
+ audioCodec = 'mp4a.40.5';
16909
+ }
16910
+ // Handle `audioCodecSwitch`
16867
16911
  const ua = navigator.userAgent.toLowerCase();
16868
16912
  if (this.audioCodecSwitch) {
16869
16913
  if (audioCodec) {
@@ -16898,7 +16942,24 @@ class StreamController extends BaseStreamController {
16898
16942
  if (video) {
16899
16943
  video.levelCodec = currentLevel.videoCodec;
16900
16944
  video.id = 'main';
16901
- this.log(`Init video buffer, container:${video.container}, codecs[level/parsed]=[${currentLevel.videoCodec || ''}/${video.codec}]`);
16945
+ const parsedVideoCodec = video.codec;
16946
+ if ((parsedVideoCodec == null ? void 0 : parsedVideoCodec.length) === 4) {
16947
+ // Make up for passthrough-remuxer not being able to parse full codec
16948
+ // (logger warning "Unhandled video codec...")
16949
+ switch (parsedVideoCodec) {
16950
+ case 'hvc1':
16951
+ case 'hev1':
16952
+ video.codec = 'hvc1.1.6.L120.90';
16953
+ break;
16954
+ case 'av01':
16955
+ video.codec = 'av01.0.04M.08';
16956
+ break;
16957
+ case 'avc1':
16958
+ video.codec = 'avc1.42e01e';
16959
+ break;
16960
+ }
16961
+ }
16962
+ this.log(`Init video buffer, container:${video.container}, codecs[level/parsed]=[${currentLevel.videoCodec || ''}/${parsedVideoCodec}${video.codec !== parsedVideoCodec ? ' parsed-corrected=' + video.codec : ''}}]`);
16902
16963
  delete tracks.audiovideo;
16903
16964
  }
16904
16965
  if (audiovideo) {
@@ -18685,7 +18746,7 @@ transfer tracks: ${JSON.stringify(transferredTracks, (key, value) => key === 'in
18685
18746
  if (trackName.slice(0, 5) === 'audio') {
18686
18747
  trackCodec = getCodecCompatibleName(trackCodec, this.appendSource);
18687
18748
  }
18688
- this.log(`switching codec ${sbCodec} to ${codec}`);
18749
+ this.log(`switching codec ${sbCodec} to ${trackCodec}`);
18689
18750
  if (trackCodec !== (track.pendingCodec || track.codec)) {
18690
18751
  track.pendingCodec = trackCodec;
18691
18752
  }
@@ -19368,7 +19429,7 @@ transfer tracks: ${JSON.stringify(transferredTracks, (key, value) => key === 'in
19368
19429
  }
19369
19430
  }
19370
19431
  getTrackCodec(track, trackName) {
19371
- const codec = track.codec || track.levelCodec;
19432
+ const codec = pickMostCompleteCodecName(track.codec, track.levelCodec);
19372
19433
  if (codec) {
19373
19434
  if (trackName.slice(0, 5) === 'audio') {
19374
19435
  return getCodecCompatibleName(codec, this.appendSource);
@@ -21319,6 +21380,100 @@ function enableStreamingMode(config, logger) {
21319
21380
  }
21320
21381
  }
21321
21382
 
21383
+ const SUPPORTED_INFO_DEFAULT = {
21384
+ supported: true,
21385
+ configurations: [],
21386
+ decodingInfoResults: [{
21387
+ supported: true,
21388
+ powerEfficient: true,
21389
+ smooth: true
21390
+ }]
21391
+ };
21392
+ const SUPPORTED_INFO_CACHE = {};
21393
+ function getMediaDecodingInfoPromise(level, audioTracksByGroup, mediaCapabilities) {
21394
+ const videoCodecs = level.videoCodec;
21395
+ const audioCodecs = level.audioCodec;
21396
+ if (!videoCodecs && !audioCodecs || !mediaCapabilities) {
21397
+ return Promise.resolve(SUPPORTED_INFO_DEFAULT);
21398
+ }
21399
+ const configurations = [];
21400
+ if (videoCodecs) {
21401
+ const baseVideoConfiguration = {
21402
+ width: level.width,
21403
+ height: level.height,
21404
+ bitrate: Math.ceil(Math.max(level.bitrate * 0.9, level.averageBitrate)),
21405
+ // Assume a framerate of 30fps since MediaCapabilities will not accept Level default of 0.
21406
+ framerate: level.frameRate || 30
21407
+ };
21408
+ const videoRange = level.videoRange;
21409
+ if (videoRange !== 'SDR') {
21410
+ baseVideoConfiguration.transferFunction = videoRange.toLowerCase();
21411
+ }
21412
+ configurations.push.apply(configurations, videoCodecs.split(',').map(videoCodec => ({
21413
+ type: 'media-source',
21414
+ video: _objectSpread2(_objectSpread2({}, baseVideoConfiguration), {}, {
21415
+ contentType: mimeTypeForCodec(fillInMissingAV01Params(videoCodec), 'video')
21416
+ })
21417
+ })));
21418
+ }
21419
+ if (audioCodecs && level.audioGroups) {
21420
+ level.audioGroups.forEach(audioGroupId => {
21421
+ var _audioTracksByGroup$g;
21422
+ if (!audioGroupId) {
21423
+ return;
21424
+ }
21425
+ (_audioTracksByGroup$g = audioTracksByGroup.groups[audioGroupId]) == null ? void 0 : _audioTracksByGroup$g.tracks.forEach(audioTrack => {
21426
+ if (audioTrack.groupId === audioGroupId) {
21427
+ const channels = audioTrack.channels || '';
21428
+ const channelsNumber = parseFloat(channels);
21429
+ if (isFiniteNumber(channelsNumber) && channelsNumber > 2) {
21430
+ configurations.push.apply(configurations, audioCodecs.split(',').map(audioCodec => ({
21431
+ type: 'media-source',
21432
+ audio: {
21433
+ contentType: mimeTypeForCodec(audioCodec, 'audio'),
21434
+ channels: '' + channelsNumber
21435
+ // spatialRendering:
21436
+ // audioCodec === 'ec-3' && channels.indexOf('JOC'),
21437
+ }
21438
+ })));
21439
+ }
21440
+ }
21441
+ });
21442
+ });
21443
+ }
21444
+ return Promise.all(configurations.map(configuration => {
21445
+ // Cache MediaCapabilities promises
21446
+ const decodingInfoKey = getMediaDecodingInfoKey(configuration);
21447
+ return SUPPORTED_INFO_CACHE[decodingInfoKey] || (SUPPORTED_INFO_CACHE[decodingInfoKey] = mediaCapabilities.decodingInfo(configuration));
21448
+ })).then(decodingInfoResults => ({
21449
+ supported: !decodingInfoResults.some(info => !info.supported),
21450
+ configurations,
21451
+ decodingInfoResults
21452
+ })).catch(error => ({
21453
+ supported: false,
21454
+ configurations,
21455
+ decodingInfoResults: [],
21456
+ error
21457
+ }));
21458
+ }
21459
+ function getMediaDecodingInfoKey(config) {
21460
+ const {
21461
+ audio,
21462
+ video
21463
+ } = config;
21464
+ const mediaConfig = video || audio;
21465
+ if (mediaConfig) {
21466
+ const codec = mediaConfig.contentType.split('"')[1];
21467
+ if (video) {
21468
+ return `r${video.height}x${video.width}f${Math.ceil(video.framerate)}${video.transferFunction || 'sd'}_${codec}_${Math.ceil(video.bitrate / 1e5)}`;
21469
+ }
21470
+ if (audio) {
21471
+ return `c${audio.channels}${audio.spatialRendering ? 's' : 'n'}_${codec}`;
21472
+ }
21473
+ }
21474
+ return '';
21475
+ }
21476
+
21322
21477
  /**
21323
21478
  * The `Hls` class is the core of the HLS.js library used to instantiate player instances.
21324
21479
  * @public
@@ -22264,6 +22419,14 @@ class Hls {
22264
22419
  var _this$interstitialsCo;
22265
22420
  return ((_this$interstitialsCo = this.interstitialsController) == null ? void 0 : _this$interstitialsCo.interstitialsManager) || null;
22266
22421
  }
22422
+
22423
+ /**
22424
+ * returns mediaCapabilities.decodingInfo for a variant/rendition
22425
+ */
22426
+ getMediaDecodingInfo(level, audioTracks = this.allAudioTracks) {
22427
+ const audioTracksByGroup = getAudioTracksByGroup(audioTracks);
22428
+ return getMediaDecodingInfoPromise(level, audioTracksByGroup, navigator.mediaCapabilities);
22429
+ }
22267
22430
  }
22268
22431
  Hls.defaultConfig = void 0;
22269
22432