惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
Netflix TechBlog - Medium
T
The Blog of Author Tim Ferriss
aimingoo的专栏
aimingoo的专栏
A
About on SuperTechFans
Stack Overflow Blog
Stack Overflow Blog
B
Blog RSS Feed
Microsoft Security Blog
Microsoft Security Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
人人都是产品经理
人人都是产品经理
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
J
Java Code Geeks
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
B
Blog
MongoDB | Blog
MongoDB | Blog
L
LangChain Blog
WordPress大学
WordPress大学
小众软件
小众软件
IT之家
IT之家
腾讯CDC
月光博客
月光博客
量子位
Blog — PlanetScale
Blog — PlanetScale
P
Proofpoint News Feed
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

Yesterday17's Blog

2026 新年解密红包 / Melody Flag | Yesterday17's Blog 谈谈 Iori 的设计思路(二):如何实现一个 Showroom 录制工具? | Yesterday17's Blog 谈谈 Iori 的设计思路(一):从 Nico Timeshift 说起 | Yesterday17's Blog Iori Minyami 0.1.0 发布 | Yesterday17's Blog 2025 新年解密红包 / Melody Flag | Yesterday17's Blog 使用 Cloudflare Warp 解决罗森票务的海外登录问题 | Yesterday17's Blog How To Blog 04: The Astro v5 Era | Yesterday17's Blog 谈谈 tokio::select! 的公平性 | Yesterday17's Blog Learning Pingora 05 - Connect with TLS | Yesterday17's Blog Leaving Bytedance | Yesterday17's Blog 大橋彩香 AsiaTour「Reflection」上海公演 个人向记录 & Repo | Yesterday17's Blog Recoving from burnout - What happened? | Yesterday17 Yubikey 重建手册 | Yesterday17's Blog How To Blog 03: Heimus | Yesterday17's Blog 🪧 Blog Migration Accouncement | Yesterday17's Blog Learn Your IDE - VSCode 是如何仅重启插件的? | Yesterday17's Blog How To Blog 02: Astro❤️Password | Yesterday17's Blog How To Blog 01: Why, How, and the Future | Yesterday17's Blog Learning Pingora 04 - Establish L4 Connection | Yesterday17's Blog Learning Pingora 03 - Upstreams and Peers | Yesterday17's Blog Learning Pingora 02 - A Simple HTTP Server | Yesterday17's Blog Learning Pingora 01 - Getting Started | Yesterday17's Blog 2024 新年解密红包 / Melody Flag | Yesterday17's Blog 向新的一年飞驰——记录 2023 | Yesterday17's Blog 「サクラノ刻」对话选摘(2) | Yesterday17's Blog PGP Key Revocation 注销声明 | Yesterday17's Blog 「サクラノ刻」对话选摘(1) | Yesterday17's Blog 2023 新年解密红包 / Melody Flag | Yesterday17's Blog 『蒼の彼方のフォーリズム』通关感想 | Yesterday17's Blog 单显卡直通教程 | Yesterday17's Blog
libass 源码阅读 00 - 开始 | Yesterday17's Blog
Yesterday17 · 2020-06-27 · via Yesterday17's Blog

ToC

  • 前言
  • 基本流程
  • 字体
  • ASS Library
    • 消息回调(msg_callback
  • ASS Renderer
  • Ass Track
  • 小结
  • 参考

前言

在字幕渲染领域,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 hash`d149636`[1],对应 libass 版本号为正式版 0.15.0

基本流程

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

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

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

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

字体

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

图 2 - 字体相关功能在 Library 和 Renderer 的分布
图 2 - 字体相关功能在 Library 和 Renderer 的分布

可以看到,字体的来源有两种:内嵌字体(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 秒时的日志输出
图 3 - test 渲染 ミリラジ 393 回 omake 第 10 秒时的日志输出

ASS Renderer

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

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

Ass Track

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

图 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)