使用 Puppeteer + canvas + WebCodecs 来代替 ffmpeg

2022-04-11 19:12:02 浏览数 (1)

来源:Demuxed 2021 主讲人:Collin Miller 内容整理:冯冬辉 Screencastify 的网页视频编辑器使用 ffmpeg 和它的 filter graph 作为渲染引擎,但是这导致了用户界面在预览渲染输出上的重复工作。为此,技术团队将 Puppeteer、MP4Box.js、WebCodecs、canvas 和 ffmpeg(final muxing)结合在一起,创建了一个管道,为网络开发者提供熟悉的 canvas 图形 API,而不牺牲 ffmpeg 的性能。

目录

  • Collin Miller:简介
  • Jon Kurinsky:架构
  • Ben Odisho:代码案例

Collin Miller:简介

Collin Miller 首先介绍了 Edit Decision List(EDL),这是一种古老的用于描述视频编辑的文本格式。如图所示,这里有三条记录,每一条都描述了从源胶带到目标胶带的时间段,以及使用哪个源。EDL 做的就是将源中所需的时间段,映射到输出上。

EDL 描述文件

EDL 描述图解

而 Screencastify 的 编辑器中实现的,基本上也是将一个 EDL 映射到 ffmpeg。

将 EDL 映射到 ffmpeg

该编辑器也使用 ffmpeg 的 complex filters 做图像操作,例如 裁剪、组装、模糊等操作。这里的挑战在于,如何结合 EDL 这种时间编辑和图像操作这种空间编辑。ffmpeg 为很多 complex filter 提供了时间编辑模型,例如 enable='between(t,25,75)'。为了将编辑操作翻译到 ffmpeg 指令,就产生了非常长的命令行字符串。

这种方式的优点在于,ffmpeg 全套打包了很多的视频专家知识。但缺点在于不断膨胀的语法,过于致密的命令行抽象,或许也需要进一步学习一些 C 语言。

对于 Collin 来说,render(state) => DOM 这种前端描述已经深深烙印进脑海。这里引发的思考是,render(timestamp, videos, edl) => frame,如果有一个时间戳,一个视频的集合,和类似 EDL 的东西,能不能来渲染一个帧?这就是该项目的启动思想。

Jon Kurinsky:架构

Jon Kurinsky 概述了项目的整体情况。Screencastify 的编辑器产品,是基于两个合成器的技术栈。在前端有一个基于 canvas 和 primitives 的 angular 应用程序。而在后端则由 ffmpeg 完成渲染过程。前后端并不能保证一致,用户的预览体验和专家的视频体验是不一样的。

下图是其预期的架构示意图。与其有两个独立的合成器,不如把前端的合成器加载到后端,(例如 Puppeteer 这种基于浏览器的技术),并找到一种方法把基于浏览器的合成器的输出连接到 ffmpeg,这样就可以期待图像数据出来后保存在磁盘上,并返还给用户。

预期的单合成器架构

第一次尝试中,把前端当作一个包,暴露出一个单一的对等函数,其输出是屏幕截图。但事实证明,性能的挑战最终确实从本质上扼杀了这种努力。在堆栈的过程中,数据被复制了很多次,以便把数据从浏览器中取出来,结果就是比实时速度慢了很多。为了直接获得浏览器中的像素数据,该团队花了深度时间,甚至考虑编写一个自定义的 Chrome 浏览器。然而,这条路线的复杂性成本超过了可能的增益。

众所周知,谷歌投入了大量的精力来研究如何让开发者直接访问低级别的视频 API。WebCodecs 允许开发者传入时间戳,然后拉出帧数据,之后借助 canvas 就可以在浏览器端运行渲染。

预期架构的技术框架

如上图所示,对于一个视频源,首先用 mux.js 对其进行解多路复用,然后把编码数据传给 WebCodecs 以获取帧数据,而 WebCodecs 可以把原始帧画到像 canvas 这样的浏览器基元上。一旦在 Canvas 中获得了帧数据,就可以利用 canvas API 做修剪、切割、裁剪、模糊、粘贴图像、组合图像的操作。

之后把 canvas 图像传给 WebCodecs 编码器,WebCodecs 编码器把那一帧添加到一个渲染帧的数组中,在后端做多路复用的工作。讲者发现,将原始编码的 H264 帧从 Puppeteer 实例上传到正在运行 Puppeteer 的节点服务器上会更容易。问题在于,WebCodecs 使用的一些编解码器只有在硬件渲染器(GPU)可用时才可用,而在 Puppeteer 无头浏览器的环境下无法工作。讲者不得不测试一堆不同的编解码器配置,以找到一些可以工作的配置。

这里描述的技术堆栈是浏览器的实验性功能。如果当所有供应商都采用这种方式时,就可以开始考虑客户端视频编码的问题了。现在有可能将这个编辑器应用程序变成一个可以离线运行的 PWA,这在过去是没法做到的。

Ben Odisho:代码案例

Ben Odisho 接着介绍了初期的代码实验,演示了编辑器以及渲染得到的视频,以及代码中的实现方式。如下图,在网页编辑器中渲染好的视频,在后端调用 ffmpeg 得到了输出视频。

Demo:浏览器端视频编辑器

Demo:后端输出的视频

最后附上演讲视频:

http://mpvideo.qpic.cn/0bc36eacuaaapiagykjqgfrfb4odflyqakqa.f10002.mp4?dis_k=cb892b8c5aa045b54b0d151169cc55e1&dis_t=1649675495&vid=wxv_2310871663208660992&format_id=10002&support_redirect=0&mmversion=false

0 人点赞