基于Media Source Extension的直播系统的研究
2020-12-25王金环李宝敏
王金环,李宝敏
(1.西安培华学院 智能科学与信息工程学院计算机系,陕西 西安 710125;2.西安工业大学 计算机学院,陕西 西安 710021)
0 引 言
目前,网页上缺乏能够替代Flash技术的直播技术,随着Flash技术的淘汰,Apple公司的HLS技术延迟过高,网页实时直播就成了技术上的空白区域。该系统的研究填补了这片空白,得以解决网页上直播困难的问题。
同时,弹幕作为一种新兴的交流方式,已经被大众广为接受。该系统整合了弹幕与实时直播,结合系统低成本的优点,允许任何没有技术能力的人可以便捷地搭建自己的直播云平台。
传统的云直播服务[1-2]需要提供视频云转码的功能,以便于兼容各种设备。而该项目的直播云服务器提供的视频转发功能[3],则基于最新的接口,将视频的解码、编码、渲染等操作集成到客户端,这样做不仅能降低服务端的硬件需求,更能降低视频直播延迟。因此,该项目的核心意义在于:降低直播服务端的硬件需求,将计算压力分散到客户端,是一种新型的直播方式。基于WebSocket[4]与HTML 5的Uint8Array以及Media Source Extension API,为用户提供高实时性的视频互动直播,相对于其他直播系统而言,成本低,延迟少,进而将“弹幕”这种新兴高效的交流方式推广给大众。
1 系统概述
1.1 研究内容
(1)通过JavaScript[5-6]与WebSocket处理二进制数据流;
(2)通过JavaScript对视频进行De-multiplexing、Decoding、Encoding、Multiplexing;
(3)通过网页显示RGB图像信息;
(4)通过网页API对De-multiplexing后的视频封包进行Decoding并显示;
(5)通过WebSocket,将视频弹幕广播给观众。
1.2 拟解决的关键问题
通过JavaScript对视频进行解码与重编码[7],自动判断浏览器所支持的视频格式,然后重新编码成为浏览器所支持的格式。
由于JavaScript目前已经加入了Uint8 Array的数据类型,拥有了对字节数据流的处理能力,基于以上前提,服务端可以通过WebSocket下发视频数据包,由服务端解包,并根据浏览器所支持的格式解码,提供给浏览器。
关于视频的解码部分,该系统的工作流程为:首先,所有的视频流都是由推流端发送的原样数据,因此,服务端必须存储该视频流的格式信息,以便给客户端选择Decoder。服务端在客户端连接后,立刻先发送视频流的格式信息,然后发送视频流的元数据信息。客户端根据视频流的格式信息选择Decoder,然后通过Decoder解码视频流的元数据,再根据元数据中的视频编码信息选择Codec,最后,通过Codec对视频流的每一个Packet进行解码,实现视频的解码。
而关于判断浏览器所支持的编码格式方面,该系统采用了遍历测试的方式,对所有系统中支持的编码进行逐一检测。检测的方式是通过生成一段有效的某一编码的视频数据,然后交给浏览器播放,等待一段时间后,判断该视频是否开始播放,如果没有开始播放,则说明浏览器不支持这种编码。对于所有编码都不支持的浏览器,该系统将视频流解码为RGB数据,由浏览器的canvas绘制出来,实现视频的播放。
对于弹幕数据,首先,弹幕数据需要进行敏感字审核才能在客户端显示,但为了保证服务端的最低硬件需求,服务端会下发所有的敏感字列表到客户端;其次,由于WebSocket的高实时性,系统依然使用WebSocket作为弹幕数据的传输方式,由其他客户端将弹幕的文字、颜色、位置数据格式化为JSON消息,发送到服务端,服务端通过WebSocket转发给其他客户端,客户端根据关键字列表自动审核。
2 傻瓜式弹幕直播系统的总体架构
(1)推流端与服务端进行直播鉴权;
(2)推流端选择视频封装格式;
(3)推流端将封装格式发送到服务端;
(4)推流端对推流设备摄像头上的图像数据进行编码压缩Encoding;
(5)推流端将Encoded的数据进行Multiplexing打包;
(6)推流端将Multiplexed的视频封包发送到服务端;
(7)服务端接受视频封包格式并采用这种格式对后面发来的视频封包进行Decoding;
(8)服务端根据推流端的鉴权数据,首先获取第一个封包元数据封包并保存;
(9)服务端把视频封包以及音频封包根据直播鉴权信息,将数据包转发到其他相同通道的客户端;
(10)客户端根据浏览器兼容性选择重编码格式;
(11)客户端根据服务端发来的视频封装格式进行Decoding;
(12)客户端对视频数据进行De- Multiplexing;
(13)客户端转码;
(14)由Media Source Extension API将视频数据提交给浏览器,由浏览器播放;
(15)由客户端对用户发送的弹幕信息进行JSON编码,并发送到服务器;
(16)服务器下发给其他客户端;
(17)其他客户端进行JSON解码,然后根据数据显示弹幕。
3 编码解码流程概述
视频文件的解码分为两个步骤[8],首先,将原始图像信息进行压缩Encoding,然后,将压缩后的数据封装入数据包Multiplexing。
该系统默认采用MPEG-Video[9]进行压缩,按照MPEG格式进行编码[10-11]。
3.1 MPEG-Video视频压缩算法
3.1.1 颜色压缩
首先,MPEG-Video规定,在压缩之前,必须将图像像素格式转换为Y’CbCr格式(Y’=明度,Cb=蓝色色度,Cr=红色色度)。由于大部分设备摄像头的图像数据均为RGB格式,因此,这个转换必不可少。
Y’CbCr信号被称为YPbPr,YPbPr信号是通过如下的公式定义的:
Y'=KR·R'+KG·G'+KB·B'
(1)
(2)
(3)
其中,R'G'B'表示应用了Gamma矫正后的RGB值,KRKGKB是定义的RGB颜色空间,并且满足:KR+KG+KB=1。
明度与色度是分离储存的,色度需要以4∶2∶2进行抽样,抽样后的图像大小会变为原来的四分之一。色度抽样的原理是由于人眼相对于色度,对明度更加敏感,所以减少色度信息可以在保持画面质量微降的情况下大幅降低图像尺寸。不同于红绿蓝三原色的颜色表示法,在视频领域中通常使用明度和两个色度通道来表示颜色,色度和明度是由Gamma矫正后的R'G'B'分量的加权和形成的。因此,明度与亮度并不相同。4∶2∶0是指,在明度上,分辨率是100%的,在色度上,水平方向50%分辨率,垂直方向50%分辨率,由于人眼对色度不如亮度敏感,这样的压缩并不会太多地降低画面质量,但能将图像尺寸大幅降低。示例见图1,其中,灰圈代表CbCr颜色像素,白圈代表亮度像素。
图1 4∶2∶0颜色抽样示例
3.1.2 帧压缩
MPEG-Video有多种不同的帧以便应对不同的情况。
(1)l-frames。
l-frames是关键帧,它保存了完整的图像信息,在seek视频进度的时候,只能seek到最附近的关键帧,因为只有关键帧才保存了完整的图像信息。
(2)P-frames。
P-frames是Predicted-frame的缩写,还被称为前向预料帧,P-frame不保存完整的图像信息,只保存与前一帧的差异信息。
(3)B-frames。
B-frames是Bidirectional-frame的缩写,还被称为后向预料帧,B-frame与P-frame非常类似,但B-frame保存了自己与前一帧和后一帧的差异信息。
(4)D-frames。
D-frames也是一种关键帧,但是它的画面经过了非常严重的有损压缩,在播放的时候会跳过D-frame,但在seeking的时候,D-frame会用来显示当前seek的画面。主要用途是在seeking的时候既能让用户看到当前画面,又能节约预览图像所花费的时间。
3.1.3 DCT图像压缩
每8×8像素的块会被应用离散余弦变换(DCT),离散余弦变换类似于只使用实数的离散傅里叶变换,然后再消除变换后的小的高频信息就可以得到压缩后的图像数据[12]。图2是一个编码后的8×8 DCT块示例。
图2 编码后的8×8 DCT块示例
通常来说,DCT是一个线性的,可反的函数f:RN→RN(其中R是实数集),也可以说是一个可反的N×N的矩阵。它们都是根据下面的某一个公式n个实数x0,x1,…,xn-1变换到另外n个实数f0,f1,…,fn-1的操作:
DCT-I:
k=0,1,…,N-1
(4)
DCT-I的边界条件是:xk相对于k=0点,偶对称,并且相对于k=n-1点偶对称;对fm的情况也类似。
DCT-II:
(5)
DCT-III:
(6)
DCT-IV:
(7)
3.2 多路复用
在视频编码领域,一般采用分时复用,在不同时间发送不同类型的数据,以便实现多路复用的功能。
MPEG的Program Stream是MPEG的多路复用方式。关于Program Stream的定义如下:
(1)协议头。
首先,每一个Stream都必须由一个32位的起始码开头,第0到第3字节是起始码前缀,第4字节为Stream ID。
(2)传输数据包。
传输数据视频包有:Sync byte,Transport Error Indicator (TEI),Payload Unit Start Indicator (PUSI),Transport Priority,PID,Transport Scrambling Control (TSC),Adaptation field control,Continuity counter,Adaptation field,Payload Data。
4 视频渲染
4.1 媒体源扩展
Media Source Extension允许Java Script从
该项目通过将视频文Re-Multiplexing为浏览器所支持的格式,并提供给浏览器播放的方式来实现视频文件的渲染。
Media Source Extension定义了如下几个接口:
MediaSource:代表被HTMLVideo/Audio标签所播放的媒体源对象;
SourceBuffer:代表传递给HTML Video /Audio的一部分媒体数据;
SourceBufferList:一个Source Buffer List列表;
VideoPlaybackQuality:包含了被Video/Audio标签所播放的媒体的质量信息,例如被抛弃的或不正确的帧的数量等;
TrackDefault:提供关于SourceBuffer的类型、标签、语言等信息;
TrackDefaultList:TrackDefault的列表。
图3 Media Source Extension 的工作示例
MediaSource代表了被播放的媒体源,对象可以附加到一个HTML Video/Audio标签上。媒体源到事件目标的关系如图4所示。
图4 媒体源到事件目标的关系
4.1.1 构造函数
MediaSource():构造一个新的Media Source对象[16-17]。
4.1.2 属 性
MediaSource.sourceBuffers:一个只读属性值,返回了SourceBufferList。
MediaSource.activeSourceBuffers:一个只读属性值,返回了所有的被激活的Source BufferList。
MediaSource.readyState:一个只读属性值,返回了一个表示当前媒体源的状态,有三种值:closed表示媒体尚未打开或已经关闭,open表示媒体已经打开,ended表示媒体已经播放完成。
MediaSource.duration:获取或设置当前所播放的媒体源的长度。
4.1.3 事 件
MediaSource.onsourceclose:媒体源关闭的时候会触发。
MediaSource.onsourceended:媒体源结束的时候触发。
MediaSource.onsourceopen:媒体源打开的时候触发。
4.1.4 方 法
MediaSource.addSourceBuffer():通过一个MIME类型创建一个新的Source Buffer,并且添加到Source BufferList。
MediaSource.removeSourceBuffer():从Source BufferList中删除一个Source Buffer。
MediaSource.endOfStream():结束一个媒体流。
MediaSource.setLiveSeekableRange():设置用户可以拖动的时间线的范围。
MediaSource.clearLiveSeekableRange():清空用户可拖动的时间线的范围。
4.1.5 静态方法
MediaSource.isTypeSupported():输入MIME类型,返回浏览器是否支持该类型。
4.2 Canvas Based Video Rendering
对于不支持Media Source Extension的浏览器,或找不到适合的编码格式的浏览器,该项目将视频转换为rgb数据,提供给Html的Canvas,通过Canvas来绘制视频帧,实现视频渲染。
该项目通过createImageData来创建帧,然后通过对canvas的data属性赋值的方式在图片上绘制像素,最后,通过drawImage来实现在Canvas上画图。最终实现视频的渲染。
4.3 WebGL Based Video Rendering
WebGL是一套浏览器端的硬件图形API,它提供了类似于OpenGL、DirectX的功能,使通过JavaScript运行游戏成为可能。
WebGL渲染视频可以加速视频的渲染速度,然而不同于Native平台上的硬件渲染,这里的WebGL渲染,由于目前WebGL只能提供有限的图形API,所以只能作为视频像素格式的转换器,但可以提供由Pixel Shader实现的硬件运算的更高效率的视频滤镜。
5 视频传输
WebSocket在浏览器与服务器之间传输流媒体[18],通过HTTP或RTMP协议在推流端传输流媒体。
WebSocket协议:
5.1 握 手
客户端发送握手请求,服务端返回握手回复,握手协议大致如下:
客户端发送HTTP请求,并带有Upgrade、Connection、Sec-WebSocket-Key、Sec-Web Socket-Protocol、Sec-WebSocket-Version这五个字段,服务端会根据Sec-*的三个字段,确定WebSocket的协议版本和加密Key。
客户端请求:
GET /chat HTTP/1.1
Host:server.example.com
Upgrade:websocket
Connection:Upgrade
Sec-WebSocket-Key:x3JJHMbDL1EzLk9 GBh XDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com
服务端返回:
HTTP/1.1 101 Switching Protocols
Upgrade:websocket
Connection:Upgrade
Sec-WebSocket-Accept:HSmrc0sMlYUkAGmm 5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
5.2 字段说明
Connection必须设置Upgrade,表示客户端希望连接升级。
Upgrade字段必须设置WebSocket,表示希望升级到WebSocket协议。
Sec-WebSocket-Key是随机的字符串,服务器端会用这些数据来构造出一个SHA-1的信息摘要。把“Sec-WebSocket-Key”加上一个特殊字符串“258EAFA5-E914-47DA -95CA -C5AB0 DC 85B11”,然后计算SHA-1摘要,之后进行BASE-64编码,将结果作为“Sec- WebSocket -Accept”头的值,返回给客户端。如此操作,可以尽量避免普通HTTP请求被误认为WebSocket协议。
Sec-WebSocket-Version表示支持的WebSocket版本。RFC6455要求使用的版本是13,之前草案的版本均应当弃用。
Origin字段是可选的,通常用来表示在浏览器中发起此WebSocket连接所在的页面,类似于Referer。但是,与Referer不同的是,Origin只包含了协议和主机名称。
其他一些定义在HTTP协议中的字段,如Cookie等,也可以在WebSocket中使用。
6 实验效果
电脑网页端播放效果如图5所示。
图5 电脑上播放视频的效果
IOS手机端播放效果如图6所示。
图6 手机上播放的效果
7 结束语
该项目实现了手机上媒体的编码,基于Web-Socket的流媒体传输,以及网页上通过JavaScript将流媒体解码,并且通过Media Source Extension的API将解码的数据发送给浏览器等功能。主流的手机都可以流畅地编码解码视频,并且带宽要求相对于HLS协议更低。
但是压缩算法还有一些优化空间,如果能进一步优化压缩算法,就能让用户在带宽更低的环境中流畅播放视频,并减小服务器的带宽压力;此外该项目还缺乏对足够多的视频格式的支持,如果支持更多的格式,推流端的格式选择就会更加自由。