From f10da7815d9d69fb6549290b5be03a15855abc97 Mon Sep 17 00:00:00 2001 From: Vance Ingalls Date: Tue, 21 Apr 2026 03:04:39 -0700 Subject: [PATCH 1/4] test(producer): add hdr-regression and hdr-hlg-regression test suites Replace the old hdr-pq + hdr-image-only tests with two consolidated regression suites that exercise the full HDR pipeline. hdr-regression (PQ, BT.2020, ~20s): - 8 windows (A-H) covering clip-only video, image+video composition, wrapper opacity, direct-on-video opacity, scene transitions, transform + border-radius, mid-clip cuts, and shader transitions. - Reuses the existing hdr-clip.mp4 fixture (NOTICE.md preserved). - New hdr-photo-pq.png generated via scripts/generate-hdr-photo-pq.py (writes a cICP chunk for BT.2020/PQ/full). hdr-hlg-regression (HLG, ARIB STD-B67, ~5s): - 2 windows (A-B) covering clip-only HLG playback and HLG + opacity tween. - New hdr-hlg-clip.mp4 fixture (last 5s of a user-recorded HLG iPhone clip). Both compositions follow the documented timed-element pattern: data-start, data-duration, and class="clip" applied directly to each timed leaf element (no wrapper inheritance). CI: regression workflow's hdr shard now runs the new pair sequentially. LFS: new MP4 fixtures and golden outputs are tracked via existing rules. Goldens generated with bun run test:update --sequential. ffprobe verifies HEVC/yuv420p10le/bt2020nc/smpte2084 (PQ) and arib-std-b67 (HLG). Made-with: Cursor --- .github/workflows/regression.yml | 2 +- packages/engine/src/utils/ffprobe.test.ts | 4 +- .../tests/hdr-hlg-regression/README.md | 45 +++ .../tests/hdr-hlg-regression/meta.json | 14 + .../output/compiled.html | 72 +++- .../hdr-hlg-regression/output/output.mp4 | 3 + .../hdr-hlg-regression/src/hdr-hlg-clip.mp4 | 3 + .../tests/hdr-hlg-regression/src/index.html | 112 ++++++ .../producer/tests/hdr-image-only/README.md | 49 --- .../producer/tests/hdr-image-only/meta.json | 14 - .../tests/hdr-image-only/output/compiled.html | 72 ---- .../tests/hdr-image-only/output/output.mp4 | 3 - .../tests/hdr-image-only/src/index.html | 60 --- packages/producer/tests/hdr-pq/meta.json | 14 - .../producer/tests/hdr-pq/output/output.mp4 | 3 - packages/producer/tests/hdr-pq/src/index.html | 68 ---- .../{hdr-pq => hdr-regression}/NOTICE.md | 0 .../producer/tests/hdr-regression/README.md | 83 ++++ .../producer/tests/hdr-regression/meta.json | 14 + .../tests/hdr-regression/output/compiled.html | 344 ++++++++++++++++ .../tests/hdr-regression/output/output.mp4 | 3 + .../scripts/generate-hdr-photo-pq.py} | 6 +- .../src/hdr-clip.mp4 | 0 .../src/hdr-photo-pq.png} | Bin .../tests/hdr-regression/src/index.html | 375 ++++++++++++++++++ 25 files changed, 1062 insertions(+), 301 deletions(-) create mode 100644 packages/producer/tests/hdr-hlg-regression/README.md create mode 100644 packages/producer/tests/hdr-hlg-regression/meta.json rename packages/producer/tests/{hdr-pq => hdr-hlg-regression}/output/compiled.html (54%) create mode 100644 packages/producer/tests/hdr-hlg-regression/output/output.mp4 create mode 100644 packages/producer/tests/hdr-hlg-regression/src/hdr-hlg-clip.mp4 create mode 100644 packages/producer/tests/hdr-hlg-regression/src/index.html delete mode 100644 packages/producer/tests/hdr-image-only/README.md delete mode 100644 packages/producer/tests/hdr-image-only/meta.json delete mode 100644 packages/producer/tests/hdr-image-only/output/compiled.html delete mode 100644 packages/producer/tests/hdr-image-only/output/output.mp4 delete mode 100644 packages/producer/tests/hdr-image-only/src/index.html delete mode 100644 packages/producer/tests/hdr-pq/meta.json delete mode 100644 packages/producer/tests/hdr-pq/output/output.mp4 delete mode 100644 packages/producer/tests/hdr-pq/src/index.html rename packages/producer/tests/{hdr-pq => hdr-regression}/NOTICE.md (100%) create mode 100644 packages/producer/tests/hdr-regression/README.md create mode 100644 packages/producer/tests/hdr-regression/meta.json create mode 100644 packages/producer/tests/hdr-regression/output/compiled.html create mode 100644 packages/producer/tests/hdr-regression/output/output.mp4 rename packages/producer/tests/{hdr-image-only/scripts/generate-fixture.py => hdr-regression/scripts/generate-hdr-photo-pq.py} (94%) rename packages/producer/tests/{hdr-pq => hdr-regression}/src/hdr-clip.mp4 (100%) rename packages/producer/tests/{hdr-image-only/src/hdr-photo.png => hdr-regression/src/hdr-photo-pq.png} (100%) create mode 100644 packages/producer/tests/hdr-regression/src/index.html diff --git a/.github/workflows/regression.yml b/.github/workflows/regression.yml index c8dd04eb5..5dae94829 100644 --- a/.github/workflows/regression.yml +++ b/.github/workflows/regression.yml @@ -95,7 +95,7 @@ jobs: - shard: render-compat args: "--sequential gsap-letters-render-compat css-spinner-render-compat raf-ball-render-compat iframe-render-compat" - shard: hdr - args: "--sequential hdr-pq hdr-image-only" + args: "--sequential hdr-regression hdr-hlg-regression" - shard: styles-a args: "style-1-prod style-2-prod style-3-prod" - shard: styles-b diff --git a/packages/engine/src/utils/ffprobe.test.ts b/packages/engine/src/utils/ffprobe.test.ts index 97bc1f698..20ebd5887 100644 --- a/packages/engine/src/utils/ffprobe.test.ts +++ b/packages/engine/src/utils/ffprobe.test.ts @@ -55,7 +55,7 @@ describe("extractVideoMetadata", () => { it("reads HDR PNG cICP metadata when ffprobe color fields are absent", async () => { const fixturePath = resolve( __dirname, - "../../../producer/tests/hdr-image-only/src/hdr-photo.png", + "../../../producer/tests/hdr-regression/src/hdr-photo-pq.png", ); const metadata = await extractVideoMetadata(fixturePath); @@ -102,7 +102,7 @@ describe("extractPngMetadataFromBuffer", () => { it("continues to parse the checked-in HDR PNG fixture", () => { const fixture = readFileSync( - resolve(__dirname, "../../../producer/tests/hdr-image-only/src/hdr-photo.png"), + resolve(__dirname, "../../../producer/tests/hdr-regression/src/hdr-photo-pq.png"), ); expect(extractPngMetadataFromBuffer(fixture)?.colorSpace?.colorTransfer).toBe("smpte2084"); }); diff --git a/packages/producer/tests/hdr-hlg-regression/README.md b/packages/producer/tests/hdr-hlg-regression/README.md new file mode 100644 index 000000000..a6dc31e41 --- /dev/null +++ b/packages/producer/tests/hdr-hlg-regression/README.md @@ -0,0 +1,45 @@ +# hdr-hlg-regression + +Regression test that locks down end-to-end **HDR HLG (BT.2020 ARIB STD-B67)** +video rendering. Companion to `hdr-regression` (PQ), kept as a separate suite +so the HLG-specific encoder/metadata path stays tested in isolation. + +## What it covers + +| Window | Time | Shape | Expected | +| ------ | ------------ | ------------------------------------- | -------- | +| A | 0.0 – 2.5 s | Baseline HLG video + DOM overlay | pass | +| B | 2.5 – 5.0 s | Wrapper opacity fade around HLG video | pass | + +The test pins the contract that: + +- `extractVideoMetadata` reports `bt2020/arib-std-b67/limited` for the HLG + source (i.e. HLG is detected and not silently coerced to PQ). +- `isHdrColorSpace` flips the orchestrator into the layered HDR path on the + HLG signal. +- The HLG source is decoded into `rgb48le` and blitted under the SDR DOM + overlay on every frame. +- Wrapper-opacity composition (window B) does not break HLG pass-through. +- `hdrEncoder` writes HEVC Main10 / `yuv420p10le` / BT.2020 HLG with the + correct color tags (no PQ mastering display metadata for HLG). + +The suite is intentionally short (5 s, two windows) — it exists to detect +regressions in the HLG-specific code path, not to enumerate every composition +shape (those live in `hdr-regression`). + +## Fixture + +`src/hdr-hlg-clip.mp4` — last 5 seconds of a user-recorded HEVC HLG clip, +remuxed (no re-encode) so the HLG color tags survive verbatim. + +## Running + +```bash +cd packages/producer +bun run test hdr-hlg-regression + +bun run test:update hdr-hlg-regression +``` + +In CI it runs in the `hdr` shard alongside `hdr-regression` +(see `.github/workflows/regression.yml`). diff --git a/packages/producer/tests/hdr-hlg-regression/meta.json b/packages/producer/tests/hdr-hlg-regression/meta.json new file mode 100644 index 000000000..95c16379a --- /dev/null +++ b/packages/producer/tests/hdr-hlg-regression/meta.json @@ -0,0 +1,14 @@ +{ + "name": "hdr-hlg-regression", + "description": "Regression test for HDR HLG (BT.2020 ARIB STD-B67) video pass-through. Two windows: (A) baseline HLG video + SDR DOM overlay, (B) wrapper-opacity fade applied to an HLG video. Verifies that an HLG HEVC source drives the layered HDR pipeline end-to-end (extractVideoMetadata reports hlg, ffmpegFrameSource decodes correctly, hdrEncoder writes HEVC Main10 / yuv420p10le / BT.2020 HLG with the appropriate mastering metadata) and that opacity composition does not break HLG signal pass-through.", + "tags": ["regression", "hdr"], + "minPsnr": 28, + "maxFrameFailures": 0, + "minAudioCorrelation": 0, + "maxAudioLagWindows": 1, + "renderConfig": { + "fps": 30, + "workers": 1, + "hdr": true + } +} diff --git a/packages/producer/tests/hdr-pq/output/compiled.html b/packages/producer/tests/hdr-hlg-regression/output/compiled.html similarity index 54% rename from packages/producer/tests/hdr-pq/output/compiled.html rename to packages/producer/tests/hdr-hlg-regression/output/compiled.html index 7e6ea0145..de20c6113 100644 --- a/packages/producer/tests/hdr-pq/output/compiled.html +++ b/packages/producer/tests/hdr-hlg-regression/output/compiled.html @@ -24,7 +24,21 @@ font-display: block; } - HDR PQ Regression + HDR HLG Regression Suite + -
- +
+ + +
+ A · HLG baseline + DOM overlay +
-
HDR PQ
+ +
+ +
+
+ B · HLG wrapper opacity fade +
+ - + diff --git a/packages/producer/tests/hdr-hlg-regression/output/output.mp4 b/packages/producer/tests/hdr-hlg-regression/output/output.mp4 new file mode 100644 index 000000000..124db64de --- /dev/null +++ b/packages/producer/tests/hdr-hlg-regression/output/output.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8a55a505de180ef3eea4311848bc58d56778a0a291713726b8c27f07e80d5bfe +size 6156319 diff --git a/packages/producer/tests/hdr-hlg-regression/src/hdr-hlg-clip.mp4 b/packages/producer/tests/hdr-hlg-regression/src/hdr-hlg-clip.mp4 new file mode 100644 index 000000000..b630e4fe3 --- /dev/null +++ b/packages/producer/tests/hdr-hlg-regression/src/hdr-hlg-clip.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e6f0be49c970a41111a10f146e6b19177da7d42c7791aeb70fdabf3cbf8e06d2 +size 4533211 diff --git a/packages/producer/tests/hdr-hlg-regression/src/index.html b/packages/producer/tests/hdr-hlg-regression/src/index.html new file mode 100644 index 000000000..d125dab3e --- /dev/null +++ b/packages/producer/tests/hdr-hlg-regression/src/index.html @@ -0,0 +1,112 @@ + + + + + HDR HLG Regression Suite + + + + +
+ + +
+ A · HLG baseline + DOM overlay +
+ + +
+ +
+
+ B · HLG wrapper opacity fade +
+
+ + + + diff --git a/packages/producer/tests/hdr-image-only/README.md b/packages/producer/tests/hdr-image-only/README.md deleted file mode 100644 index 0317f3fc8..000000000 --- a/packages/producer/tests/hdr-image-only/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# hdr-image-only - -Regression test that locks down end-to-end **HDR still-image** rendering — no -HDR video source involved. - -## What it covers - -- `parseImageElements` discovers the `` source. -- `extractStillImageMetadata` (via `ffprobe`) probes the PNG and reads the - `cICP` chunk, surfacing `colorPrimaries=bt2020`, `colorTransfer=smpte2084`. -- `isHdrColorSpace` flips the orchestrator into the layered HDR path even - though `hdrVideoColorSpace` is null (image-only compositions must still - trigger HDR). -- The image is decoded once into `rgb48le` and blitted under the SDR DOM - overlay on every frame. -- The encoder writes HEVC Main10 / `yuv420p10le` / BT.2020 PQ with HDR10 - mastering display + content light level metadata. -- The harness then visually compares the output against the golden - `output/output.mp4` (PSNR ≥ 28). - -## Fixture - -`src/hdr-photo.png` — 256×144, 16-bit RGB, with a hand-injected `cICP` chunk -(primaries=BT.2020, transfer=SMPTE ST 2084, matrix=GBR, range=full). - -ffmpeg is **not** used here because it does not embed `cICP` in PNGs — without -that chunk Chromium would not treat the file as HDR and the test would silently -fall back to SDR. - -To regenerate the fixture: - -```bash -python3 packages/producer/tests/hdr-image-only/scripts/generate-fixture.py -``` - -The script is deterministic (fixed dimensions, fixed gradient), so the PNG -hashes byte-for-byte across runs — safe to commit and diff in CI. - -## Running - -```bash -cd packages/producer -bun run regression hdr-image-only - -bun run regression --update hdr-image-only -``` - -In CI it runs in the `hdr` shard alongside `hdr-pq` -(see `.github/workflows/regression.yml`). diff --git a/packages/producer/tests/hdr-image-only/meta.json b/packages/producer/tests/hdr-image-only/meta.json deleted file mode 100644 index fece16dec..000000000 --- a/packages/producer/tests/hdr-image-only/meta.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "hdr-image-only", - "description": "Regression test for HDR still-image support. Verifies that a 16-bit BT.2020 PQ PNG (tagged via cICP) drives the layered HDR compositing pipeline end-to-end with no HDR video sources present: image is decoded once into rgb48le, blitted under the SDR DOM overlay, and encoded as HEVC Main10 with HDR10 mastering metadata.", - "tags": ["regression", "hdr"], - "minPsnr": 28, - "maxFrameFailures": 0, - "minAudioCorrelation": 0, - "maxAudioLagWindows": 1, - "renderConfig": { - "fps": 30, - "workers": 1, - "hdr": true - } -} diff --git a/packages/producer/tests/hdr-image-only/output/compiled.html b/packages/producer/tests/hdr-image-only/output/compiled.html deleted file mode 100644 index 1d677aac5..000000000 --- a/packages/producer/tests/hdr-image-only/output/compiled.html +++ /dev/null @@ -1,72 +0,0 @@ - - - - - HDR Image-Only Regression - - - -
- HDR PNG -
HDR PNG
-
- - - diff --git a/packages/producer/tests/hdr-image-only/output/output.mp4 b/packages/producer/tests/hdr-image-only/output/output.mp4 deleted file mode 100644 index 85f036119..000000000 --- a/packages/producer/tests/hdr-image-only/output/output.mp4 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e74b69e34c2c2b30a4f8cb82abc50f8cc8590fd209fd94e7c84f7f02230e2c5c -size 21760 diff --git a/packages/producer/tests/hdr-image-only/src/index.html b/packages/producer/tests/hdr-image-only/src/index.html deleted file mode 100644 index 43f021c13..000000000 --- a/packages/producer/tests/hdr-image-only/src/index.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - - HDR Image-Only Regression - - - -
- HDR PNG -
HDR PNG
-
- - - diff --git a/packages/producer/tests/hdr-pq/meta.json b/packages/producer/tests/hdr-pq/meta.json deleted file mode 100644 index 05789088c..000000000 --- a/packages/producer/tests/hdr-pq/meta.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "hdr-pq", - "description": "Regression test for HDR10 (BT.2020 PQ) video pass-through with a static SDR DOM overlay. Verifies that an HDR HEVC Main10 source plus a single white text label renders end-to-end through the layered HDR compositing pipeline (rgb48le DOM-over-video blit, x265 Main10 encode, HDR10 mastering metadata).", - "tags": ["regression", "hdr"], - "minPsnr": 28, - "maxFrameFailures": 0, - "minAudioCorrelation": 0, - "maxAudioLagWindows": 1, - "renderConfig": { - "fps": 30, - "workers": 1, - "hdr": true - } -} diff --git a/packages/producer/tests/hdr-pq/output/output.mp4 b/packages/producer/tests/hdr-pq/output/output.mp4 deleted file mode 100644 index a4be70ced..000000000 --- a/packages/producer/tests/hdr-pq/output/output.mp4 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:00c0ee1bf4e19c372898683c4b65d346a58c71ad590a03b7db1388d1255d680a -size 1732052 diff --git a/packages/producer/tests/hdr-pq/src/index.html b/packages/producer/tests/hdr-pq/src/index.html deleted file mode 100644 index 3a891ee47..000000000 --- a/packages/producer/tests/hdr-pq/src/index.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - HDR PQ Regression - - - -
- - -
HDR PQ
-
- - - diff --git a/packages/producer/tests/hdr-pq/NOTICE.md b/packages/producer/tests/hdr-regression/NOTICE.md similarity index 100% rename from packages/producer/tests/hdr-pq/NOTICE.md rename to packages/producer/tests/hdr-regression/NOTICE.md diff --git a/packages/producer/tests/hdr-regression/README.md b/packages/producer/tests/hdr-regression/README.md new file mode 100644 index 000000000..25284b1c1 --- /dev/null +++ b/packages/producer/tests/hdr-regression/README.md @@ -0,0 +1,83 @@ +# hdr-regression + +Comprehensive regression test that locks down end-to-end **HDR10 (BT.2020 PQ)** +rendering across the most common composition shapes that touch the layered HDR +compositing pipeline. Replaces the older single-shape `hdr-pq` and +`hdr-image-only` suites with a single 20-second timeline that exercises eight +windows back-to-back. + +## What it covers + +| Window | Time | Shape | Expected | +| ------ | ------------- | ----------------------------------------- | ------------------- | +| A | 0.0 – 2.0 s | Baseline HDR video + DOM overlay | pass | +| B | 2.0 – 4.5 s | Wrapper opacity fade around HDR video | pass | +| C | 4.5 – 7.0 s | Direct `