<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tutu</title>
    <description>The latest articles on DEV Community by Tutu (@meicut).</description>
    <link>https://dev.to/meicut</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4167027%2Fe3207736-f0d1-43d4-9e19-78d31c24a6e7.png</url>
      <title>DEV Community: Tutu</title>
      <link>https://dev.to/meicut</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/meicut"/>
    <language>en</language>
    <item>
      <title>Meicut Engineering #1: Video Compression at Product Scale</title>
      <dc:creator>Tutu</dc:creator>
      <pubDate>Tue, 06 Oct 2026 17:50:13 +0000</pubDate>
      <link>https://dev.to/meicut/meicut-engineering-1-video-compression-at-product-scale-108k</link>
      <guid>https://dev.to/meicut/meicut-engineering-1-video-compression-at-product-scale-108k</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Part of the Meicut Engineering series — how we build an in-browser media toolkit.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The encoding command — &lt;code&gt;ffmpeg -i in.mp4 -c:v libx264 -crf 23 out.mp4&lt;/code&gt; — is well documented. What is rarely discussed is the engineering that turns this single command into a service: where encoding runs, how long-running jobs behave, how concurrency is bounded, and how output is matched to the user's stated goal. This post covers those decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Where encoding runs
&lt;/h2&gt;

&lt;p&gt;The first architectural decision is the execution environment. Three options exist for a web media tool:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Execution&lt;/th&gt;
&lt;th&gt;Cost profile&lt;/th&gt;
&lt;th&gt;Constraints&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Server-side ffmpeg&lt;/td&gt;
&lt;td&gt;Encode on infrastructure&lt;/td&gt;
&lt;td&gt;Upload → encode → download&lt;/td&gt;
&lt;td&gt;Requires upload; full ffmpeg capability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ffmpeg.wasm&lt;/td&gt;
&lt;td&gt;In-browser (WebAssembly)&lt;/td&gt;
&lt;td&gt;No upload, strong privacy&lt;/td&gt;
&lt;td&gt;≈ an order of magnitude slower than native (community benchmarks); input+output held in a WASM heap capped near 2–4GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WebCodecs&lt;/td&gt;
&lt;td&gt;In-browser (raw codecs)&lt;/td&gt;
&lt;td&gt;No upload&lt;/td&gt;
&lt;td&gt;Most control; most implementation work&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Browser-native execution (ffmpeg.wasm / WebCodecs) is attractive for privacy — files never leave the device. It is, however, constrained by encode throughput and memory ceiling: a 500MB input can exceed the WASM heap and crash the tab. Server-side execution reliably handles large files and the full filter set (fonts for subtitles, multi-file merges).&lt;/p&gt;

&lt;p&gt;We therefore implemented server-side encoding first, deferring browser-native processing. The ordering principle — &lt;strong&gt;support the hardest case before the common case&lt;/strong&gt; — recurs throughout the product.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Task pipeline
&lt;/h2&gt;

&lt;p&gt;With encoding server-side, "compress video" becomes a pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;upload → validate → queue → encode → store → downloadable link
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three constraints follow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Long-tail latency.&lt;/strong&gt; A short clip encodes in seconds; a 4K 20-minute input at a slow preset runs for minutes. The pipeline must be asynchronous — each request returns a job ID, the client polls, and progress reflects pipeline state rather than a synthetic spinner. A wall-clock cap per job, with a clear path to re-encode at a faster preset, replaces silent failure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Concurrency.&lt;/strong&gt; If every request spawned an ffmpeg process, a burst of 4K uploads would exhaust CPU and starve smaller jobs. We bound concurrency by job size and worker pool: small jobs take a fast lane; heavy encodes run under a concurrency limit, so no single input or burst dominates. A queue with two priority tiers sufficed for our volume.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Batch as the same pipeline, reused.&lt;/strong&gt; Compression is rarely one file at a time. Many users need to &lt;strong&gt;compress multiple videos at once&lt;/strong&gt; — &lt;strong&gt;batch compression&lt;/strong&gt; is the common request behind any "video compressor" tool. Under the hood it is not a separate system: a user submits many files, each becomes a job in the same queue — sharing the concurrency bound, priority tiers, and per-file validation. Progress and results are tracked per file, and a failed item does not abort the batch; it is reported alongside the successful ones. The single-job pipeline, reused across a list of inputs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Input validation.&lt;/strong&gt; Users upload arbitrary inputs — truncated files, unusual containers, audio mislabeled as video. ffmpeg tolerates much until it does not; a mid-encode crash is poor UX. We probe inputs first (&lt;code&gt;ffprobe&lt;/code&gt;) and return a readable diagnostic before committing to an encode.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Encoding parameters
&lt;/h2&gt;

&lt;p&gt;A single CRF value applied to every input optimizes for no use case. We classify each job before encoding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Intended use&lt;/strong&gt; determines the parameter set: email attachment → aggressive size target with downscaling permitted; social → balanced 1080p; archive → keep resolution at high quality.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Content type&lt;/strong&gt; matters: screen recordings (static) and concert footage (motion-heavy) require different bitrate budgets under the same preset.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Output is &lt;strong&gt;CRF with a size-aware backstop&lt;/strong&gt;: quality-targeted, but if the result exceeds the size implied by the use case, it is re-encoded once at a stricter CRF. Checking the outcome against the goal, rather than the parameter, catches most poor encodes.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Playback compatibility
&lt;/h2&gt;

&lt;p&gt;Encoding is only half the task; guaranteeing playback is the other. Three flags are non-negotiable in a product:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;.mp4 &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="nt"&gt;-preset&lt;/span&gt; medium &lt;span class="nt"&gt;-crf&lt;/span&gt; 23 &lt;span class="nt"&gt;-pix_fmt&lt;/span&gt; yuv420p &lt;span class="nt"&gt;-movflags&lt;/span&gt; +faststart &lt;span class="nt"&gt;-c&lt;/span&gt;:a aac &lt;span class="nt"&gt;-b&lt;/span&gt;:a 128k &lt;span class="nt"&gt;-ar&lt;/span&gt; 44100 out.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-pix_fmt yuv420p&lt;/code&gt; — required for broad player and browser support; 4:4:4 or 10-bit input plays on a subset of devices.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-movflags +faststart&lt;/code&gt; — moves the moov atom forward so playback starts before download completes, reduces perceived load time on web.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Explicit audio parameters (&lt;code&gt;aac 128k 44100&lt;/code&gt;) — avoid container defaults; inaudible or silent tracks are the most common audio support issue.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Privacy as a design constraint
&lt;/h2&gt;

&lt;p&gt;The stated promise — files are used only for the task and auto-deleted — is implemented as a pipeline property rather than a toggle. Files are written to short-TTL storage and destroyed after the job, with a scheduled cleanup as a backstop in case a process terminates abnormally. Default behavior, not user-remembered settings, is what keeps the promise reliable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Video compression as a product is the pipeline surrounding the encode: execution environment, long-job behavior, bounded concurrency, and output matched to the user's goal. The command itself is the smallest part; the value is in the decisions that make it reliable at scale.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The pipeline described here is implemented in the &lt;/em&gt;&lt;a href="https://meicut.com/tools/compress-video" rel="noopener noreferrer"&gt;online video compressor&lt;/a&gt;&lt;em&gt; — no install required; files auto-delete after processing.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Meicut Engineering series:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;#1: Video Compression at Product Scale&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;#2: Trimming Videos Without Re-encoding (when &lt;code&gt;-c copy&lt;/code&gt; is and isn't viable)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;#3: "Convert Format" Is a Misnomer — containers vs codecs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;#4: Subtitles: soft vs burned, and the font problem&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>architecture</category>
      <category>backend</category>
      <category>systemdesign</category>
      <category>ffmpeg</category>
    </item>
  </channel>
</rss>
