UNPKG

rx-player

Version:
150 lines (135 loc) 5.3 kB
/** * Copyright 2015 CANAL+ Group * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import type { ISegment } from "../../../../../manifest"; import type { IEMSG } from "../../../../containers/isobmff"; import type { IIndexSegment } from "../../../utils/index_helpers"; import { calculateRepeat, toIndexTime } from "../../../utils/index_helpers"; import type ManifestBoundsCalculator from "../manifest_bounds_calculator"; import { createDashUrlDetokenizer } from "./tokens"; /** * For the given start time and duration of a timeline element, calculate how * much this element should be repeated to contain the time given. * 0 being the same element, 1 being the next one etc. * @param {Number} segmentStartTime * @param {Number} segmentDuration * @param {Number} wantedTime * @returns {Number} */ function getWantedRepeatIndex( segmentStartTime: number, segmentDuration: number, wantedTime: number, ): number { const diff = wantedTime - segmentStartTime; return diff > 0 ? Math.floor(diff / segmentDuration) : 0; } /** * Get a list of Segments for the time range wanted. * @param {Object} index - index object, constructed by parsing the manifest. * @param {number} from - starting timestamp wanted, in seconds * @param {number} durationWanted - duration wanted, in seconds * @param {Object} manifestBoundsCalculator * @param {number|undefined} scaledPeriodEnd * @param {function} isEMSGWhitelisted * @returns {Array.<Object>} */ export default function getSegmentsFromTimeline( index: { availabilityTimeComplete?: boolean | undefined; availabilityTimeOffset?: number | undefined; segmentUrlTemplate: string | null; startNumber?: number | undefined; endNumber?: number | undefined; timeline: IIndexSegment[]; timescale: number; indexTimeOffset: number; }, from: number, durationWanted: number, manifestBoundsCalculator: ManifestBoundsCalculator, scaledPeriodEnd: number | undefined, isEMSGWhitelisted: (inbandEvent: IEMSG) => boolean, ): ISegment[] { const maximumTime = manifestBoundsCalculator.getEstimatedMaximumPosition( index.availabilityTimeOffset ?? 0, ); const wantedMaximum = Math.min(from + durationWanted, maximumTime ?? Infinity); const scaledUp = toIndexTime(from, index); const scaledTo = toIndexTime(wantedMaximum, index); const { timeline, timescale, segmentUrlTemplate, startNumber, endNumber } = index; let currentNumber = startNumber ?? 1; const segments: ISegment[] = []; const timelineLength = timeline.length; for (let i = 0; i < timelineLength; i++) { const timelineItem = timeline[i]; const { duration, start, range } = timelineItem; let maxRepeatTime; if (maximumTime === undefined) { maxRepeatTime = scaledPeriodEnd; } else { maxRepeatTime = Math.min(maximumTime * timescale, scaledPeriodEnd ?? Infinity); } const repeat = calculateRepeat(timelineItem, timeline[i + 1], maxRepeatTime); const complete = index.availabilityTimeComplete !== false || (i !== timelineLength - 1 && repeat !== 0); let segmentNumberInCurrentRange = getWantedRepeatIndex(start, duration, scaledUp); let segmentTime = start + segmentNumberInCurrentRange * duration; while (segmentTime < scaledTo && segmentNumberInCurrentRange <= repeat) { const segmentNumber = currentNumber + segmentNumberInCurrentRange; if (endNumber !== undefined && segmentNumber > endNumber) { break; } const detokenizedURL = segmentUrlTemplate === null ? null : createDashUrlDetokenizer(segmentTime, segmentNumber)(segmentUrlTemplate); let time = segmentTime - index.indexTimeOffset; let realDuration = duration; if (time < 0) { realDuration = duration + time; // Remove from duration the part before `0` time = 0; } const segment = { id: String(segmentTime), time: time / timescale, end: (time + realDuration) / timescale, duration: realDuration / timescale, isInit: false, range, timescale: 1 as const, url: detokenizedURL, number: segmentNumber, timestampOffset: -(index.indexTimeOffset / timescale), complete, privateInfos: { isEMSGWhitelisted }, }; segments.push(segment); // update segment number and segment time for the next segment segmentNumberInCurrentRange++; segmentTime = start + segmentNumberInCurrentRange * duration; } if (segmentTime >= scaledTo) { // we reached ``scaledTo``, we're done return segments; } currentNumber += repeat + 1; if (endNumber !== undefined && currentNumber > endNumber) { return segments; } } return segments; }