大前端这几年算是一个热词,对于前段来说如果不是大前端,技术相对来说就已经算是落后了。如果还停留在对ES6,Vue这些基本技能的学习只能说处于一个及格线。
如果想做的卓越必须必备另一些大前端技能,比如说NodeJS,express.js, koaJs服务类,或者three.js这类3d数据图像,还有二维图像处理,比如d3,raphael, echart, 最后hls, flv视频行业。
如果只会ES6,Vue,React, Webpack这只能算是前端,大前端是至少要掌握上面的一项技能的。这篇文章就是介绍大前端领域中的视频直播。
本文主要讲述的是H5前端部分,视频音频采集部分后面会但开篇章来讲。首先带领大家快速实现一个直播系统,然后再讲解其中的重要概念,话不多说,直接开撸。
这里首先讲述mac系统的操作方法,windows系统安装方式在下面。需要的工具我已经传到的github上,可以自行下载。git地址
server是推流工具,tools里面有下面需要安装的工具。
安装yasm yasm;
// 可以在h5live中找到yasm
cd /h5live/tools/yasm-1.3.0
// 配置
./configure
// 编译 & 安装
make
sudo make install
安装sdl sdl;
// 切可以在h5live中找到sdl目录
cd /h5live/tools/SDL2-2.0.8
// 配置
./configure
// 编译 & 安装
make -j 16
sudo make install
安装ffmpeg ffmpeg;
// 切可以在h5live中找到ffmpeg,prefix为要安装到的位置
cd /h5live/tools/ffmpeg-4.3
// 配置
./configure --prefix=/usr/local/ffmpeg --enable-debug=3 --enable-shared --disable-static
// 编译 & 安装
make -j 4
sudo make install
设置ffmpeg软连接, 相当于环境变量,目的是为了在任何目录都可以使用ffmpeg命令,/usr/local/ffmpeg-4.3/ffmpeg
是安装的路径
ln -s /usr/local/ffmpeg-4.3/ffmpeg /usr/local/bin/ffmpeg
FFmpeg程序进行各种媒体格式的转换,使得它们可以在不同设备上播放。该程序只有命令行模式,因此将它安装到计算机中看上去有点麻烦,但是只要根据本指南的方法,你只需要几分钟就可以将FFmpeg安装成功!
下载 ffmpeg:
访问下载页面时,你将看到很多不同下载选项。你可以根据自己的操作系统选择下载最新的32位或64位静态程序版本。
安装:
点击开始菜单,然后点击计算机。选择安装Windows系统的磁盘(一般是C:)。在C:盘的根目录下(该目录下有名为Windows和Program Files文件夹),右击并在弹出菜单中选择新建文件夹。将新文件夹命名为“ffmpeg”。将下载的ffmpeg压缩包解压到这个文件夹中。
在环境变量中加入ffmpeg的启动命令,c:\ffmpeg\bin
, 俗称配置环境变量。
打开命令提示符窗口,输入命令“ffmpeg –version”。如果命令提示窗口返回FFmpeg的版本信息,那么就说明安装成功了,你可以在命令提示行中任意文件夹下运行FFmpeg。
如果你收到“libstdc++ -6 is missing”的错误消息,那么你可能需要安装Microsoft Visual C++ Redistributable Package,该软件包可以在微软网站免费获取。
很简单,进入从github中获取到的h5live中server所在的目录,运行server程序即可。
cd /h5live/server
open server
可以看到这里提供了三种协议的路径,分别是rtmp协议的1935接口,http-flv协议的7001端口和hls的7002端口。
找一个mp4格式的视频文件,假设这个文件叫1.mp4,可以在1.map所在的文件夹下执行下面的命令。
ffmpeg -re -i 1.mp4 -c copy -f flv rtmp://127.0.0.1:1935/live/movie
出现下图的效果就表示1.MP4这个视频开始进行流推送了。
上面我们已经说了server工具提供三种协议的视频流,分别是rtmp,http-flv以及hls。
可以使用VLC播放器验证rtmp协议的视频流。
在里面粘贴入rtmp://127.0.0.1:1935/live/movie
然后就可以看到直播的效果了。
下载 VLC 播放器:
Mac OS X
Windows
hls协议的流媒体可以使用Safari浏览器直接打开观看。我们可以直接把http://127.0.0.1:7002/live/movie.m3u8
放到Safari浏览器的地址栏中查看效果。
至此我们的推流就做完了,在H5的直播开发中,这些工作都是服务器,我们之所以演示这些是为了在实际的开发中我们可以懂得直播的过程,可以快速的给出直播的解决方案。最主要的在服务还没有开发完成之前我们可以通过这样的方式快速搭建一个推流系统,前端先开发起来。
// RTMP,可以使用VLC播放器
rtmp://127.0.0.1:1935/live/movie
// FLV
http://127.0.0.1:7001/live/movie.flv
// HLS 可以使用Safari浏览器访问
http://127.0.0.1:7002/live/movie.m3u8
这里才是前端真正需要关心的部分,主要介绍我们如何用js去写一个直播的播放器,选择一些已有的最佳实践是最稳妥的,这样可以快速的满足业务需求,这里我们会介绍三款播放器,以及他们的使用。同样这些代码我也传到了github上。
video.js是国外比较流行的视频框架,他的特长是做了非常好的自定义ui,符合线上成品的场景,除了自定义ui,还提供了很多插件,比如弹幕,快捷键,hls支持等等。他是一个比较完整的js框架,点播、直播都很合适,缺点是文件较大。
hls.js适合做hls协议的一款小巧的框架,同样也是点播直播都可以。缺点是需要自己书写UI样式。video.js可以支持hls也是因为插件是基于hls.js
flv.js是B站开源的flv格式的播放器,如果是http-flv协议的直播用它是非常合适的。
至于rtmp在H5的直播中是不常用的,所以这里就不讲了。
在github找到videojshttps://github.com/videojs/video.js
, 可以在这个网址中找到下面的两个文件,下载下来放在我们本地。
在Video.js的插件文档中存在大量的插件,我们可以从中找到自己需要的。https://videojs.com/plugins/
videojs-contrib-hls是一个支持hls直播的video插件。我们找到cdn, 将js保存到本地。使用方式很简单,只需要把插件的js引入进来就可以了。
将video.min.js和videojs-contrib-hls.js以及video-js.min.css引入到页面中,source标签的地址写上我们hls的m3u8后缀地址。就可以了。
注意这里需要在服务器环境查看。
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<link rel="stylesheet" href="video-js.min.css">
head>
<body>
<video id=example-video width=600 height=300 class="video-js vjs-default-skin" controls>
<source
src="http://127.0.0.1:7002/live/movie.m3u8"
type="application/x-mpegURL">
video>
<script src="video.min.js">script>
<script src="videojs-contrib-hls.js">script>
<script>
var player = videojs('example-video');
player.play();
script>
body>
html>
可以看到videojs帮我们处理好了ui问题。是一款可以快速使用矿建。
需要下载对应hls代码,可以去github中寻找,https://github.com/video-dev/hls.js
。
使用方式也很简单,因为hls.js并没有为我们提供UI样式,所以我们只需要引入js即可。
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<video id="video" controls width="400" height="300">video>
<script src="hls.js">script>
<script>
var video = document.getElementById('video');
var videoSrc = 'http://127.0.0.1:7002/live/movie.m3u8';
if (Hls.isSupported()) {
var hls = new Hls();
hls.loadSource(videoSrc);
hls.attachMedia(video);
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = videoSrc;
}
script>
body>
html>
flv.js是B站开源的一款flv播放器,可以说是国人的骄傲,同样使用起来非常简单。也是引入flv.js。
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<script src="flv.js">script>
<video id="videoElement" controls width="400" height="300">video>
<script>
if (flvjs.isSupported()) {
var videoElement = document.getElementById('videoElement');
var flvPlayer = flvjs.createPlayer({
type: 'flv',
url: 'http://127.0.0.1:7001/live/movie.flv'
});
flvPlayer.attachMediaElement(videoElement);
flvPlayer.load();
flvPlayer.play();
}
script>
body>
html>
这里讲述的是小程序的直播,默认我这里认为大家是有小程序开发经验的,所以如何创建小程序,安装开发者工具,调试等内容就不说了。
微信小程序直播使用的是媒体组件的live-player,并且他仅支持flv或者rtmp格式,这一点在前后端确认技术方案时尤为重要。还有就是他只针对对应行业开放。可以查看这里连接https://developers.weixin.qq.com/miniprogram/dev/component/live-player.html
符合上述类目的小程序开放,需要先通过类目审核,再在小程序管理后台,「开发」-「接口设置」中自助开通该组件权限。
打开这个权限之后,我们就可以使用小程序的live-player组件进行直播开发了。他的使用也非常简单。
<live-player src="https://domain/pull_stream" mode="RTC" autoplay bindstatechange="statechange" binderror="error" style="width: 300px; height: 225px;" />
Page({
statechange(e) {
console.log('live-player code:', e.detail.code)
},
error(e) {
console.error('live-player error:', e.detail.errMsg)
}
})
这里需要注意的是,开发者工具不能进行直播调试,只能使用远程调试。连接我们的手机查看效果。live-player 默认宽度300px、高度225px,可通过wxss设置宽高。
至此H5和小程序的直播开发我们就说完了,以上内容已经足够大家完成工作中的直播开发任务和可能出现的直播业务了。
接着我们会介绍一下直播的流程、协议以及基于nginx搭建一个直播服务。后面的内容偏理论和服务。和前端关系不大可以跳过。
对于一个直播流程来说首先是视频音频等媒体的采集,一般采集方有三种,PC端,安卓端以及IOS端,他们的工作也都是依赖摄像头和麦克风的。一般直播的人会选择购买专业的摄像头和麦克风。这里收集到的数据是流的格式,也就是二进制的数据,这里的数据会经过socket或者http上传至服务器。
信息源采集之后第一个步骤是进行编码,因为采集到的原始流是不能直接被客户端进行播放的,必须采用一定的协议去做编码,一般视频编码采用H.264,音频编码一般是AAC。这两种是直播行业最常见的编码格式。
编码之后一般可能会伴随着字幕的叠加,当然这个是不必须的是一个可有可无的过程。这里要说的其实是对视频的一些处理,可能添加水印之类的二次加工。
视频和音频处理之后就要进行推流,也就是把视频和音频推送到服务器中,也就是我们上面使用ffmpeg将1.mp4推送的过程。
工作中服务器会将推送过来的流媒体经过部署再把资源推到CDN上,一般我们静态的资源或者多媒体资源都会发布到CDN来保证用户体验和拉取的速度。
对于客户端来说是直接访问CDN的地址的,同样这里的客户端可能是PC, 安卓或者IOS的播放器。
以上就是一个简单的直播处理过程。
一般我们常见的视频格式是mp4,他的兼容性非常好,谷歌,火狐,苹果,IE等浏览器都是支持的。webm是一种流式的视频格式,常见于youtube网站,但是这种格式只有谷歌和火狐浏览器支持。
hls严格来说他不是视频格式,他是一种视频协议,他的视频格式是ts,为了好分辨一般我们叫他hls,这种格式是苹果自身研究出来的,所以Safari浏览器可直接支持,上面我们演示的时候hls是直接放在Safari浏览器的地址栏可以直接播放的。
flv是早期flash的一种视频格式,B站早起就采用的这种格式,即使现在B站也是支持H5播放器和flash播放器的。
直播目前最常用的三种协议是HLS协议,RTMP协议和HTTP-FLV协议。HLS对应的是hls格式的视频也就是.ts。RTMP和HTTP-FLV都是对应的flv格式的视频。
HLS协议是最简单的也是最常用的,他是苹果推出的一个直播协议,他的工作原理比较简单,H5一般通过video标签,从客户端获取一个M3U8索引文件,这个M3U8会直接放在video的src路径中。
因为M3U8是一个索引文件,他会被解析成很多的.ts片段,每一个片段就是一个直播流的分段。
浏览器的video标签在某个时间会再次请求m3u8,获取新的直播流片段,这样就实现了直播的实时播放,而发送这个m3u8的请求是浏览器自主的行为。
<body>
<video id=example-video width=600 height=300 class="video-js vjs-default-skin" controls>
<source
src="http://127.0.0.1:7002/live/movie.m3u8"
type="application/x-mpegURL">
video>
<script src="video.min.js">script>
<script src="videojs-contrib-hls.js">script>
<script>
var player = videojs('example-video');
player.play();
script>
body>
这是一个比较标准的直播协议,但是m3u8不一定包含了ts文件,也有可能嵌套了一层m3u8文件,也就是说第一个拿到的m3u8文件里面还是m3u8文件。
如果当前的m3u8里面包含了m3u8文件,那么当前这个文件就叫master playlist。
如果当前的m3u8文件里面包含的是ts, 那他就叫media playlists。
这种情况不常见,但是确实是存在的,我们需要额外注意一下。如果我们在实践直播的时候拿到的流文件不播放,可能是播放器不支持这种嵌套。
m3u8分为动态列表,静态列表,全量列表。在直播行业基本是见不到静态列表的,他只是存在标准中。
动态列表主要用于直播的过程中,全量列表多用于点播,也就是录播。m3u8的响应结果就是一个文本文件。
第一行标明了m3u8的版本,这个比较重要,因为他直接涉及到我们的播放器支持的hls的版本,如果版本不支持,后面的一些指令可能就无法解析。
第二行是版本的声明,默认是3,第三行是默认视频的时长,第四行是视频流块的个数,每次请求都会加1,再往下就是视频的ts文件,前面的9.901是这个ts文件的时长。这里决定了浏览器的video更新m3u8文件的时机。
静态列表和动态列表返回文件差不多,只是在第五行多添加了一个playlist-type值为event。其他的就没什么区别了。
全量列表比动态列表多了两个东西,第一个是playlist-type值为vod,还有底部的ext-x-endlist代表结束,浏览器识别到这个字段就不会再发送请求了。
对于第一个ts文件,他会有一个PAT的包,这个PAT的包告诉我们要去找一个PMT的包,PMT会告诉我们所有的TS里面哪些是视频TS哪些是音频TS。很多TS组成一个叫做PES的东西。
浏览器像去解析一个视频,首先要知道视频帧和音频帧,在第一个ts文件中会告诉浏览器,通过先找PAT, 再找PMT,再找TS文件,然后TS文件再按照视频和音频分类把相连的ts组成一个帧。
RTMP是Real Time Messaging Protocol(实时消息传输协议)的首字母缩写。该协议基于TCP, 是一个协议族,包括RTMP基本协议及RTMPT/RTMPS/RTMPE等多种变种。RTMP是一种设计用来进行实时数据通信的网络协议,主要用来在Flash,AIR平台和支持RTMP协议的流媒体/交互服务器之间进行音视频和数据通信。
传统的软件和服务器之间的交互还是以RTMP为主,比如说上文讲的视频音频的采集以PC端为主,如果客户端通过软件的方式采集基本就是基于RTMP,如果采集端用的是H5他的协议一般是webrtc。这是两种不同的技术方案。采集时RTMP传输过程中视频也是flv格式的。这里需要注意一下。
RTMP要比HLS协议用起来复杂一些因为他是基于TCP协议的。HLS使用非常简单但他的实时性会差一些,也就说他有延时,切片越多延时越大。HTTP-FLV结合了HLS的优点也就是http请求然后又集合了RTMP低延时的特性。
HTTP-FLV和RTMP都是长连接,传输的格式也都是flv,不同点在于他们和CDN的链接还有播放器的链接上,RTMP是TCP而HTTP-FLV是HTTP。
HTTP-FLV相对于RTMP优势有很多,比如可以在一定程度上避免防火墙的干扰,可以很好地兼容HTTP302跳转,做到灵活调度,可以使用HTTPS做加密通道,可以很好的支持移动端(安卓和IOS)。
这里我们补充一点video标签的知识,针对于大多数的前端开发来说,并没有真正意义上的了解video标签,他的属性,他的事件。很多人都停留在知道他是视频标签,可以播放,暂停,调节音量,有个src属性中。
这是很危险的,Video标签是H5推出的一款功能十分强大的多媒体标签,可以说他是网页中媒体的未来。
标签属性部分:
<video
src="test.map"
width="400"
height="225"
controls
controlslist="nodownload nofullscreen"
poster="预览图"
autoplay
muted
loop
preload
>video>
controls:底部控制条
controlslist:底部控制条定制
poster:预览图
autoplay: 自动播放
muted: 静音(移动端非静音的视频是不允许自动播放的,想要自动播放一定要静音)
loop: 循环播放
preload: 预加载,每个浏览器表现不一致,尤其是移动端,如果需要最好加上。
JS控制部分:
volume: 音量(0 - 1)
currentTime: 设置获取当前播放时间,单位是秒,超清和高清分别是不同的地址,档切换地址时需要定位时间。
src: 获取视频地址
video.volume = 0.5;
video.currentTime = 60;
video.src;
可以通过source标签兼容视频地址出错, 这种情况js需要使用currentSrc获取当前地址。
<video>
<source src="./test.map" type="video/mp4">source>
<source src="./test2.map" type="video/mp4">source>
video>
video事件:
loadstart: 视频开始加载。
durationchange: 时长变化,表示可以获取视频时长了。
loadedmetadata: 当指定的音频/视频的元数据已加载时,会发生 loadedmetadata 事件
loadeddata: 当前帧的数据已加载,但没有足够的数据来播放指定音频/视频的下一帧时,会发生 loadeddata 事件
progress: 当浏览器正在下载指定的音频/视频时,会发生 progress 事件
canplay: 当浏览器能够开始播放指定的音频/视频时,会发生 canplay 事件
canplaythrough: 当浏览器预计能够在不停下来进行缓冲的情况下持续播放指定的音频/视频时,会发生 canplaythrough 事件
play: 暂停状态改变到播放状态就会触发play事件
seeking: 切换进度条的时候会触发的事件。
seeked: seeking之后下载完数据就会执行。
waiting: 播放状态时,seeking之后会触发waiting。也就是播放状态如果没有足够数据支撑播放就会waiting。
playing: 播放中状态。
timeupdate: 播放时间更新的事件。
ended: 播放结束
error: 报错事件。
前面我们利用已经集成好的server工具创建了一个直播的服务器,这里我们使用nginx手动搭建一个类似的服务器,再来理解一下他的工作过程。
首先需要安装nginx和ffmpeg工具。ffmpeg工具上面已经有了安装过程,nginx的安装可以参考我之前的文章前端应该了解的nginx
工具安装完成之后我们开始配置nginx。在在nginx.conf文件中配置,我们需要配置服务RTMP模块,在配置文件的最底部新开一个代码块叫rtmp,里面写上监听1935端口,视频切片大小设置4000,也可以自行设置,然后配置一个rtmp的直播应用rtmplive,在配置一个hls的直播应用。
rtmp {
server {
# 监听端口
listen 1935;
# 切片大小
chunk_size 4000;
# RTMP 直播流配置
application rtmplive {
# 开启直播
live on;
# 最大连接数
max_connections 1024;
}
# hls直播流配置
application hls {
live on;
hls on;
# 分割文件存储的位置
hls_path /usr/local/var/www/hls;
# hls分片大小
hls_fragment 5s;
}
}
}
配置好这个之后需要在http模块中配置访问位置。我们可以在server块中增加location。
server {
listen 8080;
...
locaton /hls {
# 声明相应类型, 也就是响应头
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
# 目录指向我们rtmp块中切片的目录
root /usr/local/var/www;
# 禁止缓存
add_header Cache-Control no-cache;
}
}
至此我们nginx就配置完毕了,可以重启nginx进行测试。
nginx -s reload
同样的,我们可以找到前面的那个1.mp4使用ffmpeg来推流。这里视频采用libx264编码,音频采用aac编码,做成flv推送到rtmp://localhost:1935/rtmplive/rtmp域名,这个1935就是我们设置rtmp的端口,rtmplive就是应用名称。
ffmpeg -re -i 1.mp4 -vcodec libx264 -acodec aac -f flv rtmp://localhost:1935/rtmplive/rtmp
-i: 输入
-vcodec: 视频编码
acodec: 音频编码
这个时候就开始切割我们的视频了,这个过程也就像是摄像头实时获取视频的过程。
这是一个rtmp协议的直播流,我们可以使用vlc来播放,只要在file/open networks中输入rtmp://localhost:1935/rtmplive/rtmp
就可以播放了。
下面我们再来演示一下HLS的源文件制作,这里的ffmpeg命令基本相同,只是我们的路径需要变一下。上面nginx配置了rtmplive和hls两个。hls推流需要使用rtmp://localhost:1935/hls/stream
, 这里的stream可以随意起,不过这个名字关系都后面访问的地址。
ffmpeg -re -i 1.mp4 -vcodec libx264 -acodec aac -f flv rtmp://localhost:1935/hls/stream
这里的hls是http协议,我们之前在nginx的http协议中也增加了一个hls访问路径。http的地址我们可以使用Safari浏览器访问。也可以使用我们上面自己开发的播放器访问。
http://localhost:8080/hls/stream.m3u8
http-flv的编译比较复杂,我们这里就不过多介绍了。至此H5和小程序的直播我们就介绍完了。
点赞还是要求一下的,万一就给了呢