@remotion/studio
Version:
APIs for interacting with the Remotion Studio
79 lines (78 loc) • 2.75 kB
JavaScript
;
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);
}
}
}