Performance Review: ffmpeg-wasi¶
This document outlines the performance characteristics and concerns of the ffmpeg-wasi implementation compared to native FFmpeg execution.
1. Single-Threaded Execution¶
WASM via wazero runs purely single-threaded. Standard FFmpeg relies heavily on multi-threading to achieve real-time or faster-than-real-time transcoding:
- Slice/Frame-Level Decoding: Modern video codecs (H.264, HEVC) divide frames into slices or use frame-level parallelism to decode on multiple cores.
- Encoding: Encoders like libx264 utilize multiple threads for lookahead, motion estimation, and entropy coding.
- Impact: This implementation will be bounded to a single host CPU core per wazero instance, resulting in significantly slower transcode times, especially for high-resolution video.
2. Lack of SIMD Optimization¶
Native FFmpeg gets a massive performance boost from CPU-specific SIMD instructions (SSE, AVX2, AVX-512 on x86; NEON on ARM). While WASM has a SIMD proposal (128-bit), its adoption and the successful compilation of FFmpeg's hand-written assembly routines into WASM SIMD are historically problematic.
- Impact: Software decoders and encoders will run using scalar instructions. Tasks like color space conversion (swscale) and motion estimation will be drastically slower than native equivalents.
3. WASM/Go Memory Boundary (VFS Bridge)¶
The project uses an in-memory VFS (afero bridged to WASI).
- Every packet read from the input file and every packet written to the output file must cross the WASM memory boundary.
- Wazero's sysfs bridge needs to copy data between the Go host memory and the WASM guest memory.
- Impact: For high-bitrate video, the sheer volume of memory copying (Go -> WASM -> Go) per frame will introduce substantial I/O overhead compared to native FFmpeg reading directly from a memory-mapped file or OS page cache.
4. Forced Decode/Encode Pipeline¶
The current process.c implementation forces all inputs through a decode -> filtergraph -> encode pipeline.
- There is no support for stream copying (equivalent to FFmpeg's -c copy).
- Impact: Even if a user only wants to remux a file (e.g., MKV to MP4) or extract an audio track without re-encoding, ffmpeg-wasi will fully decode and re-encode the streams, burning CPU cycles unnecessarily and potentially degrading quality.
5. Round-Robin Processing Loop¶
The main loop in process.c reads one frame from each input sequentially.
- Impact: While sufficient for simple muxing, this tight, unbuffered loop may introduce latency bottlenecks if one input requires significantly more processing time to demux than another, stalling the entire pipeline.