Skip to content

perf(engine): encode high quality with the x264 fast preset - #6640

Merged
miguel-heygen merged 2 commits into
mainfrom
perf/high-quality-fast-preset
Oct 29, 2026
Merged

miguel-heygen merged 2 commits into
mainfrom
perf/high-quality-fast-preset

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

What

--quality high (and delivery) encodes with the x264 fast preset instead of slow, at the same CRF 15. Same visual quality, about half the encoder CPU, so high-quality renders stop waiting on the encoder after capture ends.

Why

x264 slow is often the slowest part of a high-quality render: capture finishes and the render then waits for the encoder to drain. On real frames from a render, fast reaches the same quality at the same CRF for half the CPU:

x264 at CRF 15, the 1,271 JPEG frames a real 42 s 1080x1920 render fed its encoder CPU s size VMAF mean (1% low) vs the frames
slow (today) 113.7 25.6 MB 97.62 (96.81)
fast (this PR) 56.2 26.1 MB 97.58 (96.75)
medium 66.1 25.8 MB 97.59

Why under 100 lines

One lever: the high tier's preset is one value in ENCODER_PRESETS. The rest is the two tests that pin it.

Related work

Refs #5945.

How

ENCODER_PRESETS.high.preset goes from slow to fast. Everything that reads the high tier follows:

  • local and cloud x264 encodes at high, including the distributed CFR re-encode (cfrRateControlArgs);
  • HDR (x265) at high, slow -> fast. On the same 1,271 frames (10-bit, CRF 15): 394.7 -> 153.1 CPU s, 20.3 -> 15.0 MB, VMAF 97.49 (96.41) -> 97.19 (96.04). A larger step than x264's, still far under one just-noticeable difference;
  • NVENC at high maps fast to p4 (was p5), the level standard already uses; QSV gets fast;
  • VideoToolbox, VAAPI, AMF, WebM and MOV ignore the preset name, so they do not change.

CRF, rate control, x264-params and every other quality setting are unchanged. Standard and draft are unchanged.

Test plan

  • Fails without the fix: chunkEncoder.test.ts > ENCODER_PRESETS > high uses the fast preset with low CRF for better quality and assemble.test.ts > assemble() > cfr re-encode keeps the chunks' rate control (each fails with only the test change applied).
  • chunkEncoder.test.ts 109 passed, assemble.test.ts 20 passed; tsc --noEmit (engine) exit 0; oxfmt and oxlint clean.
  • Manual testing performed: before/after on the real CLI (below).
  • Documentation updated (not applicable)
  • Comments follow CONTRIBUTING.md "Comments"

Before / after

Published hyperframes@0.8.210 vs the same bundle with only the preset changed, hyperframes render --quality high. Apple M4 Pro (14 cores, 24 GB), interleaved, medians (3 runs for the short fixtures, 2 for the long ones). wall - compile drops compile, which is network-bound. VMAF is against a lossless (--crf 0) render of the same frames.

fixture workers wall - compile, slow -> fast encode tail after capture VMAF mean (1% low), slow -> fast size
style-11-prod, 1080x1920, 14 s 4 11.31 -> 10.14 s (-10%) 0.5 -> 0.2 s 97.38 (96.50) -> 97.34 (96.52) +3.0%
overlay-montage-prod + one mix-blend layer, 42 s 4 24.21 -> 23.33 s (-3.6%) 0.1 -> 0.0 s (frames differ run to run)
4K 60 s with a video 3 68.82 -> 54.95 s (-20%) streamed: encoding runs inside capture 98.67 (97.94) -> 98.64 (97.84) +1.6%
1080p 5 minute text film with music 4 127.09 -> 125.29 s (-1.4%) 0.3 -> 0.1 s 97.05 (93.89) -> 97.01 (93.82) -3.0%

This 14-core Mac mostly keeps up with slow at 4 workers. Where the encoder is the limit, the gap opens: the same Mac with 8 capture workers (#6636) leaves the encoder less CPU.

fixture, 8 workers wall - compile, slow -> fast encode tail after capture
style-11-prod, 14 s 11.86 -> 9.48 s (-20%) 2.2 -> 0.2 s
1080p 5 minute film 94.56 -> 69.64 s (-26%) 18.1 -> 0.1 s

Peak memory (CLI + Chrome + ffmpeg) is equal or lower with fast on every fixture.

@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Edit accuracy: accurate 271 (base branch 271), smooth 139 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)

@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 · 0 blocker · 0 important · 1 nit · head 487ef3bc

One-value change; every reader of ENCODER_PRESETS.high follows it as the body says (local/streaming x264, HDR x265 via getEncoderPreset, distributed chunks via renderChunk + cfrRateControlArgs, NVENC fast→p4, QSV passthrough). The segment-resume hash keys on preset, so cached slow segments are not reused. CI, regression and Windows render verification all pass at this head.

  • nit: packages/engine/src/services/chunkEncoder.test.ts:1074 is still titled "translates the high slow preset to NVENC p5". It passes slow explicitly, so it still passes, but high no longer uses that preset.
Scope

I read chunkEncoder.ts getEncoderPreset, gpuEncoder.ts preset maps, distributed plan.ts/renderChunk.ts/assemble.ts, and segmentManifest.ts. cli/src/cloud/offload.ts hard-codes its own slow for asset re-encodes and is unaffected. Product note, not a finding: high now runs a faster preset than standard (medium). Merge waits on the product call.

@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 · 487ef3bc → faea9acf (test rename only; CI, regression, Windows render verification green)

@miguel-heygen
miguel-heygen added this pull request to the merge queue Oct 29, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 29, 2026
@miguel-heygen
miguel-heygen added this pull request to the merge queue Oct 29, 2026
Merged via the queue into main with commit be05c86 Oct 29, 2026
78 checks passed
@miguel-heygen
miguel-heygen deleted the perf/high-quality-fast-preset branch October 29, 2026 07:03
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