通过Canvas在浏览器中更酷的展示视频

有了Canvas可以更灵活的展示体验更好的视频,能够与页面更好的融合。

文 / Matthew McClure

译 / John

原文 https://mux.com/blog/canvas-adding-filters-and-more-to-video-using-just-a-browser/

视频无疑是网页中最引人关注的元素之一。在一个兼容性良好的网页内,视频的动态画面让网页内容能够更加生动地展现给用户,而那些可响应用户行为并与网页浏览者互动的网页视频元素则将这种美妙体验提升到了新的高度。
这里我想为大家介绍Canvas API!为实现更加高阶的视觉效果,Canvas API向开发人员提供了一种通过<canvas>元素在DOM中绘制图形的方法。此方法的一项常见用例就是处理图像,这也使其成为处理连续图像也就是视频的一大利器。我们希望通过以下几个典型案例为大家分享视频+画布并实现更生动精彩的网页交互效果,探索该项技术的无限可能。

样板参数

为了保证这些案例能够客观充分反映Canvas API的优势,我们确立了以下测试样板参数:首先,我们使用Mux为每个视频附予播放ID,而player.js仅仅是一个用于抓住页面中的所有视频元素与data-playback-id属性,并初始化每一个 HLS.js 的小工具;其次,我们的每个测试小样都有一个用于演示的Processor class。这些演示文件都是自包含的,即便是简单示例与高级示例之间也具有足够相似性,这样便于控制变量以精确比较他们之间的差异。

拷贝视频:从视频元素渲染到Canvas

(此处有视频,链接:https://gp0hk.csb.app/1-simple.html)
注意:这些CodeSandbox演示可能无法在Safari上运行。
在此示例中,我们所做的只是将video元素以canvas元素的输出形式呈现。这里展示的是一个带有video和canvas元素的裸露HTML文件(接下来的每个例子都使用与此完全相同的文件)。当我们创建类的新示例Processor时,我们抓取video和canvas元素然后从画布中获取2D上下文。接下来,通过设置一个监听器来启动我们所构造的函数集合,以便于在视频元素开始播放时应用这些优化。
当play事件被触发时,updateCanvas方法开始被调用。在这种情况下,被调用的只是drawImage上下文,用以确保video元素中的内容能够准确被绘制。当此调用完成后我们会使用requestAnimationFrame立即再次调用该函数。
也许你想问:这里为什么不使用setTimeout而使用requestAnimationFrame?这样做最重要的原因是避免丢帧或剪切。与setTimeout不同,requestAnimationFrame和显示器的刷新率同步,使用requestAnimationFrame能够有效规避对终端显示设备帧率与刷新率的不必要猜测。

让我们用图像创造点什么吧!

(此处有视频,链接:https://gp0hk.csb.app/2-filter.html)
上述示例与我们之前的示例几乎完全相同。但是,在这里我们不是仅仅完全复制整个video元素,而是在将图像绘制到上下文之前操作图像。
在如原先那样绘制图像之后,我们可以将该图像数据以记录了每个像素RGBA值的数组的形式从该上下文中取出。不能不说这是一件令人兴奋的事情,因为这意味着我们可以遍历每个像素并在此基础上实现我们期待的任何功能。而在此情形下,我们要做的是将把绚丽的彩色视频转换为灰阶版本。
最终我们只是采用了 Mozilla团队描述 的方法,也就是将每个RGB估值器设置为其中所有3个的平均值。随后我们更新图像数据数组中的这些值,并将更新后的版本写入到上下文中。

一个接近实际的例子:分析和利用视频的细节

这里我想与大家分享一下Phil痛苦——2015年以来,他一直任职于Demuxed 公司。今年除了常规领域,他还一直致力于 Demuxed 2019网站 ,该 网站 页面的顶部有一个大型动画,设计此动画的目标是希望其与网页背景完美融合。动画可以使用JavaScript和SVG完成,但这样会导致动画文件非常臃肿,以至于完全占据了MacBook Pro的处理器核心。我们的讨论以该命题为重点,我们希望使用合适的编码方案已实现高效的视频动画展示效果。
Phil把视频放在了hero上,并且他注意到视频的背景颜色与CSS中指定的背景颜色不完全匹配。但这并不要紧,Phil做了任何明智的开发者都会做的事情——使用颜色提取工具抓取了视频背景的十六进制颜色值,随后统一两种背景的颜色。
当Phil在不同的浏览器或设备中打开该网页时,他意识到了我们正在处理的色彩空间问题——在解码视频时,不同的浏览器或硬件处理颜色空间的方式不同,因此就像我们试图做的那样,这里基本上没有办法可靠地匹配不同解码器的十六进制值。
仔细观察,你会看到紫色背景的细微差别。经许可使用的多路分配图像。
为了解决这个问题,我们放弃了这种尝试并试图只在每个浏览器内进行初始修复。我们像以前那样将画面框架绘制到画布上并且我们只抓取边缘上的一个像素;当浏览器将图像渲染到画布时将颜色转换为正确的颜色空间,这样我们就可以抓住边缘上的一个RGBA值并将主体背景颜色设置为相同!
(此处有视频,链接:https://gp0hk.csb.app/3-analyze.html)

万事俱备!接下来我们添加点机器学习理论

在当下的技术趋势中,机器学习成为避之不及的关键热词。几乎所有技术博客文章内没有机器学习解决不了的问题;更重要的是,我们原先似乎没有利用机器学习实现什么颇具建设性的技术成就。尽管Mux 利用ML 做实现了很多 很酷的 事情 。但我本人却并未利用机器学习实现什么酷炫的优化。
我们将进一步讨论最后一个例子并将其中的一些概念结合在一起:我们使用 Tensorflow的对象检测模型 在每个帧中查找对象并对它们进行分类,然后我们将在画布中用框绘制框架和与之相关的标签。根据 Spoiler alert分类器,我们认为该分类器针对示例Big Buck Bunny中的一切物体所作出的识别结果可能都是错误的。
这里我想强调的是:我不是数据科学家,这是我第一次亲自使用Tensorflow。尽管使用机器学习搭建视觉分析框架并进行实时分析看上去非常酷炫,但这一切真的能在实际案例当中起到决定性关键作用吗?最后我们请Phil使用相机拍摄他的宠物狗散步,看看机器学习应对这一场景的效果如何……
(此处有视频,链接:https://g9zew.csb.app/5-woof.html)
实际结果的确出乎我的意料:机器学习可以成功识别99%帧内的宠物狗,仅有1%的情况将宠物狗识别成马,不得不说这超出了我的预期。

我们还能做些什么呢?

我们可以使用类似的方法实现色度值过滤器来构建自己的绿幕或构建图形和叠加层。如果你正在使用HTML5视频和画布做一些其他有趣的事情, 请与我们分享。