Files
Vulture/VApp/node_modules/mpd-parser/src/segment/segmentBase.js

158 lines
4.8 KiB
JavaScript

import errors from '../errors';
import urlTypeConverter from './urlType';
import { parseByDuration } from './durationTimeParser';
import window from 'global/window';
/**
* Translates SegmentBase into a set of segments.
* (DASH SPEC Section 5.3.9.3.2) contains a set of <SegmentURL> nodes. Each
* node should be translated into segment.
*
* @param {Object} attributes
* Object containing all inherited attributes from parent elements with attribute
* names as keys
* @return {Object.<Array>} list of segments
*/
export const segmentsFromBase = (attributes) => {
const {
baseUrl,
initialization = {},
sourceDuration,
indexRange = '',
periodStart,
presentationTime,
number = 0,
duration
} = attributes;
// base url is required for SegmentBase to work, per spec (Section 5.3.9.2.1)
if (!baseUrl) {
throw new Error(errors.NO_BASE_URL);
}
const initSegment = urlTypeConverter({
baseUrl,
source: initialization.sourceURL,
range: initialization.range
});
const segment = urlTypeConverter({ baseUrl, source: baseUrl, indexRange });
segment.map = initSegment;
// If there is a duration, use it, otherwise use the given duration of the source
// (since SegmentBase is only for one total segment)
if (duration) {
const segmentTimeInfo = parseByDuration(attributes);
if (segmentTimeInfo.length) {
segment.duration = segmentTimeInfo[0].duration;
segment.timeline = segmentTimeInfo[0].timeline;
}
} else if (sourceDuration) {
segment.duration = sourceDuration;
segment.timeline = periodStart;
}
// If presentation time is provided, these segments are being generated by SIDX
// references, and should use the time provided. For the general case of SegmentBase,
// there should only be one segment in the period, so its presentation time is the same
// as its period start.
segment.presentationTime = presentationTime || periodStart;
segment.number = number;
return [segment];
};
/**
* Given a playlist, a sidx box, and a baseUrl, update the segment list of the playlist
* according to the sidx information given.
*
* playlist.sidx has metadadata about the sidx where-as the sidx param
* is the parsed sidx box itself.
*
* @param {Object} playlist the playlist to update the sidx information for
* @param {Object} sidx the parsed sidx box
* @return {Object} the playlist object with the updated sidx information
*/
export const addSidxSegmentsToPlaylist = (playlist, sidx, baseUrl) => {
// Retain init segment information
const initSegment = playlist.sidx.map ? playlist.sidx.map : null;
// Retain source duration from initial main manifest parsing
const sourceDuration = playlist.sidx.duration;
// Retain source timeline
const timeline = playlist.timeline || 0;
const sidxByteRange = playlist.sidx.byterange;
const sidxEnd = sidxByteRange.offset + sidxByteRange.length;
// Retain timescale of the parsed sidx
const timescale = sidx.timescale;
// referenceType 1 refers to other sidx boxes
const mediaReferences = sidx.references.filter(r => r.referenceType !== 1);
const segments = [];
const type = playlist.endList ? 'static' : 'dynamic';
const periodStart = playlist.sidx.timeline;
let presentationTime = periodStart;
let number = playlist.mediaSequence || 0;
// firstOffset is the offset from the end of the sidx box
let startIndex;
// eslint-disable-next-line
if (typeof sidx.firstOffset === 'bigint') {
startIndex = window.BigInt(sidxEnd) + sidx.firstOffset;
} else {
startIndex = sidxEnd + sidx.firstOffset;
}
for (let i = 0; i < mediaReferences.length; i++) {
const reference = sidx.references[i];
// size of the referenced (sub)segment
const size = reference.referencedSize;
// duration of the referenced (sub)segment, in the timescale
// this will be converted to seconds when generating segments
const duration = reference.subsegmentDuration;
// should be an inclusive range
let endIndex;
// eslint-disable-next-line
if (typeof startIndex === 'bigint') {
endIndex = startIndex + window.BigInt(size) - window.BigInt(1);
} else {
endIndex = startIndex + size - 1;
}
const indexRange = `${startIndex}-${endIndex}`;
const attributes = {
baseUrl,
timescale,
timeline,
periodStart,
presentationTime,
number,
duration,
sourceDuration,
indexRange,
type
};
const segment = segmentsFromBase(attributes)[0];
if (initSegment) {
segment.map = initSegment;
}
segments.push(segment);
if (typeof startIndex === 'bigint') {
startIndex += window.BigInt(size);
} else {
startIndex += size;
}
presentationTime += duration / timescale;
number++;
}
playlist.segments = segments;
return playlist;
};