开发者社区 问答 正文

web端怎么播放m3u8流地址

web端怎么播放m3u8流地址?

展开
收起
有路有乔-六月 2022-12-02 13:04:28 6346 分享 版权
2 条回答
写回答
取消 提交回答
  • 帮助你安全,稳定、集约,高效的用好云和人工智能。

    一、m3u8 到底是什么

    m3u8 是 HLS(HTTP Live Streaming)协议的播放列表文件,不是视频本体。它是纯文本索引:按时间顺序列出若干 TS 分片(也支持 fMP4)的地址、时长、码率,并带有 EXT-X-VERSION、EXT-X-TARGETDURATION、EXT-X-ENDLIST 等控制标签;主播放列表(master playlist)还会列出多条不同码率的子流,供播放器做自适应码率切换。

    因此浏览器不能像 mp4 那样把地址直接交给 <video src>——video 标签不认识这套分片索引。必须由播放器读取 m3u8,逐个拉取分片、按序解码拼接、维护播放缓冲区,才能出画面。这就是"能播"和"不能播"的分界线。

    二、浏览器原生支持情况

    • Safari / iOS:原生支持 HLS,video 标签可直接播放 m3u8,WKWebView、微信内置浏览器同样适用。
    • Chrome / Firefox / Edge(桌面与 Android):不支持,必须靠 JS 播放库。
    • 统一判断方式:video.canPlayType('application/vnd.apple.mpegurl')。

    三、推荐方案:hls.js

    主流、成熟、体积适中,基于 MSE(Media Source Extensions),覆盖绝大多数需要 HLS 的桌面与安卓场景。

    引入方式:npm 安装,或用 script 标签加载构建产物(CDN 地址由发布方补充)。

    import Hls from 'hls.js'
    
    const video = document.querySelector('#player')
    const src = '/live/stream.m3u8'
    
    if (video.canPlayType('application/vnd.apple.mpegurl')) {
      video.src = src                    // Safari:走原生
    } else if (Hls.isSupported()) {
      const hls = new Hls({
        lowLatencyMode: true,            // 低延迟直播
        liveSyncDurationCount: 3         // 直播追帧:缓冲几个分片
      })
    
      hls.loadSource(src)                // 加载播放列表
      hls.attachMedia(video)             // 绑定 video 元素
      hls.on(Hls.Events.MANIFEST_PARSED, () => video.play())
    
      hls.on(Hls.Events.ERROR, (evt, data) => {
        if (!data.fatal) return          // 非致命错误交给内部重试
        if (data.type === Hls.ErrorTypes.NETWORK_ERROR) {
          hls.startLoad()                // 网络错误:重新拉流
        } else if (data.type === Hls.ErrorTypes.MEDIA_ERROR) {
          hls.recoverMediaError()        // 解码错误:恢复媒体
        } else {
          hls.destroy()
        }
      })
    }
    

    关键参数说明:

    • lowLatencyMode:低延迟直播必须开启,且要求服务端输出 LL-HLS 才有实际收益。
    • liveSyncDurationCount:直播追帧的核心。数值越小越贴近直播边缘,但越容易卡顿;延迟偏高就调小,抖动严重就调大,默认 3。
    • Hls.Events.ERROR:只处理 fatal 错误,NETWORK_ERROR 用 startLoad()、MEDIA_ERROR 用 recoverMediaError();连续失败建议加退避,不要无限重试。

    四、其他方案对比

    video.js + videojs-contrib-hls:UI 与插件体系完整,适合已有 video.js 的项目,但包体与配置成本更高;dplayer 偏 UI 层,HLS 能力仍需挂 hls.js;Safari 原生路径不需要任何库,但要自己写兼容分支。

    五、实战踩坑

    • CORS:m3u8 与 TS 分片都是跨域请求,服务端必须返回 Access-Control-Allow-Origin;携带 Cookie 时还需 Allow-Credentials 与请求端 withCredentials 配合。
    • 混合内容:HTTPS 页面不能播 HTTP 流,会被浏览器直接拦截,协议必须一致。
    • 相对路径:m3u8 内的分片地址常是相对路径,解析基准是 m3u8 自身所在目录;服务端做 URL 重写或反向代理时容易 404 或请求到错误路径。
    • 直播卡顿:先判断是网络抖动还是参数问题,再动 liveSyncDurationCount 与缓冲区配置,避免一次性改一堆参数。

    最后补一句:如果你手里的 m3u8 是自己服务器上 FFmpeg 现切出来的,转码、切片、多码率、鉴权这些活儿其实可以整条交给托管的视频点播服务去做,播放器这边照样用上面的 hls.js 接入,运维成本能省一大截——阿里云视频点播 VOD 是这类场景里比较省心的选择,控制台走一遍转码模板配置就能出播放地址。当然,继续自建 FFmpeg 也完全没问题,看你的运维预算。

    2026-09-30 19:31:00
    赞同 44 展开评论
  • 面对过去,不要迷离;面对未来,不必彷徨;活在今天,你只要把自己完全展示给别人看。
    • 这个可以使用第三方插件比如西瓜播放器或者hls插件
    • 安装hls插件
    cnpm install hls.js -S
    
    • 使用hls import Hls from 'hls.js'
    const src = ref("")
    const video = document.getElementById('player')
      if (!video) return
      if (src.value.indexOf('.m3u8') > 0) {
        if (video.canPlayType('application/vnd.apple.mpegurl')) {
          video.src = src.value
        } else if (Hls.isSupported()) {
          const hls = new Hls()
          hls.loadSource(src.value)
          hls.attachMedia(video)
          video && video.play()
        } else {
          console.error('This is an old browser that does not support MSE https://developer.mozilla.org/en-US/docs/Web/API/Media_Source_Extensions_API')
        }
      } else {
        video.play()
      }
    
    2022-12-02 13:17:44
    赞同 267 展开评论
问答地址: