From fe828433adf7703aca96566396bdcd65bbf000b5 Mon Sep 17 00:00:00 2001 From: wiiiii123 Date: Wed, 27 May 2026 18:12:21 +0700 Subject: [PATCH] fix(recording): stabilize capture quality and CUDA export canvas --- electron/ipc/export/native-video.test.ts | 14 +- electron/ipc/export/native-video.ts | 8 +- electron/ipc/register/settings.ts | 350 ++++++++++-------- electron/main.ts | 31 +- .../bin/win32-x64/helpers-manifest.json | 66 ++-- .../recordly-nvidia-cuda-compositor.exe | Bin 459776 -> 460288 bytes .../run-mp4-pipeline.mjs | 16 +- .../native/nvidia-cuda-compositor/src/main.cu | 32 +- electron/windows.ts | 100 +++-- scripts/build-nvidia-cuda-compositor.mjs | 106 +++++- src/components/launch/LaunchWindow.tsx | 235 ++++++------ .../hooks/useLaunchHudInteractionState.ts | 47 +-- src/components/video-editor/VideoEditor.tsx | 43 ++- .../timeline/zoomSuggestionUtils.test.ts | 62 ++-- .../timeline/zoomSuggestionUtils.ts | 20 + src/hooks/recordingMimeType.test.ts | 27 +- src/hooks/recordingMimeType.ts | 10 +- src/hooks/useScreenRecorder.test.ts | 43 ++- src/hooks/useScreenRecorder.ts | 164 +++++--- src/lib/exporter/exportBitrate.test.ts | 22 ++ src/lib/exporter/exportBitrate.ts | 6 + 21 files changed, 882 insertions(+), 520 deletions(-) diff --git a/electron/ipc/export/native-video.test.ts b/electron/ipc/export/native-video.test.ts index 1c82a8d4..ee31dcdd 100644 --- a/electron/ipc/export/native-video.test.ts +++ b/electron/ipc/export/native-video.test.ts @@ -406,7 +406,9 @@ describe("getNativeExportCapabilities", () => { expect(capabilities.nvidiaCuda.available).toBe(process.platform === "win32"); expect(capabilities.nvidiaCuda.hasWrapper).toBe(process.platform === "win32"); - expect(capabilities.nvidiaCuda.hasNvidiaGpu).toBe(process.platform === "win32" ? true : null); + expect(capabilities.nvidiaCuda.hasNvidiaGpu).toBe( + process.platform === "win32" ? true : null, + ); }); }); @@ -600,6 +602,16 @@ describe("resolveExperimentalNvidiaCudaExportScriptPath", () => { }); describe("buildExperimentalNvidiaCudaStaticLayoutArgs", () => { + it("passes output canvas dimensions to the CUDA wrapper", () => { + const args = buildExperimentalNvidiaCudaStaticLayoutArgs( + createNvidiaCudaSkipOptions({ width: 1020, height: 572 }), + "output.mp4", + "work", + ); + + expect(args).toEqual(expect.arrayContaining(["--width", "1020", "--height", "572"])); + }); + it("keeps explicit copy-source CUDA audio inline by default", () => { const args = buildExperimentalNvidiaCudaStaticLayoutArgs( createNvidiaCudaSkipOptions({ diff --git a/electron/ipc/export/native-video.ts b/electron/ipc/export/native-video.ts index ad884651..16b2993e 100644 --- a/electron/ipc/export/native-video.ts +++ b/electron/ipc/export/native-video.ts @@ -1990,9 +1990,7 @@ function isNvidiaCudaForceVideoOnlyEnabled() { return process.env[NVIDIA_CUDA_FORCE_VIDEO_ONLY_ENV] === "1"; } -export function getNvidiaCudaAutoStallTimeoutMs( - autoCandidateActive = false, -) { +export function getNvidiaCudaAutoStallTimeoutMs(autoCandidateActive = false) { if (!autoCandidateActive && !isExplicitNvidiaCudaExportEnabled()) { return null; } @@ -2664,6 +2662,10 @@ export function buildExperimentalNvidiaCudaStaticLayoutArgs( outputPath, "--work-dir", workDir, + "--width", + String(options.width), + "--height", + String(options.height), "--fps", String(Math.max(1, Math.round(options.frameRate))), "--bitrate-mbps", diff --git a/electron/ipc/register/settings.ts b/electron/ipc/register/settings.ts index cecabb5f..e84f6317 100644 --- a/electron/ipc/register/settings.ts +++ b/electron/ipc/register/settings.ts @@ -22,7 +22,7 @@ import { import { parseJsonWithByteOrderMark } from "../utils"; const BROWSER_MICROPHONE_PROFILE_ENV = "RECORDLY_BROWSER_MIC_PROFILE"; -const DEFAULT_BROWSER_MICROPHONE_PROFILE = "no-agc"; +const DEFAULT_BROWSER_MICROPHONE_PROFILE = "processed"; const BROWSER_MICROPHONE_PROFILES = new Set([ "processed", "no-agc", @@ -60,14 +60,18 @@ function writeAppSettingsStore(store: Record) { writeFileSync(APP_SETTINGS_FILE, JSON.stringify(store, null, 2), "utf-8"); } -export function registerSettingsHandlers() { - ipcMain.handle('app:getVersion', () => { - return app.getVersion() - }) +function hasAppSetting(store: Record, key: string): boolean { + return Reflect.getOwnPropertyDescriptor(store, key) !== undefined; +} - ipcMain.handle('get-platform', () => { - return process.platform; - }); +export function registerSettingsHandlers() { + ipcMain.handle("app:getVersion", () => { + return app.getVersion(); + }); + + ipcMain.handle("get-platform", () => { + return process.platform; + }); ipcMain.on("app-settings:get", (event, key: unknown) => { try { @@ -79,7 +83,7 @@ export function registerSettingsHandlers() { const store = readAppSettingsStore(); event.returnValue = { success: true, - value: Object.prototype.hasOwnProperty.call(store, key) ? store[key] : null, + value: hasAppSetting(store, key) ? store[key] : null, }; } catch (error) { console.error("Failed to read app setting:", error); @@ -104,173 +108,201 @@ export function registerSettingsHandlers() { } }); - // --------------------------------------------------------------------------- - // Cursor hiding for the browser-capture fallback. - // The IPC promise resolves only after the cursor hide attempt completes. - // --------------------------------------------------------------------------- - ipcMain.handle('hide-cursor', () => { - if (process.platform !== 'win32') { - return { success: true } - } + // --------------------------------------------------------------------------- + // Cursor hiding for the browser-capture fallback. + // The IPC promise resolves only after the cursor hide attempt completes. + // --------------------------------------------------------------------------- + ipcMain.handle("hide-cursor", () => { + if (process.platform !== "win32") { + return { success: true }; + } - return { success: hideCursor() } - }) + return { success: hideCursor() }; + }); - ipcMain.handle('get-shortcuts', async () => { - try { - const data = await fs.readFile(SHORTCUTS_FILE, 'utf-8'); - return parseJsonWithByteOrderMark(data); - } catch { - return null; - } - }); + ipcMain.handle("get-shortcuts", async () => { + try { + const data = await fs.readFile(SHORTCUTS_FILE, "utf-8"); + return parseJsonWithByteOrderMark(data); + } catch { + return null; + } + }); - ipcMain.handle('save-shortcuts', async (_, shortcuts: unknown) => { - try { - await fs.writeFile(SHORTCUTS_FILE, JSON.stringify(shortcuts, null, 2), 'utf-8'); - return { success: true }; - } catch (error) { - console.error('Failed to save shortcuts:', error); - return { success: false, error: String(error) }; - } - }); + ipcMain.handle("save-shortcuts", async (_, shortcuts: unknown) => { + try { + await fs.writeFile(SHORTCUTS_FILE, JSON.stringify(shortcuts, null, 2), "utf-8"); + return { success: true }; + } catch (error) { + console.error("Failed to save shortcuts:", error); + return { success: false, error: String(error) }; + } + }); - // --------------------------------------------------------------------------- - // Countdown timer before recording - // --------------------------------------------------------------------------- - ipcMain.handle('get-recording-preferences', async () => { - try { - const content = await fs.readFile(RECORDINGS_SETTINGS_FILE, 'utf-8') - const parsed = parseJsonWithByteOrderMark>(content) - return { - success: true, - microphoneEnabled: parsed.microphoneEnabled === true, - microphoneDeviceId: typeof parsed.microphoneDeviceId === 'string' ? parsed.microphoneDeviceId : undefined, - systemAudioEnabled: parsed.systemAudioEnabled === true, - } - } catch { - return { success: true, microphoneEnabled: false, microphoneDeviceId: undefined, systemAudioEnabled: false } - } - }) + // --------------------------------------------------------------------------- + // Countdown timer before recording + // --------------------------------------------------------------------------- + ipcMain.handle("get-recording-preferences", async () => { + try { + const content = await fs.readFile(RECORDINGS_SETTINGS_FILE, "utf-8"); + const parsed = parseJsonWithByteOrderMark>(content); + return { + success: true, + microphoneEnabled: parsed.microphoneEnabled === true, + microphoneDeviceId: + typeof parsed.microphoneDeviceId === "string" + ? parsed.microphoneDeviceId + : undefined, + systemAudioEnabled: parsed.systemAudioEnabled === true, + }; + } catch { + return { + success: true, + microphoneEnabled: false, + microphoneDeviceId: undefined, + systemAudioEnabled: false, + }; + } + }); - ipcMain.handle('get-recording-audio-lab-config', () => { - return getBrowserMicrophoneProfileFromEnv() - }) + ipcMain.handle("get-recording-audio-lab-config", () => { + return getBrowserMicrophoneProfileFromEnv(); + }); - ipcMain.handle('set-recording-preferences', async (_, prefs: { microphoneEnabled?: boolean; microphoneDeviceId?: string; systemAudioEnabled?: boolean }) => { - try { - let existing: Record = {} - try { - const content = await fs.readFile(RECORDINGS_SETTINGS_FILE, 'utf-8') - existing = parseJsonWithByteOrderMark>(content) - } catch { - // file doesn't exist yet - } - const merged = { ...existing, ...prefs } - await fs.writeFile(RECORDINGS_SETTINGS_FILE, JSON.stringify(merged, null, 2), 'utf-8') - return { success: true } - } catch (error) { - console.error('Failed to save recording preferences:', error) - return { success: false, error: String(error) } - } - }) + ipcMain.handle( + "set-recording-preferences", + async ( + _, + prefs: { + microphoneEnabled?: boolean; + microphoneDeviceId?: string; + systemAudioEnabled?: boolean; + }, + ) => { + try { + let existing: Record = {}; + try { + const content = await fs.readFile(RECORDINGS_SETTINGS_FILE, "utf-8"); + existing = parseJsonWithByteOrderMark>(content); + } catch { + // file doesn't exist yet + } + const merged = { ...existing, ...prefs }; + await fs.writeFile( + RECORDINGS_SETTINGS_FILE, + JSON.stringify(merged, null, 2), + "utf-8", + ); + return { success: true }; + } catch (error) { + console.error("Failed to save recording preferences:", error); + return { success: false, error: String(error) }; + } + }, + ); - ipcMain.handle('get-countdown-delay', async () => { - try { - const content = await fs.readFile(COUNTDOWN_SETTINGS_FILE, 'utf-8') - const parsed = parseJsonWithByteOrderMark<{ delay?: number }>(content) - return { success: true, delay: parsed.delay ?? 3 } - } catch { - return { success: true, delay: 3 } - } - }) + ipcMain.handle("get-countdown-delay", async () => { + try { + const content = await fs.readFile(COUNTDOWN_SETTINGS_FILE, "utf-8"); + const parsed = parseJsonWithByteOrderMark<{ delay?: number }>(content); + return { success: true, delay: parsed.delay ?? 3 }; + } catch { + return { success: true, delay: 3 }; + } + }); - ipcMain.handle('set-countdown-delay', async (_, delay: number) => { - try { - await fs.writeFile(COUNTDOWN_SETTINGS_FILE, JSON.stringify({ delay }, null, 2), 'utf-8') - return { success: true } - } catch (error) { - console.error('Failed to save countdown delay:', error) - return { success: false, error: String(error) } - } - }) + ipcMain.handle("set-countdown-delay", async (_, delay: number) => { + try { + await fs.writeFile( + COUNTDOWN_SETTINGS_FILE, + JSON.stringify({ delay }, null, 2), + "utf-8", + ); + return { success: true }; + } catch (error) { + console.error("Failed to save countdown delay:", error); + return { success: false, error: String(error) }; + } + }); - ipcMain.handle('start-countdown', async (_, seconds: number) => { - if (countdownInProgress) { - return { success: false, error: 'Countdown already in progress' } - } + ipcMain.handle("start-countdown", async (_, seconds: number) => { + if (countdownInProgress) { + return { success: false, error: "Countdown already in progress" }; + } - setCountdownInProgress(true) - setCountdownCancelled(false) - setCountdownRemaining(seconds) + setCountdownInProgress(true); + setCountdownCancelled(false); + setCountdownRemaining(seconds); - const countdownWin = createCountdownWindow() + const countdownWin = createCountdownWindow(); - if (countdownWin.webContents.isLoadingMainFrame()) { - await new Promise((resolve) => { - countdownWin.webContents.once('did-finish-load', () => { - resolve() - }) - }) - } + if (countdownWin.webContents.isLoadingMainFrame()) { + await new Promise((resolve) => { + countdownWin.webContents.once("did-finish-load", () => { + resolve(); + }); + }); + } - return new Promise<{ success: boolean; cancelled?: boolean }>((resolve) => { - let remaining = seconds - setCountdownRemaining(remaining) + return new Promise<{ success: boolean; cancelled?: boolean }>((resolve) => { + let remaining = seconds; + setCountdownRemaining(remaining); - countdownWin.webContents.send('countdown-tick', remaining) + countdownWin.webContents.send("countdown-tick", remaining); - setCountdownTimer(setInterval(() => { - if (countdownCancelled) { - if (countdownTimer) { - clearInterval(countdownTimer) - setCountdownTimer(null) - } - closeCountdownWindow() - setCountdownInProgress(false) - setCountdownRemaining(null) - resolve({ success: false, cancelled: true }) - return - } + setCountdownTimer( + setInterval(() => { + if (countdownCancelled) { + if (countdownTimer) { + clearInterval(countdownTimer); + setCountdownTimer(null); + } + closeCountdownWindow(); + setCountdownInProgress(false); + setCountdownRemaining(null); + resolve({ success: false, cancelled: true }); + return; + } - remaining-- - setCountdownRemaining(remaining) + remaining--; + setCountdownRemaining(remaining); - if (remaining <= 0) { - if (countdownTimer) { - clearInterval(countdownTimer) - setCountdownTimer(null) - } - closeCountdownWindow() - setCountdownInProgress(false) - setCountdownRemaining(null) - resolve({ success: true }) - } else { - const win = getCountdownWindow() - if (win && !win.isDestroyed()) { - win.webContents.send('countdown-tick', remaining) - } - } - }, 1000)) - }) - }) + if (remaining <= 0) { + if (countdownTimer) { + clearInterval(countdownTimer); + setCountdownTimer(null); + } + closeCountdownWindow(); + setCountdownInProgress(false); + setCountdownRemaining(null); + resolve({ success: true }); + } else { + const win = getCountdownWindow(); + if (win && !win.isDestroyed()) { + win.webContents.send("countdown-tick", remaining); + } + } + }, 1000), + ); + }); + }); - ipcMain.handle('cancel-countdown', () => { - setCountdownCancelled(true) - setCountdownInProgress(false) - setCountdownRemaining(null) - if (countdownTimer) { - clearInterval(countdownTimer) - setCountdownTimer(null) - } - closeCountdownWindow() - return { success: true } - }) + ipcMain.handle("cancel-countdown", () => { + setCountdownCancelled(true); + setCountdownInProgress(false); + setCountdownRemaining(null); + if (countdownTimer) { + clearInterval(countdownTimer); + setCountdownTimer(null); + } + closeCountdownWindow(); + return { success: true }; + }); - ipcMain.handle('get-active-countdown', () => { - return { - success: true, - seconds: countdownInProgress ? countdownRemaining : null, - } - }) + ipcMain.handle("get-active-countdown", () => { + return { + success: true, + seconds: countdownInProgress ? countdownRemaining : null, + }; + }); } diff --git a/electron/main.ts b/electron/main.ts index 0a50b6f9..ed05ffeb 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -49,6 +49,8 @@ import { getUpdateToastWindow, hideUpdateToastWindow, isHudOverlayMousePassthroughSupported, + reassertHudOverlayMousePassthrough as reassertHudOverlayMouseState, + setHudOverlayRecordingActive, showUpdateToastWindow, } from "./windows"; @@ -337,32 +339,6 @@ function focusOrCreateMainWindow() { } } -/** - * On Windows 10, focus changes and native notifications can break - * {@link BrowserWindow.setIgnoreMouseEvents} forwarding on the transparent HUD - * overlay, causing it to become permanently click-through. Call this after any - * operation that may alter focus or z-order so that hover detection keeps working. - */ -function reassertHudOverlayMouseState() { - if (process.platform !== "win32" || !isHudOverlayMousePassthroughSupported()) { - return; - } - - const hud = getHudOverlayWindow(); - if (!hud) { - return; - } - - // Toggle off then back on so the native WS_EX_TRANSPARENT flag is fully - // re-initialised rather than merely re-asserted in a potentially broken state. - hud.setIgnoreMouseEvents(false); - setTimeout(() => { - if (!hud.isDestroyed()) { - hud.setIgnoreMouseEvents(true, { forward: true }); - } - }, 50); -} - function isEditorWindow(window: BrowserWindow) { return window.webContents.getURL().includes("windowType=editor"); } @@ -803,7 +779,7 @@ function createEditorWindowWrapper() { const previousWindow = mainWindow; if (previousWindow && !previousWindow.isDestroyed()) { const closingEditorWindow = isEditorWindow(previousWindow); - + if (closingEditorWindow) { closeEditorWindowBypassingUnsavedPrompt(previousWindow); } else { @@ -985,6 +961,7 @@ app.whenReady().then(async () => { () => sourceSelectorWindow, (recording: boolean, sourceName: string) => { selectedSourceName = sourceName; + setHudOverlayRecordingActive(recording); if (!tray) createTray(); updateTrayMenu(recording); if (recording) { diff --git a/electron/native/bin/win32-x64/helpers-manifest.json b/electron/native/bin/win32-x64/helpers-manifest.json index 2df0f4e5..3a9f7dfa 100644 --- a/electron/native/bin/win32-x64/helpers-manifest.json +++ b/electron/native/bin/win32-x64/helpers-manifest.json @@ -1,35 +1,35 @@ { - "version": 1, - "platform": "win32", - "arch": "x64", - "helpers": { - "wgc-capture": { - "binaryName": "wgc-capture.exe", - "binarySha256": "298b41f371c3881046061048b466e12ed70dd93fa761bade2fd57d1ccddf3cb9", - "sourceDir": "electron/native/wgc-capture", - "sourceFingerprint": "6ee457080c27dc939ff4b61965f86b6d73995e40200440a1dc44865f9708d39f", - "updatedAt": "2026-05-24T19:49:15.077Z" - }, - "cursor-monitor": { - "binaryName": "cursor-monitor.exe", - "binarySha256": "6ae6d91103b6e891a851e8ea5791e1c1f9aaab700134c18bc4c46cfffd7fdd12", - "sourceDir": "electron/native/cursor-monitor", - "sourceFingerprint": "6ad1b8b50bb336f2a48937b06f5ec56d90b6ab4a3e56a4bca278cf67a5d3e52e", - "updatedAt": "2026-05-07T15:22:18.173Z" - }, - "recordly-gpu-export": { - "binaryName": "recordly-gpu-export.exe", - "binarySha256": "4cb3a293fd36f718af55906820d9b3fd78babc855888c2e248f0b918ec1aff3c", - "sourceDir": "electron/native/gpu-export-probe", - "sourceFingerprint": "743b386a5f1bbcc99cec5465c3de228d2b045061dead31dfcbf25cf6a1e61de5", - "updatedAt": "2026-05-07T20:13:48.585Z" - }, - "recordly-nvidia-cuda-compositor": { - "binaryName": "recordly-nvidia-cuda-compositor.exe", - "binarySha256": "a787531c07142de7c292d1726e0339c97dbce5073d9a0853d539a725265fd945", - "sourceDir": "electron/native/nvidia-cuda-compositor", - "sourceFingerprint": "528b599e9d576d81ec087d0d4dc93a79af1bbf30fdb969f44f773bef90146135", - "updatedAt": "2026-05-07T20:14:13.794Z" - } - } + "version": 1, + "platform": "win32", + "arch": "x64", + "helpers": { + "wgc-capture": { + "binaryName": "wgc-capture.exe", + "binarySha256": "298b41f371c3881046061048b466e12ed70dd93fa761bade2fd57d1ccddf3cb9", + "sourceDir": "electron/native/wgc-capture", + "sourceFingerprint": "6ee457080c27dc939ff4b61965f86b6d73995e40200440a1dc44865f9708d39f", + "updatedAt": "2026-05-24T19:49:15.077Z" + }, + "cursor-monitor": { + "binaryName": "cursor-monitor.exe", + "binarySha256": "6ae6d91103b6e891a851e8ea5791e1c1f9aaab700134c18bc4c46cfffd7fdd12", + "sourceDir": "electron/native/cursor-monitor", + "sourceFingerprint": "6ad1b8b50bb336f2a48937b06f5ec56d90b6ab4a3e56a4bca278cf67a5d3e52e", + "updatedAt": "2026-05-07T15:22:18.173Z" + }, + "recordly-gpu-export": { + "binaryName": "recordly-gpu-export.exe", + "binarySha256": "4cb3a293fd36f718af55906820d9b3fd78babc855888c2e248f0b918ec1aff3c", + "sourceDir": "electron/native/gpu-export-probe", + "sourceFingerprint": "743b386a5f1bbcc99cec5465c3de228d2b045061dead31dfcbf25cf6a1e61de5", + "updatedAt": "2026-05-07T20:13:48.585Z" + }, + "recordly-nvidia-cuda-compositor": { + "binaryName": "recordly-nvidia-cuda-compositor.exe", + "binarySha256": "e9e062d1177075ac36eecf97e5934722a7fb782809e29ab60da54b396feb95b9", + "sourceDir": "electron/native/nvidia-cuda-compositor", + "sourceFingerprint": "021ea1abd83606b589f694ddedb3af8035e2e08e2e130cf4fff6d6a3f7d64833", + "updatedAt": "2026-05-27T10:56:40.171Z" + } + } } diff --git a/electron/native/bin/win32-x64/recordly-nvidia-cuda-compositor.exe b/electron/native/bin/win32-x64/recordly-nvidia-cuda-compositor.exe index 0fd5f273232f39d5080fe19b034b66e9bbd3a056..3e6ebd579db4191476aca1f51d21a5371fc595df 100644 GIT binary patch delta 130949 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 0 ? `;[bg_scaled]boxblur=luma_radius=${safeBlurPx}:luma_power=1:chroma_radius=${safeBlurPx}:chroma_power=1:alpha_radius=${safeBlurPx}:alpha_power=1[bg]` @@ -895,7 +895,7 @@ function createBackgroundFilter(videoInfo, shadowOptions, blurPx = 0) { "-f", "lavfi", "-i", - `color=c=black@0.0:s=${videoInfo.width}x${videoInfo.height}:d=1`, + `color=c=black@0.0:s=${outputSize.width}x${outputSize.height}:d=1`, "-filter_complex", `${scaled}${blurFilter};${shadow};[bg][shadow]overlay=format=auto,format=nv12[out]`, "-map", @@ -930,6 +930,8 @@ const inputPath = resolve(getArg("--input")); const outputPath = resolve( getArg("--output", join(scriptDir, "recordly-nvdec-nvenc-mp4-output.mp4")), ); +const requestedOutputWidth = Math.round(getNumberArg("--width", 0)); +const requestedOutputHeight = Math.round(getNumberArg("--height", 0)); const fps = Math.round(getNumberArg("--fps", 30)); const bitrateMbps = Math.round(getNumberArg("--bitrate-mbps", 18)); const encodingMode = getArg("--encoding-mode", "balanced"); @@ -1050,6 +1052,8 @@ const sourcePtsPath = join(workDir, `${baseName}.source-pts.csv`); const videoInfo = getVideoInfo(inputPath); const webcamInfo = webcamInput ? getVideoInfo(webcamInput) : null; +const outputWidth = requestedOutputWidth > 0 ? requestedOutputWidth : videoInfo.width; +const outputHeight = requestedOutputHeight > 0 ? requestedOutputHeight : videoInfo.height; const timelineSegments = readTimelineSegments(timelineMap); const timelineOutputDurationSec = timelineSegments.length ? Math.max(...timelineSegments.map((segment) => segment.outputEndMs)) / 1000 @@ -1105,7 +1109,7 @@ let webcamSourceWindowFrames = webcamInfo : 0; const backgroundNv12Path = backgroundImage ? generatedBackgroundNv12Path : backgroundNv12; const backgroundFilter = createBackgroundFilter( - videoInfo, + { width: outputWidth, height: outputHeight }, shouldBakeStaticShadow ? { x: contentX, @@ -1261,6 +1265,10 @@ const encodeArgs = [ annexBPath, "--output", encodedPath, + "--width", + String(outputWidth), + "--height", + String(outputHeight), "--fps", String(fps), "--input-frames", diff --git a/electron/native/nvidia-cuda-compositor/src/main.cu b/electron/native/nvidia-cuda-compositor/src/main.cu index 6adcbcf7..8c5ea9dc 100644 --- a/electron/native/nvidia-cuda-compositor/src/main.cu +++ b/electron/native/nvidia-cuda-compositor/src/main.cu @@ -39,6 +39,8 @@ struct Options { std::string sourcePtsPath; std::string timelineMapPath; std::vector timelineSegments; + int width = 0; + int height = 0; int fps = 30; int maxFrames = 0; int inputFrames = 0; @@ -167,6 +169,10 @@ Options parseOptions(int argc, char** argv) { options.outputPath = requireValue("--output"); } else if (arg == "--source-pts") { options.sourcePtsPath = requireValue("--source-pts"); + } else if (arg == "--width") { + options.width = parsePositiveInt(requireValue("--width"), "--width"); + } else if (arg == "--height") { + options.height = parsePositiveInt(requireValue("--height"), "--height"); } else if (arg == "--timeline-map") { options.timelineMapPath = requireValue("--timeline-map"); } else if (arg == "--fps") { @@ -274,7 +280,7 @@ Options parseOptions(int argc, char** argv) { options.zoomSamplesPath = requireValue("--zoom-samples"); } else if (arg == "--help") { std::cout << "Usage: recordly-nvidia-cuda-compositor --input input.annexb.h264 " - "[--output out.h264] [--source-pts source-pts.csv] [--fps 30] " + "[--output out.h264] [--source-pts source-pts.csv] [--width N --height N] [--fps 30] " "[--max-frames N] [--bitrate-mbps N] [--encoding-mode fast|balanced|quality] " "[--post-select] [--callback-encode] [--stream-sync] [--prewarm-ms N] [--chunk-mb N] " "[--content-x N --content-y N --content-width N --content-height N --radius N] " @@ -320,6 +326,14 @@ bool hasWebcamOverlay(const Options& options) { return (!options.webcamNv12Path.empty() || !options.webcamAnnexbPath.empty()) && options.webcamSize > 0; } +int outputWidthForSource(const Options& options, int sourceWidth) { + return options.width > 0 ? options.width : sourceWidth; +} + +int outputHeightForSource(const Options& options, int sourceHeight) { + return options.height > 0 ? options.height : sourceHeight; +} + std::vector loadFramePts(const std::string& path) { std::vector timestamps; if (path.empty()) { @@ -2866,8 +2880,8 @@ void encodeMappedDisplayFrame( if (!*state->sink) { *state->sink = std::make_unique( state->context, - width, - height, + outputWidthForSource(*state->options, width), + outputHeightForSource(*state->options, height), state->options->fps, state->bitrate, state->options->outputPath, @@ -3106,8 +3120,8 @@ int main(int argc, char** argv) { if (!sink) { sink = std::make_unique( context, - decoder->GetWidth(), - decoder->GetHeight(), + outputWidthForSource(options, decoder->GetWidth()), + outputHeightForSource(options, decoder->GetHeight()), options.fps, bitrate, options.outputPath, @@ -3152,8 +3166,8 @@ int main(int argc, char** argv) { if (!sink) { sink = std::make_unique( context, - decoder->GetWidth(), - decoder->GetHeight(), + outputWidthForSource(options, decoder->GetWidth()), + outputHeightForSource(options, decoder->GetHeight()), options.fps, bitrate, options.outputPath, @@ -3225,8 +3239,8 @@ int main(int argc, char** argv) { << "\"syncMode\":\"" << (options.streamSync ? "stream" : "device") << "\"," << "\"prewarmMs\":" << options.prewarmMs << "," << "\"chunkMb\":" << options.chunkMb << "," - << "\"width\":" << decoder->GetWidth() << "," - << "\"height\":" << decoder->GetHeight() << "," + << "\"width\":" << outputWidthForSource(options, decoder->GetWidth()) << "," + << "\"height\":" << outputHeightForSource(options, decoder->GetHeight()) << "," << "\"fps\":" << options.fps << "," << "\"encodingMode\":\"" << options.encodingMode << "\"," << "\"staticLayout\":" << (hasStaticLayout(options) ? "true" : "false") << "," diff --git a/electron/windows.ts b/electron/windows.ts index a5e6cd01..982fa677 100644 --- a/electron/windows.ts +++ b/electron/windows.ts @@ -5,10 +5,7 @@ import path from "node:path"; import { fileURLToPath } from "node:url"; import { app, BrowserWindow, ipcMain } from "electron"; import { USER_DATA_PATH } from "./appPaths"; -import { - getHudOverlayWindowBounds, - resizeHudOverlayFallbackBounds, -} from "./hudOverlayBounds"; +import { getHudOverlayWindowBounds, resizeHudOverlayFallbackBounds } from "./hudOverlayBounds"; import { getPackagedRendererBaseUrl } from "./rendererServer"; const electronWindowsDir = path.dirname(fileURLToPath(import.meta.url)); @@ -17,7 +14,8 @@ const nodeRequire = createRequire(import.meta.url); const APP_ROOT = path.join(electronWindowsDir, ".."); const VITE_DEV_SERVER_URL = process.env["VITE_DEV_SERVER_URL"]; const RENDERER_DIST = path.join(APP_ROOT, "dist"); -const WINDOW_ICON_FILENAME = process.platform === "darwin" ? "recordlymac-512.png" : "recordly-512.png"; +const WINDOW_ICON_FILENAME = + process.platform === "darwin" ? "recordlymac-512.png" : "recordly-512.png"; const WINDOW_ICON_PATH = path.join( process.env.VITE_PUBLIC || RENDERER_DIST, "app-icons", @@ -28,6 +26,9 @@ let hudOverlayWindow: BrowserWindow | null = null; let hudOverlayHiddenFromCapture = true; let hudOverlayCaptureProtectionLoaded = false; let hudOverlayFallbackExpanded = false; +let hudOverlayIgnoringMouse = true; +let hudOverlayMouseReassertTimer: NodeJS.Timeout | null = null; +let hudOverlayRecordingActive = false; let countdownWindow: BrowserWindow | null = null; let updateToastWindow: BrowserWindow | null = null; @@ -190,7 +191,7 @@ function getHudOverlayBounds() { const { workArea } = getHudOverlayDisplay(); return getHudOverlayWindowBounds( workArea, - isHudOverlayMousePassthroughSupported(), + isHudOverlayMousePassthroughSupported() && !hudOverlayRecordingActive, hudOverlayFallbackExpanded, ); } @@ -247,6 +248,11 @@ function positionUpdateToastWindow() { } function setHudOverlayFallbackExpanded(expanded: boolean) { + if (hudOverlayRecordingActive) { + hudOverlayFallbackExpanded = false; + return; + } + hudOverlayFallbackExpanded = expanded; if ( !hudOverlayWindow || @@ -269,23 +275,43 @@ function setHudOverlayFallbackExpanded(expanded: boolean) { } } -ipcMain.on("hud-overlay-set-ignore-mouse", (_event, ignore: boolean) => { - if (hudOverlayWindow && !hudOverlayWindow.isDestroyed()) { - if (!isHudOverlayMousePassthroughSupported()) { - if (process.platform !== "linux") { - setHudOverlayFallbackExpanded(!ignore); - } - hudOverlayWindow.setIgnoreMouseEvents(false); - return; - } +function setHudOverlayMousePassthrough(ignore: boolean) { + hudOverlayIgnoringMouse = hudOverlayRecordingActive ? false : ignore; - if (ignore) { - hudOverlayWindow.setIgnoreMouseEvents(true, { forward: true }); - return; - } - - hudOverlayWindow.setIgnoreMouseEvents(false); + if (hudOverlayMouseReassertTimer) { + clearTimeout(hudOverlayMouseReassertTimer); + hudOverlayMouseReassertTimer = null; } + + if (!hudOverlayWindow || hudOverlayWindow.isDestroyed()) { + return; + } + + if (hudOverlayRecordingActive) { + hudOverlayFallbackExpanded = false; + applyHudOverlayBounds(); + hudOverlayWindow.setIgnoreMouseEvents(false); + return; + } + + if (!isHudOverlayMousePassthroughSupported()) { + if (process.platform !== "linux") { + setHudOverlayFallbackExpanded(!ignore); + } + hudOverlayWindow.setIgnoreMouseEvents(false); + return; + } + + if (ignore) { + hudOverlayWindow.setIgnoreMouseEvents(true, { forward: true }); + return; + } + + hudOverlayWindow.setIgnoreMouseEvents(false); +} + +ipcMain.on("hud-overlay-set-ignore-mouse", (_event, ignore: boolean) => { + setHudOverlayMousePassthrough(Boolean(ignore)); }); // Keep compatibility with existing drag IPC/state. @@ -426,7 +452,7 @@ export function createHudOverlayWindow(): BrowserWindow { win.setIgnoreMouseEvents(false); setTimeout(() => { if (!win.isDestroyed()) { - win.setIgnoreMouseEvents(true, { forward: true }); + setHudOverlayMousePassthrough(hudOverlayIgnoringMouse); } }, 50); } @@ -437,7 +463,13 @@ export function createHudOverlayWindow(): BrowserWindow { } if (isHudOverlayMousePassthroughSupported()) { - win.setIgnoreMouseEvents(true, { forward: true }); + if (hudOverlayRecordingActive) { + hudOverlayIgnoringMouse = false; + win.setIgnoreMouseEvents(false); + } else { + hudOverlayIgnoringMouse = true; + win.setIgnoreMouseEvents(true, { forward: true }); + } } // On Windows 11+, focus changes (e.g. showing a native notification) can break @@ -452,7 +484,7 @@ export function createHudOverlayWindow(): BrowserWindow { win.setIgnoreMouseEvents(false); setTimeout(() => { if (!win.isDestroyed()) { - win.setIgnoreMouseEvents(true, { forward: true }); + setHudOverlayMousePassthrough(hudOverlayIgnoringMouse); } }, 50); } @@ -566,16 +598,32 @@ export function reassertHudOverlayMousePassthrough(): void { return; } + if (hudOverlayRecordingActive) { + hud.setIgnoreMouseEvents(false); + return; + } + // Toggle off then back on so the native WS_EX_TRANSPARENT flag is fully // re-initialised rather than merely re-asserted in a potentially broken state. hud.setIgnoreMouseEvents(false); - setTimeout(() => { + if (hudOverlayMouseReassertTimer) { + clearTimeout(hudOverlayMouseReassertTimer); + } + hudOverlayMouseReassertTimer = setTimeout(() => { + hudOverlayMouseReassertTimer = null; if (!hud.isDestroyed()) { - hud.setIgnoreMouseEvents(true, { forward: true }); + setHudOverlayMousePassthrough(hudOverlayIgnoringMouse); } }, 50); } +export function setHudOverlayRecordingActive(recording: boolean): void { + hudOverlayRecordingActive = Boolean(recording); + hudOverlayFallbackExpanded = false; + applyHudOverlayBounds(); + setHudOverlayMousePassthrough(!hudOverlayRecordingActive); +} + export function createUpdateToastWindow(): BrowserWindow { const initialBounds = getUpdateToastBounds(); const parentWindow = diff --git a/scripts/build-nvidia-cuda-compositor.mjs b/scripts/build-nvidia-cuda-compositor.mjs index cdccbc12..e2959022 100644 --- a/scripts/build-nvidia-cuda-compositor.mjs +++ b/scripts/build-nvidia-cuda-compositor.mjs @@ -1,5 +1,5 @@ import { execSync } from "node:child_process"; -import { copyFileSync, existsSync, mkdirSync, rmSync } from "node:fs"; +import { copyFileSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import path from "node:path"; import { @@ -117,6 +117,110 @@ if (!existsSync(path.join(videoCodecSdkRoot, "Samples", "NvCodec"))) { ); } +function replaceOrThrow(filePath, content, pattern, replacement, label) { + const updated = content.replace(pattern, replacement); + if (updated === content) { + throw new Error(`Unable to patch ${label} in ${filePath}`); + } + return updated; +} + +function patchNvDecoderForRecordlyCallbacks() { + const nvDecoderDir = path.join(videoCodecSdkRoot, "Samples", "NvCodec", "NvDecoder"); + const headerPath = path.join(nvDecoderDir, "NvDecoder.h"); + const sourcePath = path.join(nvDecoderDir, "NvDecoder.cpp"); + + let header = readFileSync(headerPath, "utf8"); + if (!header.includes("RecordlyMappedFrameHandler")) { + header = replaceOrThrow( + headerPath, + header, + /#include "nvcuvid\.h"\r?\n/, + `#include "nvcuvid.h" + +using RecordlyMappedFrameHandler = void (*)(CUdeviceptr, unsigned int, int, int, int, int64_t, void*); +using RecordlyDisplayFramePolicy = bool (*)(int, void*); +`, + "NvDecoder callback aliases", + ); + header = replaceOrThrow( + headerPath, + header, + / {4}int setReconfigParams\(const Rect \* pCropRect, const Dim \* pResizeDim\);\r?\n/, + ` int setReconfigParams(const Rect * pCropRect, const Dim * pResizeDim); + void SetMappedFrameHandler(RecordlyMappedFrameHandler handler, void* userData) { m_recordlyMappedFrameHandler = handler; m_recordlyMappedFrameUserData = userData; } + void SetDisplayFramePolicy(RecordlyDisplayFramePolicy policy, void* userData) { m_recordlyDisplayFramePolicy = policy; m_recordlyDisplayFramePolicyUserData = userData; } + int GetDisplayFrameCount() const { return m_nDisplayFrameCount; } +`, + "NvDecoder public callback methods", + ); + header = replaceOrThrow( + headerPath, + header, + / {4}int m_nDecodedFrame = 0, m_nDecodedFrameReturned = 0;\r?\n/, + ` int m_nDecodedFrame = 0, m_nDecodedFrameReturned = 0; + int m_nDisplayFrameCount = 0; + RecordlyMappedFrameHandler m_recordlyMappedFrameHandler = nullptr; + void* m_recordlyMappedFrameUserData = nullptr; + RecordlyDisplayFramePolicy m_recordlyDisplayFramePolicy = nullptr; + void* m_recordlyDisplayFramePolicyUserData = nullptr; +`, + "NvDecoder callback state", + ); + writeFileSync(headerPath, header); + } + + let source = readFileSync(sourcePath, "utf8"); + if (!source.includes("Recordly mapped frame callback")) { + source = replaceOrThrow( + sourcePath, + source, + / {4}if \(result == CUDA_SUCCESS && \(DecodeStatus\.decodeStatus == cuvidDecodeStatus_Error \|\| DecodeStatus\.decodeStatus == cuvidDecodeStatus_Error_Concealed\)\)\r?\n {4}\{\r?\n {8}printf\("Decode Error occurred for picture %d\\n", m_nPicNumInDecodeOrder\[pDispInfo->picture_index\]\);\r?\n {4}\}\r?\n {4}uint8_t \*pDecodedFrame = nullptr;\r?\n/, + ` if (result == CUDA_SUCCESS && (DecodeStatus.decodeStatus == cuvidDecodeStatus_Error || DecodeStatus.decodeStatus == cuvidDecodeStatus_Error_Concealed)) + { + printf("Decode Error occurred for picture %d\\n", m_nPicNumInDecodeOrder[pDispInfo->picture_index]); + } + + const int displayFrameIndex = m_nDisplayFrameCount++; + if (m_recordlyDisplayFramePolicy && + !m_recordlyDisplayFramePolicy(displayFrameIndex, m_recordlyDisplayFramePolicyUserData)) + { + NVDEC_API_CALL(cuvidUnmapVideoFrame(m_hDecoder, dpSrcFrame)); + return 1; + } + + // Recordly mapped frame callback keeps the CUDA helper from making an + // extra device-to-device copy when the caller can consume mapped NV12. + if (m_recordlyMappedFrameHandler) + { + m_recordlyMappedFrameHandler( + dpSrcFrame, + nSrcPitch, + m_nWidth, + m_nHeight, + m_nSurfaceHeight, + pDispInfo->timestamp, + m_recordlyMappedFrameUserData); + NVDEC_API_CALL(cuvidUnmapVideoFrame(m_hDecoder, dpSrcFrame)); + return 1; + } + + uint8_t *pDecodedFrame = nullptr; +`, + "NvDecoder mapped frame callback hook", + ); + writeFileSync(sourcePath, source); + } +} + +try { + patchNvDecoderForRecordlyCallbacks(); +} catch (error) { + fallbackToBundledHelperOrExit( + `Failed to patch NVIDIA Video Codec SDK samples: ${error instanceof Error ? error.message : String(error)}`, + ); +} + const cmake = findCmake(); if (!cmake) { fallbackToBundledHelperOrExit( diff --git a/src/components/launch/LaunchWindow.tsx b/src/components/launch/LaunchWindow.tsx index b3c92476..d7dc51bc 100644 --- a/src/components/launch/LaunchWindow.tsx +++ b/src/components/launch/LaunchWindow.tsx @@ -21,9 +21,7 @@ import { useScreenRecorder } from "../../hooks/useScreenRecorder"; import { useVideoDevices } from "../../hooks/useVideoDevices"; import { Button } from "../ui/button"; import { HudInteractionContext } from "./contexts/HudInteractionContext"; -import { - canToggleFloatingWebcamPreview, -} from "./floatingWebcamPreview"; +import { canToggleFloatingWebcamPreview } from "./floatingWebcamPreview"; import { useHudBarDrag } from "./hooks/useHudBarDrag"; import { useLaunchHudInteractionState } from "./hooks/useLaunchHudInteractionState"; import { useLaunchWindowActions } from "./hooks/useLaunchWindowActions"; @@ -32,7 +30,10 @@ import { useRecordingTimer } from "./hooks/useRecordingTimer"; import { useWebcamPreviewOverlay } from "./hooks/useWebcamPreviewOverlay"; import styles from "./LaunchWindow.module.css"; import { CountdownPopover } from "./popovers/CountdownPopover"; -import { LaunchPopoverCoordinatorProvider, useLaunchPopoverCoordinator } from "./popovers/LaunchPopoverCoordinator"; +import { + LaunchPopoverCoordinatorProvider, + useLaunchPopoverCoordinator, +} from "./popovers/LaunchPopoverCoordinator"; import { MicPopover } from "./popovers/MicPopover"; import { MorePopover } from "./popovers/MorePopover"; import { ProjectPopover } from "./popovers/ProjectPopover"; @@ -83,7 +84,6 @@ function LaunchWindowContent() { const hudContentRef = useRef(null); const hudBarRef = useRef(null); - const { selectedSource, hasSelectedSource, @@ -166,12 +166,13 @@ function LaunchWindowContent() { recordingWebcamPreviewContainerRef, }); - const { handleHudMouseEnter, handleHudMouseLeave, beginInteractiveHudAction } = useLaunchHudInteractionState({ - openId, - isHudDraggingRef, - isWebcamPreviewDraggingRef, - webcamPreviewDragStartRef, - }); + const { handleHudMouseEnter, handleHudMouseLeave, beginInteractiveHudAction } = + useLaunchHudInteractionState({ + openId, + isHudDraggingRef, + isWebcamPreviewDraggingRef, + webcamPreviewDragStartRef, + }); useEffect(() => { let mounted = true; @@ -195,7 +196,6 @@ function LaunchWindowContent() { ease: [0.22, 1, 0.36, 1] as const, }; - const recordingControls = ( - {microphoneEnabled ? : } + {microphoneEnabled ? ( + + ) : ( + + )} } /> @@ -282,9 +286,7 @@ function LaunchWindowContent() { hudOverlayMousePassthroughSupported, )} showFloatingWebcamPreview={showFloatingWebcamPreview} - onToggleFloatingPreview={() => - setShowFloatingWebcamPreview((current) => !current) - } + onToggleFloatingPreview={() => setShowFloatingWebcamPreview((current) => !current)} showWebcamControls={showWebcamControls} setWebcamPreviewNode={setWebcamPreviewNode} videoDevices={videoDevices} @@ -307,7 +309,11 @@ function LaunchWindowContent() { } className={webcamEnabled ? styles.ibActive : ""} > - {webcamEnabled ? : } + {webcamEnabled ? ( + + ) : ( + + )} } /> @@ -328,7 +334,6 @@ function LaunchWindowContent() { } /> - } @@ -430,112 +430,113 @@ function LaunchWindowContent() { platform === "linux" || hudOverlayMousePassthroughSupported === false; return ( - +
-
- -
- -
- -
- - - {finalizing - ? finalizingControls - : recording - ? recordingControls - : idleControls} - - -
-
-
- {showRecordingWebcamPreview && (
-
- )} -
+ +
+ +
+
+ + + {finalizing + ? finalizingControls + : recording + ? recordingControls + : idleControls} + + +
+
+
+ {showRecordingWebcamPreview && ( +
+
+ )} +
+ -
); } diff --git a/src/components/launch/hooks/useLaunchHudInteractionState.ts b/src/components/launch/hooks/useLaunchHudInteractionState.ts index 31187e1a..9d0160a7 100644 --- a/src/components/launch/hooks/useLaunchHudInteractionState.ts +++ b/src/components/launch/hooks/useLaunchHudInteractionState.ts @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useRef, type MouseEvent, type RefObject } from "react"; +import { type MouseEvent, type RefObject, useCallback, useEffect, useRef } from "react"; export function useLaunchHudInteractionState({ openId, @@ -32,7 +32,7 @@ export function useLaunchHudInteractionState({ const target = e.target as HTMLElement | null; if (!target) return; const isInteractive = !!target.closest( - ".pointer-events-auto, [data-hud-interactive], [data-radix-popper-content-wrapper]" + ".pointer-events-auto, [data-hud-interactive], [data-radix-popper-content-wrapper]", ); if (isInteractive) { @@ -70,27 +70,30 @@ export function useLaunchHudInteractionState({ window.electronAPI?.hudOverlaySetIgnoreMouse?.(false); }, []); - const handleHudMouseLeave = useCallback((event: MouseEvent) => { - const nextTarget = event.relatedTarget; - if (nextTarget instanceof Node && event.currentTarget.contains(nextTarget)) { - return; - } - - isMouseOverHudRef.current = false; - - if (timeoutRef.current) clearTimeout(timeoutRef.current); - - timeoutRef.current = setTimeout(() => { - if ( - !isHudDraggingRef.current && - !isWebcamPreviewDraggingRef.current && - !webcamPreviewDragStartRef.current && - !isMouseOverHudRef.current - ) { - window.electronAPI?.hudOverlaySetIgnoreMouse?.(true); + const handleHudMouseLeave = useCallback( + (event: MouseEvent) => { + const nextTarget = event.relatedTarget; + if (nextTarget instanceof Node && event.currentTarget.contains(nextTarget)) { + return; } - }, 300); - }, [isHudDraggingRef, isWebcamPreviewDraggingRef, webcamPreviewDragStartRef]); + + isMouseOverHudRef.current = false; + + if (timeoutRef.current) clearTimeout(timeoutRef.current); + + timeoutRef.current = setTimeout(() => { + if ( + !isHudDraggingRef.current && + !isWebcamPreviewDraggingRef.current && + !webcamPreviewDragStartRef.current && + !isMouseOverHudRef.current + ) { + window.electronAPI?.hudOverlaySetIgnoreMouse?.(true); + } + }, 300); + }, + [isHudDraggingRef, isWebcamPreviewDraggingRef, webcamPreviewDragStartRef], + ); return { handleHudMouseEnter, diff --git a/src/components/video-editor/VideoEditor.tsx b/src/components/video-editor/VideoEditor.tsx index 4050189e..0893630f 100644 --- a/src/components/video-editor/VideoEditor.tsx +++ b/src/components/video-editor/VideoEditor.tsx @@ -163,7 +163,10 @@ import { RECORDLY_ISSUES_URL, } from "./TutorialHelp"; import TimelineEditor, { type TimelineEditorHandle } from "./timeline/TimelineEditor"; -import { normalizeCursorTelemetry } from "./timeline/zoomSuggestionUtils"; +import { + normalizeCursorTelemetry, + shouldAutoApplyFreshRecordingZoomsForSource, +} from "./timeline/zoomSuggestionUtils"; import { type AnnotationRegion, type AudioRegion, @@ -3344,6 +3347,23 @@ export default function VideoEditor() { ); useEffect(() => { + if ( + videoPath && + pendingFreshRecordingAutoZoomPathRef.current === videoPath && + isPreviewReady && + !shouldAutoApplyFreshRecordingZoomsForSource( + videoPlaybackRef.current?.video?.videoWidth, + videoPlaybackRef.current?.video?.videoHeight, + ) + ) { + pendingFreshRecordingAutoZoomPathRef.current = null; + if (pendingFreshRecordingAutoSuggestTimeoutRef.current !== null) { + window.clearTimeout(pendingFreshRecordingAutoSuggestTimeoutRef.current); + pendingFreshRecordingAutoSuggestTimeoutRef.current = null; + } + return; + } + if ( !videoPath || loading || @@ -3402,6 +3422,27 @@ export default function VideoEditor() { zoomRegions, ]); + useEffect(() => { + if ( + !videoPath || + !isPreviewReady || + zoomRegions.length === 0 || + autoSuggestedVideoPathRef.current !== videoPath || + shouldAutoApplyFreshRecordingZoomsForSource( + videoPlaybackRef.current?.video?.videoWidth, + videoPlaybackRef.current?.video?.videoHeight, + ) + ) { + return; + } + + autoSuggestedVideoPathRef.current = null; + setZoomRegions((prev) => { + const next = prev.filter((region) => region.mode !== "auto"); + return next.length === prev.length ? prev : next; + }); + }, [videoPath, isPreviewReady, zoomRegions]); + const handleZoomSpanChange = useCallback((id: string, span: Span) => { setZoomRegions((prev) => prev.map((region) => diff --git a/src/components/video-editor/timeline/zoomSuggestionUtils.test.ts b/src/components/video-editor/timeline/zoomSuggestionUtils.test.ts index 77080bfc..f1a6dd21 100644 --- a/src/components/video-editor/timeline/zoomSuggestionUtils.test.ts +++ b/src/components/video-editor/timeline/zoomSuggestionUtils.test.ts @@ -1,10 +1,11 @@ import { describe, expect, it } from "vitest"; +import type { CursorTelemetryPoint } from "../types"; import { + buildInteractionZoomSuggestions, CLICK_CLUSTER_MERGE_GAP_MS, CLICK_CLUSTER_PAD_MS, - buildInteractionZoomSuggestions, + shouldAutoApplyFreshRecordingZoomsForSource, } from "./zoomSuggestionUtils"; -import type { CursorTelemetryPoint } from "../types"; function makeClick( timeMs: number, @@ -20,19 +21,28 @@ function makeMove(timeMs: number, cx = 0.5, cy = 0.5): CursorTelemetryPoint { } /** Wraps click samples with surrounding move events to mimic real mixed telemetry. */ -function withMoves( - clicks: CursorTelemetryPoint[], - totalMs: number, -): CursorTelemetryPoint[] { - return [ - makeMove(0), - ...clicks, - makeMove(totalMs), - ]; +function withMoves(clicks: CursorTelemetryPoint[], totalMs: number): CursorTelemetryPoint[] { + return [makeMove(0), ...clicks, makeMove(totalMs)]; } const TOTAL_MS = 30_000; +describe("shouldAutoApplyFreshRecordingZoomsForSource", () => { + it("allows automatic fresh-recording zooms for landscape captures", () => { + expect(shouldAutoApplyFreshRecordingZoomsForSource(1920, 1080)).toBe(true); + expect(shouldAutoApplyFreshRecordingZoomsForSource(1280, 960)).toBe(true); + }); + + it("blocks automatic fresh-recording zooms for narrow or near-square captures", () => { + expect(shouldAutoApplyFreshRecordingZoomsForSource(960, 1020)).toBe(false); + expect(shouldAutoApplyFreshRecordingZoomsForSource(1080, 1080)).toBe(false); + }); + + it("does not block when source dimensions are not available yet", () => { + expect(shouldAutoApplyFreshRecordingZoomsForSource()).toBe(true); + }); +}); + describe("buildInteractionZoomSuggestions (click-cluster logic)", () => { it("creates one zoom track for a single isolated click with 500ms padding", () => { const telemetry = withMoves([makeClick(5_000)], TOTAL_MS); @@ -62,23 +72,23 @@ describe("buildInteractionZoomSuggestions (click-cluster logic)", () => { expect(result.suggestions).toHaveLength(1); }); - it.each(["right-click", "middle-click"] as const)( - "accepts %s telemetry like a standard click", - (interactionType) => { - const result = buildInteractionZoomSuggestions({ - cursorTelemetry: withMoves([makeClick(5_000, 0.5, 0.5, interactionType)], TOTAL_MS), - totalMs: TOTAL_MS, - defaultDurationMs: 3_000, - }); + it.each([ + "right-click", + "middle-click", + ] as const)("accepts %s telemetry like a standard click", (interactionType) => { + const result = buildInteractionZoomSuggestions({ + cursorTelemetry: withMoves([makeClick(5_000, 0.5, 0.5, interactionType)], TOTAL_MS), + totalMs: TOTAL_MS, + defaultDurationMs: 3_000, + }); - expect(result.status).toBe("ok"); - expect(result.suggestions).toHaveLength(1); + expect(result.status).toBe("ok"); + expect(result.suggestions).toHaveLength(1); - const [suggestion] = result.suggestions; - expect(suggestion.start).toBe(5_000 - CLICK_CLUSTER_PAD_MS); - expect(suggestion.end).toBe(5_000 + CLICK_CLUSTER_PAD_MS); - }, - ); + const [suggestion] = result.suggestions; + expect(suggestion.start).toBe(5_000 - CLICK_CLUSTER_PAD_MS); + expect(suggestion.end).toBe(5_000 + CLICK_CLUSTER_PAD_MS); + }); it("merges two clicks within 2500ms into one zoom track", () => { const telemetry = withMoves( diff --git a/src/components/video-editor/timeline/zoomSuggestionUtils.ts b/src/components/video-editor/timeline/zoomSuggestionUtils.ts index 189c7604..bf38efa6 100644 --- a/src/components/video-editor/timeline/zoomSuggestionUtils.ts +++ b/src/components/video-editor/timeline/zoomSuggestionUtils.ts @@ -3,6 +3,7 @@ import type { CursorTelemetryPoint, ZoomFocus } from "../types"; export const MIN_DWELL_DURATION_MS = 450; export const MAX_DWELL_DURATION_MS = 2600; export const DWELL_MOVE_THRESHOLD = 0.02; +export const MIN_FRESH_RECORDING_AUTO_ZOOM_SOURCE_ASPECT_RATIO = 1.2; export interface ZoomDwellCandidate { centerTimeMs: number; @@ -39,6 +40,25 @@ export interface InteractionZoomSuggestionResult { suggestions: SuggestedZoomRegion[]; } +export function shouldAutoApplyFreshRecordingZoomsForSource( + sourceWidth?: number, + sourceHeight?: number, +): boolean { + if ( + !Number.isFinite(sourceWidth) || + !Number.isFinite(sourceHeight) || + (sourceWidth ?? 0) <= 0 || + (sourceHeight ?? 0) <= 0 + ) { + return true; + } + + return ( + (sourceWidth as number) / (sourceHeight as number) >= + MIN_FRESH_RECORDING_AUTO_ZOOM_SOURCE_ASPECT_RATIO + ); +} + /** Max gap between consecutive clicks before they are split into separate zoom clusters. */ export const CLICK_CLUSTER_MERGE_GAP_MS = 2500; /** Padding added before the first click and after the last click in a cluster. */ diff --git a/src/hooks/recordingMimeType.test.ts b/src/hooks/recordingMimeType.test.ts index 9f4919f2..79dd6c2d 100644 --- a/src/hooks/recordingMimeType.test.ts +++ b/src/hooks/recordingMimeType.test.ts @@ -7,15 +7,15 @@ import { } from "./recordingMimeType"; describe("selectRecordingMimeType", () => { - it("prefers codecs the editor can play back", () => { + it("keeps browser screen captures in WebM/H.264 when supported", () => { const mimeType = selectRecordingMimeType({ isTypeSupported: () => true, canPlayType: (type) => { - if (type === "video/webm;codecs=vp9") { + if (type === "video/webm;codecs=h264") { return "probably"; } - if (type === "video/webm") { + if (type === "video/webm;codecs=vp9") { return "maybe"; } @@ -23,16 +23,13 @@ describe("selectRecordingMimeType", () => { }, }); - expect(mimeType).toBe("video/webm;codecs=vp9"); + expect(mimeType).toBe("video/webm;codecs=h264"); }); it("skips recorder-only codecs when playback support is missing", () => { const mimeType = selectRecordingMimeType({ isTypeSupported: (type) => - [ - "video/webm;codecs=vp9", - "video/webm;codecs=vp8", - ].includes(type), + ["video/webm;codecs=vp9", "video/webm;codecs=vp8"].includes(type), canPlayType: (type) => (type === "video/webm;codecs=vp8" ? "probably" : ""), }); @@ -42,14 +39,11 @@ describe("selectRecordingMimeType", () => { it("falls back to the first supported codec when playback probing is unavailable", () => { const mimeType = selectRecordingMimeType({ isTypeSupported: (type) => - [ - "video/webm;codecs=av1", - "video/webm;codecs=h264", - ].includes(type), + ["video/webm;codecs=av1", "video/webm;codecs=h264"].includes(type), canPlayType: () => "", }); - expect(mimeType).toBe("video/webm;codecs=av1"); + expect(mimeType).toBe("video/webm;codecs=h264"); }); it("returns undefined when no preferred mime type is supported", () => { @@ -64,9 +58,7 @@ describe("selectRecordingMimeType", () => { it("prefers MP4/H.264 for webcam captures when supported", () => { const mimeType = selectWebcamRecordingMimeType({ isTypeSupported: (type) => - ["video/mp4;codecs=avc1.42E01E", "video/webm;codecs=vp9"].includes( - type, - ), + ["video/mp4;codecs=avc1.42E01E", "video/webm;codecs=vp9"].includes(type), canPlayType: () => "probably", }); @@ -75,8 +67,7 @@ describe("selectRecordingMimeType", () => { it("falls back to WebM webcam capture when MP4 is unavailable", () => { const mimeType = selectWebcamRecordingMimeType({ - isTypeSupported: (type) => - ["video/webm;codecs=vp9", "video/webm"].includes(type), + isTypeSupported: (type) => ["video/webm;codecs=vp9", "video/webm"].includes(type), canPlayType: () => "probably", }); diff --git a/src/hooks/recordingMimeType.ts b/src/hooks/recordingMimeType.ts index 93a5ba82..56930b84 100644 --- a/src/hooks/recordingMimeType.ts +++ b/src/hooks/recordingMimeType.ts @@ -1,9 +1,9 @@ const RECORDING_MIME_TYPE_PREFERENCES = [ + "video/webm;codecs=h264", "video/webm;codecs=vp9", "video/webm", "video/webm;codecs=vp8", "video/webm;codecs=av1", - "video/webm;codecs=h264", ] as const; const WEBCAM_RECORDING_MIME_TYPE_PREFERENCES = [ @@ -38,9 +38,7 @@ function selectMimeTypeFromPreferences( return playableType ?? supportedTypes[0]; } -export function selectRecordingMimeType( - options: MimeTypeSelectorOptions = {}, -): string | undefined { +export function selectRecordingMimeType(options: MimeTypeSelectorOptions = {}): string | undefined { return selectMimeTypeFromPreferences(RECORDING_MIME_TYPE_PREFERENCES, options); } @@ -54,6 +52,8 @@ export function isWebmMimeType(mimeType: string | undefined | null): boolean { return /^video\/webm(?:[;\s]|$)/i.test(mimeType ?? ""); } -export function getVideoExtensionForMimeType(mimeType: string | undefined | null): ".mp4" | ".webm" { +export function getVideoExtensionForMimeType( + mimeType: string | undefined | null, +): ".mp4" | ".webm" { return /^video\/mp4(?:[;\s]|$)/i.test(mimeType ?? "") ? ".mp4" : ".webm"; } diff --git a/src/hooks/useScreenRecorder.test.ts b/src/hooks/useScreenRecorder.test.ts index 00a8a7a9..85811467 100644 --- a/src/hooks/useScreenRecorder.test.ts +++ b/src/hooks/useScreenRecorder.test.ts @@ -1,6 +1,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { + createBrowserRecordingOptions, createProcessedMicrophoneConstraints, normalizeBrowserMicrophoneProfile, resolveBrowserCaptureCursorPolicy, @@ -32,12 +33,12 @@ function createMockMediaRecorder(initialState: RecordingState = "inactive") { } describe("createProcessedMicrophoneConstraints", () => { - it("requests browser voice processing without AGC for the default microphone", () => { + it("requests browser voice processing with AGC for the default microphone", () => { expect(createProcessedMicrophoneConstraints()).toEqual({ audio: { echoCancellation: true, noiseSuppression: true, - autoGainControl: false, + autoGainControl: true, channelCount: { ideal: 1 }, sampleRate: { ideal: 48000 }, }, @@ -45,13 +46,13 @@ describe("createProcessedMicrophoneConstraints", () => { }); }); - it("keeps no-AGC voice processing when a specific microphone is selected", () => { + it("keeps default voice processing when a specific microphone is selected", () => { expect(createProcessedMicrophoneConstraints("device-123")).toMatchObject({ audio: { deviceId: { exact: "device-123" }, echoCancellation: true, noiseSuppression: true, - autoGainControl: false, + autoGainControl: true, channelCount: { ideal: 1 }, sampleRate: { ideal: 48000 }, }, @@ -103,10 +104,38 @@ describe("createProcessedMicrophoneConstraints", () => { }); }); - it("normalizes invalid lab microphone profiles to production no-AGC processing", () => { + it("normalizes invalid lab microphone profiles to production voice processing", () => { expect(normalizeBrowserMicrophoneProfile("RAW")).toBe("raw"); - expect(normalizeBrowserMicrophoneProfile("unknown")).toBe("no-agc"); - expect(normalizeBrowserMicrophoneProfile(null)).toBe("no-agc"); + expect(normalizeBrowserMicrophoneProfile("unknown")).toBe("processed"); + expect(normalizeBrowserMicrophoneProfile(null)).toBe("processed"); + }); +}); + +describe("createBrowserRecordingOptions", () => { + it("sets an aggregate bitrate target for browser screen recordings", () => { + expect( + createBrowserRecordingOptions({ + audioBitsPerSecond: 128_000, + mimeType: "video/webm;codecs=vp9", + videoBitsPerSecond: 30_600_000, + }), + ).toEqual({ + audioBitsPerSecond: 128_000, + bitsPerSecond: 30_728_000, + mimeType: "video/webm;codecs=vp9", + videoBitsPerSecond: 30_600_000, + }); + }); + + it("keeps video-only recordings on the requested video budget", () => { + expect( + createBrowserRecordingOptions({ + videoBitsPerSecond: 30_600_000, + }), + ).toEqual({ + bitsPerSecond: 30_600_000, + videoBitsPerSecond: 30_600_000, + }); }); }); diff --git a/src/hooks/useScreenRecorder.ts b/src/hooks/useScreenRecorder.ts index 4da2ae71..30ed7c62 100644 --- a/src/hooks/useScreenRecorder.ts +++ b/src/hooks/useScreenRecorder.ts @@ -29,10 +29,9 @@ const BITS_PER_MEGABIT = 1_000_000; const MIN_FRAME_RATE = 30; const CHROME_MEDIA_SOURCE = "desktop"; const RECORDING_FILE_PREFIX = "recording-"; -const VIDEO_FILE_EXTENSION = ".webm"; const AUDIO_BITRATE_VOICE = 128_000; const AUDIO_BITRATE_SYSTEM = 192_000; -const MIC_GAIN_BOOST = 1; +const MIC_GAIN_BOOST = 1.4; const WEBCAM_BITRATE = 8_000_000; const WEBCAM_WIDTH = 1280; const WEBCAM_HEIGHT = 720; @@ -52,7 +51,7 @@ export type BrowserCaptureCursorPolicy = { hideOsCursorBeforeRecording: boolean; hideEditorOverlayCursorByDefault: boolean; }; -const DEFAULT_BROWSER_MICROPHONE_PROFILE: BrowserMicrophoneProfile = "no-agc"; +const DEFAULT_BROWSER_MICROPHONE_PROFILE: BrowserMicrophoneProfile = "processed"; const BROWSER_MICROPHONE_PROFILES = new Set([ "processed", "no-agc", @@ -238,6 +237,31 @@ export function createProcessedMicrophoneConstraints( return { audio, video: false }; } +export function createBrowserRecordingOptions({ + audioBitsPerSecond, + mimeType, + videoBitsPerSecond, +}: { + audioBitsPerSecond?: number; + mimeType?: string; + videoBitsPerSecond: number; +}): MediaRecorderOptions { + const options: MediaRecorderOptions = { + videoBitsPerSecond, + bitsPerSecond: videoBitsPerSecond + (audioBitsPerSecond ?? 0), + }; + + if (audioBitsPerSecond !== undefined) { + options.audioBitsPerSecond = audioBitsPerSecond; + } + + if (mimeType) { + options.mimeType = mimeType; + } + + return options; +} + function createMicrophoneTrackSettingsSnapshot( stream: MediaStream, ): MicrophoneTrackSettingsSnapshot | null { @@ -901,7 +925,7 @@ export function useScreenRecorder(): UseScreenRecorderReturn { const webcamPath = await stopWebcamRecorder(); await storeMicrophoneSidecar(resolvedMicFallbackBlobPromise, result.path, startDelayMs); await finalizeRecordingSession(result.path, webcamPath); - + if (typeof window.electronAPI?.hudOverlayClose === "function") { window.electronAPI.hudOverlayClose(); } @@ -1106,52 +1130,60 @@ export function useScreenRecorder(): UseScreenRecorderReturn { // We pass null for webcamPath initially to avoid blocking on webcam disk writes/muxing. await finalizeRecordingSession(finalPath, null); - // 2. Perform background finalization (webcam, muxing, sidecars) - // We don't await this to keep the UI responsive - void (async () => { - try { - // Await the webcam path in the background - const webcamPath = await webcamPathPromise; - console.log("[useScreenRecorder] Background native processing: webcamPath is", webcamPath); + // 2. Perform background finalization (webcam, muxing, sidecars) + // We don't await this to keep the UI responsive + void (async () => { + try { + // Await the webcam path in the background + const webcamPath = await webcamPathPromise; + console.log( + "[useScreenRecorder] Background native processing: webcamPath is", + webcamPath, + ); - // Store sidecars - await storeMicrophoneSidecar( - micFallbackBlobPromise, - finalPath, - fallbackStartDelayMs, - fallbackTrackSettings, - ); + // Store sidecars + await storeMicrophoneSidecar( + micFallbackBlobPromise, + finalPath, + fallbackStartDelayMs, + fallbackTrackSettings, + ); - // Perform muxing/renaming if on Windows - if (isNativeWindows) { - await window.electronAPI.muxNativeWindowsRecording(expectedDurationMs); - } + // Perform muxing/renaming if on Windows + if (isNativeWindows) { + await window.electronAPI.muxNativeWindowsRecording(expectedDurationMs); + } - console.log("[useScreenRecorder] Emitting setCurrentRecordingSession with:", { finalPath, webcamPath }); + console.log( + "[useScreenRecorder] Emitting setCurrentRecordingSession with:", + { finalPath, webcamPath }, + ); - // Update the session state to notify the editor that all background assets (webcam, mic, etc.) are now ready. - // This broadcasts a 'recording-session-changed' event that the open editor listens to for re-scanning assets. - await window.electronAPI.setCurrentRecordingSession({ - videoPath: finalPath, - webcamPath, - timeOffsetMs: webcamTimeOffsetMs.current, - hideOverlayCursorByDefault: hideEditorOverlayCursorByDefault.current, - }); + // Update the session state to notify the editor that all background assets (webcam, mic, etc.) are now ready. + // This broadcasts a 'recording-session-changed' event that the open editor listens to for re-scanning assets. + await window.electronAPI.setCurrentRecordingSession({ + videoPath: finalPath, + webcamPath, + timeOffsetMs: webcamTimeOffsetMs.current, + hideOverlayCursorByDefault: hideEditorOverlayCursorByDefault.current, + }); - console.log( - `[PERF:RENDERER] Background Stop Sequence: COMPLETED in ${(performance.now() - stopStart).toFixed(2)}ms`, - ); - } catch (bgError) { - console.error("Error in background finalization:", bgError); - } finally { - // After all background tasks are done (webcam, mic sidecars, muxing), - // we can safely close the HUD window to release hardware and resources. - if (typeof window.electronAPI?.hudOverlayClose === "function") { - console.log("[useScreenRecorder] All background tasks finished, closing HUD"); - window.electronAPI.hudOverlayClose(); - } - } - })(); + console.log( + `[PERF:RENDERER] Background Stop Sequence: COMPLETED in ${(performance.now() - stopStart).toFixed(2)}ms`, + ); + } catch (bgError) { + console.error("Error in background finalization:", bgError); + } finally { + // After all background tasks are done (webcam, mic sidecars, muxing), + // we can safely close the HUD window to release hardware and resources. + if (typeof window.electronAPI?.hudOverlayClose === "function") { + console.log( + "[useScreenRecorder] All background tasks finished, closing HUD", + ); + window.electronAPI.hudOverlayClose(); + } + } + })(); })(); return; } @@ -1551,7 +1583,10 @@ export function useScreenRecorder(): UseScreenRecorderReturn { try { const hideCursorResult = await window.electronAPI.hideOsCursor?.(); if (hideCursorResult && !hideCursorResult.success) { - console.warn("Could not hide OS cursor before recording.", hideCursorResult); + console.warn( + "Could not hide OS cursor before recording.", + hideCursorResult, + ); } } catch { console.warn("Could not hide OS cursor before recording."); @@ -1747,17 +1782,19 @@ export function useScreenRecorder(): UseScreenRecorderReturn { chunks.current = []; const hasAudio = stream.current.getAudioTracks().length > 0; - const recorder = new MediaRecorder(stream.current, { - videoBitsPerSecond, - ...(mimeType ? { mimeType } : {}), - ...(hasAudio - ? { - audioBitsPerSecond: systemAudioIncluded - ? AUDIO_BITRATE_SYSTEM - : AUDIO_BITRATE_VOICE, - } - : {}), - }); + const audioBitsPerSecond = hasAudio + ? systemAudioIncluded + ? AUDIO_BITRATE_SYSTEM + : AUDIO_BITRATE_VOICE + : undefined; + const recorder = new MediaRecorder( + stream.current, + createBrowserRecordingOptions({ + audioBitsPerSecond, + mimeType, + videoBitsPerSecond, + }), + ); mediaRecorder.current = recorder; recorder.ondataavailable = (event) => { @@ -1779,10 +1816,12 @@ export function useScreenRecorder(): UseScreenRecorderReturn { ); chunks.current = []; const timestamp = recordingSessionTimestamp.current ?? Date.now(); - const videoFileName = `${RECORDING_FILE_PREFIX}${timestamp}${VIDEO_FILE_EXTENSION}`; + const videoFileName = `${RECORDING_FILE_PREFIX}${timestamp}${getVideoExtensionForMimeType(recordingBlobType)}`; try { - const videoBlob = await fixWebmDuration(buggyBlob, duration); + const videoBlob = isWebmMimeType(recordingBlobType) + ? await fixWebmDuration(buggyBlob, duration) + : buggyBlob; const arrayBuffer = await videoBlob.arrayBuffer(); const videoResult = await window.electronAPI.storeRecordedVideo( arrayBuffer, @@ -1813,14 +1852,17 @@ export function useScreenRecorder(): UseScreenRecorderReturn { videoPath: finalVideoPath, webcamPath, timeOffsetMs: webcamTimeOffsetMs.current, - hideOverlayCursorByDefault: hideEditorOverlayCursorByDefault.current, + hideOverlayCursorByDefault: + hideEditorOverlayCursorByDefault.current, }); } } finally { // After all background tasks are done (webcam), // we can safely close the HUD window to release hardware and resources. if (typeof window.electronAPI?.hudOverlayClose === "function") { - console.log("[useScreenRecorder:browser] All background tasks finished, closing HUD"); + console.log( + "[useScreenRecorder:browser] All background tasks finished, closing HUD", + ); window.electronAPI.hudOverlayClose(); } } diff --git a/src/lib/exporter/exportBitrate.test.ts b/src/lib/exporter/exportBitrate.test.ts index 5b6c5f91..1d46dc09 100644 --- a/src/lib/exporter/exportBitrate.test.ts +++ b/src/lib/exporter/exportBitrate.test.ts @@ -15,6 +15,28 @@ describe("export bitrate policy", () => { ).toBe(27_000_000); }); + it("raises high-resolution 60fps source-quality exports above the 30fps budget", () => { + const sharedOptions = { + width: 2560, + height: 1440, + quality: "source" as const, + encodingMode: "quality" as const, + }; + + const thirtyFpsBitrate = getMp4ExportBitrate({ + ...sharedOptions, + frameRate: 30, + }); + const sixtyFpsBitrate = getMp4ExportBitrate({ + ...sharedOptions, + frameRate: 60, + }); + + expect(thirtyFpsBitrate).toBe(45_000_000); + expect(sixtyFpsBitrate).toBeGreaterThan(thirtyFpsBitrate); + expect(sixtyFpsBitrate).toBe(63_639_610); + }); + it("keeps modern native static-layout source exports high enough for screen text", () => { expect( getMp4ExportBitrate({ diff --git a/src/lib/exporter/exportBitrate.ts b/src/lib/exporter/exportBitrate.ts index 7d3fa240..40110b6f 100644 --- a/src/lib/exporter/exportBitrate.ts +++ b/src/lib/exporter/exportBitrate.ts @@ -2,6 +2,7 @@ import type { ExportEncodingMode, ExportMp4FrameRate, ExportQuality } from "./ty const MIN_MP4_BITRATE = 2_000_000; const REFERENCE_PIXEL_RATE = 1920 * 1080 * 30; +const REFERENCE_FRAME_RATE = 30; export function getEncodingModeBitrateMultiplier(encodingMode: ExportEncodingMode): number { switch (encodingMode) { @@ -41,6 +42,10 @@ function getBaseMp4ExportBitrate(width: number, height: number, quality: ExportQ return 30_000_000; } +function getFrameRateBitrateMultiplier(frameRate: ExportMp4FrameRate): number { + return Math.sqrt(Math.max(1, frameRate / REFERENCE_FRAME_RATE)); +} + function getModernNativeStaticLayoutBitrateCap( width: number, height: number, @@ -87,6 +92,7 @@ export function getMp4ExportBitrate(options: { }): number { const requestedBitrate = Math.round( getBaseMp4ExportBitrate(options.width, options.height, options.quality) * + getFrameRateBitrateMultiplier(options.frameRate) * getEncodingModeBitrateMultiplier(options.encodingMode), ); const nativeStaticLayoutBitrate =