在h5 video中的直播

Javascript Sep 14, 2020

前言

直播越来越成为趋势,因为疫情的冲击,不管是直播带货还是直播教育等等,将线上模式推上了巅峰~
因为业务和兴趣关系,稍微研究了一下在H5中直播的相关知识。
PS:如果你对直播有所了解,可以skip全篇文章啦,本篇文章只涉及到一些直播相关的初级知识。

  1. 稍微了解一下直播的架构。
  2. 直播的协议。
  3. 微信小程序中的直播。
  4. 本地自己搞一个h5的直播小demo。

直播的架构

--1
如上图:首先推流就可以简单理解成你的摄像头,负责采集图像,并将数据流推送到服务器。其次拉流可以理解成你的播放器,负责将图像数据流从服务器上拉取下来。然后就是媒体流服务器,我们通常都是直接使用第三方的服务器,比方说腾讯云直播,阿里云直播等等,简单绑定域名和申请之后就能够直接使用啦~ 当然在本文最后我们会自己搭建一个非常简单的媒体流服务器。

常见的直播协议

HLS

网上相关信息很多大同小异,总结一下:苹果公司设计的,延迟很大,但是兼容性超强(h5 video标签兼容性)。
该协议原理简单来说,http请求下载playlist文件(.m3u8),里面包含切片文件信息(.ts文件),随后下载ts文件feed给video进行播放
--2
,如上图所示:m3u8文件中包含三个切片.ts文件,每个文件为targetDuration = 9s,看到左侧的三个ts文件分别是38,39,40,右侧的三个ts文件是39,40,41,以此类推,新的playlist文件被依次下载,同时新的ts文件被下载到浏览器并进行播放。
HLS这么大的延迟也好理解,因为需要等多个ts切片文件生之后再发给播放器,然而每个ts切片文件都在10s左右,所以这个延迟是模式设计上不可避免的。

RTMP

这个协议也总结下:adobe公司的似有协议(所以浏览器播放都需要插件),必须要flash播放器才能播放,延迟超短,基于TCP长链接,无需多次握手。
虽然该协议的延迟很短很优秀,但是需要flash真的是硬伤,各大浏览器已经对外宣称将不再支持flash,所以此协议到此为止~感兴趣的同学在网上搜一下到处都是。

DASH

dash的兼容性也很强,配上dash.js基本上主流浏览器(支持MEDIA SOURCE EXTENSION的)都能够支持这个协议,延迟也很低,该协议之下也是将流文件变成切片文件,据说youtube和netflix都是用了这个协议,如果你打开network面板的话和HLS很像,一直在不断的下载新文件。

HTTP-FLV

国内的主流直播平台都是用的这个协议,该协议不再是不断下载切片文件了,而是通过不设置content-length的header,使得http请求不间断的持续下载
--3
如上图所示是我在B站直播中随便找的一个网络请求,该文件是以.flv结尾的文件,还可以看到该文件的大小在我截图的瞬间已经达到了40多mb。
HTTP-FLV的协议延时很低,自己用腾讯云亲测能够达到5s以内,另外要说的就是开源库flv.js,应该是次库开创了国内web直播播放flv格式的先河,这个库也是用到了MEDIA SOURCE EXTENSION接口,才使得h5标签上能够播放flv文件。

Media Source Extension(MSE)

上文中有两次提到了Media Source Extension,一个是在h5播放dash,一个是在播放flv格式的时候,api结构图如下:
zhibo4
从图中可以得知,MediaSource中包含SourceBuffer,而SourceBuffer中包含了一个个Track,每一个Track就是我们常说的音轨和视轨,我们可以通过一些提供的接口对Track进行操作,比方说切换Track,播放或者暂停Track甚至跳转到Track的某一帧等(没有深层去了解,因为毕竟了解太多伤身~)。下面的实例代码简单的展示了如何使用MSE:

    var vidElement = document.querySelector('video');

if (window.MediaSource) {
  var mediaSource = new MediaSource();
  vidElement.src = URL.createObjectURL(mediaSource);
  mediaSource.addEventListener('sourceopen', sourceOpen);
} else {
  console.log("The Media Source Extensions API is not supported.")
}

function sourceOpen(e) {
  URL.revokeObjectURL(vidElement.src);
  var mime = 'video/webm; codecs="opus, vp9"';
  var mediaSource = e.target;
  var sourceBuffer = mediaSource.addSourceBuffer(mime);
  var videoUrl = 'droid.webm';
  fetch(videoUrl)
    .then(function(response) {
      return response.arrayBuffer();
    })
    .then(function(arrayBuffer) {
      sourceBuffer.addEventListener('updateend', function(e) {
        if (!sourceBuffer.updating && mediaSource.readyState === 'open') {
          mediaSource.endOfStream();
        }
      });
      sourceBuffer.appendBuffer(arrayBuffer);
    });
}

sourceopen事件是当我们将mediaSource赋值给video的src标签的时候会被trigger,然后我们在这个事件的回调中去fetch视频流,并将其存放到arrayBuffer中,再appendBuffer到sourceBuffer中。我的理解就是Media Source Extension这个东西可以将比方的内容变成流然后喂给video标签,使得原本video无法播放的内容变成可以播放。

    MediaSource.isTypeSupported('video/mp4; codecs="avc1.42E01E, mp4a.40.2"')

另外这个接口是用来检测检MSE是否支持某个特定的编码和容器盒子

In Conclusion

zhibo5

微信小程序中的直播

微信小程序中如果你想要植入直播事件很简单的事情,使用live-pusher组件进行推流,感觉说白了就是打开摄像头进行录影,然后使用live-player组件进行播放。中间的媒体服务器可以直接使用腾讯云的(毕竟腾讯自家产品),下图分别是生成的拉流和推流地址。
--6
--7
在腾讯云中绑定好直播域名,直接在辅助工具中输入自定义的AppNameStreamName就能够生成相应的推流和拉流地址,然后将生成的推流拉流地址作为live-pusherlive-player的url输入就可以啦。这里注意微信小程序只支持rtmp和flv格式的拉流。

本地搭建一个直播demo

推流使用OBS

--8,这个工具很强大,可以直播你的整个桌面,你的camera,甚至某一个window等等,在设置中有一个Stream选项,里面输入对应的Server地址就行

媒体服务器

node-media-server

这个媒体服务器充当着上面的腾讯云中的功能,将你推流上去的数据进行转码之后下发到拉流端,介绍一个node写的服务器叫做node-media-server
--9
配置很简单,将端口1936作为rtmp的推流端口,8002开启http的拉流端口,然后本地开始使用ffmpeg进行转码,在8002上可以拉取到各种协议下的播放流如下图:
--10

NGINX RTMP Module

NGINX的一个模块,具体使用方法不再赘述,以下是该模块的配置:

rtmp {
  server {
    listen 1935; # Listen on standard RTMP port
    chunk_size 4000;

    application show {
        live on;
        # Turn on HLS
        hls on;
        hls_path /mnt/hls/;
        hls_fragment 3;
        hls_playlist_length 60;
        # disable consuming the stream from nginx as rtmp
        deny play all;
    }
  }
}

拉流播放器

这里就是我们选择播放用的播放器啦,各种各样,可以使用比方说之前提到的flv.js来播放http-flv协议啦,使用dash.js播放dash协议的啦。除了再使用web上的播放器,当然你还可以本地下载一个VLC播放器app,能够播放各种协议的内容~
--11
到此本地的demo运行起来就可以看到效果啦。

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.