|
|
|
@ -4,23 +4,39 @@
|
|
|
|
|
{{device.displayName}}
|
|
|
|
|
</div>
|
|
|
|
|
<div class="card-body" style="padding:0;">
|
|
|
|
|
<div class="row" style="width:320px;height:240px;margin: 0 auto;background-color:black;">
|
|
|
|
|
<video :class="device.number" v-if="flvjs.isSupported()"></video>
|
|
|
|
|
<canvas :class="device.number" v-else></canvas>
|
|
|
|
|
<div class="row" style="width:320px;height:240px;margin: 0 auto;background-color:#000;position:relative;">
|
|
|
|
|
<video controls muted autoplay :class="device.number" v-if="isFlvSupported" v-on:volumechange="volumeChange($event)" style="width:100%;height:100%;object-fit:contain;"></video>
|
|
|
|
|
<canvas width="1080" height="720" style="max-width:100%;height:100%;background: black;margin:0 auto;" :class="device.number+' wxinlineplayer'" v-else></canvas>
|
|
|
|
|
<div class="control">
|
|
|
|
|
<a href="javascript:;" v-on:click="play()" style="color:#fff;margin:0 10px;line-height:30px;">
|
|
|
|
|
<i class="ion ion-md-pause" v-if="playing"></i>
|
|
|
|
|
<i v-else class="ion ion-md-play"></i>
|
|
|
|
|
</a>
|
|
|
|
|
<template v-if="playing">
|
|
|
|
|
<a href="javascript:;" v-on:click="fullScreen()" style="color:#fff;margin:0 10px;line-height:30px;float:right;">
|
|
|
|
|
<i class="ion ion-md-expand"></i>
|
|
|
|
|
</a>
|
|
|
|
|
<a href="javascript:;" v-on:click="mute()" style="color:#fff;margin:0 10px;line-height:30px;float:right;">
|
|
|
|
|
<i class="ion ion-md-volume-off" v-if="muted"></i>
|
|
|
|
|
<i class="ion ion-md-volume-high" v-else></i>
|
|
|
|
|
</a>
|
|
|
|
|
<input type="range" min="0" max="1" step="0.1" :value="volume" style="-webkit-appearance:none;float:right;width:80px;height:4px;margin:13px 2px;background:#666;outline:none;" v-on:change=volumeChange2($event) />
|
|
|
|
|
</template>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div :class="'row ptz '+ device.number" style="box-sizing:border-box; width:320px;height:140px;margin:5px auto;" >
|
|
|
|
|
<table class="ptz" style="width:100%;height:100%;">
|
|
|
|
|
<div style="box-sizing: border-box;width: 320px;height: 140px;margin: 5px auto;" :class="'row ptz '+ device.number">
|
|
|
|
|
<table class="ptz" style="width: 100%; height: 100%;">
|
|
|
|
|
<tr>
|
|
|
|
|
<td colspan="2" style="text-align:center;"><button class="weui-btn weui-btn_mini weui-btn_default" v-on:click="execApi(model.number,'/Onvif/StartRecord')">启动推流</button></td>
|
|
|
|
|
<td><img v-if="ptz" v-on:click="execApi(device.number,'/Camera/Up')" src="/IoTCenter/images/up.png" /></td>
|
|
|
|
|
<td colspan="2" style="text-align:center;"><button class="weui-btn weui-btn_mini weui-btn_default" v-on:click="execApi(model.number,'/Onvif/StopRecord')">停止推流</button></td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td><img v-if="ptz" v-on:click="execApi(device.number,'/Camera/Zoomin')" src="/IoTCenter/images/zoomin.png" /></td>
|
|
|
|
|
<td><img v-if="ptz" v-on:click="execApi(device.number,'/Camera/Left')" src="/IoTCenter/images/left.png" /></td>
|
|
|
|
|
<td><img v-if="ptz" v-on:click="execApi(device.number,'/Camera/Stop')" src="/IoTCenter/images/stop.png" /></td>
|
|
|
|
|
<td><img v-if="ptz" v-on:click="execApi(device.number,'/Camera/Right')" src="/IoTCenter/images/right.png" /></td>
|
|
|
|
|
<td><img v-if="ptz" v-on:click="execApi(device.number,'/Camera/Zoomout')" src="/IoTCenter/images/zoomout.png" /></td>
|
|
|
|
|
<td><img v-if="ptz" v-on:click="execApi(device.number,'/Camera/Zoomin')" src="/IoTCenter/images/zoomin.png" /></td>
|
|
|
|
|
<td><img v-if="ptz" v-on:click="execApi(device.number,'/Camera/Left')" src="/IoTCenter/images/left.png" /></td>
|
|
|
|
|
<td><img v-if="ptz" v-on:click="execApi(device.number,'/Camera/Stop')" src="/IoTCenter/images/stop.png" /></td>
|
|
|
|
|
<td><img v-if="ptz" v-on:click="execApi(device.number,'/Camera/Right')" src="/IoTCenter/images/right.png" /></td>
|
|
|
|
|
<td><img v-if="ptz" v-on:click="execApi(device.number,'/Camera/Zoomout')" src="/IoTCenter/images/zoomout.png" /></td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td colspan="2" style="text-align:center;"><button class="weui-btn weui-btn_mini weui-btn_default" v-on:click="execApi(model.number,'/Onvif/StartPush')">开始录像</button></td>
|
|
|
|
@ -34,62 +50,185 @@
|
|
|
|
|
</template>
|
|
|
|
|
<script>
|
|
|
|
|
({
|
|
|
|
|
props: ['device','edit'],
|
|
|
|
|
props: ['device', 'edit'],
|
|
|
|
|
data() {
|
|
|
|
|
return {
|
|
|
|
|
muted: true,
|
|
|
|
|
volume: 0.5,
|
|
|
|
|
timer: null,
|
|
|
|
|
flvPlayer: null,
|
|
|
|
|
decodedFrames: null,
|
|
|
|
|
wxInlinePlayer: null,
|
|
|
|
|
playing: false
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
mounted: function () {
|
|
|
|
|
if (flvjs.isSupported()) {
|
|
|
|
|
if (this.isFlvSupported) {
|
|
|
|
|
this.playByFlvJs();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
this.playByWXInlinePlayer();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
destroyed: function () {
|
|
|
|
|
this.stopFlvPlayer();
|
|
|
|
|
this.stopWxInlinePlayer();
|
|
|
|
|
},
|
|
|
|
|
methods: {
|
|
|
|
|
playByFlvJs: function () {
|
|
|
|
|
try {
|
|
|
|
|
var videoElement = $('video.'+this.device.number)[0];
|
|
|
|
|
livePlayer = flvjs.createPlayer({
|
|
|
|
|
type: 'flv',
|
|
|
|
|
url: this.url,
|
|
|
|
|
isLive: true,
|
|
|
|
|
cors: true
|
|
|
|
|
}, {
|
|
|
|
|
enableWorker: true,
|
|
|
|
|
enableStashBuffer: false,
|
|
|
|
|
stashInitialSize: 1,
|
|
|
|
|
fixAudioTimestampGap: false
|
|
|
|
|
var videoElement = $('video.' + this.device.number)[0];
|
|
|
|
|
var push = Enumerable.from(this.device.data).where(o => o.name === '推流').firstOrDefault();
|
|
|
|
|
if (push && push.value === '是') {
|
|
|
|
|
try {
|
|
|
|
|
this.stopFlvPlayer();
|
|
|
|
|
this.flvPlayer = flvjs.createPlayer({
|
|
|
|
|
type: 'flv',
|
|
|
|
|
url: this.url,
|
|
|
|
|
isLive: true,
|
|
|
|
|
cors: true
|
|
|
|
|
}, {
|
|
|
|
|
enableWorker: true,
|
|
|
|
|
enableStashBuffer: false,
|
|
|
|
|
stashInitialSize: 1,
|
|
|
|
|
fixAudioTimestampGap: false
|
|
|
|
|
});
|
|
|
|
|
this.flvPlayer.attachMediaElement(videoElement);
|
|
|
|
|
this.flvPlayer.load();
|
|
|
|
|
this.flvPlayer.volume = this.volume;
|
|
|
|
|
this.flvPlayer.muted = this.muted;
|
|
|
|
|
var vm = this;
|
|
|
|
|
this.timer = setInterval(function () {
|
|
|
|
|
console.log('.');
|
|
|
|
|
if (vm.flvPlayer.statisticsInfo.speed === 0) {
|
|
|
|
|
console.log('reload1');
|
|
|
|
|
clearInterval(vm.timer);
|
|
|
|
|
vm.playByFlvJs();
|
|
|
|
|
}
|
|
|
|
|
else if (vm.decodedFrames && vm.flvPlayer.statisticsInfo.decodedFrames <= decodedFrames) {
|
|
|
|
|
console.log('reload2');
|
|
|
|
|
clearInterval(vm.timer);
|
|
|
|
|
vm.playByFlvJs();
|
|
|
|
|
}
|
|
|
|
|
else if (vm.flvPlayer.buffered.length > 0 && vm.flvPlayer.buffered.end(0) - vm.flvPlayer.currentTime > 2) {
|
|
|
|
|
console.log('reset currentTime');
|
|
|
|
|
vm.flvPlayer.currentTime = vm.flvPlayer.buffered.end(0) - 0.001;
|
|
|
|
|
}
|
|
|
|
|
vm.decodedFrames = vm.flvPlayer.statisticsInfo.decodedFrames;
|
|
|
|
|
}, 10 * 1000);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.log('error:');
|
|
|
|
|
console.log(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
stopFlvPlayer: function () {
|
|
|
|
|
if (this.timer) {
|
|
|
|
|
clearInterval(this.timer);
|
|
|
|
|
}
|
|
|
|
|
if (this.flvPlayer) {
|
|
|
|
|
try {
|
|
|
|
|
this.flvPlayer.pause();
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error(e);
|
|
|
|
|
}
|
|
|
|
|
this.flvPlayer.unload();
|
|
|
|
|
this.flvPlayer.detachMediaElement();
|
|
|
|
|
try {
|
|
|
|
|
this.flvPlayer.destroy();
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error(e);
|
|
|
|
|
}
|
|
|
|
|
this.flvPlayer = null;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
stopWxInlinePlayer: function () {
|
|
|
|
|
if (this.wxInlinePlayer) {
|
|
|
|
|
this.wxInlinePlayer.stop();
|
|
|
|
|
this.wxInlinePlayer.destroy();
|
|
|
|
|
this.wxInlinePlayer = null;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
volumeChange: function (e) {
|
|
|
|
|
this.muted = e.target.muted;
|
|
|
|
|
this.volume = e.target.volume;
|
|
|
|
|
},
|
|
|
|
|
playByWXInlinePlayer: function () {
|
|
|
|
|
var videoElement = $('canvas.' + this.device.number)[0];
|
|
|
|
|
var vm = this;
|
|
|
|
|
WXInlinePlayer.ready().then(function () {
|
|
|
|
|
vm.wxInlinePlayer = new WXInlinePlayer({
|
|
|
|
|
url: vm.url,
|
|
|
|
|
$container: videoElement,
|
|
|
|
|
hasVideo: true,
|
|
|
|
|
hasAudio: true,
|
|
|
|
|
volume: 0.5,
|
|
|
|
|
muted: true,
|
|
|
|
|
autoplay: true,
|
|
|
|
|
loop: false,
|
|
|
|
|
isLive: false,
|
|
|
|
|
chunkSize: 128 * 1024,
|
|
|
|
|
preloadTime: 5e2,
|
|
|
|
|
bufferingTime: 1e3,
|
|
|
|
|
cacheSegmentCount: 64,
|
|
|
|
|
customLoader: null
|
|
|
|
|
});
|
|
|
|
|
livePlayer.attachMediaElement(videoElement);
|
|
|
|
|
livePlayer.load();
|
|
|
|
|
livePlayer.volume = volume;
|
|
|
|
|
livePlayer.muted = muted;
|
|
|
|
|
timer = setInterval(function () {
|
|
|
|
|
console.log('.');
|
|
|
|
|
if (livePlayer.statisticsInfo.speed === 0) {
|
|
|
|
|
console.log('reload1');
|
|
|
|
|
clearInterval(timer);
|
|
|
|
|
playFlv(videoElement);
|
|
|
|
|
}
|
|
|
|
|
else if (decodedFrames && livePlayer.statisticsInfo.decodedFrames <= decodedFrames) {
|
|
|
|
|
console.log('reload2');
|
|
|
|
|
clearInterval(timer);
|
|
|
|
|
playFlv(videoElement);
|
|
|
|
|
}
|
|
|
|
|
else if (livePlayer.buffered.length > 0 && livePlayer.buffered.end(0) - livePlayer.currentTime > 1) {
|
|
|
|
|
console.log('reset currentTime');
|
|
|
|
|
livePlayer.currentTime = livePlayer.buffered.end(0) - 0.001;
|
|
|
|
|
videoElement.addEventListener('click', () => {
|
|
|
|
|
vm.wxInlinePlayer.play();
|
|
|
|
|
});
|
|
|
|
|
vm.wxInlinePlayer.on('loadError', e => {
|
|
|
|
|
console.log('>>>>> load error happend: ', e);
|
|
|
|
|
});
|
|
|
|
|
vm.wxInlinePlayer.on('loadSuccess', () => {
|
|
|
|
|
console.log('>>>>> load success');
|
|
|
|
|
});
|
|
|
|
|
vm.wxInlinePlayer.on('playing', () => {
|
|
|
|
|
vm.playing = true;
|
|
|
|
|
});
|
|
|
|
|
vm.wxInlinePlayer.on('stopped', () => {
|
|
|
|
|
vm.playing = false;
|
|
|
|
|
});
|
|
|
|
|
vm.wxInlinePlayer.on('mediaInfo', mediaInfo => {
|
|
|
|
|
const { onMetaData } = mediaInfo;
|
|
|
|
|
videoElement.height = onMetaData.height || 720;
|
|
|
|
|
videoElement.width = onMetaData.width || 1080;
|
|
|
|
|
for (let i = 0; i < onMetaData.length; i++) {
|
|
|
|
|
if ('height' in onMetaData[i]) {
|
|
|
|
|
videoElement.height = onMetaData[i].height;
|
|
|
|
|
} else if ('width' in onMetaData[i]) {
|
|
|
|
|
videoElement.width = onMetaData[i].width;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
decodedFrames = livePlayer.statisticsInfo.decodedFrames;
|
|
|
|
|
}, 10 * 1000);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.log(e);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
play: function () {
|
|
|
|
|
if (this.playing) {
|
|
|
|
|
this.wxInlinePlayer.stop();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
this.wxInlinePlayer.play();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
playByWXInlinePlayer: function () {
|
|
|
|
|
mute: function () {
|
|
|
|
|
this.muted = !this.muted;
|
|
|
|
|
this.wxInlinePlayer.mute(this.muted);
|
|
|
|
|
},
|
|
|
|
|
volumeChange2: function (e) {
|
|
|
|
|
this.volume = e.target.value;
|
|
|
|
|
this.wxInlinePlayer.volume(e.target.value);
|
|
|
|
|
},
|
|
|
|
|
fullScreen: function () {
|
|
|
|
|
var videoElement = $('canvas.' + this.device.number)[0];
|
|
|
|
|
videoElement.requestFullscreen();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
computed: {
|
|
|
|
|
url: function () {
|
|
|
|
|
return getDeviceDataValue(this.device, 'flv');
|
|
|
|
|
return 'http://localhost/music.flv';
|
|
|
|
|
//return getDeviceDataValue(this.device, 'flv');
|
|
|
|
|
},
|
|
|
|
|
isFlvSupported: function () {
|
|
|
|
|
return flvjs.isSupported() && false;
|
|
|
|
|
},
|
|
|
|
|
ptz: function () {
|
|
|
|
|
if (getDeviceDataValue(this.device, '云台地址')) {
|
|
|
|
|