You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

279 lines
12 KiB

<template>
<div class="card device-component camera" style="margin">
<div class="card-header">
<h3 class="card-title">
{{device.displayName}}
<i v-if="device.isOnline" class="text-success ion ion-ios-wifi"></i>
<i v-else class="text-danger ion ion-ios-wifi"></i>
</h3>
<div class="card-tools">
<span @click="visible = true" title="操作"><i class="ion ion-md-settings"></i></span>
</div>
</div>
<div class="card-body" style="padding:0;background-color:#000;">
<div class="row video-container" style="height:100%;width:100%;position:relative;">
<video poster="images/camera.svg" controls muted autoplay :class="device.number" @volumechange="volumeChange($event)" style="width:100%;height:100%;object-fit:contain;border:none;background-color:#000;"></video>
</div>
</div>
<a-modal v-model="visible" :title="device.displayName" :footer="null">
<div class="row">
</div>
<table style="width: 100%; height:100px; text-align: center;">
<tr>
<td colspan="2" style="text-align:center;">
<button v-if="getIoTDataValue(this.device, '推流')==='否'" class="btn btn-default px-2 btn-sm" @click="execApi(device.number,'/Onvif/StartPush')">开始推流</button>
<button v-else class="btn btn-default px-2 btn-sm" @click="execApi(device.number,'/Onvif/StopPush')">停止推流</button>
</td>
<td></td>
<td colspan="2" style="text-align:center;">
<button v-if="getIoTDataValue(this.device, '录像')==='否'" class="btn btn-default px-2 btn-sm" @click="execApi(device.number,'/Onvif/StartRecord')">开始录像</button>
<button v-else class="btn btn-default px-2 btn-sm" @click="execApi(device.number,'/Onvif/StopRecord')">停止录像</button>
</td>
</tr>
<template v-if="ptz">
<tr>
<td></td>
<td></td>
<td><img @click="execApi(device.number,'/Onvif/Up')" src="images/up.svg" style="width:32px;" /></td>
<td></td>
<td></td>
</tr>
<tr>
<td><img @click="execApi(device.number,'/Onvif/Zoomin')" src="images/zoomin.svg" class="pointer" /></td>
<td><img @click="execApi(device.number,'/Onvif/Left')" src="images/left.svg" class="pointer" /></td>
<td><img @click="execApi(device.number,'/Onvif/Stop')" src="images/stop.svg" class="pointer" /></td>
<td><img @click="execApi(device.number,'/Onvif/Right')" src="images/right.svg" class="pointer" /></td>
<td><img @click="execApi(device.number,'/Onvif/Zoomout')" src="images/zoomout.svg" class="pointer" /></td>
</tr>
<tr>
<td></td>
<td></td>
<td><img @click="execApi(device.number,'/Onvif/Down')" src="images/down.svg" style="width:32px;" /></td>
<td></td>
<td></td>
</tr>
</template>
</table>
</a-modal>
</div>
</template>
<script>
export default {
props: ['device', 'edit'],
data() {
return {
visible: false,
muted: true,
volume: 0.5,
timer: null,
flvPlayer: null,
decodedFrames: null,
wxInlinePlayer: null,
playing: false
};
},
mounted: function () {
if (this.isFlvSupported) {
this.playByFlvJs();
}
else {
this.playHls();
}
},
destroyed: function () {
this.stopFlvPlayer();
this.stopWxInlinePlayer();
},
methods: {
play: function () {
if (this.playing) {
this.wxInlinePlayer.stop();
}
else {
this.wxInlinePlayer.play();
}
},
playHls: function () {
$('video.' + this.device.number).attr('src', this.url);
},
playByFlvJs: function () {
//if (getIoTDataValue(this.device, '推流') === '否') {
// return;
//}
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 <= vm.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;
}, 30 * 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;
}
},
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: true,
chunkSize: 128 * 1024,
preloadTime: 5e2,
bufferingTime: 1e3,
cacheSegmentCount: 64,
customLoader: null
});
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;
}
}
});
});
},
stopWxInlinePlayer: function () {
if (this.wxInlinePlayer) {
this.wxInlinePlayer.stop();
this.wxInlinePlayer.destroy();
this.wxInlinePlayer = null;
}
},
showControls: function (e) {
$('.control.' + this.device.number).toggle();
},
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];
var container = $(videoElement).parents('.video-container')[0];
if (document.fullscreen || document.webkitFullscreenElement) {
if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
}
else {
document.exitFullscreen();
}
}
else {
if (container.webkitRequestFullScreen) {
container.webkitRequestFullScreen();
}
else {
container.requestFullscreen();
}
}
}
},
computed: {
url: function () {
if (this.isFlvSupported) {
return location.protocol + '//' + location.hostname + '/live/' + this.device.number + '.flv';
}
else {
return location.protocol + '//' + location.hostname + '/live/' + this.device.number + '.m3u8';
}
//return getDeviceDataValue(this.device, 'flv');
},
isFlvSupported: function () {
return flvjs.isSupported() && window.navigator.userAgent.indexOf('iPhone') === -1;//AppleWebKit
},
ptz: function () {
if (getIoTDataValue(this.device, '云台地址')) {
return true;
}
return false;
}
}
};</script>