Published on

如何创造一个在线视频编辑器

VEED 团队创始人在使用复杂、笨重的应用编辑了几千小时视频后,认为现在市场上大多数视频编辑器对于一些比较简单的视频处理工作太复杂和笨重。

在处理用于分享到社交网络中的视频时,大型视频编辑器对普通人来说太复杂。普通人更需要一个简单、功能强大的在线视频编辑器。

于是,他们两人就在 2019 年开始开发 veed.io,一个在线视频编辑。

veed.io 最初的功能仅仅是为分享到社交网络上的视频添加字幕,但现在已经可以满足了常见的视频剪辑需求,每年订阅收入达到了100万美元。

在体验过veed.io 的在线视频编辑功能后,就相当好奇它的实现方式。考虑到这是一个网页版的视频编辑器,就猜测视频的编辑、渲染工作全都是在浏览器中完成的,但这个想法一直未得到证实。

直到 VEED 团队在他们的博客中介绍了他们从创意到实现产品过程中进行的技术尝试,才逐渐了解到如何来制作一个在线视频编辑器。

Table of Contents

视频编辑基础知识

在开始了解如何实现视频编辑器之前,需要充分了解视频和视频编辑的基础知识。

一个基础问题-什么是视频?一个视频是很多图片的集合,这些图片也被称为“帧”。这些图像按一定顺序并以一定速度(称为“帧速率”)播放,以创造图像是连续运动的错觉。

现在,来了解一些关于视频编辑的常见功能

“剪裁” 是用户中最受欢迎的功能之一。如果你想删除视频的特定部分,我们所需要做的就是删除不需要的帧并将视频重新粘贴在一起。这样视频就被剪裁了。相反,您可以通过组合两个不同的帧将它们缝合在一起,从而使视频更长。

假设您要为视频添加图像,文本或字幕。由于每个视频都只是帧的集合,因此我们要做的就是将我们的对象(无论是图像还是文本)放置在帧的顶部,以生成(也称为“渲染”)新的帧集。

上面介绍的是很基础的知识,如今视频和视频编辑已经发展地很远了,要比我描述地更加复杂。视频存在很多属性,而每个视频的属性都不相同。视频还有不同的格式,在做视频编辑器时都需要考虑进去。

有了一些视频和视频编辑的基础知识后,就可以开始尝试来构建一个在线视频编辑器了。

总体规划

我们想创建的是一个在线视频编辑器,很自然地就会想到需要使用一个网页来承载编辑功能,除此之外,还需要一个用于渲染高质量视频的后端。前后端需要无缝配合,以保证用户在界面看到的效果和最终得到的成果是一致的。

为了简化方案和快速推进,先单独关注后端,首先要回答一个问题:"是否已经存在开源的、高质量的、可编程的视频处理工具?",这些已经存在的工具,可以帮助我们快速拿出 MVP 版本。

后端

视频编辑工具: Processing 框架

Processing 框架是一个基于 Java 的开源数字资源工具包,专门为电子艺术和视觉交互而设计,并且非常容易上手。看起来像这样... 左侧是代码,视觉输出到单独的窗口中。

Processing 的好处:

  1. 可以通过编程的方式来进行视觉艺术创作
  2. 可以使用脚本以无头的方式来运行它,方便与其他程序集成

VEED 团队使用 Processing 框架在几分钟内就创建了一个超级简单的视频编辑器。

但是 Processing 也是有缺点的:

  1. Processing 的处理速度太慢,几秒钟的视频要花费近5分钟甚至更长的时间才能处理完。
  2. Processing 处理视频的过程中,无法保留音频,音频需要使用其他工具来单独处理

最大的问题是,无法将 Processing 和 GUI 无缝集成。

Phantom.js

在尝试使用 Processing 失败后,遇到的最大问题是需要构建一个可以与前端无缝运行的后端系统,因此 VEED 团队认为“为什么不将前端放在后端运行”。

需要做的是在浏览器中构建一个 GUI 来进行操作和预览视频,然后在服务器上以浏览器的形式执行相同的操作,并记录保存最终结果。

VEED 团队想要实现的是用户上传视频后,在浏览器中预览视频,允许用户使用 CSS 和 HTML 向预览窗口添加图层。例如,可以使用绝对定位将文本放在视频的上层。在服务器上同样以浏览器的形式添加这些图层,并将预览窗口中的内容记录下来,来获得最终的结果。

Phantom.js 可以在服务器上使用 JavaScrpit 脚本控制一个没有界面的浏览器。使用 Phantom.js 的好处是不用单独编写前端和后端,本质上都是在浏览器进行操作。

一开始,Phantom.js 运行出色,他们在短时间内使用 Phantom.js 极其简单的 API 构建了很多功能,例如添加图像和文本。为了让你更了解 Phantom.js 的功能,放一段代码,作用是加载 Google 主页,并将其保存为图片。

使用 Phantom.js 最大的问题是,它无法对视频进行帧级别的控制。具体来说,Phantom.js 只能以 1 秒为间隔记录浏览器内容,这充其量只能带来GIF 图的效果。

另一个明显的问题是,由于在后端使用 Phantom.js 来映射用户在前端看到的内容,因此必须要等 Phantom.js 在后端上完成整个视频的回放,如果视频过长,耗时长会给用户带来糟糕的体验。

选用 Phantom.js 带来的好处:

  1. 前后端实现原理相似,代码复用性高
  2. Phantom.js 的 API 简单,实现功能快速简单

Phantom.js 存在的问题:

  1. 无法对视频进行帧级别的控制,只能 1 秒为间隔记录浏览器中的内容
  2. Phantom.js 处理时间过程,用户体验不好

Adobe After Effects Render

在使用 Phantom.js 后,他们又花费了大量的精力和时间来思考可以 work 的方案。

同时他们也注意当前已经存在很多视频编辑网站,可以让用户轻松创建高质量的视频。这些网站制作出的视频甚至比现在的 VEED 还要好的多。但这些网站唯一的问题是用户只能将视频套在一个模板上,而这个模板是固定、不可编辑的。

这些网站的运行机制是,在后台使用 Adobe After Effects 或者 Adobe Premiere Pro 的 SDK 来渲染高质量的预定义模板,将用户的视频注入到模板中,有些模板允许用户修改一些区域的文字,但是用户无法控制文字的样式。

用户要么挑选使用自己喜欢的模板,要么就离开。

尽管他们青睐制作出可以渲染高质量视频的工具,但是 Adobe 的 SDK 确实有很多不足之处,主要就是使用模板不能满足用户自己创造自己喜欢的内容,而不使用模板又不能简化操作。最终决定,不采用 Adobe 的 SDK。

选用 Adobe After Effect 的好处:

  1. 可以渲染高质量视频

在此场景下 Adobe After Effect 存在的问题:

  1. 基于模板渲染,灵活性低

FFmpeg

如果你是开发人员,同时对视频编辑感兴趣,尝试构建过一些与视频相关的工具,那么很有可能会使用过 FFmpeg 命令行工具,或者至少听说过 FFmpeg 命令行工具。

FFmpeg 是一个完整的跨平台解决方案,用于记录,转换和流式传输音频和视频,是视频/音频处理最常用的开源软件。没有它,大多数基于浏览器的视频编辑工具(如果不是全部的话)将不存在。FFmpeg 确实是一款天赐之物,是瑞士军刀,凭借其令人难以置信的通用 API 帮助创造了数十亿美元的产业,Youtube 和 Itunes 也采用了它。

目前 veed.io 上大多数视频编辑功能都是使用 FFmpeg 及其工具包来实现的。

除了 FFmpeg 之外,他么也尝试了另一个开源视频编辑工具包 Moviepy,Moviepy 可以支持自定义渲染代码,但是他们觉得在多次失败之后,不想再赌博。FFmpeg 是经过大厂实验的,选用 FFmpeg 是更加稳妥的选择。

OpenCV

OpenCV 是最受欢迎的开源计算机视觉库之一,也相当成熟。VEED 团队认为使用 OpenCV 是他们开展工作的最快方法,而不是直接从基础引擎开始编码。OpenCV 使他们能够使用尽可能少的代码来生成视频。

OpenCV 这个库背后使用的是 FFmpeg 和 libavcodec,这意味着,即使 OpenCV 并非在设计时就考虑用于视频编辑,但它具有的很多功能,非常适合视频编辑。

VEED团队使用 OpenCV 的时间大约有4-5个月,后面废弃了 OpenCV,转而使用更底层的 FFmpeg 和 libavcodec。

在服务器中渲染视频,是一个非常耗费计算资源的事情,必须考虑服务器成本,以确保我们的工作从长远来看是持续的。随着用户增长,服务器成本也不断增长,需要找到一个方案来降低服务器成本,而这个方案就是直接使用更底层的工具,来提升性能。

上面多次提到的 libavcodec 是一个开源的编解码器,可用于对视频和音频数据进行编码和解码。libavcodec 是当今许多开源媒体应用程序和框架的组成部分,也是经过实践检验过的。

不再依赖 OpenCV,带来的最大挑战就是,会增加项目和代码复杂度。

初始化 libavcodec 需要编写大量的设置类代码,并且文档很少(大多数情况下,只能阅读源代码)。除了视频之外,音频处理也很复杂(尤其是与视频同时可视化时),并且需要转换格式以适应在标准输出格式中使用 AAC 编解码器。不过值得庆幸的是 FFmpeg 还可以使用 libavfilter 来帮助我们,他们可以搭配使用。

在去年渲染视频时,混合、剪切和转换音频有 50% 的几率出现错误和崩溃,但是通过缓慢调整 libavfilter 参数,现在几乎可以渲染任何文件的程度,即使文件内容存在一些损坏。

前端(WebGL + React)

veed.io 的视频渲染是在后端完成的,所以必须要提供一个界面,供用户预览、编辑视频。veed.io 实际上有两个视频渲染器,一个在前端渲染预览,另一个在后端渲染最终的视频。这里面最难的部分是使两个渲染器尽可能无缝地协同工作,即用户看见的就是最终得到的。

总体思路:

  1. 用户可以在前端进行所有必要的编辑
  2. 如果用户添加了视频、图片或其他资源,将这些资源保存到我们服务器中。
  3. 用户在执行完操作后,前端需要将用户所进行的操作转换为专门的指令。这些指令在前后端两个渲染器中都是以原始视频为参考的。(例如,这些指令记录了放置的文本、图像以及他们的 XY 坐标等)。
  4. 后端的 C++ 渲染器能够根据这些指令渲染用户的视频
  5. 最后,用户在前端获得渲染后的结果。

由于前后端是两个独立的渲染器,确保用户看到的就是最终实际得到的内容,相当困难。

VEED 团队也想了一下方法来降低难度,例如:与其在后端渲染文本,不如在前端渲染文本,输出成图片资源上传到服务端进行处理。VEED 团队也基于 WebGL 构建了一个渲染器, WebGL 实现的渲染器与后端 C++ 渲染器,在实际际使用过程中存在一些细微差异,但一般都是视频解码的差异,不是渲染器本身的差异。

另一个难点在于使很多复杂的 WebGL 代码与 React 结合在一起工作。即使和 C++ 渲染器相比,VEED团队认为他们的前端渲染器是他们迄今为止最复杂的软件。

VEED 团队没有详细的介绍前端的工作方式,以后应该会分享。

总结

通过上面的介绍,我们可以大致了解到 veed.io 现在正在使用的技术:

前端:React + WebGL

后端:FFmpeg + libavcodec

到目前为止,VEED 团队已经在浏览器中构建了一个功能相当多的视频编辑器,并且做的很好。他们认为还有很多可以优化的方向:

  1. 提升渲染效果
  2. 最大程度降低渲染等待时间,例如将 C++ 渲染器做为独立节点运行,并可以根据需求动态地缩放渲染器的数量
  3. 使用 CDN 技术减少站点加载时间
  4. 改善代码质量
  5. 尝试 GPU 加速和一些更高性能的图形引擎

从 VEED 团队的分享中,可以得到一些重要的观点:

  1. 初创团队需要快速拿出 MVP 版本
  2. 尽量选择经过时间、大厂检验的工具,特别是在需要快速稳定地产出成果时。
  3. 像视频渲染这类复杂计算,提高性能就是在降低成本。