# libass: a portable renderer for ASS and SSA subtitles

> libass is a portable C library that renders ASS and SSA subtitles, and its entire design goal is compatibility with VSFilter, the reference renderer for the format. It ships with two build systems, a large test and comparison corpus of its own, and an ISC licence.

**libass/libass** — libass is a portable subtitle renderer for the ASS/SSA (Advanced Substation Alpha/Substation Alpha) subtitle format.

- Repository: https://github.com/libass/libass
- Stars: 1,190 · Forks: 250
- Language: C
- License: ISC
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/libass-libass

## One library, one format, one reference

libass is a portable subtitle renderer for the ASS and SSA, Advanced Substation Alpha and Substation Alpha, subtitle format. It is written in C, it is cross platform, and the licence is ISC, which is the permissive licence most Linux distribution packaging and most commercial media players prefer.

The single sentence that defines the project is in the first paragraph of the README: it is mostly compatible with VSFilter.

That is the whole reason the library exists. ASS and SSA are not simple subtitle formats. They carry inline styling with override tags, drawing commands, vector graphics, karaoke effects, per-event positioning, alpha and colour control and a set of behaviours that were never written down as a formal specification but were instead defined by a particular renderer. VSFilter, which is also shipped inside MPC-HC, is the de facto reference. A renderer that matches VSFilter matches the expectations of the people who made the subtitles.

The word mostly in mostly compatible is doing real work. Perfect compatibility would be a stronger claim than a volunteer project should make, and the project's own list of alternative implementations, with several of them marked defunct, is a reminder that this is a compatibility problem with no final answer.

The current release is 0.17.5, published on 2026-06-24, with 0.17.4 from 2025-06-07 and 0.17.3 from 2024-07-02 before it. The repository is not archived, and the last push was on 2026-09-17.

## The field of other implementations, and what is left

The README includes a list of other ASS and SSA implementations, and it is the most useful thing in the document for anyone trying to understand the format's history.

The VSFilter family is listed first. There is xy-VSFilter and XySubFilter with its pfmod component, VSFilter as shipped inside MPC-HC, VSFilterMod with custom format extensions, and VSFilter in Guliverkli2. Several of these carry an explicit defunct note, and the reasons are given: VSFilterMod and its sorayuki fork are defunct and subsumed by forks, Threaded VSFilter is defunct, and VSFilter in Guliverkli is defunct and forked as Guliverkli2. There are also various forks focusing on internal use.

Then the older generation: ffdshow, Perian, asa, libjass and ASS.js, all marked defunct except ASS.js.

The list is effectively a map of where the reference implementation went. The VSFilter variants are forks of one another: Guliverkli was forked as Guliverkli2, and the surviving line is xy-VSFilter and the MPC-HC build. That is why a new project that wants to be compatible has to pick one of them to compare against, and why libass points at the VSFilter source code in Guliverkli2, which is the closest thing to a readable reference implementation of the renderer's behaviour.

The README also links the format documentation itself: the ASS File Format Guide in the project wiki, the Aegisub manual for the override tags, and the VSFilter source for the details the format guide does not cover.

## Two build systems and a clear rule for each

libass offers two build systems, and the README is unusually precise about which one to use when.

Autotools is preferred for development, because it integrates with the project's testing infrastructure and is feature-complete on all platforms that Autotools supports. If you are packaging libass for distribution, Autotools is the recommendation. When packaging for Windows, Meson should work equally well.

Meson lacks the integration with the testing infrastructure but works otherwise well on Windows. It is suited for static-only builds on any platform that Meson supports well, and for use as a Meson subproject. Notably, Meson supports MSVC and the generation of Visual Studio project files, which is the practical reason a Windows packager might reach for it.

The distinction that matters most to a contributor is the testing integration. If you are changing the renderer, you want the build that runs the test suite, and that is Autotools. The repository carries the pieces for both: configure.ac, autogen.sh, Makefile.am and Makefile_util.am for the Autotools path, and meson.build with meson_options.txt for the Meson path, plus the m4/ directory for the Autotools macros and the ltnasm.sh script that drives the NASM assembler for the hand-written assembly.

The package configuration is also there, with libass.pc.in as the pkg-config template, so linking against libass from a build system is a matter of pointing at the installed .pc file.

## A repository that is mostly test infrastructure

The top-level entries show how much of this project is verification rather than rendering.

There is a test/ directory, and separate checkasm/, compare/, fuzz/ and profile/ directories. The checkasm directory is the pattern used by assembly-heavy projects, a set of small programs that each check one assumption of the hand-written code, and the compare/ directory is for comparing output against reference renderers, which is the only sensible way to test a compatibility target. The fuzz/ directory holds fuzzing targets, which matters for a library that parses a text format that anyone can hand it. profile/ is for performance profiling.

The library itself lives in libass/, and the assembly pieces are assembled by ltnasm.sh, which points at the NASM assembler, so the project does use hand-written assembly for the hot paths. gen_defs.py is a script for generating definitions, which is what keeps the assembly and the C in step.

The legacy_arabic_cmap/ directory is a nice detail: it holds the old Arabic character map tables. That directory existing at all tells you the project takes the compatibility target seriously enough to keep the historical data around.

Around that are the ordinary files, with Changelog, RELEASEVERSION, MAINTAINERS, COPYING, a.mailmap for the author mapping and a.github/ directory. The CI badge points at a GitHub Actions workflow, and there is a Coverity scan badge, which is the static analysis service that has historically been used on C code of this kind.

## Debug macros, with no stability promise

There is a short section on macro defines, and it exists because libass has one knob worth setting while developing it.

Unless you are developing libass there is usually no need to manually define macros, and there are no stability guarantees for these manual defines.

The one macro is DEBUG_LEVEL, which takes a value from 0 to 3. A value of 0 uses the default set of asserts, and it is implied if the macro is not defined at all. Values 1 and 2 are unused. A value of 3 additionally asserts assumptions usually pledged to the compiler for optimisation purposes.

That third level is the interesting one. Assertions of the kind that the compiler is told to assume, such as alignment or non-nullness, are exactly the things a hand-written assembly routine can violate, and the level 3 setting is how you catch an assembly routine breaking an invariant the C code relies on. That is a debugging aid for the people working on the assembly, which is why the section is framed as a development note rather than a user feature.

For anyone embedding libass, the takeaway is simply that the default is what you want and that the macro names are not an interface. A library that documents its own build switches as unstable is being careful, and it is a good reminder to check what a dependency actually promises.

## How to reach the maintainers, and what to expect

The contact section is short and, unusually, it tells you what to expect from each channel.

Bugs and feature requests go to the issue tracker. There is also an IRC channel, on irc.libera.chat in the libass channel, and the README is candid about the limitations: the maintainers cannot be online all the time, and they cannot answer IRC questions if you leave the channel. Even if you do not get an immediate response, the advice is to keep your IRC client open, because they will eventually get back to you.

That is a useful thing to know before you post a question there, since a question asked in a channel you immediately leave is a question that goes unanswered, and the issue tracker is the durable place for anything that needs a record.

The packaging status is tracked with a Repology badge, which aggregates the versions of the library in the various Linux and BSD distribution repositories. For a library as widely packaged as this one, that badge is the most useful single indicator of how a change propagates, since a fix in master reaches users only as each distribution picks it up.

The changelog is in the repository, at the Changelog file, and it is linked from the Get it section as the detailed list of changes for each release. The repository is not archived, the licence is ISC, and the releases are versioned with a plain three-part scheme where 0.17.x is a stable line rather than an experiment.

## Conclusion

Adopt libass if you are building a media player that has to render styled ASS or SSA subtitles, because the format is the same one fans use for anime fansubs and the compatibility work is the hard part that has already been done. Do not adopt it if you only need plain SRT subtitles, since a much simpler parser will do, and do not expect the macro defines to be a stable interface, because the documentation says explicitly that there are no stability guarantees for manual defines. Before you start, pick the build system to match your distribution, using Autotools unless you are on Windows, and read the ASS format overview and the Aegisub override tag documentation, since the format's own documentation is where the rendering edge cases are explained.

## FAQ

### What is libass and what format does it render?

libass is a portable C library for rendering the ASS and SSA, Advanced Substation Alpha and Substation Alpha, subtitle format. It is mostly compatible with VSFilter, the reference renderer for that format, and it is released under the ISC licence.

### Which build system should I use for libass?

Autotools is preferred for development because it integrates with the testing infrastructure and is feature-complete on the platforms Autotools supports, and it is recommended for distribution packaging. Meson works equally well for packaging on Windows, supports MSVC and Visual Studio project generation, and is suited to static-only builds and use as a Meson subproject, but it lacks the testing integration.

### How does libass verify that it matches VSFilter?

The repository carries a compare/ directory for comparison against reference renderers, a checkasm/ directory of small programs that each check one assumption of the hand-written assembly, a fuzz/ directory for fuzzing the format parser, and a profile/ directory for performance work. The README also links the VSFilter source in Guliverkli2 as the closest readable reference.

### What does the DEBUG_LEVEL macro do in libass?

It takes a value from 0 to 3. Zero, the implied default when the macro is undefined, uses the default set of asserts, 1 and 2 are unused, and 3 additionally asserts assumptions usually pledged to the compiler for optimisation purposes, which is how the hand-written assembly is checked. The README states there are no stability guarantees for manual defines.

### Where should I report a bug in libass?

The issue tracker, for bugs and feature requests. There is also an IRC channel on irc.libera.chat in the libass channel, but the maintainers note they cannot be online all the time and cannot answer questions if you leave the channel, so keep the client open or use the tracker instead.

## Sources

- [Issues](https://github.com/libass/libass/issues)
- [libass/libass on GitHub](https://github.com/libass/libass)
- [License: ISC](https://github.com/libass/libass/blob/master/LICENSE)
- [README](https://github.com/libass/libass/blob/master/README.md)
- [Releases](https://github.com/libass/libass/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/libass-libass
