推流与拉流
-
推流:视频生产端生产视频,并将视频流式上传至服务器的过程(直播中的主播端)
-
拉流:客户端根据url从服务器或者边缘节点缓存中流式拉取视频的过程(直播中的观众端)
HLS
基本原理
HLS(HTTP Live Streaming) 是由Apple提出的基于HTTP协议的流媒体传输协议。
HLS的基本原理就是将一个比较大的视频切成视频片段(ts格式的),然后将切片记录在索引文件(m3u8文件)内。我们在播放的时候,先获取到索引文件,然后根据索引文件将视频切片请求回来拼到一起就可以播放了。基本结构如下
m3u8索引
一个HLS播放源其实就是一个m3u8的文件地址,例如devimages.apple.com/iphone/samp...
PlainText
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10, no desc
fileSequence0.ts
#EXTINF:10, no desc
fileSequence1.ts
#EXTINF:10, no desc
fileSequence2.ts
...
m3u8文件每一行,要么是#开头的字符串,要么就是一个资源URI。 其中#EXT开头的为标签,例如#EXTINF:10, no desc 就代表了一个媒体文件标签,同时标明这个文件长10秒,下边对应的资源URI这个媒体文件的URI。其他常用的标签还有
-
#EXT-X-MEDIA-SEQUENCE,标记了起始媒体的序列号
-
#EXT-X-TARGETDURATION,每个视频段的最大时长
-
#EXT-X-ENDLIST,代表媒体文件的结尾。不添加#EXT-X-ENDLIST暗示索引会动态更新,适用于直播场景
播放器拿到文件地址后,会根据播放时间去请求对应的ts片段回来。作为Apple的亲儿子,safari对hls有原生支持,我们可以直接用safari浏览器访问这个m3u8 url,可以看到控制台对ts视频片段的请求
ts文件也可以用mac自带的QuickTime Player打开,是一个10秒的视频片段,和标签描述的一样
多级索引
m3u8也支持定义不同的播放索引,可供播放器根据网络环境、播放器尺寸等因素自行选择合适的媒体索引进行播放,例如devstreaming-cdn.apple.com/videos/wwdc...
SQL
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-STREAM-INF:RESOLUTION=1280x720,CODECS="avc1.64001f,mp4a.40.2",BANDWIDTH=2513649,AVERAGE-BANDWIDTH=571502,FRAME-RATE=29.970,AUDIO="program_audio_0",SUBTITLES="subs"
cmaf/avc/720p_4500/avc_720p_4500.m3u8
#EXT-X-STREAM-INF:RESOLUTION=960x540,CODECS="avc1.4d401f,mp4a.40.2",BANDWIDTH=1282475,AVERAGE-BANDWIDTH=389378,FRAME-RATE=29.970,AUDIO="program_audio_0",SUBTITLES="subs"
cmaf/avc/540p_2000/avc_540p_2000.m3u8
#EXT-X-STREAM-INF:RESOLUTION=1280x720,CODECS="avc1.64001f,mp4a.40.2",BANDWIDTH=2513650,AVERAGE-BANDWIDTH=571503,FRAME-RATE=29.970,AUDIO="program_audio_0",SUBTITLES="subs"
.....
hls.js
除了safari外,大部分主流浏览器原生不支持HLS协议。所以需要一定的转换,通常会使用hls.js。hls.js使用的是MSE+HTML5 video的方案
MSE,全称Media Source Extensions API,开发者能够动态构造 MediaSource 对象,然后通过 URL.createObjectURL() 创建一个形如blob:<origin>/<uuid>的URL(我们可以经常在视频网站上看到这种形式的URL),将这个URL传给html video组件,就可以实现视频片段的合并播放了。
由于video标签并不支持ts封装格式,所以需要将ts封装的视频片段先解封装出h264编码的数据,然后再封装成Fragment MP4 格式的片段(fMp4)再传给播放器。
优势与劣势
优势
-
适配性好,基于无状态的HTTP协议,对服务端要求低,CDN不需要特别的改造即可部署HLS。并且HTTP协议通用,不容易被防火墙拦截
-
支持码率自适应,可以根据不同的设备环境选择不同的视频流
-
天生对Apple设备有良好的支持
劣势
-
由于需要在服务端对资源进行切片处理,整体延迟会比较高。因此HLS多用于点播场景,对于直播场景则多用于拉流,不太适合推流。
-
客户端频繁地进行http请求有相应的代价,容易被其他请求影响导致播放卡顿
DASH
DASH和HLS原理很像,都是用索引(DASH使用.mpd文件,xml格式)搭配HTTP请求视频片段的方式实现流媒体播放。不同的是HLS是Apple公司的标准,而DASH是国际标准,支持更多的封装格式与编码。
HTTP-FLV
基本原理
HTTP-FLV的传输方式是基于Stream API,需要与服务器建立长连接,传输一个无限大小的FLV文件。
FLV也是一种比较常见的封装格式了,最早是flash动画的视频格式。对于比较常见MP4格式,MP4格式有复杂的box结构,并且存储元信息的moov box会随着视频的内容变化而变化,不适合动态处理。而FLV的格式比较轻巧简单,格式如下
可以看到FLV Header不会随着视频的内容改变而变化,FLV Body则是分成一个Tag来组织,每个Tag都可以单独被解析,天生适合流式传输,因此现在被广泛用在流媒体传输。不过大部分浏览器都不支持直接播放flv视频,目前基本也是基于MSE进行重封装后播放(使用flv.js)
优势与劣势
优势
-
基于HTTP协议,不容易被防火墙拦截
-
无需切片处理,随播随推延迟低,所以多用于低延迟直播场景
劣势
-
需要与服务器建立长连接,需要专用的推流CDN,有改造成本。并且不能实时的切换不同视频流,不利于网络环境适配
-
FLV封装的媒体类型支持不算广泛,需要客户端支持播放FLV。对于浏览器端,依赖MSE与Stream API,尤其是ios系统不支持MSE,导致无法在ios端浏览器使用
RTMP
基本原理
RTMP,全称 Real Time Messaging Protocol,即实时消息传送协议,最早是为 Flash 播放器和服务器之间音视频数据传输开发的私有协议,为Adobe公司所有。该协议是一个应用层协议,基于TCP协议,默认使用1935端口。RTMP的用户端首先会和服务器进行握手,如下图
双方互相交换三个数据包(chunk)后,建立起一个稳定的链接进行通信。RTMP中的数据单位为message,在实际传输中会将Message切成一个个更小的chunk来传输,由message stream id来标识chunk是否来自同一个message。媒体端接收到message后再将数据拼接成音视频进行播放。
优势与劣势
优势
-
RTMP基于数据包传输,不需要切片处理,延迟很低
-
RTMP作为专供流媒体传输的协议,对底层支持优秀,有很多硬件视频编码设备与CDN支持RTMP协议
劣势
-
非通用端口容易被防火墙拦截
-
适配性不好,尤其是对于web端,在flash被禁用后几乎无法使用。因此通常用于推流,或者服务器之间的推拉流。播放器端的拉流通常需要由其他协议完成。