当你想到 Vimeo 时,你可能想到的是视频——毕竟,这是我们所做的事情。但是,我们也需要处理很多图像的创建和分发:缩略图、用户头像、频道标题,以及 Vimeo 上各种很棒的图形,仅举几例。
很长一段时间以来,所有这些内容都是静态的,并按原样从 CDN 提供。如果我们想引入新的视频分辨率,我们需要运行批处理作业来获取网站上所有视频的新、更高分辨率的缩略图(如果可能)。这也意味着,如果我们想调整这些图像的质量,我们就会很倒霉。这也意味着在移动设备或高 DPI 屏幕上,我们必须提供与我们主网站上相同大小的图像,除非我们想存储相同图像的更高或更低分辨率版本。
介绍 ViewMaster。
大约两年前,在我们的一次代码马拉松中,我们的移动网站开发人员之一向我们(转码团队)提出了这个问题,他们正在寻找一个后端解决方案。ViewMaster 当晚诞生,但由于工作量繁重,它在很长一段时间内处于闲置状态,直到几个月前才再次被启用。
我们将在下面详细介绍,但 ViewMaster 是什么以及它做什么的简要概述如下
- 使用 Go 和 C 编写。
- 实时调整大小、过滤、裁剪和编码(使用优化,例如 pngout 以不同的格式,完全在内存中进行)。
- 可以扩展;每个服务器都是“哑”的。
- 重新设计了缩略图功能,在上传过程中为每个视频选择一个“好”的缩略图,并存储一个主图,以便稍后用于实时处理。
- 将我们现有的每个图像的 _N_ 个版本迁移到一个要存储的主图,高质量图像。
这使我们能够
- 根据 DPI 和操作系统,向不同的屏幕类型提供更小或更大的图像。
- 为每个浏览器提供优化的图像;例如,WebP 用于 Chrome,JPEG-XR 用于 IE11+
- 轻松引入新的视频分辨率和播放器尺寸。
- 将缩略图图像缩放到嵌入的大小,以供显示。
- 立即引入新的优化,例如 mozjpeg,而不会遇到任何重大迁移问题。
现在介绍一些更技术性的内容。
一般架构概述和迁移
上图展示了该流程的概览。如果你想更详细地了解基础设施和迁移策略(以及更高分辨率的图表),包括一些奇怪名称的含义,请访问 Making Vimeo 博客 查看!
开源
实际的图像处理完全在内存中进行——从不访问磁盘。主要的图像处理服务是用 Go 语言编写的,并且在一定程度上利用了它的 C FFI 来调用几个库和一些微小的 C 例程,无论是否开源。众所周知,从 Go 调用 C 函数会有一定的开销,但在实践中,与库内部更密集的操作(例如解码、编码、调整大小等)所花费的时间相比,这种开销微不足道。
该过程非常简单:视频帧被定位并解码并转换为 RGB(是的,JPEG 是 YCbCr,但对我们来说,将主图存储为 RGB 更有意义)或图像被解码,并进行各种计算来考虑非方形像素、裁剪、调整大小、纵横比等。然后调整图像大小、编码并优化。所有这些都使用 Go 中的缓冲 I/O(通过 bufio
)在内存中完成,如果需要,则可以将其管道传输到外部进程并返回到服务,因为在某些情况下库不可用,例如 Gifsicle 和 pngout 的情况。
使用了很多技巧来加速处理速度,例如根据 MIME 类型、libmagic 和下面列出的库检测图像类型和分辨率,因此我们不需要调用 avformat_find_stream_info
,它会对图像进行完整解码以获取这些信息。
我们利用(并为其贡献代码!)的一些值得注意的开源库包括
- FFmpeg & Libav – 基础图像解码库(libavcodec)、调整大小(swscale)、远程图像访问。现在也支持 CMYK JPEG!
- FFMS2 – 使用上述库进行帧准确的定位。
- libwebp – WebP 编码。
- LCMS2 – ICC 配置文件处理。
除了这些库之外,我们还编写了一些 Go 包来帮助实现这些功能,其中一些我们刚刚开源
- go-util – Go 的通用实用程序函数。
- go-iccjpeg – 从通用
io.Reader
中提取 ICC 配置文件。 - go-magic – 使用
io.Reader
对 libmagic C API 进行惯用的 Go 绑定。 - go-imgparse – 从 JPEG、PNG 和 WebP 图像中提取分辨率,针对 I/O 和方便性进行了优化,同样使用标准的
io.Reader
。 - go-taglog – 与标准 Go 日志记录包兼容的扩展日志记录包。
- go-mediainfo – MediaInfo 的非常基本的绑定。
未来
尽管我们目前对 PNG 和 WebP 的优化效果很好,但仍然有许多工作要做。为此,我们一直在参与并为一些开源项目做出贡献,以创造更好、更快的网络体验。下面讨论了其中一些。这可能并不明显,因为我们倾向于使用我们的标准电子邮件帐户进行贡献,而不是我们的公司帐户……隐蔽!
mozjpeg – 已经非常有前景,添加了诸如扫描优化、格形量化、DHT/DQT 表合并和通过过冲剪切进行去环等功能,未来的功能包括 针对高 DPI 显示器优化的量化表 和 全局最优边缘扩展。我们计划在 ABI 兼容性 在 3.0 中实现后推出它,并且我们还计划向 ImageMagick 添加支持,以造福更大的社区(如果其他人还没有添加)。
jxrlib – 微软开源这项技术很棒,但它需要一些 API 方面的工作(即一个实际的 API)。直到最近,它甚至无法作为一个库构建。
jpeg-recompress – 与 mozjpeg 一起,类似的东西对于 JPEG 生成非常理想。使用出色的 IQA 与 mozjpeg 和一些其他指标(其中一个由我实现,但实现得很糟糕!)。
开源 PNG 优化库 – 这是一个让我们有点困扰的问题。当前的开源 PNG 优化实用程序根本不支持任何内存中的 API,或者实际上,甚至不支持通过 stdin/stdout 传输。 pngout 是唯一支持管道传输的工具。从长远来看,我们希望能够放弃闭源工具,并为这些项目中的一个贡献一个 API。
Photoshop、GIMP 等插件 – 我计划使用上面提到的库来实现这些插件,以便设计师可以更轻松地享受更好的图像压缩带来的好处。
关于 Derek Buitenhuis
Vimeo 的转码人员,也是 DSP 黑客。非常喜欢咖啡。非常非常喜欢。
7 条评论