How to read chapter timestamps from an mkv file
- Step 1Drop your MKV file — Drag the
.mkv(or.webm, which shares the Matroska structure) onto the tool. One file per run. Free tier handles up to 1 GB; larger files on Pro (10 GB) and Pro-media / Developer (100 GB). - Step 2FFmpeg.wasm demuxes the Matroska header — JAD runs
ffmpeg -i <file> -c copy -t 0 -f null -. This reads theChapterselement and prints each atom's boundaries and title without decoding video — fast even on a multi-hour film. - Step 3Each ChapterAtom becomes an object — JAD scrapes the
Chapter #0:N: start S, end Elines plus the followingtitle :line into{ start, end, title }. Times convert to floating-point seconds; a missing title becomesnull. - Step 4Check the chapter count and titles — The panel lists every chapter found. If the array is empty, the MKV simply has no
Chapterselement. If titles arenull, the muxer wrote boundaries without names — the timestamps are still exact. - Step 5Download the JSON — Saves as
<filename>-chapters.jsonin the standard{ chapters: [...] }shape, pretty-printed for review and diffing. - Step 6Use the timestamps downstream — Feed them into a podcast
<podcast:chapters>JSON, a navigation menu, or an NLE marker import. Seconds make formatting to any timecode a one-line map in your own code.
How MKV stores chapters vs what JAD returns
Matroska's chapter model is rich; the tool flattens it to a portable per-chapter object.
| Matroska element | What it holds | JAD output field | Notes |
|---|---|---|---|
ChapterAtom → ChapterTimeStart | Start position (nanosecond precision internally) | start (seconds, float) | Exact; you subtract for duration |
ChapterAtom → ChapterTimeEnd | Optional end position | end (seconds, float) | Often equals next chapter's start; last = file duration |
ChapterDisplay → ChapString | Title, per ChapLanguage | title (string or null) | Default/first language only — no language picker |
No Chapters element | Container has no chapter data | chapters: [] | By design, not an error |
Where MKV chapters usually come from
Different muxers populate (or skip) titles differently — this is why some MKVs return null titles.
| Source | Has start/end? | Has titles? | Typical title content |
|---|---|---|---|
| mkvtoolnix (manual or split) | Yes | If you added them | Your custom names, or Chapter NN |
yt-dlp --embed-chapters | Yes | Yes | YouTube chapter labels from the description |
| DVD / Blu-ray rip (MakeMKV) | Yes | Usually no | Often null — boundaries only |
| HandBrake → MKV | Yes | Yes | Chapter 1, Chapter 2… or custom |
Cookbook
JSON straight from real MKVs. Times are seconds; titles are verbatim or null.
A yt-dlp MKV with embedded YouTube chapters
yt-dlp --embed-chapters copies the video's chapter labels into the MKV. You get fully-named, fully-bounded chapters.
Input: talk.mkv (yt-dlp --embed-chapters)
Output: talk-chapters.json
{
"chapters": [
{ "start": 0, "end": 95.0, "title": "Welcome" },
{ "start": 95.0, "end": 740.5, "title": "Live demo" },
{ "start": 740.5, "end": 1320.0, "title": "Takeaways" }
]
}A MakeMKV rip with boundaries but null titles
Disc rips carry chapter stops without names. The boundaries are exact; you label them later from the disc menu.
Input: feature.mkv (MakeMKV rip)
Output: feature-chapters.json
{
"chapters": [
{ "start": 0, "end": 612.0, "title": null },
{ "start": 612.0, "end": 1455.3, "title": null },
{ "start": 1455.3, "end": 2890.0, "title": null }
]
}An MKV with no Chapters element
Not every MKV has chapters — a straight remux of a chapterless source has none. The empty array is the correct answer.
Input: remux.mkv (no Chapters element)
Output: remux-chapters.json
{
"chapters": []
}
→ Generate markers from cuts with scene-detector instead.Multi-language MKV — one title comes back
This MKV stored English and Japanese chapter names. FFmpeg surfaces the default; you get a single title string per chapter, not both languages.
Input: anime.mkv (en + ja ChapterDisplay)
Output: anime-chapters.json
{
"chapters": [
{ "start": 0, "end": 90.0, "title": "Opening" },
{ "start": 90.0, "end": 1380.0,"title": "Episode" }
]
}
// The Japanese ChapString is not returned — default language only.Filling null titles from a separate label list
When the rip gives null titles, merge in your own labels by index in a few lines — the JSON's array order matches disc order.
const { chapters } = require('./feature-chapters.json');
const labels = ['Cold open', 'Act 1', 'Act 2'];
const named = chapters.map((c, i) => ({ ...c, title: c.title ?? labels[i] }));
console.log(JSON.stringify(named, null, 2));Edge cases and what actually happens
MKV has no Chapters element
Empty arrayReturns { "chapters": [] }. A remux of a chapterless source, or an MKV recorded live without chapter authoring, simply has nothing to read. Use the scene-detector to derive cut timestamps from the video itself.
Chapter atom has start/end but no ChapterDisplay
title: nullMakeMKV and many rips write boundaries without names, so title is null. The timestamps are exact — see the cookbook example for filling labels in by index.
Multi-language chapter titles
Default readMatroska can hold the same chapter list in several ChapLanguages. FFmpeg surfaces the default/first title, so you get one title per chapter — there is no language-selection control in this tool.
WebM dropped instead of MKV
SupportedWebM is a Matroska subset; if it carries a Chapters element it reads identically. Most WebM web exports have none and return an empty array — that's expected, not a fault of the file type.
Nested / ordered chapters
FlattenedMatroska supports nested and ordered editions. FFmpeg's metadata read returns a flat list of atoms; you get one object per atom in file order, not a tree. Hierarchy is not represented in the JSON.
Hidden chapters in the MKV
May appearMatroska's ChapterFlagHidden is an authoring hint for players, not a strong filter in a metadata dump. Hidden atoms may still appear in the extracted list. Treat the JSON as the complete atom list and filter in your own code if needed.
Very large MKV (10 GB+)
SupportedHeader-only parsing (-c copy -t 0) means file size barely matters for speed. Free tier caps at 1 GB; raise the cap with Pro (10 GB) or Pro-media / Developer (100 GB).
Corrupt Matroska header
May failIf the EBML/Matroska header is damaged enough that FFmpeg can't open the file, no chapters print and a parse error may surface. Remux with mkvtoolnix or re-rip the source, then retry.
You want to write or edit MKV chapters
Read-onlyThis tool never modifies the MKV — it reads to JSON only. To author or rewrite Matroska chapters you need mkvtoolnix; this tool's job is the read side.
Frequently asked questions
Why is MKV better than MP4 for chapters?
Matroska was designed with a dedicated Chapters element supporting start/end times, multi-language titles, and nesting. MP4 carries chapters via QuickTime/Nero atoms, which work but are less expressive. Both read fine here — MKV just tends to carry richer metadata.
What does the output look like for an MKV?
Always { "chapters": [ { "start": <seconds>, "end": <seconds>, "title": <string or null> } ] }, saved as <filename>-chapters.json. Start/end are floating-point seconds and titles are verbatim or null.
Can I choose which language's chapter titles to extract?
No. Matroska can store titles in multiple languages, but this tool surfaces the default/first one per chapter — there's no language picker. You'll get a single title string, not all translations.
Why do my rip's chapters have null titles?
MakeMKV and similar rippers usually write chapter boundaries without names, so title is null. The timestamps are still accurate — fill in titles by index from the disc menu (see the cookbook).
Does it decode the whole MKV?
No. It runs -c copy -t 0 -f null -, which reads the header and demuxes nothing. Even a 4-hour 1080p MKV returns chapters in seconds because no frame is decoded.
Is anything uploaded?
No. FFmpeg.wasm runs in your browser; the MKV bytes stay local. Only an anonymous processed-counter is recorded server-side for signed-in dashboard stats.
Will WebM files work too?
Yes — WebM is a Matroska subset. If the WebM has a Chapters element it reads identically; most don't, so you'll often see an empty array, which is correct for that file.
Can it split the MKV at the chapter points?
No — it only reads markers to JSON. To cut an MKV into pieces use the video-splitter; for a single clean stream-copy cut, the lossless-trimmer.
How do I turn the JSON into podcast or YouTube timestamps?
Iterate the array and format start seconds to your target timecode. The JSON-export spoke's cookbook shows a YouTube MM:SS Title one-liner; the same map produces podcast chapter JSON.
Does it preserve nested/ordered chapters?
It returns a flat list of atoms in file order. Matroska's nesting and ordered editions are not represented as a tree in the JSON — each atom becomes one object.
How large an MKV can I process?
Free 1 GB, Pro 10 GB, Pro-media 100 GB, Developer 100 GB. Limits are by file size (streaming), not by duration. Header-only parsing keeps even the largest allowed file fast.
What if the MKV has hidden chapters?
Matroska's hidden flag is a player hint, so hidden atoms may still appear in the metadata dump. Treat the JSON as the full atom list and filter on your side if you need to drop hidden ones.
Privacy first
Every JAD Video tool runs entirely in your browser via WebCodecs and FFmpeg (WebAssembly). Your video files never leave your device — verified by zero outbound network requests during processing.