vue项目使用海康视频H5palyer_h5player
上篇文章中分享了vue项目中集成海康视频web插件,但在功能上线后发现存在的一些局限性,如海康视频web插件仅适用于Windows桌面操作系统,并不能在麒麟系统上使用,并且跳转界面后视频插件的界面有时还在,影响用户体验,因此又研究了H5视频播放器的应用,H5player适用于跨平台浏览器,包括window、android、ios、银河麒麟等,并且根据自己需求调用h5player功能,样式调整简单,适用性强。
一、引入h5player@2.0开发包
首先登录海康平台下载H5视频播放器开发包 V2.5.1,其中包含demo、bin、doc,可根据demo中的使用说明进行测试,doc中有开发指南,bin中包含H5视频播放器的第三方库文件。
接着在public文件夹下新建h5player文件夹,并将上面bin下所有文件复制到h5player文件夹下,即:(注意:一定要放在vue中的public文件夹中,否则会报错)
最后public文件夹下的index.html中引入h5player.min.js文件
二、h5player应用
项目需求中存在两个应用视频的场景,第一个场景点击视频icon弹出视频界面,可实现实时预览、回放、抓图、录像、云台操作、全屏功能;第二个场景是多个视频点分页显示,每个视频点可实时预览、回放、抓图、录像、云台操作、全屏。
单个视频点功能
开始 停止播放 开始录像 停止录像 抓图 全屏 云台控制
0 - 速度 0100
回放
开始回放 暂停 恢复 停止回放 import { wsvideostream,hkptzoperate } from \"@/api/api.js\";import moment from \"moment\";export default { props: { dataInfo: { type: Object, default: null, }, hkPlayerDialog: { type: Boolean, }, }, data() { return { direction: 0, centImg: 1, toOUT: false, toIN: false, beforeDire: 0, transmode: 40, //速度 lastAvtion: \"\", //旋转方向 visible: this.hkPlayerDialog, value1: \"\", previewUrl: \"\", playbackUrl: \"\", player: null, isPlaying: false, isRecording: false, command: \'\', title: \'\' }; }, methods: {//获取ws视频流 getwsUrl() { wsvideostream({ cameraIndexCode: this.dataInfo.cameraIndexCode, }).then((res) => { if (200 == res.code) { this.previewUrl = res.data; this.play(); } }); },//初始化播放器 createPlayer(option) { window.addEventListener(\"resize\", () => { setTimeout(() => { this.player.JS_Resize(); }, 100); }); this.player = new window.JSPlugin({ szId: \"player\", szBasePath: \"./h5player/\", iMaxSplit: 1, iCurrentSplit: 2, //2 oStyle: { // border: \'#0bc4db\', // borderSelect: \'#FFCC00\', // background: \'#fff\' }, }); // 事件回调绑定 this.initPlugin(); }, /** * 事件初始化 */ initPlugin() { this.player.JS_SetWindowControlCallback({ windowEventSelect: function (iWndIndex) { //插件选中窗口回调 console.log(\"windowSelect callback: \", iWndIndex); }, pluginErrorHandler: function (iWndIndex, iErrorCode, oError) { //插件错误回调 console.log(\"pluginError callback: \", iWndIndex, iErrorCode, oError); }, 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 (iWndIndex) { //性能不足回调 console.log(\"performanceLack callback: \", iWndIndex); }, StreamEnd: function (iWndIndex) { //性能不足回调 console.log(\"recv StreamEnd: \", iWndIndex); }, StreamHeadChanged: function (iWndIndex) { console.log(\"recv StreamHeadChanged: \", iWndIndex); }, ThumbnailsEvent: (iWndIndex, eventType, eventCode) => { console.log( \"recv ThumbnailsEvent: \" + iWndIndex + \", eventType:\" + eventType + \", eventCode:\" + eventCode ); }, InterruptStream: (iWndIndex, iTime) => { console.log( \"recv InterruptStream: \" + iWndIndex + \", iTime:\" + iTime ); }, ElementChanged: (iWndIndex, szElementType) => { //回调采用的是video还是canvas console.log( \"recv ElementChanged: \" + iWndIndex + \", szElementType:\" + szElementType ); }, }); this.getwsUrl(); }, /** * 开始播放 */ play(data, callback) { this.isPlaying = true; const param = { playURL: this.previewUrl, mode: 1, }; let index = 0; this.player.JS_Play(this.previewUrl, param, index).then( () => { // this.isPlaying = true; console.log(\"播放成功\"); }, (err) => { // this.isPlaying = true; console.log(\"播放失败\", err); console.log(\"play fail\"); } ); }, // 停止播放 stopPlay() { this.isPlaying = false; this.player.JS_Stop().then( () => { console.log(\"stop realplay success\"); }, (e) => { console.error(e); } ); }, //开始回放 async startPlayback() { //首先获取回放ws:url const res = await getVideoList({ factId: this.queryParams.factId }); }, //开始回放 playbackStart() { const config = { playURL: this.playbackUrl, mode: 1, }; let index = 0; let startTime = \"2025-03-21T00:00:00\" + \".000+08:00\"; let endTime = \"2025-03-21T21:00:00\" + \".000+08:00\"; this.player .JS_Play(this.playbackUrl, config, index, startTime, endTime) .then( () => { console.log(\"playbackStart success\"); // this.playback.rate = 1 }, (e) => { console.log(\"playbackStart fail\"); console.log(e); } ); }, //抓图 capture(imageType) { let player = this.player, index = player.currentWindowIndex; player.JS_CapturePicture(index, \"img\", imageType).then( () => { console.log(\"capture success\", imageType); }, (e) => { console.error(e); } ); }, //开始录像 recordStart(type) { const codeMap = { MP4: 5, PS: 2 }; //let options = {irecordType: 1, cbStreamCB: streamcb} let index = this.player.currentWindowIndex; let fileName = this.dataInfo.name + moment().format(\"YYYY-MM-DD HH:mm:ss\") + \".mp4\"; let typeCode = codeMap[type]; this.player.JS_StartSaveEx(index, fileName, typeCode).then( () => { this.isRecording = true; console.log(\"record start ...\"); }, (e) => { console.error(e); } ); }, recordStop() { let index = this.player.currentWindowIndex; this.player.JS_StopSave(index).then( () => { this.isRecording = false; console.log(\"record stoped, saving ...\"); }, (e) => { console.error(e); } ); }, changeCentImg() { if (this.direction || this.beforeDire) { //非0数为真 // 0开始 1暂停 if (this.centImg == 0) { // 开始变暂停 this.centImg = 1; this.beforeDire = this.direction; //暂存,记录的是上一次按钮的方向 this.direction = 0; } else { // 暂停变开始 this.centImg = 0; if (this.beforeDire) { this.direction = this.beforeDire; //暂存,记录的是上一次按钮的方向 } } let dirTemp = null; if (this.direction === 1) { dirTemp = \"up\"; } if (this.direction === 2) { dirTemp = \"left\"; } if (this.direction === 3) { dirTemp = \"right\"; } if (this.direction === 4) { dirTemp = \"down\"; } this.centImgMove(this.centImg, dirTemp); } }, handleClose(done) { if (this.v1 != undefined) { this.v1.disconnect(); } this.hkPlayerDialog = false; this.$emit(\"cancel\", { hkPlayerDialog: this.hkPlayerDialog, }); }, //暂停开始图标的移动行为 centImgMove(tag, beforeDire) { //根据tag判断;如果tag==1表示想要暂停,直接发送暂停命令,如果是tag==0标识想要开始,则把上一次行为记录的方向发送开始命令 if (tag === 1) { //暂停命令 this.move(this.command,1); } if (tag === 0) { //开始命令 console.log(\"beforeDire\", beforeDire); this.move(this.command,0); } }, // 移动 move(command,action) { this.command = command; if (command === \"zoom_in\" || command === \"zoom_out\") { this.centImg = action == 0 ? 0 :1; // 使用赋值操作符来设置属性的值 this.direction = -1; // 使用赋值操作符来设置属性的值 } let params = { action: action, //0 开始 1暂停 cameraIndexCode: this.dataInfo.cameraIndexCode, //h5s平台设备的token,非系统登录的token speed: this.transmode, //旋转速度 command: command }; hkptzoperate(params).then((res) => { if (res.code === 200) { console.log(res.data); } }); // } }, async changeCamera(presetIndex) { }, fullScreen() { this.player.JS_FullScreenDisplay(true).then( () => { console.log(`wholeFullScreen success`); }, (e) => { console.error(e); } ); }, initScale(){ var _that = this; var scale = function (btn,bar,count){ this.btn=document.getElementById(btn); this.bar=document.getElementById(bar); this.count=document.getElementById(count); this.step=document.getElementsByClassName(\"leftWidth\")[0];//leftWidth的div节点元素 console.log(\"this.step\",this.step); this.init(); this.count.innerHTML = 40 this.step.style.width=\'76px\'; this.count.style.left=\'50%\'; this.btn.style.left=76+\'px\' }; scale.prototype={ init:function (){ var f=this,g=document,b=window,m=Math; f.btn.onmousedown=function (e){ var x=(e||b.event).clientX; var l=this.offsetLeft; var max=f.bar.offsetWidth-this.offsetWidth; g.onmousemove=function (e){ var thisX=(e||b.event).clientX; var to=m.min(max,m.max(-2,l+(thisX-x))); f.btn.style.left=to+\'px\'; f.ondrag(m.round(m.max(0,to/max)*100),to); b.getSelection ? b.getSelection().removeAllRanges() : g.selection.empty(); }; g.onmouseup=function(e){ g.onmousemove=null //_that.move(_that.lastAvtion) } }; }, ondrag:function (pos,x){ this.step.style.width=Math.max(0,x)+\'px\'; this.count.innerHTML=pos; //标记 _that.transmode = pos this.count.style.left=Math.max(0,x)+25+\'px\'; } } setTimeout(function(){ //count表示当前速度是多少;bar表示整个横向滚动的滑动条;btn是滑动条的可拖动的点 new scale(\'btn\',\'bar\',\'count\'); },200) } }, watch: { //监听开启关闭状态,并改变相应值 hkPlayerDialog() { this.title = this.dataInfo.name; this.visible = this.hkPlayerDialog; if (this.hkPlayerDialog == true) { this.initScale(); this.$nextTick(() => { this.createPlayer(); }); } else { this.player = null; } }, },};/deep/.el-dialog { height: 740px; background: url(../../../assets/images/dialog.png) no-repeat center; background-size: 100% 100%; margin-left: 20%; // height: 70%;}/deep/.el-dialog__body { padding: 0px 10px 10px 10px;}/deep/.el-dialog__header { padding: 10px 20px; text-align: left;}/deep/ .el-dialog__title { color: #fff;}/* // 右侧视频监测 */.rightVideoWatvh { width: 30%; background: #344f6b; box-sizing: border-box; padding: 5px 6px; > .buttonset { margin-top: 15px; > div { display: flex; padding: 0 10px; justify-content: space-between; > span { text-align: center; font-size: 14px; font-weight: 400; color: #ffffff; width: 104px; height: 40px; background: url(../../../assets/images/video/rect.png) no-repeat center; background-size: 100% 100%; display: flex; align-items: center; justify-content: center; cursor: pointer; > b { font-size: 20px; margin-top: -3px; margin-right: 5px; } } .active { color: #00b3fe; } } } > p { height: 28px; background: #102944; line-height: 28px; font-size: 14px; font-family: Microsoft YaHei; font-weight: bold; color: #ffffff; position: relative; text-indent: 20px; } > p::before { content: \"\"; position: absolute; left: 13px; width: 3px; height: 15px; background: #ffffff; border-radius: 2px; top: 0; bottom: 0; margin: auto; }}.roadvideo { width: 165px; height: 165px; margin: 5px auto 5px; background: url(../../../assets/images/video/road.png) no-repeat; background-size: 100% 100%; > div { height: 55px; display: flex; > div { width: 55px; height: 55px; display: flex; align-items: center; justify-content: center; > img { width: 13px; filter: grayscale(100%) brightness(200%); cursor: pointer; } .active { filter: grayscale(0); } } .bottomImg { > img { transform: rotateX(180deg); } } .leftImg { > img { transform: rotateY(180deg) rotateZ(90deg); } } .centImg > img { margin-left: 5px; } .rightImg, .centImg { > img { transform: rotateY(180deg) rotateZ(-90deg); } } }}.lanren > li > span { color: #fff; margin-right: 10px; font-size: 14px;}.scale_panel > div:last-child { display: flex; justify-content: space-between; color: #fff; margin-top: 5px;}.scale_panel { color: #999; width: 88%; line-height: 18px;}.scale_panel .r { float: right;}.scale span { background: url(../../../assets/images/video/scroll.png) no-repeat; width: 16px; height: 16px; position: absolute; left: -5px; top: -3px; cursor: pointer; background-size: 100% 100%;}.scale { border-radius: 5px; background-repeat: repeat-x; background-position: 0 100%; height: 10px; background: #07070733; width: 85%; position: relative; font-size: 0px; border-radius: 3px;}.scale div { border-top-left-radius: 5px; border-bottom-left-radius: 5px; background-repeat: repeat-x; height: 10px; background: #626060; width: 0px; position: absolute; width: 0; left: 0; bottom: 0;}.lanren li { font-size: 12px; line-height: 50px; position: relative; height: 50px; list-style: none; display: flex; align-items: flex-end;}.lanren { // padding-top: 310px; position: relative; padding-left:10px // padding:10px; // margin: 10px;}#count { background: #454545; border-radius: 6px; padding: 3px 6px; border-radius: 6px; position: absolute; top: -15px; left: 41px; color: #fff;}.el-input__inner { background-color: transparent;}/deep/ .el-range-editor .el-range-input { background-color: transparent;}/deep/ .el-dialog__headerbtn .el-dialog__close{ color: #fff;}/deep/ .sub-wnd{ border-color: #596b87!important;}
三、总结
开发过程中遇到问题,可以先去海康官网下的软件平台咨询,选择“智能问答”,其中包含H5播放问题集,若问题集中无法解决实际遇到的问题,可邮箱咨询。
如果对小伙伴儿有帮助,请点个小赞赞哈