mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
fix(producer): wire --crf and --video-bitrate CLI overrides into encoders (#372)
## Summary Re-wire the `--crf` and `--video-bitrate` CLI flags through the three encoder spawn sites in `renderOrchestrator.ts`. They were defined and parsed in the CLI but silently dropped before reaching ffmpeg. ## Why `Chunk 10` of `plans/hdr-followups.md`. PR #292 originally wired these through with a `baseEncoderOpts` object using `effectiveQuality`/`effectiveBitrate`; PR #268 rewrote the encode paths and reverted to `preset.quality` only, accidentally dropping the override. This is a user-facing regression — `hyperframes render --crf 18` was being silently ignored. ## What changed - At the three encoder spawn sites (HDR streaming, SDR streaming, disk-based encode), `quality` defaults to `preset.quality` but is overridden by `job.config.crf` when set, and `bitrate` is set from `job.config.videoBitrate`. Mutual exclusivity is enforced upstream in the CLI, so we don't re-check it here. - Fix the contradictory note in `docs/packages/cli.mdx` that claimed CRF/bitrate were now driven only by `--quality`. The flags table now lists `--crf` and `--video-bitrate` consistent with `docs/guides/rendering.mdx`. ## Test plan - [x] `hyperframes render --crf 18 ...` now respects the CRF override (verified via ffprobe of the encoded output). - [x] `hyperframes render --hdr ...` still works (no behavior change at the default path). - [x] `hyperframes render --help` shows all flags consistent with the docs. ## Stack Chunk 10 of `plans/hdr-followups.md`. Independent of all other chunks.
This commit is contained in:
@@ -496,13 +496,15 @@ This is suppressed in CI environments, non-TTY shells, and when `HYPERFRAMES_NO_
|
|||||||
| `--format` | mp4, webm, mov | mp4 | Output format (WebM/MOV render with transparency) |
|
| `--format` | mp4, webm, mov | mp4 | Output format (WebM/MOV render with transparency) |
|
||||||
| `--fps` | 24, 30, 60 | 30 | Frames per second |
|
| `--fps` | 24, 30, 60 | 30 | Frames per second |
|
||||||
| `--quality` | draft, standard, high | standard | Encoding quality preset (drives CRF/bitrate) |
|
| `--quality` | draft, standard, high | standard | Encoding quality preset (drives CRF/bitrate) |
|
||||||
|
| `--crf` | 0-51 | — | Override encoder CRF (lower = higher quality). Mutually exclusive with `--video-bitrate` |
|
||||||
|
| `--video-bitrate` | e.g. `10M`, `5000k` | — | Target video bitrate. Mutually exclusive with `--crf` |
|
||||||
| `--hdr` | — | off | Detect HDR sources and output HDR10 (H.265 10-bit, BT.2020 PQ/HLG). MP4 only. SDR-only compositions are unaffected. See [HDR Rendering](/guides/hdr) |
|
| `--hdr` | — | off | Detect HDR sources and output HDR10 (H.265 10-bit, BT.2020 PQ/HLG). MP4 only. SDR-only compositions are unaffected. See [HDR Rendering](/guides/hdr) |
|
||||||
| `--workers` | 1-8 | 4 | Parallel render workers |
|
| `--workers` | 1-8 | 4 | Parallel render workers |
|
||||||
| `--gpu` | — | off | GPU encoding (NVENC, VideoToolbox, VAAPI) |
|
| `--gpu` | — | off | GPU encoding (NVENC, VideoToolbox, VAAPI) |
|
||||||
| `--docker` | — | off | Use Docker for [deterministic rendering](/concepts/determinism) |
|
| `--docker` | — | off | Use Docker for [deterministic rendering](/concepts/determinism) |
|
||||||
| `--quiet` | — | off | Suppress verbose output |
|
| `--quiet` | — | off | Suppress verbose output |
|
||||||
|
|
||||||
CRF and target bitrate are now driven by `--quality`. For programmatic renders, `RenderConfig.crf` and `RenderConfig.videoBitrate` still accept overrides.
|
CRF and target bitrate default to the `--quality` preset. Use `--crf` or `--video-bitrate` for fine-grained overrides; `RenderConfig.crf` and `RenderConfig.videoBitrate` accept the same overrides programmatically.
|
||||||
|
|
||||||
#### WebM with Transparency
|
#### WebM with Transparency
|
||||||
|
|
||||||
|
|||||||
@@ -1186,6 +1186,26 @@ export async function executeRenderJob(
|
|||||||
const encoderHdr = hasHdrContent ? effectiveHdr : undefined;
|
const encoderHdr = hasHdrContent ? effectiveHdr : undefined;
|
||||||
const preset = getEncoderPreset(job.config.quality, outputFormat, encoderHdr);
|
const preset = getEncoderPreset(job.config.quality, outputFormat, encoderHdr);
|
||||||
|
|
||||||
|
// CLI overrides (--crf, --video-bitrate) flow through job.config and must
|
||||||
|
// win over the preset-derived defaults. The CLI enforces mutual exclusivity
|
||||||
|
// upstream, but we still resolve them defensively. Without this, the flags
|
||||||
|
// are silently ignored at the encoder spawn sites below — see PR #268 which
|
||||||
|
// dropped the prior baseEncoderOpts wiring.
|
||||||
|
//
|
||||||
|
// Programmatic callers can construct RenderConfig directly and bypass the
|
||||||
|
// CLI's mutual-exclusivity guard. If both are set we honor crf (matches the
|
||||||
|
// CLI semantics where --crf is the explicit override) and warn loudly so
|
||||||
|
// the caller doesn't get a quietly-different bitrate than they passed in.
|
||||||
|
if (job.config.crf != null && job.config.videoBitrate) {
|
||||||
|
log.warn(
|
||||||
|
`[Render] Both crf=${job.config.crf} and videoBitrate=${job.config.videoBitrate} were set. ` +
|
||||||
|
`These are mutually exclusive; honoring crf and ignoring videoBitrate. ` +
|
||||||
|
`Set only one to silence this warning.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const effectiveQuality = job.config.crf ?? preset.quality;
|
||||||
|
const effectiveBitrate = job.config.crf != null ? undefined : job.config.videoBitrate;
|
||||||
|
|
||||||
job.framesRendered = 0;
|
job.framesRendered = 0;
|
||||||
|
|
||||||
// ── HDR z-ordered multi-layer compositing ──────────────────────────────
|
// ── HDR z-ordered multi-layer compositing ──────────────────────────────
|
||||||
@@ -1316,7 +1336,8 @@ export async function executeRenderJob(
|
|||||||
height,
|
height,
|
||||||
codec: preset.codec,
|
codec: preset.codec,
|
||||||
preset: preset.preset,
|
preset: preset.preset,
|
||||||
quality: preset.quality,
|
quality: effectiveQuality,
|
||||||
|
bitrate: effectiveBitrate,
|
||||||
pixelFormat: preset.pixelFormat,
|
pixelFormat: preset.pixelFormat,
|
||||||
hdr: preset.hdr,
|
hdr: preset.hdr,
|
||||||
rawInputFormat: "rgb48le",
|
rawInputFormat: "rgb48le",
|
||||||
@@ -2033,7 +2054,8 @@ export async function executeRenderJob(
|
|||||||
height,
|
height,
|
||||||
codec: preset.codec,
|
codec: preset.codec,
|
||||||
preset: preset.preset,
|
preset: preset.preset,
|
||||||
quality: preset.quality,
|
quality: effectiveQuality,
|
||||||
|
bitrate: effectiveBitrate,
|
||||||
pixelFormat: preset.pixelFormat,
|
pixelFormat: preset.pixelFormat,
|
||||||
useGpu: job.config.useGpu,
|
useGpu: job.config.useGpu,
|
||||||
imageFormat: captureOptions.format || "jpeg",
|
imageFormat: captureOptions.format || "jpeg",
|
||||||
@@ -2259,7 +2281,8 @@ export async function executeRenderJob(
|
|||||||
height,
|
height,
|
||||||
codec: preset.codec,
|
codec: preset.codec,
|
||||||
preset: preset.preset,
|
preset: preset.preset,
|
||||||
quality: preset.quality,
|
quality: effectiveQuality,
|
||||||
|
bitrate: effectiveBitrate,
|
||||||
pixelFormat: preset.pixelFormat,
|
pixelFormat: preset.pixelFormat,
|
||||||
useGpu: job.config.useGpu,
|
useGpu: job.config.useGpu,
|
||||||
hdr: preset.hdr,
|
hdr: preset.hdr,
|
||||||
|
|||||||
Reference in New Issue
Block a user