本文所包含内容:
- 直播的主流协议
- Video属性和方法详解
- 直播源的制作
- H5直播演示
- 微信小程序直播演示
- 常见问题
直播的主流协议
HLS协议, RTMP协议, HTTP-FLV协议
HLS协议
获取M3U8索引文件,文件中包含包含其它M3U8文件和视频分段
此类文件包含三种类型:动态列表、静态列表和全量列表,后两者较前者会多一到两个字段,文件示例
#EXTM3U
#EXT-X-VERSION:6 # 版本号,默认是3
#EXT-X-TARGETDURATION:6 # 时长
#EXT-X-MEDIA-SEQUENCE:0 # 序号
#EXT-X-PLAYLIST-TYPE:EVENT # 静态列表包含
#EXT-X-PLAYLIST-TYPE:VOD # 全量列表包含
#EXTINF:4.797000,
index0.ts
#EXTINF:4.396000,
index1.ts
#EXTINF:5.297000,
index2.ts
#EXT-X-ENDLIST # 全量列表包含
TS文件解析流程
使用方便,但缺点是在同一个M3U8中分片文件过多时会带来高延时
RTMP协议
传输文件格式是FLV,基于TCP协议,需要处理3次握手,因为使用更为复杂
HTTP-FLV协议
HTTP-FLV协议结合了HLS使用方便和RTMP低延时的特性
相比较RTMP协议的优点:
1、可以在一定程度上避免防火墙的干扰(例如,有的机房只允许80端口通过)
2、可以很好的兼容HTTP 302跳转,做到灵活调度
3、可以使用HTTPS做加密通道
4、很好地支持移动端(Android, iOS)
Video属性和方法详解
相关工具:Web Server for Chrome(在Chrome上模拟服务器请求)
下载、全屏隐藏:controlslist: nodownload, nofullscreen
贴图:poster属性
自动播放: autoplay
静音:muted (移动端非静音视频不允许自动播放)
循环播放:loop
预加载:preload (不同浏览器和客户端表现会存在差异)
音量控制:默认音量是1,添加volume属性通常无法生效,需通过JS代码来实现,如:
<script type="text/javascript">
var v = document.getElementById("my_video");
# 播放音量控制
v.volume = 0.5;
# 播放时间控制(单位:秒)
v.currentTime = 60;
# 视频地址切换(如切换不同清晰度)
v.src = "xxxx.mp4";
# 时长: duration
</script>
备用地址切换
# 当第一个地址出错时,访问第二视频地址
<video id="my_video" width="400" height="225"
controls controlslist="nodownload nofullscreen">
<source src="./video1.mp4" type="video/mp4">
<source src="./video2.mp4" type="video/mp4">
</video>
# 此时通过前述的v.src获取的地址为空,需使用v.currentSrc
事件
加载开始:loadstart
时长变化:durationchange
视频元数据下载完成:loadedmetadata
没有足够的数据播放下一帧:loadeddata
正在下载数据:progress
视频有帧可以播放:canplay
可以流畅地播放:canplaythrough
播放:play
暂停:pause
点击进度条视频查找:seeking
视频查找结束:seeked
正在准备数据:waiting
准备好数据播放:playing
播放时间变化:timeupdate
播放结束:ended
播放出错:error
# 加载开始loadstart
v.addEventListener('loadstart', function(e) {
console.log('loadstart');
})
直播源的制作
Nginx安装
Mac:
brew tap denji/nginx
brew install nginx-full --with-rtmp-module
# 输入nginx启动服务,使用http://localhost:8080进行验证
# ngnix -s stop; nginx -s reload
Windows:
http://nginx.org/en/docs/windows.html (按步骤操作需先安装Git Bash)
FFmpeg安装
Mac:
brew install ffmpeg
# 输入ffmpeg进行验证
Windows:
配置Nginx
# Mac配置
cd /usr/local/etc/nginx/
# -a后加atom或其它编辑器名称打开文件
open nginx.conf -a "Visual Studio Code"
# Windows下找到对应文件
# 添加rtmp模块
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_fragment 5s;
}
}
}
# 配置http版块
http {
...
server {
...
location /hls {
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
root /usr/local/var/www;
add_header Cache-Control no-cache;
# 解决跨域请求的问题
add_header Access-Control-Allow-Origin *;
}
}
}
工具准备:VLC播放器和Safari浏览器
RTMP测试:
通过本地视频模拟推流
ffmpeg -re -i test.mp4 -vcodec libx264 -acodec aac -f flv rtmp://localhost:1935/rtmplive/rtmp
VLC播放器中点击File > Open Network…,然后在URL部分输入前面定义的地址:
rtmp://localhost:1935/rtmplive/rtmp
HLS测试
模拟HLS推流
ffmpeg -re -i test.mp4 -vcodec libx264 -acodec aac -f flv rtmp://localhost:1935/hls/stream
打开Safari浏览器中打开http://localhost:8080/hls/stream.m3u8进行访问
TODO:HTTP-FLV的推流方式相对复杂,后续进行补充
封装包推流
如果您对Nginx不了解也不想要了解相关细节,还可以通过已封装的包进行测试
链接: https://pan.baidu.com/s/1jV51FmC0TodGODKiJM4BUg 密码: qbu9
下载该文件直接运行即可
# 执行以下命令推流
ffmpeg -re -i test.mp4 -c copy -f flv rtmp://localhost:1935/live/movie
# 直播地址
# hls
http://127.0.0.1:7002/live/movie.m3u8
# http-flv
http://127.0.0.1:7001/live/movie.flv
# rtmp
rtmp://localhost:1935/live/movie
H5直播演练
# 安装eslint
npm install eslint -g
# 初始化package.json
npm init
eslint --init
# ? How would you like to configure ESLint? Use a popular style guide
# ? Which style guide do you want to follow? Standard
# ? What format do you want your config file to be in? JavaScript
# 目录准备
mkdir source
cd source
mkdir videojs
mkdir hlsjs
mkdir flvjs
HLS视频直播
Video.js
# VIDEOJS拥有丰富的<a href="http://videojs.com/plugins/" target="_blank">插件</a>
cd videojs
curl -O vjs.zencdn.net/6.7/video-js.min.css
curl -O vjs.zencdn.net/6.7/video.min.js
# 点播测试代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>video.js点播视频的应用</title>
<link rel="stylesheet" href="./video-js.min.css">
<script src="./video.min.js" type="text/javascript"></script>
</head>
<body>
<video
id="my-player"
class="video-js"
controls
preload="auto"
poster="//vjs.zencdn.net/v/oceans.png">
<source src="../../test.mp4" type="video/mp4"></source>
<p class="vjs-no-js">
To view this video please enable JavaScript, and consider upgrading to a
web browser that supports HTML5 video
</p>
</video>
<script type="text/javascript">
var player = videojs('my-player', {
width: 400,
height: 200
});
</script>
</body>
</html>
# 直播
curl -O https://cdnjs.cloudflare.com/ajax/libs/videojs-contrib-hls/5.14.1/videojs-contrib-hls.js
# 示例代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>video.js点播视频的应用</title>
<link rel="stylesheet" href="./video-js.min.css">
<script src="./video.min.js" type="text/javascript"></script>
<script type="text/javascript" src="./videojs-contrib-hls.js"></script>
</head>
<body>
<video id="my-player" class="video-js" controls>
<source src="http://live.streamingfast.net/osmflivech4.m3u8" type="application/x-mpegURL">
<p class="vjs-no-js">
To view this video please enable JavaScript, and consider upgrading to a web browser that supports HTML5 video
</p>
</video>
<script type="text/javascript">
var player = videojs('my-player', {
width: 400,
height: 200
});
</script>
</body>
</html>
hls.js
touch index.html
touch index.js
touch index.css
curl -O https://cdn.jsdelivr.net/npm/hls.js@latest
mv hls.js\@latest hls.js
# hls.js好处在于它的轻量,可以在没有冗余的情况下自定义播放器的样式,以下是冗长的示例代码
# index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>hls.js演示</title>
<script src="./hls.js" type="text/javascript"></script>
<link rel="stylesheet" href="./index.css">
</head>
<body>
<div class="player pause">
<video id="video"></video>
<em class="btn"></em>
<span class="state">正在直播</span>
</div>
<script src="./index.js" type="text/javascript"></script>
</body>
</html>
# index.js
var video = document.getElementById('video');
var hls_url = "http://localhost:8080/hls/stream.m3u8";
var btn = document.querySelector('.btn');
var player = document.querySelector('.player');
if(Hls.isSupported()) {
var hls = new Hls();
hls.loadSource(hls_url);
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED,function() {
// video.play();
});
}else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = hls_url;
video.addEventListener('loadedmetadata',function() {
// video.play();
});
}
btn.addEventListener('click', function(){
if(video.paused){
video.play();
}else{
video.pause();
}
})
video.addEventListener('click', function() {
if(video.paused){
video.play();
}else{
video.pause();
}
})
video.addEventListener('play',function(){
player.className = 'player';
})
video.addEventListener('pause',function(){
player.className = 'player pause';
})
# index.css
html *, body *{
margin: 0;
padding: 0;
}
.player{
width: 400px;
height: 200px;
position: relative;
}
.player video{
width: 100%;
height: 100%;
}
.player .btn{
display: none;
width: 40px;
height: 40px;
border-radius: 50%;
position: absolute;
left: 50%;
top: 50%;
margin: -35px auto auto -35px;
padding: 15px;
background: rgba(255, 255, 255, 0.5);
line-height: 40px;
}
.player .btn:hover{
background: rgba(255, 255, 255, 0.7);
}
.player .btn:before{
border: 20px solid #ddd;
border-top-color: transparent;
border-bottom-color: transparent;
border-right-color: transparent;
content: " ";
display: block;
margin-left: 10px;
width: 0;
height: 0;
}
.player.btn:before:hover{
border-left-color: #fff;
}
.player.pause .btn{
display: block;
}
.player .state{
position: absolute;
bottom: 20px;
left: 20px;
font-size: 14px;
color: #000;
}
.player.pause .state{
display: none;
}
HTTP-FLV视频直播
flv.js
cd ../flvjs
touch index.html
touch index.js
curl -O http://bilibili.github.io/flv.js/dist/flv.js
# index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>flv.js演示</title>
<script src="./flv.js" charset="utf-8"></script>
</head>
<body>
<video id="videoElement" width="400" height="200" controls></video>
<script src="./index.js" charset="utf-8"></script>
</body>
</html>
# index.js
var flvjs = window.flvjs;
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();
}
微信小程序直播演示
需通过小程序开发工具的远程调试功能在手机上进行调试,手机与电脑在同一局域网,并且在直播源中使用内网地址192.168..
<!--index.wxml-->
<view class="container">
<view>
<live-player src="http://192.168.xxx.xxx:7001/live/movie.flv" mode="live" autoplay bindstatechange="statechange" binderror="error" style="width: 300px; height: 225px;" />
</view>
</view>
//index.js
Page({
statechange(e) {
console.log('live-player code:', e.detail.code)
},
error(e) {
console.error('live-player error:', e.detail.errMsg)
}
})
常见问题
1.Error: homebrew/nginx was deprecated. This tap is now empty as all its formulae were migrated.
brew tap denji/nginx
原文链接:Alan Hou 的个人博客