为什么需要 HLS.js?
原生支持 HLS 的浏览器只有 Safari(桌面和 iOS),Chrome、Firefox、Edge 均不支持直接播放 M3U8 链接。HLS.js 通过 Media Source Extensions(MSE)API 在这些浏览器中模拟 HLS 播放能力,覆盖 95% 以上的用户。
快速开始:10 行代码接入
<video id="video" controls width="640"></video>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<script>
const video = document.getElementById('video');
const src = 'https://example.com/video/index.m3u8';
if (Hls.isSupported()) {
const hls = new Hls();
hls.loadSource(src);
hls.attachMedia(video);
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
// Safari 原生支持
video.src = src;
}
</script>
Hls.isSupported() 检测当前浏览器是否支持 MSE API,Safari 走 else 分支用原生播放,不需要加载 HLS.js,节省带宽。处理 CORS 跨域问题
CORS 是 HLS.js 开发中最常见的拦路虎。M3U8 文件和 TS 片段所在的服务器必须在响应头中允许跨域访问:
# Nginx 配置示例
location ~* \.(m3u8|ts)$ {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, HEAD, OPTIONS";
add_header Cache-Control "no-cache"; # M3U8 不缓存,TS 可以缓存
}
注意:TS 片段文件名包含序号,可以长期缓存(设置 Cache-Control: max-age=86400);M3U8 文件内容会更新,不能缓存(no-cache)。
错误处理与自动恢复
hls.on(Hls.Events.ERROR, (event, data) => {
if (data.fatal) {
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
// 网络错误:等待后自动重试
console.error('网络错误,尝试恢复...');
hls.startLoad();
break;
case Hls.ErrorTypes.MEDIA_ERROR:
// 媒体解码错误:尝试修复
console.error('媒体错误,尝试修复...');
hls.recoverMediaError();
break;
default:
// 无法恢复的错误:销毁实例
hls.destroy();
showError('播放失败,请刷新页面');
break;
}
}
});
自适应码率配置
const hls = new Hls({
// 起播时自动选择最佳码率(-1 = 自动)
startLevel: -1,
// 最大缓冲时长(秒),直播建议 30s,点播可设 60s
maxMaxBufferLength: 60,
// 开启 Web Worker 解复用,避免主线程阻塞
enableWorker: true,
// 码率上行滞后系数(越大切换越保守,避免频繁波动)
abrBandWidthUpFactor: 0.7,
// 直播同步延迟目标(秒),LL-HLS 可设 2-4s
liveSyncDurationCount: 3,
});
手动切换画质
// 获取所有可用清晰度
hls.on(Hls.Events.MANIFEST_PARSED, (event, data) => {
const levels = data.levels;
levels.forEach((level, index) => {
console.log(`Level ${index}: ${level.height}p, ${(level.bitrate/1000).toFixed(0)} kbps`);
});
});
// 锁定到指定档位(0 = 最低,-1 = 自动)
hls.currentLevel = 1; // 锁定到第 2 档
hls.currentLevel = -1; // 恢复自动选择
// 获取当前正在播放的档位
console.log('当前档位:', hls.currentLevel);
console.log('当前分辨率:', hls.levels[hls.currentLevel]?.height + 'p');
如需构建完整的自定义播放器,可以参考 StreamFlow 在线播放器 的实现,它就是基于 HLS.js 构建的。
- 生产环境使用 CDN 托管的 HLS.js(如 jsDelivr),而不是自托管,利用用户浏览器缓存减少加载时间
enableWorker: true对性能提升显著,TS 解复用移到 Web Worker 后主线程更流畅,强烈推荐开启- 直播场景中,
maxMaxBufferLength设置过大会导致延迟累积,建议不超过 30 秒 - 如果多个播放器实例共存于一个页面,每个实例都会占用内存和带宽,页面不可见时调用
hls.stopLoad()暂停加载 - 调试时开启 HLS.js 的 debug 日志:
new Hls({"debug": true}),控制台会输出详细的码率切换和片段下载信息