Skip to content

Commit 6fd5daa

Browse files
Merge pull request #1711 from MinitJain/fix/trim-export-flicker
fix: prevent stale-config frames from appearing in exported video near trim boundaries
2 parents 50b1686 + d0f553c commit 6fd5daa

2 files changed

Lines changed: 61 additions & 46 deletions

File tree

apps/desktop/src/routes/editor/Editor.tsx

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,12 @@ function Inner() {
365365
setEditorState("playbackTime", payload.playhead_position / FPS);
366366
});
367367

368+
let skipRenderFrameForConfigUpdate = false;
369+
368370
const emitRenderFrame = (time: number) => {
371+
if (skipRenderFrameForConfigUpdate) {
372+
return;
373+
}
369374
if (!editorState.playing) {
370375
events.renderFrameEvent.emit({
371376
frame_number: Math.max(Math.floor(time * FPS), 0),
@@ -390,33 +395,6 @@ function Inner() {
390395
return editorState.playbackTime;
391396
});
392397

393-
createEffect(
394-
on(
395-
() => [frameNumberToRender(), previewResolutionBase()],
396-
([number]) => {
397-
if (editorState.playing) return;
398-
renderFrame(number as number);
399-
},
400-
{ defer: false },
401-
),
402-
);
403-
404-
createEffect(
405-
on(isExportMode, (exportMode, prevExportMode) => {
406-
if (prevExportMode === true && exportMode === false) {
407-
emitRenderFrame(frameNumberToRender());
408-
}
409-
}),
410-
);
411-
412-
createEffect(
413-
on(isCropMode, (cropMode, prevCropMode) => {
414-
if (prevCropMode === true && cropMode === false) {
415-
emitRenderFrame(frameNumberToRender());
416-
}
417-
}),
418-
);
419-
420398
const doConfigUpdate = async (time: number) => {
421399
const config = getPreviewProjectConfig(project, editorState);
422400
const frameNumber = Math.max(Math.floor(time * FPS), 0);
@@ -441,6 +419,7 @@ function Inner() {
441419
throttledConfigUpdate(time);
442420
trailingConfigUpdate(time);
443421
};
422+
444423
createEffect(
445424
on(
446425
() => {
@@ -451,12 +430,43 @@ function Inner() {
451430
};
452431
},
453432
() => {
433+
skipRenderFrameForConfigUpdate = true;
434+
queueMicrotask(() => {
435+
skipRenderFrameForConfigUpdate = false;
436+
});
454437
updateConfigAndRender(frameNumberToRender());
455438
},
456439
{ defer: true },
457440
),
458441
);
459442

443+
createEffect(
444+
on(
445+
() => [frameNumberToRender(), previewResolutionBase()],
446+
([number]) => {
447+
if (editorState.playing) return;
448+
renderFrame(number as number);
449+
},
450+
{ defer: false },
451+
),
452+
);
453+
454+
createEffect(
455+
on(isExportMode, (exportMode, prevExportMode) => {
456+
if (prevExportMode === true && exportMode === false) {
457+
emitRenderFrame(frameNumberToRender());
458+
}
459+
}),
460+
);
461+
462+
createEffect(
463+
on(isCropMode, (cropMode, prevCropMode) => {
464+
if (prevCropMode === true && cropMode === false) {
465+
emitRenderFrame(frameNumberToRender());
466+
}
467+
}),
468+
);
469+
460470
const fullscreenMode = () => {
461471
if (isExportMode()) return "export" as const;
462472
return null;

apps/desktop/src/routes/editor/Timeline/ClipTrack.tsx

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
} from "@solid-primitives/event-listener";
55
import { cx } from "cva";
66
import {
7+
batch,
78
type ComponentProps,
89
createEffect,
910
createMemo,
@@ -718,14 +719,16 @@ export function ClipTrack(
718719
initialStart,
719720
});
720721

721-
setProject(
722-
"timeline",
723-
"segments",
724-
i(),
725-
"start",
726-
clampedStart,
727-
);
728-
setPreviewTime(prevDuration());
722+
batch(() => {
723+
setProject(
724+
"timeline",
725+
"segments",
726+
i(),
727+
"start",
728+
clampedStart,
729+
);
730+
setPreviewTime(prevDuration());
731+
});
729732
}
730733

731734
const resumeHistory = projectHistory.pause();
@@ -822,17 +825,19 @@ export function ClipTrack(
822825
seg.start + minRecordedDuration,
823826
);
824827

825-
setProject(
826-
"timeline",
827-
"segments",
828-
i(),
829-
"end",
830-
clampedEnd,
831-
);
832-
setPreviewTime(
833-
prevDuration() +
834-
(clampedEnd - seg.start) / seg.timescale,
835-
);
828+
batch(() => {
829+
setProject(
830+
"timeline",
831+
"segments",
832+
i(),
833+
"end",
834+
clampedEnd,
835+
);
836+
setPreviewTime(
837+
prevDuration() +
838+
(clampedEnd - seg.start) / seg.timescale,
839+
);
840+
});
836841
}
837842

838843
const resumeHistory = projectHistory.pause();

0 commit comments

Comments
 (0)