chromium_third_party_libjpeg_turbo:基于OpenHarmony的JPEG图像编解码项目

libjpeg-turbo是一种JPEG图像编解码器的库

分支92Tags1
文件最后提交记录最后更新时间
3 个月前
1 年前
1 年前
1 年前
3 个月前
1 年前
1 年前
5 年前
1 年前
5 年前
11 个月前
1 年前
1 年前
8 年前

背景

libjpeg-turbo 是一款 JPEG 图像编解码器,它借助 SIMD 指令在 x86、x86-64、Arm、PowerPC 和 MIPS 系统上加速基线 JPEG 压缩与解压缩,并在 x86、x86-64 和 Arm 系统上加速渐进式 JPEG 压缩。在这些系统上,在其他条件相同的情况下,libjpeg-turbo 的速度通常是 libjpeg 的 2-6 倍。在其他类型的系统上,凭借其高度优化的霍夫曼编码例程,libjpeg-turbo 仍能显著超越 libjpeg 的性能。在许多情况下,libjpeg-turbo 的性能可与专有的高速 JPEG 编解码器相媲美。

libjpeg-turbo 既实现了传统的 libjpeg API,也提供了功能相对精简但使用更直接的 TurboJPEG API。libjpeg-turbo 还具备色彩空间扩展功能,使其能够从 32 位和大端像素缓冲区(RGBX、XBGR 等)进行压缩,或将压缩数据解压缩至这些缓冲区,同时还提供了功能完备的 Java 接口。

libjpeg-turbo 最初基于 libjpeg/SIMD,这是由 Miyasaka Masaru 开发的 libjpeg v6b 的 MMX 加速衍生版本。2009 年,TigerVNC 和 VirtualGL 项目对该编解码器进行了大量增强,2010 年初,libjpeg-turbo 独立出来成为一个独立项目,旨在向更广泛的用户和开发者提供高速 JPEG 压缩/解压缩技术。libjpeg-turbo 是 JPEG 标准的 ISO/IEC 和 ITU-T 参考实现。

有关 libjpeg-turbo 的更多信息,请访问 https://libjpeg-turbo.org

资金支持

libjpeg-turbo 是一个独立的开源项目,但我们依赖赞助和资助的开发工作来维持这种独立性。确保 libjpeg-turbo 保持以社区为中心,不受任何单一组织议程影响的最简单方法是通过 GitHub 赞助我们的项目。所有赞助资金将直接用于资助维护 libjpeg-turbo、支持用户社区以及实施错误修复和具有战略重要性的功能所需的人力。

Sponsor libjpeg-turbo

许可证

libjpeg-turbo 受三个兼容的 BSD 风格开源许可证保护。有关许可证条款的汇总,请参阅 LICENSE.md

构建 libjpeg-turbo

完整的构建说明,请参阅 BUILDING.md

使用 libjpeg-turbo

libjpeg-turbo 包含两个可用于压缩和解压缩 JPEG 图像的 API:

  • TurboJPEG API
    此 API 提供了一个易于使用的接口,用于在内存中压缩和解压缩 JPEG 图像。它还提供了一些使用底层 libjpeg API 难以直接实现的功能,例如生成 planar YUV 图像以及对图像执行多个同时进行的无损变换。libjpeg-turbo 的 Java 接口就是基于 TurboJPEG API 编写的。对于 libjpeg-turbo 的初次使用者,推荐使用 TurboJPEG API。有关其用法示例,请参阅 tjcomp.ctjdecomp.ctjtran.cTJComp.javaTJDecomp.javaTJTran.java;API 文档请参阅 https://libjpeg-turbo.org/Documentation/Documentation

  • libjpeg API
    这是用于压缩和解压缩 JPEG 图像的事实上的行业标准 API。它比 TurboJPEG API 更难使用,但也更强大。libjpeg-turbo 中的 libjpeg API 实现与 libjpeg v6b 在 API/ABI 以及数学上都是兼容的。它还可以选择配置为与 libjpeg v7 和 v8 保持 API/ABI 兼容(见下文)。有关其用法示例,请参阅 cjpeg.cdjpeg.c;API 文档请参阅 libjpeg.txt

当两种 API 用于执行类似操作时,在性能上没有显著差异。

色彩空间扩展

libjpeg-turbo 包含一些扩展,允许直接从(或直接解压缩到)使用 BGR、BGRX、RGBX、XBGR 和 XRGB 像素顺序的缓冲区压缩 JPEG 图像。这是通过十个新的色彩空间常量实现的:

JCS_EXT_RGB /* 红/绿/蓝 / JCS_EXT_RGBX / 红/绿/蓝/x / JCS_EXT_BGR / 蓝/绿/红 / JCS_EXT_BGRX / 蓝/绿/红/x / JCS_EXT_XBGR / x/蓝/绿/红 / JCS_EXT_XRGB / x/红/绿/蓝 / JCS_EXT_RGBA / 红/绿/蓝/alpha / JCS_EXT_BGRA / 蓝/绿/红/alpha / JCS_EXT_ABGR / alpha/蓝/绿/红 / JCS_EXT_ARGB / alpha/红/绿/蓝 */

cinfo.in_color_space(压缩时)或 cinfo.out_color_space(解压缩时)设置为这些值之一,将使 libjpeg-turbo 在从 RGB 缓冲区压缩或向 RGB 缓冲区解压缩时,从像素的适当位置读取或写入红、绿、蓝值。

您的应用程序可以在编译时通过以下方式检查这些扩展是否存在:

#ifdef JCS_EXTENSIONS

在运行时,如果尝试将这些扩展与不支持它们的 libjpeg 实现一起使用,将导致“Bogus input colorspace”错误。应用程序可以捕获此错误,以测试运行时是否支持色彩空间扩展。

在解压缩期间使用 RGBX、BGRX、XBGR 和 XRGB 色彩空间时,X 字节是未定义的,并且为了确保最佳性能,libjpeg-turbo 可以将该字节设置为任何值。如果应用程序期望 X 字节用作 alpha 通道,则应指定 JCS_EXT_RGBAJCS_EXT_BGRAJCS_EXT_ABGRJCS_EXT_ARGB。当使用这些色彩空间常量时,X 字节保证为 0xFF,即表示不透明。

您的应用程序可以在编译时通过以下方式检查 alpha 通道色彩空间扩展是否存在:

#ifdef JCS_ALPHA_EXTENSIONS

libjpeg-turbo 源代码树中的 jcstest.c 演示了如何在编译时和运行时检查色彩空间扩展的存在。

libjpeg v7 和 v8 API/ABI 模拟

在 libjpeg v7 和 v8 版本中,新增了一些功能,这些功能需要扩展压缩和解压缩结构体。不幸的是,由于这些结构体是暴露的,对其进行扩展也必然会破坏与早期 libjpeg 版本的 ABI 向后兼容性。因此,为使用 libjpeg v7 或 v8 而构建的程序无法与 libjpeg-turbo 一起使用,因为 libjpeg-turbo 基于 libjpeg v6b 代码库。尽管 libjpeg v7 和 v8 的使用不如 v6b 广泛,但已有足够多的程序(包括一些 Linux 发行版)进行了切换,因此有需求在 libjpeg-turbo 中模拟 libjpeg v7 和 v8 的 ABI。不过需要注意的是,添加此功能主要是为了让那些已经编译为使用 libjpeg v7+ 的应用程序能够利用加速的基线 JPEG 编码/解码,而无需重新编译。libjpeg-turbo 并未声称支持 libjpeg v7+ 的所有功能,也未声称在所有情况下都能生成与 libjpeg v7+ 完全相同的输出(见下文)。

通过向 cmake 传递 -DWITH_JPEG7=1-DWITH_JPEG8=1 参数,您可以构建一个模拟 libjpeg v7 或 v8 ABI 的 libjpeg-turbo 版本,以便针对 libjpeg v7 或 v8 构建的程序可以与 libjpeg-turbo 一起运行。下一节将描述支持哪些 libjpeg v7+ 功能以及不支持哪些功能。

对 libjpeg v7 和 v8 功能的支持

完全支持

  • libjpeg API:解压缩器中的 IDCT 缩放扩展
    libjpeg-turbo 支持 IDCT 缩放,缩放因子为 1/8、1/4、3/8、1/2、5/8、3/4、7/8、9/8、5/4、11/8、3/2、13/8、7/4、15/8 和 2/1(仅 1/4 和 1/2 具有 SIMD 加速)。

  • libjpeg API:算术编码

  • libjpeg API:内存中的源和目标管理器
    见下文说明。

  • cjpeg:亮度和色度的单独质量设置
    请注意,libjpeg v7+ API 扩展以适应此功能只是为了方便。使用 libjpeg v6b 始终可以实现此功能(参见 rdswitch.c 中的示例)。

  • cjpeg:32 位 BMP 支持

  • cjpeg:-rgb 选项

  • jpegtran:无损裁剪

  • jpegtran:-perfect 选项

  • jpegtran:执行无损裁剪时强制指定宽度/高度

  • rdjpgcom:-raw 选项

  • rdjpgcom:区域设置感知

不支持

注意:在撰写本文时,已经对 DCT 缩放作为数据缩减手段和 SmartScale 作为质量改进手段的实用性进行了广泛研究。欢迎读者查阅 https://libjpeg-turbo.org/About/SmartScale 上的研究并得出自己的结论,但我们项目的普遍看法是,这些功能尚未证明具有足够的实用性,不足以证明将其包含在 libjpeg-turbo 中是合理的。

  • libjpeg API:压缩器中的 DCT 缩放
    cinfo.scale_numcinfo.scale_denom 会被静默忽略。在模拟 libjpeg v7+ API/ABI 时,支持 DCT 缩放并没有技术上的障碍,但如果没有 SmartScale 扩展(见下文),则只能使用 1/2、8/15、4/7、8/13、2/3、8/11、4/5 和 8/9 的缩放因子,实用性有限。

  • libjpeg API:SmartScale
    cinfo.block_size 会被静默忽略。SmartScale 是 JPEG 格式的一种扩展,允许使用 8x8 以外的 DCT 块大小。提供对这种新格式的支持是可行的(特别是在没有完全加速的情况下)。然而,在该格式成为官方行业标准或至少成为社区公认的解决方案之前,我们不愿实现它,因为无法确定它将来是否会发生变化以及如何变化。我们认为,SmartScale 作为一种无损格式或质量增强手段,其效用尚未得到充分证明,因此我们支持此功能的主要兴趣在于提供额外的 DCT 缩放因子。

  • libjpeg API:压缩器中的精细下采样
    cinfo.do_fancy_downsampling 会被静默忽略。此功能需要 DCT 缩放特性,而该特性不受支持。

  • jpegtran:缩放
    此功能需要 DCT 缩放和 SmartScale 特性,而这两者均不受支持。

  • 无损 RGB JPEG 文件
    此功能需要 SmartScale 特性,而该特性不受支持。

关于 libjpeg v9

libjpeg v9 在 JPEG 压缩结构中新增了一个字段(color_transform),这导致其 ABI 与 libjpeg v8 不向后兼容。引入这个新字段的唯一目的是支持无损 SmartScale 编码。此外,实际上没有理由以这种方式扩展 API,因为完全可以通过新的 JPEG 色彩空间常量来激活色彩变换,从而保持 ABI 向后兼容。

我们的研究(参见上面的链接)表明,无损 SmartScale 通常无法实现现有标准无损格式已能更好完成的任何功能。因此,目前我们认为,软件项目从 libjpeg v8 升级到 libjpeg v9 缺乏足够的技术理由,因此我们也没有足够的技术理由去模拟 libjpeg v9 的 ABI。

内存源/目标管理器

默认情况下,即使不模拟 libjpeg v8 API/ABI,libjpeg-turbo 1.3 及更高版本也包含 jpeg_mem_src()jpeg_mem_dest() 函数。以前,必须通过源代码构建具有 libjpeg v8 API/ABI 模拟功能的 libjpeg-turbo,才能使用内存源/目标管理器,但有多个项目要求在模拟 libjpeg v6b API/ABI 时也包含这些函数。这样一来,需要这些函数的程序可以使用它们,而不会破坏不需要这些函数的程序的 ABI 兼容性,并且可以在“官方”libjpeg-turbo 二进制文件中提供这些函数。

请注意,在大多数 Un*x 系统上,动态链接器在实际使用某个函数之前不会在库中查找该函数。因此,如果某个程序是针对 libjpeg-turbo 1.3+ 构建的,并且使用了 jpeg_mem_src()jpeg_mem_dest(),那么在运行时使用旧版本的 libjpeg-turbo 或 libjpeg v7- 时,该程序不会失败,除非程序实际尝试调用 jpeg_mem_src()jpeg_mem_dest()。Windows 系统则并非如此。如果某个程序是针对 libjpeg-turbo 1.3+ DLL 构建的,并且使用了 jpeg_mem_src()jpeg_mem_dest(),那么它在运行时必须使用 libjpeg-turbo 1.3+ DLL。

cjpeg 和 djpeg 都已扩展,允许测试内存源/目标管理器函数。有关更多详细信息,请参阅它们各自的手册页。

数学兼容性

在大多数情况下,libjpeg-turbo 应能生成与 libjpeg v6b 完全相同的输出。但存在两个例外情况:

  1. 当解压缩使用 4:4:0 色度二次采样的 JPEG 图像时,libjpeg v6b 和 libjpeg-turbo 的输出可能会有所不同,因为 libjpeg-turbo 实现了一种“高级”(平滑)4:4:0 上采样算法,而 libjpeg 并未实现。

  2. 当使用浮点 DCT/IDCT 时,libjpeg v6b 和 libjpeg-turbo 的输出可能会因以下原因而不同:

    • libjpeg-turbo 中的 SSE/SSE2 浮点 DCT 实现比 libjpeg v6b 中的实现精度略高,但这种差异人类视觉无法察觉(通常 PNSR 增益在 0.01 至 0.08 dB 范围内)。

    • 当不使用 SIMD 扩展时,libjpeg-turbo 使用 libjpeg v8a 中引入的更精确(且速度略快)的浮点 IDCT 算法,而非 libjpeg v6b 中使用的算法。然而需要注意的是,该算法基本上使浮点 IDCT 的精度与精确整数 IDCT 的精度保持一致。浮点 DCT/IDCT 算法主要是一项遗留功能,它们并未比精确整数算法产生显著更高的精度。(具体来说,两种算法之间的 PNSR 典型差异小于 0.10 dB,而在质量等级上限将质量级别更改 1,通常会产生约 1.0 dB 的差异。)

    • 如果在特定平台上未使用 SIMD 指令实现 libjpeg-turbo 中的浮点算法,则浮点 DCT/IDCT 的精度可能取决于编译器设置。

尽管 libjpeg-turbo 模拟了 libjpeg v8 的 API/ABI,但在底层它仍使用与 libjpeg v6b 相同的算法,因此在以下几种特定情况下,不能期望 libjpeg-turbo 生成与 libjpeg v8 相同的输出:

  • 当使用 1/2 和 1/4 的缩放因子进行解压缩时,因为 libjpeg v8 实现这些缩放算法的方式与 libjpeg v6b 不同,而 libjpeg-turbo 的 SIMD 扩展基于 libjpeg v6b 的行为。

  • 当使用色度二次采样时,因为 libjpeg v8 通过其 DCT/IDCT 缩放算法实现此功能,而非使用单独的下采样/上采样算法。在我们的测试中,由于这个原因,libjpeg v8 的二次采样/上采样输出精度低于 libjpeg v6b。

  • 当使用大于 1 的缩放因子并结合(也称为“非高级”或“非平滑”)色度上采样进行解压缩时,因为 libjpeg v8 不支持缩放因子大于 1 时的合并上采样。

性能陷阱

重启标记

libjpeg-turbo 中优化的霍夫曼解码器处理重启标记的方式无法让 libjpeg 的其他基础架构正常工作,因此在解压缩包含重启标记的 JPEG 图像时,必须使用慢速霍夫曼解码器。这可能会导致解压缩性能下降多达 20%,但性能仍将远高于 libjpeg。许多消费类软件包(如 Photoshop)在生成 JPEG 图像时会使用重启标记,因此这些程序生成的图像会遇到此问题。

高质量级别下的快速整数前向 DCT

当将快速整数前向 DCT 与 98-100 的 JPEG 质量一起使用时,SIMD 加速量化函数所使用的算法无法产生正确结果。因此,在这些情况下,libjpeg-turbo 必须使用非 SIMD 量化函数。这会导致性能下降多达 40%。因此,强烈建议在编码 JPEG 质量为 98 或更高的图像时,使用精确整数前向 DCT。

内存调试器陷阱

当与 libjpeg-turbo 的 SIMD 扩展一起使用时,Valgrind 和内存 sanitizer (MSan) 可能会产生误报(具体而言,是对未初始化内存访问的错误报告)。通常建议在使用 Valgrind、MSan 或其他内存调试器测试 libjpeg-turbo 时,禁用 SIMD 扩展,方法是在配置构建时向 cmake 传递 -DWITH_SIMD=0 参数,或者在运行时将环境变量 JSIMD_FORCENONE 设置为 1

项目介绍

libjpeg-turbo是一种JPEG图像编解码器的库

定制我的领域