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

No one assigned

    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