UNPKG

@remotion/studio

Version:

APIs for interacting with the Remotion Studio

79 lines (78 loc) 2.75 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.extractFrames = extractFrames; const mediabunny_1 = require("mediabunny"); async function extractFrames({ src, timestampsInSeconds, onVideoSample, signal, }) { var _a; const input = new mediabunny_1.Input({ formats: mediabunny_1.ALL_FORMATS, source: new mediabunny_1.UrlSource(src), }); const dispose = () => { input.dispose(); }; if (signal) { signal.addEventListener('abort', dispose, { once: true }); } try { const [durationInSeconds, format, videoTrack] = await Promise.all([ input.computeDuration(), input.getFormat(), input.getPrimaryVideoTrack(), ]); if (!videoTrack) { throw new Error('No video track found in the input'); } const timestamps = typeof timestampsInSeconds === 'function' ? await timestampsInSeconds({ track: { width: videoTrack.displayWidth, height: videoTrack.displayHeight, }, container: format.name, durationInSeconds, }) : timestampsInSeconds; if (timestamps.length === 0) { return; } const sink = new mediabunny_1.VideoSampleSink(videoTrack); const sampleIterator = sink.samplesAtTimestamps(timestamps); try { for await (const videoSample of sampleIterator) { if (signal === null || signal === void 0 ? void 0 : signal.aborted) { videoSample === null || videoSample === void 0 ? void 0 : videoSample.close(); break; } if (!videoSample) { continue; } onVideoSample(videoSample); } } finally { // When input.dispose() causes the iterator to throw // InputDisposedError, for-await does not call .return() on the // iterator (it only does so on `break`). Explicitly call it so // the iterator can close any internally buffered VideoSamples. try { await ((_a = sampleIterator.return) === null || _a === void 0 ? void 0 : _a.call(sampleIterator)); } catch (_b) { // Iterator already done or input disposed } } } catch (error) { if (error instanceof mediabunny_1.InputDisposedError) { return; } throw error; } finally { dispose(); if (signal) { signal.removeEventListener('abort', dispose); } } }