广告
— 广告位 In-Article —

为什么需要 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}),控制台会输出详细的码率切换和片段下载信息