484 lines
12 KiB
Vue
484 lines
12 KiB
Vue
<template>
|
|
<view class="video-detail">
|
|
<!-- <nav-bar :is-back="true" title="视频监控"></nav-bar> -->
|
|
<view class="video-box">
|
|
|
|
<!-- <video id="myVideo" :src="url" autoplay v-if="showVideo" show-mute-btn="true" vslide-gesture="true" :controls="btnToggle"> -->
|
|
<!-- #ifdef APP-PLUS -->
|
|
<video id="myVideo" :src="dataObj.flvUrl" autoplay show-fullscreen-btn v-if="showVideo" :controls="false">
|
|
<cover-view class="btn-toggle" v-if="btnToggle" @click="quitFullScreen">
|
|
退出全屏
|
|
</cover-view>
|
|
<view class="btn-toggle" v-if="btnToggle" @click="quitFullScreen">
|
|
退出全屏
|
|
</view>
|
|
</video>
|
|
<!-- #endif -->
|
|
|
|
<!-- #ifdef MP-WEIXIN -->
|
|
<video id="myVideo" class="video-content" :src="dataObj.m3u8Url" :autoplay="true" :direction="0"
|
|
:muted="true" :controls="true" :is-live="true" object-fit="contain" @binderror="error" :custom-cache="false"
|
|
title="放大后会显示的标题" show-fullscreen-btn>
|
|
</video>
|
|
<!--<video id="myVideo" :src="dataObj.m3u8Url" autoplay show-fullscreen-btn v-if="showVideo" :controls="false">
|
|
<cover-view class="btn-toggle" v-if="btnToggle" @click="quitFullScreen">
|
|
退出全屏
|
|
</cover-view> -->
|
|
<!-- <view class="btn-toggle" v-if="btnToggle" @click="quitFullScreen">
|
|
退出全屏
|
|
</view>
|
|
</video> -->
|
|
<!-- #endif -->
|
|
|
|
<!-- #ifdef MP-WEIXIN
|
|
<live-player id="live-video" :src="dataObj.url" v-if="showVideo" autoplay @statechange="statechange"
|
|
@netstatus="netstatus">
|
|
<cover-view class="btn-toggle" v-if="btnToggle" @click="quitFullScreen">
|
|
退出全屏
|
|
</cover-view>
|
|
</live-player>
|
|
#endif -->
|
|
|
|
</view>
|
|
<view class="video-title">
|
|
{{dataObj.name}}
|
|
</view>
|
|
<view class="channe-name">
|
|
通道名称:{{dataObj.channeName}}
|
|
</view>
|
|
<!-- #ifdef MP-WEIXIN -->
|
|
<view class="slider-box">
|
|
<!-- <view class="title">
|
|
推流状态
|
|
</view> -->
|
|
<view class="net-status">
|
|
<text>速度:{{netStatus.netSpeed==undefined?'':netStatus.netSpeed}}</text>
|
|
<text>网络抖动:{{netStatus.netJitter==undefined?'':netStatus.netJitter}}</text>
|
|
<text>视频帧率:{{netStatus.videoFPS==undefined?'':netStatus.videoFPS}}</text>
|
|
<text>状态码:{{videoStatus}}</text>
|
|
</view>
|
|
</view>
|
|
<!-- #endif -->
|
|
|
|
<!-- <view class="slider-box">
|
|
<view class="title">
|
|
速度
|
|
</view>
|
|
<slider v-model="speed" step="10" @change="sliderChange" max="200" show-value />
|
|
</view> -->
|
|
|
|
<view class="title">
|
|
云台控制
|
|
</view>
|
|
<view class="btn-box">
|
|
<view class="btn">
|
|
<view class="btn-top-bottom" @touchstart="PTZcontrol(ptzType.up)"
|
|
@touchcancel="PTZcontrol(ptzType.stop)" @touchend="PTZcontrol(ptzType.stop)">
|
|
<view class="iconfont icon-fangxiang-shang"></view>
|
|
</view>
|
|
<view class="btn-center">
|
|
<view class="btn-left-right" @touchstart="PTZcontrol(ptzType.left)"
|
|
@touchcancel="PTZcontrol(ptzType.stop)" @touchend="PTZcontrol(ptzType.stop)">
|
|
<view class="iconfont icon-fangxiang-zuo"></view>
|
|
</view>
|
|
<view class="btn-center-center">
|
|
<!-- <view class="iconfont iconluyin" @touchstart="startRecording()" @touchcancel="endRecording()" @touchend="endRecording()"></view> -->
|
|
</view>
|
|
<view class="btn-left-right" @touchstart="PTZcontrol(ptzType.right)"
|
|
@touchcancel="PTZcontrol(ptzType.stop)" @touchend="PTZcontrol(ptzType.stop)">
|
|
<view class="iconfont icon-fangxiang-you"></view>
|
|
</view>
|
|
</view>
|
|
<view class="btn-top-bottom" @touchstart="PTZcontrol(ptzType.down)"
|
|
@touchcancel="PTZcontrol(ptzType.stop)" @touchend="PTZcontrol(ptzType.stop)">
|
|
<view class="iconfont icon-fangxiang-xia"></view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view class="display-box">
|
|
<view class="title">
|
|
显示
|
|
</view>
|
|
<button class="zoom-btn" type="default" @click="fullScreen()">全屏</button>
|
|
</view>
|
|
<u-toast ref="uToast" />
|
|
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import {
|
|
getPTZCmd,
|
|
PTZ_TYPE
|
|
} from '@/static/common/js/video/ptz-cmd.js'
|
|
export default {
|
|
data() {
|
|
return {
|
|
title: '',
|
|
url: '',
|
|
speed: 100,
|
|
btnToggle: false,
|
|
dataObj: {
|
|
flvUrl: '',
|
|
m3u8Url: '',
|
|
id:'',
|
|
name: '',
|
|
channeId:'',
|
|
channeName:'',
|
|
},
|
|
refreshdata: 11,
|
|
showVideo: true,
|
|
// 时间
|
|
// 录音地址
|
|
videoStatus: '',
|
|
netStatus: {
|
|
netSpeed: '',
|
|
netJitter: '',
|
|
videoFPS: '',
|
|
},
|
|
videoObj: {
|
|
url: '',
|
|
id: '',
|
|
channel: '',
|
|
},
|
|
// 平台控制头
|
|
ptzTypeUrl:'',
|
|
ptzType: {}
|
|
};
|
|
},
|
|
onLoad(option) {
|
|
console.log("option",option)
|
|
this.ptzType = PTZ_TYPE;
|
|
console.log("PTZ_TYPE", PTZ_TYPE)
|
|
console.log("option: ", option);
|
|
let deviceObj = JSON.parse(decodeURIComponent(option.deviceObj));
|
|
let channeObj = JSON.parse(decodeURIComponent(option.channeObj));
|
|
this.videoObj.url = channeObj.hlsUrl;
|
|
this.dataObj.flvUrl = channeObj.hdlUrl;
|
|
this.dataObj.m3u8Url = channeObj.hlsUrl;
|
|
this.dataObj.id = channeObj.devId;
|
|
this.dataObj.name = deviceObj.name;
|
|
this.dataObj.channeId = channeObj.channelId;
|
|
this.dataObj.channeName = channeObj.name;
|
|
this.ptzTypeUrl = channeObj.baseUrl;
|
|
// if (obj.siteM7sHost && obj.siteM7sPort && obj.devId && obj.devChannel) {
|
|
// if (obj.https) {
|
|
// this.videoObj = {
|
|
// url: 'https://' + obj.siteM7sHost + ':' + obj.siteM7sPort,
|
|
// id: obj.devId,
|
|
// channel: obj.devChannel,
|
|
// }
|
|
// this.pullVideoList('https://' + obj.siteM7sHost + ':' + obj.siteM7sPort, obj.devId, obj.devChannel)
|
|
// this.dataObj.url = 'https://' + obj.siteM7sHost + ':' + obj.siteM7sPort + '/hdl/' + obj.devId + '/' +
|
|
// obj.devChannel + '.flv'
|
|
// } else {
|
|
// this.videoObj = {
|
|
// url: 'http://' + obj.siteM7sHost + ':' + obj.siteM7sPort,
|
|
// id: obj.devId,
|
|
// channel: obj.devChannel,
|
|
// }
|
|
// this.pullVideoList('http://' + obj.siteM7sHost + ':' + obj.siteM7sPort, obj.devId, obj.devChannel)
|
|
// this.dataObj.url = 'http://' + obj.siteM7sHost + ':' + obj.siteM7sPort + '/hdl/' + obj.devId + '/' +
|
|
// obj.devChannel + '.flv'
|
|
// }
|
|
// } else {
|
|
// this.$u.toast('摄像头参数错误!');
|
|
// }
|
|
|
|
console.log("当前flv地址:" + this.videoObj.url)
|
|
// 为了防止苹果手机静音无法播放
|
|
// uni.setInnerAudioOption({
|
|
// obeyMuteSwitch: false
|
|
// })
|
|
|
|
},
|
|
watch: {
|
|
refreshdata() {
|
|
this.$nextTick(() => {
|
|
this.showVideo = true
|
|
})
|
|
}
|
|
},
|
|
methods: {
|
|
statechange(e) {
|
|
// console.log('live-player code:', e)
|
|
this.videoStatus = e.detail.code;
|
|
if (e.detail.code == -2301) {
|
|
this.$u.toast('网络断连,且经多次重连抢救无效,更多重试请自行重启播放')
|
|
}
|
|
},
|
|
netstatus(e) {
|
|
// console.log('live-player netstatus:', e)
|
|
this.netStatus = e.detail.info;
|
|
},
|
|
pullVideoList(url, id, channel) {
|
|
// console.log("开启推流",url,id,channel)
|
|
let params = {
|
|
id: id,
|
|
channel: channel,
|
|
// startTime:1657165870,
|
|
// endTime:1657770669,
|
|
}
|
|
let DefaultOpts = {
|
|
url: url + '/api/gb28181/invite',
|
|
data: params,
|
|
method: "GET",
|
|
}
|
|
uni.request(DefaultOpts).then(
|
|
(res) => {
|
|
console.log("pullVideoList", res);
|
|
}
|
|
).catch(
|
|
(response) => {
|
|
console.log("pullVideoList错误", res);
|
|
}
|
|
)
|
|
},
|
|
// 进入全屏
|
|
fullScreen() {
|
|
|
|
// #ifdef APP-PLUS
|
|
// const subNvue=uni.getSubNVueById('popup'); //获取
|
|
// subNvue.show() // 显示
|
|
this.videoContext = uni.createVideoContext('myVideo');
|
|
// 进入全屏状态
|
|
this.videoContext.requestFullScreen();
|
|
this.btnToggle = true;
|
|
// #endif
|
|
|
|
// #ifdef MP-WEIXIN
|
|
this.videoContext = uni.createLivePlayerContext('live-video');
|
|
this.videoContext.requestFullScreen({
|
|
direction: 90
|
|
});
|
|
this.btnToggle = true;
|
|
// #endif
|
|
},
|
|
// 退出全屏
|
|
quitFullScreen() {
|
|
// #ifdef APP-PLUS
|
|
this.videoContext = uni.createVideoContext('myVideo');
|
|
// 进入全屏状态
|
|
this.videoContext.exitFullScreen();
|
|
this.btnToggle = false;
|
|
// const subNvue=uni.getSubNVueById('popup');
|
|
// subNvue.hide() //隐藏
|
|
// #endif
|
|
// #ifdef MP-WEIXIN
|
|
this.videoContext = uni.createLivePlayerContext('live-video');
|
|
this.videoContext.exitFullScreen();
|
|
this.btnToggle = false;
|
|
// #endif
|
|
},
|
|
// 滑动速度滚动条
|
|
sliderChange(e) {
|
|
console.log(e);
|
|
this.speed = e.detail.value;
|
|
},
|
|
// 云台控制
|
|
PTZcontrol(type) {
|
|
console.log("type", type);
|
|
let ptzcmd = getPTZCmd({
|
|
type: type
|
|
});
|
|
console.log("ptzcmd", ptzcmd)
|
|
this.btnToast(type);
|
|
let params = {
|
|
id: this.dataObj.id,
|
|
channel: this.dataObj.channeId,
|
|
ptzcmd: ptzcmd
|
|
}
|
|
let DefaultOpts = {
|
|
url: this.ptzTypeUrl + '/gb28181/api/control',
|
|
data: params,
|
|
method: "GET",
|
|
}
|
|
uni.request(DefaultOpts).then(
|
|
(res) => {
|
|
console.log("PTZcontrol", res);
|
|
}
|
|
).catch(
|
|
(response) => {
|
|
console.log("PTZcontrol错误", res);
|
|
}
|
|
)
|
|
},
|
|
error(e){
|
|
console.log("播放错误",error)
|
|
},
|
|
btnToast(type) {
|
|
if (type == this.ptzType.up) {
|
|
this.$refs.uToast.show({
|
|
title: '向上移动!',
|
|
type: 'success',
|
|
})
|
|
} else if (type == this.ptzType.left) {
|
|
this.$refs.uToast.show({
|
|
title: '向左移动!',
|
|
type: 'success',
|
|
})
|
|
} else if (type == this.ptzType.right) {
|
|
this.$refs.uToast.show({
|
|
title: '向右移动!',
|
|
type: 'success',
|
|
})
|
|
} else if (type == this.ptzType.down) {
|
|
this.$refs.uToast.show({
|
|
title: '向下移动!',
|
|
type: 'success',
|
|
})
|
|
} else if (type == this.ptzType.stop) {
|
|
this.$refs.uToast.show({
|
|
title: '停止移动!',
|
|
type: 'error',
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="less" scoped>
|
|
.video-detail {
|
|
background-color: #fff;
|
|
height: 100%;
|
|
height: 100%;
|
|
|
|
.video-box {
|
|
width: 750rpx;
|
|
height: 422rpx;
|
|
|
|
video,
|
|
live-player {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.btn-toggle {
|
|
position: fixed;
|
|
top: 60rpx;
|
|
right: 80rpx;
|
|
z-index: 9999;
|
|
padding: 10rpx;
|
|
background: rgba(0, 0, 0, 0.5);
|
|
color: #fff;
|
|
font-size: 28rpx;
|
|
line-height: 36rpx;
|
|
}
|
|
}
|
|
|
|
.video-title {
|
|
font-weight: bold;
|
|
font-size: 36rpx;
|
|
line-height: 100rpx;
|
|
text-indent: 30rpx;
|
|
}
|
|
|
|
.channe-name{
|
|
font-size: 28rpx;
|
|
line-height: 60rpx;
|
|
margin: 0 30rpx 0 20rpx;
|
|
}
|
|
|
|
.title {
|
|
font-size: 26rpx;
|
|
font-weight: bold;
|
|
margin: 0 30rpx 0 20rpx;
|
|
}
|
|
|
|
.btn-box {
|
|
display: flex;
|
|
justify-content: center;
|
|
margin: 30rpx;
|
|
|
|
.btn {
|
|
width: 336rpx;
|
|
height: 336rpx;
|
|
border-radius: 50%;
|
|
background-color: #f2f3f7;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
color: #7d90ab;
|
|
font-size: 56rpx;
|
|
overflow: hidden;
|
|
|
|
.btn-top-bottom {
|
|
width: 141rpx;
|
|
height: 98rpx;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
.btn-center {
|
|
display: flex;
|
|
align-items: center;
|
|
|
|
.btn-left-right {
|
|
width: 98rpx;
|
|
height: 141rpx;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
.btn-center-center {
|
|
width: 141rpx;
|
|
height: 141rpx;
|
|
background-color: #dde1ea;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
}
|
|
|
|
.btn-top-bottom:active,
|
|
.btn-left-right:active {
|
|
background-color: #dde1ea;
|
|
color: #7d90ab;
|
|
}
|
|
|
|
.btn-center-center:active {
|
|
background-color: #7d90ab;
|
|
color: #dde1ea;
|
|
}
|
|
}
|
|
}
|
|
|
|
.slider-box {
|
|
display: flex;
|
|
align-items: center;
|
|
margin: 30rpx;
|
|
|
|
slider {
|
|
width: 536rpx;
|
|
}
|
|
}
|
|
|
|
.zoom-box,
|
|
.display-box {
|
|
margin: 30rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
|
|
.zoom-btn {
|
|
margin: 0;
|
|
line-height: 2;
|
|
border-color: #8293ab;
|
|
color: #8293ab;
|
|
}
|
|
}
|
|
}
|
|
/deep/.u-position-center{
|
|
top: calc(var(--status-bar-height) + 470rpx + 45px) !important;
|
|
}
|
|
.net-status {
|
|
text {
|
|
margin-right: 10rpx;
|
|
display: block;
|
|
}
|
|
}
|
|
</style>
|