Files
Recordly/scripts/benchmark-export-queues.mjs
webadderall 5d040fbf2c refactor: split large files into focused modules
Split all source files exceeding 500 lines into smaller, focused modules:

- electron/main.ts → mainBootstrapHelpers, mainRuntimeState, mainUpdateIntegration, mainWindowControls
- electron/windows.ts → editorWindows, hudWindows, windowShared
- electron/updater.ts → updaterDialogs, updaterEventHandlers, updaterShared
- electron/preload.ts → preloadExtensionsBridge, preloadUpdateBridge
- electron/ipc/register/recording.ts → recording/ directory with focused handlers
- src/components/video-editor/VideoEditor.tsx → EditorContent, EditorHeader, EditorSidebar, EditorToolbar, hooks/
- src/components/video-editor/SettingsPanel.tsx → settings/ directory with per-section components
- src/components/video-editor/AnnotationSettingsPanel.tsx → tab components
- src/components/video-editor/ExtensionManager.tsx → extension-manager/ directory
- src/components/video-editor/VideoPlayback.tsx → videoPlaybackComponent/ directory
- src/components/video-editor/projectPersistence.ts → projectPersistence{Normalization,Paths,Regions,Shared}.ts
- src/components/video-editor/timeline/TimelineEditor.tsx → TimelineEditor/ directory
- src/components/video-editor/types.ts → focused type modules
- src/components/launch/LaunchWindow.tsx → LaunchWindow/ directory
- src/hooks/useScreenRecorder.ts → useScreenRecorder/ directory
- src/lib/exporter/audioEncoder.ts → audioEncoder/ directory
- src/lib/exporter/frameRenderer.ts → frameRenderer modules
- src/lib/exporter/modernFrameRenderer.ts → filters and lifecycle modules
- src/lib/exporter/modernVideoExporter.ts → modernVideoExporter/ directory
- src/lib/exporter/videoExporter.ts → video-exporter/ directory
- src/lib/exporter/streamingDecoder.ts → streamingDecoderHelpers.ts
- src/lib/extensions/extensionHost.ts → extensionHost{ApiFactory,QueryApi,RegistrationApi,Shared,State}.ts
- src/lib/extensions/types.ts → focused type modules
- electron/native/ScreenCaptureKitRecorder.swift → ScreenCaptureKitRecorder/ directory
- scripts/benchmark-export-queues.mjs → benchmark-export-queues/ directory
- .github/workflows/release.yml → extracted merge-macos-metadata composite action
- scripts/build-native-helpers.mjs → updated for multi-file Swift compilation

Also incorporates upstream default export quality change (good → source).
2026-04-20 20:41:42 +10:00

177 lines
6.0 KiB
JavaScript

import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import electron from "electron";
import ffmpegStatic from "ffmpeg-static";
import { buildBenchmarkRequests, createBenchmarkConfig } from "./benchmark-export-queues/config.mjs";
import { createFixtureVideo, ensureBuildArtifacts } from "./benchmark-export-queues/fixtures.mjs";
import {
calculateDelta,
printBackendDetailTable,
printDeltaTable,
printRequestedConfigTable,
printTimingSummaryTable,
} from "./benchmark-export-queues/reporting.mjs";
import { runBenchmarkRequest } from "./benchmark-export-queues/runner.mjs";
function logBenchmarkConfig(config, benchmarkRequests) {
console.log("[benchmark-export-queues] Config");
console.log(
JSON.stringify({
width: config.width,
height: config.height,
frameRate: config.frameRate,
durationSeconds: config.durationSeconds,
timeoutMs: config.timeoutMs,
runsPerVariant: config.runsPerVariant,
requestedPipeline: config.exportPipeline,
requestedBackend: config.exportBackend,
requestedBackends: benchmarkRequests.map((request) => request.label),
backendSweepEnabled: benchmarkRequests.length > 1,
requestedEncodingMode: config.exportEncodingMode,
requestedShadowIntensity: config.exportShadowIntensity,
webcamEnabled: config.useWebcamOverlay,
requestedWebcamShadowIntensity: config.webcamShadowIntensity,
requestedWebcamSize: config.webcamSize,
}),
);
printRequestedConfigTable(config, benchmarkRequests);
}
function printJsonSummary(benchmarkResults, config) {
console.log("[benchmark-export-queues] Summary");
for (const result of benchmarkResults) {
for (const summary of result.summaries) {
console.log(
JSON.stringify({
requestedPipeline: result.request.pipeline,
requestedBackend: result.request.backend,
name: summary.variant.name,
webcamEnabled: config.useWebcamOverlay,
webcamShadowIntensity: config.webcamShadowIntensity,
webcamSize: config.webcamSize,
maxEncodeQueue: summary.variant.maxEncodeQueue,
maxDecodeQueue: summary.variant.maxDecodeQueue,
maxPendingFrames: summary.variant.maxPendingFrames,
averageElapsedMs: summary.averageElapsedMs,
medianElapsedMs: summary.medianElapsedMs,
minElapsedMs: summary.minElapsedMs,
maxElapsedMs: summary.maxElapsedMs,
averageSizeBytes: summary.averageSizeBytes,
averageOutputDurationSeconds: summary.averageOutputDurationSeconds,
averageSmokeElapsedMs: summary.averageSmokeElapsedMs,
observedRenderBackends: summary.observedRenderBackends,
observedEncodeBackends: summary.observedEncodeBackends,
observedEncoders: summary.observedEncoders,
runs: summary.runs.map((run) => ({
elapsedMs: run.elapsedMs,
sizeBytes: run.sizeBytes,
outputDuration: run.outputDuration,
smokeExportReport: run.smokeExportReport,
smokeProgressSummary: run.smokeProgressSummary,
})),
}),
);
}
}
}
function printVariantComparisons(benchmarkResults) {
for (const result of benchmarkResults) {
if (result.summaries.length < 2) {
continue;
}
const baseline = result.summaries[0];
const tuned = result.summaries[1];
const { deltaMs, deltaPercent } = calculateDelta(
baseline.averageElapsedMs,
tuned.averageElapsedMs,
);
const { deltaMs: medianDeltaMs, deltaPercent: medianPercent } = calculateDelta(
baseline.medianElapsedMs,
tuned.medianElapsedMs,
);
const backendLabel = result.request.backend ?? "default";
console.log(
`[benchmark-export-queues] ${backendLabel} tuned vs baseline: ${deltaMs}ms (${typeof deltaPercent === "number" ? deltaPercent.toFixed(1) : "-"}%)`,
);
console.log(
`[benchmark-export-queues] ${backendLabel} tuned vs baseline (median): ${medianDeltaMs}ms (${typeof medianPercent === "number" ? medianPercent.toFixed(1) : "-"}%)`,
);
}
}
async function main() {
if (typeof ffmpegStatic !== "string" || ffmpegStatic.length === 0) {
throw new Error("ffmpeg-static is unavailable for this platform");
}
if (typeof electron !== "string" || electron.length === 0) {
throw new Error("The Electron binary is unavailable in this workspace");
}
const config = createBenchmarkConfig();
await ensureBuildArtifacts(config);
const benchmarkRequests = buildBenchmarkRequests(config);
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "recordly-export-queue-bench-"));
const inputPath = path.join(tempDir, "input.mp4");
const webcamInputPath = config.useWebcamOverlay ? path.join(tempDir, "webcam.mp4") : null;
try {
logBenchmarkConfig(config, benchmarkRequests);
console.log(`[benchmark-export-queues] Generating fixture video: ${inputPath}`);
await createFixtureVideo(ffmpegStatic, inputPath, {
durationSeconds: config.durationSeconds,
frameRate: config.frameRate,
fixtureWidth: config.width,
fixtureHeight: config.height,
});
if (webcamInputPath) {
console.log(
`[benchmark-export-queues] Generating webcam fixture video: ${webcamInputPath}`,
);
await createFixtureVideo(ffmpegStatic, webcamInputPath, {
durationSeconds: config.durationSeconds,
frameRate: config.frameRate,
fixtureWidth: config.webcamWidth,
fixtureHeight: config.webcamHeight,
includeAudio: false,
videoFilter: `testsrc=size=${config.webcamWidth}x${config.webcamHeight}:rate=${config.frameRate}`,
});
}
const benchmarkResults = [];
for (const benchmarkRequest of benchmarkRequests) {
benchmarkResults.push(
await runBenchmarkRequest(
electron,
ffmpegStatic,
inputPath,
webcamInputPath,
benchmarkRequest,
config,
),
);
}
printJsonSummary(benchmarkResults, config);
printTimingSummaryTable(benchmarkResults);
printBackendDetailTable(benchmarkResults);
printDeltaTable(benchmarkResults);
printVariantComparisons(benchmarkResults);
} finally {
await fs.rm(tempDir, { recursive: true, force: true });
}
}
main().catch((error) => {
console.error(
`[benchmark-export-queues] ${error instanceof Error ? error.message : String(error)}`,
);
process.exitCode = 1;
});