Part of this guide

This answers one question from m3u file format, which covers the whole picture.

The short answer

An M3U8 file is a playlist: a plain text list of addresses, saved in UTF-8. That is the whole of the formal definition, and it is not what most people are asking. On the web today the extension almost always means something narrower. It is the index a video player reads to find the pieces of a stream, and the stream itself is somewhere else entirely.

That gap between the definition and the usage is why M3U8 files confuse people. You download one expecting a video and get four kilobytes of text. Nothing has gone wrong. You are holding the table of contents, not the book.

What the 8 actually means

It is the encoding, and only the encoding. The original M3U format never declared one, which was survivable in 1999 when the filenames were ASCII and the software was one program on one machine. It stopped being survivable the moment playlists carried channel names in Arabic, Cyrillic or Chinese, because the file gave a reader no way to know how to interpret the bytes. Different players guessed differently and the names came out as mojibake.

M3U8 settles it by definition: the contents are UTF-8. Same syntax, same tags, same structure. A correct M3U8 file is a correct M3U file that has committed to an alphabet.

The reason the extension now implies far more than that is HTTP Live Streaming. When Apple published HLS it used this format for its manifests, and because HLS became the default way video reaches a browser, the extension picked up the association. So in practice M3U8 files are one of two quite different things: a plain playlist of whole media files, or an HLS manifest describing a stream cut into segments. The tags inside tell you which, and the rest of this page is about reading them.

Inside an HLS manifest

Every line is either a tag, beginning with #EXT, or an address. Anything else starting with # is a comment. Here is a complete one, and it is complete: this is not an excerpt with the boring parts removed.

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:9.009,
segment0.ts
#EXTINF:9.009,
segment1.ts
#EXTINF:3.003,
segment2.ts
#EXT-X-ENDLIST

#EXTM3U must be the first line. Without it a strict player rejects the file before reading anything else, and a surprising number of hand-edited playlists fail for exactly this reason. #EXT-X-VERSION declares which revision of the specification the file expects, which matters because later tags are silently ignored by players that predate them.

#EXT-X-TARGETDURATION is the maximum segment length in whole seconds, and it is a promise rather than a description: no segment in the file may exceed it. A player uses it to decide how often to come back for an updated manifest on a live stream, so a wrong value produces either needless requests or a stream that falls behind.

#EXTINF gives the duration of the segment named on the following line, in seconds, with a trailing comma where a title would go. Durations are fractional and rarely round, because they follow the encoder rather than the clock. The last segment here is shorter than the others, which is simply where the content ended.

#EXT-X-MEDIA-SEQUENCE numbers the first segment in the list, and it is uninteresting on a recording, where it stays at zero forever. On a live stream it is the part that makes the whole scheme work. Segments are named unhelpfully and rotate out of the list as new ones arrive, so a player that fetched the manifest a moment ago needs to know which entries it has already seen. The sequence number tells it, and a stream whose publisher resets that counter will make players re-request segments they already played.

One tag is missing from the example and worth knowing about, because it produces a failure that looks like a broken player. #EXT-X-KEY declares that segments are encrypted and gives the address of the key needed to decrypt them. The manifest fetches cleanly, the segments download, and playback still fails, because the key is served from somewhere the player cannot reach or is not authorised to ask.

#EXT-X-ENDLIST says there will be no more segments. It is the single most useful tag in the file for working out what you are looking at, and it earns its own section below.

Master playlists, and why the quality changes

The file above lists segments directly. Many manifests do not. Instead they list other manifests, one per quality rendition, and that outer file is called a master playlist:

#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=640x360
360p/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2400000,RESOLUTION=1280x720
720p/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=6000000,RESOLUTION=1920x1080
1080p/index.m3u8

Each #EXT-X-STREAM-INF describes a rendition of the same content at a different bitrate, and the address beneath it points at that rendition’s own manifest, which does list segments. The player measures how quickly segments are arriving and moves between them as network conditions change. That is adaptive bitrate streaming, and it is the reason a video softens for a few seconds instead of stopping.

This also explains a complaint that sounds like a player fault and is not. A stream offering one rendition has nothing to fall back to. When the connection dips it cannot drop to something smaller, so it stalls and waits. Persistent buffering on a stream that is otherwise healthy usually means the master playlist is short, and counting the#EXT-X-STREAM-INF lines tells you in seconds whether that is the case.

Telling a live stream from a recording

Look for #EXT-X-ENDLIST. If it is there, the manifest is finished: every segment that will ever exist is already listed, the duration is the sum of the#EXTINF values, and a player can offer a seek bar because it knows where the end is. That is a recording, which the specification calls video on demand.

If it is absent, the manifest is a window onto something still being produced. The player re-requests the same address every few seconds, expecting new segments to have been appended and old ones dropped from the top. That is a live stream, and it is why a live manifest fetched twice a minute apart is not the same file.

This distinction accounts for a class of confusion that is otherwise hard to explain. A live manifest saved to disk and opened later contains addresses to segments that have since been rotated away, so it plays nothing at all despite being a perfectly valid file that worked minutes earlier. Nothing is corrupted. The list simply expired.

What opens M3U8 files

Two answers, because there are two questions hiding in it. M3U8 files are text, so any editor opens one, and doing so is genuinely useful rather than a last resort. The file is short, the tags are legible, and looking at what a player was actually handed settles most arguments about why it misbehaved.

To play one you need something that understands HLS. Safari and most mobile browsers support it natively. Other desktop browsers do not, and reach it through a JavaScript library that fetches the manifest, requests segments and feeds them to the video element, which is how a browser-based player works at all. Desktop applications such as VLC handle both plain playlists and HLS manifests directly.

What will not work is treating the file as a video. Renaming it to .mp4produces a file that is still four kilobytes of text, and every player that opens it will say so in its own way.

Why a valid manifest still refuses to play

The file being correct and the stream being playable are separate questions, and in a browser they come apart more often than anywhere else. Four causes account for nearly all of it.

The source is gone. M3U8 files outlive the infrastructure they describe, and a link collected from a forum post is frequently pointing at a server that stopped answering months ago.

The server will not permit a browser to read it. A page on one origin may only fetch from another if that other server sends anAccess-Control-Allow-Origin header saying so. Plenty of stream servers never send one, having been built for applications rather than web pages. The stream is fine and plays in VLC; the browser is refusing on instruction, and no player running inside that browser can override it.

The address is plain http:// while the page is https://. Browsers block that combination outright as mixed content, usually with nothing more informative than a silent failure.

The master answers and the variant does not. A master playlist returning 200 says only that the outer file exists. The rendition manifests it names are separate requests to separate addresses, and one of those returning 404 produces a stream that appears to load and then plays nothing. Checking the master alone is the most common incomplete diagnosis there is.