UNPKG

@remotion/media-parser

Version:

A pure JavaScript library for parsing video files

116 lines (115 loc) 4.77 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getSeekingByteFromMatroska = void 0; const log_1 = require("../../../log"); const toSeconds = (timeInTimescale, track) => { return (timeInTimescale / track.timescale) * 1000; }; const findBiggestCueBeforeTime = ({ cues, time, track, }) => { let biggestCueBeforeTime; for (const cue of cues) { const cueTimeInSeconds = toSeconds(cue.timeInTimescale, track); if (cueTimeInSeconds < time && (!biggestCueBeforeTime || cueTimeInSeconds > toSeconds(biggestCueBeforeTime.timeInTimescale, track))) { biggestCueBeforeTime = cue; } } return biggestCueBeforeTime; }; const findKeyframeBeforeTime = ({ keyframes, time, }) => { let keyframeBeforeTime; for (const keyframe of keyframes) { if (keyframe.decodingTimeInSeconds < time && (!keyframeBeforeTime || keyframe.decodingTimeInSeconds > keyframeBeforeTime.decodingTimeInSeconds)) { keyframeBeforeTime = keyframe; } } return keyframeBeforeTime !== null && keyframeBeforeTime !== void 0 ? keyframeBeforeTime : null; }; const getByteFromCues = ({ cuesResponse, time, info, logLevel, }) => { if (!cuesResponse) { log_1.Log.trace(logLevel, 'Has no Matroska cues at the moment, cannot use them'); return null; } const { cues, segmentOffset } = cuesResponse; log_1.Log.trace(logLevel, 'Has Matroska cues. Will use them to perform a seek.'); const biggestCueBeforeTime = findBiggestCueBeforeTime({ cues, time, track: info.track, }); if (!biggestCueBeforeTime) { return null; } return { byte: biggestCueBeforeTime.clusterPositionInSegment + segmentOffset, timeInSeconds: toSeconds(biggestCueBeforeTime.timeInTimescale, info.track), }; }; const getSeekingByteFromMatroska = async ({ time, webmState, info, logLevel, mediaSection, }) => { var _a, _b, _c, _d, _e; if (!info.track) { log_1.Log.trace(logLevel, 'No video track found, cannot seek yet'); return { type: 'valid-but-must-wait', }; } const cuesResponse = (_a = info.loadedCues) !== null && _a !== void 0 ? _a : (await webmState.cues.getLoadedCues()); // Check if we have already read keyframes const byteFromObservedKeyframe = findKeyframeBeforeTime({ keyframes: info.keyframes, time, }); // Check if we have `Cues` const byteFromCues = getByteFromCues({ cuesResponse, time, info, logLevel, }); // Fallback: back to the beginning const byteFromFirstMediaSection = (_c = (_b = webmState.getFirstCluster()) === null || _b === void 0 ? void 0 : _b.start) !== null && _c !== void 0 ? _c : null; // Optimization possibility for later: // Don't seek back, if the last seen time is smaller than the time we want to seek to const seekPossibilities = [ (_d = byteFromCues === null || byteFromCues === void 0 ? void 0 : byteFromCues.byte) !== null && _d !== void 0 ? _d : null, (_e = byteFromObservedKeyframe === null || byteFromObservedKeyframe === void 0 ? void 0 : byteFromObservedKeyframe.positionInBytes) !== null && _e !== void 0 ? _e : null, byteFromFirstMediaSection, ].filter((n) => n !== null); const byteToSeekTo = seekPossibilities.length === 0 ? null : Math.max(...seekPossibilities); if (byteToSeekTo === null) { // dont know what to do return { type: 'invalid', }; } // we have assured this is in a media section, but it might not be marked yet // setting size because there is deduplication and media sections which are encompassed // by others will get deleted mediaSection.addMediaSection({ start: byteToSeekTo, size: 1, }); const timeInSeconds = (() => { if (byteToSeekTo === (byteFromObservedKeyframe === null || byteFromObservedKeyframe === void 0 ? void 0 : byteFromObservedKeyframe.positionInBytes)) { return Math.min(byteFromObservedKeyframe.decodingTimeInSeconds, byteFromObservedKeyframe.presentationTimeInSeconds); } if (byteToSeekTo === (byteFromCues === null || byteFromCues === void 0 ? void 0 : byteFromCues.byte)) { return byteFromCues.timeInSeconds; } if (byteToSeekTo === byteFromFirstMediaSection) { return 0; } throw new Error('Should not happen'); })(); return { type: 'do-seek', byte: byteToSeekTo, timeInSeconds, }; }; exports.getSeekingByteFromMatroska = getSeekingByteFromMatroska;