hls.js 1.5.12-0.canary.10340 → 1.5.12-0.canary.10341
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.js +431 -288
- package/dist/hls.js.d.ts +49 -16
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +364 -178
- package/dist/hls.light.js.map +1 -1
- package/dist/hls.light.min.js +1 -1
- package/dist/hls.light.min.js.map +1 -1
- package/dist/hls.light.mjs +356 -179
- package/dist/hls.light.mjs.map +1 -1
- package/dist/hls.min.js +1 -1
- package/dist/hls.min.js.map +1 -1
- package/dist/hls.mjs +422 -288
- package/dist/hls.mjs.map +1 -1
- package/dist/hls.worker.js +1 -1
- package/dist/hls.worker.js.map +1 -1
- package/package.json +1 -1
- package/src/controller/audio-stream-controller.ts +13 -5
- package/src/controller/base-stream-controller.ts +28 -26
- package/src/controller/fragment-finders.ts +12 -14
- package/src/controller/fragment-tracker.ts +14 -14
- package/src/controller/id3-track-controller.ts +38 -28
- package/src/controller/stream-controller.ts +9 -4
- package/src/controller/subtitle-stream-controller.ts +3 -3
- package/src/demux/transmuxer-interface.ts +4 -4
- package/src/hls.ts +3 -1
- package/src/loader/date-range.ts +71 -5
- package/src/loader/fragment.ts +6 -2
- package/src/loader/level-details.ts +7 -6
- package/src/loader/m3u8-parser.ts +138 -144
- package/src/types/events.ts +2 -5
- package/src/types/fragment-tracker.ts +2 -2
- package/src/utils/attr-list.ts +96 -9
- package/src/utils/level-helper.ts +68 -40
- package/src/utils/variable-substitution.ts +0 -19
package/dist/hls.js
CHANGED
@@ -463,14 +463,151 @@
|
|
463
463
|
return ErrorDetails;
|
464
464
|
}({});
|
465
465
|
|
466
|
+
var Logger = function Logger(label, logger) {
|
467
|
+
this.trace = void 0;
|
468
|
+
this.debug = void 0;
|
469
|
+
this.log = void 0;
|
470
|
+
this.warn = void 0;
|
471
|
+
this.info = void 0;
|
472
|
+
this.error = void 0;
|
473
|
+
var lb = "[" + label + "]:";
|
474
|
+
this.trace = noop;
|
475
|
+
this.debug = logger.debug.bind(null, lb);
|
476
|
+
this.log = logger.log.bind(null, lb);
|
477
|
+
this.warn = logger.warn.bind(null, lb);
|
478
|
+
this.info = logger.info.bind(null, lb);
|
479
|
+
this.error = logger.error.bind(null, lb);
|
480
|
+
};
|
481
|
+
var noop = function noop() {};
|
482
|
+
var fakeLogger = {
|
483
|
+
trace: noop,
|
484
|
+
debug: noop,
|
485
|
+
log: noop,
|
486
|
+
warn: noop,
|
487
|
+
info: noop,
|
488
|
+
error: noop
|
489
|
+
};
|
490
|
+
function createLogger() {
|
491
|
+
return _extends({}, fakeLogger);
|
492
|
+
}
|
493
|
+
|
494
|
+
// let lastCallTime;
|
495
|
+
// function formatMsgWithTimeInfo(type, msg) {
|
496
|
+
// const now = Date.now();
|
497
|
+
// const diff = lastCallTime ? '+' + (now - lastCallTime) : '0';
|
498
|
+
// lastCallTime = now;
|
499
|
+
// msg = (new Date(now)).toISOString() + ' | [' + type + '] > ' + msg + ' ( ' + diff + ' ms )';
|
500
|
+
// return msg;
|
501
|
+
// }
|
502
|
+
|
503
|
+
function consolePrintFn(type, id) {
|
504
|
+
var func = self.console[type];
|
505
|
+
return func ? func.bind(self.console, ('') + "[" + type + "] >") : noop;
|
506
|
+
}
|
507
|
+
function getLoggerFn(key, debugConfig, id) {
|
508
|
+
return debugConfig[key] ? debugConfig[key].bind(debugConfig) : consolePrintFn(key);
|
509
|
+
}
|
510
|
+
var exportedLogger = createLogger();
|
511
|
+
function enableLogs(debugConfig, context, id) {
|
512
|
+
// check that console is available
|
513
|
+
var newLogger = createLogger();
|
514
|
+
if (typeof console === 'object' && debugConfig === true || typeof debugConfig === 'object') {
|
515
|
+
var keys = [
|
516
|
+
// Remove out from list here to hard-disable a log-level
|
517
|
+
// 'trace',
|
518
|
+
'debug', 'log', 'info', 'warn', 'error'];
|
519
|
+
keys.forEach(function (key) {
|
520
|
+
newLogger[key] = getLoggerFn(key, debugConfig);
|
521
|
+
});
|
522
|
+
// Some browsers don't allow to use bind on console object anyway
|
523
|
+
// fallback to default if needed
|
524
|
+
try {
|
525
|
+
newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.5.12-0.canary.10341");
|
526
|
+
} catch (e) {
|
527
|
+
/* log fn threw an exception. All logger methods are no-ops. */
|
528
|
+
return createLogger();
|
529
|
+
}
|
530
|
+
// global exported logger uses the same functions as new logger without `id`
|
531
|
+
keys.forEach(function (key) {
|
532
|
+
exportedLogger[key] = getLoggerFn(key, debugConfig);
|
533
|
+
});
|
534
|
+
} else {
|
535
|
+
// Reset global exported logger
|
536
|
+
_extends(exportedLogger, newLogger);
|
537
|
+
}
|
538
|
+
return newLogger;
|
539
|
+
}
|
540
|
+
var logger = exportedLogger;
|
541
|
+
|
542
|
+
var VARIABLE_REPLACEMENT_REGEX = /\{\$([a-zA-Z0-9-_]+)\}/g;
|
543
|
+
function hasVariableReferences(str) {
|
544
|
+
return VARIABLE_REPLACEMENT_REGEX.test(str);
|
545
|
+
}
|
546
|
+
function substituteVariables(parsed, value) {
|
547
|
+
if (parsed.variableList !== null || parsed.hasVariableRefs) {
|
548
|
+
var variableList = parsed.variableList;
|
549
|
+
return value.replace(VARIABLE_REPLACEMENT_REGEX, function (variableReference) {
|
550
|
+
var variableName = variableReference.substring(2, variableReference.length - 1);
|
551
|
+
var variableValue = variableList == null ? void 0 : variableList[variableName];
|
552
|
+
if (variableValue === undefined) {
|
553
|
+
parsed.playlistParsingError || (parsed.playlistParsingError = new Error("Missing preceding EXT-X-DEFINE tag for Variable Reference: \"" + variableName + "\""));
|
554
|
+
return variableReference;
|
555
|
+
}
|
556
|
+
return variableValue;
|
557
|
+
});
|
558
|
+
}
|
559
|
+
return value;
|
560
|
+
}
|
561
|
+
function addVariableDefinition(parsed, attr, parentUrl) {
|
562
|
+
var variableList = parsed.variableList;
|
563
|
+
if (!variableList) {
|
564
|
+
parsed.variableList = variableList = {};
|
565
|
+
}
|
566
|
+
var NAME;
|
567
|
+
var VALUE;
|
568
|
+
if ('QUERYPARAM' in attr) {
|
569
|
+
NAME = attr.QUERYPARAM;
|
570
|
+
try {
|
571
|
+
var searchParams = new self.URL(parentUrl).searchParams;
|
572
|
+
if (searchParams.has(NAME)) {
|
573
|
+
VALUE = searchParams.get(NAME);
|
574
|
+
} else {
|
575
|
+
throw new Error("\"" + NAME + "\" does not match any query parameter in URI: \"" + parentUrl + "\"");
|
576
|
+
}
|
577
|
+
} catch (error) {
|
578
|
+
parsed.playlistParsingError || (parsed.playlistParsingError = new Error("EXT-X-DEFINE QUERYPARAM: " + error.message));
|
579
|
+
}
|
580
|
+
} else {
|
581
|
+
NAME = attr.NAME;
|
582
|
+
VALUE = attr.VALUE;
|
583
|
+
}
|
584
|
+
if (NAME in variableList) {
|
585
|
+
parsed.playlistParsingError || (parsed.playlistParsingError = new Error("EXT-X-DEFINE duplicate Variable Name declarations: \"" + NAME + "\""));
|
586
|
+
} else {
|
587
|
+
variableList[NAME] = VALUE || '';
|
588
|
+
}
|
589
|
+
}
|
590
|
+
function importVariableDefinition(parsed, attr, sourceVariableList) {
|
591
|
+
var IMPORT = attr.IMPORT;
|
592
|
+
if (sourceVariableList && IMPORT in sourceVariableList) {
|
593
|
+
var variableList = parsed.variableList;
|
594
|
+
if (!variableList) {
|
595
|
+
parsed.variableList = variableList = {};
|
596
|
+
}
|
597
|
+
variableList[IMPORT] = sourceVariableList[IMPORT];
|
598
|
+
} else {
|
599
|
+
parsed.playlistParsingError || (parsed.playlistParsingError = new Error("EXT-X-DEFINE IMPORT attribute not found in Multivariant Playlist: \"" + IMPORT + "\""));
|
600
|
+
}
|
601
|
+
}
|
602
|
+
|
466
603
|
var DECIMAL_RESOLUTION_REGEX = /^(\d+)x(\d+)$/;
|
467
604
|
var ATTR_LIST_REGEX = /(.+?)=(".*?"|.*?)(?:,|$)/g;
|
468
605
|
|
469
606
|
// adapted from https://github.com/kanongil/node-m3u8parse/blob/master/attrlist.js
|
470
607
|
var AttrList = /*#__PURE__*/function () {
|
471
|
-
function AttrList(attrs) {
|
608
|
+
function AttrList(attrs, parsed) {
|
472
609
|
if (typeof attrs === 'string') {
|
473
|
-
attrs = AttrList.parseAttrList(attrs);
|
610
|
+
attrs = AttrList.parseAttrList(attrs, parsed);
|
474
611
|
}
|
475
612
|
_extends(this, attrs);
|
476
613
|
}
|
@@ -512,6 +649,13 @@
|
|
512
649
|
_proto.enumeratedString = function enumeratedString(attrName) {
|
513
650
|
return this[attrName];
|
514
651
|
};
|
652
|
+
_proto.enumeratedStringList = function enumeratedStringList(attrName, dict) {
|
653
|
+
var attrValue = this[attrName];
|
654
|
+
return (attrValue ? attrValue.split(/[ ,]+/) : []).reduce(function (result, identifier) {
|
655
|
+
result[identifier.toLowerCase()] = true;
|
656
|
+
return result;
|
657
|
+
}, dict);
|
658
|
+
};
|
515
659
|
_proto.bool = function bool(attrName) {
|
516
660
|
return this[attrName] === 'YES';
|
517
661
|
};
|
@@ -525,17 +669,75 @@
|
|
525
669
|
height: parseInt(res[2], 10)
|
526
670
|
};
|
527
671
|
};
|
528
|
-
AttrList.parseAttrList = function parseAttrList(input) {
|
672
|
+
AttrList.parseAttrList = function parseAttrList(input, parsed) {
|
529
673
|
var match;
|
530
674
|
var attrs = {};
|
531
675
|
var quote = '"';
|
532
676
|
ATTR_LIST_REGEX.lastIndex = 0;
|
533
677
|
while ((match = ATTR_LIST_REGEX.exec(input)) !== null) {
|
678
|
+
var name = match[1].trim();
|
534
679
|
var value = match[2];
|
535
|
-
|
680
|
+
var quotedString = value.indexOf(quote) === 0 && value.lastIndexOf(quote) === value.length - 1;
|
681
|
+
var hexadecimalSequence = false;
|
682
|
+
if (quotedString) {
|
536
683
|
value = value.slice(1, -1);
|
684
|
+
} else {
|
685
|
+
switch (name) {
|
686
|
+
case 'IV':
|
687
|
+
case 'SCTE35-CMD':
|
688
|
+
case 'SCTE35-IN':
|
689
|
+
case 'SCTE35-OUT':
|
690
|
+
hexadecimalSequence = true;
|
691
|
+
}
|
692
|
+
}
|
693
|
+
if (parsed && (quotedString || hexadecimalSequence)) {
|
694
|
+
{
|
695
|
+
value = substituteVariables(parsed, value);
|
696
|
+
}
|
697
|
+
} else if (!hexadecimalSequence && !quotedString) {
|
698
|
+
switch (name) {
|
699
|
+
case 'CLOSED-CAPTIONS':
|
700
|
+
if (value === 'NONE') {
|
701
|
+
break;
|
702
|
+
}
|
703
|
+
// falls through
|
704
|
+
case 'ALLOWED-CPC':
|
705
|
+
case 'CLASS':
|
706
|
+
case 'ASSOC-LANGUAGE':
|
707
|
+
case 'AUDIO':
|
708
|
+
case 'BYTERANGE':
|
709
|
+
case 'CHANNELS':
|
710
|
+
case 'CHARACTERISTICS':
|
711
|
+
case 'CODECS':
|
712
|
+
case 'DATA-ID':
|
713
|
+
case 'END-DATE':
|
714
|
+
case 'GROUP-ID':
|
715
|
+
case 'ID':
|
716
|
+
case 'IMPORT':
|
717
|
+
case 'INSTREAM-ID':
|
718
|
+
case 'KEYFORMAT':
|
719
|
+
case 'KEYFORMATVERSIONS':
|
720
|
+
case 'LANGUAGE':
|
721
|
+
case 'NAME':
|
722
|
+
case 'PATHWAY-ID':
|
723
|
+
case 'QUERYPARAM':
|
724
|
+
case 'RECENTLY-REMOVED-DATERANGES':
|
725
|
+
case 'SERVER-URI':
|
726
|
+
case 'STABLE-RENDITION-ID':
|
727
|
+
case 'STABLE-VARIANT-ID':
|
728
|
+
case 'START-DATE':
|
729
|
+
case 'SUBTITLES':
|
730
|
+
case 'SUPPLEMENTAL-CODECS':
|
731
|
+
case 'URI':
|
732
|
+
case 'VALUE':
|
733
|
+
case 'VIDEO':
|
734
|
+
case 'X-ASSET-LIST':
|
735
|
+
case 'X-ASSET-URI':
|
736
|
+
// Since we are not checking tag:attribute combination, just warn rather than ignoring attribute
|
737
|
+
logger.warn(input + ": attribute " + name + " is missing quotes");
|
738
|
+
// continue;
|
739
|
+
}
|
537
740
|
}
|
538
|
-
var name = match[1].trim();
|
539
741
|
attrs[name] = value;
|
540
742
|
}
|
541
743
|
return attrs;
|
@@ -550,96 +752,30 @@
|
|
550
752
|
}]);
|
551
753
|
}();
|
552
754
|
|
553
|
-
var Logger = function Logger(label, logger) {
|
554
|
-
this.trace = void 0;
|
555
|
-
this.debug = void 0;
|
556
|
-
this.log = void 0;
|
557
|
-
this.warn = void 0;
|
558
|
-
this.info = void 0;
|
559
|
-
this.error = void 0;
|
560
|
-
var lb = "[" + label + "]:";
|
561
|
-
this.trace = noop;
|
562
|
-
this.debug = logger.debug.bind(null, lb);
|
563
|
-
this.log = logger.log.bind(null, lb);
|
564
|
-
this.warn = logger.warn.bind(null, lb);
|
565
|
-
this.info = logger.info.bind(null, lb);
|
566
|
-
this.error = logger.error.bind(null, lb);
|
567
|
-
};
|
568
|
-
var noop = function noop() {};
|
569
|
-
var fakeLogger = {
|
570
|
-
trace: noop,
|
571
|
-
debug: noop,
|
572
|
-
log: noop,
|
573
|
-
warn: noop,
|
574
|
-
info: noop,
|
575
|
-
error: noop
|
576
|
-
};
|
577
|
-
function createLogger() {
|
578
|
-
return _extends({}, fakeLogger);
|
579
|
-
}
|
580
|
-
|
581
|
-
// let lastCallTime;
|
582
|
-
// function formatMsgWithTimeInfo(type, msg) {
|
583
|
-
// const now = Date.now();
|
584
|
-
// const diff = lastCallTime ? '+' + (now - lastCallTime) : '0';
|
585
|
-
// lastCallTime = now;
|
586
|
-
// msg = (new Date(now)).toISOString() + ' | [' + type + '] > ' + msg + ' ( ' + diff + ' ms )';
|
587
|
-
// return msg;
|
588
|
-
// }
|
589
|
-
|
590
|
-
function consolePrintFn(type, id) {
|
591
|
-
var func = self.console[type];
|
592
|
-
return func ? func.bind(self.console, ('') + "[" + type + "] >") : noop;
|
593
|
-
}
|
594
|
-
function getLoggerFn(key, debugConfig, id) {
|
595
|
-
return debugConfig[key] ? debugConfig[key].bind(debugConfig) : consolePrintFn(key);
|
596
|
-
}
|
597
|
-
var exportedLogger = createLogger();
|
598
|
-
function enableLogs(debugConfig, context, id) {
|
599
|
-
// check that console is available
|
600
|
-
var newLogger = createLogger();
|
601
|
-
if (typeof console === 'object' && debugConfig === true || typeof debugConfig === 'object') {
|
602
|
-
var keys = [
|
603
|
-
// Remove out from list here to hard-disable a log-level
|
604
|
-
// 'trace',
|
605
|
-
'debug', 'log', 'info', 'warn', 'error'];
|
606
|
-
keys.forEach(function (key) {
|
607
|
-
newLogger[key] = getLoggerFn(key, debugConfig);
|
608
|
-
});
|
609
|
-
// Some browsers don't allow to use bind on console object anyway
|
610
|
-
// fallback to default if needed
|
611
|
-
try {
|
612
|
-
newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.5.12-0.canary.10340");
|
613
|
-
} catch (e) {
|
614
|
-
/* log fn threw an exception. All logger methods are no-ops. */
|
615
|
-
return createLogger();
|
616
|
-
}
|
617
|
-
// global exported logger uses the same functions as new logger without `id`
|
618
|
-
keys.forEach(function (key) {
|
619
|
-
exportedLogger[key] = getLoggerFn(key, debugConfig);
|
620
|
-
});
|
621
|
-
} else {
|
622
|
-
// Reset global exported logger
|
623
|
-
_extends(exportedLogger, newLogger);
|
624
|
-
}
|
625
|
-
return newLogger;
|
626
|
-
}
|
627
|
-
var logger = exportedLogger;
|
628
|
-
|
629
755
|
// Avoid exporting const enum so that these values can be inlined
|
630
756
|
|
757
|
+
var CLASS_INTERSTITIAL = 'com.apple.hls.interstitial';
|
631
758
|
function isDateRangeCueAttribute(attrName) {
|
632
|
-
return attrName !== "ID" && attrName !== "CLASS" && attrName !== "START-DATE" && attrName !== "DURATION" && attrName !== "END-DATE" && attrName !== "END-ON-NEXT";
|
759
|
+
return attrName !== "ID" && attrName !== "CLASS" && attrName !== "CUE" && attrName !== "START-DATE" && attrName !== "DURATION" && attrName !== "END-DATE" && attrName !== "END-ON-NEXT";
|
633
760
|
}
|
634
761
|
function isSCTE35Attribute(attrName) {
|
635
|
-
return attrName === "SCTE35-OUT" || attrName === "SCTE35-IN";
|
762
|
+
return attrName === "SCTE35-OUT" || attrName === "SCTE35-IN" || attrName === "SCTE35-CMD";
|
636
763
|
}
|
637
764
|
var DateRange = /*#__PURE__*/function () {
|
638
|
-
function DateRange(dateRangeAttr, dateRangeWithSameId) {
|
765
|
+
function DateRange(dateRangeAttr, dateRangeWithSameId, tagCount) {
|
766
|
+
var _dateRangeWithSameId$;
|
767
|
+
if (tagCount === void 0) {
|
768
|
+
tagCount = 0;
|
769
|
+
}
|
639
770
|
this.attr = void 0;
|
771
|
+
this.tagAnchor = void 0;
|
772
|
+
this.tagOrder = void 0;
|
640
773
|
this._startDate = void 0;
|
641
774
|
this._endDate = void 0;
|
775
|
+
this._cue = void 0;
|
642
776
|
this._badValueForSameId = void 0;
|
777
|
+
this.tagAnchor = (dateRangeWithSameId == null ? void 0 : dateRangeWithSameId.tagAnchor) || null;
|
778
|
+
this.tagOrder = (_dateRangeWithSameId$ = dateRangeWithSameId == null ? void 0 : dateRangeWithSameId.tagOrder) != null ? _dateRangeWithSameId$ : tagCount;
|
643
779
|
if (dateRangeWithSameId) {
|
644
780
|
var previousAttr = dateRangeWithSameId.attr;
|
645
781
|
for (var key in previousAttr) {
|
@@ -653,9 +789,9 @@
|
|
653
789
|
dateRangeAttr = _extends(new AttrList({}), previousAttr, dateRangeAttr);
|
654
790
|
}
|
655
791
|
this.attr = dateRangeAttr;
|
656
|
-
this._startDate = new Date(dateRangeAttr["START-DATE"]);
|
792
|
+
this._startDate = dateRangeWithSameId ? dateRangeWithSameId.startDate : new Date(dateRangeAttr["START-DATE"]);
|
657
793
|
if ("END-DATE" in this.attr) {
|
658
|
-
var endDate = new Date(this.attr["END-DATE"]);
|
794
|
+
var endDate = (dateRangeWithSameId == null ? void 0 : dateRangeWithSameId.endDate) || new Date(this.attr["END-DATE"]);
|
659
795
|
if (isFiniteNumber(endDate.getTime())) {
|
660
796
|
this._endDate = endDate;
|
661
797
|
}
|
@@ -671,6 +807,30 @@
|
|
671
807
|
get: function get() {
|
672
808
|
return this.attr.CLASS;
|
673
809
|
}
|
810
|
+
}, {
|
811
|
+
key: "cue",
|
812
|
+
get: function get() {
|
813
|
+
var _cue = this._cue;
|
814
|
+
if (_cue === undefined) {
|
815
|
+
return this._cue = this.attr.enumeratedStringList(this.attr.CUE ? 'CUE' : 'X-CUE', {
|
816
|
+
pre: false,
|
817
|
+
post: false,
|
818
|
+
once: false
|
819
|
+
});
|
820
|
+
}
|
821
|
+
return _cue;
|
822
|
+
}
|
823
|
+
}, {
|
824
|
+
key: "startTime",
|
825
|
+
get: function get() {
|
826
|
+
var tagAnchor = this.tagAnchor;
|
827
|
+
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
|
828
|
+
if (tagAnchor === null || tagAnchor.programDateTime === null) {
|
829
|
+
logger.warn("Expected tagAnchor Fragment with PDT set for DateRange \"" + this.id + "\": " + tagAnchor);
|
830
|
+
return NaN;
|
831
|
+
}
|
832
|
+
return tagAnchor.start + (this.startDate.getTime() - tagAnchor.programDateTime) / 1000;
|
833
|
+
}
|
674
834
|
}, {
|
675
835
|
key: "startDate",
|
676
836
|
get: function get() {
|
@@ -714,10 +874,15 @@
|
|
714
874
|
get: function get() {
|
715
875
|
return this.attr.bool("END-ON-NEXT");
|
716
876
|
}
|
877
|
+
}, {
|
878
|
+
key: "isInterstitial",
|
879
|
+
get: function get() {
|
880
|
+
return this.class === CLASS_INTERSTITIAL;
|
881
|
+
}
|
717
882
|
}, {
|
718
883
|
key: "isValid",
|
719
884
|
get: function get() {
|
720
|
-
return !!this.id && !this._badValueForSameId && isFiniteNumber(this.startDate.getTime()) && (this.duration === null || this.duration >= 0) && (!this.endOnNext || !!this.class);
|
885
|
+
return !!this.id && !this._badValueForSameId && isFiniteNumber(this.startDate.getTime()) && (this.duration === null || this.duration >= 0) && (!this.endOnNext || !!this.class) && (!this.attr.CUE || !this.cue.pre && !this.cue.post || this.cue.pre !== this.cue.post) && (!this.isInterstitial || 'X-ASSET-URI' in this.attr || 'X-ASSET-LIST' in this.attr);
|
721
886
|
}
|
722
887
|
}]);
|
723
888
|
}();
|
@@ -809,7 +974,6 @@
|
|
809
974
|
}
|
810
975
|
}]);
|
811
976
|
}();
|
812
|
-
|
813
977
|
/**
|
814
978
|
* Object representing parsed data from an HLS Segment. Found in {@link hls.js#LevelDetails.fragments}.
|
815
979
|
*/
|
@@ -1040,6 +1204,7 @@
|
|
1040
1204
|
this.fragmentHint = void 0;
|
1041
1205
|
this.partList = null;
|
1042
1206
|
this.dateRanges = void 0;
|
1207
|
+
this.dateRangeTagCount = 0;
|
1043
1208
|
this.live = true;
|
1044
1209
|
this.ageHeader = 0;
|
1045
1210
|
this.advancedDateTime = void 0;
|
@@ -2768,78 +2933,6 @@
|
|
2768
2933
|
return uint8View;
|
2769
2934
|
}
|
2770
2935
|
|
2771
|
-
var VARIABLE_REPLACEMENT_REGEX = /\{\$([a-zA-Z0-9-_]+)\}/g;
|
2772
|
-
function hasVariableReferences(str) {
|
2773
|
-
return VARIABLE_REPLACEMENT_REGEX.test(str);
|
2774
|
-
}
|
2775
|
-
function substituteVariablesInAttributes(parsed, attr, attributeNames) {
|
2776
|
-
if (parsed.variableList !== null || parsed.hasVariableRefs) {
|
2777
|
-
for (var i = attributeNames.length; i--;) {
|
2778
|
-
var name = attributeNames[i];
|
2779
|
-
var value = attr[name];
|
2780
|
-
if (value) {
|
2781
|
-
attr[name] = substituteVariables(parsed, value);
|
2782
|
-
}
|
2783
|
-
}
|
2784
|
-
}
|
2785
|
-
}
|
2786
|
-
function substituteVariables(parsed, value) {
|
2787
|
-
if (parsed.variableList !== null || parsed.hasVariableRefs) {
|
2788
|
-
var variableList = parsed.variableList;
|
2789
|
-
return value.replace(VARIABLE_REPLACEMENT_REGEX, function (variableReference) {
|
2790
|
-
var variableName = variableReference.substring(2, variableReference.length - 1);
|
2791
|
-
var variableValue = variableList == null ? void 0 : variableList[variableName];
|
2792
|
-
if (variableValue === undefined) {
|
2793
|
-
parsed.playlistParsingError || (parsed.playlistParsingError = new Error("Missing preceding EXT-X-DEFINE tag for Variable Reference: \"" + variableName + "\""));
|
2794
|
-
return variableReference;
|
2795
|
-
}
|
2796
|
-
return variableValue;
|
2797
|
-
});
|
2798
|
-
}
|
2799
|
-
return value;
|
2800
|
-
}
|
2801
|
-
function addVariableDefinition(parsed, attr, parentUrl) {
|
2802
|
-
var variableList = parsed.variableList;
|
2803
|
-
if (!variableList) {
|
2804
|
-
parsed.variableList = variableList = {};
|
2805
|
-
}
|
2806
|
-
var NAME;
|
2807
|
-
var VALUE;
|
2808
|
-
if ('QUERYPARAM' in attr) {
|
2809
|
-
NAME = attr.QUERYPARAM;
|
2810
|
-
try {
|
2811
|
-
var searchParams = new self.URL(parentUrl).searchParams;
|
2812
|
-
if (searchParams.has(NAME)) {
|
2813
|
-
VALUE = searchParams.get(NAME);
|
2814
|
-
} else {
|
2815
|
-
throw new Error("\"" + NAME + "\" does not match any query parameter in URI: \"" + parentUrl + "\"");
|
2816
|
-
}
|
2817
|
-
} catch (error) {
|
2818
|
-
parsed.playlistParsingError || (parsed.playlistParsingError = new Error("EXT-X-DEFINE QUERYPARAM: " + error.message));
|
2819
|
-
}
|
2820
|
-
} else {
|
2821
|
-
NAME = attr.NAME;
|
2822
|
-
VALUE = attr.VALUE;
|
2823
|
-
}
|
2824
|
-
if (NAME in variableList) {
|
2825
|
-
parsed.playlistParsingError || (parsed.playlistParsingError = new Error("EXT-X-DEFINE duplicate Variable Name declarations: \"" + NAME + "\""));
|
2826
|
-
} else {
|
2827
|
-
variableList[NAME] = VALUE || '';
|
2828
|
-
}
|
2829
|
-
}
|
2830
|
-
function importVariableDefinition(parsed, attr, sourceVariableList) {
|
2831
|
-
var IMPORT = attr.IMPORT;
|
2832
|
-
if (sourceVariableList && IMPORT in sourceVariableList) {
|
2833
|
-
var variableList = parsed.variableList;
|
2834
|
-
if (!variableList) {
|
2835
|
-
parsed.variableList = variableList = {};
|
2836
|
-
}
|
2837
|
-
variableList[IMPORT] = sourceVariableList[IMPORT];
|
2838
|
-
} else {
|
2839
|
-
parsed.playlistParsingError || (parsed.playlistParsingError = new Error("EXT-X-DEFINE IMPORT attribute not found in Multivariant Playlist: \"" + IMPORT + "\""));
|
2840
|
-
}
|
2841
|
-
}
|
2842
|
-
|
2843
2936
|
/**
|
2844
2937
|
* MediaSource helper
|
2845
2938
|
*/
|
@@ -3097,10 +3190,7 @@
|
|
3097
3190
|
if (result[1]) {
|
3098
3191
|
var _level$unknownCodecs;
|
3099
3192
|
// '#EXT-X-STREAM-INF' is found, parse level tag in group 1
|
3100
|
-
var attrs = new AttrList(result[1]);
|
3101
|
-
{
|
3102
|
-
substituteVariablesInAttributes(parsed, attrs, ['CODECS', 'SUPPLEMENTAL-CODECS', 'ALLOWED-CPC', 'PATHWAY-ID', 'STABLE-VARIANT-ID', 'AUDIO', 'VIDEO', 'SUBTITLES', 'CLOSED-CAPTIONS', 'NAME']);
|
3103
|
-
}
|
3193
|
+
var attrs = new AttrList(result[1], parsed);
|
3104
3194
|
var uri = substituteVariables(parsed, result[2]) ;
|
3105
3195
|
var level = {
|
3106
3196
|
attrs: attrs,
|
@@ -3125,10 +3215,7 @@
|
|
3125
3215
|
case 'SESSION-DATA':
|
3126
3216
|
{
|
3127
3217
|
// #EXT-X-SESSION-DATA
|
3128
|
-
var sessionAttrs = new AttrList(attributes);
|
3129
|
-
{
|
3130
|
-
substituteVariablesInAttributes(parsed, sessionAttrs, ['DATA-ID', 'LANGUAGE', 'VALUE', 'URI']);
|
3131
|
-
}
|
3218
|
+
var sessionAttrs = new AttrList(attributes, parsed);
|
3132
3219
|
var dataId = sessionAttrs['DATA-ID'];
|
3133
3220
|
if (dataId) {
|
3134
3221
|
if (parsed.sessionData === null) {
|
@@ -3156,8 +3243,7 @@
|
|
3156
3243
|
{
|
3157
3244
|
// #EXT-X-DEFINE
|
3158
3245
|
{
|
3159
|
-
var variableAttributes = new AttrList(attributes);
|
3160
|
-
substituteVariablesInAttributes(parsed, variableAttributes, ['NAME', 'VALUE', 'QUERYPARAM']);
|
3246
|
+
var variableAttributes = new AttrList(attributes, parsed);
|
3161
3247
|
addVariableDefinition(parsed, variableAttributes, baseurl);
|
3162
3248
|
}
|
3163
3249
|
break;
|
@@ -3165,10 +3251,7 @@
|
|
3165
3251
|
case 'CONTENT-STEERING':
|
3166
3252
|
{
|
3167
3253
|
// #EXT-X-CONTENT-STEERING
|
3168
|
-
var contentSteeringAttributes = new AttrList(attributes);
|
3169
|
-
{
|
3170
|
-
substituteVariablesInAttributes(parsed, contentSteeringAttributes, ['SERVER-URI', 'PATHWAY-ID']);
|
3171
|
-
}
|
3254
|
+
var contentSteeringAttributes = new AttrList(attributes, parsed);
|
3172
3255
|
parsed.contentSteering = {
|
3173
3256
|
uri: M3U8Parser.resolve(contentSteeringAttributes['SERVER-URI'], baseurl),
|
3174
3257
|
pathwayId: contentSteeringAttributes['PATHWAY-ID'] || '.'
|
@@ -3214,15 +3297,12 @@
|
|
3214
3297
|
var id = 0;
|
3215
3298
|
MASTER_PLAYLIST_MEDIA_REGEX.lastIndex = 0;
|
3216
3299
|
while ((result = MASTER_PLAYLIST_MEDIA_REGEX.exec(string)) !== null) {
|
3217
|
-
var attrs = new AttrList(result[1]);
|
3300
|
+
var attrs = new AttrList(result[1], parsed);
|
3218
3301
|
var type = attrs.TYPE;
|
3219
3302
|
if (type) {
|
3220
3303
|
var groups = groupsByType[type];
|
3221
3304
|
var medias = results[type] || [];
|
3222
3305
|
results[type] = medias;
|
3223
|
-
{
|
3224
|
-
substituteVariablesInAttributes(parsed, attrs, ['URI', 'GROUP-ID', 'LANGUAGE', 'ASSOC-LANGUAGE', 'STABLE-RENDITION-ID', 'NAME', 'INSTREAM-ID', 'CHARACTERISTICS', 'CHANNELS']);
|
3225
|
-
}
|
3226
3306
|
var lang = attrs.LANGUAGE;
|
3227
3307
|
var assocLang = attrs['ASSOC-LANGUAGE'];
|
3228
3308
|
var channels = attrs.CHANNELS;
|
@@ -3269,6 +3349,7 @@
|
|
3269
3349
|
M3U8Parser.parseLevelPlaylist = function parseLevelPlaylist(string, baseurl, id, type, levelUrlId, multivariantVariableList) {
|
3270
3350
|
var level = new LevelDetails(baseurl);
|
3271
3351
|
var fragments = level.fragments;
|
3352
|
+
var programDateTimes = [];
|
3272
3353
|
// The most recent init segment seen (applies to all subsequent segments)
|
3273
3354
|
var currentInitSegment = null;
|
3274
3355
|
var currentSN = 0;
|
@@ -3327,7 +3408,7 @@
|
|
3327
3408
|
// avoid sliced strings https://github.com/video-dev/hls.js/issues/939
|
3328
3409
|
var uri = (' ' + result[3]).slice(1);
|
3329
3410
|
frag.relurl = substituteVariables(level, uri) ;
|
3330
|
-
assignProgramDateTime(frag, prevFrag);
|
3411
|
+
assignProgramDateTime(frag, prevFrag, programDateTimes);
|
3331
3412
|
prevFrag = frag;
|
3332
3413
|
totalduration += frag.duration;
|
3333
3414
|
currentSN++;
|
@@ -3375,22 +3456,22 @@
|
|
3375
3456
|
break;
|
3376
3457
|
case 'SKIP':
|
3377
3458
|
{
|
3378
|
-
|
3379
|
-
|
3380
|
-
substituteVariablesInAttributes(level, skipAttrs, ['RECENTLY-REMOVED-DATERANGES']);
|
3459
|
+
if (level.skippedSegments) {
|
3460
|
+
level.playlistParsingError = new Error("#EXT-X-SKIP MUST NOT appear more than once in a Playlist");
|
3381
3461
|
}
|
3462
|
+
var skipAttrs = new AttrList(value1, level);
|
3382
3463
|
var skippedSegments = skipAttrs.decimalInteger('SKIPPED-SEGMENTS');
|
3383
3464
|
if (isFiniteNumber(skippedSegments)) {
|
3384
|
-
level.skippedSegments
|
3465
|
+
level.skippedSegments += skippedSegments;
|
3385
3466
|
// This will result in fragments[] containing undefined values, which we will fill in with `mergeDetails`
|
3386
3467
|
for (var _i = skippedSegments; _i--;) {
|
3387
|
-
fragments.
|
3468
|
+
fragments.push(null);
|
3388
3469
|
}
|
3389
3470
|
currentSN += skippedSegments;
|
3390
3471
|
}
|
3391
3472
|
var recentlyRemovedDateranges = skipAttrs.enumeratedString('RECENTLY-REMOVED-DATERANGES');
|
3392
3473
|
if (recentlyRemovedDateranges) {
|
3393
|
-
level.recentlyRemovedDateranges = recentlyRemovedDateranges.split('\t');
|
3474
|
+
level.recentlyRemovedDateranges = (level.recentlyRemovedDateranges || []).concat(recentlyRemovedDateranges.split('\t'));
|
3394
3475
|
}
|
3395
3476
|
break;
|
3396
3477
|
}
|
@@ -3424,12 +3505,9 @@
|
|
3424
3505
|
break;
|
3425
3506
|
case 'DATERANGE':
|
3426
3507
|
{
|
3427
|
-
var dateRangeAttr = new AttrList(value1);
|
3428
|
-
|
3429
|
-
|
3430
|
-
substituteVariablesInAttributes(level, dateRangeAttr, dateRangeAttr.clientAttrs);
|
3431
|
-
}
|
3432
|
-
var dateRange = new DateRange(dateRangeAttr, level.dateRanges[dateRangeAttr.ID]);
|
3508
|
+
var dateRangeAttr = new AttrList(value1, level);
|
3509
|
+
var dateRange = new DateRange(dateRangeAttr, level.dateRanges[dateRangeAttr.ID], level.dateRangeTagCount);
|
3510
|
+
level.dateRangeTagCount++;
|
3433
3511
|
if (dateRange.isValid || level.skippedSegments) {
|
3434
3512
|
level.dateRanges[dateRange.id] = dateRange;
|
3435
3513
|
} else {
|
@@ -3442,8 +3520,7 @@
|
|
3442
3520
|
case 'DEFINE':
|
3443
3521
|
{
|
3444
3522
|
{
|
3445
|
-
var variableAttributes = new AttrList(value1);
|
3446
|
-
substituteVariablesInAttributes(level, variableAttributes, ['NAME', 'VALUE', 'IMPORT', 'QUERYPARAM']);
|
3523
|
+
var variableAttributes = new AttrList(value1, level);
|
3447
3524
|
if ('IMPORT' in variableAttributes) {
|
3448
3525
|
importVariableDefinition(level, variableAttributes, multivariantVariableList);
|
3449
3526
|
} else {
|
@@ -3480,10 +3557,7 @@
|
|
3480
3557
|
break;
|
3481
3558
|
case 'MAP':
|
3482
3559
|
{
|
3483
|
-
var mapAttrs = new AttrList(value1);
|
3484
|
-
{
|
3485
|
-
substituteVariablesInAttributes(level, mapAttrs, ['BYTERANGE', 'URI']);
|
3486
|
-
}
|
3560
|
+
var mapAttrs = new AttrList(value1, level);
|
3487
3561
|
if (frag.duration) {
|
3488
3562
|
// Initial segment tag is after segment duration tag.
|
3489
3563
|
// #EXTINF: 6.0
|
@@ -3509,6 +3583,7 @@
|
|
3509
3583
|
currentInitSegment = frag;
|
3510
3584
|
createNextFrag = true;
|
3511
3585
|
}
|
3586
|
+
currentInitSegment.cc = discontinuityCounter;
|
3512
3587
|
break;
|
3513
3588
|
}
|
3514
3589
|
case 'SERVER-CONTROL':
|
@@ -3535,10 +3610,7 @@
|
|
3535
3610
|
}
|
3536
3611
|
var previousFragmentPart = currentPart > 0 ? partList[partList.length - 1] : undefined;
|
3537
3612
|
var index = currentPart++;
|
3538
|
-
var partAttrs = new AttrList(value1);
|
3539
|
-
{
|
3540
|
-
substituteVariablesInAttributes(level, partAttrs, ['BYTERANGE', 'URI']);
|
3541
|
-
}
|
3613
|
+
var partAttrs = new AttrList(value1, level);
|
3542
3614
|
var part = new Part(partAttrs, frag, baseurl, index, previousFragmentPart);
|
3543
3615
|
partList.push(part);
|
3544
3616
|
frag.duration += part.duration;
|
@@ -3546,19 +3618,13 @@
|
|
3546
3618
|
}
|
3547
3619
|
case 'PRELOAD-HINT':
|
3548
3620
|
{
|
3549
|
-
var preloadHintAttrs = new AttrList(value1);
|
3550
|
-
{
|
3551
|
-
substituteVariablesInAttributes(level, preloadHintAttrs, ['URI']);
|
3552
|
-
}
|
3621
|
+
var preloadHintAttrs = new AttrList(value1, level);
|
3553
3622
|
level.preloadHint = preloadHintAttrs;
|
3554
3623
|
break;
|
3555
3624
|
}
|
3556
3625
|
case 'RENDITION-REPORT':
|
3557
3626
|
{
|
3558
|
-
var renditionReportAttrs = new AttrList(value1);
|
3559
|
-
{
|
3560
|
-
substituteVariablesInAttributes(level, renditionReportAttrs, ['URI']);
|
3561
|
-
}
|
3627
|
+
var renditionReportAttrs = new AttrList(value1, level);
|
3562
3628
|
level.renditionReports = level.renditionReports || [];
|
3563
3629
|
level.renditionReports.push(renditionReportAttrs);
|
3564
3630
|
break;
|
@@ -3576,7 +3642,7 @@
|
|
3576
3642
|
level.fragmentHint = prevFrag;
|
3577
3643
|
}
|
3578
3644
|
} else if (level.partList) {
|
3579
|
-
assignProgramDateTime(frag, prevFrag);
|
3645
|
+
assignProgramDateTime(frag, prevFrag, programDateTimes);
|
3580
3646
|
frag.cc = discontinuityCounter;
|
3581
3647
|
level.fragmentHint = frag;
|
3582
3648
|
if (levelkeys) {
|
@@ -3597,6 +3663,21 @@
|
|
3597
3663
|
if (firstFragment) {
|
3598
3664
|
level.startCC = firstFragment.cc;
|
3599
3665
|
}
|
3666
|
+
/**
|
3667
|
+
* Backfill any missing PDT values
|
3668
|
+
* "If the first EXT-X-PROGRAM-DATE-TIME tag in a Playlist appears after
|
3669
|
+
* one or more Media Segment URIs, the client SHOULD extrapolate
|
3670
|
+
* backward from that tag (using EXTINF durations and/or media
|
3671
|
+
* timestamps) to associate dates with those segments."
|
3672
|
+
* We have already extrapolated forward, but all fragments up to the first instance of PDT do not have their PDTs
|
3673
|
+
* computed.
|
3674
|
+
*/
|
3675
|
+
if (firstPdtIndex > 0) {
|
3676
|
+
backfillProgramDateTimes(fragments, firstPdtIndex);
|
3677
|
+
if (firstFragment) {
|
3678
|
+
programDateTimes.unshift(firstFragment);
|
3679
|
+
}
|
3680
|
+
}
|
3600
3681
|
} else {
|
3601
3682
|
level.endSN = 0;
|
3602
3683
|
level.startCC = 0;
|
@@ -3605,31 +3686,63 @@
|
|
3605
3686
|
totalduration += level.fragmentHint.duration;
|
3606
3687
|
}
|
3607
3688
|
level.totalduration = totalduration;
|
3608
|
-
level.
|
3609
|
-
|
3610
|
-
/**
|
3611
|
-
* Backfill any missing PDT values
|
3612
|
-
* "If the first EXT-X-PROGRAM-DATE-TIME tag in a Playlist appears after
|
3613
|
-
* one or more Media Segment URIs, the client SHOULD extrapolate
|
3614
|
-
* backward from that tag (using EXTINF durations and/or media
|
3615
|
-
* timestamps) to associate dates with those segments."
|
3616
|
-
* We have already extrapolated forward, but all fragments up to the first instance of PDT do not have their PDTs
|
3617
|
-
* computed.
|
3618
|
-
*/
|
3619
|
-
if (firstPdtIndex > 0) {
|
3620
|
-
backfillProgramDateTimes(fragments, firstPdtIndex);
|
3689
|
+
if (programDateTimes.length && level.dateRangeTagCount && firstFragment) {
|
3690
|
+
mapDateRanges(programDateTimes, level);
|
3621
3691
|
}
|
3692
|
+
level.endCC = discontinuityCounter;
|
3622
3693
|
return level;
|
3623
3694
|
};
|
3624
3695
|
return M3U8Parser;
|
3625
3696
|
}();
|
3697
|
+
function mapDateRanges(programDateTimes, details) {
|
3698
|
+
// Make sure DateRanges are mapped to a ProgramDateTime tag that applies a date to a segment that overlaps with its start date
|
3699
|
+
var programDateTimeCount = programDateTimes.length;
|
3700
|
+
var lastProgramDateTime = programDateTimes[programDateTimeCount - 1];
|
3701
|
+
var playlistEnd = details.live ? Infinity : details.totalduration;
|
3702
|
+
var dateRangeIds = Object.keys(details.dateRanges);
|
3703
|
+
for (var i = dateRangeIds.length; i--;) {
|
3704
|
+
var dateRange = details.dateRanges[dateRangeIds[i]];
|
3705
|
+
var startDateTime = dateRange.startDate.getTime();
|
3706
|
+
dateRange.tagAnchor = lastProgramDateTime;
|
3707
|
+
for (var j = programDateTimeCount; j--;) {
|
3708
|
+
var fragIndex = findFragmentWithStartDate(details, startDateTime, programDateTimes, j, playlistEnd);
|
3709
|
+
if (fragIndex !== -1) {
|
3710
|
+
dateRange.tagAnchor = details.fragments[fragIndex];
|
3711
|
+
break;
|
3712
|
+
}
|
3713
|
+
}
|
3714
|
+
}
|
3715
|
+
}
|
3716
|
+
function findFragmentWithStartDate(details, startDateTime, programDateTimes, index, endTime) {
|
3717
|
+
var pdtFragment = programDateTimes[index];
|
3718
|
+
if (pdtFragment) {
|
3719
|
+
var _programDateTimes;
|
3720
|
+
// find matching range between PDT tags
|
3721
|
+
var durationBetweenPdt = (((_programDateTimes = programDateTimes[index + 1]) == null ? void 0 : _programDateTimes.start) || endTime) - pdtFragment.start;
|
3722
|
+
var pdtStart = pdtFragment.programDateTime;
|
3723
|
+
if ((startDateTime >= pdtStart || index === 0) && startDateTime <= pdtStart + durationBetweenPdt * 1000) {
|
3724
|
+
// map to fragment with date-time range
|
3725
|
+
var startIndex = programDateTimes[index].sn - details.startSN;
|
3726
|
+
var fragments = details.fragments;
|
3727
|
+
if (fragments.length > programDateTimes.length) {
|
3728
|
+
var endSegment = programDateTimes[index + 1] || fragments[fragments.length - 1];
|
3729
|
+
var endIndex = endSegment.sn - details.startSN;
|
3730
|
+
for (var i = endIndex; i > startIndex; i--) {
|
3731
|
+
var fragStartDateTime = fragments[i].programDateTime;
|
3732
|
+
if (startDateTime >= fragStartDateTime && startDateTime < fragStartDateTime + fragments[i].duration * 1000) {
|
3733
|
+
return i;
|
3734
|
+
}
|
3735
|
+
}
|
3736
|
+
}
|
3737
|
+
return startIndex;
|
3738
|
+
}
|
3739
|
+
}
|
3740
|
+
return -1;
|
3741
|
+
}
|
3626
3742
|
function parseKey(keyTagAttributes, baseurl, parsed) {
|
3627
3743
|
var _keyAttrs$METHOD, _keyAttrs$KEYFORMAT;
|
3628
3744
|
// https://tools.ietf.org/html/rfc8216#section-4.3.2.4
|
3629
|
-
var keyAttrs = new AttrList(keyTagAttributes);
|
3630
|
-
{
|
3631
|
-
substituteVariablesInAttributes(parsed, keyAttrs, ['KEYFORMAT', 'KEYFORMATVERSIONS', 'URI', 'IV', 'URI']);
|
3632
|
-
}
|
3745
|
+
var keyAttrs = new AttrList(keyTagAttributes, parsed);
|
3633
3746
|
var decryptmethod = (_keyAttrs$METHOD = keyAttrs.METHOD) != null ? _keyAttrs$METHOD : '';
|
3634
3747
|
var decrypturi = keyAttrs.URI;
|
3635
3748
|
var decryptiv = keyAttrs.hexadecimalInteger('IV');
|
@@ -3690,16 +3803,18 @@
|
|
3690
3803
|
fragPrev = frag;
|
3691
3804
|
}
|
3692
3805
|
}
|
3693
|
-
function assignProgramDateTime(frag, prevFrag) {
|
3806
|
+
function assignProgramDateTime(frag, prevFrag, programDateTimes) {
|
3694
3807
|
if (frag.rawProgramDateTime) {
|
3695
3808
|
frag.programDateTime = Date.parse(frag.rawProgramDateTime);
|
3809
|
+
if (!isFiniteNumber(frag.programDateTime)) {
|
3810
|
+
frag.programDateTime = null;
|
3811
|
+
frag.rawProgramDateTime = null;
|
3812
|
+
return;
|
3813
|
+
}
|
3814
|
+
programDateTimes.push(frag);
|
3696
3815
|
} else if (prevFrag != null && prevFrag.programDateTime) {
|
3697
3816
|
frag.programDateTime = prevFrag.endProgramDateTime;
|
3698
3817
|
}
|
3699
|
-
if (!isFiniteNumber(frag.programDateTime)) {
|
3700
|
-
frag.programDateTime = null;
|
3701
|
-
frag.rawProgramDateTime = null;
|
3702
|
-
}
|
3703
3818
|
}
|
3704
3819
|
function setInitSegment(frag, mapAttrs, id, levelkeys) {
|
3705
3820
|
frag.relurl = mapAttrs.URI;
|
@@ -4923,9 +5038,6 @@
|
|
4923
5038
|
}
|
4924
5039
|
return Number.POSITIVE_INFINITY;
|
4925
5040
|
}();
|
4926
|
-
function dateRangeDateToTimelineSeconds(date, offset) {
|
4927
|
-
return date.getTime() / 1000 - offset;
|
4928
|
-
}
|
4929
5041
|
function hexToArrayBuffer(str) {
|
4930
5042
|
return Uint8Array.from(str.replace(/^0x/, '').replace(/([\da-fA-F]{2}) ?/g, '0x$1 ').replace(/ +$/, '').split(' ')).buffer;
|
4931
5043
|
}
|
@@ -4955,6 +5067,7 @@
|
|
4955
5067
|
hls.on(Events.FRAG_PARSING_METADATA, this.onFragParsingMetadata, this);
|
4956
5068
|
hls.on(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
|
4957
5069
|
hls.on(Events.LEVEL_UPDATED, this.onLevelUpdated, this);
|
5070
|
+
hls.on(Events.LEVEL_PTS_UPDATED, this.onLevelPtsUpdated, this);
|
4958
5071
|
};
|
4959
5072
|
_proto._unregisterListeners = function _unregisterListeners() {
|
4960
5073
|
var hls = this.hls;
|
@@ -4964,6 +5077,7 @@
|
|
4964
5077
|
hls.off(Events.FRAG_PARSING_METADATA, this.onFragParsingMetadata, this);
|
4965
5078
|
hls.off(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
|
4966
5079
|
hls.off(Events.LEVEL_UPDATED, this.onLevelUpdated, this);
|
5080
|
+
hls.off(Events.LEVEL_PTS_UPDATED, this.onLevelPtsUpdated, this);
|
4967
5081
|
}
|
4968
5082
|
|
4969
5083
|
// Add ID3 metatadata text track.
|
@@ -5096,8 +5210,16 @@
|
|
5096
5210
|
}
|
5097
5211
|
};
|
5098
5212
|
_proto.onLevelUpdated = function onLevelUpdated(event, _ref2) {
|
5099
|
-
var _this = this;
|
5100
5213
|
var details = _ref2.details;
|
5214
|
+
this.updateDateRangeCues(details, true);
|
5215
|
+
};
|
5216
|
+
_proto.onLevelPtsUpdated = function onLevelPtsUpdated(event, data) {
|
5217
|
+
if (Math.abs(data.drift) > 0.01) {
|
5218
|
+
this.updateDateRangeCues(data.details);
|
5219
|
+
}
|
5220
|
+
};
|
5221
|
+
_proto.updateDateRangeCues = function updateDateRangeCues(details, removeOldCues) {
|
5222
|
+
var _this = this;
|
5101
5223
|
if (!this.media || !details.hasProgramDateTime || !this.hls.config.enableDateRangeMetadataCues) {
|
5102
5224
|
return;
|
5103
5225
|
}
|
@@ -5106,7 +5228,7 @@
|
|
5106
5228
|
var dateRanges = details.dateRanges;
|
5107
5229
|
var ids = Object.keys(dateRanges);
|
5108
5230
|
// Remove cues from track not found in details.dateRanges
|
5109
|
-
if (id3Track) {
|
5231
|
+
if (id3Track && removeOldCues) {
|
5110
5232
|
var idsToRemove = Object.keys(dateRangeCuesAppended).filter(function (id) {
|
5111
5233
|
return !ids.includes(id);
|
5112
5234
|
});
|
@@ -5129,21 +5251,21 @@
|
|
5129
5251
|
if (!this.id3Track) {
|
5130
5252
|
this.id3Track = this.createTrack(this.media);
|
5131
5253
|
}
|
5132
|
-
var dateTimeOffset = lastFragment.programDateTime / 1000 - lastFragment.start;
|
5133
5254
|
var Cue = getCueClass();
|
5134
5255
|
var _loop2 = function _loop2() {
|
5135
5256
|
var id = ids[_i];
|
5136
5257
|
var dateRange = dateRanges[id];
|
5137
|
-
var startTime =
|
5258
|
+
var startTime = dateRange.startTime;
|
5138
5259
|
|
5139
5260
|
// Process DateRanges to determine end-time (known DURATION, END-DATE, or END-ON-NEXT)
|
5140
5261
|
var appendedDateRangeCues = dateRangeCuesAppended[id];
|
5141
5262
|
var cues = (appendedDateRangeCues == null ? void 0 : appendedDateRangeCues.cues) || {};
|
5142
5263
|
var durationKnown = (appendedDateRangeCues == null ? void 0 : appendedDateRangeCues.durationKnown) || false;
|
5143
5264
|
var endTime = MAX_CUE_ENDTIME;
|
5144
|
-
var
|
5145
|
-
|
5146
|
-
|
5265
|
+
var duration = dateRange.duration,
|
5266
|
+
endDate = dateRange.endDate;
|
5267
|
+
if (endDate && duration !== null) {
|
5268
|
+
endTime = startTime + duration;
|
5147
5269
|
durationKnown = true;
|
5148
5270
|
} else if (dateRange.endOnNext && !durationKnown) {
|
5149
5271
|
var nextDateRangeWithSameClass = ids.reduce(function (candidateDateRange, id) {
|
@@ -5156,7 +5278,7 @@
|
|
5156
5278
|
return candidateDateRange;
|
5157
5279
|
}, null);
|
5158
5280
|
if (nextDateRangeWithSameClass) {
|
5159
|
-
endTime =
|
5281
|
+
endTime = nextDateRangeWithSameClass.startTime;
|
5160
5282
|
durationKnown = true;
|
5161
5283
|
}
|
5162
5284
|
}
|
@@ -5173,6 +5295,9 @@
|
|
5173
5295
|
if (cue) {
|
5174
5296
|
if (durationKnown && !appendedDateRangeCues.durationKnown) {
|
5175
5297
|
cue.endTime = endTime;
|
5298
|
+
} else if (Math.abs(cue.startTime - startTime) > 0.01) {
|
5299
|
+
cue.startTime = startTime;
|
5300
|
+
cue.endTime = endTime;
|
5176
5301
|
}
|
5177
5302
|
} else if (Cue) {
|
5178
5303
|
var data = dateRange.attr[key];
|
@@ -5703,7 +5828,7 @@
|
|
5703
5828
|
frag.endPTS = endPTS;
|
5704
5829
|
frag.minEndPTS = minEndPTS;
|
5705
5830
|
frag.endDTS = endDTS;
|
5706
|
-
var sn = frag.sn;
|
5831
|
+
var sn = frag.sn;
|
5707
5832
|
// exit if sn out of range
|
5708
5833
|
if (!details || sn < details.startSN || sn > details.endSN) {
|
5709
5834
|
return 0;
|
@@ -5781,8 +5906,8 @@
|
|
5781
5906
|
currentInitSegment = oldFrag.initSegment;
|
5782
5907
|
}
|
5783
5908
|
});
|
5909
|
+
var fragmentsToCheck = newDetails.fragmentHint ? newDetails.fragments.concat(newDetails.fragmentHint) : newDetails.fragments;
|
5784
5910
|
if (currentInitSegment) {
|
5785
|
-
var fragmentsToCheck = newDetails.fragmentHint ? newDetails.fragments.concat(newDetails.fragmentHint) : newDetails.fragments;
|
5786
5911
|
fragmentsToCheck.forEach(function (frag) {
|
5787
5912
|
var _currentInitSegment;
|
5788
5913
|
if (frag && (!frag.initSegment || frag.initSegment.relurl === ((_currentInitSegment = currentInitSegment) == null ? void 0 : _currentInitSegment.relurl))) {
|
@@ -5801,15 +5926,28 @@
|
|
5801
5926
|
}
|
5802
5927
|
newDetails.startSN = newDetails.fragments[0].sn;
|
5803
5928
|
newDetails.startCC = newDetails.fragments[0].cc;
|
5804
|
-
} else
|
5805
|
-
|
5929
|
+
} else {
|
5930
|
+
if (newDetails.canSkipDateRanges) {
|
5931
|
+
newDetails.dateRanges = mergeDateRanges(oldDetails.dateRanges, newDetails);
|
5932
|
+
}
|
5933
|
+
var programDateTimes = oldDetails.fragments.filter(function (frag) {
|
5934
|
+
return frag.rawProgramDateTime;
|
5935
|
+
});
|
5936
|
+
if (oldDetails.hasProgramDateTime && !newDetails.hasProgramDateTime) {
|
5937
|
+
for (var _i2 = 1; _i2 < fragmentsToCheck.length; _i2++) {
|
5938
|
+
if (fragmentsToCheck[_i2].programDateTime === null) {
|
5939
|
+
assignProgramDateTime(fragmentsToCheck[_i2], fragmentsToCheck[_i2 - 1], programDateTimes);
|
5940
|
+
}
|
5941
|
+
}
|
5942
|
+
}
|
5943
|
+
mapDateRanges(programDateTimes, newDetails);
|
5806
5944
|
}
|
5807
5945
|
}
|
5808
5946
|
var newFragments = newDetails.fragments;
|
5809
5947
|
if (ccOffset) {
|
5810
5948
|
logger.warn('discontinuity sliding from playlist, take drift into account');
|
5811
|
-
for (var
|
5812
|
-
newFragments[
|
5949
|
+
for (var _i3 = 0; _i3 < newFragments.length; _i3++) {
|
5950
|
+
newFragments[_i3].cc += ccOffset;
|
5813
5951
|
}
|
5814
5952
|
}
|
5815
5953
|
if (newDetails.skippedSegments) {
|
@@ -5851,21 +5989,31 @@
|
|
5851
5989
|
newDetails.advancedDateTime = oldDetails.advancedDateTime;
|
5852
5990
|
}
|
5853
5991
|
}
|
5854
|
-
function mergeDateRanges(oldDateRanges,
|
5992
|
+
function mergeDateRanges(oldDateRanges, newDetails) {
|
5993
|
+
var deltaDateRanges = newDetails.dateRanges,
|
5994
|
+
recentlyRemovedDateranges = newDetails.recentlyRemovedDateranges;
|
5855
5995
|
var dateRanges = _extends({}, oldDateRanges);
|
5856
5996
|
if (recentlyRemovedDateranges) {
|
5857
5997
|
recentlyRemovedDateranges.forEach(function (id) {
|
5858
5998
|
delete dateRanges[id];
|
5859
5999
|
});
|
5860
6000
|
}
|
5861
|
-
Object.keys(
|
5862
|
-
|
5863
|
-
|
5864
|
-
|
5865
|
-
|
5866
|
-
|
5867
|
-
|
5868
|
-
|
6001
|
+
var mergeIds = Object.keys(dateRanges);
|
6002
|
+
var mergeCount = mergeIds.length;
|
6003
|
+
if (mergeCount) {
|
6004
|
+
Object.keys(deltaDateRanges).forEach(function (id) {
|
6005
|
+
var mergedDateRange = dateRanges[id];
|
6006
|
+
var dateRange = new DateRange(deltaDateRanges[id].attr, mergedDateRange);
|
6007
|
+
if (dateRange.isValid) {
|
6008
|
+
dateRanges[id] = dateRange;
|
6009
|
+
if (!mergedDateRange) {
|
6010
|
+
dateRange.tagOrder += mergeCount;
|
6011
|
+
}
|
6012
|
+
} else {
|
6013
|
+
logger.warn("Ignoring invalid Playlist Delta Update DATERANGE tag: \"" + JSON.stringify(deltaDateRanges[id].attr) + "\"");
|
6014
|
+
}
|
6015
|
+
});
|
6016
|
+
}
|
5869
6017
|
return dateRanges;
|
5870
6018
|
}
|
5871
6019
|
function mapPartIntersection(oldParts, newParts, intersectionFn) {
|
@@ -5892,7 +6040,7 @@
|
|
5892
6040
|
for (var i = start; i <= end; i++) {
|
5893
6041
|
var _oldFrag = oldFrags[delta + i];
|
5894
6042
|
var _newFrag = newFrags[i];
|
5895
|
-
if (skippedSegments && !_newFrag &&
|
6043
|
+
if (skippedSegments && !_newFrag && _oldFrag) {
|
5896
6044
|
// Fill in skipped segments in delta playlist
|
5897
6045
|
_newFrag = newDetails.fragments[i] = _oldFrag;
|
5898
6046
|
}
|
@@ -5945,19 +6093,19 @@
|
|
5945
6093
|
return Math.round(reloadInterval);
|
5946
6094
|
}
|
5947
6095
|
function getFragmentWithSN(level, sn, fragCurrent) {
|
5948
|
-
|
6096
|
+
var details = level == null ? void 0 : level.details;
|
6097
|
+
if (!details) {
|
5949
6098
|
return null;
|
5950
6099
|
}
|
5951
|
-
var
|
5952
|
-
var fragment = levelDetails.fragments[sn - levelDetails.startSN];
|
6100
|
+
var fragment = details.fragments[sn - details.startSN];
|
5953
6101
|
if (fragment) {
|
5954
6102
|
return fragment;
|
5955
6103
|
}
|
5956
|
-
fragment =
|
6104
|
+
fragment = details.fragmentHint;
|
5957
6105
|
if (fragment && fragment.sn === sn) {
|
5958
6106
|
return fragment;
|
5959
6107
|
}
|
5960
|
-
if (sn <
|
6108
|
+
if (sn < details.startSN && fragCurrent && fragCurrent.sn === sn) {
|
5961
6109
|
return fragCurrent;
|
5962
6110
|
}
|
5963
6111
|
return null;
|
@@ -8333,11 +8481,10 @@
|
|
8333
8481
|
_proto.detectPartialFragments = function detectPartialFragments(data) {
|
8334
8482
|
var _this2 = this;
|
8335
8483
|
var timeRanges = this.timeRanges;
|
8336
|
-
|
8337
|
-
part = data.part;
|
8338
|
-
if (!timeRanges || frag.sn === 'initSegment') {
|
8484
|
+
if (!timeRanges || data.frag.sn === 'initSegment') {
|
8339
8485
|
return;
|
8340
8486
|
}
|
8487
|
+
var frag = data.frag;
|
8341
8488
|
var fragKey = getFragmentKey(frag);
|
8342
8489
|
var fragmentEntity = this.fragments[fragKey];
|
8343
8490
|
if (!fragmentEntity || fragmentEntity.buffered && frag.gap) {
|
@@ -8351,7 +8498,7 @@
|
|
8351
8498
|
}
|
8352
8499
|
var timeRange = timeRanges[elementaryStream];
|
8353
8500
|
var partial = isFragHint || streamInfo.partial === true;
|
8354
|
-
fragmentEntity.range[elementaryStream] = _this2.getBufferedTimes(frag, part, partial, timeRange);
|
8501
|
+
fragmentEntity.range[elementaryStream] = _this2.getBufferedTimes(frag, data.part, partial, timeRange);
|
8355
8502
|
});
|
8356
8503
|
fragmentEntity.loaded = null;
|
8357
8504
|
if (Object.keys(fragmentEntity.range).length) {
|
@@ -8504,16 +8651,14 @@
|
|
8504
8651
|
return false;
|
8505
8652
|
};
|
8506
8653
|
_proto.onFragLoaded = function onFragLoaded(event, data) {
|
8507
|
-
var frag = data.frag,
|
8508
|
-
part = data.part;
|
8509
8654
|
// don't track initsegment (for which sn is not a number)
|
8510
8655
|
// don't track frags used for bitrateTest, they're irrelevant.
|
8511
|
-
if (frag.sn === 'initSegment' || frag.bitrateTest) {
|
8656
|
+
if (data.frag.sn === 'initSegment' || data.frag.bitrateTest) {
|
8512
8657
|
return;
|
8513
8658
|
}
|
8514
|
-
|
8659
|
+
var frag = data.frag;
|
8515
8660
|
// Fragment entity `loaded` FragLoadedData is null when loading parts
|
8516
|
-
var loaded = part ? null : data;
|
8661
|
+
var loaded = data.part ? null : data;
|
8517
8662
|
var fragKey = getFragmentKey(frag);
|
8518
8663
|
this.fragments[fragKey] = {
|
8519
8664
|
body: frag,
|
@@ -10403,14 +10548,12 @@
|
|
10403
10548
|
part.stats.parsing.end = now;
|
10404
10549
|
}
|
10405
10550
|
// See if part loading should be disabled/enabled based on buffer and playback position.
|
10406
|
-
|
10407
|
-
|
10408
|
-
|
10409
|
-
|
10410
|
-
|
10411
|
-
|
10412
|
-
this.loadingParts = shouldLoadParts;
|
10413
|
-
}
|
10551
|
+
var levelDetails = this.getLevelDetails();
|
10552
|
+
var loadingPartsAtEdge = levelDetails && frag.sn > levelDetails.endSN;
|
10553
|
+
var shouldLoadParts = loadingPartsAtEdge || this.shouldLoadParts(levelDetails, frag.end);
|
10554
|
+
if (shouldLoadParts !== this.loadingParts) {
|
10555
|
+
this.log("LL-Part loading " + (shouldLoadParts ? 'ON' : 'OFF') + " after parsing segment ending @" + frag.end.toFixed(2));
|
10556
|
+
this.loadingParts = shouldLoadParts;
|
10414
10557
|
}
|
10415
10558
|
this.updateLevelTiming(frag, part, level, chunkMeta.partial);
|
10416
10559
|
};
|
@@ -17491,7 +17634,7 @@
|
|
17491
17634
|
baseTime: initPTS,
|
17492
17635
|
timescale: timescale
|
17493
17636
|
};
|
17494
|
-
this.log("InitPTS for cc: " + cc + " found from main: " + initPTS);
|
17637
|
+
this.log("InitPTS for cc: " + cc + " found from main: " + initPTS + "/" + timescale);
|
17495
17638
|
this.videoTrackCC = cc;
|
17496
17639
|
// If we are waiting, tick immediately to unblock audio fragment transmuxing
|
17497
17640
|
if (this.state === State.WAITING_INIT_PTS) {
|
@@ -17823,8 +17966,8 @@
|
|
17823
17966
|
};
|
17824
17967
|
_proto._handleFragmentLoadProgress = function _handleFragmentLoadProgress(data) {
|
17825
17968
|
var _frag$initSegment;
|
17826
|
-
var frag = data.frag
|
17827
|
-
|
17969
|
+
var frag = data.frag;
|
17970
|
+
var part = data.part,
|
17828
17971
|
payload = data.payload;
|
17829
17972
|
var config = this.config,
|
17830
17973
|
trackId = this.trackId,
|
@@ -29010,8 +29153,8 @@
|
|
29010
29153
|
};
|
29011
29154
|
_proto._handleFragmentLoadProgress = function _handleFragmentLoadProgress(data) {
|
29012
29155
|
var _frag$initSegment;
|
29013
|
-
var frag = data.frag
|
29014
|
-
|
29156
|
+
var frag = data.frag;
|
29157
|
+
var part = data.part,
|
29015
29158
|
payload = data.payload;
|
29016
29159
|
var levels = this.levels;
|
29017
29160
|
if (!levels) {
|
@@ -29351,7 +29494,7 @@
|
|
29351
29494
|
}
|
29352
29495
|
|
29353
29496
|
// Avoid buffering if backtracking this fragment
|
29354
|
-
if (video && details
|
29497
|
+
if (video && details) {
|
29355
29498
|
var prevFrag = details.fragments[frag.sn - 1 - details.startSN];
|
29356
29499
|
var isFirstFragment = frag.sn === details.startSN;
|
29357
29500
|
var isFirstInDiscontinuity = !prevFrag || frag.cc > prevFrag.cc;
|
@@ -30520,7 +30663,7 @@
|
|
30520
30663
|
* Get the video-dev/hls.js package version.
|
30521
30664
|
*/
|
30522
30665
|
function get() {
|
30523
|
-
return "1.5.12-0.canary.
|
30666
|
+
return "1.5.12-0.canary.10341";
|
30524
30667
|
}
|
30525
30668
|
}, {
|
30526
30669
|
key: "Events",
|