libass 源码阅读(0)开始

发布日期:分类:Aegisub

前言

在字幕渲染领域,libassxy-VSFilter 可以说是两架马车。libass 使用 C 语言编写,根据 Google Code 存档的说法,在大多数情况下 libass 的效率比 xy-VSFilter50%。从支持的角度来看,ffmpeg 支持 libass 而非 xy-VSFilter,而 Linux 版本的 Aegisub 也只有 libass 可以选用。

最初对 libass 源码的兴趣源于 vsfiltermod 中的 \fsc 标签。根据描述,其功能近似于同时设置 \fscx\fscy,而在实验中,我发现 libass 也会解析 \fsc,但其只会将字体大小复位,和 vsfiltermod 的效果不同。由此,我开始了对 libass 源码的探索之旅。

本系列使用的 libass 源码的 commit hashd149636[1],对应 libass 版本号为正式版 0.15.0

基本流程

我们的样例是 test/test.c。这个样例的功能是调用 libass,读取字幕文件并输出某一秒的渲染结果为 png 图片。通过梳理源码,我们可以整理出简单的程序执行流程,如图 1 所示:

图 1 – libass 测试样例的执行流程图

图中实心箭头表示这个样例中主干部分的执行流程,而空心箭头则表示了详细的内部调用过程。这里我们只列出了大致的调用流程,省略了错误处理等情况。

简单梳理一下,图 1 中相对重要的部分有:font_providerass_libraryass_rendererass_read_fileass_render_frame,分别对应了 libass 中的字体ASS LibraryASS RendererASS Track实际渲染部分。暂时忽略实际渲染,我们来看一看剩下的四个概念。

字体

字幕字幕,核心是。既然有字那就必然存在字体libass 中字体相关的架构如图 2 所示:

图 2 – 字体相关功能在 LibraryRenderer 的分布

可以看到,字体的来源有两种:内嵌字体(Embbed Font)和外部字体。内嵌字体位于 ASS 文件的字体行中;而外部字体则和不同的操作系统有着密切的联系,libass 把对这部分的抽象命名为 Font Provider

不同的操作系统对外部字体的支持方式不尽相同。如 AppleCore Text[2],Win32DirectWrite[3],Linuxfontconfig[4] 等,各自都是互不相同的字体实现方案。

样例通过 ass_get_available_font_providers 函数获取了系统中可用的字体实现方案。

ASS Library

从功能角度而言,ASS_Library 的职责并不单一:主要负责内嵌字体样式相关的内容,同时也兼任消息回调的执行。

TODO: 将代码修改为图表形式

struct ass_library {
    char *fonts_dir;
    int extract_fonts;
    char **style_overrides;

    ASS_Fontdata *fontdata;
    int num_fontdata;
    void (*msg_callback)(int, const char *, va_list, void *);
    void *msg_callback_data;
};

typedef struct ass_library ASS_Library;

libass 中,ASS_Library 还算常见。当你遇到它但又不记得具体功能时,回来看看就行了。

消息回调(msg_callback

libass 通过消息回调向外界输出日志。为使这个过程更加灵活,libass 使用了消息回调的方式,调用用户定义的 msg_callback 函数进行输出。样例在渲染米粒垃圾 393 回 omake 时的日志输出如图 3 所示:

图 3 – test 渲染 ミリラジ 393 回 omake 第 10 秒时的日志输出

ASS Renderer

作为字幕渲染库,libass 的本质工作终究还是渲染。ASS_Renderer 就是 libass 中负责渲染的核心组件。

ASS Renderer 中记录了渲染所需的全部信息。由于这个部件过于复杂,我们之后单独论述。

Ass Track

正确读入 ass 字幕文件是渲染的前提,libass 中通过 ASS_Track 存储字幕,其基本结构如图 4 所示:

图 4 – 字幕解析存储格式

可以看到,ASS Track 包含了一个字幕文件的全部信息,而 ASS ParserPriv 则包含一些解析时会用到的非公开信息。

小结

通过 test/test.c 的示例,我们简单梳理了 libass 中的一些基本概念。本文也是继技术型博客行文迷思(1)之后的第一篇博客,期待各位在可读性、流畅性等方面提出宝贵意见(笑)。

参考

  1. https://github.com/libass/libass/releases/tag/0.15.0
  2. https://developer.apple.com/documentation/coretext
  3. https://docs.microsoft.com/en-us/windows/win32/directwrite/direct-write-portal
  4. https://wiki.archlinux.org/index.php/Font_configuration_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)

1条评论

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注