Differences between Libass and VSFilters - TheOneric/libass GitHub Wiki

Though libass generally aims at compatibility with (Guliverkli2) VSFilter, there are still some differences. A few of them deliberate, some are result of libass' ASS extensions, for others just no one found time to fix it yet or fixing it is difficult and sometimes even the VSFilter variants are not doing the same thing.

This list is meant to give subtitle authors (and API-users) an idea of what future changes should be anticipated and which VSFilter-incompatibilities can be considered "features" rather than bugs and will stay.

Other differences not listed here on this page, and which are not related to libass' ASS extensions, are likely a bug and should be fixed eventually. Take a look at the issue tracker to get a list of them. If you are seeing a difference not listed here and not yet reported, please consider doing so.

Deliberate or Cannot be changed

These changes from *VSFilter are deliberate and won't be changed in libass. Although still an incompatibility, emulating *VSFilter in these cases will likely do more harm than good.
So you can probably rely on the current behaviour of libass to remain the default (it's still an incompatibility, so keep it in mind when writing portable scripts)

VSFilter parses some HTML tags
libass will not [ref]
Borderwidth and transforms
VSFilter's border widths are unaffected by transforms. This is usually undesirable for typesets and doesn't matter otherwise, which is why libass will not reproduce VSFilter's behaviour in that case. (see here for example)
ScaledBorderAndShadow for ffmpeg files
Between 2010 and 2014, ffmpeg generated files could only be played with libass, due to relying on a libasss extension. Between 2014 and 2020 ffmpeg could be played by both *VSFilter and libass, but it did not set the ScaledBorderAndShadow header even though it was clearly expected to default to yes (which was libass' behaviour at the time). libass has since changed its default to match VSFilter, but still uses ScaledBorderAndShadow: yes as the default iff the value was not set explicitly and the file either has
  • custom format lines (can't be played with *VSFilter anyway)
  • has a ; Script generated by FFmpeg/Lavf signature line and matches typical properties of ffmpeg generated files.
Windows Version and Regional Settings
Some of VSFilters behaviours, like font selection or some bidi and rtl-charateristics are influenced by Windows' regional setting and sometimes the version of Windows even for the very same VSFilter version. The regional setting will not be emulated by libass and in case of differences between Windows versions libass may select any version depending on criteria like current and historic prevelance, usefulness or anything else. (eg here for version difference)

Longstanding Issues

These incompatibilities are known for a long time, but they are either low prio or we didn't have the time to fix them yet. They are still incopatibilities though and you must not rely on the current behaviour as it may change to match VSFilter at any time.

They are listed here merely for informational purposes to avoid accidental reliance on the current state.

Automatic Linebreaking and WrapStyle
Auto linebreak produces slightly different results in libass and VSFilter. Note that typesets should not rely on automatic linebreaks and use \N anyway, so this is unlikely to cause any problems and some even prefer libass' line breaking results. [ref]
Also libass doesn't implement WrapStyle modes 0 and 3 as per "spec", but tries to equalise the line length across all lines (comments in code and [ref] )
fadeaway{width,height}
Libass currently ignores the (optional) fadeawayheight field of the Banner effect and the (optional) fadeawaywidth field of the Scroll up and Scroll down effects.
( [ancient src] and current[2] source code)
Style Encoding and \fe
Libass currently ignores the Encoding field of Style definitions and the corresponding \fe override tag (except the special value -1, which is a libass extension). In most VSFilters, any value other than 1 limits font selection to fonts that claim to support (have good glyph coverage for) the corresponding Windows code page, and other fonts are not used even if the FontName matches their name. This has historically been used as a shortcut for selecting a known default font, e. g. \fe2 to select Wingdings or Encoding=0 to select Arial. Good scripts should instead specify the exact desired font name and set Encoding to either 1 or a value known to be supported by the desired font.
Collision header
There's also the Collision header, which is being parsed by VSFilter (see: "$Guliverkli2"/src/subtitels/STS.cpp:1369) but not libass. However, it appears like even VSFilter doesn't do anything with the value after parsing (src/subtitles/RTS.cpp:1131).
v4.00++
VSFilter supports a 4.00++ Script Version, see: "$Guliverkli2"/src/subtitels/STS.cpp:1367.
It splits vertical margin into separate properties for top and bottom and adds a relativeTo property to Styles. The latter appears to be implemented inconsistent between guliverkli, guliverkli2, xy-VSFilter and MPC-HC and we assume its intended purpose was to distinguish types from dialogue, allowing the latter to be placed outside the actual video area.
It also added \kt but it is available to all format versions and already implemented in libass.

Inter-VSFilter Compatibility issue

In case of inter-VSFilter compatibility issues libass mostly follows xy-VSFilter or Guliverkli2-VSFilter. (RFC: is this correct?)

  • MPC-HC ISR

    • BorderStyle=3 is scaled differently in MPC-HC than in libass' and other VSFilters.
    • BorderStyle=3 and \bord0 does not display any box in libass and other VSFilters, but used to draw a minimal bounding box in MPC-HC. As of 1.9.23 (2022-08-26) and possibly a bit earlier already this is no longer the case.
    • It behaves different with regards to 3D-rotations, blur, and with SBAS=no borders and shadows if the subtitle’s PlayRes does not match the video resolution
    • An empty or no YCbCr Matrix header at all doesn’t use TV.601 but the video’s colour matrix for initial conversion, breaking compatibility with e.g. old guliverkli(2) scripts. There’s still minor mangling due to imprecisions and potentially limited TV-range. Non-empty, unknown YCbCr Matrix values effectively use TV.601.
      YCbCr Matrix: None is only supported since 1.9.24 (2022-11-12) and does actually fully avoid mangling by using untouched RGB values. (see: corresponding MPC-HC issue)
    • Encoding=0 is ignored since 1.9.23 (2022-08-26), allowing any font to match (like libass but not like other VSFilters).
      In 1.9.23 (but not 1.9.24 or later, 2022-11-12), and in MPC-BE since 1.6.4, all Encoding values are ignored.
  • Guliverkli and MPC-HC

    • support for fractional values for eg font sizes was not present in original VSFilter or Guliverkli2, but was added in many renderers — except MPC-HC. [ref]
  • xy-VSFilter

    • Unlike XySubFilter, xy-VSFilter does not know the actual video colourspace and guesses based on resolution for YCbCr Matrix: None
  • The aforementioned differences caused by Windows version and the regional setting

    • Not really a difference between differnt VSFilters per se, but still a difference you can encounter between specific installations of (possibly identical) VSFilters.
  • Nested Parentheses

    • Original VSFilter does not parse nested parantheses so in \t(1,500,\1c(&HFFAA03)\fsc500) the scaling is not part of the t-tag! VSFilterMod (which only targets hardsubs anyway), MPC-HC and for a few releases also XySubFilter did change this to parse nested parantheses. However, this is causes problems with existing subs, therefore most VSFilters and libass do not parse nested parantheses. If you want to be compatible with either variant you must balance your parantheses and the first closing paranthesis must only be followed by other closing parantheses until they are balanced again.

Notable Historic Differences

In the past libass used for a long time to treat BiDi more like would be expected by regular text renderig software. However, this was problematic as it is not compatible with VSFilter and so caused many issues for sub authors. Since 0.16.0, libass now emulates VSFilter behaviour by default and the old behaviour is retained in the libass-specific Encoding: -1 extension.
If some old file using RTL or BiDI has a messed up word ordering in both VSFilters and modern libass, changing the encoding to -1 may potentially improve the rendering.

LayoutRes

The introduction of LayoutRes{X,Y} headers was coordinated between active VSFilters and libass, so admittedly this doesn't quite fit on this page. But anyway, here are the times and versions when each renderer added support for this new header pair:

renderer commit release
libass 1a533e5 (2022-11-28) 0.17.0 (2022-11-30)
Cyberbeing/xy-VSFilter xy-VSFilter: 6ee748 (2023-01-05);
XySubFilter: 8b9d9b3 (2023-01-05)
(no yet, last without: xy-VSFilter 3.0.0.306
and XySubFilter 3.1.0.752)
pinterf/xy-VSFilter 15390e5 (2023-01-18) 3.2.0.809 (2024-01-02)
MPC-HC ISR several commits, starting with b3b5c26 (2022-11-29) 2.0.0 (2023-01-11)

2: 01.06.2020

⚠️ **GitHub.com Fallback** ⚠️