Skip to content

Commit 5baca94

Browse files
authored
Merge pull request #6280 from remotion-dev/bugfix/web-renderer-onprogress
2 parents 88410b2 + a4d7866 commit 5baca94

File tree

3 files changed

+59
-4
lines changed

3 files changed

+59
-4
lines changed

packages/web-renderer/src/render-media-on-web.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,9 @@ const internalRenderMediaOnWeb = async <
279279
target,
280280
});
281281

282+
using throttledProgress = createThrottledProgressCallback(onProgress);
283+
const throttledOnProgress = throttledProgress?.throttled ?? null;
284+
282285
try {
283286
if (signal?.aborted) {
284287
throw new Error('renderMediaOnWeb() was cancelled');
@@ -337,8 +340,6 @@ const internalRenderMediaOnWeb = async <
337340
encodedFrames: 0,
338341
};
339342

340-
const throttledOnProgress = createThrottledProgressCallback(onProgress);
341-
342343
for (let frame = realFrameRange[0]; frame <= realFrameRange[1]; frame++) {
343344
if (signal?.aborted) {
344345
throw new Error('renderMediaOnWeb() was cancelled');

packages/web-renderer/src/test/render-media.test.tsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,43 @@ test('should throttle onProgress callback to 250ms', {retry: 2}, async (t) => {
9898
}
9999
}
100100
});
101+
102+
test('should not fire stale progress callbacks after render completes', async (t) => {
103+
if (t.task.file.projectName === 'webkit') {
104+
t.skip();
105+
return;
106+
}
107+
108+
let renderCompleted = false;
109+
let staleCallbackReceived = false;
110+
let callbackCallCount = 0;
111+
112+
const Component: React.FC = () => null;
113+
114+
await renderMediaOnWeb({
115+
composition: {
116+
component: Component,
117+
id: 'stale-progress-test',
118+
width: 100,
119+
height: 100,
120+
fps: 30,
121+
durationInFrames: 60,
122+
},
123+
inputProps: {},
124+
onProgress: () => {
125+
callbackCallCount++;
126+
if (renderCompleted) {
127+
staleCallbackReceived = true;
128+
}
129+
},
130+
licenseKey: 'free-license',
131+
});
132+
133+
renderCompleted = true;
134+
135+
// eslint-disable-next-line
136+
await new Promise((resolve) => setTimeout(resolve, 500));
137+
138+
expect(staleCallbackReceived).toBe(false);
139+
expect(callbackCallCount).toBeGreaterThan(0);
140+
});

packages/web-renderer/src/throttle-progress.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,19 @@ import type {RenderMediaOnWebProgressCallback} from './render-media-on-web';
22

33
const DEFAULT_THROTTLE_MS = 250;
44

5+
export type ThrottledProgressResult = {
6+
throttled: RenderMediaOnWebProgressCallback;
7+
[Symbol.dispose]: () => void;
8+
};
9+
510
/**
611
* Creates a throttled version of a progress callback that ensures it's not called
712
* more frequently than the specified interval (default: 250ms)
813
*/
914
export const createThrottledProgressCallback = (
1015
callback: RenderMediaOnWebProgressCallback | null,
1116
throttleMs: number = DEFAULT_THROTTLE_MS,
12-
): RenderMediaOnWebProgressCallback | null => {
17+
): ThrottledProgressResult | null => {
1318
if (!callback) {
1419
return null;
1520
}
@@ -52,5 +57,14 @@ export const createThrottledProgressCallback = (
5257
}
5358
};
5459

55-
return throttled;
60+
const cleanup = () => {
61+
if (timeoutId !== null) {
62+
clearTimeout(timeoutId);
63+
timeoutId = null;
64+
}
65+
66+
pendingUpdate = null;
67+
};
68+
69+
return {throttled, [Symbol.dispose]: cleanup};
5670
};

0 commit comments

Comments
 (0)