web端播放m3u8视频流注意事项

6,867 阅读3分钟

项目上有一个播放实时视频(直播)的需求,后端童鞋直接传过来一个类似 https://...️️/live.m3u8的视频流地址。让我自行播放,拿到地址的我一脸懵逼,下面开始我的探索(baidu)之路。

HLS(HTTP Live Streaming)

介绍.m3u8之前得先介绍一下HLS技术,HLS是苹果公司提出的,官方给出的简介如下:

使用Apple的HTTP实时流媒体(HLS)技术,将实时和点播的音频和视频发送到iPhone,iPad,Mac,Apple TV和PC。 使用与Web相同的协议,HLS允许您使用普通Web服务器和内容交付网络部署内容。 HLS旨在提高可靠性,并通过针对可用的有线和无线连接速度优化回放来动态适应网络条件。

HLS将音频和视频作为一系列小文件发送,通常持续时间约为6秒,称为媒体段文件。 索引文件或播放列表提供媒体段文件的URL的有序列表。 HLS的索引文件保存为M3U8播放列表,这是用于MP3播放列表的M3U格式的扩展名。 客户端访问索引文件的URL,然后客户端按顺序请求索引文件。

简而言之,.m3u8格式的文件是HLS技术下的产物,它是HLS的索引文件。如果看到后端童鞋传给我们的视频流链接后缀是.m3u8,基本就可以断定直播流采用的是HLS技术。

m3u8文件

出于好奇,我下载了其中一个.m3u8文件,并用电脑自带的文本编辑器打开,内容如下:

它实际上就是一个普通的文本文件。

  • #EXT-X-MEDIA-SEQUENCE:每一个媒体文件在 PlayList中的唯一序列号,相邻之间序号加一。上图中是序号 303。
  • #EXT-X-TARGETDURATION:每一份媒体文件的时间, 以秒为单位。 上图中是2s。
  • #EXTINF:格式 #EXTINF <duration>,<title>duration:每一份 媒体文件持续时间;title:每一个媒体文件url地址。上图中seghik303.ts就是后缀为.ts视频切片文件的地址,这里看上去应该是相对路径。

如何在网页上播放?

我项目里是用的hls.js来播放的(以React为例)。

  1. 先安装依赖
npm i hls.js
  1. 然后相应的文件头里引入
import Hls from 'hls.js';
  1. 页面上放入标签
<video id="hlsVedio"></video>
  1. 操作播放
componentDidMount() {
    const video = document.getElementById('hlsVedio');
    if (Hls.isSupported()) {
      const hls = new Hls();
      this.hls = hls;
      hls.loadSource('https://.../live.m3u8');
      hls.attachMedia(video);
      hls.on(Hls.Events.MANIFEST_PARSED, function() {
        video.play();
      });
    } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
      video.src = 'https://.../live.m3u8';
      video.addEventListener('loadedmetadata', function() {
        video.play();
      });
    }
  }

完成上面四步,基本上直播视频流可以播放了

打开浏览器的控制台看一下

它怎么突然穿了品如的衣服,它怎么一直在发送请求?难道我代码里写死循环了?还是浏览器需要重启一下?

再回过头看一下HLS,发现这项流媒体技术就是会根据.m3u8的索引文件去不断请求新的.m3u8.ts视频文件。所以浏览器不断发送请求是正常的,不发送才是不正常的。

  1. 销毁视频流

    componentWillUnmount() {
        if (this.hls) {
          this.hls.destroy();
        }
      }
    

    千万不要忘记在组件销毁的生命周期里销毁创建的hls对象,不然在SPA应用里切换页面或者切换tab的时候,虽然看不到视频组件了,但还会一直在发送请求。