随着B站、抖音、快手、淘宝直播等直播视频平台的快速崛起,前端衍生出了多媒体技术方向,各公司的传统前端团队里陆续出现了一支新军:Web多媒体团队。光看团队Title,这应该是一个拥有前端×多媒体交叉领域稀有技能的群体。阿里巴巴内部也存在众多Web多媒体团队,在内部我们针对新人整理了一份多媒体前端技术入门指南,今天将这份入门指南也对外分享出来,让大家了解我们近几年在该领域有哪些方向的工作,有哪些实践和落地,本文将从以下几个方面带着大家一窥究竟:
利用专业的前端能力,解决多媒体场景下各类技术和业务问题的前端,称之为多媒体前端。目前的多媒体前端主要从两类人群转化而来,一类是学数字媒体专业后从事前端开发的,一类是专业做前端后再学习多媒体的。这是两个成熟的知识体系交叉碰撞后的一个新的工作领域,需要具备高度还原、体验把控、跨端、工程化等前端开发能力,又要具有音视频基础、流媒体协议、播放技术、Web媒体技术等多媒体能力,目前这类人才的缺口还非常大。
最开始接触多媒体前端开发,一般场景比较简单,比如在网页上播放一个视频/音频,实现基础的播放控制(播放、暂停、进度条、音量大小、静音等)。在HTML5标准之前如果要在浏览器里播放视频内容,需要使用Adobe Flash或微软的Silverlight等插件,但是插件存在需要用户安装的不便捷和不安全等问题,因此W3C的HTML5标准中定义了一系列新的媒体元素来避免使用插件。以下是媒体开发者常用的HTML元素:
<video>
标签用于播放视频或直播流,可以通过JS HTMLVideoElement对象访问,结合媒体API和其他DOM技术可实现更丰富的媒体应用<audio>
标签用于播放音频,可以通过JS HTMLAudioElement对象访问<source>
标签放在 <audio>
或者 <video>
内部,以指定播放的媒体源,可以添加多个不同格式、大小、分辨率的媒体源,通过JS HTMLSourceElement对象访问<track>
标签放在 <audio>
或者 <video>
内部,在媒体播放时提供 WebVTT 格式化字幕或标题轨道。可以通过JS HTMLTrackElement对象访问浏览器提供的媒体播放功能都是相当简单的,一个 video 或者 audio 标签再加上src就搞定了,但这缺少了诸如视频分段加载、视频码率切换、部分加载、内存管理等现代播放器应该有的功能,需要更定制化的播放需求,或者更丰富的多媒体应用,就要使用媒体API:
媒体API
媒体源扩展API
MSE (Media Source Extension) 扩展了浏览器的媒体播放功能,允许用JS动态构造媒体流MediaSource对象,然后喂给<video>
和<audio>
标签进行更精细化的播放控制。也可以用JS把一些不支持的视频流格式转封装为支持的格式,B站开源的flv.js就是这个技术的一个典型实现,使用MSE技术将FLV源用JS实时转封装成HTML5支持的视频格式。更多信息会在下一节播放场景和解决方案中介绍。
网络音频 API
Web Audio API 用于处理和合成Web应用程序中的音频,允许开发者进行声音合成、添加音频特效、音频可视化等,使用Web Audio API 我们几乎可以完成一个专业的Web音频处理软件(如节拍器、调音器等)。
媒体捕获和流媒体API
Media Stream API 让开发者可以使用本地摄像头和麦克风来采集录制音视频,或者捕获电脑屏幕,或者读取本地视频做合成,常用于Web摄像头、拍照、录屏、视频通话等,下文视频剪辑章节也有1688使用该技术实现web视频剪辑的案例。MediaStream 是连接 WebRTC API 和底层物理流的中间层,WebRTC将音视频经过Vocie / Video engine进行处理后,再通过MediaStream API暴露给上层使用。
WebRTC
WebRTC 是一套支持浏览器进行实时音视频对话的 W3C Javascript API,它包括了音视频的采集、编解码、网络传输、显示等功能,使互联网上任意两位用户在无需服务器的情况下实现实时的音频、视频和任意数据的通信。在2010年左右,实时通信只能使用专有软件、插件或Adobe Flash进行;2013年,Chrome 和 Firefox 之间进行了首次跨浏览器视频通话,开启浏览器之间无插件化的音视频通话的序幕。现在WebRTC的使用场景非常丰富,在音视频通信、直播推流、云剪辑、云游戏等场景都可以看到WebRTC的使用。
除了这些媒体API,还有一些技术通常与媒体API共同使用:
与媒体 API 共同使用的技术
Canvas API
Canvas API 允许在 <canvas>
上绘画、操纵并改变图像内容。这样可以与媒体以多种方式使用,包括设置 <canvas>
元素作为视频播放或摄像头捕获的节点以捕获或操纵视频帧。
WebGL
WebGL 在已存在的 Canvas API 上提供了与 OpenGL ES 兼容的 API,使得在 Web 上制作强大的 3D 图像成为可能。通过一张画布,用于为媒体内容添加 3D 图像。
WebVR
Web Virtual Reality API 支持虚拟现实 (VR) 设备,使开发人员能够将用户的位置和移动转换为 3D 场景中的移动,然后在设备上显示。WebVR 有望逐渐被 WebXR 所取代,后者涵盖了更广泛的用例。
WebXR
WebXR 旨在最终取代 WebVR,是一种支持创建虚拟现实 (VR) 和增强现实 (AR) 内容的技术。混合现实内容可以显示在设备的屏幕上,或者是显示在眼镜或耳机内。
前文提到浏览器里通过<video>
就能实现视频播放了,那还需要我们前端做些什么呢?其实<video>
也存在很多限制,我们要先从媒体内容的封装格式和编码格式说起。
媒体内容源文件都是比较大的,为了便于传输和存储,需要对原视频文件通过编码来压缩文件大小,再通过容器封装将压缩后的视音频、字幕组合到一个容器内,这就是 编码 和 容器封装 的过程(可以用 压缩饼干 和 封袋包装 来理解,会出现很多不同的压缩工艺和包装规格)。
那么在播放端进行播放时,就要进行相应的 解封装 和 解码 (先拆开包装拿出饼干,享用饼干可以直接吃、也可以碾碎了吃、也可以泡着牛奶吃)。浏览器自带的播放器<video>
标签拥有解封装和解码功能,但对媒体内容的格式是有所限制的(浏览器只会拆开特定的包装方式,只能消化特定的饼干吃法)。那浏览器碰到“不会拆、不消化的饼干”,我们要怎么喂给<video>
呢?
除了容器格式、编码格式,还有流媒体协议、渲染容器、多实例播放等等问题需要多媒体前端一一解决,下面来分别介绍:
随着流媒体业务发展,出现了很多新的传输协议,媒体内容进一步包含在一层传输协议中(以HLS协议为例,增加了m3u8索引文件,并将源文件内容分片后封装到了一个个 TS 容器格式中),这样<video>
就无法识别了。要支持多协议、多容器格式的播放,开发者可以通过 MSE 来帮助浏览器识别并处理,将媒体内容 转封装 成可识别的容器格式(如MP4),这样<video>
就可以识别并播放各种媒体内容了。
上文提到的B站的flv.js以及社区的hls.js都是利用 MSE 来解决多协议、多容器格式的播放器库。
1. flv.js
flv.js是Bilibili网站开源的HTML5 flv播放器,基于HTTP-FLV流媒体协议,通过纯JS实现FLV转封装,使flv格式文件能在Web上进行播放。
但是flv.js也不是所有的flv格式视频都能播放,并且对浏览器环境也有一定的要求,以下是flv.js的使用限制:
2. hls.js
hls.js是基于Http Live Stream协议开发,利用Media Source Extension,用于实现HLS在web上播放的一款js播放库。
由于HLS协议由苹果提出,并且在移动端设备上广泛支持,因此可以被广泛应用于直播场景。而hls.js在pc端只需要支持MSE便可以应用,移动端使用原生video标签设置src便可完成播放。hls.js会先请求m3u8文件,然后读取到文件的分片列表,以及视频的编码格式、时长等。随后会按照顺序去对TS分片进行请求,然后借助MSE将二进制buffer内容进行合流,组成一个可播的媒体资源文件。
阿里内部也有多个团队有类似播放器产品,如阿里云的Aliplayer、淘系的VideoX、优酷的KPlayer,实现思路都基本一致。
3. 阿里云 Aliplayer
Aliplayer 经过几个版本的迭代演进,整个架构更加合理,赋予本身和用户更多的扩展能力,具有独立增加播放类型和功能的能力,比如要h5支持flv的播放能力,只需要新增Flv Extend功能扩展模块,而不用修改其他模块的代码,比如HLS Extend等等,确保不影响其他功能的正常工作,保持每个版本发布的稳定性。
4. 淘系 VideoX
Videox 底层的播放层也经历了几次变化,从最开始简单的 <video>
标签,到通过MSE来扩展各种格式的<video>
标签,到通过WebAssembly来对编解码格式进行扩展的<canvas>
+ Web Audio API的方式,未来可能还有底层通信的扩展及上层互动能力的增强。
5. 优酷 KPlayer
KPlayer 目前的方案拆分的较细,包括多个库和组件,主要有KMux 转封装库、KDRM WebDRM插件、KCTRL 播放器控制行为的核心抽象、MediaEngine 解码&渲染&播放的核心抽象、KUI 嵌入式UI框架。KPlayer播放核心设计如下:
上一小节解决了浏览器<video>
不支持的协议和格式(不会拆饼干包装)的问题,那遇到不支持的编码格式(不能消化的压缩工艺)该怎么办呢?
新的视频编码标准H.265、AV1等比传统H.264拥有更高压缩率,但浏览器<video>
本身并不支持,而业务为了降低成本都全链路切换新的编码格式如H.265,那多媒体前端就要自己实现浏览器端的JS播放器。由于Javascript是一种动态解释型语言,性能比C++等语言差很多,处理多媒体数据时性能短板就体现出来,WebAssembly的出现解决了Javascript的性能短板,极大扩展浏览器端的多媒体处理能力和场景。
对于Web端H.265播放器,阿里内部有多个团队都进行了相应的尝试,包括优酷、阿里云、淘系、ICBU等,思路基本一致,都是通过FFmpeg + Webassembly来实现一个JS播放器,使用JS拉流、解封装,将FFmpeg的265解码能力编译成wasm模块供JS调用,视频经过FFmpeg解码出来YUV帧数据,通过WebGL绘制图像帧数据,而音频方面因为浏览器支持AAC、MP3等主流音频格式,音频数据直接通过Web Audio API进行播放。设计思路如下:
上面描述的场景主要是PC的Web浏览器,但我们更多的业务场景在移动端,面向消费者的场景对播放的体验和性能要求非常高,于是引入了播放器的跨端支持问题,尤其是跨渲染容器(Webview/Weex/小程序)。端侧的播放器主要使用Native播放器,前端封装成Weex/同层渲染组件,在各渲染容器中运行。
在端侧如果采用原生video方案,存在兼容性及性能问题,播放器本身占用内存高,业务不规范使用会带来稳定性风险,甚至导致APP Crash。以端内H5为例,采用的是和Rax团队、客户端基础团队、客户端播放器团队一起打造的同层渲染方案:
前面提到的都是单个视频播放的场景,实际业务中还有同一个页面中多个播放器的场景,比如列表流、版头等,这时候就引入了播放器多实例控制的问题,需要保证页面内只有一个播放器播放(播放甜区)、内存管理等。
播放器需要具备强大的播控能力,即播放调度能力:
事件中心驱动
播放器内部维护一份待播放队列,由rax-view的onAppear和onDisappear实现,当执行onAppear时,待播放队列将对应播放器唯一id存入到队列中,当对应播放器执行onDisappear时,从队列中剔除
队列中的播放形式主要分为3种:1,滚动播放;2,指定id播放;3,onAppear场景播放;均由事件管控。再由事件中心分发到不同播放器,告知哪个播放器可播放,哪个不可播放
播放器存在于pcom库,无论是对于会场场景或是源码开发场景,均可保证事件中心通知到所有播放器
播控调度
播放器实例内存占用大概在20-40MB,对于一个H5页面来说,内存占用过高,极容易引发页面内存占用过大,导致crash等严重问题。所以在事件驱动播放同时,事件中心会保证有且仅有一个播放器实例正在播放
前面提到的都是单纯的播放功能,但实际的业务场景是直播间或者短视频全屏页,从播放器到直播间/短视频,还有很重要的一个部分就是用户互动层,这就引入了直播视频里的业务体系。 以直播为例,对于观众有两个诉求:观看直播、参与互动。一般直播的设计如下: 通常的直播间架构分为三种:Web直播间、Hybrid直播间、小程序直播间,比如钉钉公开课直播采用的是Web直播间架构,蚂蚁、天猫精灵等采用的是小程序直播间架构,其他绝大多数的业务采用的是Hybrid直播间架构。
纯Web直播间,是指主要运行在Web浏览器上的H5直播间,主要包括H5播放器、事件通道、UI组件等。但移动端浏览器兼容性较差,移动端播放延时较高,所以一般对体验和性能要求高的业务场景,都会选择Hybrid直播间架构。 Hybrid直播间使用原生的播放器能力,兼容性更好,体验更流畅;同时事件通道是Native通道,相对于Web直播间 websocket更安全。
Hybrid直播间的宿主是Native,使用原生播放器,互动玩法是在播放器上面盖了一层互动层(Webview或WEEX容器),并且能够和播放器通信。 Hybrid架构中互动层方案也经历了几个阶段的演变,从最开始的每个玩法组件一个独立层,到所有玩法组件打包到一个层,再到定义出直播容器来动态加载组件: 直播容器具有以下几个特征:- 统一规范的组件消息协议:包括组件包名、组件行为、业务自定义字段等
在Hybrid架构下开发调试组件,需要一个完整的直播间环境和直播容器才能开发调试,没有配套的工程体系,组件开发很低效。所以这种架构下还需要配套的工程体系,主要包含以下几个部分:- def 套件:直播间组件开发脚手架,增强调试能力,包括直播间模拟、调试代理、热更新、编译检测等功能
多媒体前端团队通过打造直播容器和工程体系,才能高效、稳定的构建出直播视频里的业务体系。 当然Hybrid架构因为其联合Native和前端带来了架构上的复杂度,特别是在直播和视频上下滑时直播间的状态管理、播放器实例和webview实例管理等,会导致一些状态问题,比如某直播平台曾出现过“神奇三串”bug:薇娅 直播间里播放的是 李佳琦 的直播流,但展示的是 叶一茜 的商品:
基于Hybrid架构我们可以考虑进一步升级,让播放器和互动层更加融合,形成「超级Video」,或者叫可交互的Video方案,甚至定义新的 <span style="color: rgb(0, 0, 0);font-size: 16px;"><video>
标准。
随着跨端业务的出现,尤其是跨APP的场景,Hybrid直播间架构就像个大胖子,天然没有跨端优势(客户端集成、维护SDK成本极高),在这个背景下小程序直播间架构出现了。小程序直播间设计上分为以下几层:
由蚂蚁和淘宝直播联合打造的小程序直播方案,在多个APP端(包括外部媒体APP)得到了广泛应用。
前面提到的更多的是面向消费侧的场景,随着业务的发展,各个多媒体团队开始更加关注生产侧的能力建设,毕竟内容的生产是整个内容生态的血液供给。作为开发者,需要给商家、主播、达人等创作者提供高效、好用的生产工具。在生产侧主要有两个方向,一个是面向直播的直播推流工具,一个是面向视频的视频剪辑工具。
直播推流前端主要有两种方案:
相对于直播的生产,视频的生产覆盖度更广,参与到这个方向建设的团队也更多,包括阿里妈妈、淘系、盒马、1688、阿里小蜜、蚂蚁等。生产文章内容需要用富文本编辑器,那生产视频内容就需要视频剪辑工具,当然这两者的复杂度是完全不一样的。我们打造或智能生产、或高效好用的深度剪辑工具,都是期望降低生产成本,能像编辑文章一样方便地剪辑视频。
传统的桌面剪辑软件是提供一个GUI界面,给用户提供所见既所得的编辑效果反馈,并在编辑完成之后产生编辑描述数据,最后交由图形图像模块、音频处理模块以及视频编码模块去生成最终视频文件。参考大部分开源剪辑软件实现,前半部分GUI通过操作系统图形界面或跨平台如QT、SDL、SWT方式实现,这部分我们称之为 “GUI前端”,而后面涉及图形图像、音频、编码相关部分,大部分都会有一套媒体编辑内核来支撑,例如Linux下著名的MLT、GStreamer等等,这里我们称之为 “编辑内核”。 基于以上 GUI前端 + 编辑内核 的思路之下,多媒体前端在剪辑工具上通常有以下几种实现方案:
桌面端剪辑:Electron方案,GUI前端在Webview,编辑内核在Native,打包成Node模块供前端调用(和上述Electron直播推流类似)。采用该方案的有淘系的Marvel剪辑工具,用于亲拍业务
纯Web剪辑:浏览器方案,GUI前端和编辑内核都在浏览器。编辑内核提供的编辑、渲染、合成等能力通过 Media Stream API 或 者 FFmepg + WebAssembly 来实现。采用该方案的有1688视频编辑器(幻雀)、阿里小蜜的小蜜视频创作工具,以小蜜的方案为例:
Web云剪辑:浏览器+服务端方案,GUI前端在浏览器,编辑内核在服务端。因为GUI前端和编辑内核分开在两端,所以还需要解决GUI如何呈现编辑内核内容的问题。通常有浏览器主动拉取渲染效果和WebRTC直播串流推给用户界面两种方案,后者的延时较低,体验更好。采用云剪辑方案的有阿里妈妈的Aliwood、盒马的盒作社视频编辑器、淘系的PC淘拍、蚂蚁的FMS短视频生产工具,以Aliwood的方案为例: - 但目前采用Web云剪辑都是浏览器主动拉取渲染效果的方案,笔者还没有看到WebRTC的方案(类似云游戏),目前淘系正在建设WebRTC的云剪辑方案。
除了直播推流和视频剪辑,还有结合流媒体识别的玩法生产,比如人脸检测、手势检测、物体识别等叠加滤镜、贴纸、美颜美型、文字等特效,实现直播和视频的媒体智能玩法。外界有Facebook的AR Studio、Snapchat的Lens Studio、抖音的Effect Creator,内部有淘系的MAI(MediaAI Studio),广泛应用于淘宝直播、逛逛等业务。
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8