2026-05-10

Weekly open source: goro's VM lands, OxideAV fills the codec matrix

The thing W18 said was coming — "a VM lands in goro" — landed. libwallet shipped a single fix that had been silently breaking every Bitcoin send. OxideAV widened from "the document stack and a handful of codecs" into something much closer to a full ffmpeg-shaped matrix in pure Rust.

goro: bytecode VM

goro (PHP in Go) had been running on a tree-walking interpreter and an ahead-of-time PHP → Go transpiler. The missing middle was a bytecode VM. This week it landed.

The shape:

  • Compiler + runtime skeleton — lower the AST to bytecode, dispatch through a small VM, GORO_VM gate so the existing interp stays the default while coverage settles.
  • Native ops — literals, variables, binops (routed through compiler.EvalBinop for full PHP semantics), arrays + indexing + append, foreach, ?? null coalesce, object instantiation + property read + method call, throw / try / catch / finally, closure bodies dispatched through the VM with $this binding, native string interpolation, class const / static / ::class access.
  • Wins — slot-array locals (skip the hashtable on reads) → −50% on the Arithmetic micro-bench. Inline closures with indirect calls → −21% on FunctionCalls.

Regression-free against the phpt suite, with diff tests comparing interp vs. VM. The VM is opt-in for now; the default flips later.

libwallet: a double-reversed txid

libwallet v0.4.13 → v0.4.17. The headline fix: wlttx/bitcoin: fix double txid byte-reversal that broke every send. A txid endian had been flipped twice, so every signed Bitcoin transfer referenced inputs that didn't exist on-chain. The kind of bug that only surfaces when you actually try to broadcast.

Also this week:

  • priority field on Bitcoin transfers selects cheap vs. fast fee budget.
  • wlttx/maxSendable pins inputs + fee rate so the "send max" amount survives between estimate and broadcast, and accounts for both m/0 and m/1 derivation chains with per-input vsize.
  • UTXO fetcher collapsed to a single source (modchain_assets) so coin selection and broadcast can't disagree about what's available.
  • Bitcoin broadcast errors now include inputs + raw hex.
  • Dart FFI loads the right native library per platform.

OxideAV: the matrix fills out

W18 covered the document stack — TTF / OTF / SVG / PDF — plus the first lossless and legacy codec sweeps. W19 is the matrix expanding sideways into video, audio, images, hardware, and 3D.

Encoders pushed deep

  • H.266 / VVC (oxideav-h266) — encoder rounds 49 → 56 over the week: chroma SAO RDO + apply, chroma residual emit, joint alf_luma_clip_idx coeff/clip RDO with chroma SAO merge, explicit tu_*_coded_flag CABAC, MTT BT/TT split syntax, per-CU cu_qp_delta, forced QT split for 128×128 CTBs, multi-row CU neighbour tracking.
  • JPEG XL (oxideav-jpegxl) — re-implementing against ISO/IEC 18181-1:2024. All five small lossless fixtures decode pixel-correct; rounds 20 → 28 worked through DC_GROUP boundary recount, ANS-final-state oracle, parent-dispatch IDCT, and Annex L colour transforms (XYB / YCbCr inverse).
  • WebP VP8L (oxideav-webp) — Viterbi-style optimal LZ77 for the lossless path; VP8 intra-frame holds at 100% bit-exact.
  • MagicYUV (oxideav-magicyuv) — clean-room rebuild rounds 1-3, all 17 FOURCCs plus encoder, declared 100% with Auditor sign-off.
  • TTA (oxideav-tta) — clean-room rebuild rounds 1+2, Auditor PASS.

Codec siblings, new this week

VideoH.261, H.263, H.264, H.265, AV1, VP6 / VP8 / VP9, MPEG-1/2 / MPEG-4 / MS-MPEG4, MJPEG, Dirac, Theora, ProRes, AVIF.

AudioAAC, AC-3, AC-4, Opus + CELT, Vorbis, FLAC, MP1 / MP2 / MP3, Speex, GSM, iLBC, G.711 / G.722 / G.723.1 / G.728 / G.729, Ogg container.

ImagePNG, JPEG 2000, OpenEXR, Radiance HDR, BMP, ICO, TGA, PCX, QOI, DDS, Farbfeld, WBMP, Apple PICT, Amiga IFF/ILBM, ICER (NASA Mars rover compression).

Tracker / chipAmiga MOD, ScreamTracker S3M, Nintendo NSF.

Hardware acceleration

A new family of sibling crates wraps OS hardware codec engines behind the same oxideav-core API:

These are the only crates in the project that use OS FFI, and they have to, because the engines they wrap are OS-provided. The workspace README was reframed to make that explicit: "pure Rust" is a preset (pure-rust = all minus hwaccel), not a project-wide claim.

PDF: encryption

oxideav-pdf landed ISO 32000-1 §7.6 encryption decode, including AES-256 revision 5 and revision 6. Password-protected PDFs round-trip.

3D assets

A 3D-mesh stack plumbed through the scene model: mesh3d as the in-memory shape, with STL, OBJ, glTF, and USDZ siblings. The USDZ test path runs through Apple's usdzconvert as an oracle (CI pins Python 3.9 + usd-core 21.11 for compat).

Workspace shape

  • oxideav-format-all renamed to oxideav-meta. Explicit register_all(ctx) instead of linkme, with Cargo features to shape the registered set. The oxideav umbrella was thinned out: every sibling exposes a register(ctx) via an enable!() macro, and the umbrella stops depending on everything.
  • Pure-Rust preset (pure-rust = all minus hwaccel) is now first-class.
  • New CLI surface: oxideav info <codec> prints backend availability; bench measures per-codec throughput against hardware backends; transcode handles multi-stream inputs; list shows the per-codec backend table grouped by media type.
  • oxideav-meta and oxideav-cli-convert each got their first 0.0.x / 0.1 cuts.

Also this week

  • oxideav-vfw — Video for Windows / DirectShow shim, working through IBaseFilter / IFilterGraph / IPin::ReceiveConnection wiring, then auto-discovery.
  • oxideav-image-filter — image filter graph, rounds 7 → 10.

Next week

JPEG XL keeps grinding through the 2024 spec. H.266 continues the encoder loop. The hardware-acceleration crates start sprouting first working backends. goro's VM begins flipping on more PHP semantics.