fix(export): validate edited-track fast-path inputs

This commit is contained in:
wiiiii123
2026-04-21 18:09:23 +07:00
parent fcdc842371
commit 2b19493bb7
4 changed files with 103 additions and 6 deletions
@@ -100,6 +100,23 @@ describe("editedTrackStrategy", () => {
).toBe("offline-render-fallback");
});
it("falls back when source duration or speed-region bounds are invalid", () => {
const invalidBounds: SpeedRegion[] = [
{ id: "speed-1", startMs: Number.NaN, endMs: 10_000, speed: 1.5 },
];
expect(
classifyEditedTrackStrategy({
primaryAudioSourcePath: "recording.mp4",
sourceDurationMs: Number.POSITIVE_INFINITY,
trimRegions: EMPTY_TRIMS,
speedRegions: invalidBounds,
audioRegions: [],
sourceAudioFallbackPaths: [],
}),
).toBe("offline-render-fallback");
});
it("builds source segments that preserve trims and speed boundaries", () => {
const trimRegions: TrimRegion[] = [{ id: "trim-1", startMs: 10_000, endMs: 12_000 }];
const speedRegions: SpeedRegion[] = [
@@ -118,4 +135,12 @@ describe("editedTrackStrategy", () => {
{ startMs: 18_000, endMs: 20_000, speed: 1 },
]);
});
it("returns no source segments when speed-region bounds are invalid", () => {
expect(
buildEditedTrackSourceSegments(SOURCE_DURATION_MS, EMPTY_TRIMS, [
{ id: "speed-1", startMs: 15_000, endMs: 10_000, speed: 1.5 },
]),
).toEqual([]);
});
});
+38 -3
View File
@@ -26,8 +26,29 @@ function isSafeFiltergraphSpeed(speed: number): boolean {
);
}
function hasSafeFiltergraphSpeedRegions(speedRegions: SpeedRegion[]): boolean {
return speedRegions.every((region) => isSafeFiltergraphSpeed(region.speed));
function hasFiniteTimelineRange(startMs: number, endMs: number, sourceDurationMs: number): boolean {
return (
Number.isFinite(startMs) &&
Number.isFinite(endMs) &&
startMs >= 0 &&
endMs > startMs &&
endMs <= sourceDurationMs
);
}
function hasSafeFiltergraphSpeedRegions(
speedRegions: SpeedRegion[],
sourceDurationMs: number,
): boolean {
if (!Number.isFinite(sourceDurationMs) || sourceDurationMs <= 0) {
return false;
}
return speedRegions.every(
(region) =>
hasFiniteTimelineRange(region.startMs, region.endMs, sourceDurationMs) &&
isSafeFiltergraphSpeed(region.speed),
);
}
function buildKeptRanges(
@@ -64,6 +85,20 @@ export function buildEditedTrackSourceSegments(
trimRegions: TrimRegion[],
speedRegions: SpeedRegion[],
): EditedTrackSourceSegment[] {
if (!Number.isFinite(sourceDurationMs) || sourceDurationMs <= 0) {
return [];
}
if (
speedRegions.some(
(region) =>
!hasFiniteTimelineRange(region.startMs, region.endMs, sourceDurationMs) ||
!isSafeFiltergraphSpeed(region.speed),
)
) {
return [];
}
const segments: EditedTrackSourceSegment[] = [];
const keptRanges = buildKeptRanges(sourceDurationMs, trimRegions);
@@ -119,7 +154,7 @@ export function classifyEditedTrackStrategy(input: EditedTrackStrategyInput): Ed
return "offline-render-fallback";
}
if (!hasSafeFiltergraphSpeedRegions(input.speedRegions)) {
if (!hasSafeFiltergraphSpeedRegions(input.speedRegions, input.sourceDurationMs)) {
return "offline-render-fallback";
}