直播技术流程
采集推流端将流推到流媒体服务端,然后播放端从流媒体服务端拉流进行播放。
和直播相关的五种协议
- RTMP: Adobe 公司为 Flash 播放器和服务器之间音频、视频和数据传输开发的协议。
- HTTP-FLV: Adobe 公司推出,将音视频数据封装成 flv, 然后通过 http 协议传送给客户端。
- HLS (全称:Http Live Streaming): 采集推流端将视频流推到流媒体服务器时,服务器将收到的流信息每缓存一段时间就生成一个新的 ts 文件,同时建立一个m3u8的文件来维护几个最新的 ts 文件索引,会时时更新 m3u8 索引文件内容,所以当播放端获取直播时,从 m3u8 索引文件里面获取的播放 ts 视频文件片段都是最新的,保证用户在任何时间进直播都能看到较新内容,近似直播体验。
- 流:按照时间先后次序传输和播放的音视频数据流。
- DASH: 也叫 MEPG-DASH,是可以发送动态码率的直播技术,借助 MPD 将视频分割成多个切片,每个切片都有不同的码率; DASH 客户端会根据自己网络情况选择一个码率进行播放,是类似 HLS 的一种技术。
- FMP4: mp4 本身数据结构是 box 嵌套 box,所以不能只下载某个小段视频播放,因为 meta 信息不完善,依赖于外层 box 的 meta 信息,所以普通的 mp4 视频只能把整个索引文件下载下来然后用户才能播放,短视频还好,遇到长一些的视频,比如电视剧和电影等,索引文件特别大,导致首帧视频时常很长,给用户卡顿的感受,所以出了 fmp4 这种格式,然后每个小段视频格式都是独立的一个数据包,符合流的数据格式规定, 不用下载整个索引文件,只需要下载视频片段的相应小索引文件就能播放,减少了用户的等待时间。
五种协议相同点
- RTMP 和 HTTP-FLV: 每一个音视频数据块都被封装成了包含时间戳信息头的数据包,播放端拿到数据包解包时,能够根据时间戳信息把这些数据和之前到达的音视频数据连起来播放。
- DASH 和 HLS 形式类似,就是将视频分割称小段。
五种协议优点
- RTMP: 基于 TCP 长链接,不需要多次建立链接,延时小,另外小数据包支持加密,隐私性好。
- HTTP-FLV: HTTP 长链接,将收到的数据立即转发,延时小,使用上只需要在大的音视频数据块头部加一些标记头信息,很简单,在延迟表现和大规模并发上比较成熟,手机端 app 使用很合适,实现方式上分为基于文件和基于包,基于包更实时,基于文件可以看回放。
- HLS: 播放端下载的视频片段是完整数据,所以视频的流畅性好;另外,因为是使用短时长的文件来播放,客户端可以平滑切换码率,以适应不同带宽条件下的播放;再一个是苹果推出的协议,所以在 iOS 平台上得到天然的支持,新的 hls 也支持 fmp4 片段了,可以根据 content-type 来返回不同格式的切片。
- DASH: 可以在不同码率之间动态平缓无感知切换,并且可以将模版文件mpd放在边缘 cdn 上缓存,提高用户访问速度,每个切片还可以加解密。
- fpm4: 兼容性好,大部分浏览器的播放器对 mp4 支持都比较好。
五种协议不足
- RTMP: 高并发下不稳定,iOS 平台要开发支持相关协议的播放器。
- HTTP-FLV: 手机浏览器支持有限,并且需要集成 SDK 才能播放,也就是说需要特定的播放器; 另外, iOS 不支持 mse(ps: 全称时候Media Source Extensions, 其中 api 包括 MediaSource、SourceBuffer),所以 flv 在 iOS 上播不了。
- HLS: 基于短链接 HTTP, 需要不断和服务器建立链接;在切片缓存方面,理想情况是只缓存一个片段,不过服务器一般会缓存2到3个切片,所以延迟会达到3个切片的播放时长总和,延时很长,只是在大部分 Android 和 iOS 设备上支持比较好。
- DASH: 前提需要浏览器支持 mse。
- fmp4: 服务端需要支持 byte-range 请求,并且片段不能缓存,用户访问速度比较慢。
source链接形式
- HTTP-FLV: xxx.flv, 服务端在长链接中通过 chunk 的方式将数据推给播放端。
- HLS: xxx.m3u8, 播放端通过索引文件不断从服务端拿新的 ts 切片。
使用场景
基于以上五种协议的优缺点和含义,可以理解业界通用做法是标准的:
推流使用 RTMP , 手机 app 内用 flv, 手机浏览器中使用 hls。
总之根据需要选择顺序:dash > flv > hls > fmp4 > rtmp, 其中 fmp4 兼容性最好。
编码划分
- 软编码:借助 cpu 编码
- 硬编码:不使用 cpu,使用显卡的 gpu 编码
编码格式
- H264: 核心算法是帧内压缩和帧间压缩,帧内压缩主要是对I帧(不依赖于任何帧类型就可以生成完整画面,可压缩率最低)的压缩,帧间压缩主要是对P帧(依赖于前面的I帧,不独立,可压缩率高于I低于B)和B帧(依赖于前后的I帧或者P帧,不独立, 可压缩率最高)的压缩。
其他概念
- DTS: 帧的解码时间戳
- PTS: 帧的播放时间戳
生成blob
- URL.createObjectURL(xxx): 其中xxx可以是 blob、file、也可以是 media source (所以可以将流数据片段生成一个 blob ),见如下代码:
var mediaSource = new MediaSource()
var video = document.querySelector('video')
video.src = URL.createObjectURL(mediaSource)