完结篇:关于 OpenH264 的谢幕

2025年3月22日 星期六

可能有人注意到我提到过从 Freedesktop SDK 中移除 OpenH264 的事情。在这里,我将尝试深入探讨一下这段历史、时间线以及导致最终决定的原因。

简单介绍

如果您不熟悉 Freedesktop SDK 项目:它最初是 Alexander Larsson 创建的 1.6 Flatpak runtime image,旨在为 Flatpaks 提供一个与宿主机无关的 "runtime"。此后,在 Codethink 和其他人的帮助下,它成长为一个由社区维护的独立项目,旨在提供 "一个最小的 Linux runtime"。

目前,它包括 org.freedesktop.{Sdk, Platform} Flatpak runtimes,以及一系列其他的 Flatpak extensions,例如 GL (Mesa) extensions、一个包含 Linux kernel、firmware 和 drivers 等内容的 bootable image stack,以及一系列 Docker images。

这些 runtimes(以及更广泛的 "Flatpak" 技术栈)构成了 GNOMEKDE Flatpak runtimes 的基础,它们共同被 2000 多个 Flatpaks 使用。而 bootable stack 和其他部分则构成了 GNOME OS 等的基础。

一些历史

H.264 是当今 使用最广泛 的 codecs 之一,但不幸的是,它拥有多项专利,并且其中一些专利 至今仍然有效。这样的专利阻碍了在基础 runtime 中发布处理该 codec 的软件(因为我们希望它能被各种供应商使用,并且没有任何法律上的灰色地带),这给所有相关人员带来了麻烦。

为了解决这个问题并向用户发布可用的软件,7 年前,在 2019 年,Tom Coldrick 将 OpenH264 extension 的前身,即 html5-codecs extension 添加到了 Freedesktop runtime 中。这个想法很简单——它将包含 FFMPEG 的内部 H.264 decoder,并且会是一个可选的 Flatpak extension,因为我们无法将其发布到 runtime 本身中。

快进几个月,在 2019 年 6 月,Robert McQueen 提出了一个 issue,建议将 Cisco 的 OpenH264(通常也称为 libopenh264)作为 runtime 的 extension 包含进来。

libopenh264 代码是开源的,但由于 H.264 的专利问题,任何供应商在法律上都不允许发布自己的 binaries。对此的解决方案是直接将 Cisco 未修改的 binaries 分发给用户,这样实际上就可以免除任何 royalties。但问题在于,这些 binaries 有 一些 license restrictions

因此,Endless 在那个时候为 Flatpak 添加了 extra-data 支持。这意味着 Flatpak extension 的 metadata 只会包含 Cisco binaries 的 URL、checksums 和一个 "recipe",用于从中创建一个可用的 extension。binary 会在最终用户的机器上、在一个 sandbox 内下载,然后执行 "recipe" 来创建一个可用的 extension。这完全避免了各种 "redistribution" 限制,因为我们并没有发布 binary 本身。

然而,这种方法仍然存在最后一个问题。除非最终用户的系统已经下载了 extension,否则 ABI 的一部分将从基础 runtime 本身中缺失。此外,extension 还会被 mount 到 Flatpak sandbox 内的一个非标准位置。因此,为了针对它进行构建,我们需要一个包含在 runtime 本身的 "public" library。

Endless 提出了一个名为 noopenhh264 的 stub OpenH264 library 来解决这个问题。它会与 Cisco 实际的 OpenH264 library 保持 ABI/API 兼容,并位于 runtime 内的 $libdir 中,以便软件链接到 libopenh264 并提供 fallback。在运行时,如果用户下载了实际的 OpenH264 extension,stub library 将通过 Flatpak 的 ld.so config 被 extension 中的 library 覆盖。瞧,您就拥有了一个可用的 OpenH264 设置!

OpenH264 extension 的开始

经过上述繁琐的细节,在 2019 年 8 月,Tom Coldrick 再次添加 了这个 "noopenh264" library 到 runtime,并设置了名为 org.freedesktop.Platform.openh264 的 extension point。

大约在那个时候,"stub" noopenh264 library 的开发也转移到了 Freedesktop SDK 旗下,而这个 extra-data extension 的开发则在一个 专用 repository 中进行。

我之前提到过 extra-data Flatpak extension 的 "recipe",它实际上只是一组在名为 apply_extra 的特殊文件中定义的命令,用于 stage 和 install source。例如,如果它是一个 .deb 文件,那么它将是一系列 arbsdtar 命令,用于提取它,然后将其安装到 Flatpak 的 extra-data prefix 中。

这里的关键在于,使用任何这样的 utility 都会使 extension 直接依赖于 Flatpak runtime 的特定 branch,以及由此提供的 API/ABI。

由于 Freedesktop runtime 的每个年度主要版本都是一个全新的 ABI,因此我们需要不断地为 OpenH264 extension 衍生新的 branches。例如,对于 libopenh264 的 2.1.0 版本,我们需要 org.freedesktop.Platform.openh264//2.1.0-{18.08, 19.08, 20.08} branches 用于 extension,依此类推。这将使在 Freedesktop runtime 本身中更新 extension 变得有些繁琐,对于我们的下游 runtimes 也是如此。

作为对此的解决方案,编写了一个自定义的 apply_extra 脚本,它只使用几个标准 headers,并且将 静态构建 到一个固定的 toolchain。

这意味着一些复杂性,因为我们不允许使用大多数可以简化此过程的方法,但同时也意味着最终的 extension 独立于 runtime API/ABI,并且构建在 "NoRuntime" 之上。

缺陷开始显现

尽管 Cisco 在维护方面存在一些问题,但整个设置在很长一段时间内都运行良好。然而,也存在一些缺陷。

我之前说过,每个供应商都必须分发 Cisco 托管在 https://ciscobinary.openh264.org 上的 binaries。不幸的是,至少从 2014 年起ciscobinary.openh264.org 缺少有效的 SSL certificate,并且 Cisco 既不提供 GPG signatures,也不提供像 SHA-256 这样的强 checksums 用于 binary releases。

这意味着我们无法验证 Cisco binaries 的真实性,从而使我们面临各种 MiTM 和 supply-chain vulnerabilities。我们联系了 Mozilla,并通过 Fedora/RedHat 敦促 Cisco 修复这个问题,正如您可以在线程中看到的评论,但什么也没有发生。

最近(大约在 2024-2025 年),这个 SSL 问题意味着该 domain 开始被 DNS 阻止,这会导致 extra-data 下载失败,从而破坏安装。

另一个关键问题是,如果 upstream 进行了安全修复,然后在发布时破坏了 ABI,我们将无法为 Flatpak runtimes 修复它。通过 extra-data 直接分发 binaries 意味着没有 cherry-picking patches 的余地,并且 ABI 的破坏意味着新版本只能进入 runtime 的新 branch。

我们真的别无选择。如果我们考虑到潜在的缺陷而放弃这个 extension,整个 Flatpak 用户群将失去 H.264 decoding 和 encoding 支持,因此我们不得不接受这种设置。

codecs-extra extension 的开始

大约在 2024 年 6 月,由于一系列安全问题,gdk-pixbuf 放弃了支持 许多 "fringe" loaders。由于我们不断分析稳定 branches 中的 ABI,我们立即注意到了这一变化。

为了弥补 dropped loaders,我们 决定webp, avif, jxl, heif 支持(通过 pixbuf loaders)添加到 runtime。大约在同一时间,Will Thompson 提出了一个 issue,建议将 libheif 添加到 runtime,并将有问题的 HEIC decoder 作为 runtime extension。

因此,我们决定,仅仅为了两个 libheif plugins 而创建另一个 extension 不值得维护,这些应该放在 ffmpeg-full extension 中(这是 html5-codecs extension 的继任者,创建于 2019-2020 年左右)。所以我 再次 添加libx265, libde265 和相应的 libheif plugins 到 ffmpeg-full extension。几个月后,我还 添加libx264 到其中,因为我们已经发布了 libx265,并且 Cisco 的 OpenH264 在 encoding 性能方面不太理想。

我对结果感到满意,所有这些都发布在了 Freedesktop SDK 24.08 中。但有些人因为合理的原因而不满意。

ffmpeg-full extension 被创建时,由于各种原因,它从未被添加到 runtime 或 SDK manifest 中。它作为一个可选的 "app" extension 存在——这意味着 app developers 需要在他们的 Flatpak manifest 中添加一个 short snippet 才能使用它。

这在某些方面是有问题的——有时 app developers 不知道 extension 或者他们需要它,并且 app manifest 中缺少允许使用 extension 的 snippet。这使得用户和开发者的体验有些糟糕。一旦我们开始在 ffmpeg-full 中发布 libheif,这个问题就变得稍微严重了,因为实际的 libheif library 在 runtime 中,但如果没有 extension,它就无法 decode 任何 HEIF/HEIC image。因此,extension 实际上是强制性的。Albert Astals Cid 是在 Flathub 上维护 KDE Flatpaks 的团队成员,他对此提出了抱怨,并且 Erick555 提出了一个 issue,讨论了将 ffmpeg-full 变成 runtime extension 的可能性。

最初,我出于各种原因不愿意这样做,并且情况再次有点超出我们的控制(这次是由于 H.265 的专利)。但我们询问了各个方面,例如 Endless,并且非常令人惊讶的是,事实证明没有人真正反对将其变为 runtime extension,甚至让它与 runtime 一起自动下载。

随着这个变化,我们决定再次重命名 ffmpeg-full extension,这次将其命名为 codecs-extra,以更好地反映它不仅会包含带有 patented parts 的 FFMPEG,还会包含其他处理 patented codecs 的 libraries。这有点类似于发行版为 patented 或 restricted codecs 提供的各种 "meta-packages"。

因此,种子被播下了,我 一个月前ffmpeg-full 切换到 codecs-extra

这应该会在 Freedesktop SDK 25.08 中发布。app developers 的主要变化是,不再需要类似这样的内容:

add-extensions:
  org.freedesktop.Platform.ffmpeg-full:
    version: '24.08'
    directory: lib/ffmpeg
    add-ld-path: .

在 manifest 中。org.freedesktop.Platform.codecs-extra 将由 runtime 自动安装,并且对用户可用。

放弃 OpenH264 extension

上面的 codecs-extra 更改意味着我们现在真的没有使用 org.freedesktop.Platform.openh264 的用例了,因为 codecs-extra 已经包含了 FFMPEG 的内部 H.264 decoder 和 libx264 encoder。

因此,我最初禁用了自动下载,并考虑到上面讨论的 OpenH264 的各种 "缺陷",我 提出了一个 issue,计划在 26.08 中将其 retire。

当在 libopenh264 中发现了一个 high severity flaw,影响了 2.5.0 及更早版本时,这种情况完全被推翻了。

Freedesktop runtime 的 23.08 branch 被锁定为 2.2.0,并且由于多个 ABI breaks 和 upstream 的 SONAME bumps,无法升级到修复后的版本。如我之前所说,Patching 也不是一个选项。

我们紧急采取措施来缓解这种情况。对于 23.08,我们决定进行 "ABI break" 并 删除 extension,因为更新是不可能的。所以我发表了一个有些吓人的 公告

但我们仍然有 24.08,它基于 2.4.1,并且由于 ABI bump,再次阻止了更新到修复后的版本,即 2.6.0。

然而,通过查看 2.4.1 和 2.6.0 之间的 commits,并通过 libabigail 分析 library,我们没有找到实际的 ABI break,并且考虑到 Cisco 过去进行了不必要的 SONAME bumps,我们尝试 patching 2.6.0 release 以提供旧的 ABI。

mess 与那个 venerable apply_extra,并编写了一个小型 utility 来 patching SONAMEs。但是 upstream 及时指出了 ABI break,这个想法不得不完全放弃。(在与 libabigail maintainer Dodji Seketeli 交谈后,我后来才发现 liabigail 无法显示 ABI break 的原因。)

然后,我们 要求 upstream 提供一个带有旧 ABI 的 patch release 2.5.1,令人惊讶的是,他们在几周内就做到了!这发布在 24.08.15 中,修复了 runtime 的 24.08 branch。

经过所有这些崩溃和额外的 "headache" 之后,我们没有人再觉得发布 openH264 extension 是一个好主意。因此,它被 删除 了 master branch,这意味着对于 25.08+,将不会有任何 org.freedesktop.Platform.openh264 extension 或 noopenh264

结语

考虑到所有因素,我认为并希望我们做出了正确的决定,并希望新的 org.freedesktop.Platform.codecs-extra 能够奏效。libx264, libx265 和其他 libraries 都是从 source 构建的,并且不涉及任何 binaries 或 extra-data。因此,从理论上讲,我们应该能够 patching 并修复将来出现的任何问题。

除了这些之外,我有点担心这种设置可能会出现法律问题,以及新的 extension 包含 "太多",但我们将不得不拭目以待事态的发展。

作为一个有趣的 tidbit,我不知道 Fedora 也在使用我们的 org.freedesktop.Platform.openh264 extension。我为他们造成了一些工作,因为 noopenh264 再次搬家,现在搬到了 Fedora,他们正在寻找方法来创建自己的 OpenH264 extension,类似于我们所做的方式。

我希望这里的经验可以帮助将来想要维护此类 extension 的任何人,并且这也将提醒我们,像这样的专利会导致多少额外的工作。