手牵手之流媒体视频协议前端解决方案详参

4,133 阅读11分钟

1. 前言

因本人厚积薄发,突然对流媒体来了兴致😄,机缘巧合需要整理方案,于是乎整理了关于流媒体协议,前端基本解决方案的一些看法。

2. 流媒体背景

流媒体就是指采用流式传输技术在网络上连续实时播放的媒体格式,如音频、视频或多媒体文件。流媒体技术也称流式媒体技术。如有疑惑可以先了解下音视频技术的一些基础概念

3. 流媒体协议

流媒体协议是服务器与客户端之间通信遵循的规定。当前网络上主要的流媒体协议如图表所示。

名称 推出机构 传输层协议 客户端 使用领域 优缺点
RTSP+RTP IETF TCP+UDP VLC,WMP IPTV 支持组播,效率较高,存在丢包问题,浏览器不支持。
RTMP Adobe Inc TCP Flash 互联网直播 Adobe支持度高,适合长时间播放,延迟低(1s),有累积延迟。
RTMFP Adobe Inc UDP Flash 互联网直播 带宽消耗低,数据传输速率高,但需安装Flash Player 10。
HLS Apple TCP Video 互联网点播 Apple支持度高,兼容性好,但延时高(20S),缓存,存储有难度。
HTTP-FLV Adobe Inc TCP Video 互联网直播/点播 兼容性好,延迟低(1s),拉流、保密性不强。

延迟、性能排序:

在支持浏览器的协议里,延迟排序(由高到低)是:

HLS > WebSocket-FLV >RTMP = HTTP-FLV

而性能排序(由高到低)恰好相反:

RTMP > HTTP-FLV = WebSocket-FLV > HLS

也就是说延迟小的性能不好。

对比分析:

  • 在浏览器里做直播,使用HTTP-FLV协议是不错的,性能优于RTMP+Flash,延迟可以做到和RTMP+Flash一样甚至更好。
  • HLS 延迟大,适合视频点播。
  • RTMP强在浏览器支持好,加载Flash插件后就能直接播放。

4. 基于流媒体视频前端解决方案

4.1 hls.js

4.1.1 hls.js简介

hls.js是一个实现HTTP Live Streaming客户端的JavaScript库。它依靠HTML5视频和MediaSource扩展进行播放。

它的工作原理是将MPEG-2传输流和AAC / MP3流转换为ISO BMFF(MP4)片段。如果在浏览器中可用,则可以使用Web Worker异步执行此传输。hls.js也支持HLS+fmp4,正如在WWDC2016期间宣布的那样hls.js不需要任何播放器,它直接在标准的HTML <video>元素之上工作。hls.js 使用ECMAScript6编写,使用BabelECMAScript5中编译。

4.1.2 hls.js的优缺点及兼容性

优势:

  • 体积比较小,很纯净。
  • 原生支持Video标签。
  • HTMLVideoElement控件和事件可以无缝使用。
  • UI可以根据自己的业务自扩展,自己封装功能和UI。

限制:

  • 没有封装好的UI,功能上也需要自己去实现。
  • 有一定延迟。

兼容性:

hls.js与支持MediaSource扩展(MSE)API的浏览器兼容,带有'video / MP4'mimetypes输入。

  • Chrome for Android 34+
  • Chrome for Desktop 34+
  • 适用于Android 41+的Firefox
  • Firefox for Desktop 42+
  • IE11 +适用于Windows 8.1+
  • 适用于Windows 10+的Edge
  • Opera for Desktop
  • Vivaldi for Desktop
  • Safari for Mac 8+(测试版)
  • 最新兼容详情

请注意: iOS Safari“Mobile”不支持MediaSource API。然而,Safari浏览器通过普通视频“标记”源URL支持内置HLS。当平台既没有MediaSource也没有本机HLS支持时,您将无法播放HLS。

4.1.3 hls.js原理

事件流:

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

hls整体流程如下:

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

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

4.1.4 hls.js使用

安装:

npm install  hls.js --save

npm install @types/hls.js -dev 

或者

https://cdnjs.cloudflare.com/ajax/libs/hls.js/0.12.4/hls.min.js

案例:

参考:

事件基本使用:

const hls = new Hls();
hls.on(Hls.Events.ERROR, (data) => {
    // do something~~        
});

注意:

声明hls实例 const hls = new Hls() ,一定要在组件销毁前,使用 hls.destroy() 注销hls实例,否则会造成内存泄漏(都是坑出来的o(╥﹏╥)o)

4.2 flv.js

4.2.1 flv.js简介

flv.js是来自Bilibli的开源项目。它解析FLV文件喂给原生HTML5 Video标签播放音视频数据,使浏览器在不借助Flash的情况下播放FLV成为可能。

4.2.2 flv.js的优缺点及兼容

优势:

  • 由于浏览器对原生Video标签采用了硬件加速,性能很好,支持高清。
  • 同时支持录播和直播。
  • 去掉对Flash的依赖。
  • FLV over WebSocket直播流播放。
  • HTTP FLV低延迟直播流播放。
  • 支持ts编译。

限制:

  • FLV里所包含的视频编码必须是H.264,音频编码必须是AAC或MP3, IE11和Edge浏览器不支持MP3音频编码,所以FLV里采用的编码最好是H.264+AAC,这个让音视频服务兼容不是问题。
  • 对于录播,依赖 原生HTML5 Video标签 和 Media Source Extensions API
  • 对于直播,依赖录播所需要的播放技术,同时依赖 HTTP FLV 或者 WebSocket 中的一种协议来传输FLV。其中 HTTP FLV 需通过流式IO去拉取数据,支持流式IO的有fetch或者stream
  • flv.min.js 文件大小 164Kb,gzip后 35.5Kb,flash播放器gzip后差不多也是这么大。
  • 由于依赖 Media Source Extensions,目前所有iOS和Android4.4.4以下里的浏览器都不支持,也就是说目前对于移动端flv.js基本是不能用的。。
  • HTTP FLV实时流当前不适用于所有浏览器,请参阅livestream.md

兼容性:

  • 由于IO限制,flv.js可以支持HTTP FLV直播流Chrome 43+,FireFox 42+,Edge 15.15048+和Safari 10.1+现在。
  • HTTP FLV直播,必须Access-Control-Allow-Origin在流服务器上正确配置标头。有关详细信息,请参阅cors.md
  • flv.js依赖的浏览器特性兼容列表

flv.js兼容方案:

由于目前flv.js兼容性还不是很好,要用在产品中必要要兼顾到不支持flv.js的浏览器。兼容方案如下:

PC端:

  • 优先使用 HTTP-FLV,因为它延迟小,性能也不差1080P都很流畅。
  • 不支持 flv.js 就使用 Flash播放器播 RTMP 流。Flash兼容性很好,但是性能差默认被很多浏览器禁用。
  • 不想用Flash兼容也可以用HLS,但是PC端只有Safari支持HLS。

移动端:

  • 优先使用 HTTP-FLV,因为它延迟小,支持HTTP-FLV的设备性能运行 flv.js 足够了。
  • 不支持 flv.js 就使用 HLS,但是 HLS延迟非常大。
  • HLS 也不支持就没法直播了,因为移动端都不支持Flash。

4.2.3 flv.js原理

flv.js只做了一件事,在获取到FLV格式的音视频数据后通过原生的JS去解码FLV数据,再通过Media Source Extensions API 喂给原生HTML5 Video标签。(HTML5 原生仅支持播放 mp4/webm 格式,不支持 FLV)

flv.js 为什么要绕一圈,从服务器获取FLV再解码转换后再喂给Video标签呢?原因如下:

  • 兼容目前的直播方案:目前大多数直播方案的音视频服务都是采用FLV容器格式传输音视频数据。
  • FLV容器格式相比于MP4格式更加简单,解析起来更快更方便。

4.2.4 flv.js使用

安装:

npm install --save flv.js

案例:

入门demo

搭建音视频服务:

gwuhaolin 用go语言实现的livego,因为它可以运行在任何操作系统上,对Golang感兴趣?请看Golang 中文学习资料汇总

  1. 下载livego,注意选对你的操作系统和位数。
  2. 解压livego,服务就启动好了。它会启动RTMP(1935端口)服务用于主播推流,以及HTTP-FLV(7001端口)服务用于播放。

实现播放页:

在react体系里使用react flv.js 组件reflv 快速实现。 先安装npm i reflv,再写代码:

import React, { PureComponent } from 'react';
import Reflv from 'reflv';

export class HttpFlv extends PureComponent {
  render() {
    return (
      <Reflv
        url={`http://localhost:7001/live/test.flv`}
        type="flv"
        isLive
        cors
      />
    )
  }
}

注: reflv是个人封装flv.js,可以参考,不建议直接使用。

让以上代码在浏览器里运行。这是你还看不到直播,是因为还没有主播推流。

  • 你可以使用OBS来推流,注意要配置好OBS。

    6b12348fbc7d13903c39a8b2f141b6bc.png

  • 也可以使用ffmpeg来推流,推流命令

    ffmpeg -f avfoundation -i "0" -vcodec h264 -acodec aac -f flv rtmp://localhost/live/test
    

参考:

flv.js延迟优化:

优化前先要介绍下直播运行流程:

  1. 主播端在采集到一段时间的音视频原数据后,因为音视频原数据庞大需要先压缩数据:

    • 通过H264视频编码压缩数据数据
    • 通过PCM音频编码压缩音频AAC数据
  2. 压缩完后再通过FLV容器格式封装压缩后的数据,封装成一个FLV TAG。

  3. 再把FLV TAG通过RTMP协议推流到音视频服务器,音视频服务器再从RTMP协议里解析出FLV TAG。

  4. 音视频服务器再通过HTTP协议通过和浏览器建立的长链接流式把FLV TAG传给浏览器。

  5. flv.js 获取FLV TAG后解析出压缩后的音视频数据喂给Video播放。

知道流程后我们就知道从哪入手优化了:

  • 主播端采集时收集了一段时间的音视频原数据,它专业的叫法是GOP。缩短这个收集时间(也就是减少GOP长度)可以优化延迟,但这样做的坏处是导致视频压缩率不高,传输效率低。
  • 关闭音视频服务器的I桢缓存可以优化延迟,坏处是用户看到直播首屏的时间变大。
  • 减少音视频服务器的buffer可以优化延迟,坏处是音视频服务器处理效率降低。
  • 减少浏览器端flv.js的buffer可以优化延迟,坏处是浏览器端处理效率降低。
  • 浏览器端开启flv.js的Worker,多线程运行flv.js提升解析速度可以优化延迟,这样做的flv.js配置代码是:
    {
        enableWorker: true,
        enableStashBuffer: false,
        stashInitialSize: 128,// 减少首桢显示等待时长
    }
    

4.3 video.js

4.3.1 video.js简介

Video.js是一款基于HTML5的网络视频播放器。它支持HTML5和Flash视频,以及YouTube和Vimeo(通过插件)。支持在桌面和移动设备上播放视频。这个项目从2010年中期开始,现已经在40多万个网站上使用。

4.3.2 video.js的优缺点

优势:

  • 开源免费,可以在github很容易的获取它的最新代码。
  • 兼容主流浏览器。
  • 界面可以定制,纯javascript和css打造。
  • 支持HLS, RTMP需引入插件支持。
  • 灵活插件机制。
  • 比较完善的文档。
  • 项目热度,开源作者对项目的维护比较积极。

限制:

  • 内置hls.js,体积偏大。

4.3.3 video.js原理

参考: H5播放器源码解读 (video.js)

4.3.4 video.js使用

安装:

CDN

<link href="//vjs.zencdn.net/7.3.0/video-js.min.css" rel="stylesheet">
<script src="//vjs.zencdn.net/7.3.0/video.min.js"></script>
// 支持RTMP
<script src="https://cdn.jsdelivr.net/npm/videojs-flash@2/dist/videojs-flash.min.js"></script>

npm

yarn add video.js --save
// 支持RTMP
yarn add videojs-flash -- save

案例:

入门demo

Video.js 踩坑简单入门:

采坑 采坑2

参考:

video.js文档

5. HTML5视频播放器

以下几款HTML5视频播放器,可配置插件,皮肤,自带UI,支持弹幕,支持FLV,HLS按需引入,集成配置功能。可参考使用。更多功能可参考文档。

xgplayer

xgplayer是一个网络视频播放器库。它基于一切都是组件化的原则设计了一个独立的,可拆卸的UI组件。更重要的是,它不仅在UI层中具有灵活性,而且在功能上也大胆:它消除了视频加载,缓冲和视频依赖的格式支持。特别是在mp4上它可以分阶段加载,因为它不支持流mp4。这意味着无缝切换,清晰度,负载控制和视频节省。它还集成了FLV,HLS和dash的按需和实时支持。

DPlayer

DPlayer是一个可爱的HTML5 danmaku视频播放器,可以帮助人们轻松地构建视频和danmaku。

6. 流媒体测试

6.1 流媒体测试工具

要播放视频直播流,或者测试一个直播视频地址是否可以使用。这里推荐 VLC 媒体播放器。功能强大且跨平台。支持 Windows、Mac OS、Linux、Android、iOS。

官网地址:链接

使用:

6.1 流媒体直播测试源

于2019年6月21日经测试可用。

HLS直播源地址:

RTMP直播源地址:

  • 香港卫视1:rtmp://live.hkstv.hk.lxdns.com/live/hks1

  • 香港卫视2:rtmp://live.hkstv.hk.lxdns.com/live/hks2

  • 湖南卫视:rtmp://58.200.131.2:1935/livetv/hunantv

  • 美国1:rtmp://ns8.indexforce.com/home/mystream

  • 美国中文电视:rtmp://media3.sinovision.net:1935/live/livestream

  • 香港财经:rtmp://202.69.69.180:443/webcast/bshdlive-pc

  • 韩国GoodTV:rtmp://mobliestream.c3tv.com:554/live/goodtv.sdp

7. 参考

8. 小结

声明:部分内容从网络获取,如有侵权行为,请与作者联系,作者将于2日内删除。

Peace: 👋 祝你们明天也是元气慢慢的一天哦~~ 😄