ImgIng's in-browser video compressor added H.265 export recently, and from the outside it splits into two paths. When the machine has a hardware HEVC encoder, the browser does the work and the job is done in seconds. When it doesn't and the source is already H.265, the page loads x265 compiled to WebAssembly and encodes inside the tab. I spent three years on codec SDKs before I moved to browser tooling, and people still ask me what a fallback like that costs as if it were one number. I measured this one on 2026-10-19 with no view of its code, and it turned out to be two bills that behave very differently: a download of about 25 MB that you pay once, and an encode that is about six times slower on every run.
I used the live build of ImgIng (https://imging.ai/) through its Chinese-language site, on a single Apple M4 machine running macOS 26.5 and Chromium 149. I don't own a machine without an HEVC encoder, so I made one by turning off hardware video encoding in Chromium. That simulates the condition. It is not a real low-end laptop. The source was a 60-second 1080p30 screen recording I generated frame by frame and converted to H.265 Main, 20,645,740 bytes, stiller and cleaner than a real recording. Preset "HD balanced", output MP4 H.265, one run per configuration.
The switch between the two paths lines up with what the browser reports. With hardware encoding on, VideoEncoder.isConfigSupported returned true for HEVC Main under all three hardwareAcceleration values. With it off, all three returned false, and the capability panel changed from native hardware to local WASM. In the normal build prefer-software also said true, but at about 6 seconds for 30 frames I wouldn't count that as a usable middle path, and the page doesn't seem to either.
The 25 MB download happens once
Nothing is fetched when the page opens. About 2.0 seconds after I pressed Start, the page requested ffmpeg-core.wasm, 25,357,446 bytes on the wire, which took about 5.1 seconds on that day's connection. An earlier HEAD request had reported 25,328,759 bytes, and I still haven't tracked down the 28 KB gap. A few small scripts came along, tens of KB in total, one of them an OPFS file-system shim. The glue script was requested 33 times and the worker script 32 times, every one after the first a cache hit with 0 bytes. My reading is that the multi-threaded build (directory core-lto-mt) starts workers that each load their own copy. After the run, two console lines showed what stayed behind:
await caches.keys(); // ['imging-x264-high10-0.12.10-imging-2-mt-lto1']
(await navigator.storage.estimate()).usage; // 31334742
A second run on the same page made no wasm request, and neither did a third after a reload. The cache is named after x264 High 10, which matches the panel's note that the core is shared with that export, so whichever path runs first should pay the download for both. About 31 MB of site storage stays on the user's disk until it's cleared. Those download and storage figures are decimal, 1 MB = 1,000,000 bytes. The MB values in the table below are what the interface shows, where 1 MB = 1024×1024 bytes. A private window should fetch it again each time, which I didn't check.
The encode is where the time goes
| Run | Time | Output | VMAF |
|---|---|---|---|
| Hardware HEVC | 8.5 s | 6,299,368 bytes (6.01 MB) | 98.32 |
| WASM x265, first run | 55.5 s | 6,005,135 bytes (5.73 MB) | 97.97 |
| WASM x265, same page again | 53.8 s | 5.73 MB | not scored |
| WASM x265, after a reload | 76.9 s | 5.73 MB | not scored |
The first WASM row is from my earlier session. In the session that produced the next two rows, the first run took 56.5 seconds. The download accounted for about 5 of those 56.5 seconds. With nothing left to fetch, the second run still needed 53.8 seconds, roughly 6.3 times the hardware path. The cache buys back only those first few seconds. The run after a reload was about 20 seconds slower than the other two, and I don't know why yet. It's a single run, so I'm leaving it there. VMAF is libvmaf with outputs scaled back to 1080p. The WASM file came out 4.7% smaller and 0.35 points lower, which on this clip I'd call a draw.
Why only H.265 sources fall back
The panel's note for this path says x265 runs locally so the output keeps the source's codec, bit depth, resolution, frame rate and colour curves. Its job is keeping an H.265 file H.265. With hardware encoding off and an H.264 source, H.265 output shows as unavailable on this device and the tool points you to MP4 with H.264 or to WebM. With the hardware encoder, H.265 saved 19 to 30% over H.264 at the same preset on my two test clips. Spending 25 MB and six times the encode time to get that, for a file that still needs an H.264 copy for players without HEVC, is a poor trade. If it were my call, I'd draw the line in the same place. I didn't test 10-bit or HDR sources, and those are exactly the files the panel note says this path keeps intact.
If you're building a fallback like this, time the first download and the per-run encode separately, because only one of them goes away. Check caches.keys() after a run to see what stays on the user's disk. Two things are still open on my side: the 20-second slowdown after a reload, and how a real machine without an HEVC encoder behaves, as opposed to this one where I switched it off.
Top comments (0)