Browser streaming contract
The canonical WASM ABI, exact byte-range contract, cancellation generations, and bounded presentation model.
View authoritative sourceThe browser API is incremental and container-aware. Rust/WASM owns Avelune parsing and codec semantics; JavaScript owns byte transport, cancellation, clocks, audio scheduling, and presentation.
Canonical WASM surface
The important operations are conceptually:
avelune_abi_version() -> 0x0002_0000
decoder_create() -> handle
decoder_destroy(handle)
input_reserve(handle, len) -> ptr
decoder_push(handle, len)
decoder_finish_input(handle)
decoder_seek_reset_epoch(handle, epoch_id)
decoder_pop_video(handle)
decoder_pop_audio(handle)
video_encoder_create(width, height, fps_flags, qstep, preset, epoch_frames, meta0) -> handle
video_encoder_create_error_ptr() / video_encoder_create_error_len()
video_encoder_frame_ptr(handle) -> ptr
video_encoder_push_frame(handle)
video_encoder_finish(handle)
video_encoder_output_ptr(handle) / video_encoder_output_len(handle)
The ABI also exposes the Rust-validated front index, stream descriptors, indexed epoch byte ranges, and stream IDs on decoded outputs. JavaScript therefore does not implement Avelune packet framing, CRC, stream routing, or reference-state semantics independently.
decoder_finish_input is required at an indexed-range boundary. Transport EOF by itself does not
prove that a parser ended on a complete packet.
The video encoder surface is intentionally narrower than the decoder. It accepts complete planar 8-bit 4:2:0 frames, uses fixed-duration epochs, and returns a video-only Draft Generation 1 container. The demo’s Y4M encoder lab is a validation/usefulness feature, not a claim that browsers can natively demux arbitrary MP4/WebM inputs. A general upload workflow should only be added with a reliable media-ingest layer; FFmpeg-WASM is not pulled in merely to make the demo appear complete.
Scalar and SIMD128 artifacts
build-wasm.sh produces separate avelune-scalar.wasm and avelune-simd128.wasm modules. The
loader prefers SIMD128 in auto mode and falls back to scalar if the SIMD module cannot be loaded.
This is module selection, not a second codec backend.
Byte sources
The player uses one range-source contract for HTTP and local files.
For HTTP, every media range must:
-
return status
206; -
return a parseable
Content-Rangematching the exact requested first and last byte; -
remain consistent about total source size when supplied;
-
return the expected
Content-Lengthwhen that header is present; -
deliver exactly the indexed byte count, neither shorter nor longer.
Local Blob/File playback uses Blob.slice() in bounded chunks and exercises the same epoch decode
path without uploading the file.
Decode generations and seeking
Starting a load or epoch decode creates a new decoder generation and invalidates the previous one.
This check is intrinsic to the loader, in addition to AbortSignal transport cancellation. A stale
source that ignores cancellation is therefore stopped before its next bytes can enter the reset WASM
decoder.
An epoch transaction is:
-
reset the canonical session for the expected indexed epoch ID;
-
stream arbitrary byte fragments into the decoder;
-
drain decoded outputs with presentation backpressure;
-
explicitly finalize input;
-
accept success only if the parser/session is complete and semantically valid.
Presentation and buffering
Decoded callbacks are awaited, so JavaScript does not need to collect an entire epoch before presentation. WebAudio scheduling is bounded and cancelled on pause/seek/reload. Canvas2D and WebGPU are presentation implementations only; they do not change codec semantics. WebGPU textures and pipelines are reused while dimensions remain unchanged.