# Performance and resource observations

ffmpeg.wasm runs native media code compiled to WebAssembly. It is normally much
slower than desktop FFmpeg and may hold source, decoded frames, filters and
output at once. No hardware encoder is used.

## Fixed download footprint

Uncompressed self-hosted core assets for
`0.12.10-reviewed-stack5m.1`:

| Mode          |   JavaScript/worker |         WASM |        Total |
| ------------- | ------------------: | -----------: | -----------: |
| single-thread |           111,804 B | 32,232,580 B | 32,344,384 B |
| multithread   | 128,953 B + 2,115 B | 32,718,455 B | 32,849,523 B |

Only the selected mode is loaded. HTTP compression may reduce JavaScript
transfer but not necessarily WASM to the same degree; report transfer and
decoded sizes separately. Versioned core assets may be cached immutably.

## Benchmark record

One opt-in pinned-core baseline was recorded on 2026-07-24 with Chrome for
Testing 149.0.7827.55 (Playwright 1.61.1), Linux 7.0.0-28 on Ubuntu 24.04,
Intel Core i7-8700 (6 cores/12 threads) and 31 GiB RAM.
`navigator.hardwareConcurrency` reported 12 and every sample was
cross-origin-isolated. Each row used a fresh browser context; the first core
fetch may populate the browser HTTP cache, so later rows are explicitly
potentially warm-cache observations.

Preset: MP4, H.264/libx264 CRF 23 medium, AAC. Times are milliseconds.
“Export end-to-end” spans the Convert click through result construction,
cleanup, verification re-probe and visible result. The three narrower engine
columns come from the export validation report.

| Source                                  | Input bytes | Mode              |  Init | Probe | FFmpeg exec | Output read | Cleanup | Export end-to-end | Output bytes | Observed JS heap |
| --------------------------------------- | ----------: | ----------------- | ----: | ----: | ----------: | ----------: | ------: | ----------------: | -----------: | ---------------: |
| 2 s, 160×90 H.264/AAC synthetic pattern |      34,057 | ST                | 294.4 | 131.4 |       315.6 |         1.0 |     1.2 |             422.4 |       68,700 |     10,000,000 B |
| same                                    |      34,057 | MT (`-threads 2`) | 914.5 | 126.4 |       294.3 |         1.3 |     1.9 |             416.8 |       68,753 |     10,000,000 B |
| 6 s, 640×360 H.264/AAC synthetic loop   |     526,632 | ST                | 270.2 | 163.6 |     6,854.1 |         1.3 |     0.8 |           7,030.9 |      585,981 |     15,200,000 B |
| same                                    |     526,632 | MT (`-threads 2`) | 946.3 | 121.6 |     4,053.1 |         1.6 |     0.5 |           4,497.5 |      585,884 |     11,200,000 B |

Command:

```sh
npm run benchmark:browser
```

Result: **1 passed (18.2 s)**; test body 17.6 s. Chromium exposed
`performance.memory.usedJSHeapSize`, but this coarse post-operation value is
not a peak-WASM-memory measurement. One run is not a statistical distribution;
cold-cache repetitions, median/range, mobile and other-browser measurements
remain release-quality evidence gaps. Never present this workstation as a
universal promise.

## Measurement boundaries

- initialization: wrapper construction through successful capability query;
- probe: input mount/write through parsed ffprobe JSON;
- conversion: accepted command through exit code;
- output read: exit through Blob/result construction;
- cleanup: final result read through job directory unmount/delete;
- cancellation: cancel request through worker termination and recoverable idle
  state (fresh-engine load is a separate measure).

Progress events are experimental estimates and not a timer. Use monotonic
browser timing around lifecycle boundaries.

## Product limits

Default soft input warning is 256 MiB; hard single/total input is 1.5 GiB.
Estimated output warns at 512 MiB and is blocked at 1 GiB. FFmpeg jobs are
serial; the application retains at most eight scheduled operations in its
in-memory queue. Timeline clips are capped at 100, streams per input at 64,
images at 8192×8192/67,108,864 pixels, generated output files at 255,
contact-sheet cells at 500, scene-change results at 100, crossfades at 10
seconds and runtime at four hours. Scene selection is a bounded two-step
workflow but its analysis step can still decode the complete source when few
frames meet the threshold. The documented ffmpeg.wasm input ceiling is 2 GiB,
but real limits can be substantially lower on mobile or memory-constrained
browsers.

Source inspection has a bounded, size-aware watchdog: 30 seconds for small
files, a two-MiB-per-second scan budget for larger files, and a five-minute
ceiling. Recognized local audio/video can begin browser playback from its
temporary object URL while that worker inspection continues; completed probe
metadata remains authoritative for editing and export.

Lowering resolution, duration, frame rate, passes and output count reduces
work. MT can be faster but consumes more memory/CPU and requires isolation; ST
is not inherently a low-memory guarantee.
