test: log source copy fast path blockers

This commit is contained in:
EtienneLescot
2026-05-07 09:37:43 +02:00
parent afd5e35730
commit 4e5b7a4f5a
2 changed files with 64 additions and 21 deletions
+16 -1
View File
@@ -1,5 +1,9 @@
import { describe, expect, it } from "vitest";
import { isSourceCopyFastPathEligible, type VideoExporterConfig } from "./videoExporter";
import {
getSourceCopyFastPathBlockers,
isSourceCopyFastPathEligible,
type VideoExporterConfig,
} from "./videoExporter";
function createConfig(overrides: Partial<VideoExporterConfig> = {}): VideoExporterConfig {
return {
@@ -123,3 +127,14 @@ describe("isSourceCopyFastPathEligible", () => {
).toBe(false);
});
});
describe("getSourceCopyFastPathBlockers", () => {
it("reports the source-size mismatch that blocks copy-only export", () => {
expect(
getSourceCopyFastPathBlockers(createConfig({ height: 1080 }), {
width: 1920,
height: 1032,
}),
).toContain("output-size 1920x1080 differs from source 1920x1032");
});
});
+48 -20
View File
@@ -92,25 +92,39 @@ export function isSourceCopyFastPathEligible(
config: VideoExporterConfig,
videoInfo: { width: number; height: number },
) {
return (
config.width === videoInfo.width &&
config.height === videoInfo.height &&
!config.webcamVideoUrl &&
!hasActiveTimeRegions(config.trimRegions) &&
!hasActiveSpeedRegions(config.speedRegions) &&
!hasActiveTimeRegions(config.zoomRegions) &&
!hasActiveTimeRegions(config.annotationRegions) &&
!hasNativeCursorOverlay(config) &&
!hasCursorHighlightOverlay(config) &&
isDefaultCrop(config.cropRegion) &&
(config.padding ?? 0) <= SOURCE_COPY_EPSILON &&
(config.videoPadding ?? 0) <= SOURCE_COPY_EPSILON &&
(config.borderRadius ?? 0) <= SOURCE_COPY_EPSILON &&
!config.showShadow &&
config.shadowIntensity <= SOURCE_COPY_EPSILON &&
!config.showBlur &&
(config.motionBlurAmount ?? 0) <= SOURCE_COPY_EPSILON
);
return getSourceCopyFastPathBlockers(config, videoInfo).length === 0;
}
export function getSourceCopyFastPathBlockers(
config: VideoExporterConfig,
videoInfo: { width: number; height: number },
) {
const blockers: string[] = [];
if (config.width !== videoInfo.width || config.height !== videoInfo.height) {
blockers.push(
`output-size ${config.width}x${config.height} differs from source ${videoInfo.width}x${videoInfo.height}`,
);
}
if (config.webcamVideoUrl) blockers.push("webcam overlay is enabled");
if (hasActiveTimeRegions(config.trimRegions)) blockers.push("trim regions are present");
if (hasActiveSpeedRegions(config.speedRegions)) blockers.push("speed regions are present");
if (hasActiveTimeRegions(config.zoomRegions)) blockers.push("zoom regions are present");
if (hasActiveTimeRegions(config.annotationRegions))
blockers.push("annotation regions are present");
if (hasNativeCursorOverlay(config)) blockers.push("editable cursor overlay is enabled");
if (hasCursorHighlightOverlay(config)) blockers.push("cursor highlight overlay is enabled");
if (!isDefaultCrop(config.cropRegion)) blockers.push("crop is not default");
if ((config.padding ?? 0) > SOURCE_COPY_EPSILON) blockers.push("padding is not zero");
if ((config.videoPadding ?? 0) > SOURCE_COPY_EPSILON) blockers.push("video padding is not zero");
if ((config.borderRadius ?? 0) > SOURCE_COPY_EPSILON) blockers.push("roundness is not zero");
if (config.showShadow || config.shadowIntensity > SOURCE_COPY_EPSILON) {
blockers.push("shadow is enabled");
}
if (config.showBlur) blockers.push("background blur is enabled");
if ((config.motionBlurAmount ?? 0) > SOURCE_COPY_EPSILON) blockers.push("motion blur is enabled");
return blockers;
}
function isMp4Source(videoUrl: string, blob: Blob) {
@@ -645,12 +659,22 @@ export class VideoExporter {
}
private async trySourceCopyFastPath(videoInfo: { width: number; height: number }) {
if (!isSourceCopyFastPathEligible(this.config, videoInfo)) {
const blockers = getSourceCopyFastPathBlockers(this.config, videoInfo);
if (blockers.length > 0) {
console.info("[VideoExporter] source-copy fast path disabled", {
blockers,
output: { width: this.config.width, height: this.config.height },
source: videoInfo,
});
return null;
}
const sourceBlob = await this.loadSourceBlob();
if (!sourceBlob || !isMp4Source(this.config.videoUrl, sourceBlob)) {
console.info("[VideoExporter] source-copy fast path disabled", {
blockers: ["source is not a readable MP4"],
source: videoInfo,
});
return null;
}
@@ -665,6 +689,10 @@ export class VideoExporter {
estimatedTimeRemaining: 0,
phase: "finalizing",
});
console.info("[VideoExporter] using source-copy fast path", {
source: videoInfo,
bytes: sourceBlob.size,
});
return {
success: true,