How FFmpeg Works — Explained with a Diagram (Beginner Friendly)
Most people's first encounter with ffmpeg is a line like this:
ffmpeg -i input.mp4 output.mkv
And they think: "wow, one command turned mp4 into mkv."
But the biggest lesson from building tools.beer is this: ffmpeg is not a "format converter" — it's a multimedia factory pipeline. Once you see that pipeline, the re-encode vs stream copy puzzle ("why is stream copy fast and re-encode slow?") explains itself — because they travel completely different stretches of that line.
1. The one-line definition
FFmpeg is an open-source multimedia framework. The ffmpeg command is just an "operator console": you give it an input, tell it the output you want, and it assembles a pipeline out of its parts to process the material into a finished file.
The parts that actually do the work are these libraries:
- libavformat: unboxing and reboxing (demux / mux);
- libavcodec: decoding and encoding (compressing and decompressing video/audio);
- libavfilter: processing (crop, volume, watermark, etc.);
- libswscale / libswresample: image scaling and audio resampling.
You don't need to memorize the library names. Just remember: ffmpeg chains five steps into one line; raw material goes in one end, finished file comes out the other.
2. The analogy: a multimedia factory pipeline
Picture one conversion as a factory processing a batch of goods:
- Demux = unbox: receive a shipping box (the container file), open it, and sort the video packets and audio packets.
- Decode = decompress: expand the compressed video/audio back into "raw material" (uncompressed frames, raw audio samples).
- Filter = process (optional): modify the raw material — crop black bars, adjust volume, add a watermark, scale resolution.
- Encode = compress: re-compress the processed raw material into small data streams with the target codec.
- Mux = rebox: package the new video and audio streams into the target container, index them, and produce a playable file.
3. The five stages, one by one
- Demux: read the container and split the interleaved video, audio, and subtitle packets. Like opening a box and sorting clothes, books, and snacks into piles.
- Decode: expand each compressed stream back to raw form — video into frames, audio into samples. CPU-intensive.
- Filter (optional): process the raw material —
-vf "crop=..."to cut black bars,-af "volume=2"to raise volume,scaleto change resolution. Skip it and the stage is bypassed. - Encode: re-compress the raw material with the target codec — video into H.264/H.265, audio into AAC/MP3. Also CPU-intensive, and a lossy codec loses quality here.
- Mux: package the new video and audio streams into the target container (mp4/mkv/webm), write the index, and produce a playable file.
4. Connecting it back: what stream copy actually skips
Recall re-encode vs stream copy: stream copy (-c copy) is exactly the pipeline with the middle three stages — decode → filter → encode — skipped. After demux, the packets go straight into mux, untouched.
Because the audio/video data is never touched:
- it's fast (CPU barely participates);
- it's lossless (not a single byte changed);
- it can only swap containers or extract streams — it can't change codec or resolution.
Re-encode runs the full pipeline, and the decode → encode core is the heaviest part, so it's slow and may look worse. One diagram explains both — that's the point of this article.
5. Real bugs we hit
These aren't abstract theory — they are things we actually ran into running ffmpeg in the browser and on the desktop at tools.beer.
Bug 1: the browser ffmpeg wouldn't start until we added two HTTP headers.
Our web tool uses FFmpeg.wasm (ffmpeg compiled to WebAssembly, running in the browser). It depends on SharedArrayBuffer, which the browser only provides when the page is crossOriginIsolated — and that requires the server to send both Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp. Miss one and crossOriginIsolated is false, so the ffmpeg core throws on load. We spent a long time before pinning it on those two headers.
Bug 2: browser ffmpeg is slower than native — for a physical reason. The decode → encode core is CPU-heavy. On the desktop (we call a native ffmpeg binary via Tauri) it gets multi-core and hardware acceleration; the WebAssembly build in the browser gets neither, so the same pipeline is clearly slower there. That's why our desktop "convert to mp4" (a real libx264 re-encode) takes genuine time, while a pure container swap in the browser finishes in seconds — the latter is essentially stream copy.
Bug 3: ffmpeg isn't just a converter — it may re-encode behind your back.
ffmpeg -i in.mp4 out.mkv looks like a plain format swap. But if the target container doesn't support the source codec, ffmpeg automatically triggers a re-encode — often without you noticing, until "why is it slow and blurry now?". Understand the pipeline and you'll see it actually ran the whole line and re-compressed everything.
6. Summary
- FFmpeg isn't a "format converter" — it's a pipeline: demux → decode → filter → encode → mux;
- Blue blocks handle the container (unbox/rebox), red blocks handle the codec (decompress/compress), green is optional processing;
- Decode → encode is the CPU-heavy core — it decides the overall speed;
- Stream copy (-c copy) skips the middle three stages, so it's fast and lossless — the real reason stream copy is fast from the previous article;
- The same pipeline runs slower in browser wasm than native, because of the hardware-acceleration gap, not magic.
Further reading
- Container vs Codec — explained in plain English
- Re-encode vs stream copy: why conversion sometimes gets slow or blurry
- How to choose formats? MP4 / MKV / WebM / MOV
- Lossless vs lossy: what is the real difference?
- Can you transcode in the browser? WebAssembly FFmpeg explained
- Walkthrough: what happens when you click mp4→mp3
- The complete guide to audio/video conversion
Want to try it now? You can convert MP4 to MP3 right in your browser.
References (authoritative sources)
FFmpeg official site and documentationWikipedia: FFmpeg
Written by the tools.beer team, based on real lessons from running FFmpeg.wasm in the browser and native ffmpeg on the desktop. Last updated 2026-08-20.