Skip to content

feat(engine): a chunk-fed encoder and the rule for which films may use it, off by default - #7029

Merged
miguel-heygen merged 2 commits into
mainfrom
feat/inpage-encode-chunk-encoder
Nov 2, 2026
Merged

miguel-heygen merged 2 commits into
mainfrom
feat/inpage-encode-chunk-encoder

Conversation

@miguel-heygen

Copy link
Copy Markdown
Collaborator

First slice of encoding inside the page: the Node side of it, with nothing wired in yet, so no render changes.

Today each drawElement frame leaves the page as a JPEG, goes to Node, and ffmpeg encodes it with x264. The plan is for the page to encode the frames itself (WebCodecs, hardware where present) and for ffmpeg to only copy the stream into the mp4 with the audio. This slice adds the pieces Node needs for that:

  • chunkStreamingEncoder.ts: spawns ffmpeg on an Annex-B H.264 stream with -c:v copy, writes the BT.709 colour tags into the stream and the container (range taken from what the page encoder reports), and exposes the same StreamingEncoder interface as today's, so the capture loop can use either.
  • spawnFfmpegStream in streamingEncoder.ts: the process, back-pressure, timeout and close handling that spawnStreamingEncoder already had, moved into one function both encoders use. The JPEG check stays with the image encoder. No change to its arguments.
  • inPageEncodeEligibility.ts: the one rule for which films may use the new path (drawElement capture, mp4, h264, one worker, no HDR, alpha, HLS or video layer, and a supported page encoder). Everything else keeps today's path.
  • useInPageEncode in the engine config, off by default, HF_INPAGE_ENCODE to turn it on. Nothing reads it yet.

Test

New: chunkStreamingEncoder.test.ts builds an Annex-B stream with x264, feeds it in three pieces, and checks the mp4 has 30 frames at 30 fps and BT.709 tags; it also pins the arguments (copy, no filter, the stream tag, the reported range). inPageEncodeEligibility.test.ts covers each reason a film stays on today's path. The existing streaming encoder tests pass unchanged (217 tests across the four files, 3 runs in a row, tsc and oxfmt clean). Removing the stream tag from the arguments fails the two argument tests.

Size

About 400 changed lines, mostly new files and tests. The page-side encoder and the capture branch that uses these follow in the next slices.

@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Edit accuracy: accurate 271 (base branch 271), smooth 116 of those

The gate passes.
Smoothness is reported in the artifact, not gated. A case fails only if it fails 2 of 3 runs.

Quarantined, measured but not gated (0)

Unstable (1)

  • seqab-none-pct-r0-root-z100: tracking 0.05, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo true, teleport true / tracking 0.05, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo true, teleport true / tracking 0.05, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo true, teleport true

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: REQUEST CHANGES · 1 blocker · 0 important · 0 nits · head 2b19b9a9

CI is red because of this diff: the producer's ffprobe argv contract rejects the new test ↓ inline. The rest checks out. The flag is off by default and nothing reads it yet. The spawnFfmpegStream extraction keeps no references to options, and the JPEG check is unchanged for the image encoder. This is a feature PR, so it does not need a 'fails without the fix:' line.

Scope

Read all 7 files end-to-end. No prior reviews. CI: Producer: unit tests ✗ (ffprobeArgvContract.test.ts, 1 failed), and Test ✗ as a consequence. Everything else is green.

— Genesis (Lane B)

"-show_entries",
"stream=nb_read_frames,r_frame_rate,color_space,color_primaries,color_transfer,color_range",
])
.concat(["-of", "json", out]),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blocker (CI): Producer: unit tests fails in src/utils/ffprobeArgvContract.test.ts, which reports chunkStreamingEncoder.test.ts: "--" must be immediately before the input. Every ffprobe argv in the repo needs -- right before the path.

Suggested change
.concat(["-of", "json", out]),
.concat(["-of", "json", "--", out]),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Fixed in dca10dc

@miguel-heygen

Copy link
Copy Markdown
Collaborator Author

Pushed (rebased on main). The blocker was ffprobeArgvContract.test.ts: my new chunkStreamingEncoder.test.ts ran ffprobe without -- right before the input, and the argv was built with a .concat chain the contract's reader could not parse. It is now one plain argv literal ending in "--", out. The contract test passes (118); the chunk encoder, eligibility and streaming encoder tests pass 3 runs in a row (104), tsc and oxfmt clean.

@miguel-heygen
miguel-heygen force-pushed the feat/inpage-encode-chunk-encoder branch from 2b19b9a to dca10dc Compare November 2, 2026 17:37

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE — 1 resolved, 0 open, 0 new · 2b19b9a → dca10dc

@miguel-heygen
miguel-heygen added this pull request to the merge queue Nov 2, 2026
Merged via the queue into main with commit 0bcd816 Nov 2, 2026
90 checks passed
@miguel-heygen
miguel-heygen deleted the feat/inpage-encode-chunk-encoder branch November 2, 2026 18:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant