{
  "schemaVersion": 1,
  "contentVersion": "ca42e61ede0a24f789d7287a0001244ad22f4abf",
  "id": "docs/codecs/subtitles",
  "collection": "docs",
  "title": "Subtitle formats overview",
  "description": "A comparison of SRT, ASS, WebVTT and image-based subtitle formats, which containers carry them, and how to convert, mux or burn them in with FFmpeg.",
  "canonicalUrl": "https://encode.wiki/codecs/subtitles/",
  "apiUrl": "https://encode.wiki/api/v1/documents/docs/codecs/subtitles.json",
  "markdownUrl": "https://encode.wiki/api/v1/markdown/docs/codecs/subtitles.md",
  "status": "current",
  "tags": [
    "subtitles",
    "overview"
  ],
  "license": "CC BY-SA 4.0",
  "dates": {
    "lastVerified": "2026-10-08T00:00:00.000Z"
  },
  "authors": [],
  "sources": [
    {
      "title": "WebVTT: The Web Video Text Tracks Format (W3C)",
      "url": "https://www.w3.org/TR/webvtt1/",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "Matroska codec mappings — subtitles",
      "url": "https://www.matroska.org/technical/codec_specs.html",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "FFmpeg subtitle filters",
      "url": "https://ffmpeg.org/ffmpeg-filters.html#subtitles-1",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "FFmpeg overlay filter",
      "url": "https://ffmpeg.org/ffmpeg-filters.html#overlay-1",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "libass",
      "url": "https://github.com/libass/libass",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "IMSC — TTML profiles for Internet media subtitles and captions",
      "url": "https://www.w3.org/TR/ttml-imsc/",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    }
  ],
  "headings": [
    {
      "depth": 2,
      "text": "Choosing a format",
      "anchor": "choosing-a-format"
    },
    {
      "depth": 2,
      "text": "Where each container can put them",
      "anchor": "where-each-container-can-put-them"
    },
    {
      "depth": 2,
      "text": "Converting between formats",
      "anchor": "converting-between-formats"
    },
    {
      "depth": 2,
      "text": "Muxing subtitles",
      "anchor": "muxing-subtitles"
    },
    {
      "depth": 2,
      "text": "Burning subtitles into the video",
      "anchor": "burning-subtitles-into-the-video"
    },
    {
      "depth": 2,
      "text": "Encoding problems",
      "anchor": "encoding-problems"
    }
  ],
  "sections": [
    {
      "id": "_preamble",
      "title": "Page introduction",
      "depth": 0,
      "canonicalUrl": "https://encode.wiki/codecs/subtitles/",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/codecs/subtitles/_preamble.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/codecs/subtitles/_preamble.md",
      "checksum": "8712cb177b0341bec28ad2124ac32ed841c5070568ebba15760c1f446156e8cc",
      "bytes": 298
    },
    {
      "id": "choosing-a-format",
      "title": "Choosing a format",
      "depth": 2,
      "anchor": "choosing-a-format",
      "canonicalUrl": "https://encode.wiki/codecs/subtitles/#choosing-a-format",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/codecs/subtitles/choosing-a-format.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/codecs/subtitles/choosing-a-format.md",
      "checksum": "a86453d0bc734694a922e1f51fba1d002d3624bd39d63b507c279140d9ed6735",
      "bytes": 2099
    },
    {
      "id": "where-each-container-can-put-them",
      "title": "Where each container can put them",
      "depth": 2,
      "anchor": "where-each-container-can-put-them",
      "canonicalUrl": "https://encode.wiki/codecs/subtitles/#where-each-container-can-put-them",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/codecs/subtitles/where-each-container-can-put-them.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/codecs/subtitles/where-each-container-can-put-them.md",
      "checksum": "583490b249d1c8d4af5f2782643ae2cb32ae0ebf767adb79977be54f8beb3b69",
      "bytes": 612
    },
    {
      "id": "converting-between-formats",
      "title": "Converting between formats",
      "depth": 2,
      "anchor": "converting-between-formats",
      "canonicalUrl": "https://encode.wiki/codecs/subtitles/#converting-between-formats",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/codecs/subtitles/converting-between-formats.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/codecs/subtitles/converting-between-formats.md",
      "checksum": "d4f75077b3424d56a8e8efda23748af7465e54bbc08881baf6a4a10c3aa6ba29",
      "bytes": 705
    },
    {
      "id": "muxing-subtitles",
      "title": "Muxing subtitles",
      "depth": 2,
      "anchor": "muxing-subtitles",
      "canonicalUrl": "https://encode.wiki/codecs/subtitles/#muxing-subtitles",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/codecs/subtitles/muxing-subtitles.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/codecs/subtitles/muxing-subtitles.md",
      "checksum": "2cb47d26d19d49e9c063298bd3517f83b051f388e7bffb85295a93cc1987bf4d",
      "bytes": 488
    },
    {
      "id": "burning-subtitles-into-the-video",
      "title": "Burning subtitles into the video",
      "depth": 2,
      "anchor": "burning-subtitles-into-the-video",
      "canonicalUrl": "https://encode.wiki/codecs/subtitles/#burning-subtitles-into-the-video",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/codecs/subtitles/burning-subtitles-into-the-video.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/codecs/subtitles/burning-subtitles-into-the-video.md",
      "checksum": "70bdac9f5dc27d728b32804f59e64315a3895bad23f44d43c4181129dd0b24b2",
      "bytes": 1549
    },
    {
      "id": "encoding-problems",
      "title": "Encoding problems",
      "depth": 2,
      "anchor": "encoding-problems",
      "canonicalUrl": "https://encode.wiki/codecs/subtitles/#encoding-problems",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/codecs/subtitles/encoding-problems.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/codecs/subtitles/encoding-problems.md",
      "checksum": "9aac801a9f354f4ab48558d488a4a00336460a805b249cb21d9af6c2cdb98ace",
      "bytes": 264
    }
  ],
  "outboundReferences": [
    "/codecs/subtitles/srt/",
    "/codecs/subtitles/ssa/",
    "/codecs/subtitles/webvtt/",
    "/containers/matroska/",
    "/containers/mp4/",
    "/containers/webm/"
  ],
  "checksum": "04ac4147fe00611d0b2504d5615e9b975f224c665619e134378a6d22ec096406",
  "contentFormat": "markdown",
  "markdown": "Subtitle formats fall into three families: plain or lightly styled **text** (SRT, WebVTT), fully styled **script** text (ASS/SSA), and **images** (PGS from Blu-ray, VobSub from DVD). Which one you want depends on where the video will be played, and converting between them usually loses something.\n\n## Choosing a format\n\n| Format                              | What it is                                            | Use it for                                                       | Carried in                                     |\n| ----------------------------------- | ----------------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------- |\n| [SRT](/codecs/subtitles/srt/)       | Timed text with `<i>`, `<b>`, `<u>`, `<font>` tags    | Anything that just needs dialogue; the lowest common denominator | `.srt`, MKV (`S_TEXT/UTF8`), MP4 as `mov_text` |\n| [ASS/SSA](/codecs/subtitles/ssa/)   | Styled script: fonts, colours, positioning, animation | Anime fansubs, typeset signs and songs, karaoke                  | `.ass`, MKV (`S_TEXT/ASS`)                     |\n| [WebVTT](/codecs/subtitles/webvtt/) | SRT-like text with cue positioning and CSS styling    | Web video (`<track>`), HLS                                       | `.vtt`, WebM, MKV                              |\n| PGS (`.sup`)                        | Blu-ray bitmaps                                       | Keeping Blu-ray subtitles exactly as authored                    | MKV (`S_HDMV/PGS`), M2TS                       |\n| VobSub (`.idx` + `.sub`)            | DVD bitmaps                                           | Keeping DVD subtitles                                            | MKV (`S_VOBSUB`), VOB                          |\n| TTML / IMSC                         | XML timed text                                        | Broadcast and streaming-service deliverables                     | Separate files, DASH/CMAF segments             |\n| CEA-608/708, DVB                    | Broadcast caption systems                             | TV broadcast and recordings                                      | Embedded in video or MPEG-TS                   |\n\nText formats stay small, searchable, and resizable by the player. Image formats look exactly like the original but cannot be edited, restyled, or searched without OCR.\n\n## Where each container can put them\n\n| Container                         | Text subtitles                      | Image subtitles |\n| --------------------------------- | ----------------------------------- | --------------- |\n| [Matroska](/containers/matroska/) | SRT, ASS/SSA, WebVTT                | PGS, VobSub     |\n| [MP4](/containers/mp4/)           | `mov_text` only (SRT-level styling) | Not portable    |\n| [WebM](/containers/webm/)         | WebVTT                              | None            |\n\nIf a player or device cannot show your subtitle format, the fallback is **burning it in** (see below).\n\n## Converting between formats\n\n```sh\nffmpeg -i subs.srt subs.ass\nffmpeg -i subs.srt subs.vtt\nffmpeg -i subs.vtt subs.srt\nffmpeg -i subs.ass subs.srt\nffmpeg -i input.mkv -map 0:s:0 subs.srt\n```\n\nGoing from a richer format to a poorer one loses information, and FFmpeg does not clean up after itself. ASS to SRT turns each style into `<font size=\"…\" color=\"…\">` wrappers (with the ASS script's sizes, meaningless to an SRT player), drops `\\pos` and leaves tags like `{\\an8}` in the text; ASS to WebVTT keeps italics and bold but drops styles and positioning. Always check the result, and keep the original. Converting image subtitles to text needs OCR (Subtitle Edit, for example); FFmpeg cannot do it.\n\n## Muxing subtitles\n\n```sh\nffmpeg -i video.mkv -i subs.srt -map 0 -map 1 -c copy -metadata:s:s:0 language=eng output.mkv\nmkvmerge -o output.mkv video.mkv --language 0:eng --track-name 0:\"English\" subs.srt\nffmpeg -i video.mkv -i subs.srt -map 0 -map 1 -c copy -c:s mov_text output.mp4\n```\n\nThe `--language 0:eng` option applies to the file that follows it (here `subs.srt`, track 0). To keep fonts for ASS subtitles, attach them to the MKV; see [SubStation Alpha](/codecs/subtitles/ssa/).\n\n## Burning subtitles into the video\n\nHard-coding the subtitles re-encodes the video, so it is a last resort for devices that cannot render soft subtitles:\n\n```sh\nffmpeg -i input.mkv -vf subtitles=input.mkv -c:v libx264 -crf 18 -c:a copy output.mp4\nffmpeg -i input.mkv -vf \"subtitles=subs.srt:force_style='FontSize=24,Outline=2'\" -c:v libx264 -crf 18 -c:a copy output.mp4\nffmpeg -i input.mkv -vf ass=subs.ass -c:v libx264 -crf 18 -c:a copy output.mp4\n```\n\n`subtitles` takes any text format FFmpeg can read and picks the first subtitle stream of the file (`:si=1` for the second); when the file is an MKV it also loads the attached fonts. `ass` only reads `.ass` files. Both need an FFmpeg built with libass.\n\nImage subtitles (PGS, VobSub) are burned in with the `overlay` filter instead:\n\n```sh\nffmpeg -i input.mkv -filter_complex \"[0:v][0:s:0]overlay=shortest=1\" -c:v libx264 -crf 18 -c:a copy output.mp4\n```\n\n`shortest=1` ends the output with the video. Without it, the last subtitle event (which has no end time) can stretch the output far past the end of the video, and an MP4 mux fails. If you are also downscaling, put the `scale` after `overlay` so the subtitles shrink with the picture.\n\nSRT has no style of its own, so FFmpeg converts it with a default ASS style. Override it with `force_style` using ASS style names (`FontName`, `FontSize`, `Outline`, `MarginV`). `FontSize` is measured against a 288-line script that libass scales to the video, so it is not a pixel size: 24 is a font size of 1/12 of the picture height at any resolution.\n\n## Encoding problems\n\nOld SRT files are often in a legacy codepage rather than UTF-8, which shows up as garbled accents. Tell FFmpeg what the file is with `-sub_charenc CP1252 -i subs.srt` (or `charenc=` on the filter), or convert with `iconv -f CP1252 -t UTF-8`.\n"
}
