# mediaway-decoder — roadmap
**Facade** crate (traits). Platform backends: `mediaway-decoder-windows`, `mediaway-decoder-web`, …
Packaging: [`docs/spec/crate-packaging.md`](../../../docs/spec/crate-packaging.md).
Platform order: **Windows → Web → Linux → other**.
Workspace index: [`docs/roadmap.md`](../../../docs/roadmap.md).
## Stages
### 0 — Scaffold
- [x] Facade crate + `docs/` / `adr/`
- [x] ADR: decoder traits (align with encoder)
- [x] ADR: facade vs `mediaway-decoder-<platform>` boundary
### 1 — Windows
- [x] Add `mediaway-decoder-windows` workspace member
- [x] WMF H.264 decode (HW MFT, DX11 Zero-Copy out)
- [x] HEVC / AV1 / VP9 HW decode open (same DXGI path; MFT may be absent)
- [x] CPU frame output path (`CpuFramesOk`) for Windows H.264
- [x] H.264 CPU round-trip with demuxer + encoder tests
(`crates/mediaway/tests/trim_and_splice_windows.rs`); the test skips
gracefully when the host has no usable WMF encoder/decoder.
### 2 — Web
- [x] Add `mediaway-decoder-web`
- [x] WebCodecs decode + `VideoFrame` / WebGPU interop
- [x] First audio decode surface (`is_webcodecs_audio_decode_supported`,
`decode_audio_chunks -> DecodedAudioData`), codec-parameterized from the start,
exercised via Opus — adr/web/0001; wasm32 compile-verified only, no real-browser
verification in this environment; `AudioData` planar/interleaved readback shape
unverified against real Chrome
### 3 — Linux
- [x] `linux::vaapi` module: VA-API H.264 CPU-output decode, IDR-only —
see [adr/linux/0001](../adr/linux/0001-vaapi-h264-cpu-out.md)
- [x] `linux::vaapi` P-slice decode: single-forward-reference P-slices,
sliding-window DPB ported from `vulkan/dpb.rs` — implemented,
compile+test-verified on real WSL2 Linux (`libva-dev`); **zero
real-hardware verification** (no VA-API device available this
session); see [adr/linux/0002](../adr/linux/0002-vaapi-h264-p-slice-dpb.md)
- [x] `linux::vaapi` HEVC decode: HEVC Main profile IDR I-slices +
single-forward-reference P-slices, **fresh** single-slot `HevcDpb`
(no hardware-verified porting source existed — Vulkan's own HEVC
decode is IDR-only) — implemented, compile+test-verified on real
WSL2 Linux (`libva-dev`); **zero real-hardware verification**; CRA/
random-access pictures a permanent scope cut; `VaapiVideoDecoder`
enum unifies H.264/HEVC/AV1/VP9 dispatch (no `Box<dyn>`); see
[adr/linux/0003](../adr/linux/0003-vaapi-hevc-p-slice-dpb.md)
- [x] `linux::vaapi` AV1 `KEY_FRAME`-only decode: single tile, Main profile, spec-derived OBU/
sequence-header/frame-header parser (no AV1 decode precedent existed anywhere in this
workspace to port from) — implemented, compile+clippy+test-verified on real WSL2 Linux;
**zero real-hardware verification** (no VA-API device available this session); see
[adr/linux/0005](../adr/linux/0005-vaapi-av1-key-frame-decode.md)
- [x] `linux::vaapi` VP9 `KEY_FRAME` + general single-tile `INTER_FRAME` decode (compound
prediction included, no artificial reference-count restriction — a real structural finding
that VP9's entropy adaptation is driver-internal and its reference model needs only a
two-field-per-slot shadow table, not AV1's twelve-field one — a genuinely broader
real-world-stream-compatible scope than this crate's own AV1 sibling reached): spec-derived
`uncompressed_header()` parser copied verbatim from the real primary VP9 spec text
(`pdftotext`-extracted this session), persistent 8-logical-slot reference shadow table
(`vp9::ref_table`, `POOL_SIZE = 9` physical surfaces, pigeonhole-guaranteed free-index
allocation) — implemented, compile+clippy+test-verified on real WSL2 Linux (100+ new
sans-io bitstream-parser unit tests); **zero real-hardware verification** (no VA-API device
available this session); see
[adr/linux/0004](../adr/linux/0004-vaapi-vp9-key-frame-and-inter-decode.md)
- [x] `vulkan` module (portable, not OS-suffixed — see
[adr/vulkan/0001](../adr/vulkan/0001-vulkan-video-decode.md)): H.264
general-GOP decode **hardware-verified** (RTX 4090); HEVC IDR decode
**hardware-verified**; HEVC P/B still deferred; AV1 `KEY_FRAME`-only,
single-tile decode **hardware-verified** (RTX 4090, first attempt, no
driver-maturity wall — unlike this workspace's AV1 Vulkan *encode*
path) per
[adr/vulkan/0002](../adr/vulkan/0002-av1-decode-keyframe-first.md);
general-GOP AV1 (`INTER_FRAME`, multi-tile, film grain) still deferred
### 4 — Other
- [x] `android` module: NDK `AMediaCodec` H.264 CPU NV12 decode, general GOP —
zero compile/runtime verification (no NDK/device in dev env); see
[adr/android/0001](../adr/android/0001-ndk-amediacodec-h264-cpu-out.md)
- [x] `apple` module: `VTDecompressionSession` H.264/HEVC/VP9/AV1 general-GOP CPU-output **and
Zero-Copy** decode (`src/apple/`, H.264/HEVC one VPS(HEVC)/SPS/PPS + 4-byte length size;
VP9/AV1 require a container-supplied `vpcC`/`av1C` config record at `open()`, no bitstream
parsing) — compiles/lints on this Windows host (the real `objc2-*`-calling code in
`videotoolbox/{video,format_desc}.rs` is `cfg`-gated to Apple targets; pure `codec.rs`
tick/NV12/validation helpers are host-testable and covered by real unit tests, 22 total),
**zero compile verification of the Apple-only code path itself** (no Apple SDK in this dev
environment) — **wired into `mediaway::platform`'s `AutoDecoder`/`decoder_support`**;
Zero-Copy output (`GpuBufferHandle::Metal`) needs no DPB/slot-recycling bookkeeping unlike
this crate's VA-API/Vulkan Zero-Copy backends — `CVPixelBufferPool` grows on demand rather
than reusing a fixed slot, so the decoder just holds the last-returned handle's
`CFRetained` and releases it on the next call; see
[adr/apple/0001](../adr/apple/0001-videotoolbox-h264-cpu-out.md),
[adr/apple/0002](../adr/apple/0002-videotoolbox-hevc-vp9-av1-decode.md), and
[adr/apple/0003](../adr/apple/0003-videotoolbox-metal-zero-copy-decode.md)