Registers wai.video.int_cond and its frame form wai.video.int_cond.frame, NeuralIntegerExact at decode-equivalence. Each frame's latent is coded given a temporal context, the previous frame's decoded feature (zero for an intra frame): an integer context network over that context gives every latent element's scale and mean, the element is decoded against its scale's table, and an integer conditional decoder and synthesis give the frame and the feature the next frame reads. Every network is a WHM1 network through whm1/1, so every scale, table choice, feature and frame is the encoder's on every decoder. The context is a feature, not pixels, so the decode takes no warp operator and wai-ops/1 gains none. integer-payloads §17 pins WIC1 (a clip of WCF1 frames) and WCF1 (one frame, carried one an object by frame-stream), their checks and decode, and the one-file set WCB1 (model.wcb: ctx, prior, dec, recon and the tables). §17.7 (informative) sets out what lowering DCVC-RT's published weights onto the topology by post-training quantisation takes, as int_hyper was lowered from mbt2018_mean: its blocks are WHG1 graphs of operators wai-ops/1 has, and its hyperprior, spatial passes and rate are what WCF1 does not carry. integer-operators §13.4a adds the lowering wcb1/1 and §13.5 its driver row; SPEC §5 Video rows and the frame-forms text, determinism-tiers rows. wai-rs: int_cond_video (CondModel, plan, load, decode_frame, decode_clip, CondFrames under FrameStream, split, join, corpus); int_payload::wire parses and writes WIC1 and WCF1, which join the magics a format_capability_mismatch names; decode_int decodes the clip; the emit paths parse both payloads. float_free reads int_ops_offload.rs, an integer module its list lacked. wai-ops: lower::wcb1. tools/wai_int_cond_export.py trains the topology on seeded procedural clips, quantises it after training and codes a six-frame 64x64 clip with the integer networks themselves (tests/vectors/int_cond/; its sidecar names its buffer, and tests/int_kernels_vectors.rs holds the clip to it under every kernel policy). int-payload-conformance/int-cond/: the clip's frames, frame streams (clean, two groups, a frame lost, another picture size, a stream that runs out), a fixture for every parse code and the decode's, set fixtures, join refusals. int_payload_verify.py --int-cond decodes the clip, the streams and the decode fixtures with its own integer networks and rANS decoder. Byte-identical on Linux x86_64 and Linux arm64. Co-Authored-By: Claude Opus 5.5 <[email protected]>
38 KiB
WAI Extension: Frame Streams
Status: Draft. Carries an inter-frame video capability one frame an object: each object is one whole
WAI1envelope holding one frame; a group opens with an intra frame, which resets the decoder state; and each later frame of the group names its predecessor by content hash, so that a sink refuses a lost, reordered or altered frame instead of decoding past it against the wrong reference. Registers four frame capabilities (§1), the manifest memberframe(§2), the neural frame payloadWNF1(§4) beside the integer one,WIF1(integer-payloads §16), and the checks a sink makes (§5). The MoQ catalog member that declares a frame stream on a track,wai_frame_stream, is moq-streaming-format §4.3. §9 maps a neural frame stream to and from a track of the neural video packaging of the MOQT Streaming Format (NMSF,draft-herz-moq-nmsf-01), byte for byte where both sides state a frame. No transport is defined or changed: a frame stream rides any carrier that delivers objects in order. Reference implementation:wai-rs—frame_stream::{FrameStream, IntFrames, ParseOnly, split_wiv1, split_dcvc, join_dcvc, catalog, nmsf},neural::DcvcFrames. Conformance:int-payload-conformance/frame-stream/. Keywords MUST, MUST NOT, SHOULD, MAY are RFC 2119/8174.
1. Scope
An inter-frame capability's registered payload holds a whole clip: WIV1 codes every frame
of a clip in one residual stream (integer-payloads §3), and the reference neural
inter-frame payload holds every frame's bitstreams behind one header (§6). A live sender
has one frame at a time, and a carrier that moves objects (MoQ, SPEC §1) moves each frame
as it is made. Each frame capability below carries one frame of its base's
bitstream as its payload:
| frame capability | base | payload | parameter set | registry class |
|---|---|---|---|---|
wai.video.int_motion.frame |
wai.video.int_motion |
WIF1, keyframe 0 (integer-payloads §16) |
none | StandardDefined |
wai.video.int_hyper.frame |
wai.video.int_hyper |
WIF1, keyframe 1 (integer-payloads §16) |
the base's: entropy.json, g_s.whm, h_s.whm |
NeuralIntegerExact |
wai.video.int_cond.frame |
wai.video.int_cond |
WCF1 (integer-payloads §17) |
the base's: model.wcb |
NeuralIntegerExact |
wai.neural.dcvc_rt.frame |
wai.neural.dcvc_rt |
WNF1 (§4) |
the base's, sink-supplied | NeuralFloat |
wai.neural.dcvc_fm.frame |
wai.neural.dcvc_fm |
WNF1 (§4) |
the base's, sink-supplied | NeuralFloat |
A frame capability is a capability of its own because it is a different framing of its
base's bitstream, and a registered string's payload format is fixed (SPEC §8);
wai.audio.opus.packet is the precedent, a capability of one Opus packet whose decoder
state carries from packet to packet. Each is a payload capability, media class video,
with its base's fidelity tier and licence class, and decodes against its base's parameter
set, of its base's shape: a pin on a frame object names the set its base's pin would name.
2. Groups and the frame member
A frame stream is a sequence of objects of one frame capability, in the order a sink
receives them. It is made of groups: a group is one intra frame, then zero or more
inter frames, in order. An intra frame's decode reads nothing but its own payload (and the
parameter set); an inter frame's reads the state the frames before it in its group left
(for WIF1, the previous decoded frame and its intra frame's table; for WNF1 and
WCF1, the reference feature).
Every envelope of a frame capability carries the manifest member frame, an object:
| member | type | meaning |
|---|---|---|
index |
integer, 0 to 2^53 − 1 | the frame's position in its group: 0 for its intra frame, the frame before it plus 1 for every other |
prev |
string, or null |
on an inter frame, the content hash (jwp-receipts §2.1) of the envelope of the frame before it in its group, as 64 lowercase hexadecimal digits; null on an intra frame |
number |
OPTIONAL, integer, 0 to 2^53 − 1 | the frame's sequence number in its stream, as its publisher counts it: on every frame of a group whose intra frame carries one, each the one before it plus 1; on none of a group whose intra frame carries none |
capture_ms |
OPTIONAL, integer, 1 to 2^53 − 1 | the wallclock at which the frame was captured, in milliseconds since 1970-01-01T00:00:00Z, as its publisher states it; absent where it states none |
"frame": { "index": 3, "prev": "<64 lowercase hexadecimal digits>", "number": 1203, "capture_ms": 1793491239699 }
- A member of
framethis revision does not define is ignored.index,numberandcapture_msare integers written as one (SPEC §2). numberandcapture_msare inside the envelope, so the content hash, the next frame'sprevand the object's receipt cover them with the frame. A sink holds a group'snumbers to their sequence (§5) and readscapture_msas its publisher's statement.prevnames the predecessor's whole envelope, its manifest included, and so its ownprev: the hash of a group's last frame commits to every frame of the group, in order, as a receipt chain does.- The content hash is over the envelope's bytes as they travel, the bytes an object receipt names (jwp-receipts §2.1). A sink that receives an encrypted envelope (SPEC §6) takes the hash of what it received, before it opens the payload.
- An encoder writes
fallbacknull: no other capability reads a frame's payload. - Every frame of a group carries the pin its intra frame carries: both have no
conditioning.prior, or both have the same value.
frame is an OPTIONAL manifest member under SPEC §8's rule for a MINOR revision: an
envelope that does not carry it keeps its bytes and its meaning. It is carried exactly
when the capability is a frame capability. A reader of an earlier revision does not
advertise a frame capability, so it finds such an envelope's capability unsupported and
the envelope inert (SPEC §4).
3. The integer frame forms
wai.video.int_motion.frame and wai.video.int_hyper.frame carry WIF1
(integer-payloads §16). A group's intra frame carries the group's residual table, its q
and offset, and frame 0: with keyframe 0 its residual symbols, predicted from grey; with
keyframe 1 the base's nested WIH1, the learned keyframe. Each inter frame carries its
motion vectors, its mv_precision and block, and its residual symbols, in a stream of its
own. The decode of each frame is WIV1's frame step (integer-payloads §3), through the
same stage operators (integer-operators §13.5; the keyframe through
whm1/1, §13.2), so:
- a frame decodes to the same bytes on every conforming sink, given its chain: each frame capability has its base's registry class, and its frames' frame-state-equivalence digests (SPEC §7 Digests) are portable;
- a stream split from a clip (§6) decodes, frame by frame, to the clip's frames, byte for byte, and to the digests the clip's decode gives.
wai.video.int_cond.frame carries WCF1 (integer-payloads §17): one frame of conditional
inter-frame coding, whose latent is coded given the feature the frame before it in its group
left, and which leaves its own feature to the frame after it. Its intra frame reads the zero
feature. Each frame is decoded by integer-payloads §17.4 through its pinned set, so the same
two properties hold: its frames reproduce on every conforming sink given their chain, and a
group split from a WIC1 clip (integer-payloads §17.2, a copy of the clip's frames) decodes
to the clip's frames, byte for byte.
4. WNF1 — one frame of the reference neural inter-frame payload
wai.neural.dcvc_rt.frame and wai.neural.dcvc_fm.frame carry WNF1: one frame's two
bitstreams, behind the clip header every frame of its group repeats.
| off | size | field | rule |
|---|---|---|---|
| 0 | 4 | magic WNF1 |
|
| 4 | 1 | version | 1 |
| 5 | 1 | kind |
0 intra, 1 inter |
| 6 | 2 | reserved | 0 |
| 8 | 4 | h |
≥ 1 |
| 12 | 4 | w |
≥ 1 |
| 16 | 4 | fps_milli |
frames per second × 1000 |
| 20 | 2 | cy |
≥ 1: the latent's channels |
| 22 | 2 | cz |
≥ 1: the hyper-latent's channels |
| 24 | 1 | sy_log2 |
≤ 15: the latent's side is sy = 2^sy_log2 |
| 25 | 1 | sz_log2 |
≤ 15: the hyper-latent's side is sz = 2^sz_log2 |
| 26 | 2 | q |
the quality index the entropy tables are read at |
| 28 | 2 | cf |
≥ 1: the reference feature's channels |
| 30 | 2 | reserved | 0 |
| 32 | 4 | lz |
the hyper-latent bitstream's length |
| 36 | 4 | ly |
the latent bitstream's length |
| 40 | lz |
the hyper-latent bitstream | |
| … | ly |
the latent bitstream |
Nothing follows the latent bitstream. Every multi-byte field is little-endian.
Checks, in this order, each with its code from integer-payloads §8: the magic
(bad_magic); the version byte, present (stream_length) and 1 (version); the fixed
header of 40 bytes (stream_length); the reserved fields (reserved_nonzero); kind, then
h, w, cy, cz and cf at least 1, then sy_log2 and sz_log2 at most 15
(field_range); the frame h·w·3, the latent cy·sy·sy, the hyper-latent cz·sz·sz and
the reference feature cf·sy·sy, each at most 2^26 elements (too_large); the two
bitstreams (stream_length); nothing after them (trailing).
Decode. The bitstreams are the capability's own, as its reference decoder reads them
(neural/video_dcvc.rs): the latents are entropy-decoded from the two bitstreams against
the base's parameter set at q, and the base's temporal network maps the latents and the
reference feature to the frame and the next reference feature. An intra frame starts the
reference feature at zero; an inter frame reads the one the frame before it left, and
carries its intra frame's header, every field from h to cf (geometry_mismatch). A
decode the capability's decoder cannot complete is refused payload_malformed, and a pin
that does not resolve with SPEC §3.1's code. The decode runs floating point: its frames
reproduce on one build and not across hardware (NeuralFloat, SPEC §7), so these strings
never back intent = replicate. The chain of §2 still holds every frame to its
predecessor: two sinks may present different pixels, never different frames.
5. What a sink checks
A sink holds, for each frame stream it decodes, its reference: the last frame it
decoded, its content hash, its index and its pin, and the decoder state the frame left. It
checks each object it receives, in this order, and refuses it at the first rule that fails:
- The envelope reads (SPEC §2):
envelope_malformed. - Its capability is the stream's:
frame_capability_mismatch. - It carries
frame, an object:frame_link_missing. frame'sindexis an integer from 0 to 2^53 − 1, itsprevisnullor 64 lowercase hexadecimal digits, itsnumber, where present, is an integer from 0 to 2^53 − 1, and itscapture_ms, where present, is an integer from 1 to 2^53 − 1:frame_link_malformed.- The payload parses alone: integer-payloads §16 for
WIF1, §17.1 forWCF1, §4 forWNF1, each with its code. frameagrees with the payload's kind: an intra frame hasindex0 andprevnull, an inter frame anindexof 1 or more and aprev:frame_link_mismatch.
An intra frame then drops the reference, is decoded (SPEC §3.1's pin checks, then the decode's codes), and becomes the reference. An inter frame is checked against the reference first:
- The sink holds a reference:
frame_no_reference. - Its
previs the reference's content hash:frame_gapwhen itsindexis past the one after the reference's (frames are missing),frame_prev_mismatchotherwise. - Its
indexis the reference's plus 1:frame_index_mismatch. Itsnumberis the reference's plus 1 where the reference carries one, and absent where the reference carries none:frame_number_mismatch. - Its
conditioning.prioris the reference's, compared as JSON values (both absent counts as the same):frame_prior_changed. - It is decoded against the reference: for
WIF1, itsh × wis its group's (geometry_mismatch), then the decode's codes; forWCF1, its header,htocf, is its group's (geometry_mismatch), then the decode's codes (integer-payloads §17.4); forWNF1, its header is its group's (geometry_mismatch), then the decode's.
It then becomes the reference. After any refusal the sink holds no reference: every
inter frame it receives is refused (frame_no_reference) until an intra frame opens a group.
So a sink never decodes an inter frame against a reference that is not its predecessor's
decode: a lost frame, a frame delivered twice or out of order, and an altered prev are
each refused at the first frame they would corrupt, and the stream resumes at the next
group. A sink that joins a stream joins at an intra frame.
| code | when |
|---|---|
envelope_malformed |
the object is not a WAI1 envelope that reads |
frame_capability_mismatch |
the object's capability is not the stream's |
frame_link_missing |
no frame member, or one that is not an object |
frame_link_malformed |
an index or prev outside its type or range |
frame_link_mismatch |
an intra frame with a prev or an index other than 0, or an inter frame with no prev or index 0 |
frame_no_reference |
an inter frame while the sink holds no reference |
frame_gap |
an inter frame whose predecessor is not the reference, with frames missing between |
frame_prev_mismatch |
an inter frame whose prev is not the reference's content hash |
frame_index_mismatch |
an inter frame that names the reference but whose index is not the next |
frame_number_mismatch |
an inter frame whose number is not the one after the reference's, or that carries one where the reference carries none, or none where it carries one |
frame_prior_changed |
an inter frame whose pin is not its group's |
A payload's refusals are integer-payloads §8's codes; a pin's are SPEC §3.1's.
6. Splitting a clip
WIV1. A WIV1 clip is one group of WIF1 frames, frame for frame. Frame 0 is the
intra frame: the clip's table, q and offset, and, with keyframe 0, frame 0's residual
symbols; with keyframe 1, the clip's nested WIH1. Each frame f ≥ 1 is an inter frame:
frame f's motion vectors, the clip's mv_precision and block, and frame f's residual
symbols. Each frame's symbols are the ones the clip's residual stream decodes to for that
frame, coded into a stream of their own by the rANS coder integer-payloads §2 decodes (its
state starting at 2^31, so each stream ends canonically). The group decodes, frame by
frame, to the clip's frames, byte for byte (§3). The split refuses a clip whose residual
stream does not decode: stream_exhausted, stream_noncanonical, and the parse's codes.
A stream of several groups is the split of several clips, one after another.
The reference neural payload. The reference decoder of wai.neural.dcvc_rt and
wai.neural.dcvc_fm reads a whole clip as: h, w, n_frames, fps_milli (u32),
cy, cz (u16), sy_log2, sz_log2 (u8), q, cf (u16), 26 bytes; then
n_frames pairs of u32 lengths (lz, ly); then each frame's hyper-latent and latent
bitstreams, in order. Its split is one group of WNF1 frames, each with the clip's header
and its own two bitstreams, copied; frame 0 intra, every other inter. The split reads the
clip strictly: its header as WNF1's checks read it, at least one frame (field_range),
every bitstream inside it (stream_length) and nothing after the last (trailing). The
join is its inverse: one group of WNF1 frames, the first intra and the others inter
(field_range), each with the first's header (geometry_mismatch), back to the clip. The
split and the join give each other's input back, byte for byte, and the decode of the
frames is the decode of the clip: the reference decoder's whole-clip decode runs the same
step a frame (neural/video_dcvc.rs, Temporal::step).
7. Carriage
A frame stream rides any carrier that delivers its objects in order; this extension
defines no transport. Each object keeps every rule of the carrier for a WAI1 object, and
its receipt is an object receipt like any other (jwp-receipts).
- MoQ. One track carries one frame stream, its catalog entry declaring it
(
wai_frame_stream, moq-streaming-format §4.3). Each MOQT group of the track is one group of the stream, and the object of Object ID k in it is the frame ofindexk. A subscriber joins at a group's first object (MOQT §3.5). A frame a relay drops is refused as a gap at the frame after it, never decoded past; the group's receipts still account for it (moq-streaming-format §5). A frame stream of a neural frame capability maps to and from a track of packagingnvc(§9). - HTTP and files. A sequence of envelopes, in order: a playlist's objects (http-delivery), or a file of envelopes one after another.
A frame object is complete when its frame is coded, so a live sender publishes each frame as it is made, and a sink presents it when it is decoded.
8. Reference implementation and conformance
wai-rs(featurevideo_int):frame_stream::FrameStreamholds a stream's reference and makes §5's checks in order, decoding through aFrameCodec:IntFrames, the decoder of the integer frame forms (int_video::decode_unit_typed, the clip decode's frame step, and, for a keyframe,int_payload::decode_keyframethrough the capability's set as its pin resolves it); andParseOnly, which parses each frame and checks its geometry against its group's intra frame without decoding.frame_stream::split_wiv1,split_dcvcandjoin_dcvcare §6's;frame_stream::envelopeandwrap_groupwrite frame objects;frame_stream::catalogreadswai_frame_streamand checks an object against it;container::check_int_payload_framingparsesWIF1,WCF1andWNF1on every emit path.int_cond_video::CondFramesdecodeswai.video.int_cond.frame, keeping the reference feature from frame to frame (integer-payloads §17.5); its corpus isint-payload-conformance/int-cond/.neural::DcvcFrames(featuresneuralandvideo_int) decodes the neural frame forms through the reference decoder'sTemporal::step.int-payload-conformance/frame-stream/, written bywai_int_payload_vectors genand checked bywai_int_payload_vectors verify: the committedWIV1clipsint_video,video_real(half-pel) andvideo_nk(a learned keyframe, pinned) split into frame objects, each frame decoding to its clip's frame byte for byte; two clips as one stream of two groups; a stream with each of §5's faults planted;WIF1andWNF1payloads each changed in one place; a synthetic neural clip, its split, its join and their refusals; and catalog entries with objects checked against them. The neural clip's bitstreams are generated bytes, not an encode: the corpus holds its framing and its chain, and no decode, which needs the sink-supplied networks.int_payload_verify.py, which shares no code with wai-rs, checks the same corpus from this text: it splits each clip again with its own rANS coder and requires the committed payloads, decodes every keyframe-0 frame and requires each frame's SHA-256, makes §5's checks over every stream with its own BLAKE3, and checks every payload, split, join and catalog case. It does not decode aWIH1keyframe; those streams it checks to §5 and the frames' parse, and wai-rs checks their decode.
9. NMSF tracks
draft-herz-moq-nmsf-01 (NMSF) packages the frames of a neural inter-frame codec for the
MOQT Streaming Format as packaging nvc: one frame an object, a group of pictures a MOQT
group that opens with a neural keyframe (NMSF §3.5), the model's weights installed on both
sides and named, not sent (NMSF §8). A frame stream of wai.neural.dcvc_rt.frame or
wai.neural.dcvc_fm.frame carries the same bitstreams, so a publisher maps one to the
other: an NMSF frame becomes one WNF1 frame object (a rewrap, §9.4), and a frame object
becomes one NMSF object, or two (an unwrap, §9.5). Neither changes a bitstream; an
unwrap of a rewrap gives the NMSF objects back byte for byte; and a relay forwards both
tracks as it forwards any track. A section number of NMSF here is one of that revision's;
where a later revision renumbers or changes what this section cites, this section is what
changes.
9.1 What maps
An NMSF object is a 26-byte header and a payload (NMSF §3.2). This section reads the header
from the field definitions, which give each field's size and sum to the 26 bytes the section
states; the figure before them draws pts_ms one byte short. Every field is big-endian:
| off | size | field |
|---|---|---|
| 0 | 1 | frame_type: 0x00 Intra, 0x01 Inter, 0x02 to 0xFF reserved (NMSF §3.3) |
| 1 | 1 | qp: 0 to 63; 64 to 255 reserved |
| 2 | 4 | frame_number |
| 6 | 8 | pts_ms |
| 14 | 4 | width |
| 18 | 4 | height |
| 22 | 4 | payload_len |
| 26 | payload_len |
the payload |
The payload is components (NMSF §3.6), each channels, height, width and
data_len (u32, big-endian) and then data_len bytes of an entropy-coded tensor. In
single-track mode an object's payload is the hyperprior's component and then the latent's;
in two-track mode the hyperprior track's object holds the hyperprior's component and the
latent track's object the latent's, the two objects of a frame with the same header (NMSF
§3.4). A frame object holds the same frame as:
| NMSF | frame object | where it has no form |
|---|---|---|
codec dcvc-rt, dcvc-fm (NMSF §5) |
the capability wai.neural.dcvc_rt.frame, wai.neural.dcvc_fm.frame; conditioning.kind dcvc_rt, dcvc_fm |
any other codec: nmsf_codec_unmapped. dcvc-dc is SPEC §5's candidate wai.neural.dcvc_dc, which pins no bitstream and has no frame form; ssf, fvc, rlvc and elfvc WAI does not register |
| a MOQT group: an Intra frame, then Inter frames | a group of the stream (§2); the object of Object ID k is the frame of index k (moq-streaming-format §4.3) |
|
frame_type Intra, Inter |
WNF1 kind 0 (index 0, prev null), 1 (index 1 or more, prev the frame before) |
a reserved type: nmsf_reserved |
qp |
WNF1 q |
a reserved qp: nmsf_reserved; a q past 63 (§9.5): nmsf_value_unmappable |
frame_number |
frame.number (§2) |
a frame with no number, or one past 2^32 − 1 (§9.5): nmsf_value_unmappable |
pts_ms; 0 where it states none |
frame.capture_ms (§2); absent where it states none |
a pts_ms past 2^53 − 1: nmsf_value_unmappable |
width, height |
WNF1 w, h |
|
| the hyperprior's component | WNF1 cz, sz_log2 (the side is 2^sz_log2) and the hyper-latent bitstream |
a tensor that is not square, whose side is not a power of two at most 2^15, or of channels outside 1 to 65 535 (§4): nmsf_shape_unmappable |
| the latent's component | WNF1 cy, sy_log2 and the latent bitstream |
as the hyperprior's |
the catalog's framerate |
WNF1 fps_milli |
a framerate that is not a whole number of thousandths (§9.2), or a frame of another fps_milli (§9.5): nmsf_value_unmappable |
| — | WNF1 cf, the reference feature's channels, from the model binding (§9.3) |
|
codec and nvc.modelVersion, the model by name |
conditioning.prior and wai_priors, its parameter set by SHA-256 (SPEC §3.1), through the model binding |
9.2 The catalog member wai_nmsf
A WAI track whose frames map to an NMSF track keeps that track's catalog entries in the
member wai_nmsf: an array of one entry (single-track mode) or two (two-track mode, a
hyperprior and a latent track, NMSF §3.1), each a JSON object as NMSF §3.7 and §3.8 state
it, in the order given. The frame objects do not carry colorspace, gopSize, priority,
nvcRole, depends or the nvc object, and wai_nmsf keeps them, so the entries an unwrap
publishes are the entries the rewrap read, member for member. A rewrap publishes the entry:
{ "name": "video/wai", "packaging": "wai", "isLive": true, "role": "video",
"width": 64, "height": 64, "framerate": 30,
"wai_capabilities": ["wai.neural.dcvc_rt.frame"],
"wai_frame_stream": { "capability": "wai.neural.dcvc_rt.frame" },
"wai_priors": [ { "capability": "wai.neural.dcvc_rt.frame",
"sha256": "<64 lowercase hexadecimal digits>",
"form": "wai.prior.set", "tier": "none" } ],
"wai_nmsf": [ { "name": "video", "packaging": "nvc", "isLive": true, "codec": "dcvc-rt",
"width": 64, "height": 64, "framerate": 30, "colorspace": "ycbcr-bt709",
"gopSize": 4, "nvc": { "modelVersion": "cvpr2025" } } ] }
Its name is the publisher's; isLive, width, height and framerate are the first NMSF
entry's; it declares the frame stream (moq-streaming-format §4.3); wai_priors (§4.2) lists
the binding's pin, with its form and tier where the pin states them, and is absent where
the binding has no pin; wai_nmsf holds the NMSF entries.
Reading NMSF entries. A publisher reads them, in this order, and refuses the track at the first rule that fails:
- Each entry is an object with
name(a non-empty string),packaging"nvc",isLive(a boolean),codecandcolorspace(strings),width,heightandgopSize(integers of at least 1) andframerate(a number above 0);priority, where present, a number;nvcRoleanddepends, where present, strings; andnvc, where present, an object whosemodelVersion, where present, is a string. There is one entry, with nonvcRole, or two: one ofnvcRole"hyperprior"and one of"latent", whosedependsis the hyperprior entry'sname, the two names different. Otherwisenmsf_catalog_malformed. - Two entries agree on
codec,isLive,width,height,framerate(as numbers),colorspace,gopSizeandnvc.modelVersion(both absent counts as the same):nmsf_track_mismatch. - The codec has a frame capability (§9.1):
nmsf_codec_unmapped. fps_milliis the integer m nearestframerate× 1000, from 1 to 2^32 − 1, where m ÷ 1000 isframeratein binary64 arithmetic: 29.97 is 29 970, and 30 000 ÷ 1 001 has none (nmsf_value_unmappable).
Reading a WAI entry. An unwrap reads the entry's frame stream (moq-streaming-format
§4.3, catalog_frame_stream_malformed; a track that declares none has no NMSF form,
nmsf_no_form); its wai_nmsf (absent or null: nmsf_no_form; not an array:
nmsf_catalog_malformed), whose entries read as above and whose codec's frame capability is
the declared one (nmsf_catalog_malformed); and the pin wai_priors lists for that
capability: each of its entries an object, and one for the capability with a sha256 of 64
lowercase hexadecimal digits and a form that is absent, null or a string
(nmsf_catalog_malformed). It lists none, and the frames carry no pin; or one, and they
carry it; or several, and the track has no NMSF form, which names one model
(nmsf_no_form). A publisher that unwraps a frame stream it wrote itself states its NMSF
entries in wai_nmsf: the colorspace and GOP size its frames do not carry are its to state.
9.3 The model binding
NMSF names a model by codec and nvc.modelVersion and leaves the distribution of its
weights to the deployment (NMSF §8). A frame object names its parameter set by SHA-256 in its
pin, which a sink checks before it decodes (SPEC §3.1). A model binding is the
publisher's statement of the set a name stands for, and of what WNF1 needs of the model
that an NMSF object does not carry:
{ "codec": "dcvc-rt", "modelVersion": "cvpr2025", "cf": 64,
"prior": { "id": "dcvc-rt/cvpr2025", "sha256": "<64 lowercase hexadecimal digits>",
"determinism": "float", "form": "wai.prior.set", "tier": "none" } }
| member | presence | meaning |
|---|---|---|
codec |
REQUIRED, string | the NMSF codec identifier |
modelVersion |
string, null or absent |
the nvc.modelVersion it binds; null or absent binds a track that names none |
cf |
REQUIRED, integer, 1 to 65 535 | the channels of the model's reference feature, WNF1's cf (§4) |
prior |
a pin (SPEC §3.1), null or absent |
the parameter set every frame object carries as its pin; null or absent, the frames carry none |
A binding that does not read so is nmsf_binding_malformed. A rewrap maps a track through
the first binding whose codec and modelVersion are the track's: none is
nmsf_model_unbound. The neural frame forms are NeuralFloat, so a binding's pin claims no
tier above none (SPEC §3.1). A binding is the publisher's configuration and is not carried:
in the catalog a rewrap publishes, its name is in wai_nmsf and its pin in wai_priors, so an
unwrap reads both from there.
9.4 Rewrap: NMSF to frame objects
A publisher maps an NMSF track's frames in the order it receives them: each frame one object,
or in two-track mode the hyperprior track's object and the latent track's object of the
frame (NMSF §4.2), with the MOQT Object ID where the carrier gives one. It holds the
group it is mapping: its last frame's index, frame_number, WNF1 header and frame
object's content hash. It checks each frame in this order, and refuses it at the first rule
that fails:
- The frame is one object in single-track mode and two in two-track mode:
nmsf_track_mismatch. - Each object, in order, is at least 26 bytes and its
payload_lenis the length of the bytes after its header (nmsf_object_malformed), and itsframe_typeandqpare not reserved (nmsf_reserved). - The two objects of a frame have the same header,
payload_lenaside:nmsf_track_mismatch. - Components fill each payload: two in single-track mode, one in each object in two-track
mode:
nmsf_object_malformed. - An Intra frame drops the group, and is at Object ID 0 where it has one. An Inter frame
follows a group, its
frame_numberthe group's last plus 1 and its Object ID, where it has one, the group's lastindexplus 1. Otherwisenmsf_group_order. - Its
pts_msis at most 2^53 − 1:nmsf_value_unmappable. - Each component has a
WNF1form (§9.1), and theWNF1header the frame gives passes §4's checks:nmsf_shape_unmappable. - An Inter frame's
WNF1header is its group's, so itsqp,width,heightand tensor shapes are its Intra frame's:nmsf_group_header_changed.
It then writes the frame object: a WAI1 envelope of the codec's frame capability, media
video, intent perceptual, conditioning.kind the codec's (§9.1) and conditioning.prior
the binding's pin, with no fallback (§2). Its payload is the WNF1 frame of kind
frame_type, h height, w width, fps_milli the track's (§9.2), cy, cz,
sy_log2 and sz_log2 the components', q qp, cf the binding's, and the components'
data as its two bitstreams. Its frame is index, prev, number frame_number and
capture_ms pts_ms, absent where pts_ms is 0. The frame object becomes the group's
last.
After any refusal the publisher holds no group: it refuses every Inter frame
(nmsf_group_order) until an Intra frame opens one. A lost or damaged NMSF object therefore
yields no frame object for any frame its loss would have changed. A single-track frame and the
two objects of the same frame in two-track mode give the same frame object, which a sink
admits as any frame (§5).
9.5 Unwrap: frame objects to NMSF
A publisher whose WAI entry reads (§9.2) maps each frame object in order, and refuses it at the first rule that fails:
- It is admitted as a sink admits a frame (§5), its payload parsed and held to its group's
header as
ParseOnlyholds it: §5's codes and §4's. - An intra frame's pin is the one the entry lists: the same
sha256andform, or no pin where the entry lists none:nmsf_model_unbound. §5 holds each inter frame's pin to its group's. - Its
frame.numberis present and at most 2^32 − 1:nmsf_value_unmappable. - Its
WNF1qis at most 63 and itsfps_milliis the track's:nmsf_value_unmappable.
It then writes the NMSF object, or the two: the header frame_type kind, qp q,
frame_number number, pts_ms capture_ms (0 where absent), width w, height h;
the hyperprior's component (cz channels, a side of 2^sz_log2 both ways, the hyper-latent
bitstream) and the latent's (cy, 2^sy_log2, the latent bitstream). In single-track mode
one object holds both components; in two-track mode the hyperprior track's object holds the
first and the latent track's object the second, the same header on both. The frame's cf is
not carried. After any refusal the publisher holds no reference (§5), and refuses every
inter frame until an intra frame opens a group.
9.6 What each side carries, and the codes
A frame object carries what an NMSF object does not:
- the link to the frame before it (§2): a sink refuses a lost, reordered or altered frame at the first frame it would change, and resumes at the next group (§5);
- a receipt per object (jwp-receipts), which covers the frame with its
numberandcapture_ms; - the parameter set by SHA-256 (SPEC §3.1), which a sink checks against the set it holds;
- a catalog from which a sink chooses, before it subscribes, a track it can decode: a frame stream, or beside it a track of a floor or recommended video capability (SPEC §5) for a sink that holds no networks;
- the integer frame forms (§3), whose frames reproduce on every machine; NMSF registers no
codec for them, so a frame stream of
wai.video.int_motion.frameorwai.video.int_hyper.framehas no NMSF form.
An NMSF track carries what a frame stream does not:
- two-track delivery, the hyperprior on a track of its own at a priority of its own (NMSF §3.1, §3.8). A frame object holds both bitstreams; an unwrap to two-track mode gives the NMSF subscriber both tracks;
colorspace,gopSize,priorityand thenvcobject, whichwai_nmsfkeeps (§9.2);- a
qpthat changes inside a group, whichWNF1holds once a group (nmsf_group_header_changed); tensors of any shape, whereWNF1holds square tensors whose side is a power of two, as the reference decoder takes them (§4,nmsf_shape_unmappable); and frame rates that are not whole thousandths (nmsf_value_unmappable).
| code | when |
|---|---|
nmsf_catalog_malformed |
an NMSF entry, or wai_nmsf or wai_priors in a WAI entry, does not read (§9.2) |
nmsf_track_mismatch |
two NMSF entries disagree (§9.2), or the two objects of a frame are not two, or differ in their headers (§9.4) |
nmsf_codec_unmapped |
an NMSF codec with no frame capability |
nmsf_model_unbound |
no model binding for the track's codec and model version (§9.3), or an intra frame whose pin is not the one the WAI entry lists (§9.5) |
nmsf_binding_malformed |
a model binding that does not read (§9.3) |
nmsf_object_malformed |
an object shorter than its header, whose payload_len is not its payload's length, or whose payload is not its components (§9.4) |
nmsf_reserved |
a reserved frame_type or qp |
nmsf_group_order |
an Intra frame past Object ID 0, an Inter frame with no group, or not the next frame_number or Object ID |
nmsf_value_unmappable |
a pts_ms, framerate, number, q or fps_milli the other side cannot state |
nmsf_shape_unmappable |
a tensor or frame WNF1 cannot state (§9.1) |
nmsf_group_header_changed |
an Inter frame whose qp, size or tensor shapes are not its group's |
nmsf_no_form |
a WAI track with no frame stream, no wai_nmsf, or several pins |
9.7 Reference implementation and conformance
wai-rs(featurevideo_int):frame_stream::nmsf—parse_object,write_object,parse_componentsandwrite_component(§9.1);read_nmsf,Track::bind,Track::wai_entryandread_wai(§9.2);Binding(§9.3);Rewrap(§9.4) andUnwrap(§9.5), which runsFrameStreamoverParseOnly.frame_stream::Stampreadsnumberandcapture_ms(§2), andFrameStreammakes §5's checks of them.int-payload-conformance/frame-stream/nmsf/, written bywai_int_payload_vectors genand checked bywai_int_payload_vectors verify: a 64 × 64 stream of two groups as NMSF objects in single-track and two-track mode and the frame objects each maps to, the same frame objects for both modes; NMSF objects changed in one place each, for every rule of §9.4; NMSF entries and WAI entries for every rule of §9.2; model bindings that do not read; frame objects an unwrap refuses, among them the reference neural stream of §8, whose frames carry nonumber; and streams whosenumberorcapture_msa sink refuses (§5). The objects' bitstreams are generated bytes, not an encode: the corpus holds the framing and the mapping, and no decode. Every stream's frame objects unwrap back to its NMSF objects byte for byte, and every code of §9.6 is given by a case.int_payload_verify.py, which shares no code with wai-rs, checks the same corpus from this text: it reads every NMSF object and entry with its own parser, maps every stream and requires each committed frame object's payload and manifest, admits the frame objects with its own §5 checks and BLAKE3, unwraps them and requires the NMSF objects byte for byte, and checks every catalog, binding, unwrap and links case.