How to Play M3U8 Video Online

A complete guide to M3U8 playback with HLS.js and native players.

Free online M3U8 player with HLS adaptive bitrate and subtitle support.

PlayerHLS.jsWeb development

Quick Start

The fastest option is to use our online player:

Use M3U8 Player Now

🌐 浏览器兼容性

浏览器支持情况

Safari (iOS/macOS)
原生支持
Chrome
需要HLS.js
Firefox
需要HLS.js
Edge
需要HLS.js
IE 11及以下
不支持

🎬 在线播放器选择

Web播放器

  • • 本站播放器 - 功能全面
  • • Video.js - 开源播放器
  • • Plyr - 简洁美观
  • • JW Player - 商业方案

移动应用

  • • VLC - 跨平台播放器
  • • IINA (macOS) - 原生体验
  • • MX Player - Android首选
  • • nPlayer - iOS专业播放器

💻 HLS.js实现方法

基础播放器实现

<!DOCTYPE html>
<html>
<head>
  <title>M3U8 Player</title>
  <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
</head>
<body>
  <video id="video" controls style="width: 100%; max-width: 600px;"></video>
  
  <script>
    const video = document.getElementById('video');
    const videoSrc = 'https://example.com/video.m3u8';
    
    if (Hls.isSupported()) {
      const hls = new Hls();
      hls.loadSource(videoSrc);
      hls.attachMedia(video);
      
      hls.on(Hls.Events.MANIFEST_PARSED, function() {
        video.play();
      });
    } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
      // Safari原生支持
      video.src = videoSrc;
    }
  </script>
</body>
</html>

🎯 原生播放支持

Safari原生HLS支持

Safari和iOS设备原生支持HLS,可以直接使用HTML5 video标签:

<!-- 最简单的原生播放 -->
<video controls>
  <source src="https://example.com/video.m3u8" type="application/x-mpegURL">
  <source src="https://example.com/video.m3u8" type="application/vnd.apple.mpegurl">
  您的浏览器不支持视频播放
</video>

<!-- 带有完整属性的播放器 -->
<video 
  id="player"
  controls
  autoplay
  muted
  playsinline
  poster="thumbnail.jpg"
  width="100%"
  preload="auto">
  <source src="video.m3u8" type="application/x-mpegURL">
</video>

⚡ 高级功能实现

自定义控制栏

// 自定义播放控制
class CustomPlayer {
  constructor(videoElement) {
    this.video = videoElement;
    this.setupControls();
  }
  
  setupControls() {
    // 播放/暂停
    this.playBtn = document.getElementById('play-btn');
    this.playBtn.onclick = () => this.togglePlay();
    
    // 进度条
    this.progressBar = document.getElementById('progress');
    this.progressBar.oninput = (e) => {
      const time = (e.target.value / 100) * this.video.duration;
      this.video.currentTime = time;
    };
    
    // 音量控制
    this.volumeSlider = document.getElementById('volume');
    this.volumeSlider.oninput = (e) => {
      this.video.volume = e.target.value / 100;
    };
    
    // 全屏
    this.fullscreenBtn = document.getElementById('fullscreen');
    this.fullscreenBtn.onclick = () => this.toggleFullscreen();
    
    // 更新进度
    this.video.ontimeupdate = () => this.updateProgress();
  }
  
  togglePlay() {
    if (this.video.paused) {
      this.video.play();
      this.playBtn.textContent = '暂停';
    } else {
      this.video.pause();
      this.playBtn.textContent = '播放';
    }
  }
  
  updateProgress() {
    const percent = (this.video.currentTime / this.video.duration) * 100;
    this.progressBar.value = percent;
  }
  
  toggleFullscreen() {
    if (!document.fullscreenElement) {
      this.video.requestFullscreen();
    } else {
      document.exitFullscreen();
    }
  }
}

质量切换功能

// 手动质量切换
hls.on(Hls.Events.MANIFEST_PARSED, function(event, data) {
  // 获取所有质量级别
  const levels = hls.levels;
  const qualitySelector = document.getElementById('quality');
  
  // 添加自动选项
  qualitySelector.innerHTML = '<option value="-1">自动</option>';
  
  // 添加各个质量选项
  levels.forEach((level, index) => {
    const option = document.createElement('option');
    option.value = index;
    option.textContent = `${level.height}p`;
    qualitySelector.appendChild(option);
  });
  
  // 质量切换事件
  qualitySelector.onchange = (e) => {
    hls.currentLevel = parseInt(e.target.value);
  };
  
  // 显示当前质量
  hls.on(Hls.Events.LEVEL_SWITCHED, function(event, data) {
    qualitySelector.value = data.level;
    console.log('当前质量:', levels[data.level].height + 'p');
  });
});

字幕支持

// 添加字幕轨道
hls.on(Hls.Events.SUBTITLE_TRACKS_UPDATED, function(event, data) {
  const subtitleTracks = data.subtitleTracks;
  const subtitleSelector = document.getElementById('subtitles');
  
  subtitleSelector.innerHTML = '<option value="-1">关闭</option>';
  
  subtitleTracks.forEach((track, index) => {
    const option = document.createElement('option');
    option.value = index;
    option.textContent = track.name || track.lang;
    subtitleSelector.appendChild(option);
  });
  
  subtitleSelector.onchange = (e) => {
    hls.subtitleTrack = parseInt(e.target.value);
  };
});

📱 移动端适配

iOS特殊处理

// iOS播放策略
const video = document.getElementById('video');

// 允许内联播放(iOS 10+)
video.setAttribute('playsinline', '');
video.setAttribute('webkit-playsinline', '');

// iOS低功耗模式检测
if (iOS && video.paused) {
  // 显示播放按钮提示
  showPlayButton();
  
  // 用户交互后播放
  playButton.onclick = () => {
    video.play().catch(err => {
      console.error('播放失败:', err);
    });
  };
}

// 处理iOS全屏
video.addEventListener('webkitbeginfullscreen', () => {
  console.log('进入全屏');
});

video.addEventListener('webkitendfullscreen', () => {
  console.log('退出全屏');
});

响应式设计

/* 响应式视频容器 */
.video-container {
  position: relative;
  padding-bottom: 56.25%; /* 16:9 */
  height: 0;
  overflow: hidden;
}

.video-container video {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

/* 移动端控制栏 */
@media (max-width: 768px) {
  .controls {
    font-size: 14px;
    padding: 8px;
  }
  
  .control-button {
    width: 40px;
    height: 40px;
  }
}

❓ 常见问题解决

CORS错误

解决方案:

  • • 服务器添加CORS头:Access-Control-Allow-Origin: *
  • • 使用代理服务器转发请求
  • • 将视频文件放在同域下

自动播放失败

浏览器策略限制,解决方法:

  • • 添加 muted 属性实现静音自动播放
  • • 用户交互后再播放
  • • 显示播放按钮引导用户点击

播放卡顿

优化建议:

  • • 增加缓冲区大小:maxBufferLength: 60
  • • 启用自适应码率
  • • 使用CDN加速
  • • 优化片段大小(建议6-10秒)

黑屏或无画面

检查项:

  • • 视频编码是否为H.264
  • • M3U8文件格式是否正确
  • • 网络是否能访问TS片段
  • • 浏览器控制台错误信息

🔒 安全考虑

内容保护

  • • 使用HTTPS传输
  • • 实施Token验证
  • • 限制Referer来源
  • • 设置播放时限

DRM支持

  • • FairPlay (Safari)
  • • Widevine (Chrome)
  • • PlayReady (Edge)
  • • AES-128加密

📚 相关资源