Skip to content

Parallel capture: worker's first frame is captured before the seek paints, leaving a fully transparent frame at every worker chunk boundary #2477

Description

@yahelshiran-rvr

Describe the bug

I render transparent WebM overlays with parallel capture (4 workers, and I see massive flickering
I dug in and found the flicker is baked into the file: a single fully transparent frame at every interior worker chunk boundary. For a 144 frame render with 4 workers that's frames 36, 72 and 108, exactly w * ceil(totalFrames/workers). Worker 0 is fine because frame 0 is the initially painted state.

Root cause: executeWorkerTask calls captureFrameRange right after initializeSession, and the first loop iteration captures task.startFrame right after __hf.seek(t). On loaded machines the seek hasn't painted yet, so the screenshot catches an empty page. Every later frame is fine because the previous iteration's seek already settled the page.

One more thing worth saying: you already have the fix in the codebase. discardWarmupCapture (throwaway seek+capture that restores all the session counters) is defined and exported but never called anywhere.

Link to reproduction

Steps to reproduce

The bug is verifiable in code on any machine, no render needed:

  1. Open dist/index.js of any published version from 0.7.25 to 0.7.58
  2. Look at executeWorkerTask: it calls captureFrameRange immediately after initializeSession
  3. captureFrameRange's first loop iteration captures task.startFrame right after __hf.seek(t), with no settle. Every later frame is fine because the previous iteration's seek already painted
  4. Note discardWarmupCapture is defined and exported with zero call sites, so nothing warms up the parallel workers

To detect it on any affected output, decode with libvpx and scan the alpha plane:

ffmpeg -c:v libvpx-vp9 -i out.webm -vf "alphaextract,signalstats,metadata=mode=print" -f null -

Frames at w * ceil(totalFrames/workers) show alpha mean ~0.0 between normal neighbors. The frames are transparent, not black, so color plane blackdetect misses them.

Expected behavior

Every worker's first captured frame contains the actual seeked state of the composition, same as a serial capture of that frame index would produce.

Actual behavior

frame 71 alphaYAVG=4.17
frame 72 alphaYAVG=0.00 <- boundary blank (144/4 * 2)
frame 73 alphaYAVG=4.2

Environment

@hyperframes/producer 0.7.25 on node:22.16-slim (linux/amd64),
Chromium + SwiftShader (no GPU), c6a.4xlarge, 4 parallel workers, forceScreenshot,
transparent WebM (yuva420p)

Additional context

No response

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions