添加zlm集群支持

This commit is contained in:
64850858
2021-07-16 16:34:51 +08:00
parent 06d78575cc
commit 89a9ab4534
75 changed files with 2431 additions and 914 deletions

View File

@@ -7,22 +7,23 @@
<el-main>
<div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;">
<span style="font-size: 1rem; font-weight: bold;">云端录像</span>
<div style="position: absolute; right: 5rem; top: 0.3rem;">
节点选择: <el-select size="mini" @change="chooseMediaChange" style="width: 16rem; margin-right: 1rem;" v-model="mediaServer" placeholder="请选择" default-first-option>
<el-option
v-for="item in mediaServerList"
:key="item.id"
:label="item.id + '( ' + item.streamIp + ' )'"
:value="item">
</el-option>
</el-select>
</div>
<div style="position: absolute; right: 1rem; top: 0.3rem;">
<el-button v-if="!recordDetail" icon="el-icon-refresh-right" circle size="mini" :loading="loading" @click="getRecordList()"></el-button>
<el-button v-if="recordDetail" icon="el-icon-arrow-left" circle size="mini" @click="backToList()"></el-button>
</div>
</div>
<div v-if="!recordDetail">
<div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;font-size: 14px;">
节点选择: <el-select size="mini" @change="chooseMediaChange" style="width: 16rem; margin-right: 1rem;" v-model="mediaServer" placeholder="请选择" default-first-option>
<el-option
v-for="item in mediaServerList"
:key="item.generalMediaServerId"
:label="item.generalMediaServerId + '( ' + item.wanIp + ' )'"
:value="item">
</el-option>
</el-select>
</div>
<!--设备列表-->
<el-table :data="recordList" border style="width: 100%" :height="winHeight">
<el-table-column prop="app" label="应用名" align="center">
@@ -60,6 +61,7 @@
<script>
import uiHeader from './UiHeader.vue'
import cloudRecordDetail from './CloudRecordDetail.vue'
import MediaServer from './service/MediaServer'
export default {
name: 'app',
components: {
@@ -78,6 +80,7 @@
count:15,
total:0,
loading: false,
mediaServerObj : new MediaServer(),
recordDetail: false
};
@@ -107,20 +110,13 @@
},
getMediaServerList: function (){
let that = this;
this.$axios({
method: 'get',
url:`/api/server/media_server/list`,
}).then(function (res) {
console.log(res)
that.mediaServerList = res.data;
that.mediaServerObj.getMediaServerList((data)=>{
that.mediaServerList = data;
if (that.mediaServerList.length > 0) {
that.mediaServer = that.mediaServerList[0]
that.getRecordList();
}
}).catch(function (error) {
console.log(error);
});
})
},
getRecordList: function (){
let that = this;

View File

@@ -17,6 +17,8 @@
</el-table-column>
<el-table-column prop="gbId" label="国标编码" width="150" align="center">
</el-table-column>
<el-table-column prop="mediaServerId" label="流媒体" width="150" align="center">
</el-table-column>
<el-table-column label="开始时间" align="center" >
<template slot-scope="scope">
<el-button-group>
@@ -29,7 +31,7 @@
{{(scope.row.status == false && scope.row.gbId == null) || scope.row.status ?'是':'否'}}
</template>
</el-table-column>
<el-table-column label="操作" width="360" align="center" fixed="right">
<template slot-scope="scope">
<el-button-group>
@@ -125,7 +127,7 @@
that.getDeviceListLoading = false;
});
},
playPuhsh: function(row){
let that = this;
this.getListLoading = true;
@@ -134,7 +136,8 @@
url:`/api/media/stream_info_by_app_and_stream`,
params: {
app: row.app,
stream: row.stream
stream: row.stream,
mediaServerId: row.mediaServerId
}
}).then(function (res) {
that.getListLoading = false;

View File

@@ -32,6 +32,15 @@
</div>
</template>
</el-table-column>
<el-table-column prop="mediaServerId" label="流媒体" width="150" align="center"></el-table-column>
<el-table-column label="类型" width="100" align="center">
<template slot-scope="scope">
<div slot="reference" class="name-wrapper">
<el-tag size="medium">{{scope.row.type}}</el-tag>
</div>
</template>
</el-table-column>
<el-table-column prop="gbId" label="国标编码" width="180" align="center" show-overflow-tooltip/>
<el-table-column label="启用" width="120" align="center">
<template slot-scope="scope">
@@ -147,8 +156,6 @@
count: that.count
}
}).then(function (res) {
console.log(res);
console.log(res.data.list);
that.total = res.data.total;
that.streamProxyList = res.data.list;
that.getListLoading = false;
@@ -170,7 +177,6 @@
this.getListLoading = false;
if (res.data.code == 0 ){
if (res.data.data.length > 0) {
console.log(res.data.data)
this.$refs.onvifEdit.openDialog(res.data.data, (url)=>{
if (url != null) {
this.$refs.onvifEdit.close();
@@ -200,7 +206,8 @@
url:`/api/media/stream_info_by_app_and_stream`,
params: {
app: row.app,
stream: row.stream
stream: row.stream,
mediaServerId: row.mediaServerId
}
}).then(function (res) {
that.getListLoading = false;

View File

@@ -7,6 +7,17 @@
<el-main>
<div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;">
<span style="font-size: 1rem; font-weight: bold;">控制台</span>
<div style="position: absolute; right: 17rem; top: 0.3rem;">
节点选择: <el-select size="mini" @change="chooseMediaChange" style="width: 16rem; margin-right: 1rem;" v-model="mediaServerChoose" placeholder="请选择" default-first-option>
<el-option
v-for="item in mediaServerList"
:key="item.id"
:label="item.id + '( ' + item.streamIp + ' )'"
:value="item.id">
</el-option>
</el-select>
<span >{{loadCount}}</span>
</div>
<div style="position: absolute; right: 1rem; top: 0.3rem;">
<el-popover placement="bottom" width="750" height="300" trigger="click">
<div style="height: 600px;overflow:auto;">
@@ -53,6 +64,7 @@
<script>
import uiHeader from './UiHeader.vue'
import MediaServer from './service/MediaServer'
import echarts from 'echarts';
export default {
@@ -87,68 +99,101 @@ export default {
chartInterval: 0, //更新图表统计图定时任务标识
allSessionData: [],
visible: false,
serverConfig: {}
serverConfig: {},
mediaServer : new MediaServer(),
mediaServerChoose : null,
loadCount : 0,
mediaServerList : []
};
},
mounted() {
this.getAllSession();
this.initTable();
this.updateData();
this.chartInterval = setInterval(this.updateData, 3000);
this.mediaServer.getMediaServerList((data)=>{
this.mediaServerList = data.data;
if (this.mediaServerList && this.mediaServerList.length > 0) {
this.mediaServerChoose = this.mediaServerList[0].id
this.loadCount = this.mediaServerList[0].count;
this.getThreadsLoad();
this.getAllSession();
}
})
},
destroyed() {
clearInterval(this.chartInterval); //释放定时任务
},
methods: {
chooseMediaChange: function (val) {
this.loadCount = 0
this.initTable()
this.updateData();
},
updateData: function () {
this.getThreadsLoad();
this.getLoadCount();
this.getAllSession();
},
/**
* 获取线程状态
*/
getThreadsLoad: function () {
let that = this;
this.$axios({
if (that.mediaServerChoose != null) {
this.$axios({
method: 'get',
url: '/zlm/index/api/getThreadsLoad'
}).then(function (res) {
url: '/zlm/' + that.mediaServerChoose +'/index/api/getThreadsLoad'
}).then(function (res) {
if (res.data.code == 0) {
that.tableOption.xAxis.data.push(new Date().toLocaleTimeString('chinese', {
hour12: false
}));
that.table1Option.xAxis.data.push(new Date().toLocaleTimeString('chinese', {
hour12: false
}));
that.tableOption.xAxis.data.push(new Date().toLocaleTimeString('chinese', {
hour12: false
}));
that.table1Option.xAxis.data.push(new Date().toLocaleTimeString('chinese', {
hour12: false
}));
for (var i = 0; i < res.data.data.length; i++) {
if (that.tableOption.series[i] === undefined) {
let data = {
data: [],
type: 'line'
};
let data1 = {
data: [],
type: 'line'
};
data.data.push(res.data.data[i].delay);
data1.data.push(res.data.data[i].load);
that.tableOption.series.push(data);
that.table1Option.series.push(data1);
} else {
that.tableOption.series[i].data.push(res.data.data[i].delay);
that.table1Option.series[i].data.push(res.data.data[i].load);
}
for (var i = 0; i < res.data.data.length; i++) {
if (that.tableOption.series[i] === undefined) {
let data = {
data: [],
type: 'line'
};
let data1 = {
data: [],
type: 'line'
};
data.data.push(res.data.data[i].delay);
data1.data.push(res.data.data[i].load);
that.tableOption.series.push(data);
that.table1Option.series.push(data1);
} else {
that.tableOption.series[i].data.push(res.data.data[i].delay);
that.table1Option.series[i].data.push(res.data.data[i].load);
}
that.tableOption.dataZoom[0].start = that.charZoomStart;
that.tableOption.dataZoom[0].end = that.charZoomEnd;
that.table1Option.dataZoom[0].start = that.charZoomStart;
that.table1Option.dataZoom[0].end = that.charZoomEnd;
//that.myChart = echarts.init(document.getElementById('ThreadsLoad'));
that.myChart.setOption(that.tableOption, true);
// that.myChart1 = echarts.init(document.getElementById('WorkThreadsLoad'));
that.myChart1.setOption(that.table1Option, true);
}
that.tableOption.dataZoom[0].start = that.charZoomStart;
that.tableOption.dataZoom[0].end = that.charZoomEnd;
that.table1Option.dataZoom[0].start = that.charZoomStart;
that.table1Option.dataZoom[0].end = that.charZoomEnd;
//that.myChart = echarts.init(document.getElementById('ThreadsLoad'));
that.myChart.setOption(that.tableOption, true);
// that.myChart1 = echarts.init(document.getElementById('WorkThreadsLoad'));
that.myChart1.setOption(that.table1Option, true);
}
});
});
}
},
getLoadCount: function (){
let that = this;
if (that.mediaServerChoose != null) {
that.mediaServer.getMediaServer(that.mediaServerChoose, (data)=>{
if (data.code == 0) {
that.loadCount = data.data.count
}
})
}
},
initTable: function () {
let that = this;
@@ -242,10 +287,9 @@ export default {
getAllSession: function () {
let that = this;
that.allSessionData = [];
console.log("地址:" + '/zlm/index/api/getAllSession');
this.$axios({
method: 'get',
url: '/zlm/index/api/getAllSession'
url: '/zlm/' + that.mediaServerChoose +'/index/api/getAllSession'
}).then(function (res) {
res.data.data.forEach(item => {
let data = {

View File

@@ -39,6 +39,22 @@
<el-form-item label="超时时间:毫秒" prop="timeout_ms" v-if="proxyParam.type=='ffmpeg'">
<el-input v-model="proxyParam.timeout_ms" clearable></el-input>
</el-form-item>
<el-form-item label="节点选择" prop="rtp_type">
<el-select
v-model="proxyParam.mediaServerId"
@change="mediaServerIdChange"
style="width: 100%"
placeholder="请选择拉流节点"
>
<el-option label="自动选择" value="auto"></el-option>
<el-option
v-for="item in mediaServerList"
:key="item.id"
:label="item.id"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="FFmpeg命令模板" prop="ffmpeg_cmd_key" v-if="proxyParam.type=='ffmpeg'">
<!-- <el-input v-model="proxyParam.ffmpeg_cmd_key" clearable></el-input>-->
<el-select
@@ -68,6 +84,7 @@
<el-option label="组播" value="2"></el-option>
</el-select>
</el-form-item>
<el-form-item label="国标平台">
<el-select
v-model="proxyParam.platformGbId"
@@ -106,6 +123,8 @@
</template>
<script>
import MediaServer from './../service/MediaServer'
export default {
name: "streamProxyEdit",
props: {},
@@ -134,27 +153,8 @@ export default {
isLoging: false,
dialogLoading: false,
onSubmit_text: "立即创建",
platformList: [{
id: 1,
enable: true,
name: "141",
serverGBId: "34020000002000000001",
serverGBDomain: "3402000000",
serverIP: "192.168.1.141",
serverPort: 15060,
deviceGBId: "34020000002000000001",
deviceIp: "192.168.1.20",
devicePort: "5060",
username: "34020000002000000001",
password: "12345678",
expires: "300",
keepTimeout: "60",
transport: "UDP",
characterSet: "GB2312",
ptz: false,
rtcp: false,
status: true,
}],
platformList: [],
mediaServer: new MediaServer(),
proxyParam: {
name: null,
type: "default",
@@ -170,7 +170,9 @@ export default {
enable_hls: true,
enable_mp4: false,
platformGbId: null,
mediaServerId: "auto",
},
mediaServerList:{},
ffmpegCmdList:{},
rules: {
@@ -193,7 +195,6 @@ export default {
}
let that = this;
this.$axios({
method: 'get',
url:`/api/platform/query/10000/0`
@@ -202,17 +203,28 @@ export default {
}).catch(function (error) {
console.log(error);
});
this.$axios({
method: 'get',
url:`/api/proxy/ffmpeg_cmd/list`
}).then(function (res) {
that.ffmpegCmdList = res.data.data;
}).catch(function (error) {
console.log(error);
});
this.mediaServer.getMediaServerList((data)=>{
this.mediaServerList = data;
})
},
mediaServerIdChange:function (){
let that = this;
if (that.proxyParam.mediaServerId !== "auto"){
that.$axios({
method: 'get',
url:`/api/proxy/ffmpeg_cmd/list`,
params: {
mediaServerId: that.proxyParam.mediaServerId
}
}).then(function (res) {
that.ffmpegCmdList = res.data.data;
}).catch(function (error) {
console.log(error);
});
}
},
onSubmit: function () {
console.log("onSubmit");
this.dialogLoading = true;
var that = this;
that.$axios({
@@ -239,7 +251,6 @@ export default {
});
},
close: function () {
console.log("关闭添加视频平台");
this.showDialog = false;
this.dialogLoading = false;
this.$refs.streamProxy.resetFields();

View File

@@ -181,6 +181,7 @@ export default {
showVideoDialog: false,
streamId: '',
app : '',
mediaServerId : '',
convertKey: '',
deviceId: '',
channelId: '',
@@ -218,7 +219,7 @@ export default {
if (tab.name == "codec") {
this.$axios({
method: 'get',
url: '/zlm/index/api/getMediaInfo?vhost=__defaultVhost__&schema=rtmp&app='+ this.app +'&stream='+ this.streamId
url: '/zlm/' +this.mediaServerId+ '/index/api/getMediaInfo?vhost=__defaultVhost__&schema=rtmp&app='+ this.app +'&stream='+ this.streamId
}).then(function (res) {
that.tracksLoading = false;
if (res.data.code == 0 && res.data.online) {
@@ -235,12 +236,11 @@ export default {
}
},
openDialog: function (tab, deviceId, channelId, param) {
console.log("openDialog")
console.log(param)
this.tabActiveName = tab;
this.channelId = channelId;
this.deviceId = deviceId;
this.streamId = "";
this.mediaServerId = "";
this.app = "";
this.videoUrl = ""
if (!!this.$refs.videoPlayer) {
@@ -257,8 +257,8 @@ export default {
break;
case "streamPlay":
this.tabActiveName = "media";
this.showRrecord = false,
this.showPtz = false,
this.showRrecord = false;
this.showPtz = false;
this.play(param.streamInfo, param.hasAudio)
break;
case "control":
@@ -269,19 +269,17 @@ export default {
console.log(val)
},
play: function (streamInfo, hasAudio) {
this.hasAudio = hasAudio;
this.isLoging = false;
// this.videoUrl = streamInfo.rtc;
this.videoUrl = this.getUrlByStreamInfo(streamInfo);
this.streamId = streamInfo.streamId;
this.app = streamInfo.app;
this.mediaServerId = streamInfo.mediaServerId;
this.playFromStreamInfo(false, streamInfo)
},
getUrlByStreamInfo(streamInfo){
let baseZlmApi = process.env.NODE_ENV === 'development'?`${location.host}/debug/zlm`:`${location.host}/zlm`
console.log(12121212)
console.log(baseZlmApi)
// return `${baseZlmApi}/${streamInfo.app}/${streamInfo.streamId}.flv`;
// return `http://${baseZlmApi}/${streamInfo.app}/${streamInfo.streamId}.flv`;
return streamInfo.ws_flv;
@@ -430,6 +428,7 @@ export default {
var streamInfo = res.data;
that.app = streamInfo.app;
that.streamId = streamInfo.streamId;
that.mediaServerId = streamInfo.mediaServerId;
that.videoUrl = that.getUrlByStreamInfo(streamInfo);
that.recordPlay = true;
});

View File

@@ -0,0 +1,32 @@
import axios from 'axios';
class MediaServer{
constructor() {
this.$axios = axios;
}
getMediaServerList(callback){
this.$axios({
method: 'get',
url:`/api/server/media_server/list`,
}).then(function (res) {
if (typeof (callback) == "function") callback(res.data)
}).catch(function (error) {
console.log(error);
});
}
getMediaServer(id, callback){
this.$axios({
method: 'get',
url:`/api/server/media_server/one/` + id,
}).then(function (res) {
if (typeof (callback) == "function") callback(res.data)
}).catch(function (error) {
console.log(error);
});
}
}
export default MediaServer;