open-standards/wai/tools/wai_carriage_demo.sh
Transaction Science fb103ac5ae wai: one registry table, candidate capabilities, public-text checks
Every registered string now lives in one table (codecs/registry.rs) with
its kind, status, media class, registering SPEC section, edition and
registration date. `wai registry export` writes registry/capabilities.json,
its JSON Schema, the generated table in REGISTRY.md and vocab v2; --check
fails on drift. vocab v1 stays stable.

A candidate capability (a registered string whose payload format no
revision has pinned) must not be emitted. The C packers, the browser
writers and `wai wrap` refuse one, and `codecs::is_dispatchable` is the
single dispatch and selection predicate (SPEC §4): candidates,
companion-only capabilities, records and derivations are not
dispatchable, and an unregistered string is decoded only where the sink
advertises it.

The codec glossary is linked to the registry through a reviewed table and
held to its schema by a library test; `org` becomes `body`, from a closed
allowlist. The SPEC gains §5 sections on kinds and candidates, a §8
edition rule, corrected citations and rewritten appendices. The
quantum-ops vectors are regenerated with neutral device ids.

CI declares the feature-gated test targets with required-features, checks
the registry export, builds wai-web for wasm32, and runs two public-text
checks (comparative prose, and private name patterns) with a self-test.
The specification, extensions, research notes, READMEs, glossary and
source comments are rewritten to name no company or product and to make
no comparisons.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-30 22:38:09 -04:00

298 lines
17 KiB
Shell
Executable file

#!/usr/bin/env bash
# Demonstrate WAI carrying the registered media classes end-to-end on REAL
# bytes. WAI's job is carriage + dispatch; the decoder is sink-supplied. So for
# each class this:
# 1. obtains REAL canonical bytes of the format (where an open encoder is
# installed) or a representative payload otherwise,
# 2. `wai wrap`s them into an envelope and `wai unwrap`s them back,
# 3. asserts the payload is BYTE-IDENTICAL (the §2 carriage guarantee),
# 4. hands the extracted bytes to a sink decoder (OpenJPEG / ffmpeg) where one
# is installed — the full carry → dispatch → decode path on a real file.
#
# Honest status per row:
# real+decode = real canonical bytes, carried byte-exact, decoded by a real
# reference tool acting as the sink (JPEG 2000, IAMF, and the
# AVC / HEVC / VP9 / AAC broadcast rows via ffmpeg).
# companion = a companion-only capability (SPEC §5: HDR dynamic metadata,
# LCEVC) carried the one conforming way, as a WAI2 companion
# bound to a base rendition: the companion comes back
# byte-exact, the envelope passes the role check, `wai wrap`
# refuses the WAI1 form, and a real base decodes.
# real+parse = real canonical bytes (a genuine encoder built the bitstream),
# carried byte-exact, structurally decoded into the format's
# units by a real reference parser as the sink (V-PCC → V3C).
# real = real canonical bytes carried byte-exact (sink decoder not
# installed here; payload is genuine).
# carriage = representative payload carried byte-exact; decoder
# sink-supplied (no open encoder installed for the format).
# proprietary = carried byte-exact; decoder is proprietary (sink-supplied).
# candidate = a registered capability with no pinned payload format (SPEC §5); `wai wrap` must refuse it and write nothing.
#
# ./tools/wai_carriage_demo.sh
#
# The volumetric / immersive-audio rows decode for real only when their sink
# tools are on PATH (G-PCC tmc3, V-PCC tmc2 + TMC2_CFG, IVAS_cod/IVAS_dec).
# `tools/build_reference_decoders.sh` fetches and builds them at pinned
# versions and prints the exact PATH/TMC2_CFG to export here. Rows fall back to
# byte-exact carriage when a tool is absent.
set -uo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
WAI="$ROOT/wai-rs/target/release/wai"
TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT
echo "building wai CLI…"
( cd "$ROOT/wai-rs" && cargo build --release --features codecs --bin wai >/dev/null 2>&1 ) \
|| { echo "build failed"; exit 1; }
have() { command -v "$1" >/dev/null 2>&1; }
src_png="$TMP/src.png"
# a small real image (any source) — fall back to a generated gradient
if have sips && [ -f "/System/Library/Desktop Pictures/Sonoma.heic" ]; then
sips -s format png -Z 128 "/System/Library/Desktop Pictures/Sonoma.heic" --out "$src_png" >/dev/null 2>&1
fi
[ -f "$src_png" ] || ffmpeg -hide_banner -loglevel error -y -f lavfi -i "testsrc=size=128x128:duration=1" -frames:v 1 "$src_png" 2>/dev/null
printf '\n%-22s %-7s %-13s %s\n' "capability" "fidelity" "status" "round-trip"
printf '%-22s %-7s %-13s %s\n' "----------------------" "-------" "-------------" "----------"
# $1 capability $2 payload-file $3 status-label $4 decode-cmd (optional; runs on the unwrapped payload)
demo() {
local cap="$1" pay="$2" status="$3" decode="${4:-}"
local env="$TMP/e.wai" out="$TMP/p.out"
local tier; tier="$("$WAI" capabilities 2>/dev/null | awk -v c="$cap" '$1==c{print $2}')"
"$WAI" wrap "$cap" "$pay" -o "$env" >/dev/null 2>&1
"$WAI" unwrap "$env" -o "$out" >/dev/null 2>&1
local rt="✗ MISMATCH"
if cmp -s "$pay" "$out"; then rt="✓ byte-exact"; fi
if [ -n "$decode" ]; then
if eval "$decode" >/dev/null 2>&1; then rt="$rt → decoded"; else rt="$rt → decode FAILED"; fi
fi
printf '%-22s %-7s %-13s %s\n' "$cap" "${tier:-?}" "$status" "$rt"
}
rep() { head -c "${2:-512}" /dev/urandom > "$1"; } # representative payload
# ---- cinema: JPEG 2000 (real, decoded by OpenJPEG) ----
if have opj_compress && have opj_decompress; then
opj_compress -i "$src_png" -o "$TMP/c.j2k" >/dev/null 2>&1
demo wai.image.jp2 "$TMP/c.j2k" "real+decode" "opj_decompress -i $TMP/p.out -o $TMP/c_dec.png"
else
rep "$TMP/c.j2k" 4096; demo wai.image.jp2 "$TMP/c.j2k" "carriage"
fi
# ---- immersive audio: IAMF (real, demuxed by ffmpeg) ----
if have ffmpeg; then
ffmpeg -hide_banner -loglevel error -y -f lavfi -i "sine=frequency=440:duration=1,aformat=channel_layouts=stereo" \
-c:a libopus -stream_group "type=iamf_audio_element:id=1:st=0,layer=ch_layout=stereo" \
-stream_group "type=iamf_mix_presentation:id=2:stg=0,submix=parameter_id=100|parameter_rate=48000|element=stg=0:headphones_rendering_mode=stereo" \
-map 0 -f iamf "$TMP/a.iamf" >/dev/null 2>&1
if [ -s "$TMP/a.iamf" ]; then
demo wai.audio.iamf "$TMP/a.iamf" "real+decode" "ffmpeg -hide_banner -loglevel error -y -i $TMP/p.out -f f32le $TMP/a.pcm"
else rep "$TMP/a.iamf" 2048; demo wai.audio.iamf "$TMP/a.iamf" "carriage"; fi
else rep "$TMP/a.iamf" 2048; demo wai.audio.iamf "$TMP/a.iamf" "carriage"; fi
# ---- the rest: representative payloads, decoder sink-supplied / proprietary ----
rep "$TMP/v.j2k" 4096; demo wai.video.j2k "$TMP/v.j2k" "carriage"
rep "$TMP/ac4" 2048; demo wai.audio.ac4 "$TMP/ac4" "proprietary"
# ---- immersive voice/audio: 3GPP IVAS (real, decoded by IVAS_dec) ----
# IVAS_cod / IVAS_dec = the 3GPP TS 26.258 reference (build from
# forge.3gpp.org/rep/ivas-codec-pc/ivas-codec). Encode real stereo PCM and
# decode it back — a full PCM -> bitstream -> PCM round-trip via the sink.
if have IVAS_cod && have IVAS_dec && have ffmpeg; then
ffmpeg -hide_banner -loglevel error -y -f lavfi -i "sine=frequency=440:duration=1" \
-f lavfi -i "sine=frequency=660:duration=1" \
-filter_complex "[0:a][1:a]join=inputs=2:channel_layout=stereo[a]" -map "[a]" \
-ar 48000 -f s16le -acodec pcm_s16le "$TMP/ivas_in.pcm" >/dev/null 2>&1
IVAS_cod -stereo 48000 48 "$TMP/ivas_in.pcm" "$TMP/ivas" >/dev/null 2>&1
if [ -s "$TMP/ivas" ]; then
demo wai.audio.ivas "$TMP/ivas" "real+decode" "IVAS_dec STEREO 48 $TMP/p.out $TMP/ivas_dec.pcm"
else rep "$TMP/ivas" 2048; demo wai.audio.ivas "$TMP/ivas" "carriage"; fi
else rep "$TMP/ivas" 2048; demo wai.audio.ivas "$TMP/ivas" "carriage"; fi
# ---- 3D geometry: Draco (real, decoded by draco_decoder) ----
if have draco_encoder && have draco_decoder; then
python3 - "$TMP/sphere.obj" <<'PY'
import math, sys
S=16; verts=[]; faces=[]
for i in range(S+1):
lat=math.pi*(-0.5+i/S)
for j in range(S):
lon=2*math.pi*j/S
verts.append((math.cos(lat)*math.cos(lon), math.sin(lat), math.cos(lat)*math.sin(lon)))
for i in range(S):
for j in range(S):
a=i*S+j+1;b=i*S+(j+1)%S+1;c=(i+1)*S+j+1;d=(i+1)*S+(j+1)%S+1
faces+=[(a,c,b),(b,c,d)]
open(sys.argv[1],'w').write(''.join(f'v {x:.5f} {y:.5f} {z:.5f}\n' for x,y,z in verts)
+''.join(f'f {a} {b} {c}\n' for a,b,c in faces))
PY
draco_encoder -i "$TMP/sphere.obj" -o "$TMP/drc" >/dev/null 2>&1
demo wai.mesh.draco "$TMP/drc" "real+decode" "draco_decoder -i $TMP/p.out -o $TMP/m_dec.obj"
else rep "$TMP/drc" 4096; demo wai.mesh.draco "$TMP/drc" "carriage"; fi
# ---- point cloud: MPEG G-PCC (real, decoded by tmc3 if built/on PATH) ----
# tmc3 = the MPEG G-PCC reference (build from github.com/MPEGGroup/mpeg-pcc-tmc13).
if have tmc3; then
python3 - "$TMP/cloud.ply" <<'PY'
import math, random, sys
random.seed(0); pts=[]
for _ in range(2000):
u,v=random.random(),random.random(); th=2*math.pi*u; ph=math.acos(2*v-1)
pts.append((int(200*math.sin(ph)*math.cos(th))+256,
int(200*math.sin(ph)*math.sin(th))+256, int(200*math.cos(ph))+256))
f=open(sys.argv[1],'w')
f.write('ply\nformat ascii 1.0\nelement vertex %d\nproperty float x\nproperty float y\nproperty float z\nend_header\n'%len(pts))
[f.write(f'{x} {y} {z}\n') for x,y,z in pts]
PY
tmc3 --mode=0 --uncompressedDataPath="$TMP/cloud.ply" --compressedStreamPath="$TMP/gpcc" --positionQuantizationScale=1 >/dev/null 2>&1
demo wai.pc.gpcc "$TMP/gpcc" "real+decode" "tmc3 --mode=1 --compressedStreamPath=$TMP/p.out --reconstructedDataPath=$TMP/pc_dec.ply"
else rep "$TMP/gpcc" 4096; demo wai.pc.gpcc "$TMP/gpcc" "carriage"; fi
# ---- point cloud: MPEG V-PCC (real encode + structural V3C decode if tmc2 built) ----
# tmc2 = the MPEG V-PCC reference (build from github.com/MPEGGroup/mpeg-pcc-tmc2,
# bundles its HM video codec). Set TMC2_CFG to the reference cfg/ directory.
# Encode is geometry-only (--noAttributes) so the RGB→YUV color pipeline (which
# needs HDRTools) is not required; the bitstream is still a conformant V3C stream.
if have PccAppEncoder && have PccAppParser && [ -n "${TMC2_CFG:-}" ] && [ -d "${TMC2_CFG:-}" ]; then
python3 - "$TMP/vpcc_f0000.ply" <<'PY'
import math, random, sys
random.seed(1); pts=[]
for _ in range(4000):
u,v=random.random(),random.random(); th=2*math.pi*u; ph=math.acos(2*v-1); r=128
x=int(r*math.sin(ph)*math.cos(th))+256; y=int(r*math.sin(ph)*math.sin(th))+256; z=int(r*math.cos(ph))+256
pts.append((x,y,z,(x*7)%256,(y*5)%256,(z*3)%256))
f=open(sys.argv[1],'w')
f.write('ply\nformat ascii 1.0\nelement vertex %d\nproperty float x\nproperty float y\nproperty float z\nproperty uchar red\nproperty uchar green\nproperty uchar blue\nend_header\n'%len(pts))
[f.write('%d %d %d %d %d %d\n'%p) for p in pts]
PY
PccAppEncoder --configurationFolder="$TMC2_CFG/" \
--uncompressedDataPath="$TMP/vpcc_f%04d.ply" --compressedStreamPath="$TMP/vpcc" \
--frameCount=1 --startFrameNumber=0 --resolution=1023 --noAttributes=1 --absoluteD1=1 --absoluteT1=1 \
--geometryConfig=hm/ctc-hm-geometry-ai.cfg --attributeConfig=hm/ctc-hm-attribute-ai.cfg \
--occupancyMapConfig=hm/ctc-hm-occupancy-map-ai-main.cfg \
--videoEncoderOccupancyPath="$(command -v PccAppVideoEncoder)" \
--videoEncoderGeometryPath="$(command -v PccAppVideoEncoder)" \
--videoEncoderAttributePath="$(command -v PccAppVideoEncoder)" >/dev/null 2>&1
if [ -s "$TMP/vpcc" ]; then
# sink = PccAppParser: structurally decode the carried payload into V3C units.
# Parse to a file then grep — a `... | grep -q` pipe SIGPIPEs the parser early
# (its dump is large), which trips `set -o pipefail` into a false failure.
demo wai.pc.vpcc "$TMP/vpcc" "real+parse" "PccAppParser $TMP/p.out >$TMP/v3c.txt 2>&1; grep -q V3C_VPS $TMP/v3c.txt"
else rep "$TMP/vpcc" 4096; demo wai.pc.vpcc "$TMP/vpcc" "carriage"; fi
else rep "$TMP/vpcc" 4096; demo wai.pc.vpcc "$TMP/vpcc" "carriage"; fi
rep "$TMP/sog" 4096; rm -f "$TMP/sog.wai"
if "$WAI" wrap wai.splat.sog "$TMP/sog" -o "$TMP/sog.wai" >/dev/null 2>&1 || [ -e "$TMP/sog.wai" ]; then sog_rt="✗ wrap ACCEPTED a candidate"; else sog_rt="✓ refused, nothing written"; fi
printf '%-22s %-7s %-13s %s\n' "wai.splat.sog" "$("$WAI" capabilities 2>/dev/null | awk '$1=="wai.splat.sog"{print $2}')" "candidate" "$sog_rt"
echo '{"version":1,"avatars":[]}' > "$TMP/h.hjif"
demo wai.haptic.mihs "$TMP/h.hjif" "carriage"
# ---- broadcast and streaming codecs ----
# Where ffmpeg has an encoder, build the REAL payload in the framing SPEC §5 pins
# (Annex B byte stream / IVF / ADTS) and decode the carried bytes with the
# matching raw demuxer FORCED (-f h264 / hevc / ivf / aac), so the row shows a
# real decoder consumes exactly the pinned framing. The others carry a
# representative payload; their decoders are sink-supplied.
# The decode must yield every encoded frame, not merely exit 0: 10 video frames,
# and for AAC the frame count of the encoded ADTS stream, counted independently
# of the decoder by walking its frame headers.
# Encoder list captured once: `ffmpeg -encoders | grep -q` would SIGPIPE ffmpeg
# and trip `set -o pipefail` into a false "no encoder".
ENCODERS=""; have ffmpeg && ENCODERS="$(ffmpeg -hide_banner -encoders 2>/dev/null)"
has_enc() { grep -q " $1 " <<<"$ENCODERS"; }
# $1 capability $2 encoder $3 muxer (the pinned framing) $4 extension
bcast_video() {
local cap="$1" enc="$2" fmt="$3" ext="$4"
if has_enc "$enc"; then
ffmpeg -hide_banner -loglevel error -y -f lavfi -i "testsrc=size=128x96:rate=10:duration=1" \
-c:v "$enc" -pix_fmt yuv420p -f "$fmt" "$TMP/b.$ext" >/dev/null 2>&1
if [ -s "$TMP/b.$ext" ]; then
demo "$cap" "$TMP/b.$ext" "real+decode" \
"ffmpeg -hide_banner -loglevel error -y -f $fmt -i $TMP/p.out -f framemd5 $TMP/d.md5 && [ \$(grep -vc '^#' $TMP/d.md5) -eq 10 ]"
return
fi
fi
rep "$TMP/b.$ext" 4096; demo "$cap" "$TMP/b.$ext" "carriage"
}
bcast_video wai.video.avc libx264 h264 h264
bcast_video wai.video.hevc libx265 hevc hevc
bcast_video wai.video.vp9 libvpx-vp9 ivf ivf
# Count the ADTS frames of a stream by walking each header's frame_length.
# Prints nothing unless the walk lands exactly on the end of the file.
adts_frames() {
python3 - "$1" <<'ADTS'
import sys
b = open(sys.argv[1], 'rb').read(); i = n = 0
while i + 7 <= len(b) and b[i] == 0xFF and (b[i+1] & 0xF6) == 0xF0:
fl = ((b[i+3] & 3) << 11) | (b[i+4] << 3) | (b[i+5] >> 5)
if fl < 7 or i + fl > len(b): break
i += fl; n += 1
print(n if n > 0 and i == len(b) else "")
ADTS
}
if has_enc aac; then
ffmpeg -hide_banner -loglevel error -y -f lavfi -i "sine=frequency=440:duration=1" \
-c:a aac -f adts "$TMP/b.aac" >/dev/null 2>&1
fi
if [ -s "$TMP/b.aac" ]; then
AAC_FRAMES="$(adts_frames "$TMP/b.aac")"
demo wai.audio.aac "$TMP/b.aac" "real+decode" \
"[ -n '$AAC_FRAMES' ] && ffmpeg -hide_banner -loglevel error -y -f aac -i $TMP/p.out -f framemd5 $TMP/d.md5 && [ \$(grep -vc '^#' $TMP/d.md5) -eq '$AAC_FRAMES' ]"
else rep "$TMP/b.aac" 2048; demo wai.audio.aac "$TMP/b.aac" "carriage"; fi
for cap in wai.video.av2 wai.video.vvc wai.video.evc wai.video.evc.baseline \
wai.video.avs3 wai.audio.mpegh wai.audio.avs3; do
rep "$TMP/b.bin" 4096; demo "$cap" "$TMP/b.bin" "carriage"
done
# ---- companion-only capabilities: HDR dynamic metadata, LCEVC (SPEC §5) ----
# Their payload means nothing without its base, so the only conforming carriage
# is a WAI2 companion bound to a base rendition. Each row wraps base + companion,
# requires the role check to pass, unwraps the companion byte-exact, requires
# `wai wrap` to refuse the WAI1 form, and (for a real base) decodes the base —
# the picture a sink without the companion's decoder presents. The base is a
# real AVC Annex B stream when libx264 is installed. The companion payloads are
# representative: no open encoder for them is installed here.
BASE_CAP=wai.video.avc; BASE="$TMP/base.h264"; BASE_REAL=""
if has_enc libx264; then
ffmpeg -hide_banner -loglevel error -y -f lavfi -i "testsrc=size=128x96:rate=10:duration=1" \
-c:v libx264 -pix_fmt yuv420p -f h264 "$BASE" >/dev/null 2>&1
[ -s "$BASE" ] && BASE_REAL=1
fi
[ -n "$BASE_REAL" ] || rep "$BASE" 4096
# $1 companion capability $2 companion payload [$3 a second payload of the
# same capability, which must be refused when stacked on the same base]
demo_companion() {
local cap="$1" pay="$2" env="$TMP/c.wai" out="$TMP/c.out" ins
local tier; tier="$("$WAI" capabilities 2>/dev/null | awk -v c="$cap" '$1==c{print $2}')"
rm -f "$env" "$out"
"$WAI" wrap "$BASE_CAP" "$BASE" -o "$env" --companion "$cap" "$pay" >/dev/null 2>&1
"$WAI" unwrap "$env" --component 1 -o "$out" >/dev/null 2>&1
local rt="✗ MISMATCH"
if cmp -s "$pay" "$out"; then rt="✓ byte-exact"; fi
# capture first: `wai inspect | grep -q` would SIGPIPE wai under pipefail
ins="$("$WAI" inspect "$env" 2>/dev/null)"
if grep -q 'component roles: *✓' <<<"$ins"; then rt="$rt · roles ✓"; else rt="$rt · roles ✗"; fi
if "$WAI" wrap "$cap" "$pay" -o "$TMP/refused.wai" >/dev/null 2>&1; then
rt="$rt · WAI1 ✗ ACCEPTED"; else rt="$rt · WAI1 refused"; fi
if [ -n "${3:-}" ]; then
if "$WAI" wrap "$BASE_CAP" "$BASE" -o "$TMP/stacked.wai" --companion "$cap" "$pay" \
--companion "$cap" "$3" >/dev/null 2>&1; then
rt="$rt · 2 on 1 base ✗ ACCEPTED"; else rt="$rt · 2 on 1 base refused"; fi
fi
if [ -n "$BASE_REAL" ]; then
rm -f "$TMP/base.out" "$TMP/base.md5"
"$WAI" unwrap "$env" -o "$TMP/base.out" >/dev/null 2>&1
if ffmpeg -hide_banner -loglevel error -y -f h264 -i "$TMP/base.out" -f framemd5 "$TMP/base.md5" >/dev/null 2>&1 \
&& [ "$(grep -vc '^#' "$TMP/base.md5")" -eq 10 ]; then
rt="$rt → base decoded"; else rt="$rt → base decode FAILED"; fi
fi
printf '%-22s %-7s %-13s %s\n' "$cap" "${tier:-?}" "companion" "$rt"
}
rep "$TMP/hdr" 256; demo_companion wai.meta.hdr10plus "$TMP/hdr"
rep "$TMP/dovi" 256; demo_companion wai.meta.dovi "$TMP/dovi"
rep "$TMP/lcevc" 1024; rep "$TMP/lcevc2" 1024
demo_companion wai.video.lcevc "$TMP/lcevc" "$TMP/lcevc2"
echo
echo "carriage is byte-exact for every class (§2). 'real+decode' rows ran a real"
echo "reference decoder (OpenJPEG / ffmpeg) on the unwrapped payload — the full"
echo "carry → dispatch → decode path. The rest carry identically; their decoders"
echo "are sink-supplied (open) or proprietary, by WAI's design."