mirror of
https://github.com/webadderallorg/Recordly.git
synced 2026-09-25 15:25:44 +00:00
Preserve paused preview camera and defer composition until seek completion
This commit is contained in:
@@ -1044,9 +1044,9 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
|
||||
});
|
||||
cropBoundsRef.current = result.cropBounds;
|
||||
|
||||
// Reset camera container to identity
|
||||
cameraContainer.scale.set(1);
|
||||
cameraContainer.position.set(0, 0);
|
||||
// Layout updates the media geometry, not the composed camera pose.
|
||||
// In particular, a ResizeObserver notification while paused must not
|
||||
// replace the exported spring position with an unzoomed frame.
|
||||
|
||||
const selectedId = selectedZoomIdRef.current;
|
||||
const activeRegion = selectedId
|
||||
@@ -1893,6 +1893,7 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
|
||||
video,
|
||||
getClips: () => clipRegionsRef.current,
|
||||
onTime: (time, source) => {
|
||||
timelineTimeRef.current = time;
|
||||
if (source !== null) currentTimeRef.current = source * 1000;
|
||||
onTimeUpdate(time);
|
||||
},
|
||||
@@ -1909,6 +1910,7 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
|
||||
transport.seek(timelineTimeRef.current);
|
||||
const handleSeeked = () => {
|
||||
isSeekingRef.current = false;
|
||||
shouldSnapPausedFrameRef.current = true;
|
||||
};
|
||||
const handleSeeking = () => {
|
||||
isSeekingRef.current = true;
|
||||
@@ -2016,6 +2018,7 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
|
||||
if (
|
||||
!shouldComposePreviewFrame({
|
||||
motionMode,
|
||||
isSeeking: isSeekingRef.current || Boolean(videoRef.current?.seeking),
|
||||
contentTimeChanged,
|
||||
shouldSnapPausedFrame: shouldSnapPausedFrameRef.current,
|
||||
})
|
||||
|
||||
@@ -43,13 +43,13 @@ describe("resolveSceneZoomTarget", () => {
|
||||
});
|
||||
|
||||
describe("resolvePreviewMotionMode", () => {
|
||||
it("preserves the composed frame on a plain pause", () => {
|
||||
it.each([false, true])("preserves a plain pause with classic mode %s", (zoomClassicMode) => {
|
||||
expect(
|
||||
resolvePreviewMotionMode({
|
||||
isPlaying: false,
|
||||
isSeeking: false,
|
||||
shouldSnapPausedFrame: false,
|
||||
zoomClassicMode: false,
|
||||
zoomClassicMode,
|
||||
}),
|
||||
).toBe("preserve");
|
||||
});
|
||||
@@ -97,3 +97,16 @@ describe("shouldComposePreviewFrame", () => {
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("preview seek completion", () => {
|
||||
it("holds the composed frame until seeking finishes, even with a pending refresh", () => {
|
||||
const pending = {
|
||||
motionMode: "snap" as const,
|
||||
contentTimeChanged: true,
|
||||
shouldSnapPausedFrame: true,
|
||||
};
|
||||
expect(shouldComposePreviewFrame({ ...pending, isSeeking: true })).toBe(false);
|
||||
expect(shouldComposePreviewFrame({ ...pending, isSeeking: false })).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -32,7 +32,7 @@ export function resolvePreviewMotionMode({
|
||||
shouldSnapPausedFrame: boolean;
|
||||
zoomClassicMode: boolean;
|
||||
}): PreviewMotionMode {
|
||||
if (isSeeking || shouldSnapPausedFrame || zoomClassicMode) {
|
||||
if (isSeeking || shouldSnapPausedFrame || (isPlaying && zoomClassicMode)) {
|
||||
return "snap";
|
||||
}
|
||||
|
||||
@@ -42,14 +42,17 @@ export function resolvePreviewMotionMode({
|
||||
/** Match export's one-composition-per-media-frame behavior. */
|
||||
export function shouldComposePreviewFrame({
|
||||
motionMode,
|
||||
isSeeking = false,
|
||||
contentTimeChanged,
|
||||
shouldSnapPausedFrame,
|
||||
}: {
|
||||
motionMode: PreviewMotionMode;
|
||||
isSeeking?: boolean;
|
||||
contentTimeChanged: boolean;
|
||||
shouldSnapPausedFrame: boolean;
|
||||
}): boolean {
|
||||
if (motionMode === "preserve") {
|
||||
// Do not consume the pending composition against the old decoded image.
|
||||
if (isSeeking || motionMode === "preserve") {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user