Parsing DASH and HLS segments as one stream: why the init segment matters
You pulled a handful of .m4s files off a DASH or HLS stream - maybe from a .mpd/.m3u8 manifest, maybe downloaded one by one, maybe saved straight out of your browser DevTools network tab. You drop one of them, say seg-1.m4s, into the analyzer to see what is inside, and it comes back as Unknown Stream. The container boxes are there, but the codec is unrecognized and not a single video sample decodes. The file is not corrupt. It is just incomplete.
A media segment carries no codec configuration. The H.264 parameter sets - the SPS (sequence parameter set) and PPS (picture parameter set) - live only in the init segment, never in the media segments. Without the init in front of it, a media segment is a box of samples that nothing knows how to read.
This guide shows how to fix that in the Advanced tab of the Open File dialog, which parses the init segment and the media segments together as one sequence - so the init's SPS/PPS apply across every segment, exactly the way a player sees them.
DASH, HLS, and CMAF segments in brief
DASH (MPEG-DASH, ISO/IEC 23009) and HLS (Apple's HTTP Live Streaming) are adaptive-streaming protocols. Instead of one big file, the stream is sliced into chunks, and a manifest lists them: a .mpd for DASH, a .m3u8 for HLS. The manifest points to one init segment plus a sequence of media segments, each usually a few seconds long, and often offered at several bitrates so the player can switch quality on the fly.
The split of responsibilities is the part that matters here:
- The init segment carries movie-level metadata - the track definition and codec configuration - and no media at all. It is commonly named
init.mp4,init.m4s, or something withinitin the name. - The media segments carry the actual coded frames, one slice of the timeline each, and nothing that tells you how to decode them.
CMAF (Common Media Application Format, ISO/IEC 23000-19) standardizes that fragmented-MP4 segment structure so the same segments can serve both DASH and HLS. Modern HLS uses fragmented MP4 / CMAF; legacy HLS used MPEG-TS. File extensions you will run into: .m4s, .mp4, and .cmf* for CMAF, and .ts for legacy HLS. These segments are fragmented MP4 under the hood - the moof/trun machinery is covered in detail in the fragmented MP4 post (opens in new tab).
Why a media segment alone is "Unknown Stream"
The init segment is where the decoder learns the codec. Its moov defines the track, and the codec config sits at stsd -> avc1 -> avcC, holding the SPS and PPS. A media segment references that configuration but never repeats it. Open the two halves separately and you can see each one is missing what the other has:
| Input | Detected as | Track 1 codec | Sample packets |
|---|---|---|---|
init.m4s alone | ISO Media File | H.264/AVC | 2 AVC packets (SPS + PPS only; no media samples) |
seg-1.m4s alone | MP4 Segment | Unknown Stream | ~50 sample packets, all unrecognized |
init + 3 media segments together (Advanced tab) | (one sequence) | H.264/AVC | "Found 4 streams, 211 packets"; samples parsed as AVC IDR Slice (I) and AVC Non-IDR Slice (P/B) |
The init alone knows the codec but has no frames to show. A media segment alone has 50-odd frames but no idea what they are. Stitch the init in front, and the analyzer propagates its SPS/PPS to every following segment - the media samples resolve into real AVC IDR Slice (I) and AVC Non-IDR Slice (P/B) packets. That propagation is the entire point of the workflow.
Parsing segments together in the Advanced tab
The Open File dialog has three tabs: Simple, Advanced, and URL. The Advanced tab is the one that opens multiple files and parses them as a single concatenated sequence. Its in-app help text says it plainly:
Add multiple files to parse segmented streams (e.g. HLS, DASH, CMAF segments) as a single sequence. Files are auto-sorted when added. Drag items to reorder manually, or click Sort to re-sort all.
The workflow is short:
- Click Open File, then switch to the Advanced tab.
- Add Files with the multi-select picker, or drag the files in from your OS file manager. Add all the segments, and crucially include the init segment.
- The list auto-sorts as files are added - the init goes first, media segments follow in order.
- Reorder by dragging an item, or click Sort to re-sort everything. File order is parse order, so verify it looks right.
- Leave Parser Selection on Automatic (or force a specific parser if auto-detect misfires).
- Click Analyze.
The auto-sort is smarter than a plain alphabetical sort, which matters because filenames like seg-10.m4s sort before seg-2.m4s lexically. It works in stages: it detects init/header segments by filename pattern (init.mp4, init-stream0.m4s, header.mp4, 1_init.mp4, and similar) and floats them to the front; it groups files by stream id (stream0); it recognizes a naming template of prefix + numeric index + suffix and orders by that index; and it falls back to a natural, numeric-aware sort otherwise. In practice you can add files in any order - drop in [seg-2, seg-3, init, seg-1] shuffled, and they land as init.m4s, seg-1.m4s, seg-2.m4s, seg-3.m4s. Per-file controls let you remove any file with its x, and Clear All empties the list to start over.
Reading the combined view
Parsing four files as one sequence raises an obvious question: which segment did a given box come from? The analyzer answers it everywhere by drawing a labeled separator before each file's content, in both the packet list and the hex view. You always know which segment you are looking at, even though it is parsed as a single stream.
In the packet list, the order follows the bytes. The init boxes come first - ftyp, then moov with mvhd, trak, down through avc1, avcC, the SPS and PPS, and the stbl sample tables. Then the seg-1.m4s separator appears, and the first media segment begins with its styp Segment Type Box, followed by sidx, moof and its children, mdat, and finally the recognized AVC slices.
The hex view marks the same boundaries. Each file is introduced by a horizontal divider with the filename centered on it. The init.m4s divider sits just above offset 0, and the bytes right below it read 00 00 00 1c 66 74 79 70 - a 28-byte box whose type is ftyp, exactly the start of an ISOBMFF file. Byte offsets are continuous and absolute across the whole concatenated sequence, and the per-file dividers tell you where each file begins within that running count.
Because boxes from every segment share one packet list, you can hunt for a specific box across the whole combined sequence at once - handy for confirming, say, that every moof has the tfdt you expect.
Inside a media segment
Once the init is in place, a media segment is a compact fragmented-MP4 unit. Here is what each top-level box does:
| Box | Name | Role |
|---|---|---|
styp | Segment Type Box | Declares the segment-level brand. |
sidx | Segment Index | Optional timing and byte-range index for the segment. |
moof | Movie Fragment | Header for this fragment; contains mfhd (sequence number) and traf. |
traf | Track Fragment | Per-track fragment data: tfhd (defaults), tfdt (baseMediaDecodeTime), trun (per-sample size, offset, flags). |
mdat | Media Data | The coded samples themselves - the actual frames. |
The link back to the init is what makes any of this decodable. The init's moov defines the track, and its mvex/trex declare the defaults that each fragment's moof/trun reference and selectively override - so a trun can carry only the values that differ per sample. And the init's avcC SPS/PPS are what turn the mdat bytes into recognizable H.264 slices. For the full box-by-box breakdown of fragmented MP4, see the fragmented MP4 post (opens in new tab).
Tips and gotchas
- Always include the init segment. It is the single most common mistake. Without it you get "Unknown Stream" and unrecognized samples, every time.
- Order matters. The init must come first, then media segments in chronological order. Auto-sort handles this for the common naming schemes, but glance at the list before you hit Analyze - parse order is file order.
- Force a parser if auto-detect misfires. Leave Parser Selection on Automatic for normal use; switch it to a specific parser only when detection picks the wrong one.
- Same segments, both protocols. This works for HLS fragmented MP4 and DASH alike, because CMAF gives them the same segment structure.
- Legacy
.tsworks too. Older HLS streams use MPEG-TS (.ts) segments rather than fragmented MP4. Because MPEG-TS carries its own PAT/PMT in-band, each segment is self-describing - there is no separate init segment, so you do not strictly need the Advanced tab at all; a single.tssegment parses fine on its own. It is still perfectly fine to use the Advanced tab if you want to line up several segments and view them as one stream.
Next time a downloaded segment parses as "Unknown Stream", do not assume the file is broken. Open the Advanced tab, add the init segment alongside it, verify the order, and analyze - and watch those mystery samples resolve into the AVC slices they always were.
Comments