@remotion/studio
Version:
APIs for interacting with the Remotion Studio
1,002 lines (1,001 loc) • 48.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RenderModalWithLoader = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const client_1 = require("@remotion/renderer/client");
const studio_shared_1 = require("@remotion/studio-shared");
const react_1 = require("react");
const ShortcutHint_1 = require("../../error-overlay/remotion-overlay/ShortcutHint");
const colors_1 = require("../../helpers/colors");
const convert_env_variables_1 = require("../../helpers/convert-env-variables");
const copy_text_1 = require("../../helpers/copy-text");
const make_render_command_1 = require("../../helpers/make-render-command");
const render_modal_sections_1 = require("../../helpers/render-modal-sections");
const use_keybinding_1 = require("../../helpers/use-keybinding");
const audio_1 = require("../../icons/audio");
const Checkmark_1 = require("../../icons/Checkmark");
const data_1 = require("../../icons/data");
const file_1 = require("../../icons/file");
const frame_1 = require("../../icons/frame");
const gear_1 = require("../../icons/gear");
const gif_1 = require("../../icons/gif");
const modals_1 = require("../../state/modals");
const sidebar_1 = require("../../state/sidebar");
const Button_1 = require("../Button");
const is_menu_item_1 = require("../Menu/is-menu-item");
const ModalHeader_1 = require("../ModalHeader");
const DismissableModal_1 = require("../NewComposition/DismissableModal");
const NotificationCenter_1 = require("../Notifications/NotificationCenter");
const OptionsPanel_1 = require("../OptionsPanel");
const actions_1 = require("../RenderQueue/actions");
const SegmentedControl_1 = require("../SegmentedControl");
const vertical_1 = require("../Tabs/vertical");
const CrfSetting_1 = require("./CrfSetting");
const DataEditor_1 = require("./DataEditor");
const get_default_codecs_1 = require("./get-default-codecs");
const get_string_before_suffix_1 = require("./get-string-before-suffix");
const out_name_checker_1 = require("./out-name-checker");
const render_modals_1 = require("./render-modals");
const RenderModalAdvanced_1 = require("./RenderModalAdvanced");
const RenderModalAudio_1 = require("./RenderModalAudio");
const RenderModalBasic_1 = require("./RenderModalBasic");
const RenderModalGif_1 = require("./RenderModalGif");
const RenderModalPicture_1 = require("./RenderModalPicture");
const ResolveCompositionBeforeModal_1 = require("./ResolveCompositionBeforeModal");
const initialState = { type: 'idle' };
const reducer = (state, action) => {
if (action.type === 'start') {
return {
type: 'load',
};
}
if (action.type === 'fail') {
return {
type: 'error',
};
}
if (action.type === 'succeed') {
return {
type: 'success',
};
}
return state;
};
const RenderModal = ({ readOnlyStudio, initialFrame, initialVideoImageFormat, initialStillImageFormat, initialJpegQuality, initialScale, initialLogLevel, initialConcurrency, maxConcurrency, minConcurrency, initialMuted, initialEnforceAudioTrack, initialProResProfile, initialx264Preset, initialPixelFormat, initialVideoBitrate, initialAudioBitrate, initialEveryNthFrame, initialNumberOfGifLoops, initialDelayRenderTimeout, initialOffthreadVideoCacheSizeInBytes, initialEnvVariables, initialDisableWebSecurity, initialGl, initialHeadless, initialIgnoreCertificateErrors, initialEncodingBufferSize, initialEncodingMaxRate, initialOffthreadVideoThreads, initialMediaCacheSizeInBytes, initialDarkMode, initialUserAgent, defaultProps, inFrameMark, outFrameMark, initialColorSpace, initialMultiProcessOnLinux, defaultConfigurationAudioCodec, defaultConfigurationVideoCodec, initialBeep, initialRepro, initialForSeamlessAacConcatenation, renderTypeOfLastRender, initialHardwareAcceleration, defaultMetadata, initialChromeMode, renderDefaults, }) => {
const { setSelectedModal } = (0, react_1.useContext)(modals_1.ModalsContext);
const context = (0, react_1.useContext)(ResolveCompositionBeforeModal_1.ResolvedCompositionContext);
if (!context) {
throw new Error('Should not be able to render without resolving comp first');
}
const { resolved: { result: resolvedComposition }, unresolved: unresolvedComposition, } = context;
const isMounted = (0, react_1.useRef)(true);
const [isVideo] = (0, react_1.useState)(() => {
return typeof resolvedComposition.durationInFrames === 'undefined'
? true
: resolvedComposition.durationInFrames > 1;
});
const [{ initialAudioCodec, initialRenderType, initialVideoCodec, initialVideoCodecForAudioTab, initialVideoCodecForVideoTab, },] = (0, react_1.useState)(() => {
return (0, get_default_codecs_1.getDefaultCodecs)({
defaultConfigurationVideoCodec,
compositionDefaultVideoCodec: resolvedComposition.defaultCodec,
defaultConfigurationAudioCodec,
renderType: renderTypeOfLastRender !== null && renderTypeOfLastRender !== void 0 ? renderTypeOfLastRender : (isVideo ? 'video' : 'still'),
});
});
const [state, dispatch] = (0, react_1.useReducer)(reducer, initialState);
const [unclampedFrame, setFrame] = (0, react_1.useState)(() => initialFrame);
const [stillImageFormat, setStillImageFormat] = (0, react_1.useState)(() => initialStillImageFormat);
const [videoImageFormat, setVideoImageFormat] = (0, react_1.useState)(() => {
var _a;
return (_a = initialVideoImageFormat !== null && initialVideoImageFormat !== void 0 ? initialVideoImageFormat : resolvedComposition.defaultVideoImageFormat) !== null && _a !== void 0 ? _a : renderDefaults.videoImageFormat;
});
const [sequenceImageFormat, setSequenceImageFormat] = (0, react_1.useState)(() => initialStillImageFormat === 'jpeg' ? 'jpeg' : 'png');
const [concurrency, setConcurrency] = (0, react_1.useState)(() => initialConcurrency);
const [videoCodecForVideoTab, setVideoCodecForVideoTab] = (0, react_1.useState)(() => initialVideoCodecForVideoTab);
const [userSelectedAudioCodec, setUserSelectedAudioCodec] = (0, react_1.useState)(() => initialAudioCodec);
const [separateAudioTo, setSeparateAudioTo] = (0, react_1.useState)(null);
const [envVariables, setEnvVariables] = (0, react_1.useState)(() => (0, convert_env_variables_1.envVariablesObjectToArray)(initialEnvVariables).filter(([key]) => key !== 'NODE_ENV'));
const [initialOutName] = (0, react_1.useState)(() => {
return (0, studio_shared_1.getDefaultOutLocation)({
compositionName: resolvedComposition.id,
defaultExtension: initialRenderType === 'still'
? initialStillImageFormat
: isVideo
? client_1.BrowserSafeApis.getFileExtensionFromCodec(initialVideoCodec, initialAudioCodec)
: initialStillImageFormat,
type: 'asset',
compositionDefaultOutName: resolvedComposition.defaultOutName,
outputLocation: renderDefaults.outputLocation,
});
});
const [videoCodecForAudioTab, setVideoCodecForAudioTab] = (0, react_1.useState)(() => initialVideoCodecForAudioTab);
const [mutedState, setMuted] = (0, react_1.useState)(() => initialMuted);
const [repro, setRepro] = (0, react_1.useState)(() => initialRepro);
const [enforceAudioTrackState, setEnforceAudioTrackState] = (0, react_1.useState)(() => initialEnforceAudioTrack);
const [forSeamlessAacConcatenation, setForSeamlessAacConcatenation] = (0, react_1.useState)(() => initialForSeamlessAacConcatenation);
const [renderMode, setRenderModeState] = (0, react_1.useState)(initialRenderType);
const [jpegQuality, setJpegQuality] = (0, react_1.useState)(() => initialJpegQuality);
const [scale, setScale] = (0, react_1.useState)(() => initialScale);
const [logLevel, setLogLevel] = (0, react_1.useState)(() => initialLogLevel);
const [disallowParallelEncoding, setDisallowParallelEncoding] = (0, react_1.useState)(false);
const [disableWebSecurity, setDisableWebSecurity] = (0, react_1.useState)(() => initialDisableWebSecurity);
const [headless, setHeadless] = (0, react_1.useState)(() => initialHeadless);
const [beepOnFinish, setBeepOnFinish] = (0, react_1.useState)(() => initialBeep);
const [ignoreCertificateErrors, setIgnoreCertificateErrors] = (0, react_1.useState)(() => initialIgnoreCertificateErrors);
const [multiProcessOnLinux, setChromiumMultiProcessOnLinux] = (0, react_1.useState)(() => initialMultiProcessOnLinux);
const [darkMode, setDarkMode] = (0, react_1.useState)(() => initialDarkMode);
const [openGlOption, setOpenGlOption] = (0, react_1.useState)(() => initialGl !== null && initialGl !== void 0 ? initialGl : 'default');
const [colorSpace, setColorSpace] = (0, react_1.useState)(() => initialColorSpace);
const [userAgent, setUserAgent] = (0, react_1.useState)(() => initialUserAgent === null
? null
: initialUserAgent.trim() === ''
? null
: initialUserAgent);
const chromiumOptions = (0, react_1.useMemo)(() => {
return {
headless,
disableWebSecurity,
ignoreCertificateErrors,
gl: openGlOption === 'default' ? null : openGlOption,
userAgent: userAgent === null ? null : userAgent.trim() === '' ? null : userAgent,
enableMultiProcessOnLinux: multiProcessOnLinux,
darkMode,
};
}, [
headless,
disableWebSecurity,
ignoreCertificateErrors,
openGlOption,
userAgent,
multiProcessOnLinux,
darkMode,
]);
const [outName, setOutName] = (0, react_1.useState)(() => initialOutName);
const [endFrameOrNull, setEndFrame] = (0, react_1.useState)(() => outFrameMark !== null && outFrameMark !== void 0 ? outFrameMark : null);
const [startFrameOrNull, setStartFrame] = (0, react_1.useState)(() => inFrameMark !== null && inFrameMark !== void 0 ? inFrameMark : null);
const [proResProfileSetting, setProResProfile] = (0, react_1.useState)(() => {
var _a;
return (_a = initialProResProfile !== null && initialProResProfile !== void 0 ? initialProResProfile : resolvedComposition.defaultProResProfile) !== null && _a !== void 0 ? _a : 'hq';
});
const [x264PresetSetting, setx264Preset] = (0, react_1.useState)(() => initialx264Preset);
const [hardwareAcceleration, setHardwareAcceleration] = (0, react_1.useState)(() => initialHardwareAcceleration);
const [userPreferredPixelFormat, setPixelFormat] = (0, react_1.useState)(() => {
var _a;
return (_a = initialPixelFormat !== null && initialPixelFormat !== void 0 ? initialPixelFormat : resolvedComposition.defaultPixelFormat) !== null && _a !== void 0 ? _a : renderDefaults.pixelFormat;
});
const [preferredQualityControlType, setQualityControl] = (0, react_1.useState)(() => initialVideoBitrate === null ? 'crf' : 'bitrate');
const [shouldHaveCustomTargetAudioBitrate, setShouldHaveCustomTargetAudioBitrate,] = (0, react_1.useState)(() => initialAudioBitrate !== null);
const [customTargetAudioBitrate, setCustomTargetAudioBitrateValue] = (0, react_1.useState)(() => initialAudioBitrate !== null && initialAudioBitrate !== void 0 ? initialAudioBitrate : '320K');
const [customTargetVideoBitrate, setCustomTargetVideoBitrateValue] = (0, react_1.useState)(() => initialVideoBitrate !== null && initialVideoBitrate !== void 0 ? initialVideoBitrate : '1M');
const [encodingMaxRate, setEncodingMaxRate] = (0, react_1.useState)(() => initialEncodingMaxRate !== null && initialEncodingMaxRate !== void 0 ? initialEncodingMaxRate : null);
const [encodingBufferSize, setEncodingBufferSize] = (0, react_1.useState)(() => initialEncodingBufferSize !== null && initialEncodingBufferSize !== void 0 ? initialEncodingBufferSize : null);
const [limitNumberOfGifLoops, setLimitNumberOfGifLoops] = (0, react_1.useState)(() => initialNumberOfGifLoops !== null);
const [numberOfGifLoopsSetting, setNumberOfGifLoopsSetting] = (0, react_1.useState)(() => initialNumberOfGifLoops !== null && initialNumberOfGifLoops !== void 0 ? initialNumberOfGifLoops : 0);
const [delayRenderTimeout, setDelayRenderTimeout] = (0, react_1.useState)(() => initialDelayRenderTimeout);
const [chromeMode, setChromeMode] = (0, react_1.useState)(() => initialChromeMode);
const [offthreadVideoCacheSizeInBytes, setOffthreadVideoCacheSizeInBytes] = (0, react_1.useState)(initialOffthreadVideoCacheSizeInBytes);
const [mediaCacheSizeInBytes, setMediaCacheSizeInBytes] = (0, react_1.useState)(initialMediaCacheSizeInBytes);
const [offthreadVideoThreads, setOffthreadVideoThreads] = (0, react_1.useState)(() => initialOffthreadVideoThreads);
const codec = (0, react_1.useMemo)(() => {
if (renderMode === 'audio') {
return videoCodecForAudioTab;
}
return videoCodecForVideoTab;
}, [videoCodecForAudioTab, renderMode, videoCodecForVideoTab]);
const numberOfGifLoops = (0, react_1.useMemo)(() => {
if (codec === 'gif' && limitNumberOfGifLoops) {
return numberOfGifLoopsSetting;
}
return null;
}, [codec, limitNumberOfGifLoops, numberOfGifLoopsSetting]);
const audioBitrate = (0, react_1.useMemo)(() => {
if (shouldHaveCustomTargetAudioBitrate) {
return customTargetAudioBitrate;
}
return null;
}, [customTargetAudioBitrate, shouldHaveCustomTargetAudioBitrate]);
const supportsCrf = client_1.BrowserSafeApis.codecSupportsCrf(codec);
const supportsVideoBitrate = client_1.BrowserSafeApis.codecSupportsVideoBitrate(codec);
const supportsBothQualityControls = (0, react_1.useMemo)(() => {
return (supportsCrf &&
supportsVideoBitrate &&
hardwareAcceleration !== 'if-possible' &&
hardwareAcceleration !== 'required');
}, [hardwareAcceleration, supportsCrf, supportsVideoBitrate]);
const qualityControlType = (0, react_1.useMemo)(() => {
// When hardware acceleration is enabled, only bitrate is supported
if (hardwareAcceleration === 'if-possible' ||
hardwareAcceleration === 'required') {
if (supportsVideoBitrate) {
return 'bitrate';
}
return null;
}
if (supportsBothQualityControls) {
return preferredQualityControlType;
}
if (supportsCrf) {
return 'crf';
}
if (supportsVideoBitrate) {
return 'bitrate';
}
return null;
}, [
hardwareAcceleration,
preferredQualityControlType,
supportsBothQualityControls,
supportsCrf,
supportsVideoBitrate,
]);
const videoBitrate = (0, react_1.useMemo)(() => {
if (qualityControlType === 'bitrate') {
return customTargetVideoBitrate;
}
return null;
}, [customTargetVideoBitrate, qualityControlType]);
const { crf, maxCrf, minCrf, setCrf } = (0, CrfSetting_1.useCrfState)(codec);
const dispatchIfMounted = (0, react_1.useCallback)((payload) => {
if (isMounted.current === false)
return;
dispatch(payload);
}, []);
const muted = (0, react_1.useMemo)(() => {
if (renderMode === 'video') {
return mutedState;
}
return false;
}, [mutedState, renderMode]);
const enforceAudioTrack = (0, react_1.useMemo)(() => {
if (renderMode === 'video') {
return enforceAudioTrackState;
}
if (renderMode === 'audio') {
return enforceAudioTrackState;
}
return false;
}, [enforceAudioTrackState, renderMode]);
const proResProfile = (0, react_1.useMemo)(() => {
if (renderMode === 'video' && codec === 'prores') {
return proResProfileSetting;
}
return null;
}, [codec, proResProfileSetting, renderMode]);
const x264Preset = (0, react_1.useMemo)(() => {
if (renderMode === 'video' && codec === 'h264') {
return x264PresetSetting;
}
return null;
}, [codec, x264PresetSetting, renderMode]);
const [inputProps, _setInputProps] = (0, react_1.useState)(() => defaultProps);
const setInputProps = (0, react_1.useCallback)((updater) => {
_setInputProps(updater);
}, []);
const [metadata] = (0, react_1.useState)(() => defaultMetadata);
const endFrame = (0, react_1.useMemo)(() => {
if (endFrameOrNull === null) {
return resolvedComposition.durationInFrames - 1;
}
return Math.max(0, Math.min(resolvedComposition.durationInFrames - 1, endFrameOrNull));
}, [resolvedComposition.durationInFrames, endFrameOrNull]);
const startFrame = (0, react_1.useMemo)(() => {
if (startFrameOrNull === null) {
return 0;
}
return Math.max(0, Math.min(endFrame - 1, startFrameOrNull));
}, [endFrame, startFrameOrNull]);
const frame = (0, react_1.useMemo)(() => {
const parsed = Math.floor(unclampedFrame);
return Math.max(0, Math.min(resolvedComposition.durationInFrames - 1, parsed));
}, [resolvedComposition.durationInFrames, unclampedFrame]);
const deriveFinalAudioCodec = (0, react_1.useCallback)((passedVideoCodec, passedAudioCodec) => {
if (passedAudioCodec !== null &&
client_1.BrowserSafeApis.supportedAudioCodecs[passedVideoCodec].includes(passedAudioCodec)) {
return passedAudioCodec;
}
return client_1.BrowserSafeApis.defaultAudioCodecs[passedVideoCodec]
.compressed;
}, []);
const setDefaultOutName = (0, react_1.useCallback)((options) => {
if (options.type === 'still') {
setOutName((prev) => {
const newFileName = (0, get_string_before_suffix_1.getStringBeforeSuffix)(prev) + '.' + options.imageFormat;
return newFileName;
});
}
else if (options.type === 'sequence') {
setOutName((prev) => {
const folderName = (0, get_string_before_suffix_1.getStringBeforeSuffix)(prev);
return folderName;
});
}
else {
setOutName((prev) => {
const codecSuffix = client_1.BrowserSafeApis.getFileExtensionFromCodec(options.codec, deriveFinalAudioCodec(options.codec, options.audioCodec));
const newFileName = (0, get_string_before_suffix_1.getStringBeforeSuffix)(prev) + '.' + codecSuffix;
return newFileName;
});
}
}, [deriveFinalAudioCodec]);
const setAudioCodec = (0, react_1.useCallback)((newAudioCodec) => {
setUserSelectedAudioCodec(newAudioCodec);
setDefaultOutName({
type: 'render',
codec: videoCodecForVideoTab,
audioCodec: newAudioCodec,
});
setSeparateAudioTo((prev) => {
if (prev === null) {
return null;
}
const newExtension = client_1.BrowserSafeApis.getExtensionFromAudioCodec(newAudioCodec);
const newFileName = (0, get_string_before_suffix_1.getStringBeforeSuffix)(prev) + '.' + newExtension;
return newFileName;
});
}, [setDefaultOutName, videoCodecForVideoTab]);
const setCodec = (0, react_1.useCallback)((newCodec) => {
if (renderMode === 'audio') {
setVideoCodecForAudioTab(newCodec);
}
else {
setVideoCodecForVideoTab(newCodec);
}
setDefaultOutName({
type: 'render',
codec: newCodec,
audioCodec: deriveFinalAudioCodec(newCodec, userSelectedAudioCodec),
});
}, [
userSelectedAudioCodec,
deriveFinalAudioCodec,
renderMode,
setDefaultOutName,
]);
const setStillFormat = (0, react_1.useCallback)((format) => {
setStillImageFormat(format);
setDefaultOutName({ type: 'still', imageFormat: format });
}, [setDefaultOutName]);
const { setSidebarCollapsedState } = (0, react_1.useContext)(sidebar_1.SidebarContext);
const onClickStill = (0, react_1.useCallback)(() => {
var _a;
setSidebarCollapsedState({ left: null, right: 'expanded' });
(0, OptionsPanel_1.persistSelectedOptionsSidebarPanel)('renders');
(_a = OptionsPanel_1.optionsSidebarTabs.current) === null || _a === void 0 ? void 0 : _a.selectRendersPanel();
dispatchIfMounted({ type: 'start' });
(0, actions_1.addStillRenderJob)({
compositionId: resolvedComposition.id,
outName,
imageFormat: stillImageFormat,
jpegQuality,
frame,
scale,
logLevel,
chromiumOptions,
delayRenderTimeout,
envVariables: (0, convert_env_variables_1.envVariablesArrayToObject)(envVariables),
inputProps,
offthreadVideoCacheSizeInBytes,
multiProcessOnLinux,
beepOnFinish,
metadata,
chromeMode,
offthreadVideoThreads,
mediaCacheSizeInBytes,
})
.then(() => {
dispatchIfMounted({ type: 'succeed' });
setSelectedModal(null);
})
.catch(() => {
dispatchIfMounted({ type: 'fail' });
});
}, [
setSidebarCollapsedState,
dispatchIfMounted,
resolvedComposition.id,
outName,
stillImageFormat,
jpegQuality,
frame,
scale,
logLevel,
chromiumOptions,
delayRenderTimeout,
envVariables,
inputProps,
offthreadVideoCacheSizeInBytes,
multiProcessOnLinux,
beepOnFinish,
setSelectedModal,
metadata,
chromeMode,
offthreadVideoThreads,
mediaCacheSizeInBytes,
]);
const [everyNthFrameSetting, setEveryNthFrameSetting] = (0, react_1.useState)(() => initialEveryNthFrame);
const everyNthFrame = (0, react_1.useMemo)(() => {
if (codec === 'gif') {
return everyNthFrameSetting;
}
return 1;
}, [codec, everyNthFrameSetting]);
const audioCodec = deriveFinalAudioCodec(codec, userSelectedAudioCodec);
const availablePixelFormats = (0, react_1.useMemo)(() => {
return client_1.BrowserSafeApis.validPixelFormatsForCodec(codec);
}, [codec]);
const pixelFormat = (0, react_1.useMemo)(() => {
if (availablePixelFormats.includes(userPreferredPixelFormat)) {
return userPreferredPixelFormat;
}
return availablePixelFormats[0];
}, [availablePixelFormats, userPreferredPixelFormat]);
const onClickVideo = (0, react_1.useCallback)(() => {
var _a;
setSidebarCollapsedState({ left: null, right: 'expanded' });
(0, OptionsPanel_1.persistSelectedOptionsSidebarPanel)('renders');
(_a = OptionsPanel_1.optionsSidebarTabs.current) === null || _a === void 0 ? void 0 : _a.selectRendersPanel();
dispatchIfMounted({ type: 'start' });
(0, actions_1.addVideoRenderJob)({
compositionId: resolvedComposition.id,
outName,
imageFormat: videoImageFormat,
jpegQuality: stillImageFormat === 'jpeg' ? jpegQuality : null,
scale,
logLevel,
codec,
concurrency,
crf: qualityControlType === 'crf' &&
hardwareAcceleration !== 'if-possible' &&
hardwareAcceleration !== 'required'
? crf
: null,
endFrame,
startFrame,
muted,
enforceAudioTrack,
proResProfile,
x264Preset,
pixelFormat,
audioBitrate,
videoBitrate,
everyNthFrame,
numberOfGifLoops,
delayRenderTimeout,
audioCodec,
disallowParallelEncoding,
chromiumOptions,
envVariables: (0, convert_env_variables_1.envVariablesArrayToObject)(envVariables),
inputProps,
offthreadVideoCacheSizeInBytes,
colorSpace,
multiProcessOnLinux,
encodingBufferSize,
encodingMaxRate,
beepOnFinish,
repro,
forSeamlessAacConcatenation,
separateAudioTo,
metadata,
hardwareAcceleration,
chromeMode,
offthreadVideoThreads,
mediaCacheSizeInBytes,
})
.then(() => {
dispatchIfMounted({ type: 'succeed' });
setSelectedModal(null);
})
.catch(() => {
dispatchIfMounted({ type: 'fail' });
});
}, [
setSidebarCollapsedState,
dispatchIfMounted,
resolvedComposition.id,
outName,
videoImageFormat,
stillImageFormat,
jpegQuality,
scale,
logLevel,
codec,
concurrency,
qualityControlType,
crf,
endFrame,
startFrame,
muted,
enforceAudioTrack,
proResProfile,
x264Preset,
pixelFormat,
audioBitrate,
videoBitrate,
everyNthFrame,
numberOfGifLoops,
delayRenderTimeout,
audioCodec,
disallowParallelEncoding,
chromiumOptions,
envVariables,
inputProps,
offthreadVideoCacheSizeInBytes,
colorSpace,
multiProcessOnLinux,
encodingBufferSize,
encodingMaxRate,
beepOnFinish,
repro,
forSeamlessAacConcatenation,
separateAudioTo,
setSelectedModal,
metadata,
hardwareAcceleration,
chromeMode,
offthreadVideoThreads,
mediaCacheSizeInBytes,
]);
const onClickSequence = (0, react_1.useCallback)(() => {
var _a;
setSidebarCollapsedState({ left: null, right: 'expanded' });
(0, OptionsPanel_1.persistSelectedOptionsSidebarPanel)('renders');
(_a = OptionsPanel_1.optionsSidebarTabs.current) === null || _a === void 0 ? void 0 : _a.selectRendersPanel();
dispatchIfMounted({ type: 'start' });
(0, actions_1.addSequenceRenderJob)({
compositionId: resolvedComposition.id,
outName,
imageFormat: sequenceImageFormat,
scale,
logLevel,
concurrency,
endFrame,
jpegQuality,
startFrame,
delayRenderTimeout,
chromiumOptions,
envVariables: (0, convert_env_variables_1.envVariablesArrayToObject)(envVariables),
inputProps,
offthreadVideoCacheSizeInBytes,
disallowParallelEncoding,
multiProcessOnLinux,
beepOnFinish,
repro,
metadata,
chromeMode,
offthreadVideoThreads,
mediaCacheSizeInBytes,
})
.then(() => {
dispatchIfMounted({ type: 'succeed' });
setSelectedModal(null);
})
.catch(() => {
dispatchIfMounted({ type: 'fail' });
});
}, [
setSidebarCollapsedState,
dispatchIfMounted,
resolvedComposition.id,
outName,
sequenceImageFormat,
scale,
logLevel,
concurrency,
endFrame,
jpegQuality,
startFrame,
delayRenderTimeout,
chromiumOptions,
envVariables,
inputProps,
offthreadVideoCacheSizeInBytes,
disallowParallelEncoding,
multiProcessOnLinux,
beepOnFinish,
repro,
setSelectedModal,
metadata,
chromeMode,
offthreadVideoThreads,
mediaCacheSizeInBytes,
]);
(0, react_1.useEffect)(() => {
return () => {
isMounted.current = false;
};
}, []);
const imageFormatOptions = (0, react_1.useMemo)(() => {
if (renderMode === 'still') {
return [
{
label: 'PNG',
onClick: () => setStillFormat('png'),
key: 'png',
selected: stillImageFormat === 'png',
},
{
label: 'JPEG',
onClick: () => setStillFormat('jpeg'),
key: 'jpeg',
selected: stillImageFormat === 'jpeg',
},
{
label: 'PDF',
onClick: () => setStillFormat('pdf'),
key: 'pdf',
selected: stillImageFormat === 'pdf',
},
{
label: 'WebP',
onClick: () => setStillFormat('webp'),
key: 'webp',
selected: stillImageFormat === 'webp',
},
];
}
if (renderMode === 'sequence') {
return [
{
label: 'PNG',
onClick: () => setSequenceImageFormat('png'),
key: 'png',
selected: sequenceImageFormat === 'png',
},
{
label: 'JPEG',
onClick: () => setSequenceImageFormat('jpeg'),
key: 'jpeg',
selected: sequenceImageFormat === 'jpeg',
},
];
}
return [
{
label: 'PNG',
onClick: () => setVideoImageFormat('png'),
key: 'png',
selected: videoImageFormat === 'png',
},
{
label: 'JPEG',
onClick: () => setVideoImageFormat('jpeg'),
key: 'jpeg',
selected: videoImageFormat === 'jpeg',
},
];
}, [
renderMode,
videoImageFormat,
stillImageFormat,
setStillFormat,
sequenceImageFormat,
]);
const setRenderMode = (0, react_1.useCallback)((newRenderMode) => {
setRenderModeState(newRenderMode);
if (newRenderMode === 'audio') {
setDefaultOutName({
type: 'render',
codec: videoCodecForAudioTab,
audioCodec: deriveFinalAudioCodec(videoCodecForAudioTab, userSelectedAudioCodec),
});
}
if (newRenderMode === 'video') {
setDefaultOutName({
type: 'render',
codec: videoCodecForVideoTab,
audioCodec: deriveFinalAudioCodec(videoCodecForVideoTab, userSelectedAudioCodec),
});
}
if (newRenderMode === 'still') {
setDefaultOutName({ type: 'still', imageFormat: stillImageFormat });
}
if (newRenderMode === 'sequence') {
setDefaultOutName({ type: 'sequence' });
}
}, [
videoCodecForAudioTab,
userSelectedAudioCodec,
deriveFinalAudioCodec,
setDefaultOutName,
stillImageFormat,
videoCodecForVideoTab,
]);
const renderTabOptions = (0, react_1.useMemo)(() => {
if ((resolvedComposition === null || resolvedComposition === void 0 ? void 0 : resolvedComposition.durationInFrames) < 2) {
return [
{
label: 'Still',
onClick: () => {
setRenderMode('still');
},
key: 'still',
selected: renderMode === 'still',
},
];
}
return [
{
label: 'Still',
onClick: () => {
setRenderMode('still');
},
key: 'still',
selected: renderMode === 'still',
},
{
label: 'Video',
onClick: () => {
setRenderMode('video');
},
key: 'video',
selected: renderMode === 'video',
},
{
label: 'Audio',
onClick: () => {
setRenderMode('audio');
},
key: 'audio',
selected: renderMode === 'audio',
},
{
label: 'Image sequence',
onClick: () => {
setRenderMode('sequence');
},
key: 'sequence',
selected: renderMode === 'sequence',
},
];
}, [resolvedComposition === null || resolvedComposition === void 0 ? void 0 : resolvedComposition.durationInFrames, renderMode, setRenderMode]);
const outnameValidation = (0, out_name_checker_1.validateOutnameGui)({
outName,
codec,
audioCodec,
renderMode,
stillImageFormat,
separateAudioTo,
});
const { tab, setTab, shownTabs } = (0, render_modal_sections_1.useRenderModalSections)(renderMode, codec);
const { registerKeybinding } = (0, use_keybinding_1.useKeybinding)();
const readOnlyRenderCommand = (0, react_1.useMemo)(() => {
if (!readOnlyStudio) {
return null;
}
return (0, make_render_command_1.makeReadOnlyStudioRenderCommand)({
remotionVersion: window.remotion_version,
locationHref: window.location.href,
compositionId: resolvedComposition.id,
outName,
renderMode,
renderDefaults,
durationInFrames: resolvedComposition.durationInFrames,
concurrency,
frame,
startFrame,
endFrame,
stillImageFormat,
sequenceImageFormat,
videoImageFormat,
jpegQuality: renderMode === 'video'
? stillImageFormat === 'jpeg'
? jpegQuality
: null
: renderMode === 'audio'
? null
: jpegQuality,
codec,
muted,
enforceAudioTrack,
proResProfile,
x264Preset,
pixelFormat,
crf: qualityControlType === 'crf' &&
hardwareAcceleration !== 'if-possible' &&
hardwareAcceleration !== 'required'
? crf
: null,
videoBitrate,
audioBitrate,
audioCodec,
everyNthFrame,
numberOfGifLoops,
disallowParallelEncoding,
encodingBufferSize,
encodingMaxRate,
forSeamlessAacConcatenation,
separateAudioTo,
colorSpace,
scale,
logLevel,
delayRenderTimeout,
hardwareAcceleration,
chromeMode,
headless,
disableWebSecurity,
ignoreCertificateErrors,
gl: openGlOption === 'default' ? null : openGlOption,
userAgent,
multiProcessOnLinux,
darkMode,
offthreadVideoCacheSizeInBytes,
offthreadVideoThreads,
mediaCacheSizeInBytes,
beepOnFinish,
repro,
metadata,
envVariables: (0, convert_env_variables_1.envVariablesArrayToObject)(envVariables),
inputProps,
});
}, [
audioBitrate,
audioCodec,
beepOnFinish,
chromeMode,
codec,
colorSpace,
concurrency,
crf,
darkMode,
delayRenderTimeout,
disableWebSecurity,
disallowParallelEncoding,
endFrame,
encodingBufferSize,
encodingMaxRate,
enforceAudioTrack,
envVariables,
everyNthFrame,
frame,
forSeamlessAacConcatenation,
hardwareAcceleration,
headless,
ignoreCertificateErrors,
inputProps,
jpegQuality,
logLevel,
mediaCacheSizeInBytes,
metadata,
multiProcessOnLinux,
muted,
numberOfGifLoops,
offthreadVideoCacheSizeInBytes,
offthreadVideoThreads,
openGlOption,
outName,
pixelFormat,
proResProfile,
qualityControlType,
readOnlyStudio,
renderDefaults,
renderMode,
repro,
resolvedComposition.durationInFrames,
resolvedComposition.id,
scale,
separateAudioTo,
sequenceImageFormat,
startFrame,
stillImageFormat,
userAgent,
videoImageFormat,
videoBitrate,
x264Preset,
]);
const [commandCopiedAt, setCommandCopiedAt] = (0, react_1.useState)(null);
const renderDisabled = readOnlyStudio
? false
: !outnameValidation.valid || state.type === 'load';
const trigger = (0, react_1.useCallback)(() => {
if (readOnlyStudio) {
if (!readOnlyRenderCommand) {
return;
}
(0, copy_text_1.copyText)(readOnlyRenderCommand)
.then(() => {
setCommandCopiedAt(Date.now());
})
.catch((err) => {
(0, NotificationCenter_1.showNotification)(`Could not copy: ${err.message}`, 2000);
});
return;
}
if (renderMode === 'still') {
onClickStill();
}
else if (renderMode === 'sequence') {
onClickSequence();
}
else {
onClickVideo();
}
}, [
onClickSequence,
onClickStill,
onClickVideo,
readOnlyRenderCommand,
readOnlyStudio,
renderMode,
]);
(0, react_1.useEffect)(() => {
if (commandCopiedAt === null) {
return;
}
const timeout = setTimeout(() => {
setCommandCopiedAt(null);
}, 2000);
return () => clearTimeout(timeout);
}, [commandCopiedAt]);
(0, react_1.useEffect)(() => {
if (renderDisabled) {
return;
}
const enter = registerKeybinding({
callback() {
trigger();
},
commandCtrlKey: true,
key: 'Enter',
event: 'keydown',
preventDefault: true,
triggerIfInputFieldFocused: true,
keepRegisteredWhenNotHighestContext: false,
});
return () => {
enter.unregister();
};
}, [registerKeybinding, renderDisabled, trigger]);
const pixelFormatOptions = (0, react_1.useMemo)(() => {
return availablePixelFormats.map((option) => {
return {
label: option,
onClick: () => setPixelFormat(option),
key: option,
id: option,
keyHint: null,
leftItem: pixelFormat === option ? jsx_runtime_1.jsx(Checkmark_1.Checkmark, {}) : null,
quickSwitcherLabel: null,
subMenu: null,
type: 'item',
value: option,
};
});
}, [availablePixelFormats, pixelFormat]);
return (jsx_runtime_1.jsxs("div", { style: render_modals_1.outerModalStyle, children: [
jsx_runtime_1.jsx(ModalHeader_1.ModalHeader, { title: `Render ${resolvedComposition.id}` }), jsx_runtime_1.jsxs("div", { style: render_modals_1.container, children: [
jsx_runtime_1.jsx(SegmentedControl_1.SegmentedControl, { items: renderTabOptions, needsWrapping: false }), jsx_runtime_1.jsx("div", { style: render_modals_1.flexer }), jsx_runtime_1.jsxs(Button_1.Button, { autoFocus: true, onClick: trigger, disabled: renderDisabled, style: {
...render_modals_1.buttonStyle,
backgroundColor: outnameValidation.valid ? colors_1.BLUE : colors_1.BLUE_DISABLED,
}, children: [readOnlyStudio
? commandCopiedAt
? 'Copied command!'
: 'Copy command'
: state.type === 'idle'
? `Render ${renderMode}`
: 'Rendering...', jsx_runtime_1.jsx(ShortcutHint_1.ShortcutHint, { keyToPress: "\u21B5", cmdOrCtrl: true })
] })
] }), jsx_runtime_1.jsxs("div", { style: render_modals_1.horizontalLayout, children: [
jsx_runtime_1.jsxs("div", { style: render_modals_1.leftSidebar, children: [shownTabs.includes('general') ? (jsx_runtime_1.jsxs(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'general', onClick: () => setTab('general'), children: [
jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(file_1.FileIcon, { style: render_modals_1.icon }) }),
"General"] })) : null, shownTabs.includes('data') ? (jsx_runtime_1.jsxs(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'data', onClick: () => setTab('data'), children: [
jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(data_1.DataIcon, { style: render_modals_1.icon }) }),
"Input Props"] })) : null, shownTabs.includes('picture') ? (jsx_runtime_1.jsxs(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'picture', onClick: () => setTab('picture'), children: [
jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(frame_1.PicIcon, { style: render_modals_1.icon }) }),
"Picture"] })) : null, shownTabs.includes('audio') ? (jsx_runtime_1.jsxs(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'audio', onClick: () => setTab('audio'), children: [
jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(audio_1.AudioIcon, { style: render_modals_1.icon }) }),
"Audio"] })) : null, shownTabs.includes('gif') ? (jsx_runtime_1.jsxs(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'gif', onClick: () => setTab('gif'), children: [
jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(gif_1.GifIcon, { style: render_modals_1.icon }) }),
"GIF"] })) : null, shownTabs.includes('advanced') ? (jsx_runtime_1.jsxs(vertical_1.VerticalTab, { style: render_modals_1.horizontalTab, selected: tab === 'advanced', onClick: () => setTab('advanced'), children: [
jsx_runtime_1.jsx("div", { style: render_modals_1.iconContainer, children: jsx_runtime_1.jsx(gear_1.GearIcon, { style: render_modals_1.icon }) }),
"Other"] })) : null] }), jsx_runtime_1.jsx("div", { style: render_modals_1.optionsPanel, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: tab === 'general' ? (jsx_runtime_1.jsx(RenderModalBasic_1.RenderModalBasic, { codec: codec, resolvedComposition: resolvedComposition, frame: frame, imageFormatOptions: imageFormatOptions, outName: outName, proResProfile: proResProfile, renderMode: renderMode, setVideoCodec: setCodec, setFrame: setFrame, setOutName: setOutName, setProResProfile: setProResProfile, endFrame: endFrame, setEndFrame: setEndFrame, setStartFrame: setStartFrame, setVerboseLogging: setLogLevel, logLevel: logLevel, showOutputName: !readOnlyStudio, startFrame: startFrame, validationMessage: outnameValidation.valid ? null : outnameValidation.error.message })) : tab === 'picture' ? (jsx_runtime_1.jsx(RenderModalPicture_1.RenderModalPicture, { renderMode: renderMode, scale: scale, setScale: setScale, pixelFormat: pixelFormat, pixelFormatOptions: pixelFormatOptions, imageFormatOptions: imageFormatOptions, crf: crf, setCrf: setCrf, customTargetVideoBitrate: customTargetVideoBitrate, maxCrf: maxCrf, minCrf: minCrf, jpegQuality: jpegQuality, qualityControlType: qualityControlType, setJpegQuality: setJpegQuality, setColorSpace: setColorSpace, colorSpace: colorSpace, setCustomTargetVideoBitrateValue: setCustomTargetVideoBitrateValue, setQualityControl: setQualityControl, videoImageFormat: videoImageFormat, stillImageFormat: stillImageFormat, shouldDisplayQualityControlPicker: supportsBothQualityControls, encodingBufferSize: encodingBufferSize, setEncodingBufferSize: setEncodingBufferSize, encodingMaxRate: encodingMaxRate, setEncodingMaxRate: setEncodingMaxRate, compositionWidth: resolvedComposition.width, compositionHeight: resolvedComposition.height })) : tab === 'audio' ? (jsx_runtime_1.jsx(RenderModalAudio_1.RenderModalAudio, { muted: muted, renderMode: renderMode, setMuted: setMuted, codec: codec, audioCodec: audioCodec, setAudioCodec: setAudioCodec, enforceAudioTrack: enforceAudioTrack, setEnforceAudioTrackState: setEnforceAudioTrackState, customTargetAudioBitrate: customTargetAudioBitrate, setCustomTargetAudioBitrateValue: setCustomTargetAudioBitrateValue, setShouldHaveCustomTargetAudioBitrate: setShouldHaveCustomTargetAudioBitrate, shouldHaveCustomTargetAudioBitrate: shouldHaveCustomTargetAudioBitrate, forSeamlessAacConcatenation: forSeamlessAacConcatenation, setForSeamlessAacConcatenation: setForSeamlessAacConcatenation, separateAudioTo: separateAudioTo, setSeparateAudioTo: setSeparateAudioTo, outName: outName })) : tab === 'gif' ? (jsx_runtime_1.jsx(RenderModalGif_1.RenderModalGif, { everyNthFrame: everyNthFrame, limitNumberOfGifLoops: limitNumberOfGifLoops, numberOfGifLoopsSetting: numberOfGifLoopsSetting, setEveryNthFrameSetting: setEveryNthFrameSetting, setLimitNumberOfGifLoops: setLimitNumberOfGifLoops, setNumberOfGifLoopsSetting: setNumberOfGifLoopsSetting })) : tab === 'data' ? (jsx_runtime_1.jsx(DataEditor_1.DataEditor, { defaultProps: inputProps, setDefaultProps: setInputProps, unresolvedComposition: unresolvedComposition, propsEditType: "input-props", canSaveDefaultProps: {
canUpdate: false,
reason: 'render dialogue',
determined: false,
} })) : (jsx_runtime_1.jsx(RenderModalAdvanced_1.RenderModalAdvanced, { x264Preset: x264Preset, setx264Preset: setx264Preset, concurrency: concurrency, maxConcurrency: maxConcurrency, minConcurrency: minConcurrency, renderMode: renderMode, setConcurrency: setConcurrency, delayRenderTimeout: delayRenderTimeout, setDelayRenderTimeout: setDelayRenderTimeout, disallowParallelEncoding: disallowParallelEncoding, setDisallowParallelEncoding: setDisallowParallelEncoding, setDisableWebSecurity: setDisableWebSecurity, setIgnoreCertificateErrors: setIgnoreCertificateErrors, setHeadless: setHeadless, headless: headless, ignoreCertificateErrors: ignoreCertificateErrors, disableWebSecurity: disableWebSecurity, openGlOption: openGlOption, setOpenGlOption: setOpenGlOption, setEnvVariables: setEnvVariables, envVariables: envVariables, offthreadVideoCacheSizeInBytes: offthreadVideoCacheSizeInBytes, setMediaCacheSizeInBytes: setMediaCacheSizeInBytes, mediaCacheSizeInBytes: mediaCacheSizeInBytes, setOffthreadVideoCacheSizeInBytes: setOffthreadVideoCacheSizeInBytes, offthreadVideoThreads: offthreadVideoThreads, setOffthreadVideoThreads: setOffthreadVideoThreads, enableMultiProcessOnLinux: multiProcessOnLinux, setChromiumMultiProcessOnLinux: setChromiumMultiProcessOnLinux, codec: codec, userAgent: userAgent, setUserAgent: setUserAgent, setBeep: setBeepOnFinish, beep: beepOnFinish, repro: repro, setRepro: setRepro, hardwareAcceleration: hardwareAcceleration, setHardwareAcceleration: setHardwareAcceleration, chromeModeOption: chromeMode, setChromeModeOption: setChromeMode, darkMode: darkMode, setDarkMode: setDarkMode })) })
] })
] }));
};
const RenderModalWithLoader = (props) => {
return (jsx_runtime_1.jsx(DismissableModal_1.DismissableModal, { children: jsx_runtime_1.jsx(ResolveCompositionBeforeModal_1.ResolveCompositionBeforeModal, { compositionId: props.compositionId, children: jsx_runtime_1.jsx(RenderModal, { ...props }) }) }));
};
exports.RenderModalWithLoader = RenderModalWithLoader;