UNPKG

@remotion/studio

Version:

APIs for interacting with the Remotion Studio

181 lines (180 loc) 7.68 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ClientRenderQueueProcessor = exports.downloadBlob = void 0; const web_renderer_1 = require("@remotion/web-renderer"); const react_1 = require("react"); const save_render_output_1 = require("../../api/save-render-output"); const context_1 = require("./context"); const downloadBlob = (blob, filename) => { const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; const cleanFilename = filename.includes('/') ? filename.substring(filename.lastIndexOf('/') + 1) : filename; a.download = cleanFilename; a.click(); URL.revokeObjectURL(url); }; exports.downloadBlob = downloadBlob; const ClientRenderQueueProcessor = () => { const { getAbortController, getCompositionForJob, updateClientJobProgress, markClientJobSaving, markClientJobDone, markClientJobFailed, markClientJobCancelled, setProcessJobCallback, } = (0, react_1.useContext)(context_1.RenderQueueContext); const processStillJob = (0, react_1.useCallback)(async (job, signal) => { var _a, _b; const compositionRef = getCompositionForJob(job.id); if (!compositionRef) { throw new Error(`Composition not found for job ${job.id}`); } const { blob } = await (0, web_renderer_1.renderStillOnWeb)({ composition: { component: compositionRef.component, width: compositionRef.width, height: compositionRef.height, fps: compositionRef.fps, durationInFrames: compositionRef.durationInFrames, defaultProps: compositionRef.defaultProps, calculateMetadata: (_a = compositionRef.calculateMetadata) !== null && _a !== void 0 ? _a : undefined, id: job.compositionId, }, frame: job.frame, imageFormat: job.imageFormat, inputProps: job.inputProps, delayRenderTimeoutInMilliseconds: job.delayRenderTimeout, mediaCacheSizeInBytes: job.mediaCacheSizeInBytes, logLevel: job.logLevel, licenseKey: (_b = job.licenseKey) !== null && _b !== void 0 ? _b : undefined, scale: job.scale, signal, }); return { getBlob: () => Promise.resolve(blob), width: compositionRef.width, height: compositionRef.height, }; }, [getCompositionForJob]); const processVideoJob = (0, react_1.useCallback)(async (job, signal, onProgress) => { var _a, _b, _c; const compositionRef = getCompositionForJob(job.id); if (!compositionRef) { throw new Error(`Composition not found for job ${job.id}`); } const totalFrames = job.endFrame - job.startFrame + 1; const { getBlob } = await (0, web_renderer_1.renderMediaOnWeb)({ composition: { component: compositionRef.component, width: compositionRef.width, height: compositionRef.height, fps: compositionRef.fps, durationInFrames: compositionRef.durationInFrames, defaultProps: compositionRef.defaultProps, calculateMetadata: (_a = compositionRef.calculateMetadata) !== null && _a !== void 0 ? _a : undefined, id: job.compositionId, }, inputProps: job.inputProps, delayRenderTimeoutInMilliseconds: job.delayRenderTimeout, mediaCacheSizeInBytes: job.mediaCacheSizeInBytes, logLevel: job.logLevel, videoCodec: (_b = job.videoCodec) !== null && _b !== void 0 ? _b : undefined, audioCodec: job.audioCodec, audioBitrate: job.audioBitrate, container: job.container, videoBitrate: job.videoBitrate, hardwareAcceleration: job.hardwareAcceleration, keyframeIntervalInSeconds: job.keyframeIntervalInSeconds, frameRange: [job.startFrame, job.endFrame], transparent: job.transparent, muted: job.muted, scale: job.scale, signal, onProgress: (progress) => { onProgress(job.id, { encodedFrames: progress.encodedFrames, totalFrames, doneIn: progress.doneIn, renderEstimatedTime: progress.renderEstimatedTime, progress: progress.progress, }); }, outputTarget: 'web-fs', licenseKey: (_c = job.licenseKey) !== null && _c !== void 0 ? _c : undefined, }); return { getBlob, width: compositionRef.width, height: compositionRef.height, }; }, [getCompositionForJob]); const processJob = (0, react_1.useCallback)(async (job) => { const abortController = getAbortController(job.id); try { let result; if (job.type === 'client-still') { result = await processStillJob(job, abortController.signal); } else if (job.type === 'client-video') { result = await processVideoJob(job, abortController.signal, updateClientJobProgress); } else { throw new Error(`Unknown job type`); } const blob = await result.getBlob(); const metadata = { width: result.width, height: result.height, sizeInBytes: blob.size, }; markClientJobSaving(job.id); const getBlob = () => Promise.resolve(blob); const downloadAndFinish = () => { (0, exports.downloadBlob)(blob, job.outName); markClientJobDone(job.id, metadata, getBlob); }; if (window.remotion_isReadOnlyStudio) { downloadAndFinish(); } else { try { await (0, save_render_output_1.saveOutputFile)({ blob, filePath: job.outName }); await (0, save_render_output_1.registerClientRender)({ id: job.id, type: job.type, compositionId: job.compositionId, outName: job.outName, startedAt: job.startedAt, deletedOutputLocation: false, metadata, }); markClientJobDone(job.id, metadata); } catch (err) { // eslint-disable-next-line no-console console.error('Failed to save render output, falling back to browser download.', err); downloadAndFinish(); } } } catch (err) { if (abortController.signal.aborted) { markClientJobCancelled(job.id); } else { markClientJobFailed(job.id, err); } } }, [ getAbortController, processStillJob, processVideoJob, updateClientJobProgress, markClientJobSaving, markClientJobDone, markClientJobFailed, markClientJobCancelled, ]); (0, react_1.useEffect)(() => { setProcessJobCallback(processJob); return () => setProcessJobCallback(null); }, [processJob, setProcessJobCallback]); return null; }; exports.ClientRenderQueueProcessor = ClientRenderQueueProcessor;