Skip to main content
This page is the demo

A base first, refinements after.
Every stage rebuilt in this tab, and checked.

In the standard· staged-delivery extension Building· the WebAssembly binding this page runs
wai.video.int_motion wai.video.int_refine decode-equivalence

A clip arrives as separate objects. Each group of four frames has a coarse base; each frame then has a layer 1, and each group a layer 2. Every layer is its own WAI1 envelope that names, by content hash, the base it refines and the producer of the stage it expects each frame to be at. A sink applies a layer only to a frame that is exactly there, holds it for a frame that is not there yet, and refuses it with a reason from a closed list otherwise.

This page runs the reference implementation's sink, compiled to WebAssembly. It fetches each object as binary bytes, offers it to the sink, and checks every stage the sink reaches against the stage hash the native reference wrote for the same frame and producer.

loading the WebAssembly sink…
frame — stage — tier —

Shown at 8 frames per second, enlarged three times without smoothing; the source runs at 25.

Each frame's stage

Group 1
Group 2
Group 3

The number in each corner is the frame's stage: 0 for its base, 1 and 2 for its layers. A ✓ means the stage hash equals the native reference's; frozen marks a frame a conflict stopped. Select a frame to show it in the player.

Quality and bytes per stage

StageObjects deliveredBytesBytes so farFrames seen at this stagePSNR over those framesRebuild time in this tab
0 · bases——————
1 · layer 1——————
2 · layer 2——————
The clip now—————

PSNR = 10·log10(255²·N / SSE), where SSE is the exact integer sum of squared differences between the rebuilt frames and the source frames over all N samples of the frames counted (128 × 128 × 3 per frame), summed by the WebAssembly sink itself. A frame is counted at a stage when the page sees it there; a layer the sink applies as its base arrives is never seen at the stages below it. Rebuild time is the wall-clock time of the sink's calls for that stage's objects. Bytes are the objects as delivered.

The objects

Each object is a binary WAI1 envelope: 12 bytes of framing, the manifest and the payload. The split, a layer's residual step q, and the declared cost (the output bytes, symbols and working bytes a decode will need) are read from the envelope when it arrives. The sink compares a layer's declared cost with its limit, and the page a base's, before anything is decoded or allocated. Nothing on the wire is JSON or base64.

ObjectLayerBytesFraming · manifest · payloadqDeclared cost: output B · symbols · working BIdentity (content hash, SHA-256)OutcomeDeliver

What the sink reported

    What a layer names

    Each layer carries refines: the base it refines, its layer number, the span of frames it covers, and prev, the producer it expects each of those frames to have. A frame's producer is the content hash of the envelope that made its current stage: its base at stage 0. A layer 1 here covers one frame and names its base; a layer 2 covers four frames and names, as runs, the four layer-1 objects it was coded against.

    Held, applied, refused

    A layer whose base the sink has not decoded is held for that base. A frame one stage short of a layer holds it until its own predecessor applies, then takes it; past the hold bound it is discarded for that frame (layer-gap), and the frame keeps what it had. Two different layers for the same frame, layer and producer conflict: the sink refuses the second (layer-conflict) and freezes the frame at its stage, so no later layer moves it.

    Why every stage has one hash

    The base is wai.video.int_motion, an integer decode, and each layer is a WIR1 residual: an integer prediction from the stage below, plus the residual times its step, clamped. Every stage is therefore the same bytes on every conforming sink, its tier is decode-equivalence, and its SHA-256 can be compared with the native reference's. A tier the sink cannot state gets no hash.

    The reference, and the code

    The objects were written, and the reference stage hashes produced, with the wai stage command-line tool. The sink in this tab is the same Rust, wai::staged::StageSink, compiled to WebAssembly; a conformance script replays the standard's staged-delivery corpus through the WebAssembly build. The extension is staged delivery; the code is Apache-2.0 in the open-standards repository.

    The source and how the objects were made

    Frames 1 to 12 of the sequence “Sunflower” (1920 × 1080, 25 frames per second) from the Xiph.org test media collection (derf), whose notes state Restrictions of use: No restrictions and Copyright: No Copyright. A 384 × 384 window is converted from BT.709 YCbCr in integer arithmetic and averaged in 3 × 3 blocks to 128 × 128. The page fetches these source frames as raw RGB bytes to measure PSNR.

    The commands
    python3 extract_source.py Sunflower_1920x1080_25-1fps_500f.yuv source.rgb
    # per group g of four frames (gop.rgb), and per frame f (frame.rgb):
    wai stage base   --frames gop.rgb --dims 4,128,128 --q 32 -o g/base.wai
    wai stage refine --base g/base.wai --span f:1 --target frame.rgb --q 8 -o g/L1_ff.wai
    wai stage refine --base g/base.wai --on g/L1_f0.wai … --on g/L1_f3.wai \
                     --target gop.rgb --q 2 -o g/L2.wai
    # the conflicting layer: frame 2 again, at another step
    wai stage refine --base g0/base.wai --span 1:1 --target frame.rgb --q 12 -o g0/L1_f1_alt.wai
    # the native reference
    wai stage apply --json g0/base.wai g1/base.wai g2/base.wai g*/L1_f?.wai g*/L2.wai

    The full script, make.sh, and the extraction script sit beside the objects, under /models/staged/v1/, with a README and the SHA-256 of every file.

    Runs the reference implementation compiled to WebAssembly. In the standard: the staged-delivery extension, its refinement capabilities and the sink. Building: the WebAssembly binding this page loads. Measured in this browser on this content; not a general result.