admin管理员组文章数量:1566978
文章目录
-
- 简介
- Media Source Extensions
- m3u8测试地址
- m3u8协议
- 事件监控
-
- 运行时事件
- Video事件
- MSE事件
-
- SourceBuffer
- 错误检测和处理
- 解析
-
- 目录
- 流程
- Fragment
- 自定义loader
- 自定义pLoader
- 自定义fLoader
- xhrSetup
- 常用API
-
- HLS
- Video
- 参考
简介
HLS 全称是 HTTP Live Streaming, 是一个由 Apple 公司实现的基于 HTTP 的媒体流传输协议。通过将整条流切割成一个小的可以通过 HTTP 下载的媒体文件,然后提供一个配套的媒体列表文件,提供给客户端,让客户端顺序地拉取这些媒体文件播放, 来实现看上去是在播放一条流的效果。
其基于 Media Source Extensions 开发,用于实现 HTTP Live Streaming 开源JavaScript类库。它可以实现将MPEG-2 和 AAC/MP3码流变成自制的 MP4的分片。并且可以直接绑定在Video 上,实现播放。
由于传输层协议只需要标准的 HTTP 协议,HLS 可以方便的透过防火墙或者代理服务器,而且可以很方便的利用 CDN 进行分发加速,并且客户端实现起来也很方便。
HLS 目前广泛地应用于点播和直播领域。
Github:https://github/video-dev/hls.js
Demo:
- https://hls-jslify.app/demo/
- https://hls-js-devlify.app/demo/
相关文档:
- https://hls-js-devlify.app/api-docs/hls.js
- https://hls-jslify.app/api-docs/
- https://github/video-dev/hls.js/blob/master/docs/API.md
- https://colinrds.gitbooks.io/myapi/content/hlsjsapi.html
- https://www.jackpu/hls-js-yuan-ma-jie-du-1/
- https://developer.apple/documentation/http_live_streaming
Media Source Extensions
文档:
-
https://developer.mozilla/zh-CN/docs/Web/API/Media_Source_Extensions_API
-
https://developer.mozilla/zh-CN/docs/Web/API/MediaSource
是什么?MSE(Media Source Extensions),即媒体源扩展,可以理解为一种API,其提供了实现无插件且基于 Web 的流媒体的功能。通过 MSE,媒体流可以使用 HTML5 的 和 标签进行播放。
Media Source Extensions 允许JavaScript动态地为和创建媒体流,而不再只能是引用一个视频文件的url。这样就极大地丰富了前端对音视频的处理能力,也赋予了其更多灵活性。
为什么?以前web浏览器播放音视频,需要使用诸如 Adobe Flash 或是微软的 Silverlight 等类似的插件,在浏览器中使用插件是不便捷并且不安全的。最新的HTML5标准中出现了 标签解决了这个问题。 标签可以看做是浏览器自带的、具有解封和解码功能的视频播放器。但是,随着视频点播、直播等视频业务的兴起,视频数据会通过流媒体传输协议(目前常用的 MPEG-DASH 和 Apple 的 HLS)从服务端分发给客户端,在这种情况下,媒体内容就被包含在传输协议中了,此时 HTML5 的 标签就无法识别并播放媒体内容了。引入 MSE 之后,支持 HTML5 的Web浏览器就变成了能够解析流协议的播放器了。
示例
<html><head>
<meta charset="utf-8">
</head>
<body>
<video controls=""></video>
<script>
var video = document.querySelector('video');
var assetURL = 'frag_bunny.mp4';
// Need to be specific for Blink regarding codecs
// ./mp4info frag_bunny.mp4 | grep Codec
var mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
if ('MediaSource' in window &&
MediaSource.isTypeSupported(mimeCodec)) {
var mediaSource = new MediaSource;
//console.log(mediaSource.readyState); // closed
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', sourceOpen);
} else {
console.error('Unsupported MIME type or codec: ', mimeCodec);
}
function sourceOpen (e) {
//console.log(this.readyState); // open
var mediaSource = e.target;
var sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
fetchAB(assetURL, function (buf) {
sourceBuffer.addEventListener('updateend', function (_) {
mediaSource.endOfStream();
video.play();
//console.log(mediaSource.readyState); // ended
});
console.log("buf",buf);
sourceBuffer.appendBuffer(buf);
});
};
function fetchAB (url, cb) {
console.log(url);
var xhr = new XMLHttpRequest;
xhr.open('get', url);
xhr.responseType = 'arraybuffer';
xhr.onload = function () {
cb(xhr.response);
};
xhr.send();
};
</script>
</body></html>
m3u8测试地址
- https://cph-p2p-msl.akamaized/hls/live/2000341/test/master.m3u8【live多码流】
- http://playertest.longtailvideo/adaptive/bipbop/gear4/prog_index.m3u8【vod计时器】
- https://d2zihajmogu5jn.cloudfront/sintel/master.m3u8【vod多码流】
- http://devimages.apple/iphone/samples/bipbop/gear1/prog_index.m3u8
- http://220.161.87.62:8800/hls/0/index.m3u8
- http://220.161.87.62:8800/hls/1/index.m3u8
- https://players.akamai/players/hlsjs
- bitmovin
m3u8协议
Master Playlist
只有多码流才会有Master Playlist。
当 m3u8 作为主播放列表(Master Playlist)时,其内部提供的是同一份媒体资源的多份流列表资源(Variant Stream)。
#EXTM3U 标识当前是一个M3U8文件,该标签必须出现在文件的第一行。
#EXT-X-STREAM-INF:BANDWIDTH=150000,RESOLUTION=416x234,CODECS="avc1.42e00a,mp4a.40.2"
http://example/low/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=240000,RESOLUTION=416x234,CODECS="avc1.42e00a,mp4a.40.2"
http://example/lo_mid/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=440000,RESOLUTION=416x234,CODECS="avc1.42e00a,mp4a.40.2"
http://example/hi_mid/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=640000,RESOLUTION=640x360,CODECS="avc1.42e00a,mp4a.40.2"
http://example/high/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=64000,CODECS="mp4a.40.5"
http://example/audio/index.m3u8
- #EXT-X-STREAM-INF:用于标识一个Variant Stream,这是由一系列的Redition组成的。该标签的属性列表中包含了Variant Stream的描述信息。例如:
- BANDWIDTH表示Variant Stream中的峰值比特率,单位bits/s。
- AVERAGE-BANDWIDTH表示Variant Stream中的平均比特率,单位bits/s。
- CODECS包含Variant Stream中音视频编码格式相关的信息,比如上面的"mp4a.40.5"。
- RESOLUTION包含Variant Stream中对应视频流的分辨率。
- FRAME-RATE表示Variant Stream中的视频帧率。
Media PlayList
一般分为直播Live和点播VOD。
Live示例
#EXTM3U
#EXT-X-VERSION:3 协议版本号
#EXT-X-ALLOW-CACHE:NO 指定文件是否可以缓存
#EXT-X-MEDIA-SEQUENCE:268 第一个媒体片段的序列号 在 PlayList中只有唯一的序号,相邻之间序号+1。
#EXT-X-TARGETDURATION:3 表示最大的秒数
#EXT-X-KEY:METHOD=AES-128,URI="https://xxx/1111",IV=0x39333764333063306139653264353066 表示 Media Segment 已加密, 该值用于解密.
#EXTINF:2.015, 指定每个媒体段(ts)的持续时间
https://d23kaes948ag5n.cloudfront/1K
#EXTINF:2.031,
https://d23kaes948ag5n.cloudfront/2K
加密参数
#EXT-X-KEY
,包括加密算法METHOD=AES-128
、密钥URI
和可选参数IV
(初始化向量)客户端收到M3U8文件后,使用key URI发起请求。该请求检索密钥。然后,客户端使用加密算法和密钥解密传输流 (TS) 文件。
VOD示例
#EXTM3U 每个M3U文件第一行必须是这个tag,提供标示作用
#EXT-X-VERSION:3 用以标示协议版本。这里是3, 那么这里用的就是HLS协议第三个版本,此标签只能有0或1个,不写代表使用版本1
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:13 所有切片的最大时长,有些Apple设备这个参数不正确会无法播放。
#EXT-X-MEDIA-SEQUENCE:430 切片的开始序号。每一个切片都有唯一的序号,相邻之间序号+1。这个编号会继续增长,保证流的连续性。
#EXT-X-PLAYLIST-TYPE:VOD 类型,vod 表示点播。
#EXTINF:11.800 ts 切片的实际时长。duration : 媒体持续时间
news-430.ts ts 切片的文件名
#EXTINF:10.120
news-431.ts
#EXT-X-DISCONTINUITY 表示后续分片属性发生变化,如文件格式/编码/序号。
#EXTINF:11.952
news-430.ts
#EXTINF:12.640
news-431.ts
#EXTINF:11.160
news-432.ts
#EXT-X-DISCONTINUITY
#EXTINF:11.751
news-430.ts
#EXTINF:2.040
news-431.ts
// 重点
#EXT-X-ENDLIST 文件结束符号。表示不再向播放列表文件添加媒体文件。
事件监控
运行时事件
只记录核心事件,都是以
Hls.Events.
开头,例如:Hls.Events.MEDIA_ATTACHING。
事件 | 字符串 | 描述 |
---|---|---|
MEDIA_ATTACHING | hlsMediaAttaching | 在MediaSource附加到媒体元素之前被触发 |
MEDIA_ATTACHED | hlsMediaAttached | 在MediaSource成功附加到媒体元素时触发 |
MANIFEST_LOADING | hlsManifestLoading | 在Manifest加载时触发 |
MANIFEST_LOADED | hlsManifestLoaded | 在Manifest被加载后触发 |
MANIFEST_PARSED | hlsManifestParsed | 在Manifest被解析后触发 |
LEVEL_SWITCHING | hlsLevelSwitching | 在Level切换被请求时触发 |
LEVEL_LOADING | hlsLevelLoading | 在Level加载时触发 |
LEVEL_LOADED | hlsLevelLoaded | 在Level被加载后触发 |
LEVEL_UPDATED | hlsLevelUpdated | 在Level的详细信息更新时触发 |
LEVEL_SWITCHED | hlsLevelSwitched | 在Level切换完成时触发 |
KEY_LOADING | hlsKeyLoading | 在解密Key加载开始前触发 |
FRAG_LOADING | hlsFragLoading | 在片段开始加载前时触发 |
KEY_LOADED | hlsKeyLoaded | 在解密Key加载完成后触发 |
FRAG_LOADED | hlsFragLoaded | 在片段加载完成后触发 |
BUFFER_CREATED | hlsBufferCreated | 当sourcebuffers被创建完成时触发**(只一次)** |
FRAG_PARSING_INIT_SEGMENT | hlsFragParsingInitSegment | 当初始Segment从Fragment抽取完触发**(每个Level只一次)** |
BUFFER_APPENDING | hlsBufferAppending | 在往sourcebuffer添加媒体数据前触发 |
FRAG_DECRYPTED | hlsFragDecrypted | 在fragment完成解密后触发 |
FRAG_PARSED | hlsFragParsed | 当片段解析完成时触发 |
BUFFER_APPENDED | hlsBufferAppended | 在往sourcebuffer添加媒体数据后触发 |
FRAG_CHANGED | hlsFragChanged | 当与当前视频位置的片段匹配发生变化时触发**(播放态 切换片段时)** |
FRAG_BUFFERED | hlsFragBuffered | 当解码后的数据都加载到sourcebuffer后触发。 |
BUFFER_FLUSHING | hlsBufferFlushing | 当sourcebuffer被清空部分前触发 |
BUFFER_FLUSHED | hlsBufferFlushed | 当sourcebuffer被清空部分完成时触发 |
Hls.Events.DESTROYING | hlsDestroying | 当hls.js实例开始销毁时触发。不同于MEDIA_DETACHED人们可能希望将视频分离并重新连接到hls.js的实例来处理中端视频 |
Hls.Events.ERROR | hlsError | 错误事件的标识符 |
bufferStalledError | 当播放卡住时引发,因为缓冲区数据不足 调到最新位置播放。 | |
bufferNudgeOnStall |
Hls.ErrorDetails.BUFFER_STALLED_ERROR bufferStalledError
- bufferStalledError 当播放卡住时引发,因为缓冲区数据不足 调到最新位置播放。
-- data: { type : MEDIA_ERROR,
details : Hls.ErrorDetails.BUFFER_STALLED_ERROR,
fatal : true or false,
buffer : 缓冲区长度(可选)
}
Video事件
// 1、loadstart:视频查找。当浏览器开始寻找指定的音频/视频时触发,也就是当加载过程开始时
video.addEventListener('loadstart', function (e) {
console.log('提示视频的元数据已加载')
console.log(e)
console.log(video.duration) // NaN
})
// 2、durationchange:时长变化。当指定的音频/视频的时长数据发生变化时触发,加载后,时长由 NaN 变为音频/视频的实际时长
video.addEventListener
版权声明:本文标题:HLS的入门总结 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/dongtai/1725802946a1043741.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论