UNPKG

@remotion/studio

Version:

APIs for interacting with the Remotion Studio

1,002 lines (1,001 loc) 48.9 kB
"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;