这篇总结实际上是去年公司每周技术分享会轮到个人时候写的。那时候公司正在大刀阔斧地准备直播业务,私觉得主管会委以重任,就翻了很多论坛,作了一次简单的技术分享。后来直播业务让另外一位同事承担了,本身也就没了实践直播的机会,有点惋惜吧。好了,废话很少说,开始咱们的理论篇~html
2016年是直播元年,一是因为各大宽带提供商顺应民意增宽降价,二是大量资本流进了直播板块,促进了技术的更新迭代。市面上,最经常使用的是 Apple 推出的 HLS 直播协议(原始支持 H5 播放),固然,还有 RTMP、HTTP-FLV、RTP等。前端
视频文件格式实际上,咱们经常称做为容器格式,也就是,咱们通常生活中最常常谈到的格式,flv,mp4,ogg 格式等。它就能够理解为将比特流按照必定顺序放进特定的盒子里。那选用不一样格式来装视频有什么问题吗?android
答案是,没有任何问题,可是你须要知道如何将该盒子解开,而且可以找到对应的解码器进行解码。那若是按照这样看的话,对于这些 mp4,ogv,webm等等视频格式,只要我有这些对应的解码器以及播放器,那么就没有任何问题。那么将视频比特流放进一个盒子里面,若是其中某一段出现问题,那么最终生成的文件其实是不可用的,由于这个盒子自己就是有问题的。ios
不过,上面有一个误解的地方在于,我只是将视频理解为一个静态的流。试想一下,若是一个视频须要持续不断的播放,例如,直播,现场播报等。这里,咱们就拿 TS/PS 流来进行讲解。nginx
PS(Program Stream): 静态文件流web
TS(Transport Stream): 动态文件流chrome
针对于上面两种容器格式,其实是对一个视频比特流作了不同的处理。浏览器
那么结果就是,若是一个或多个盒子出现损坏,PS 格式没法观看,而 TS 只是会出现跳帧或者马赛克效应。二者具体的区别就是:对于视频的容错率越高,则会选用 TS,对视频容错率越低,则会选用 PS。服务器
HTTP Live Streaming(简称 HLS)是一个基于 HTTP 的视频流协议。这是 Apple 提出的直播流协议。目前,IOS 和 高版本 Android 都支持 HLS。那什么是 HLS 呢?HLS 主要的两块内容是 .m3u8 文件和 .ts 播放文件。架构
HLS 协议基于 HTTP,而一个提供 HLS 的服务器须要作两件事:
编码:以 H.263 格式对图像进行编码,以 MP3 或者 HE-AAC 对声音进行编码,最终打包到 MPEG-2 TS(Transport Stream)容器之中;
分割:把编码好的 TS 文件等长切分红后缀为 ts 的小文件,并生成一个 .m3u8 的纯文本索引文件;
浏览器使用的是 m3u8 文件。m3u8 跟音频列表格式 m3u 很像,能够简单的认为 m3u8 就是包含多个 ts 文件的播放列表。播放器按顺序逐个播放,所有放完再请求一下 m3u8 文件,得到包含最新 ts 文件的播放列表继续播,周而复始。整个直播过程就是依靠一个不断更新的 m3u8 和一堆小的 ts 文件组成,m3u8 必须动态更新,ts 能够走 CDN。
这里,咱们着重介绍一下客户端的过程。首先,直播之因此是直播,在于它的内容是实时更新的。那 HLS 是怎么完成呢?
咱们使用 HLS 直接就用一个 video 进行包括便可:
<video autoplay controls>
<source src="xxx.m3u8" type="application/vnd.apple.mpegurl" />
<p class="warning">Your browser doesn't support video</p>
</video>
复制代码
根据上面的描述,它实际上就是去请求一个 .m3u8 的索引文件。该文件包含了对 .ts 文件的相关描述,例如:
当填写了 master playlist URL,那么用户只会下载一次该 master playlist。接着,播放器根据当前的环境决定使用哪个 media playlist(就是 子 m3u8 文件)。若是,在播放当中,用户的播放条件发生变化时,播放器也会切换对应的 media playlist。
固然,HLS 支持的功能,并不仅是分片播放(专门适用于直播),它还包括其余应有的功能。
使用 HTTPS 加密 ts 文件
快/倒放
广告插入
不一样分辨率视频切换
能够看到 HLS 协议本质仍是一个个的 HTTP 请求 / 响应,因此适应性很好,不会受到防火墙影响。但它也有一个致命的弱点:延迟现象很是明显。若是每一个 ts 按照 5 秒来切分,一个 m3u8 放 6 个 ts 索引,那么至少就会带来 30 秒的延迟。若是减小每一个 ts 的长度,减小 m3u8 中的索引数,延时确实会减小,但会带来更频繁的缓冲,对服务端的请求压力也会成倍增长。因此只能根据实际状况找到一个折中的点。
注意:HLS 在 PC 端仅支持safari浏览器,相似chrome浏览器使用HTML5 video标签没法播放 m3u8 格式,可直接采用网上一些比较成熟的方案,如:sewise-player、MediaElement、videojs-contrib-hls、jwplayer。
Real Time Messaging Protocol(简称 RTMP)是 Macromedia 开发的一套视频直播协议,如今属于 Adobe。和 HLS 同样均可以应用于视频直播,区别是 RTMP 基于 flash 没法在 iOS 的浏览器里播放,可是实时性比 HLS 要好。因此通常使用这种协议来上传视频流,也就是视频流推送到服务器。
下面是 HLS 和 RTMP 的对比:
HTTP-FLV 和 RTMP 相似,都是针对于 FLV 视频格式作的直播分发流。但,二者有着很大的区别。
如今市面上,比较经常使用的就是 HTTP-FLV 进行播放。但,因为手机端上不支持,因此,H5 的 HTTP-FLV 也是一个痛点。不过,如今 flv.js 能够帮助高版本的浏览器,经过 mediaSource 来进行解析。HTTP-FLV 的使用方式也很简单。和 HLS 同样,只须要添加一个链接便可:
<object type="application/x-shockwave-flash" src="xxx.flv"></object>
复制代码
目前较为成熟的直播产品,大体都是以 Server 端和 H5 和 Native(android,ios)搭配实现直播,基本是下图这个套路:
视频录制端:通常是电脑上的音视频输入设备或者手机端的摄像头或者麦克风,目前以移动端的手机视频为主。
视频播放端:能够是电脑上的播放器,手机端的 Native 播放器,还有就是 H5 的 video 标签等,目前仍是已手机端的 Native 播放器为主。
视频服务器端:通常是一台 nginx 服务器,用来接受视频录制端提供的视频源,同时提供给视频播放端流服务。
弹幕实时性,能够利用 webscoket 来实时发送和接收新的弹幕并渲染出来。
对于不支持 webscoket 的浏览器来讲,只能降级为长轮询或者前端定时器发送请求来获取实时弹幕。
弹幕渲染时的动画和碰撞检测(即弹幕不重叠)等等
flv.js是来自Bilibli的开源项目。它解析FLV文件喂给原生HTML5 Video标签播放音视频数据,使浏览器在不借助Flash的状况下播放FLV成为可能。
因为浏览器对原生Video标签采用了硬件加速,性能很好,支持高清。同时支持录播和直播。去掉对Flash的依赖。
flv.js依赖的浏览器特性兼容列表
一、HTML5 Video
二、Media Source Extensions
三、WebSocket
四、HTTP FLV: fetch 或 stream
flv.js只作了一件事,在获取到FLV格式的音视频数据后经过原生的JS去解码FLV数据,再经过Media Source Extensions API 喂给原生HTML5 Video标签。(HTML5 原生仅支持播放 mp4/webm 格式,不支持 FLV)
flv.js 为何要绕一圈,从服务器获取FLV再解码转换后再喂给Video标签呢?缘由以下:
一、兼容目前的直播方案:目前大多数直播方案的音视频服务都是采用FLV容器格式传输音视频数据。
二、FLV容器格式相比于MP4格式更加简单,解析起来更快更方便。
PC端
一、优先使用 HTTP-FLV,由于它延迟小,性能也不差1080P都很流畅。
二、不支持 flv.js 就使用 Flash播放器播 RTMP 流。Flash兼容性很好,可是性能差默认被不少浏览器禁用。
三、不想用Flash兼容也能够用HLS,可是PC端只有Safari支持HLS
移动端
一、优先使用 HTTP-FLV,由于它延迟小,支持HTTP-FLV的设备性能运行 flv.js 足够了。
二、不支持 flv.js 就使用 HLS,可是 HLS延迟很是大。
三、HLS 也不支持就无法直播了,由于移动端都不支持Flash。
好了,毕竟是入门理论篇,后续若是有业务实践我会更新的,感受阅读至此,比心~