open-standards/wai/wai-web/demo/verify_platform_decode.mjs
Transaction Science 4c1f640588 platform-decode: keep the query, move the order into browser-sink's routing, drop the budget
The review of #452 (M4–M9) found its platform-decode part at odds with
browser-sink on main. Reworked inside EN-C:

- Kept: the query read from the payload (AV1-ISOBMFF codec string from the
  sequence header, Annex E.3 from an HEVC SPS) with queries.json; the rule that
  powerEfficient and prefer-hardware are hints, never energy and never evidence
  of hardware.
- Reworked: the answers enter browser-sink §3's report, one shape
  (report_answer): supported from isConfigSupported() alone, smooth and
  power_efficient from decodingInfo() only once WebCodecs said supported, so a
  Media Capabilities supported:false overrides nothing (http-delivery §12.2).
  The extension defines no order and no second meaning of advertising: the order
  is SPEC §4's energy order inside browser-sink §4.7, where an answer counts only
  for an object routed ua (AV1's user-agent tier is none; a decode-equivalence
  need with no probe run routes elsewhere).
- Dropped: rank/order/select, advertise_for_envelope (a second advertising
  definition that could make a decodable WAI1 inert), the EnergyBudget and its
  ceiling, and order.json. A learned entry's measurement is browser-sink §6's
  energy entry.
- wai-web: the platform bundle binds platformQuery, platformAnswer and
  platformChoose (browser-sink §4.7) on the browser_sink feature; the demo builds
  every query from a payload (the hand-written 1920x1080 query is gone), asks
  Media Capabilities after WebCodecs, and marks its one figure synthetic. The
  wording calls the HEVC source the platform's encoder configured with
  prefer-hardware. wai-web-wasm.yml builds the bundle.
- int_kernels_vectors: the two new corpora's sidecar exclusions (review M1).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
(cherry picked from commit ce38948dad)
2026-10-26 08:31:14 -04:00

121 lines
6.6 KiB
JavaScript

// Platform decode capabilities and browser-sink §4.7's choice, in a browser
// (extensions/platform-decode.md, extensions/browser-sink.md).
//
// Build the page's bundle first, from wai/wai-web:
//
// cargo build --release --target wasm32-unknown-unknown --features platform_decode
// wasm-bindgen --target web --out-dir demo/pkg-platform --out-name wai_platform_decode \
// target/wasm32-unknown-unknown/release/wai_web.wasm
//
// then, with Playwright installed under PLAYWRIGHT_HOST:
//
// [WAI_PLATFORM_BROWSER_CHANNEL=chrome] PLAYWRIGHT_HOST=<dir with node_modules/playwright>/ \
// node wai/wai-web/demo/verify_platform_decode.mjs
//
// It serves wai-web/demo and wai/pack-conformance on 127.0.0.1, lists the AV1 floor
// objects of the packaging corpus (WAI1 envelopes of wai.video.av1) as objects.json,
// opens platform_decode.html in a headless browser and prints the page's report. It fails
// on a page error, on an AV1 object that does not decode every temporal unit through
// WebCodecs with the configuration the reference's query gives, on an HEVC stream the
// platform's encoder wrote that does not decode back with the derived configuration, and
// on a choice that is not the one the ranks give: the learned alternative without a figure
// last and AV1 chosen; with the synthetic figure, the learned alternative ranked classical
// and the first in the order chosen.
import http from "node:http";
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { createRequire } from "node:module";
const HERE = path.dirname(fileURLToPath(import.meta.url));
const PACKS = path.resolve(HERE, "../../pack-conformance");
const PORT = Number(process.env.PORT || 8798);
const { chromium } = createRequire(process.env.PLAYWRIGHT_HOST || HERE + "/")("playwright");
/// The AV1 floor objects: WAI1 envelopes ("WAI1", a u32 manifest length, the manifest)
/// whose manifest's capability is wai.video.av1.
function av1Objects() {
const out = [];
const packs = path.join(PACKS, "packs");
for (const p of fs.readdirSync(packs).sort()) {
const dir = path.join(packs, p, "package", "objects");
if (!fs.existsSync(dir)) continue;
for (const f of fs.readdirSync(dir).sort()) {
const b = fs.readFileSync(path.join(dir, f));
if (b.length < 8 || b.toString("latin1", 0, 4) !== "WAI1") continue;
const m = JSON.parse(b.toString("utf8", 8, 8 + b.readUInt32LE(4)));
if (m.model_requirement && m.model_requirement.capability === "wai.video.av1") out.push(`/pack-conformance/packs/${p}/package/objects/${f}`);
}
}
return out;
}
const objects = av1Objects();
const ROOTS = { "/pack-conformance/": PACKS, "/demo/": HERE };
const MIME = { ".js": "text/javascript", ".wasm": "application/wasm", ".html": "text/html", ".json": "application/json" };
const server = http.createServer((req, res) => {
const url = decodeURIComponent(req.url.split("?")[0]);
if (url === "/demo/objects.json") {
res.writeHead(200, { "content-type": "application/json" });
return res.end(JSON.stringify(objects));
}
const prefix = Object.keys(ROOTS).find((p) => url.startsWith(p));
const root = prefix && ROOTS[prefix];
const f = root && path.resolve(root, "." + url.slice(prefix.length - 1));
if (!f || !f.startsWith(root + path.sep) || !fs.existsSync(f) || !fs.statSync(f).isFile()) {
res.writeHead(404);
return res.end("not found");
}
res.writeHead(200, { "content-type": MIME[path.extname(f)] || "application/octet-stream" });
fs.createReadStream(f).pipe(res);
});
let browser;
try {
if (!fs.existsSync(path.join(HERE, "pkg-platform", "wai_platform_decode.js"))) {
console.error("no pkg-platform/wai_platform_decode.js; build it as this file's header says");
process.exit(2);
}
if (objects.length === 0) {
console.error("no AV1 floor object found under pack-conformance/packs");
process.exit(2);
}
await new Promise((r) => server.listen(PORT, "127.0.0.1", r));
const channel = process.env.WAI_PLATFORM_BROWSER_CHANNEL || undefined;
browser = await chromium.launch({ channel, args: process.platform === "darwin" ? ["--use-angle=metal"] : [] });
console.log(`browser: ${channel || "chromium"} ${browser.version()}`);
const page = await browser.newPage();
const errs = [];
page.on("pageerror", (e) => errs.push(String(e)));
await page.goto(`http://127.0.0.1:${PORT}/demo/platform_decode.html`, { waitUntil: "domcontentloaded", timeout: 30000 });
await page.waitForFunction(() => window.platformDecode && window.platformDecode.done === true, null, { timeout: 5 * 60 * 1000, polling: 500 });
const report = await page.evaluate(() => window.platformDecode.report);
console.log(report);
for (const e of errs) console.log(`page error: ${e}`);
const lines = report.split("\n");
const fail = [];
if (errs.length || /page error/.test(report)) fail.push("a page error");
const objs = lines.filter((l) => l.startsWith("platform av1 object:"));
if (objs.length !== objects.length) fail.push(`${objs.length} AV1 objects reported, ${objects.length} served`);
for (const l of objs) {
const m = / decoded=(\d+)\/(\d+) /.exec(l);
if (!m || m[1] !== m[2] || / error=/.test(l)) fail.push(`not every unit decoded: ${l}`);
}
const hevc = lines.find((l) => l.startsWith("platform hevc encoder:"));
if (!hevc) fail.push("no HEVC line");
else if (!/not supported/.test(hevc)) {
const m = / decoded=(\d+)\/(\d+)/.exec(hevc);
if (!m || m[1] !== m[2] || / error=/.test(hevc) || !/ no-preference=true /.test(hevc)) fail.push(`the derived HEVC configuration did not decode the stream back: ${hevc}`);
}
const parse = (l) => { const m = / order=(\[.*?\]) ranks=(\[.*?\]) chosen=(\S+)$/.exec(l || ""); return m && { order: JSON.parse(m[1]), ranks: JSON.parse(m[2]), chosen: m[3] }; };
const plain = parse(lines.find((l) => l.startsWith("platform choose: ")));
if (!plain || plain.order[1] !== "int_hyper" || plain.ranks[1] !== "learned-without-budget" || plain.chosen !== "av1") fail.push(`without a figure the learned alternative was not last, or AV1 was not chosen: ${JSON.stringify(plain)}`);
const fig = parse(lines.find((l) => l.startsWith("platform choose with a synthetic figure:")));
const learnedAt = fig ? fig.order.indexOf("int_hyper") : -1;
if (!fig || learnedAt < 0 || fig.ranks[learnedAt] !== "classical" || fig.chosen !== fig.order[0]) fail.push(`with the synthetic figure the learned alternative was not ranked classical, or the first in the order was not chosen: ${JSON.stringify(fig)}`);
for (const f of fail) console.log(`FAIL ${f}`);
if (fail.length) process.exitCode = 1;
} finally {
if (browser) await browser.close();
server.close();
}