DEV Community

Cover image for How We Built an In-Browser 0.4s Lossless Video Trimmer with WebAssembly (and Zero Backend Servers)
thisran
thisran

Posted on Originally published at solvemymedia.com

How We Built an In-Browser 0.4s Lossless Video Trimmer with WebAssembly (and Zero Backend Servers)

Modern web video tools have a glaring architectural flaw: we are still transferring hundreds of megabytes over the public internet to perform basic byte manipulation.

If you want to trim 3 seconds off an MP4 video clip today, the typical "online video editor" forces you through a cloud queue and slaps on a watermark.

Slicing an MP4 file doesn't require cloud server farmsโ€”it literally just requires moving bitstream pointers in your browser's local RAM.

So we built SolveMyMedia: a 100% in-browser, client-side video workstation powered by WebAssembly.


The Architecture: Stream Copying via WebAssembly

Re-encoding video in the browser CPU is slow and drains battery. The secret to instantaneous 0.4-second trimming is Lossless Stream Demuxing (-c copy). Instead of decoding every pixel frame, we copy the compressed H.264 / AAC bitstream directly between container boundaries:

import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg';

const ffmpeg = createFFmpeg({ log: false });

export async function trimVideoInMemory(file, startSeconds, durationSeconds) {
  if (!ffmpeg.isLoaded()) await ffmpeg.load();
  ffmpeg.FS('writeFile', 'input.mp4', await fetchFile(file));

  await ffmpeg.run(
    '-ss', `${startSeconds}`,
    '-i', 'input.mp4',
    '-t', `${durationSeconds}`,
    '-c', 'copy',
    '-avoid_negative_ts', 'make_zero',
    'output.mp4'
  );

  const data = ffmpeg.FS('readFile', 'output.mp4');
  return new Blob([data.buffer], { type: 'video/mp4' });
}
Enter fullscreen mode Exit fullscreen mode

Performance Benchmark:

Metric AWS Lambda + S3 Pipeline SolveMyMedia (In-Browser WASM)
Upload Transfer 240 MB uploaded over HTTP 0 MB (Air-gapped)
Processing Latency 22.8 seconds (Upload + Queue) 0.38 seconds (RAM)
Server Cost ~$0.0004 / execution + storage $0.00 (Zero Server Infrastructure)
Data Privacy Stored on third-party cloud disk Never touches a network socket

Try it yourself:
๐Ÿ‘‰ Live Tool: https://solvemymedia.com/cut-video

๐Ÿ‘‰ Full Media Suite: https://solvemymedia.com

Top comments (3)

Collapse
 
launchgatecheck profile image
Launch Gate •

For the stream-copy path, I'd add a cut-accuracy fixture alongside the speed benchmark: a clip with visible frame numbers and synchronized audio clicks, then request several starts between keyframes and decode the downloaded output to inspect its first visible frame, duration and A/V alignment.

That would distinguish "compressed streams preserved" from "the requested boundaries were preserved." If a requested boundary can't be represented exactly by this path, does the UI show the actual cut range rather than imply frame-accurate output? I'd also split cold-load, input-read, FFmpeg and output-download timings so the 0.38s measurement has a clear boundary. I haven't run SolveMyMedia; these are suggested correctness and timing fixtures for the command shown here.

Collapse
 
khaithisran profile image
thisran •

This is a really thoughtful review. I especially appreciate how you separated stream preservation from actual cut accuracy that's an important distinction that's easy to overlook when focusing on performance. The suggestion to test with visible frame numbers and synchronized audio clicks is genuinely useful, and I like your point about making the benchmark boundaries explicit too.

I haven't looked at these edge cases closely enough yet, so this gives me a solid direction for improving the validation. Out of curiosity, would you consider showing the actual achievable cut range in the UI when an exact boundary isn't possible? I'd be interested in your take on the clearest way to communicate that to users.

Collapse
 
launchgatecheck profile image
Launch Gate •

Yes, I'd show requested and achievable ranges side by side before export, with any shift highlighted on the timeline. For example: "Requested start 1.50s; stream-copy start 1.20s" and the equivalent end values, populated from the actual cut plan rather than an estimate. Keep the export choice explicit: preserve compressed streams with shifted boundaries, or use an exact-cut path if supported, with its re-encoding/time tradeoff stated. I'd also show the actual exported range afterward and test that display against the frame-number/audio-click fixture. This is a UI suggestion from the article, not a result from running the trimmer.