爱奇艺直播WebAssembly优化之路

WebAssembly技术简介

近几年,WebAssembly技术非常火,可以说是成为了JavaScript一个新的转折点。JavaScript自1995年诞生之日起,其性能问题就被大家诟病。直到2008年,很多浏览器加入了即时编译器,JavaScript也开始引入JITs,再加上Google等厂商对其的大力优化,其性能提升了10倍不止。由此,JavaScript也开始跳出了浏览器的范围,在各个领域崭露头脚,比如后台使用的Node.js和桌面端使用的Electron等。

JIT技术简而言之是在JavaScript解释执行时将常用的二进制代码块暂存下来,在下一次解释执行相同的代码块的时候可以直接运行暂存的二进制代码块,节约了解释的时间。那能不能将所有JavaScript代码一次性都编译成二进制,提升运行效率呢?WebAssembly的出现回答了这个问题。

在WebAssembly出现之前,JavaScript是浏览器里可以运行的唯一的编程语言。而WebAssembly技术使浏览器运行别的语言编写的程序变成了可能。目前可以使用 C、C++、Rust、Go、Java、C# 编译器(还有更多)来创建wasm 模块。浏览器在运行时将wasm模块放在专有的虚拟机中运行。由于是二进制的文件,运行效率比解释执行的JavaScript脚本要高很多,因此,很多前端开发者也把WebAssembly技术视作下一代的前端技术。

目前WebAssembly的兼容性如下图所示:

可以看到,在新版本上,主流浏览器不管是在PC端还是移动端都支持了WebAssembly,而且各大浏览器厂商还在持续支持此项技术,相信不久就会得到非常普遍的应用。

WebAssembly和直播,不一样的火花

一直以来,爱奇艺生产的直播流有mp4和flv两种格式,但Html5的video标签原生只支持mp4的播放,如何解决flv格式在网页端播放的问题就摆在了所有人的面前。一般来说flv格式在网页端播放有以下几种解决方案:

1、使用flash播放器插件

不过因为性能和安全等各种问题,各大浏览器已经逐渐弱化了这种方式,Chrome也将在2020年左右停止对flash player的支持,所以现在基本很少有人用了。

2、网页对flv格式的视频解码

使用canvas渲染图像,使用audio播放声音,相当于网页端做一个播放器,这也是可行的。但各大浏览器厂商对原生video控件会针对不同的平台做硬件加速渲染的优化,如果自己渲染的话,硬件加速这块便也需要自己做,这样会耗费极大的人力,并且效果也很难和浏览器原生的硬件加速相比。

3、在网页端将flv格式转成mp4格式然后使用原生播放器

这也是目前使用得最多的方案。这样既可以播放flv的直播流,也可以将渲染丢给原生播放器去做,充分发挥原生播放器的优化能力。

爱奇艺直播使用的就是第三种方式,当flv的直播流到达前端时,使用JavaScript将flv转换成mp4,再交给原生播放器。但由于JavaScript运行效率较低,这部分的性能一直都令人不太满意,所以决定引入WebAssembly技术,看看是否能带来不一样的提升。现在打开任意的爱奇艺直播间,在后面输入__enablewasm__=true,就能打开WebAssembly转码模式,如下图所示:

体验上,两种模式都能满足流畅观看直播的需求。由此可见,WebAssembly模块可以很完美地替换原来的JavaScript所写的转码模块。下面来看一下如何接入WebAssembly。

接入WebAssembly的步骤

使用WebAssembly非常简单,总的来说,分为以下几步:

1、使用c编写flv转mp4的代码

首先定义WebAssembly被js调用的接口文件:

如果想在被编译成wasm文件后可以被JavaScript调用,就需要在可以被外部调用的函数前使用EM_PORT_API来标识,这样在后面编译的时候WebAssembly就会将此函数作为可被JavaScript调用的方法抛出。

然后还需定义一些WebAssembly调用JavaScript的接口,如下面所示:

主要是通知js转换mp4流的头部信息和已经转好的部分流的缓存区地址等,实际调用的代码需要使用EM_ASM_()函数包起来,里面填上调用的JavaScript方法名和带的参数。

定义好接口后就是转码实现的部分了,这里涉及到flv和mp4格式的相关知识(对这两种格式不太了解的同学可以自行阅读相关文档)。整体转码采用flv和mp4双缓存区的模式,流程如下图所示:

a. JavaScript获取到直播流后将流存入flv缓存区;

b. JavaScript通知WebAssembly缓存区首地址和进度;

c. WebAssembly请求缓存区数据;

d. WebAssembly进行转码;

e. 将转好的mp4片段存入mp4缓存区;

f. WebAssembly通知JavaScript转码进度;

最后由JavaScript通知原生播放器直接播放mp4缓存区的视频流。

2、使用emcc编译出flv2Mp4.js和flv2Mp4.wasm

首先需要安装emscripten环境,安装和配置的具体步骤可以参考emscripten的官网

安装完成后就可以使用emcc命令编译c文件了,使用命令 emcc main.c -s TOTAL_MEMORY=268435456 -g -o flvToMp4.js,最终可以得到两个文件,flvToMp4.js和flvToMp4.wasm。

其中flvToMp4.wasm是实际转码的code,flvToMp4.js相当于接口文件,播放器可以通过引入flvToMp4.js来加载wasm文件和调用wasm文件中的二进制代码。

通过阅读flvToMp4.js,我们可以发现自动生成初始化WebAssembly的相关代码,获取WebAssembly的二进制文件后,调用了WebAssembly.instantiate(),初始化了WebAssembly,并且在获取或加载wasm文件失败后还能再次重试。

通过查看getBinaryPromise()方法也可以看到下载的过程。

使用自动生成的代码,就基本可以不用管加载wasm文件等问题,非常方便。

3、对接编译好的wasm文件

因为转码是高cpu的工作,所以将其放入web_worker中运行,这样不会阻碍主线程的渲染。

worker创建后将事件和主线程对应绑定,也即绑定前面定义的wasm调用JavaScript的几个方法:

上面就是WebAssembly通知JavaScript的相关消息接口的定义,到此已经完成了整个转码过程的全部接口定义,全部流程就如下面的时序图所展示。

由时序图可以看到播放器在收到流时就会初始化WebAssembly模块,初始化完成后进入转码阶段,通知WebAssembly进行转码并存入缓存区,再通知播放器播放。

使用WebAssembly实际性能对比

体验上能保持一致,那实际性能上有多少提升呢?还是要用数据说话。爱奇艺直播团队先后使用代码打点和浏览器自带的性能监测工具实时监测数据的方式来测试WebAssembly的实际使用性能。

1、直播流转码效率情况

首先,测试使用WebAssembly实际转码的速度。分别使用原来JavaScript所开发的转码模块和使用WebAssembly的转码模块进行转换,在实际直播间转换flv流数据包的前后进行打点计时,最终得到的数据如下所示:

前后各挑取了30包flv数据,表中第二列是每一包转码耗时,第三列是包的大小,在表的最后统计了总包的大小和总耗时,由此计算出未开启WebAssembly和开启WebAssembly的平均传输速率分别为35305.6字节/s和46608.1字节/s。可以看出,WebAssembly开启后转码速度的提升还是非常明显的。

2、运行时浏览器资源消耗情况

WebAssembly实际应用在直播间中,能给直播间带来什么样的提升呢?最明显的是cpu占用率的下降。这一点可以通过使用Chrome浏览器自带的Performance monitor对使用WebAssembly前后的资源消耗做对比来证明。

如上图所示,可以在开发者工具More tools中找到Performance monitor。通过这个工具,可以大概得到平时运行时的cpu占用率。下面两张图分别显示稳定播放时未开启WebAssembly和开启WebAssembly的cpu占用率情况:

  • 未开启WebAssembly
  • 开启WebAssembly

从图中可以大致看到,未开启WebAssembly时,cpu占用率基本稳定在7%左右,而开启WebAssembly之后,cpu占用率能稳定在5%上下,由此可以估算出大约有10%-20%的提升(注:使用测试机型为macbookpro 2018款,cpu i7 2.2 GHz,不同机器测试出的性能可能有差别,波动状况也不完全一致,但在不同平台开启WebAssembly基本都能获得不同程度性能的提升)。

WebAssembly未来的更多可能

使用WebAssembly转码还只是WebAssembly的一个非常小的用处,爱奇艺直播团队还将使用WebAssembly技术实现更多有趣、有价值的功能,比如:

  • c++项目的移植。现在很多图像相关的项目、算法都是由c++编写的,如果想在浏览器上运行,以前就只能使用JavaScript重写一遍;而现在,通过WebAssembly,只需要极小的改动,就使其能在浏览器上跑起来。
  • 算法的加密。由于WebAssembly编译成的wasm是二进制文件,反编译的成本很高,部分保密性比较强的算法会使用WebAssembly技术。
  • H.265编码格式的支持。H.265编码方式凭借其出色的压缩比,被越来越多的产品所应用,但目前各主流浏览器原生还不支持H.265的硬解。但是也可以根据同样的思路,使用WebAssembly将H.265的流转化为H.264的流,然后再使用原生播放器播放,最终达到Web端播放H.265流的效果,这样可以极大地降低带宽成本。

得益于性能上的提升,WebAssembly开始在各个领域崭露头脚,今后,爱奇艺直播团队也将尝试使用WebAsssembly实现更多的功能来优化爱奇艺的直播体验。

本文转载自公众号爱奇艺技术产品团队(ID:iQIYI-TP)

原文链接

https://mp.weixin.qq.com/s/LRGNOuFwHXALs_lhPyN3Zw

  • 发表于:
  • 本文为 InfoQ 中文站特供稿件
  • 首发地址https://www.infoq.cn/article/kVafMaidop0IVdRAFWtc

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励