Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 23 additions & 9 deletions crates/compositor/src/regions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,22 @@ pub fn speed_segments_for_window(
for region in overlapping {
let start = region.start_sec.max(source_start_sec).max(cursor);
let end = region.end_sec.min(source_end_sec);
// Projection can leave a zero-width region at a trim boundary. It may still pass
// the overlap filter when rounding puts its start just inside the clip window. Skip
// it before emitting the 1x gap, or the unchanged cursor makes that gap render twice.
if end <= start {
continue;
}
if start > cursor {
push_speed_segment(&mut spans, cursor, start, 1.0, fps);
}
if end > start {
let speed = if region.speed.is_finite() && region.speed > 0.0 {
region.speed
} else {
1.0
};
push_speed_segment(&mut spans, start, end, speed, fps);
cursor = end;
}
let speed = if region.speed.is_finite() && region.speed > 0.0 {
region.speed
} else {
1.0
};
push_speed_segment(&mut spans, start, end, speed, fps);
cursor = end;
}
if cursor < source_end_sec {
push_speed_segment(&mut spans, cursor, source_end_sec, 1.0, fps);
Expand Down Expand Up @@ -3133,6 +3137,16 @@ mod exporter_frame_totals {
60,
"région débordant la fenêtre gardée"
);
let issue_876_fps = 60.0;
let first_clip = frames(
0.0,
44.81830642526596,
&[region(44.818, 44.818, 1.5)],
issue_876_fps,
);
let second_clip = frames(0.0, 47.833333, &[region(0.0, 1.87, 1.5)], issue_876_fps);
assert_eq!(first_clip, 2690, "une région vide ne double pas le premier clip");
assert_eq!(first_clip + second_clip, 5523, "total corrigé du repro #876");
assert_eq!(
frames(
0.0,
Expand Down
15 changes: 15 additions & 0 deletions src/lib/exporter/outputFrameCount.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,21 @@ describe("outputFrameCount", () => {
).toBe(60);
});

it("does not double-count a clip for an empty speed region at its trimmed edge (#876)", () => {
const clips = [
{ sourceStartSec: 0, sourceEndSec: 44.81830642526596 },
{ sourceStartSec: 0, sourceEndSec: 47.833333 },
];
const regions = [
{ startSec: 44.818, endSec: 44.818, speed: 1.5, clipIndex: 0 },
{ startSec: 0, endSec: 1.87, speed: 1.5, clipIndex: 1 },
];

// The first region is empty after trim projection. Before the fix it caused the first
// clip's normal-speed prefix to be counted twice, yielding the reported 8,213 frames.
expect(outputFrameCount(clips, regions, 60)).toBe(5_523);
});

it("never renders the same source time twice when two regions overlap", () => {
// A stale payload can overlap; the first region keeps the covered portion, matching
// `speed_segments_for_window`'s cursor.
Expand Down
14 changes: 9 additions & 5 deletions src/lib/exporter/outputFrameCount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,18 @@ export function clipOutputFrameCount(
for (const region of overlapping) {
const start = Math.max(region.startSec, sourceStartSec, cursor);
const end = Math.min(region.endSec, sourceEndSec);
// Projection can leave a zero-width region at a trim boundary. It may still pass
// the overlap filter when rounding puts its start just inside the clip window. Skip
// it before emitting the 1x gap, or the unchanged cursor makes that gap render twice.
if (end <= start) {
continue;
}
if (start > cursor) {
frames += segmentFrames(cursor, start, 1, fps);
}
if (end > start) {
const speed = Number.isFinite(region.speed) && region.speed > 0 ? region.speed : 1;
frames += segmentFrames(start, end, speed, fps);
cursor = end;
}
const speed = Number.isFinite(region.speed) && region.speed > 0 ? region.speed : 1;
frames += segmentFrames(start, end, speed, fps);
cursor = end;
}
if (cursor < sourceEndSec) {
frames += segmentFrames(cursor, sourceEndSec, 1, fps);
Expand Down
Loading