Skip to content

feat(player): improve enhancement quality and preserve video geometry - #755

Merged
stackia merged 6 commits into
mainfrom
codex/video-enhancement-quality
Sep 8, 2026
Merged

feat(player): improve enhancement quality and preserve video geometry#755
stackia merged 6 commits into
mainfrom
codex/video-enhancement-quality

Conversation

@stackia

@stackia stackia commented Sep 8, 2026

Copy link
Copy Markdown
Owner

Improve denoising and display-size scaling for SD and 1080p/i playback, and prevent the picture changing proportions when enhancement is toggled on anamorphic channels such as Shanxi Satellite TV.

  • Replace spatial-only noise reduction with motion-adaptive temporal denoising. Reject stale history on moving edges and scene cuts, and reset history on seeks and source changes.
  • Run EASU only when the output width or height exceeds the source, retaining the original half-pixel tolerance. Native-size and smaller output skip EASU while keeping denoising and RCAS sharpening. Support 1080p/i enhancement at the display's physical pixel size, up to 3840 × 2160, including both reconstructed interlaced fields.
  • Use noise-aware luminance sharpening with local extrema bounds. Compensate horizontal and vertical gradient gates for their respective upscale ratios so 1080 content displayed at 1440p or 4K does not lose sharpening merely because neighboring output samples are closer together. Keep unit compensation for native-size and smaller output. Restore the mild 1.04 contrast and 1.03 saturation adjustments after sharpening. Interpret denoiser and EASU alpha metadata correctly in their respective sharpening paths.
  • Allocate video textures from decoded media dimensions instead of SAR-adjusted display dimensions, including when enhancement is enabled while paused. A 720 × 576 raster presented as 768 × 576 now retains the complete picture. Initialize immutable upload storage for ANGLE Metal and release shader resources on compilation failures.

Validation: 43 frontend tests, TypeScript checking, changed-file Biome checks, and the production frontend build passed. Real WebGL checks on Chromium covered 32 combinations of native, smaller, and upscaled output, independent axis scaling, Y-flipping, caller-bound framebuffers, contrast and saturation, and returning from upscale to native size; both RGBA16F and RGBA8 denoising history paths passed. Six playback cases verified the expected shader stages for 1080p/i at 1920 × 1080, 2560 × 1440, and 3840 × 2160, plus 24 anamorphic geometry checks covering paused toggles and deinterlacing. Live preview checks on CCTV-1 at all three output sizes and on Shanxi Satellite TV confirmed the expected scale uniforms and contrast/saturation values; paired GPU replays of captured frames had zero pixel error. No GL errors were observed.


Note

Medium Risk
Large changes to the real-time WebGL video path (shaders, temporal state, and sizing) affect every enhanced playback session, though failures fall back to passthrough with explicit resets on seeks.

Overview
Replaces the spatial mosquito-nr filter with a new TemporalDenoiser at source resolution: motion-adaptive history blending, variance clipping on cuts, and original luma packed in alpha for downstream sharpening. History resets on seeks, stage changes, and timeline discontinuities.

FSR path is reworked: EASU runs only when the canvas is larger than the source; native-size output still gets denoise + RCAS with stronger, noise-aware luma sharpening (using denoiser/EASU alpha), scale-aware edge gating, and RGB10_A2 intermediates. Bit-hack reciprocals are replaced with guarded exact math.

The renderer keys uploads and the render gate off rVFC decoded dimensions (metadata.width/height), not SAR-scaled videoWidth/videoHeight, so anamorphic rasters keep correct aspect when enhancement is toggled. Frame textures use pre-allocated RGB8 storage plus texSubImage2D for ANGLE/Metal stability; createProgram cleans up shaders on link/compile failure.

Pipeline wiring moves resize/discontinuity handling into the renderer (seeking, emptied, lightweight rVFC when stopped) and caps upscale targets with MAX_TEXTURE_SIZE.

Reviewed by Cursor Bugbot for commit 9327ca6. Configure here.

@cursor

cursor Bot commented Sep 8, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_dbf43106-a99b-459d-a619-8b47f4e2d645)

Comment thread tools/video-quality/main.ts Fixed
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Documentation preview

The documentation preview has been deployed for this pull request.

@cursor

cursor Bot commented Sep 8, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_c4500fd3-b418-4b30-84dd-62e5480e79db)

@cursor

cursor Bot commented Sep 8, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_ab667cc2-fa70-4822-9bd4-45008d21aab5)

@stackia
stackia merged commit d3e9215 into main Sep 8, 2026
12 checks passed
@stackia
stackia deleted the codex/video-enhancement-quality branch September 8, 2026 08:08
stackia added a commit that referenced this pull request Sep 9, 2026
Fix the brief black flash after the first picture when picture
enhancement or deinterlacing is enabled. This fixes a startup regression
introduced in #755.

The first video-frame callback can arrive while `readyState` is still
`HAVE_METADATA`, so `primeCanvas()` skips drawing. The callback now
renders that decoded frame when startup left the texture ring empty,
instead of exposing an empty canvas until the next frame. Successfully
primed frames still avoid a duplicate upload and filter pass.

Validation: five focused regression tests cover enhancement,
deinterlacing, both enabled, already-primed startup, and raw-video
fallback. The three affected cases fail before the fix. All 48 frontend
tests, TypeScript, changed-file Biome checks, and the production
frontend build pass. Six Chrome/WebGL playback cases using generated
fixtures, including progressive and 1080i H.264/MP2 MSE playback, show
no black frames after the first picture and no GL errors. The
low-frame-rate fixture reproduces the black flash before the fix. E2E
lint and both collection entry points also pass (626 tests collected;
daemon tests were not run for this frontend-only change).

Fixes #760.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Narrow change to first-frame scheduling in the video render loop, with
regression tests; no auth, data, or API surface changes.
> 
> **Overview**
> Fixes a **startup black flash** when picture enhancement or
deinterlacing is on: the first `requestVideoFrameCallback` can fire
before `readyState` reaches `HAVE_CURRENT_DATA`, so `primeCanvas()`
skips and the canvas stays empty until the next frame.
> 
> **`scheduleFrame`** now calls `processFrame` when the texture ring is
still empty (`textures.length === 0`), not only when the loop was
already running (`wasRunning`). Frames that were already primed still
skip a second upload/filter pass.
> 
> Adds **`renderer.test.ts`** with Vitest coverage: first-frame present
for enhancement/deinterlace combos, no double upload when startup is
already primed, and no GL path when both processing features are off
(mocked presenters/GPU).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
99c97d4. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
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.

2 participants