Browse Source

add html demo& doc

pull/168/head
xwc1125 4 years ago
parent
commit
579777dcdb
  1. 10
      README.md
  2. 82
      README_OBS.md
  3. BIN
      doc/img.png
  4. BIN
      doc/img_1.png
  5. BIN
      doc/img_2.png
  6. BIN
      doc/img_3.png
  7. BIN
      doc/img_4.png
  8. 108
      htmlVideoDemo/flvTest/demo.css
  9. 229
      htmlVideoDemo/flvTest/flvTest.html
  10. 12056
      htmlVideoDemo/flvTest/flvjs/flv.js
  11. 51
      htmlVideoDemo/hlsTest/hlsVideoTest.html
  12. 1388
      htmlVideoDemo/hlsTest/video-js.css
  13. 57494
      htmlVideoDemo/hlsTest/video.js
  14. 8
      htmlVideoDemo/hlsTest/videojs-contrib-hls.min.js
  15. 35
      livego.yaml
  16. 1
      protocol/hls/source.go
  17. 2
      protocol/httpflv/server.go

10
README.md

@ -42,9 +42,13 @@ Run `docker run -p 1935:1935 -p 7001:7001 -p 7002:7002 -p 8090:8090 -d gwuhaolin @@ -42,9 +42,13 @@ Run `docker run -p 1935:1935 -p 7001:7001 -p 7002:7002 -p 8090:8090 -d gwuhaolin
2. Get a channelkey(used for push the video stream) from `http://localhost:8090/control/get?room=movie` and copy data like your channelkey.
3. Upstream push: Push the video stream to `rtmp://localhost:1935/{appname}/{channelkey}` through the` RTMP` protocol(default appname is `live`), for example, use `ffmpeg -re -i demo.flv -c copy -f flv rtmp://localhost:1935/{appname}/{channelkey}` push([download demo flv](https://s3plus.meituan.net/v1/mss_7e425c4d9dcb4bb4918bbfa2779e6de1/mpack/default/demo.flv));
4. Downstream playback: The following three playback protocols are supported, and the playback address is as follows:
- `RTMP`:`rtmp://localhost:1935/{appname}/movie`
- `FLV`:`http://127.0.0.1:7001/{appname}/movie.flv`
- `HLS`:`http://127.0.0.1:7002/{appname}/movie.m3u8`
- `RTMP`:`rtmp://localhost:1935/live/movie`
- `FLV`:`http://127.0.0.1:7001/live/movie.flv`
- `HLS`:`http://127.0.0.1:7002/live/movie.m3u8`
5. 查看状态:
- http://127.0.0.1:8090/stat/livestat
all options:
```bash

82
README_OBS.md

@ -0,0 +1,82 @@ @@ -0,0 +1,82 @@
# LiveGO+OBS+Flv.js
## LiveGO部署及使用
### 部署
- docker部署
```docker
docker run -p 1935:1935 -p 7001:7001 -p 7002:7002 -p 8090:8090 -d gwuhaolin/livego
```
- 源码编译部署
```shell
1. 下载源码git clone https://github.com/gwuhaolin/livego.git
2. 去 livego 目录中 执行 go build
```
### 使用
- 启动服务:执行 `livego` 二进制文件启动 `livego` 服务;
- 获取房间channelkey:访问 http://localhost:8090/control/get?room=movie (channelkey用于推流,movie用于播放).
- 推流: 通过RTMP协议推送视频流到地址 `rtmp://localhost:1935/{appname}/{channelkey}` (appname默认是live),
例如: 使用 `ffmpeg -re -i demo.flv -c copy -f flv rtmp://localhost:1935/live/{channelkey}` 推流;
- 播放: 支持多种播放协议,播放地址如下:
- RTMP:rtmp://localhost:1935/live/{channelkey}
- FLV:http://127.0.0.1:7001/live/{channelkey}.flv
- HLS:http://127.0.0.1:7002/live/{channelkey}.m3u8
- 查看live状态:
```shell
http://127.0.0.1:8090/stat/livestat
```
- 重新生成channelkey
```shell
http://127.0.0.1:8090/control/reset?room=ROOM_NAME
```
- 删除房间
```shell
http://127.0.0.1:8090/control/delete?room=ROOM_NAME
```
## OBS
- 配置OBS
![img_2.png](doc/img_2.png)
- 添加媒体源,添加一个本地的flv文件即可
![img_3.png](doc/img_3.png)
- 开始推流
![img_4.png](doc/img_4.png)
## 流媒体服务器
流媒体在播放之前都要通过服务器进行过传输,从而实现播放行为
![img.png](doc/img.png)
### 1.什么是流媒体服务器?
> 流媒体是将一连串的媒体数据压缩后,经过网上分段发送数据,进行网上即时传输,是边下载边观赏影音的一种技术和过程。使得数据包像水流一样发送,如果不适用此技术,必须在使用之前下载整个流媒体文件。
> 流媒体服务器是流媒体应用的核心系统,在流媒体技术中承担了对音频,视频,图片等进行采集,缓存,调度和传输播放等功能。
> 流媒体服务器既然是在网络上输送流媒体数据到数据客户端,就一定涉及传输协议。流媒体服务器最常采用的协议有:RTMP,RTP,RTSP等。
### 2.流媒体服务器的传输方式有哪些?
主要传输方式有:`顺序流式传输`和`实时流式传输`
- 顺序流式传输:即顺序下载,在下载文件的同时,用户可以观看在线媒体。如果使用普通的HTTP服务器,将音视频数据通过从头到尾的方式进行发送即为顺序流媒体传输。
- 实时流式传输:总是实时传送,非常适合现场事件。比如视频为现场直播或者是使用专用的流媒体服务器,可以应用像RTSP等专用实时协议。实时流式传输必须要匹配链接宽带,也意味着图像质量会因网络速度的降低而变差。
![img_1.png](doc/img_1.png)
> 以上就是流媒体服务器的主要内容和原理,而且在流式传输的过程中,流媒体数据是具有实时性和等时性等基本特点的,流服务器和客户终端需要保证各种媒体之间的同步关系。由此可见,在开发过程中需要注意和兼顾的问题有很多。所以在直播平台建设的过程中,流媒体传输对于最大延时和延时抖动等参数的严格要求是需要特别注意的。
### 点量流媒体服务器和普通服务器有什么区别?
> 点量流媒体服务器除了能实现视频服务器所有功能外,点量流媒体流媒体服务器还可以实现直播转播大并发,加密防盗,边下边播功能,结合ott点播系统使用效果更佳!
> 点量流媒体服务器可以把连续的音频和视频信息压缩后放到网络服务器上,用户边下载边观看,而不必等待整个文件下载完毕。基于点量流媒体技术的优越性,点量流媒体服务器广泛应用于视频点播、视频会议、远程教育、远程医疗和在线直播系统中:

BIN
doc/img.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

BIN
doc/img_1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
doc/img_2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
doc/img_3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
doc/img_4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

108
htmlVideoDemo/flvTest/demo.css

@ -0,0 +1,108 @@ @@ -0,0 +1,108 @@
.mainContainer {
display: block;
width: 100%;
margin-left: auto;
margin-right: auto;
}
@media screen and (min-width: 1152px) {
.mainContainer {
display: block;
width: 1152px;
margin-left: auto;
margin-right: auto;
}
}
.video-container {
position: relative;
margin-top: 8px;
}
.video-container:before {
display: block;
content: "";
width: 100%;
padding-bottom: 56.25%;
}
.video-container > div {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.video-container video {
width: 100%;
height: 100%;
}
.urlInput {
display: block;
width: 100%;
margin-left: auto;
margin-right: auto;
margin-top: 8px;
margin-bottom: 8px;
}
.centeredVideo {
display: block;
width: 100%;
height: 100%;
margin-left: auto;
margin-right: auto;
margin-bottom: auto;
}
.controls {
display: block;
width: 100%;
text-align: left;
margin-left: auto;
margin-right: auto;
margin-top: 8px;
margin-bottom: 10px;
}
.logcatBox {
border-color: #CCCCCC;
font-size: 11px;
font-family: Menlo, Consolas, monospace;
display: block;
width: 100%;
text-align: left;
margin-left: auto;
margin-right: auto;
}
.url-input , .options {
font-size: 13px;
}
.url-input {
display: flex;
}
.url-input label {
flex: initial;
}
.url-input input {
flex: auto;
margin-left: 8px;
}
.url-input button {
flex: initial;
margin-left: 8px;
}
.options {
margin-top: 5px;
}
.hidden {
display: none;
}

229
htmlVideoDemo/flvTest/flvTest.html

@ -0,0 +1,229 @@ @@ -0,0 +1,229 @@
<html><head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<title>pingos flv.js player (v1.5.0)</title>
<link rel="stylesheet" type="text/css" href="demo.css">
</head>
<body>
<div class="mainContainer">
<div>
<div id="streamURL" class="">
<div class="url-input">
<label for="sURL">Stream URL:</label>
<input id="sURL" type="text" value="">
<button onclick="switch_mds()">Switch to MediaDataSource</button>
</div>
<div class="options">
<input type="checkbox" id="enableStashBuffer" onchange="saveSettings()" checked="">
<label for="enableStashBuffer">enableStashBuffer</label>
<input type="checkbox" id="isLive" onchange="saveSettings()" checked="">
<label for="isLive">isLive</label>
<input type="checkbox" id="withCredentials" onchange="saveSettings()">
<label for="withCredentials">withCredentials</label>
<input type="checkbox" id="hasAudio" onchange="saveSettings()" checked="">
<label for="hasAudio">hasAudio</label>
<input type="checkbox" id="hasVideo" onchange="saveSettings()" checked="">
<label for="hasVideo">hasVideo</label>
<label for="stashInitialSize">stashInitialSize:</label>
<input id="stashInitialSize" type="text" value="100">
</div>
</div>
<div id="mediaSourceURL" class="hidden">
<div class="url-input">
<label for="msURL">MediaDataSource JsonURL:</label>
<input id="msURL" type="text" value="http://127.0.0.1/flv/7182741.json">
<button onclick="switch_url()">Switch to URL</button>
</div>
</div>
</div>
<div class="video-container">
<div>
<video name="videoElement" class="centeredVideo" controls="" autoplay="" src="http://localhost:7001/live/movie.flv" muted>
Your browser is too old which doesn't support HTML5 video.
</video>
</div>
</div>
<div class="controls">
<button onclick="flv_load()">Load</button>
<button onclick="flv_start()">Start</button>
<button onclick="flv_pause()">Pause</button>
<button onclick="flv_destroy()">Destroy</button>
<input style="width:100px" type="text" name="seekpoint">
<button onclick="flv_seekto()">SeekTo</button>
</div>
<textarea name="logcatbox" class="logcatBox" rows="10" readonly=""></textarea>
</div>
<script src="flvjs/flv.js"></script>
<script>
var checkBoxFields = ['enableStashBuffer', 'isLive', 'withCredentials', 'hasAudio', 'hasVideo'];
var streamURL, mediaSourceURL;
function flv_load() {
console.log('isSupported: ' + flvjs.isSupported());
if (mediaSourceURL.className === '') {
var url = document.getElementById('msURL').value;
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onload = function (e) {
var mediaDataSource = JSON.parse(xhr.response);
flv_load_mds(mediaDataSource);
}
xhr.send();
} else {
var i;
var mediaDataSource = {
type: 'flv'
};
for (i = 0; i < checkBoxFields.length; i++) {
var field = checkBoxFields[i];
/** @type {HTMLInputElement} */
var checkbox = document.getElementById(field);
mediaDataSource[field] = checkbox.checked;
}
mediaDataSource['url'] = document.getElementById('sURL').value;
console.log('MediaDataSource', mediaDataSource);
flv_load_mds(mediaDataSource);
}
}
function flv_load_mds(mediaDataSource) {
var element = document.getElementsByName('videoElement')[0];
if (typeof player !== "undefined") {
if (player != null) {
player.unload();
player.detachMediaElement();
player.destroy();
player = null;
}
}
player = flvjs.createPlayer(mediaDataSource, {
enableWorker: false,
lazyLoadMaxDuration: 3 * 60,
seekType: 'range',
});
player.attachMediaElement(element);
player.load();
}
function flv_start() {
player.play();
}
function flv_pause() {
player.pause();
}
function flv_destroy() {
player.pause();
player.unload();
player.detachMediaElement();
player.destroy();
player = null;
}
function flv_seekto() {
var input = document.getElementsByName('seekpoint')[0];
player.currentTime = parseFloat(input.value);
}
function switch_url() {
streamURL.className = '';
mediaSourceURL.className = 'hidden';
saveSettings();
}
function switch_mds() {
streamURL.className = 'hidden';
mediaSourceURL.className = '';
saveSettings();
}
function ls_get(key, def) {
try {
var ret = localStorage.getItem('flvjs_demo.' + key);
if (ret === null) {
ret = def;
}
return ret;
} catch (e) {}
return def;
}
function ls_set(key, value) {
try {
localStorage.setItem('flvjs_demo.' + key, value);
} catch (e) {}
}
function saveSettings() {
if (mediaSourceURL.className === '') {
ls_set('inputMode', 'MediaDataSource');
} else {
ls_set('inputMode', 'StreamURL');
}
var i;
for (i = 0; i < checkBoxFields.length; i++) {
var field = checkBoxFields[i];
/** @type {HTMLInputElement} */
var checkbox = document.getElementById(field);
ls_set(field, checkbox.checked ? '1' : '0');
}
var msURL = document.getElementById('msURL');
var sURL = document.getElementById('sURL');
var stashInitSize = document.getElementById('stashInitialSize');
ls_set('msURL', msURL.value);
ls_set('sURL', sURL.value);
ls_set('stashInitialSize', stashInitSize.value);
console.log('save');
}
function loadSettings() {
var i;
for (i = 0; i < checkBoxFields.length; i++) {
var field = checkBoxFields[i];
/** @type {HTMLInputElement} */
var checkbox = document.getElementById(field);
var c = ls_get(field, checkbox.checked ? '1' : '0');
checkbox.checked = c === '1' ? true : false;
}
var msURL = document.getElementById('msURL');
var sURL = document.getElementById('sURL');
msURL.value = ls_get('msURL', msURL.value);
sURL.value = ls_get('sURL', sURL.value);
if (ls_get('inputMode', 'StreamURL') === 'StreamURL') {
switch_url();
} else {
switch_mds();
}
}
function showVersion() {
var version = flvjs.version;
document.title = document.title + " (v" + version + ")";
}
var logcatbox = document.getElementsByName('logcatbox')[0];
flvjs.LoggingControl.addLogListener(function(type, str) {
logcatbox.value = logcatbox.value + str + '\n';
logcatbox.scrollTop = logcatbox.scrollHeight;
});
document.addEventListener('DOMContentLoaded', function () {
streamURL = document.getElementById('streamURL');
mediaSourceURL = document.getElementById('mediaSourceURL');
loadSettings();
showVersion();
flv_load();
});
</script>
</body></html>

12056
htmlVideoDemo/flvTest/flvjs/flv.js

File diff suppressed because it is too large Load Diff

51
htmlVideoDemo/hlsTest/hlsVideoTest.html

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>前端播放m3u8格式视频</title>
<link href="video-js.css" rel="stylesheet">
<script src='video.js'></script>
<script src="videojs-contrib-hls.min.js" type="text/javascript"></script>
<!-- videojs-contrib-hls 用于在电脑端播放 如果只需手机播放可以不引入 -->
</head>
<body>
<style>
.video-js .vjs-tech {position: relative !important;}
</style>
<div>
<video id="myVideo" class="video-js vjs-default-skin vjs-big-play-centered" controls preload="auto" data-setup='{}' style='width: 100%;height: auto'>
<source id="source" src="http://localhost:7001/live/movie.m3u8" type="application/x-mpegURL"></source>
</video>
</div>
<div class="qiehuan" style="width:100px;height: 100px;background: red;margin:0 auto;line-height: 100px;color:#fff;text-align: center">切换视频</div>
</body>
<script>
// videojs 简单使用
var myVideo = videojs('myVideo', {
bigPlayButton: true,
textTrackDisplay: false,
posterImage: false,
errorDisplay: false,
})
myVideo.play()
var changeVideo = function (vdoSrc) {
if (/\.m3u8$/.test(vdoSrc)) { //判断视频源是否是m3u8的格式
myVideo.src({
src: vdoSrc,
type: 'application/x-mpegURL' //在重新添加视频源的时候需要给新的type的值
})
} else {
myVideo.src(vdoSrc)
}
myVideo.load();
myVideo.play();
}
var src = 'http://localhost:7001/live/movie.m3u8';
document.querySelector('.qiehuan').addEventListener('click', function () {
changeVideo(src);
})
</script>
</html>

1388
htmlVideoDemo/hlsTest/video-js.css

File diff suppressed because one or more lines are too long

57494
htmlVideoDemo/hlsTest/video.js

File diff suppressed because it is too large Load Diff

8
htmlVideoDemo/hlsTest/videojs-contrib-hls.min.js vendored

File diff suppressed because one or more lines are too long

35
livego.yaml

@ -1,22 +1,39 @@ @@ -1,22 +1,39 @@
# # Logger level
# level: info
level: debug
# # FLV Options
# flv_archive: false
# flv_dir: "./tmp"
# httpflv_addr: ":7001"
# flv_archive:表示存档,将推送过来的数据进行保存
flv_archive: true
# flv_dir:存到路径
flv_dir: "./tmp"
# httpflv_addr:存档的端口
httpflv_addr: ":7001"
# # RTMP Options
# rtmp_noauth: false
# rtmp_addr: ":1935"
# read_timeout: 10
# write_timeout: 10
rtmp_noauth: true
rtmp_addr: ":1935"
read_timeout: 10
write_timeout: 10
# # HLS Options
#hls_addr: ":7002"
# # livego是支出两种存储方式,一种是localCache,另一种是redis,想启用redis就需要在配置文件中增加两项配置
# #想启用redis需要打开以下两项注释,不打开默认启用本地存储
#redis_addr: 127.0.0.1:6379
#redis_pwd:
# #想启用jwt需要打开以下三项注释
# # # algorithm: 仅支持 以下三种算法 默认HS256算法
# # # # HMAC签名方法: HS256 HS384 HS512
# # # # RSA签名方法: RS256,RS384,RS512
# # # # ECDSA签名方法: ES256,ES384,ES512
#jwt:
#- secret: xxx
# algorithm: xxx
# # API Options
# api_addr: ":8090"
api_addr: ":8090"
server:
- appname: live
live: true

1
protocol/hls/source.go

@ -97,6 +97,7 @@ func (source *Source) DropPacket(pktQue chan *av.Packet, info av.Info) { @@ -97,6 +97,7 @@ func (source *Source) DropPacket(pktQue chan *av.Packet, info av.Info) {
log.Debug("packet queue len: ", len(pktQue))
}
// 推送过来的数据包
func (source *Source) Write(p *av.Packet) (err error) {
err = nil
if source.closed {

2
protocol/httpflv/server.go

@ -122,7 +122,9 @@ func (server *Server) handleConn(w http.ResponseWriter, r *http.Request) { @@ -122,7 +122,9 @@ func (server *Server) handleConn(w http.ResponseWriter, r *http.Request) {
} else {
include := false
for _, item := range msgs.Publishers {
log.Debug("playPath=" + path + ",publishPath=" + item.Key)
if item.Key == path {
log.Info("PlaySuccess:" + "path=" + path)
include = true
break
}

Loading…
Cancel
Save