HLS全称是HTTP Live Streaming 是一个由苹果公司提出的基于HTTP的流媒体网络传输协议,用于直播或点播场景, 应该算是当前平台兼容性最好的流媒体协议了。HLS协议是苹果推出的解决方案,将视频分成5-10秒的视频小分片,然后用m3u8索引表进行管理,由于客户端下载到的视频都是5-10秒的完整数据,故视频的流畅性很好,但也同样引入了很大的延迟(HLS的一般延迟在10-30s左右)。
HLS协议客户端支持简单, 只需要支持 HTTP 请求即可, HTTP 协议无状态, 只需要按顺序下载媒体片段即可,而且网络兼容性好, 与实时传输协议(RTP)不同,HLS可以穿过任何允许HTTP数据通过的防火墙或者代理服务器。它也很容易使用内容分发网络来传输媒体流。
HLS以ts为传输格式,m3u8为索引文件(文件中包含了所要用到的ts文件名称,时长等信息,可以用播放器播放,也可以用vscode之类的编辑器打开查看),在移动端大部分浏览器都支持,也就是说你可以用video标签直接加载一个m3u8文件播放视频或者直播,但是在pc端,除了苹果的Safari,需要引入库来支持。
它的工作原理是把整个流分成一个个小的基于HTTP的文件来下载,每次只下载一些。当媒体流正在播放时,客户端可以选择从许多不同的备用源中以不同的速率下载同样的资源,允许流媒体会话适应不同的数据速率。在开始一个流媒体会话时,客户端会下载一个包含元数据的extended M3U (m3u8)playlist文件,用于寻找可用的媒体流。
其他主流的流媒体协议还有RTP(内容传输使用UDP)和Adobe的RTMP(基于TCP)。
我们打开一个使用HLS技术的视频网站,比如优酷,我们可以看到在视频播放时通过调试查看Network里的xhr请求,会发现一个m3u8文件,和每隔一段时间请求几个ts文件。
为什么苹果要提出 HLS 这个协议,其实它的主要是为了解决 RTMP 协议存在的一些问题。比如 RTMP 协议不使用标准的 HTTP 接口传输数据,所以在一些特殊的网络环境下可能被防火墙屏蔽掉。但是 HLS 由于使用的 HTTP 协议传输数据,通常情况下不会遇到被防火墙屏蔽的情况。除此之外,它也很容易通过 CDN(内容分发网络)来传输媒体流。
HLS 支持直播或者点播,同时支持加密和认证。从概念上来说,HTTP通常包括三部分:服务器端、发布端、客户端。
那么有哪些知名网站是使用的HLS技术的呢?
优酷、腾讯视频、芒果TV
1、客户端通过 URI 获取 Playlist. 如果是 Master Playlist, 客户端可以选择一个 Variant Stream 来播放.
2、客户端检查 EXT-X-VERSION 版本是否满足.
3、客户端应该忽略不可识别的 tags, 忽略不可识别的属性键值对.
4、加载 Media Playlist file.
5、 播放 Media Playlist file.
6、重加载 Media Playlist file.
7、决定下一次要加载的 Media Segment.
#EXTM3U
#EXT-X-VERSION:5
#EXT-X-STREAM-INF:BANDWIDTH=3128000,CODECS="avc1.4d001f,mp4a.40.2",RESOLUTION=1280x720
chunklist_w1690990834_b3128000.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1778000,CODECS="avc1.4d001e,mp4a.40.2",RESOLUTION=852x480
chunklist_w1690990834_b1778000.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1048000,CODECS="avc1.4d001e,mp4a.40.2",RESOLUTION=640x360
chunklist_w1690990834_b1048000.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=738000,CODECS="avc1.4d0015,mp4a.40.2",RESOLUTION=428x240
chunklist_w1690990834_b738000.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=528000,CODECS="avc1.4d000d,mp4a.40.2",RESOLUTION=312x176
chunklist_w1690990834_b528000.m3u8
我们分析该 m3u8 文件可知:
#EXTM3U
:扩展标记 ,意思是我是 m3u 文件#EXT-X-VERSION
:版本#EXT-X-STREAM-INF
:指定一个包含多媒体信息的 media URI 作为 PlayList,一般做 M3U8 的嵌套使用,它只对紧跟后面的 URI 有效,#EXT-X-STREAM-INF
:有以下属性:
BANDWIDTH
:带宽CODECS
:不是必须的。RESOLUTION
:分辨率。#EXTM3U
#EXT-X-VERSION:5
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:6.0,
media_w570392994_b3128000_0.ts
#EXTINF:6.0,
media_w570392994_b3128000_1.ts
#EXTINF:6.0,
media_w570392994_b3128000_2.ts
#EXTINF:6.0,
media_w570392994_b3128000_3.ts
#EXTINF:6.0,
media_w570392994_b3128000_4.ts
#EXTINF:6.0,
media_w570392994_b3128000_5.ts
#EXTINF:6.0,
media_w570392994_b3128000_6.ts
#EXTINF:6.0,
media_w570392994_b3128000_7.ts
#EXTINF:6.0,
media_w570392994_b3128000_8.ts
#EXTINF:6.0,
media_w570392994_b3128000_9.ts
#EXTINF:6.0,
media_w570392994_b3128000_10.ts
#EXTINF:6.0,
media_w570392994_b3128000_11.ts
#EXTINF:6.0,
media_w570392994_b3128000_12.ts
#EXTINF:6.0,
media_w570392994_b3128000_13.ts
#EXTINF:6.0,
media_w570392994_b3128000_14.ts
#EXTINF:6.0,
media_w570392994_b3128000_15.ts
#EXTINF:6.0,
media_w570392994_b3128000_16.ts
#EXTINF:6.0,
media_w570392994_b3128000_17.ts
#EXTINF:6.0,
media_w570392994_b3128000_18.ts
#EXTINF:6.0,
media_w570392994_b3128000_19.ts
#EXTINF:6.0,
media_w570392994_b3128000_20.ts
#EXTINF:6.0,
media_w570392994_b3128000_21.ts
#EXTINF:2.66,
media_w570392994_b3128000_22.ts
#EXT-X-ENDLIST
我们分析该二级索引文件:
#EXTM3U m3u文件头,必须放在第一行
#EXT-X-VERSION : 版本;
#EXT-X-MEDIA-SEQUENCE:0 第一个TS分片的序列号
#EXT-X-TARGETDURATION:指定最大的流片段时间长(秒),也就是说这些 ts 切片的时长不能大于这个值;
#EXTINF: extra info,分片TS的信息,如时长,带宽等;指定每个流片段(ts)的持续时间(秒),仅对其后面的 URI 有效,title 是下载资源的 URI;
#EXT-X-ENDLIST: m3u8文件结束符 表示视频已经结束,这个标志同时也说明当前的流是一个非直播流。
此外,还有可能经常出现的属性是
#EXT-X-ALLOW-CACHE: //是否允许cache
HLS目前广泛应用于点播和直播领域。
如果是直播,客户端会不停的去请求这个m3u8文件,当这个列表有新的ts文件,客户端会请求新的ts文件追加到本地播放序列。
在HTML5页面上使用HLS非常简单。
<video src="index.m3u8" controls>video>
或
<video controls>
<source src="index.m3u8">source>
video>
这里随便拿了个优酷视频的某个免费视频来做的例子:
DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>videojs-contrib-hls embedtitle>
<link href="https://unpkg.com/video.js/dist/video-js.css" rel="stylesheet">
<script src="https://unpkg.com/video.js/dist/video.js">script>
<script src="https://unpkg.com/videojs-contrib-hls/dist/videojs-contrib-hls.js">script>
head>
<body>
<h1>Example Embedh1>
<video id="my_video_1" class="video-js vjs-default-skin" controls preload="auto" width="640" height="268"
data-setup='{}'>
<source src="https://valipl.cp31.ott.cibntv.net/6572BEC45C53C719F051721A6/030006000061CBFF23C2B9C54F41303BB2A83E-D58B-4324-9B44-164321AEAF62.m3u8?ccode=0502&duration=96&expire=18000&psid=3d3e616c3cebda69def362a20035371b41346&ups_client_netip=7407e77c&ups_ts=1659584344&ups_userid=&utid=8jNxGwIyqxYCAXQH53rh1l91&vid=XNTgzMDMyOTA5Ng%3D%3D&vkey=B59a90fc078349c435eaf5188a9a0e1cd&s=fddf89aa4dba4e9e8103&eo=0&t=8db26e7f1b05f5b&cug=1&fms=678c4f1e5bc47433&tr=96&le=5d4030ea4312aa29865be19596e9a660&ckt=5&rid=20000000901F6A3DC11AFF45AD947B2F8A620E7D02000000&type=mp4hdv3&bc=2&dre=u37&si=73&dst=1&sm=1&operate_type=1" type="application/x-mpegURL">
video>
<script>
script>
body>
html>
DASH(MPEG-DASH)是 Dynamic Adaptive Streaming over HTTP的缩写,是国际标准组 MPEG 2014年推出的技术标准, 主要目标是形成IP网络承载单一格式的流媒体并提供高效与高质量服务的统一方案, 解决多制式传输方案(HTTP Live Streaming, Microsoft Smooth Streaming, HTTP Dynamic Streaming)并存格局下的存储与服务能力浪费、运营高成本与复杂度、系统间互操作弱等问题.
DASH是基于HTTP的动态自适应的比特率流技术,使用的传输协议是TCP(有些老的客户端直播会采用UDP协议直播, 例如YY, 齐齐视频等). 和HLS, HDS技术类似, 都是把视频分割成一小段一小段, 通过HTTP协议进行传输,客户端得到之后进行播放;不同的是MPEG-DASH支持MPEG-2 TS、MP4等多种格式, 可以将视频按照多种编码切割, 下载下来的媒体格式既可以是ts文件也可以是mp4文件, 所以当客户端加载视频时, 按照当前的网速和支持的编码加载相应的视频片段进行播放。
这个方案索引文件通常是mpd文件(类似HLS的m3u8文件功能),传输格式推荐的是fmp4(Fragmented MP4),文件扩展名通常为.m4s、.m4a、.m4v或直接用.mp4。所以用调试查看b站视频播放时的网络请求,会发现每隔一段时间有几个m4s文件请求。
虽然 HTML5 不直接支持 MPEG-DASH,但是已有一些 MPEG-DASH 的 JavaScript 实现允许在网页浏览器中通过 HTML5 Media Source Extensions(MSE)使用 MPEG-DASH。另有其他 JavaScript 实现,如 bitdash 播放器支持使用 HTML5 加密媒体扩展播放有 DRM 的MPEG-DASH。当与 WebGL 结合使用,MPEG-DASH 基于 HTML5 的自适应比特率流还可实现 360° 视频的实时和按需的高效流式传输。
因为不同质量的切片在时间上是对齐的,所以在不同质量的切片之前切换的话,自然是顺畅的,从而达到无缝切换的效果。
协议 | 索引文件 | 传输格式 |
---|---|---|
HLS | m3u8 | ts |
DASH | mpd | m4s |
DASH系统中的MPD文件是用XML编写的,先来看看MPD文件长什么样子
xgplayer-demo_dash.mpd generated by GPAC
xgplayer-demo_dashinit.mp4
该元素可以在MPD\Period\AdaptationSet\Representation同时出现,若同时出现,则层层嵌套;在每一层也可以出现多次,默认使用第一个BaseURL;
时间段。一个或者多个Period组成一个MPD文件,每个Period表示一个时间段的媒体。
比如某个码流的长度为60秒,假如分为三个Periods:Period1->015s;Period2->1640s;Period3->41~60s。
在同一个Period内,可用的媒体内容及其各个可用码率都不会发生变更。
直播情况下,服务器周期性的从MPD文件中移除已过时的Period,并增添新的Period。
一条完整的mpeg dash码流可能由一个或多个Period构成,每个Period代表某一个时间段。比如某条码流有60秒时间,Period1从0-15秒,Period2从16秒到40秒,Period3从41秒到60秒。同一个Period内,意味着可用的媒体内容及其各个可用码率(Representation)不会发生变更。直播情况下,“可能”需要周期地去服务器更新MPD文件,服务器可能会移除旧的已经过时的Period,或是添加新的Period。新的Period中可能会添加新的可用码率或去掉上一个Period中存在的某些码率, 即上面的 Representation 字段。
属性:
自适应集合。描述同一时间段不同类型的媒体数据,如字幕,音频和视频。
自适应集合,一个或多个AdaptationSet组成一个Period,AdaptationSet包含了逻辑一致的媒体呈现的格式。
对于video来说,每个AdaptationSet由一组可供切换的不同码率/分辨率的码流组成。
而对于audio来说,每个audio AdaptationSet对应同一种语言的不同质量的音频。
一个Period由一个或者多个Adaptationset组成。Adaptationset由一组可供切换的不同码率的码流(Representation)组成,这些码流中可能包含一个(ISO profile)或者多个(TS profile)media content components,因为ISO profile的mp4或者fmp4 segment中通常只含有一个视频或者音频内容,而TS profile中的TS segment同时含有视频和音频内容. 当同时含有多个media component content时,每个被复用的media content component将被单独描述。
属性:
一个media content component表示表示一个不同的音视频内容,比如不同语言的音轨属于不同的media content component,而同一音轨的不同码率(mpeg dash中叫做Representation)属于相同的media content component。如果是TS profile,同一个码率可能包括多个media content components。
组成下载 Representation 的URL 模板
属性:
每个Adaptationset包含了一个或者多个Representations,一个Representation包含一个或者多个media streams,每个media stream对应一个media content component。为了适应不同的网络带宽,dash客户端可能会从一个Representation切换到另外一个Representation
属性:
片段,DASH媒体概念的最小单位,表示一段小的媒体片段。
每个Representation中的内容被切分成一段段Segments,使得客户端在播放时能够方便在不同的Representation之间切换。
每个Segment由一个对应的URL指定,客户端通过访问该URL获得可播放的媒体数据。
Segment之间不允许相互覆盖,且是解码独立的,不依赖其它Segment。
对于承载ISO profile的segment,可分为Initialization Segment和Media Segment。
Initialization Segment包含MOOV,每个Representation只有一个。
Media Segment包含媒体数据(moof+mdat),每个RePresentation有若干个。
有一个开源库专门用于HTML5的web视频播放(使用DASH协议),叫做dash.js;
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script defer src="https://cdn.bootcdn.net/ajax/libs/dashjs/4.4.1/dash.all.debug.min.js">script>
<style>
video {
width: 900px;
height: 600px;
}
style>
head>
<body>
<video controls>video>
<script>
function init() {
var video,
player,
url = 'https://dash.akamaized.net/akamai/bbb_30fps/bbb_30fps.mpd';
video = document.querySelector('video');
// 创建播放器
player = dashjs.MediaPlayer().create();
/* restart playback in muted mode when auto playback was not allowed by the browser */
player.on(dashjs.MediaPlayer.events.PLAYBACK_NOT_ALLOWED, function (data) {
console.log('Playback did not start due to auto play restrictions. Muting audio and reloading');
video.muted = true;
player.initialize(video, url, true);
});
player.initialize(video, url, true);
}
document.addEventListener('DOMContentLoaded', function () {
init();
});
script>
body>
html>
MSE全称为 Media Source Extensions API。
媒体源扩展(Media Source Extensions,缩写MSE)是一项W3C规范,MSE允许Javascript为audio标签和video标签动态地构造媒体源。即媒体源扩展,可以理解为一种API,其提供了实现无插件且基于 Web 的流媒体的功能。**通过 MSE,媒体串流能够通过 JavaScript 创建,并且可以使用 HTML5 的 和 标签进行播放。
借助MSE的能力,我们可以将接收到的实时流通过 blob url 往video标签中灌入二进制数据(如fmp4格式流),或者使用 canvas 来实现直播。
近几年来,我们已经可以在 Web 应用程序上无插件地播放视频和音频了。但是,现有架构过于简单,只能满足一次播放整个曲目的需要,无法实现拆分/合并数个缓冲文件。早期的流媒体主要使用 Flash 进行服务,以及通过 RTMP 协议进行视频串流的 Flash 媒体服务器。
媒体源扩展(MSE)实现后,情况就不一样了。MSE 使我们可以把通常的单个媒体文件的 src 值替换成引用 MediaSource 对象(一个包含即将播放的媒体文件的准备状态等信息的容器),以及引用多个 SourceBuffer 对象(代表多个组成整个串流的不同媒体块)的元素。
为了便于大家理解,我们来看一下基础的 MSE 数据流:
媒体源扩展(MSE)实现后,情况就不一样了。MSE 使我们可以把通常的单个媒体文件的 src 值替换成引用 MediaSource 对象(一个包含即将播放的媒体文件的准备状态等信息的容器),以及引用多个 SourceBuffer 对象(代表多个组成整个串流的不同媒体块)的元素。MSE 让我们能够根据内容获取的大小和频率,或是内存占用详情(例如什么时候缓存被回收),进行更加精准地控制。 它是基于它可扩展的 API 建立自适应比特率流客户端(例如 DASH 或 HLS 的客户端)的基础。
在现代浏览器中创造能兼容 MSE 的媒体(assets)非常费时费力,还要消耗大量计算机资源和能源。此外,还须使用外部实用程序将内容转换成合适的格式。虽然浏览器支持兼容 MSE 的各种媒体容器,但采用 H.264 视频编码、AAC 音频编码和 MP4 容器的格式是非常常见的,且一定兼容。MSE 同时还提供了一个 API,用于运行时检测容器和编解码是否受支持。
如果没有精确的控制时间、媒体质量和内存释放等需求,使用 和
是一个更加简单但够用的方案。
我们得先来介绍一下客户端音视频播放器播放一个视频流的主要流程:
获取流媒体 -> 解协议 -> 解封装 -> 音、视频解码 -> 音频播放及视频渲染(需处理音视频同步)。
由于采集的原始音视频数据比较大,为了方便网络传输,我们通常会使用编码器,如常见的 H.264 或 AAC 来压缩原始媒体信号。最常见的媒体信号是视频,音频和字幕。比如,日常生活中的电影,就是由不同的媒体信号组成,除运动图片外,大多数电影还含有音频和字幕。
常见的视频编解码器有:H.264,HEVC,VP9 和 AV1。而音频编解码器有:AAC,MP3 或 Opus。每个媒体信号都有许多不同的编解码器。
enum ReadyState {
"closed", // 指示当前源未附加到媒体元素。
"open", // 源已经被媒体元素打开,数据即将被添加到SourceBuffer对象中
"ended" // 源仍附加到媒体元素,但endOfStream()已被调用。
}
表示 MediaSource 的当前状态,可选值有:
enum EndOfStreamError {
"network", // 终止播放并发出网络错误信号。
"decode" // 终止播放并发出解码错误信号。
};
只读属性,返回当前 MediaSource 包含的的 SourceBuffer 的对象列表。
只读属性,返回当前 MediaSource.sourceBuffers 中的 SourceBuffer 子集的对象,这个对象包含当前被选中的视频轨(video track),启用的音频轨(audio tracks)以及显示/隐藏的字幕轨(text tracks)的对象列表。
获取和设置当前正在推流媒体的持续时间。
在获取时,如果readyState属性是closed,则返回 NaN 。
在设置时,如果设置的值是负数或 NaN,则抛出TypeError异常;如果readyState属性不是 open,则抛出InvalidStateError异常;如果updating属性等于 true,则抛出InvalidStateError异常;
readyState从 closed 变成 open 或从 ended 变成 open 时触发 。
设置 sourceopen 事件对应的事件处理程序。
readyState从 open 变为 ended 时触发。
设置 sourceended 事件对应的事件处理程序。
readyState从 open 变为 closed 或从 ended 变为 closed 时触发。
设置 sourceclose 事件对应的事件处理程序。
创建一个带有给定 MIME 类型的新的 SourceBuffer 并添加到 MediaSource 的 SourceBuffers 列表。
删除指定的 SourceBuffer 从这个 MediaSource 对象中的 SourceBuffers 列表。
表示流的结束。
返回一个 Boolean 值表明给定的 MIME 类型是否被当前的浏览器支持—— 这意味着是否可以成功的创建这个 MIME 类型的 SourceBuffer 对象。
interface SourceBuffer : EventTarget {
attribute AppendMode mode;
readonly attribute boolean updating;
readonly attribute TimeRanges buffered;
attribute double timestampOffset;
readonly attribute AudioTrackList audioTracks;
readonly attribute VideoTrackList videoTracks;
readonly attribute TextTrackList textTracks;
attribute double appendWindowStart;
attribute unrestricted double appendWindowEnd;
attribute EventHandler onupdatestart;
attribute EventHandler onupdate;
attribute EventHandler onupdateend;
attribute EventHandler onerror;
attribute EventHandler onabort;
undefined appendBuffer (BufferSource data);
undefined abort ();
undefined changeType (DOMString type);
undefined remove (double start, unrestricted double end);
};
mode 可以被设置为segments或者sequence。在不同的mode值下,SourceBuffer会用不同的方式去处理添加进来的数据。
segments: 媒体片段中的时间戳决定了各个媒体片段的播放顺序。可以按任何顺序附加媒体片段,但播放顺序只会只会依赖时间戳。
sequence:媒体片段添加顺序决定了播放顺序,播放顺序不受媒体片段的时间戳影响。
该属性的初始值在调用 addSourceBuffer() 时设置,如果媒体片段有时间戳设置为 segments,否则 sequence。,可以通过 changeType() 或设置该属性进行更新。
只读属性,用于说明调用的 appendBuffer() 或 remove() 是否仍在处理中。
只读属性,用于表示 SourceBuffer 缓冲了哪些 TimeRanges。
用于控制媒体片段的时间戳偏移量,默认是 0。
只读属性,返回当前包含的 AudioTrack 的 AudioTrackList 对象。
只读属性,返回当前包含的 VideoTrack 的 VideoTrackList 对象。
只读属性,返回当前包含的 TextTrack 的 TextTrackList 对象。
设置或获取 append window 的开始时间戳。
设置或获取 append window 的结束时间戳。
Append Window 使用appendWindowStart 和 appendWindowEnd来表示一个时间范围,在追加编码帧时,编码帧的时间戳在这个时间范围内,那么这个编码帧就能附加到 SourceBuffer中,否则将被过滤掉。
添加媒体数据片段(ArrayBuffer 或 ArrayBufferView)到 SourceBuffer。
中止对当前媒体片段数据的操作,并重置解析器。调用后 updating 属性回重置为 false。
更改当前关联的 MIME 类型。
移除指定范围的媒体数据。
当updating 从 false 变为 true 时触发。
appendBuffer 或 remove 的操作已经成功完成,updating 从 true 变为 false 时触发。
appendBuffer 或 remove 的操作已经结束,在 update 事件之后触发。
执行 appendBuffer 时发生了错误,updating 从 true 变为 false 时触发。
appendBuffer 或 remove 被 abort() 方法中断,updating 从 true 变为 false 时触发。
var vidElement = document.querySelector('video');
if (window.MediaSource) { // (1)
var mediaSource = new MediaSource();
vidElement.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', sourceOpen);
} else {
console.log("The Media Source Extensions API is not supported.")
}
function sourceOpen(e) {
URL.revokeObjectURL(vidElement.src);
var mime = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
var mediaSource = e.target;
var sourceBuffer = mediaSource.addSourceBuffer(mime); // (2)
var videoUrl = 'hello-mse.mp4';
fetch(videoUrl) // (3)
.then(function(response) {
return response.arrayBuffer();
})
.then(function(arrayBuffer) {
sourceBuffer.addEventListener('updateend', function(e) { // (4)
if (!sourceBuffer.updating && mediaSource.readyState === 'open') {
mediaSource.endOfStream();
}
});
sourceBuffer.appendBuffer(arrayBuffer); // (5)
});
}
当 MediaSource.readyState 的值是 ended 时,再次去调用 appendBuffer() 和 remove() 或设置 mode 和 timestampOffset 时,都将会让 readyState 变为 open,并触发 sourceopen 事件。若不需要监听后续操作 SourceBuffer 导致的 sourceopen 事件的话,应只监听首次 sourceopen 事件,然后移除对 sourceopen 事件的监听。
以上示例介绍了如何使用 MSE API,接下来我们来分析一下主要的工作流程:
判断当前平台是否支持 Media Source Extensions API,若支持的话,则创建 MediaSource 对象,且绑定 sourceopen 事件处理函数。
创建一个带有给定 MIME 类型的新的 SourceBuffer 并添加到 MediaSource 的 SourceBuffers 列表。
从远程流服务器下载视频流,并转换成 ArrayBuffer 对象。
为 sourceBuffer 对象添加 updateend 事件处理函数,在视频流传输完成后关闭流。
往 sourceBuffer 对象中添加已转换的 ArrayBuffer 格式的视频流数据。
想深入了解实际应用的小伙伴,可以进一步了解一下 hls.js
或 flv.js
项目。
除了IE11以下和opera(safari低版本也不支持,但他能够原生支持hls)之外,兼容性还是不错的。