Skip to content

Build1 publisher2 min readPublished

ClearPix cuts an in-browser video job from 95 seconds to 9 by replacing ffmpeg.wasm with WebCodecs

ClearPix rebuilt its browser watermark remover on WebCodecs hardware codecs and MediaBunny muxing, cutting one job from 95 seconds to 9. The result comes from one job on the team's own Macs, and it holds only where the browser can reach a hardware H.264 encoder.

The Engineer · Build desk

Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction

Illustration accompanying ClearPix cuts an in-browser video job from 95 seconds to 9 by replacing ffmpeg.wasm with WebCodecs
Generated illustration

What happened

  • ClearPix says every ffmpeg.wasm run paid three fixed costs: a 33MB download, file copies through an in-memory filesystem, and software H.264 encoding in WebAssembly.
  • A streaming single-pass design held memory use constant, so the team raised its clip duration limit from 30 seconds to 120.
  • Before choosing WebCodecs, a dispatcher checks that the browser can encode 1080p H.264 at 8 Mbps and 30 fps and decode it at 1080p.
  • ffmpeg.wasm stays in the product as a deliberately feature-frozen fallback that keeps its original behavior and hard limits.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • constraint A regression in the WebCodecs path, the one most ClearPix users run, can pass the automated Playwright suite and surface only in real-Chrome testing.
  • cost Covering machines without hardware H.264 means carrying two video backends; ClearPix limits that cost by freezing one, so those users keep the pre-streaming limits.
  • decision Teams with slow browser media tools should profile downloads, copies and codecs before tuning the model, since ClearPix found the two costs comparable in size.

Per frame, the shipped loop is short. MediaBunny opens the upload as a BlobSource, takes the primary video track and checks canDecode before touching a frame [13]. VideoSampleSink then yields decoded frames as an async iterator [13]. Each sample is drawn to a canvas, closed, and passed to an encode step that snapshots the canvas to JPEG, with at most eight snapshots in flight [14]. The draw call also applies rotation and flip metadata, so phone footage comes out upright with no extra code [15].

I think the sample.close() call and the cap of eight explain most of the flat memory profile. A decoded frame is released as soon as it is drawn. The queue of pending snapshots has the same bound for a short clip as for one at the new 120-second limit [6]. The authors credit the streaming single-pass design [6]. One overhead survived the rewrite. The post lists JPEG round-trips among the costs that replacing ffmpeg.wasm removed [11], yet the loop still encodes every frame to JPEG [14]. What went away is the copy of each frame into and out of ffmpeg.wasm's virtual filesystem [4].

The gain is a factor of about 10.6, or 86 seconds per run [1][2]. It was measured on one job, watermark removal, on the team's Macs, where VideoToolbox handles H.264 encoding in dedicated hardware [5]. Part of the old baseline was a cold start. The post says the 33MB fetch costs "the first several seconds of the session" on a cold cache [3], while WebCodecs initialization downloads nothing and reports ready at once [9]. A returning user with the wasm build already cached would have seen a smaller gap. Workload shape matters too. The authors' rule is that "pipeline overhead and model overhead are the same order of magnitude, and pipeline overhead is usually cheaper to fix" [12]. A tool whose run time is mostly inference would get less from the same migration.

The backend switch is careful work. A ?vbackend=ffmpeg|webcodecs URL parameter or a localStorage key overrides the dispatcher [16]. Forcing webcodecs skips the probe and hard-routes, so a hardware failure throws during testing instead of dropping silently to the fallback [17]. I would ship the same default. Automated coverage is thinner. Playwright's bundled Chromium has no H.264 codec, so the end-to-end suite forces the ffmpeg path [10].

Freezing the fallback is the right call in their context. Streaming it "would cost a week of work on a path almost nobody runs," the post says [18]. That judgement rests on "almost nobody." The post does not give the share of sessions that fail the hardware probe.

What to watch

  • Whether ClearPix publishes the share of sessions that fail the hardware H.264 probe and land on the frozen ffmpeg.wasm fallback.
  • A per-stage timing breakdown of the 95-second baseline separating the 33MB download, MEMFS copies, software encode and model time.
  • Whether Playwright's bundled Chromium gains an H.264 codec, letting the end-to-end suite run against the WebCodecs path.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories