@remotion/media: Apply effects during video rendering#7756
Conversation
…fix-media-video-render-effects
There was a problem hiding this comment.
Important
The !completed guard after runEffectChain in the render path can leave delayRender handles unclosed, which stalls the render pipeline. Details are inline.
Reviewed changes — Fix @remotion/media <Video> to apply effects in the render path (not just preview), by drawing the extracted ImageBitmap to a canvas and running the effect chain before compositing.
video.tsx— Pass memoizedeffectsintoVideoForRendering.video-for-rendering.tsx— AcquireeffectChainState, draw the extracted frame to the output canvas, and runInternals.runEffectChainwhen effects are present.
Kimi K2 | 𝕏
There was a problem hiding this comment.
Important
The previously raised issue on video-for-rendering.tsx is still present in the latest revision.
Reviewed changes — No new substantive code changes were introduced by the merge commit d10f72b; the diff is identical to the prior revision. The finding from the initial review still applies.
Kimi K2 | 𝕏
|
|
||
| if (!completed) { | ||
| imageBitmap.close(); | ||
| return; |
There was a problem hiding this comment.
!completed skips continueRender(newHandle), leaving the delayRender handle open indefinitely and stalling the render pipeline.
runEffectChain returns false only when superseded by a newer run. In the render path, that can only happen when a prior async frame extraction (already cleaned up by useLayoutEffect) races to finish. None of the other effect-chain consumers — CanvasImage, HtmlInCanvas, Gif, or video-iterator-manager — check this return value. Remove the guard and let execution fall through to continueRender.
There was a problem hiding this comment.
Thanks for the review! I think this one is okay to leave as-is: runEffectChain() returns false only when superseded by a newer run, and in that scenario the previous useLayoutEffect cleanup has already called continueRender(newHandle). We also intentionally avoid falling through for stale effect-chain results so we do not continue/register work from an outdated frame. This matches the pattern in other effect consumers such as CanvasImage, Solid, and AnimatedImage, which only continue when the chain completed.

Summary
effectsinto the@remotion/media<Video>render pathImageBitmapframes through the canvas before running effects to preserve WebGL orientationFixes #7725.
Testing
cd packages/media && bunx oxfmt src --writebun run buildbun run formatting