Design video streaming

How does a recipe video play smoothly on a slow phone?

About 55 minutes · open lesson · System design

Why does the recipe video stop in every tunnel?

By August, 2,000 home cooks sell through the delivery service, and partner kitchens have been asking for one feature: a short video of a dish being made, next to the menu.

The first version adds an upload button. The phone sends the video file to the app server, which saves it in the bucket that already holds menu photos and links it from the menu page.

One cook records four minutes in her kitchen: 480 MB. Her home Wi-Fi drops at 80% and the upload starts again from zero. The third try works.

The next evening a customer opens the video on the train from Mumbai to Pune. Ten seconds of video, then the spinner. Ten more seconds, then the spinner. In the ghat tunnels it stops completely, and he gives up before Lonavala.

The file is the phone’s original. Work out its bitrate before reading on: 480 MB for four minutes is 480 x 8 / 240, or 16 megabits a second, recorded by a phone that expects to be watched on Wi-Fi. On a train the signal is often under 2 megabits a second, and in a tunnel it is close to nothing. And the service pays for every megabyte a phone pulls, whether anyone watches it or not.

His phone could have played a smaller video, but it was sent the big original. Most of the design follows from that. Keep each video in several sizes, cut into short pieces, and let the phone choose the size piece by piece as its signal changes. Around that sit two more problems: an upload that survives a dropped connection, and slow processing that must not run on the server taking orders.

Pause and predict A 480 MB upload dropped at 80% and started again from zero. What fixes that?

What must never go wrong?

Start with the people and the systems around the video service.

The first quality target: once a video starts playing, it should keep playing. A blurry picture for a while is acceptable; a spinner that stops the video is not.

Core entities, in two minutes

A Video (owner, title, status), its Renditions (one per rung of the ladder, each a playlist of segments), the Upload in progress, and the Transcode tasks that turn an original into renditions.

The estimate that changes the design

QuantityWorkingResult
Video uploaded per week300 x 5 min1,500 min (90,000 s)
Originals per week, at 16 Mb/s90,000 s x 16 Mb / 8180 GB
Renditions per week, six rungs (7,340 kb/s in total)90,000 s x 7.34 Mb / 882.6 GB
Stored per year, originals and renditions(180 + 82.6) GB x 5213.7 TB
Delivered per day50,000 x 180 s x 1.5 Mb / 81.69 TB
Delivered per month1.69 TB x 3050.6 TB
Evening peak bandwidth1.69 TB x 8 / 86,400 s x 3≈ 470 Mb/s

The surprise is the ratio. Every month the service sends out about 50 TB, roughly four times what it stores in a whole year. So the money and the risk are in delivery: the CDN’s hit rate and the bitrates the player chooses. Storage tiers and clever transcoding matter much less. And 1,500 minutes of new video a week is little processing: a small pool of workers, idle most of the day, is enough.

The obvious version, and how it breaks

The first version reuses what worked for menu photos in lesson 1.3: put the file in the bucket and link it.

It breaks in four places at once:

  • One size for every phone. A 16 Mb/s file needs a 16 Mb/s connection to play without stopping. Most of the service’s customers watch on mobile data.
  • One long download. The phone fetches the file from the start and cannot change its mind. When the signal drops, it can only wait.
  • An upload that starts over. A 480 MB file in one request fails as a whole. The two failed tries sent nearly 800 MB for nothing.
  • Heavy work on the wrong server. When files were converted with ffmpeg inside the app server, order requests queued behind a four-minute encode.

You will run the first two in the simulator under Break it: “Always the best” is the first version with a choice of sizes added, and it still stalls on the train.

A mental model

Adaptive bitrate streaming (ABR)
The video is stored at several qualities, each cut into short segments. Before fetching each segment, the player chooses which quality to fetch, based on how fast recent downloads were and how much video it already holds.
For example: Segment 14 at 2,000 kb/s on good signal; segment 15 at 145 kb/s in a tunnel; segment 16 at 730 kb/s coming out.

Three ideas make the design: a bitrate ladder (the same video encoded at several sizes), segments (a few seconds each, aligned across every rung so the player can switch between any two), and a manifest that lists them. None of it needs a special streaming server: segments are ordinary files, served over ordinary HTTP by the CDN you already have.

Short or long segments?

The segment length is set once, when videos are packaged, and changing it means repackaging the library. Two goals pull it in opposite directions.

The first-frame times are the lowest rung on a weak signal: 145 kb/s x 2 s = 290 kb takes 0.7 s at 400 kb/s; 145 x 6 = 870 kb takes 2.2 s. Short segments do start faster and react sooner. The simulator in Break it settles the rest: on the train trace, with a 30-second buffer, the throughput-based player stalls zero times at 2, 4 or 6 seconds. The buffer carries a phone through a 15-second tunnel; the segment length barely matters.

What to remember

  1. Store each video as a bitrate ladder, cut into short aligned segments, listed in a manifest (HLS or DASH). Plain HTTP files, served by a CDN.
  2. The player adapts, segment by segment, from measured throughput, from its buffer, or both. A bitrate above the average bandwidth stalls whatever the buffer.
  3. Upload with multipart pre-signed URLs, so a dropped connection costs one part; transcode on a queue of workers whose tasks are safe to repeat.
  4. Do the estimate: delivery dwarfs storage, so the CDN hit rate and the ladder decide the bill. Keep every original to re-encode later.

Prepare several sizes in short pieces, and let the player pick each piece from its own buffer and bandwidth.

In the real world

Real video platforms go further than our design. They tune the ladder per title, since a cooking video with a still camera needs far fewer bits than a football match at the same quality. They run several codecs side by side (H.264 for older phones, HEVC or AV1 where supported), measure quality with perceptual metrics in place of bitrate, and run players that combine throughput and buffer signals, abandon slow downloads mid-segment, and start at a rung chosen from the last session’s bandwidth.

The simulator keeps one idea: the player chooses, piece by piece, from a ladder the server prepared. In the paper above, the authors found that the buffer alone was enough in steady state, and that a throughput estimate mattered mainly while the buffer was filling at startup.

Open the interactive lesson

The interactive lesson adds the predictions with their answers, the labs, and graded practice with spaced review.