skip to content

In progressive-download video playback over HTTP, how does a player seek to minute 40 without downloading everything before it?

level: middleimportance: nice to knowfreq 30%

answer

  1. one file, addressed by position
  2. time-to-offset lookup first
  3. a partial answer to a Range
  4. 206 versus 200 versus 416
  5. index at the front or tail

basics

~20 s

The player uses the file's index to map minute 40 to a byte offset at a nearby keyframe, then sends an HTTP Range request from that offset; a server that supports ranges replies 206 Partial Content with only those bytes.

solid answer

~50 s

A progressively downloaded video is one file, and its **index**, a metadata structure mapping playback time to byte offsets and keyframe positions, tells the player where each moment lives. To seek, the player looks up the keyframe at or just before minute 40 and sends `Range: bytes=<offset>-` (or a bounded range) to the same URL. A server that supports ranges, advertised with `Accept-Ranges: bytes`, replies `206 Partial Content` with a `Content-Range` header; a range beyond the file gets `416 Range Not Satisfiable`, and a server that ignores ranges returns `200` with the whole file, which the player must then read from the start. If the index sits at the end of the file, the player first fetches that tail with a range request, which is why files are often prepared with the index at the front. The same mechanism powers resumable downloads and lets segmented streams address pieces inside one large file.

code

http · 8 lines
http
GET /videos/lecture-17 HTTP/1.1
Host: media.example.com
Range: bytes=734003200-735051775

HTTP/1.1 206 Partial Content
Content-Range: bytes 734003200-735051775/1468006400
Content-Length: 1048576
Accept-Ranges: bytes

go deeper

for a junior

Recall the Range request header and the 206 Partial Content response, and that the player needs to know which byte offset corresponds to the time it wants.

for a middle

Explain the index that maps time to offsets, snapping to a keyframe, and the difference between 206, 200 and 416 responses to a range request.

for a senior

Handle the production edge cases: an index at the end of the file, intermediaries that drop ranges, If-Range for safe resume, and files replaced while viewers are mid-download.

for a principal

Decide where single-file delivery with byte ranges is good enough and where a full segmented ladder is justified, weighing packaging and transcode cost against adaptation and viewer experience.

## Progressive download versus segmented streaming **Progressive download** means the player plays a single video file over HTTP while it is still downloading. There is one rendition, one URL and no manifest of segments. It is simple to produce and serve, but it cannot change quality mid-playback. Seeking works only because HTTP lets a client ask for part of a file: a **byte-range request**. ## How HTTP range requests work | Element | Direction | Meaning | |---|---|---| | `Accept-Ranges: bytes` | response | the server supports byte ranges for this resource | | `Range: bytes=500-999` | request | ask for bytes 500 through 999 inclusive | | `Range: bytes=500-` | request | ask for everything from byte 500 to the end | | `Range: bytes=-500` | request | ask for the last 500 bytes | | `206 Partial Content` | response | the body holds only the requested range | | `Content-Range: bytes 500-999/8000` | response | which bytes were sent, and the total size | | `416 Range Not Satisfiable` | response | the range lies outside the resource | | `If-Range` | request | send the range only if the resource is unchanged, otherwise send it all | Ranges are inclusive on both ends, so `bytes=500-999` is exactly 500 bytes. A request may list several ranges, in which case the server can answer with a multipart body. ## The seek, step by step 1. The player already holds the file's **index** — the metadata that maps playback time to byte offsets and marks where keyframes are. 2. The viewer drags to minute 40. The player looks up the **keyframe** at or just before that time, because predicted frames cannot be decoded without the frames they reference. 3. It sends a GET for the same URL with `Range: bytes=<offset>-`, or a bounded range if it wants to fetch in pieces. 4. The server answers `206 Partial Content`; the player feeds the bytes to its decoder starting at that keyframe. 5. For an accurate seek, the player decodes forward from the keyframe to exactly minute 40 and shows frames from there; for a fast seek it simply starts at the keyframe. With keyframes a few seconds apart, the gap between the requested time and the keyframe is small. ## Where the index lives The index can sit at the **front** or the **end** of the file, depending on how it was written: - **Index at the front**: the first bytes the player reads contain the map, so playback and seeking can begin at once. Preparing files this way is often called a fast-start layout. - **Index at the end**: common when a recorder writes the index after it knows the final sizes. The player must first request the tail (for example with a suffix range) to read the map, costing an extra round trip before playback. - **No range support at all**: if the index is at the end and ranges are unavailable, the player effectively has to download the whole file before it can play. ## Pitfalls in production - An intermediary or misconfigured server may **ignore** `Range` and return `200` with the full body; a player that assumes it received the requested offset will decode garbage. - A file **replaced** while a viewer is mid-download can yield a mix of old and new bytes; `If-Range` with the earlier `ETag` or `Last-Modified` value prevents that. - Requests for a range past the end, for example after a file was truncated, return `416` and must be handled rather than retried forever. - Very small ranges multiply requests and round trips, so players usually fetch generous chunks. ## Byte ranges inside segmented streams Range requests are not only for progressive files. HLS can describe a segment as a sub-range of a larger resource with `#EXT-X-BYTERANGE`, and MPEG-DASH can locate segments through a segment index stored at a known byte range of one file. This keeps the number of stored objects low while still giving the player segment-level access — at the cost of every request depending on range support along the whole delivery path.

  • What should a player do when a server or intermediary ignores the Range header?
    It will receive 200 OK with the full body starting at byte zero, not at the requested offset. The player must check the status before decoding: it can read and discard bytes up to the target, which wastes bandwidth and time, or report that seeking is unavailable. Checking for Accept-Ranges and a 206 response before relying on ranges avoids decoding the wrong bytes.
  • Why use If-Range when resuming a partially downloaded video?
    If the file changed since the first bytes were fetched, appending new bytes to old ones would corrupt it. If-Range carries the earlier ETag or Last-Modified value: if it still matches, the server returns 206 with the requested range; if not, it returns 200 with the whole current file, so the client starts over instead of mixing versions.
  • When is progressive download still a reasonable choice over segmented streaming?
    For short clips, previews or offline downloads where one fixed quality is acceptable. A single file needs no rendition ladder, packaging step or manifest, and range requests still give seeking and resume. It gives up mid-playback quality adaptation, so long-form viewing on variable networks usually justifies segmented streaming.

saying these in an interview costs you the question

  • Seeking in a progressive file requires downloading every byte before the target.
  • A 200 response to a Range request means the requested range was returned.
  • The player can begin decoding at any byte offset it chooses.
  • Range requests need a special streaming server instead of plain HTTP.
  • Accept-Ranges is a header the client sends to ask for partial content.