Fundamentals 14 min read

Why Chrome Sends Hundreds of 206 Requests for One MP4 and How FFmpeg Fixes It

An MP4 video with a misplaced moov box and poor interleaving caused Chrome to issue an initial three 206 requests followed by thousands of range‑jumping requests, inflating CDN traffic, while re‑encoding the file with FFmpeg faststart eliminated the excess requests and restored normal bandwidth usage.

ITPUB
ITPUB
ITPUB
Why Chrome Sends Hundreds of 206 Requests for One MP4 and How FFmpeg Fixes It

Background

A 1 GB training video that should have generated only a few terabytes of traffic for 2,500 viewers was observed to consume more than 120 TB of CDN bandwidth.

Phenomenon Identification

Traffic pattern

CDN logs showed that the top‑consuming files were a handful of MP4 videos, each about 1 GB and 30 minutes long. When the video was played in Chrome with the developer tools open, the full playback downloaded 8 GB and generated 3,700 HTTP 206 range requests.

Three 206 requests appear at the start of playback.

After the third request the browser repeatedly issues additional 206 requests.

The Range header values jump back and forth between distant file offsets.

Verification with a smaller file

A second video (500 MB, 40 minutes) exhibited the same pattern of multiple 206 requests, confirming that the behaviour is not size‑specific.

Investigation

MP4 file structure

ftyp – file type (header)
moov – metadata (index information)
mdat – actual audio/video data

The moov box contains the index that tells the player where each sample resides. The player must read moov before it can locate the mdat payload. moov holds all index tables (e.g., stco, stsz, stsc). mdat stores the raw media streams.

If moov is placed at the end of the file, the player must seek to the file tail, read moov, then seek back to mdat, causing extra HTTP 206 requests.

Browser playback flow

Chrome uses the FFmpegDemuxer to parse MP4 files. The simplified sequence is:

Read ftyp + moov → Seek to mdat → Start playback

When moov is at the end, the demuxer performs two additional seeks, resulting in three initial 206 requests.

Source‑code analysis

The function mov_find_next_sample() selects the next sample based on DTS (decoding timestamp) difference and file offset. For poorly interleaved files the “closest” DTS may be far away in the file, causing the demuxer to jump back and forth.

static AVIndexEntry *mov_find_next_sample(AVFormatContext *s, AVStream **st) {
    for (i = 0; i < s->nb_streams; i++) {
        // if DTS diff ≤ 1 s, pick the earlier file position
        // else pick the smallest DTS
    }
    return sample;
}

When audio and video packets are not interleaved, the algorithm repeatedly selects distant offsets, generating many range requests.

Test verification

A deliberately poorly interleaved video ( longbad.mp4) was processed with FFmpeg tracing. The default interleaved read produced 5,078 HTTP 206 requests for a 5‑second clip.

ffmpeg -i https://example/longbad.mp4 -ss 60 -t 5 -y output.mp4 -loglevel trace 2>&1 | grep "Range"
# → 5078 requests

Disabling interleaved read ( -interleaved_read 0) reduced the count to three requests.

ffmpeg -interleaved_read 0 -i https://example/longbad.mp4 -ss 60 -t 5 -y output.mp4 -loglevel trace 2>&1 | grep "Range"
# → 3 requests

Root Cause Analysis

Why three initial 206 requests?

The moov box resides at the file end. The player performs:

1. Seek to file end, read ftyp+moov → 206 #1
2. Read moov (still at tail) → 206 #2
3. Seek to mdat and start playback → 206 #3

Why many subsequent 206 requests with jumping ranges?

The audio and video packets are stored in large, non‑interleaved blocks (e.g., all audio first, then video). FFmpeg’s mov_find_next_sample() prefers the earliest file offset when DTS differences are ≤ 1 s. Because the “earliest” packet may be far from the current position, the demuxer repeatedly seeks between distant audio and video blocks, each seek generating a new HTTP 206 request.

Why does re‑encoding with FFmpeg solve the problem?

Running:

ffmpeg -i bad.mp4 -c copy -movflags faststart good.mp4

moves the moov box to the beginning of the file and re‑interleaves the streams. The resulting file is read sequentially, producing a single 206 request and bandwidth consumption equal to the file size.

Solution

For short‑form videos, process the source MP4 with FFmpeg using the -movflags faststart option (or -interleaved_read 1) to ensure:

The moov box is placed at the file header.

Audio and video packets are interleaved in time order.

This eliminates excessive range requests and reduces CDN bandwidth usage.

For long‑form content, adopt adaptive streaming formats such as HLS or DASH, which split the media into small segments and allow progressive download, providing better bandwidth efficiency and smoother playback.

References

The investigation of excessive FFmpeg requests: https://blog.dreamfever.me/posts/2024-06-09-poor-performance-of-ffmpeg-i-url/#reference

Endless canceled HTTP requests when playing an MP4 in a <video> tag: https://issues.chromium.org/issues/40292515

Chromium source (mov.c): https://source.chromium.org/chromium/chromium/src/+/main:third_party/ffmpeg/libavformat/mov.c;l=11048

FFmpeg source (mov.c lines 9767‑9795): https://github.com/FFmpeg/FFmpeg/blob/94f2274a8b61438572f0873ccf430e55ce0e0e2b/libavformat/mov.c#L9767-L9795

Chromeffmpegvideo streamingMP4File InterleavingHTTP 206
ITPUB
Written by

ITPUB

Official ITPUB account sharing technical insights, community news, and exciting events.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.