RockPaperScissors/node_modules/m3u8stream/dist/dash-mpd-parser.js
2021-12-02 17:15:29 +01:00

183 lines
7.3 KiB
JavaScript

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const stream_1 = require("stream");
const sax_1 = __importDefault(require("sax"));
const parse_time_1 = require("./parse-time");
/**
* A wrapper around sax that emits segments.
*/
class DashMPDParser extends stream_1.Writable {
constructor(targetID) {
super();
this._parser = sax_1.default.createStream(false, { lowercase: true });
this._parser.on('error', this.destroy.bind(this));
let lastTag;
let currtime = 0;
let seq = 0;
let segmentTemplate;
let timescale, offset, duration, baseURL;
let timeline = [];
let getSegments = false;
let gotSegments = false;
let isStatic;
let treeLevel;
let periodStart;
const tmpl = (str) => {
const context = {
RepresentationID: targetID,
Number: seq,
Time: currtime,
};
return str.replace(/\$(\w+)\$/g, (m, p1) => `${context[p1]}`);
};
this._parser.on('opentag', node => {
switch (node.name) {
case 'mpd':
currtime =
node.attributes.availabilitystarttime ?
new Date(node.attributes.availabilitystarttime).getTime() : 0;
isStatic = node.attributes.type !== 'dynamic';
break;
case 'period':
// Reset everything on <Period> tag.
seq = 0;
timescale = 1000;
duration = 0;
offset = 0;
baseURL = [];
treeLevel = 0;
periodStart = parse_time_1.durationStr(node.attributes.start) || 0;
break;
case 'segmentlist':
seq = parseInt(node.attributes.startnumber) || seq;
timescale = parseInt(node.attributes.timescale) || timescale;
duration = parseInt(node.attributes.duration) || duration;
offset = parseInt(node.attributes.presentationtimeoffset) || offset;
break;
case 'segmenttemplate':
segmentTemplate = node.attributes;
seq = parseInt(node.attributes.startnumber) || seq;
timescale = parseInt(node.attributes.timescale) || timescale;
break;
case 'segmenttimeline':
case 'baseurl':
lastTag = node.name;
break;
case 's':
timeline.push({
duration: parseInt(node.attributes.d),
repeat: parseInt(node.attributes.r),
time: parseInt(node.attributes.t),
});
break;
case 'adaptationset':
case 'representation':
treeLevel++;
if (!targetID) {
targetID = node.attributes.id;
}
getSegments = node.attributes.id === `${targetID}`;
if (getSegments) {
if (periodStart) {
currtime += periodStart;
}
if (offset) {
currtime -= offset / timescale * 1000;
}
this.emit('starttime', currtime);
}
break;
case 'initialization':
if (getSegments) {
this.emit('item', {
url: baseURL.filter(s => !!s).join('') + node.attributes.sourceurl,
seq: seq,
init: true,
duration: 0,
});
}
break;
case 'segmenturl':
if (getSegments) {
gotSegments = true;
let tl = timeline.shift();
let segmentDuration = ((tl === null || tl === void 0 ? void 0 : tl.duration) || duration) / timescale * 1000;
this.emit('item', {
url: baseURL.filter(s => !!s).join('') + node.attributes.media,
seq: seq++,
duration: segmentDuration,
});
currtime += segmentDuration;
}
break;
}
});
const onEnd = () => {
if (isStatic) {
this.emit('endlist');
}
if (!getSegments) {
this.destroy(Error(`Representation '${targetID}' not found`));
}
else {
this.emit('end');
}
};
this._parser.on('closetag', tagName => {
switch (tagName) {
case 'adaptationset':
case 'representation':
treeLevel--;
if (segmentTemplate && timeline.length) {
gotSegments = true;
if (segmentTemplate.initialization) {
this.emit('item', {
url: baseURL.filter(s => !!s).join('') +
tmpl(segmentTemplate.initialization),
seq: seq,
init: true,
duration: 0,
});
}
for (let { duration: itemDuration, repeat, time } of timeline) {
itemDuration = itemDuration / timescale * 1000;
repeat = repeat || 1;
currtime = time || currtime;
for (let i = 0; i < repeat; i++) {
this.emit('item', {
url: baseURL.filter(s => !!s).join('') +
tmpl(segmentTemplate.media),
seq: seq++,
duration: itemDuration,
});
currtime += itemDuration;
}
}
}
if (gotSegments) {
this.emit('endearly');
onEnd();
this._parser.removeAllListeners();
this.removeAllListeners('finish');
}
break;
}
});
this._parser.on('text', text => {
if (lastTag === 'baseurl') {
baseURL[treeLevel] = text;
lastTag = null;
}
});
this.on('finish', onEnd);
}
_write(chunk, encoding, callback) {
this._parser.write(chunk, encoding);
callback();
}
}
exports.default = DashMPDParser;
//# sourceMappingURL=dash-mpd-parser.js.map