Advertisement
— 广告位 In-Article —

Why HLS.js?

Only Safari natively supports HLS. Chrome, Firefox, and Edge cannot play M3U8 URLs directly. HLS.js uses the Media Source Extensions (MSE) API to enable HLS playback in these browsers, covering over 95% of users.

Quick Start: 10 Lines of Code

<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')) {
  video.src = src; // Safari native
}
</script>
Note: Hls.isSupported() detects MSE support. Safari takes the else branch and plays natively — no need to load HLS.js at all, saving bandwidth.

Fixing CORS Issues

CORS is the most common blocker in HLS.js development. The M3U8 file and TS segments must be served with the appropriate headers:

# Nginx config
location ~* \.(m3u8|ts)$ {
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Methods "GET, HEAD, OPTIONS";
    add_header Cache-Control "no-cache"; # For M3U8; TS can be cached longer
}

Error Handling and Recovery

hls.on(Hls.Events.ERROR, (event, data) => {
  if (data.fatal) {
    switch (data.type) {
      case Hls.ErrorTypes.NETWORK_ERROR:
        hls.startLoad(); // retry
        break;
      case Hls.ErrorTypes.MEDIA_ERROR:
        hls.recoverMediaError(); // attempt recovery
        break;
      default:
        hls.destroy();
        break;
    }
  }
});

ABR Configuration

const hls = new Hls({
  startLevel: -1,           // Auto-select initial quality
  maxMaxBufferLength: 60,   // Max buffer (s); use 30 for live
  enableWorker: true,       // Move demuxing to Web Worker
  abrBandWidthUpFactor: 0.7, // Conservative upswitch threshold
  liveSyncDurationCount: 3,  // Live sync target (segments)
});

Manual Quality Switching

hls.on(Hls.Events.MANIFEST_PARSED, (event, data) => {
  data.levels.forEach((level, i) => {
    console.log(`Level ${i}: ${level.height}p, ${(level.bitrate/1000).toFixed(0)} kbps`);
  });
});

hls.currentLevel = 1;   // Lock to level 1
hls.currentLevel = -1;  // Back to auto

For a working reference implementation, see the StreamFlow online player, which is built on HLS.js.

💡 Performance Tips
  • Use a CDN-hosted HLS.js (e.g., jsDelivr) rather than self-hosting — users may already have it cached from other sites.
  • enableWorker: true significantly improves smoothness by moving TS demuxing off the main thread. Always enable it in production.
  • For live streams, keep maxMaxBufferLength under 30 seconds to prevent latency buildup.
  • If multiple players coexist on a page, call hls.stopLoad() when a player is off-screen to save bandwidth.
  • Enable debug logging during development: new Hls({ debug: true }) — the console will show detailed ABR switching and segment download events.