Skip to content

fix(engine): normalize mixed HDR/SDR video inputs#258

Open
vanceingalls wants to merge 1 commit intomainfrom
fix/mixed-hdr-sdr-video-normalization
Open

fix(engine): normalize mixed HDR/SDR video inputs#258
vanceingalls wants to merge 1 commit intomainfrom
fix/mixed-hdr-sdr-video-normalization

Conversation

@vanceingalls
Copy link
Copy Markdown
Collaborator

@vanceingalls vanceingalls commented Apr 14, 2026

Summary

When a HyperFrames composition contains both HDR and SDR video files, the SDR content looks washed out because Chrome's compositor clamps HDR pixel values to sRGB range. This PR normalizes all video inputs to the same color space before rendering.

What it does

  • Detects HDR color spacesffprobe now extracts colorTransfer, colorPrimaries, and colorSpace from video metadata. A new isHdrColorSpace() helper identifies bt2020/PQ/HLG sources.
  • Converts SDR to HDR when needed — If any video in the composition is HDR, all SDR videos (bt709) are converted to HLG/BT.2020 via FFmpeg's colorspace filter during frame extraction. This ensures all video frames share the same color space before compositing.
  • Preserves original quality — HDR sources are never tone-mapped down. The conversion only goes SDR → HDR, never HDR → SDR.

Files changed

File What changed
packages/engine/src/utils/ffprobe.ts Added VideoColorSpace to metadata, isHdrColorSpace() detection
packages/engine/src/services/videoFrameExtractor.ts 3-phase extraction (resolve → normalize → extract), convertSdrToHdr() via colorspace filter
packages/engine/src/services/videoFrameExtractor.test.ts Smoke test for isHdrColorSpace re-export

How to test

Render a composition that mixes an iPhone HDR clip (HLG) with a standard SDR clip. The SDR clip should look normal — not washed out or orange-shifted.

Stack position

1 of 6 — This is the base of the HDR stack. All subsequent PRs build on this normalization.

🤖 Generated with Claude Code

…ut colors

When a composition contains both HDR (bt2020) and SDR (bt709) video elements,
the SDR content appears washed out because Chrome clamps HDR frames to sRGB
during rendering. This adds automatic color space detection and normalization
during the video frame extraction phase — if any video is HDR, all SDR videos
are converted to HLG/BT.2020 (npl=600) via zscale before frame extraction.

- Add colorSpace (transfer, primaries, matrix) to VideoMetadata via ffprobe
- Add isHdrColorSpace() to detect bt2020/PQ/HLG content
- Add convertSdrToHdr() using zscale with 600 nit nominal peak luminance
- Restructure extractAllVideoFrames into 3 phases: resolve, normalize, extract
- 6 new unit tests for HDR detection across all color space variants

Same approach as HeyGen Rio's pipeline (heygen_rio.py#L568-585).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vanceingalls vanceingalls force-pushed the fix/mixed-hdr-sdr-video-normalization branch from bc461a1 to 4923ab0 Compare April 16, 2026 00:07
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