速来报名!AICon北京站鸿蒙专场~ 了解详情
写点什么

爱奇艺直播 WebAssembly 优化之路

  • 2019-10-31
  • 本文字数:3679 字

    阅读完需:约 12 分钟

爱奇艺直播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


2019-10-31 08:003688

评论

发布
暂无评论
发现更多内容

40 岁程序员会有哪些肺腑之言?这篇文章告诉你

宇宙之一粟

学习 程序员 读书感悟 9月月更

SSM整合(功能模块的开发)

十八岁讨厌编程

Java ssm 后端开发 9月月更

SSM整合(接口测试)

十八岁讨厌编程

Java SSM框架 后端开发 9月月更

【Vue2】简易Vue2-简易图书借阅管理

Sam9029

Vue 前端 9月月更

大厂校招SSP获得者—张金瑞 :开源项目,求职者的最佳简历|《大神详解开源 BUFF 增益攻略》讲座回顾

Apache IoTDB

开源 求职 Apache IoTDB 企业号九月金秋榜

干货分享|使用 Istio 实现灰度发布

北京好雨科技有限公司

istio #Kubernetes#

数字化转型新抓手:一看就懂的《企业应用现代化行动指南》(附下载)

York

容器 微服务 云原生 应用现代化

跟着卷卷龙一起学Camera--CCM

卷卷龙

ISP 9月月更

JS-内置对象API-Array(数组)-(二)-不改变原数组的API-篇

Sam9029

JavaScript 前端 9月月更

获得多家大厂SSP的清华应届毕业生—田原:大厂各轮面试中开源经验有什么用|《大神详解开源 BUFF 增益攻略》讲座回顾

Apache IoTDB

数据库 开源 求职 Apache IoTDB 企业号九月金秋榜

软件测试 | 测试开发 | 不懂PO 设计模式?这篇实战文带你搞定 PO

测吧(北京)科技有限公司

测试

springboot搭建基于minio的高性能存储

CTO技术共享

Onedev v7.4.14 路径遍历漏洞分析(CVE-2022-38301)

墨菲安全

网络安全 开发安全 漏洞分析 软件供应链安全

深入理解MYSQL之缓存

C++后台开发

MySQL 数据库 缓存 中间件 后端开发

用户组角色绑定(原生element-plus-ui表格)

青柚1943

Element Plus Vue3 Typescript

kube-prometheus 监控系统使用与总结

CTO技术共享

Ubuntu服务器上部署Kubernetes集群

CTO技术共享

ESP32-C3入门教程 基础篇(三、UART模块 — 与Enocean无线模块串口通信)

矜辰所致

ESP32-C3 9月月更 UART

阿里云PolarDB-X 荣获“2022 OSCAR 尖峰开源项目及开源社区”奖

阿里云数据库开源

阿里云 分布式数据库 开源数据库 PolarDB-X 可信开源

EMQ走进亚马逊云科技:携手云端,共筑「面向未来」的IoT基础设施底座

EMQ映云科技

物联网 IoT 解决方案 亚马逊云科技 9月月更

数据平台发展史-从数据仓库数据湖到数据湖仓

明哥的IT随笔

hadoop spark 数据仓库 数据湖 湖仓一体

开发者有话说 | 一个普通人的前端职业成长之路

范文杰

个人成长

[SSM]SSM整合①(整合配置)

十八岁讨厌编程

Java 后端开发 9月月更

软件测试 | 测试开发 | 一文彻底理解 Cookie、Session、Token

测吧(北京)科技有限公司

测试

软件测试 | 测试开发 | 一文搞定 Postman 接口自动化测试

测吧(北京)科技有限公司

测试

性能测试知识科普(二):测试策略

老张

性能测试

阿里MaxCompute生态团队负责人—李睿博 : 参与开源,让自己的履历与众不同|《大神详解开源 BUFF 增益攻略》讲座回顾

Apache IoTDB

数据库 线上讲座 Apache IoTDB 企业号九月金秋榜

软件测试 | 测试开发 | 《穿越时空的git》之创建版本库和常用命令操作

测吧(北京)科技有限公司

测试

个推直播预告:9月26日,一线专家分享APP数字化运营方法与实践

个推

数字化 用户画像 标签体系

计算机网络——封装成帧和透明传输

StackOverflow

编程 计算机网络 9月月更

RAID(独立冗余磁盘阵列)

阿柠xn

Linux 运维 操作系统 raid 9月月更

爱奇艺直播WebAssembly优化之路_文化 & 方法_直播技术团队_InfoQ精选文章