580 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="comp-container">
<slot></slot>
<view id="hk-video" class="hk-video">
</view>
<!-- 顶部显示监控点名称 -->
<view class="name-view" :class="{show:showOptBar}">
{{curCameraName}}
</view>
<!-- 底部操作 -->
<view class="control-view" :class="{show:showOptBar}">
<view class="left">
<!-- 停止播放 -->
<image class="icon stop-icon" :src="stopIcon" mode="widthFix" @click="handleStop"></image>
</view>
<view class="right">
<!-- 声音 -->
<image class="icon sound-icon" :src="hasSound ? soundIcon:muteIcon" mode="widthFix"
@click="handleSound"></image>
<!-- 全屏 -->
<image class="icon full-icon" :src="fullScreenIcon" mode="widthFix" @click="singleFullScreen"></image>
</view>
</view>
</view>
</template>
<script>
// const IS_MOVE_DEVICE = document.body.clientWidth < 992 // 是否移动设备
import stopIcon from './images/stop.png'
import fullScreenIcon from './images/full_screen.png'
import soundIcon from './images/sound.png'
import muteIcon from './images/mute.png'
export default {
props: {
//默认分屏2:2x2布局
currentSplit: {
type: Number,
default: 1
},
//最大分屏4:4x4布局
maxSplit: {
type: Number,
default: 4
},
jsBasePath: {
type: String,
default: '/static/lib'
},
//当前处于预览状态的窗口信息,包含窗口号,监控点编码
previewWindList: {
type: Array,
default: () => []
}
},
data() {
return {
stopIcon,
fullScreenIcon,
soundIcon,
muteIcon,
player: null,
curWindIndex: 0, //当前窗口索引1开始
curPlayWinds: [], //当前正在播放的窗口
showOptBar: false, //是否显示操作栏
interval: null,
isChangeLayout: false,
curCameraName: '', //当前窗口设备名称
hasSound: false, //是否有声音
}
},
watch: {
},
computed: {
},
mounted() {
this.init()
this.onWindowEvent()
},
methods: {
init() {
//实例化
this.player = new window.JSPlugin({
szId: 'hk-video',
szBasePath: this.jsBasePath,
iMaxSplit: this.maxSplit || 4,
iCurrentSplit: this.currentSplit || 1,
openDebug: true,
oStyle: {
borderSelect: '#FFCC00',
background: '#4C4C4C'
}
})
// 事件回调绑定
this.player.JS_SetWindowControlCallback({
windowEventSelect: iWndIndex => { //插件选中窗口回调
if (this.curWindIndex == iWndIndex && this.curPlayWinds.find(item => item
.windowIndex === iWndIndex) && !this.interval && !this
.isChangeLayout) { //第二次点击窗口号,且当前窗口处于播放状态显示操作栏
this.showOptBar = true
this.curCameraName = this.getCurCameraName()
this.interval = setTimeout(() => {
this.showOptBar = false
this.interval = null
}, 5000)
} else if (this.curWindIndex != iWndIndex) {
this.curWindIndex = iWndIndex
this.$emit('windowChange', this.curWindIndex)
}
},
pluginErrorHandler: (iWndIndex, iErrorCode, oError) => { //插件错误回调
console.log('pluginError callback: ', iWndIndex, iErrorCode, oError);
this.$emit('pluginError', iErrorCode)
},
windowEventOver: function(iWndIndex) { //鼠标移过回调
//console.log(iWndIndex);
},
windowEventOut: function(iWndIndex) { //鼠标移出回调
//console.log(iWndIndex);
},
windowEventUp: function(iWndIndex) { //鼠标mouseup事件回调
//console.log(iWndIndex);
},
windowFullCcreenChange: function(bFull) { //全屏切换回调
console.log('fullScreen callback: ', bFull);
},
firstFrameDisplay: function(iWndIndex, iWidth, iHeight) { //首帧显示回调
console.log('firstFrame loaded callback: ', iWndIndex, iWidth, iHeight);
},
performanceLack: function() { //性能不足回调
console.log('performanceLack callback: ');
}
});
},
//窗口事件处理
onWindowEvent() {
// 设置播放容器的宽高并监听窗口大小变化
window.addEventListener('resize', () => {
this.player.JS_Resize()
})
},
getCurCameraName() {
let target = this.curPlayWinds.find(item => item.windowIndex === this.curWindIndex)
if (target) return target.name
return ''
},
/** 预览
* @param url:流媒体url
* @param windowIndex:窗口号
* @param config:播放配置
* @param cameraName:设备(监控点)名称
*/
startPreview(url, cameraName = '', windowIndex = this.curWindIndex, config = {}) {
return new Promise((resolve, reject) => {
this.player.JS_Play(url, {
playURL: url,
mode: 1, //解码类型0=普通模式; 1=高级模式 默认为0,h5高级模式才能播放
...config
}, windowIndex).then(() => {
//console.log('play success')
//保存当前播放的窗口号
if (!this.curPlayWinds.find(v => v.windowIndex === windowIndex)) {
this.curPlayWinds.push({
windowIndex,
name: cameraName
})
this.$emit('previewChange', this.curPlayWinds)
}
resolve()
}).catch(e => {
console.log(e)
reject(e)
})
})
},
//停止某个窗口播放
stopOnePlay(windowIndex = this.curWindIndex) {
return new Promise((resolve, reject) => {
this.player.JS_Stop(windowIndex).then(() => {
this.curPlayWinds = this.curPlayWinds.filter(item => item.windowIndex !==
windowIndex)
this.showOptBar = false;
this.interval = null
this.$emit('previewChange', this.curPlayWinds)
resolve()
}).catch(e => {
console.log(e)
reject(e)
})
})
},
//停止所有窗口播放
stopAllPlay() {
return new Promise((resolve, reject) => {
this.player.JS_StopRealPlayAll().then(() => {
this.curPlayWinds = []
this.showOptBar = false;
this.interval = null
this.$emit('previewChange', this.curPlayWinds)
resolve()
}).catch(e => {
console.log(e)
reject(e)
})
})
},
//开启声音
openSound(windowIndex = this.curWindIndex) {
return new Promise((resolve, reject) => {
this.player.JS_OpenSound(windowIndex).then(() => {
// console.log('open success')
resolve()
}).catch(e => {
console.log(e)
reject(e)
})
})
},
//关闭声音
closeSound(windowIndex = this.curWindIndex) {
return new Promise((resolve, reject) => {
this.player.JS_CloseSound(windowIndex).then(() => {
//console.log('close succes')
resolve()
}).catch(e => {
console.log(e)
reject(e)
})
})
},
/** 设置音量
* @param volumn:音量大小范围1~100默认50
* @param windowIndex:窗口号,默认当前窗口
*/
setVolume(volumn = 50, windowIndex = this.curWindIndex) {
return new Promise((resolve, reject) => {
this.player.JS_SetVolume(volumn, windowIndex).then(() => {
//console.log('setVolume succes')
resolve()
}).catch(e => {
console.log(e)
reject(e)
})
})
},
/** 录像回放
* @param url:流媒体url
* @param windowIndex:窗口号
* @param config:播放配置
* @param startTime :回放开始时间格式类型2021-06-29T00:00:00Z
* @param endTime:回放结束时间格式类型2021-06-29T00:00:00Z
*/
startPlayBack(url, startTime, endTime, windowIndex = this.curWindIndex, config = {}) {
return new Promise((resolve, reject) => {
this.player.JS_Play(url, {
playURL: url,
mode: 1, //解码类型0=普通模式; 1=高级模式 默认为0,h5高级模式才能播放
...config
}, windowIndex, startTime, endTime).then(() => {
//console.log('play success')
resolve()
}).catch(e => {
console.log(e)
reject(e)
})
})
},
//暂停回放
pausePlayBack(windowIndex = this.curWindIndex) {
return new Promise((resolve, reject) => {
this.player.JS_Pause().then(() => {
//console.log('pause success')
resolve()
}).catch(e => {
console.log(e)
reject(e)
})
})
},
//恢复播放
resumePlayBack(windowIndex = this.curWindIndex) {
return new Promise((resolve, reject) => {
this.player.JS_Resume(windowIndex).then(() => {
//console.log('resume success')
resolve()
}).catch(e => {
console.log(e)
reject(e)
})
})
},
//回放快放
fastPlayBack(windowIndex = this.curWindIndex) {
return new Promise((resolve, reject) => {
this.player.JS_Fast(windowIndex).then(() => {
//console.log('fast success')
resolve()
}).catch(e => {
console.log(e)
reject(e)
})
})
},
//慢放
slowPlayBack(windowIndex = this.curWindIndex) {
return new Promise((resolve, reject) => {
this.player.JS_Slow(windowIndex).then(() => {
//console.log('slow success')
resolve()
}).catch(e => {
console.log(e)
reject(e)
})
})
},
/** 录像
* @param fileName:文件名,可不带后缀,默认为.mp4
* @param idstType:录像文件类型,2-ps 5-mp4
* @param windowIndex:窗口号
*/
startSave(fileName, idstType = 5, windowIndex = this.curWindIndex) {
return new Promise((resolve, reject) => {
if (!fileName) {
fileName = new Date().getTime() + '_videotape'
}
this.player.JS_StartSaveEx(windowIndex, fileName, idstType).then(() => {
resolve(windowIndex)
}).catch(e => {
reject(e)
})
})
},
//停止录像并保存
stopSave(windowIndex = this.curWindIndex) {
return new Promise((resolve, reject) => {
this.player.JS_StopSave(windowIndex).then(() => {
resolve()
}).catch(e => {
console.log(e)
reject(e)
})
})
},
/** 抓图
* @param fileName:图片名
* @param fileType:图片类型,'JPEG','BMP'
* @param windowIndex:窗口号
*/
capture(fileName, fileType = 'JPEG', windowIndex = this.curWindIndex, callback = () => {}) {
return new Promise((resolve, reject) => {
if (!fileName) {
fileName = new Date().getTime() + "_snap"
}
this.player.JS_CapturePicture(windowIndex, fileName, fileType, res => {
if (res) {
//base64
this.saveImg(res, fileName)
resolve()
}
}).catch(e => {
reject(e)
})
})
},
//开始对讲szTalkUrl:对讲URL,需要https域名下才支持
startTalk(szTalkUrl) {
return new Promise((resolve, reject) => {
this.player.JS_StartTalk(szTalkUrl).then(() => {
resolve()
}, e => {
reject(e)
})
})
},
//停止对讲
stopTalk() {
return new Promise((resolve, reject) => {
this.player.JS_StopTalk().then(() => {
//console.log('stopTalk success')
resolve()
}).catch(e => {
console.log(e)
reject(e)
})
})
},
//设置对讲音量(0-100)
setTalkVolume(nVolume) {
return new Promise((resolve, reject) => {
this.player.JS_TalkSetVolume(nVolume).then(() => {
//console.log('setTalkVolume success')
resolve()
}).catch(e => {
console.log(e)
reject(e)
})
})
},
//分屏
setLayout(splitNum) {
this.isChangeLayout = true;
this.player.JS_ArrangeWindow(splitNum).then(() => {}).catch(e => {
console.log(e)
}).finally(() => {
setTimeout(() => {
this.isChangeLayout = false
}, 200)
})
},
//是否全屏
isFullScreen(is = true) {
this.player.JS_FullScreenDisplay(is).then(() => {
//console.log('fullscreen success')
}).catch(e => {
console.log(e)
reject(e)
})
},
//单窗口全屏
singleFullScreen(windowIndex = this.curWindIndex) {
this.player.JS_FullScreenSingle(windowIndex).then(() => {
//console.log('singlefullscreen success')
}).catch(e => {
console.log(e)
reject(e)
})
},
//设置窗口大小
setWindResize(width, height) {
return new Promise((resolve, reject) => {
this.player.JS_Resize(width, height).then(() => {
//console.log('resize success')
resolve()
}).catch(e => {
console.log(e)
reject(e)
})
})
},
//获取音视频信息
getVideoInfo(windowIndex = this.curWindIndex) {
return new Promise((resolve, reject) => {
this.player.JS_GetVideoInfo(windowIndex).then((e) => {
//console.log('videoinfo success')
resolve(e)
}).catch(e => {
console.log(e)
reject(e)
})
})
},
//操作栏上停止按钮点击停止播放
handleStop() {
this.stopOnePlay()
},
//保存抓图图片
saveImg(bold, fileName) {
let aLink = document.createElement('a')
let blob = this.base64ToBlob(bold)
let evt = document.createEvent('HTMLEvents')
evt.initEvent('click', true, true) //
aLink.download = fileName
aLink.href = URL.createObjectURL(blob)
aLink.click()
},
// base64转blob
base64ToBlob(code) {
let parts = code.split(';base64,')
let contentType = parts[0].split(':')[1]
let raw = window.atob(parts[1]) // 解码base64得到二进制字符串
let rawLength = raw.length
let uInt8Array = new Uint8Array(rawLength) // 创建8位无符号整数值的类型化数组
for (let i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i) // 数组接收二进制字符串
}
return new Blob([uInt8Array], {
type: contentType
})
},
//声音处理
handleSound() {
if (this.hasSound) { //静音
this.closeSound()
} else {
this.openSound()
}
this.hasSound = !this.hasSound
}
}
}
</script>
<style scoped lang="scss">
.comp-container {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
}
/*
*组件大小由父元素决定
*/
.hk-video {
width: 100%;
height: 100%;
position: relative;
}
.control-view {
position: absolute;
z-index: 998;
width: 100%;
height: 70rpx;
bottom: 0;
background-color: #000;
color: #fff;
display: flex;
align-items: center;
justify-content: space-between;
padding-right: 30rpx;
box-sizing: border-box;
transition: 0.3s all;
transform: translateY(100%);
.right {
display: flex;
align-items: center;
}
.icon {
margin-left: 30rpx;
width: 34rpx;
height: auto;
&.sound-icon {
width: 40rpx;
}
}
&.show {
transform: translateY(0);
}
}
.name-view {
position: absolute;
z-index: 998;
width: 100%;
height: 40rpx;
top: 0;
background-color: #000;
padding-left: 30rpx;
box-sizing: border-box;
transition: 0.3s all;
transform: translateY(-100%);
font-size: 24rpx;
line-height: 40rpx;
color: #fff;
text-align: left;
&.show {
transform: translateY(0);
}
}
</style>