ribbon image search rewind fast-forward speech-bubble pie-graph star

hls.js 源码解读【1】

hls.js 是一款基于 Media Source Extensions 开发的,用于实现 HTTP Live Streaming 开源JavaScript类库。它可以实现将MPEG-2 和 AAC/MP3码流变成自制的 MP4的分片。并且可以直接绑定在Video 上,实现播放。

文章主要是通过解读源码,希望读者可以了解实现基本的前端 HLS 的主要流程,同事也可以扩展读者对 Media Source Extensions 和 video api 以及 视频编解码的相关知识有更进一部的了解。

第一篇文章可能会从整体方面,让大家理解一下调用的

整体流程,让大家对真个项目的基本代码架构有个基础的认识。

目录指南

只对和项目相关的文件进行说明

dist // 打包后的文件目录,  
src  
  + cotroler
      - abr-controller.js // 用于分片筛选
      - audio-stream-controller.js 
      - audio-track-controller.js 
      - buffer-controler.js // 用于对 buffer 的操作
      - cap-level-controller.js // 限流处理
      - fps-controller.js  // 监测帧数
      - id3-track-controller.js // id3 track 是术语,一般记录 mp3 文件的 封面,歌词等信息
      - level-controller.js // 
      - stream-controller.js // 视频流的处理
      - subtitle-track-controller.js // 后面三个 字幕 相关
      - subtitle-stream-comtroller.js
      - timeline-controller.js

 + crypt 对加密视频流进行解码
 + demux // 逆向多路复用
 + helper 
     - acc.js
     - buffer-helper.js 对 buffer 之类的辅助函数
     - level-helper.js
 + loader 
     -  fragment-loader.js // 对分片进行加载
     -  key-loader.js
     -  playlist-loader.js  // 处理播放内容列表
 + remux
 + utils  // 辅助类库 需要用到再提及
     - attr-list.js
     - binary-search.js
     - cea-608-parser.js
     - cues.js
     - discontinuities.js
     - ewma-bandwidth-estimator.js
     - fetch-loader.js
     - hex.js
     - logger.js
     - timeRanges.js
     - vttcue.js
     - vttparser.js
     - webvtt-prser.js
     - xhr-loader.js
- config.js  // 基本配置
- errors.js // 用于定义错误码
- event-handler.js // 这是一个 controller 集成的ji
- events.js // 定义事件类型
- hls.js hls //类库定义
- index.js

基本使用

我们在深入代码之前,可以看下基本使用,可以让页面跑起来。

<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>  
<video id="video"></video>  
<script>  
  if(Hls.isSupported()) {
    var video = document.getElementById('video');
    var hls = new Hls();
    hls.loadSource('https://video-dev.github.io/streams/x36xhzz/x36xhzz.m3u8');
    hls.attachMedia(video);
    hls.on(Hls.Events.MANIFEST_PARSED,function() {
      video.play();
  });
 }
</script>  

其中如果你希望自己生成 m3u8 的文件,你可以使用 ffmpeg 进行处理,将单一的 mp4 拆分成多个分片文件。

ffmpeg -i your_file.mp4 -b:v 1M -g 60 -hls_time 2 -hls_list_size 0 -hls_segment_size 500000 output.m3u8  

npm

如果你使用 npm 引入模块的话,在 dist 目录下 存在多个文件,其中 hls.light.js ,是通过配置去掉可选音频流和字幕流处理的版本,相对而言其体积更小。

npm install hls.js --save  

事件流

由于内部通信都是基于 EventEmitter 来实现,透过事件流,你可以了解到代码运行的整体流程。

hls 整体流程如下

hls实际会先通过 ajax(loader 是可以完成自定义的) 请求 m3u8文件,然后会读取到文件的分片列表,以及视频的编码格式,时长等。随后会按照顺序(非 seek )去对分片进行请求,这些也是通过 ajax 请求二进制的文件,然后借助 Media Source Extensions 将 buffer 内容进行合流,然后组成一个可播的媒体资源文件。

由于内部通过自定事件进行数据传递和流程控制,参考下面的图:

events.js

其中主要的流程是在 level-controller.js 以及 stream-controller.js完成。

后面会分析这里面的具体实现。

扩展阅读

由于 hls.js 在阅读前,要求作者对视频格式,编解码,以及 Media Source Extensions 以及 buffer 操作等知识有要求。大家可以参考下面提供的一些资料 :

You Can Speak "Hi" to Me in Those Ways