AcademySoftwareFoundation / AcademySoftwareFoundation/openapv

PSNR ceiling at high bitrates caused by the non-orthogonal transform pair, with an encoder-only fix

Open
#255 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
C
Stars
250
Forks
45
Avg merge
1d 21h
Merged PRs (30d)
10

Description

## Summary

PSNR saturates at high bitrates: beyond a certain point, spending more bits does not raise PSNR, unlike other codecs. The cause is not the internal bit depth, the transform shifts, or the quantizer — it is the **non-orthogonality of the integer transform matrix pair**. An encoder-only change that is fully bitstream-compatible removes the ceiling; measurements below.

## Analysis

Ruled out by measurement (8x8 kernel harness, 20k random full-range blocks per case):

| hypothesis | measurement | verdict |
|---|---|---|
| coefficient grid (s16) too coarse | grid-only floor is ~83 dB | not the cause |
| forward-transform intermediate rounding | single-rounding forward changes nothing (0.4 dB) | not the cause |
| quantizer step / level clipping | at QP 0 max level 8953, zero clipped levels | not the cause |
| implementation bug | exact-arithmetic ITX reproduces the same floor | not the cause |

The floor comes from the matrix pair itself. For the 8x8 base matrix `T`, `T*T^T` has diagonal `32768, 32740, 33124, 32740, ...` and off-diagonal entries up to 50 — rows 2 and 6 (84, 35, ...) have a squared norm 1.1% larger than the others. The decoder applies `T^T` as the inverse, but `T^T != T^-1 * 32768`, so the reconstruction error is **proportional to the signal amplitude**: with full-range random blocks the round-trip is ~52 dB at any bit depth; at 1/8 amplitude it is ~69 dB; at 1/64 amplitude it is lossless.

This also explains why codecs sharing this matrix family do not show the ceiling in practice: they transform small prediction residuals, so the multiplicative error is proportionally small. APV has no pixel-domain prediction — full-amplitude samples enter the transform, exposing the floor in the working range.

## Encoder-only fix (bitstream compatible)

The forward transform is an encoder choice; only the inverse is normative. Replacing the forward matrix with the **least-squares pseudo-inverse of the normative inverse transform**, `G = (T*T^T)^-1 * T`, makes the encoder produce the coefficients that the fixed decoder reconstructs best. Scaled to s16 constants (2^19, i.e. 16x the base scale; entries are the base values x16 with small corrections, e.g. row 2: 1344 -> 1330) the matrix keeps its even/odd symmetry, so the same butterfly structure applies with a generic 4-multiply stage and +4 on both forward shifts.

Branch: https://github.com/AcademySoftwareFoundation/openapv/tree/improve_forward_transform

## Measurements

Kernel round-trip (transform + spec integer ITX): 52.0 -> 100.7 dB (10-bit), 52.0 -> 76.6 dB (12-bit, coefficient-grid bound).

End-to-end, pattern y4m 320x240 10-bit, medium preset, 3 frames:

| QP | size (base -> new) | PSNR (base -> new) |
|---|---|---|
| 0 | 88230 -> 88125 | 67.33 -> **87.46** |
| 2 | 83847 -> 83776 | 67.35 -> 83.96 |
| 6 | 76751 -> 76671 | 67.05 -> 78.15 |
| 12 | 66781 -> 66746 | 66.07 -> 71.87 |
| 18 | 58195 -> 58172 | 63.90 -> 66.30 |
| 24 | 50514 -> 50487 | 59.52 -> 60.16 |
| 30 | 43228 -> 43209 | 54.38 -> 54.52 |
| 40 | 32373 -> 32366 | 45.03 -> 45.07 |

The bitrate is unchanged (marginally smaller), the gain appears exactly where the ceiling used to bind, and mid/high QPs are untouched. 12-bit behaves the same (QP 0: 64.7 -> 79.7 dB, measured with the fix from #254 applied to the decoder). All ctest cases pass, including the conformance hash checks, since the decoder is not modified.

## Remaining work

- The branch forces the C forward transform; the AVX2/NEON `txb` kernels need the new constants (s16, madd-friendly) and the +4 shifts before this can be a PR
- BD-rate measurement on natural content to confirm the mid-QP neutrality
- The RDOQ distortion model keeps working unchanged since the coefficient scale is identical

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with the improve_forward_transform branch and inspect the C forward transform alongside the AVX2/NEON txb kernels, which still need corresponding work. Run the existing ctest cases and compare the listed kernel and end-to-end PSNR measurements; completion also requires BD-rate results on natural content while preserving decoder conformance hashes.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
audio-video-rtc
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.