前端使用二开Thingsboard一、二、三事(七)-集成海康威视h5player(下)
angular集成海康威视H5player拓展
本章接着上一章介绍一些海康H5player拓展开发内容,上面两章基本把预览需要用到的功能都说完了,对于回放模式H5player中调用的api与预览是一样,区别在于接口取流不同,回放接口==/api/video/v2/cameras/playbackURLs==,之后在传入参数时必须要有开始和结束时间,然后根据项目需求添加一些回放模式下的各种功能按钮
接口地址链接: 获取监控点回放取流URLv2
1.H5回放-大致效果图
回放模式大概需要四个参数,监控点编号、开始时间、结束时间(开始结束时间,格式类型:2021-06-29T00:00:00Z)、播放索引,因为是回放所以我设置默认只有一个窗口(索引为0),用户需要先在下拉框中选择设备,时间默认当天时间,然后点击回放就可以进行视频回放了,放回模式下把分页和分屏都去掉了因为没啥实际意义看个人项目需求了,这样回放用户体验感可能并不太好,所以添加了一些回放功能按钮,都是比较简单功能
2.回放功能展示
都是一些简单的调用api的过程,没啥好讲的,直接上代码
// html
<div class="h5backPlay" style="margin-left: 20px;margin-right: 20px;" *ngIf="!live&&!flagCompany">
<button (click)="suPlay()" style="font-size: 15px;font-weight: bold;margin-left:5px;" class="btn short">暂停</button>
<button (click)="rePlay()" style="font-size: 15px;font-weight: bold;margin-left:5px;" class="btn short">恢复</button>
<button (click)="stopPlay()" style="font-size: 15px;font-weight: bold;margin-left:5px;"
class="btn short">停止回放</button>
<button (click)="slowPlay()" style="font-size: 15px;font-weight: bold;margin-left:5px;" class="btn short">慢放</button>
<button (click)="qePlay()" style="font-size: 15px;font-weight: bold;margin-left:5px;" class="btn short">快放</button>
<input type="datetime-local" [(ngModel)]="posTime" (blur)="posTimeChange($event.target.value)" class="time"
style="margin-left:5px;">
<button (click)="posPlay()" style="font-size: 15px;font-weight: bold;" class="btn short">回放定位</button>
</div>
//ts文件中
import * as moment from 'moment';
public startTime: any
public startTimes: any
public endTime: any
public endTimes: any
public posTime: any
ngOnInit(): void {
//我这里直接给个默认时间,实际页面中我是有个按钮切换预览和回放模式,在切换过程中给的时间,都是小事,理解就可以了,时间需要注意插件方案的时间是时间戳,H5方案的时间格式是ISO 8601格式的时间,我用的原生写的使用了moment.js,实际中根据你自己的ui框架自己选择如何转换,接口里面的时间格式与H5player里面JS_Play回放所需要的时间两个时间是一致的但是时间格式是不一样的,一定要分清楚。
let date = moment().format("YYYY-MM-DD")
this.startTimes = date + 'T' + '00:00:00Z'
this.endTimes = date + 'T' + '23:59:59Z'
}
//回放方法
backPlay(){
let that = this
let params = {
'recordLocation': this.location,//这个是存储位置与插件方案中的存储位置是一致的
'cameraIndexCode': this.cameraIndexCode,//设备监控点编码
'streamType': 1,//子码流
'protocol': 'ws',//取流协议
'transmode': 1,//忽略
"beginTime": this.startTime + ':00.000+08:00', //注意这个时间格式
"endTime": this.endTime + ':00.000+08:00',//注意这个时间格式
'expand': 'transcode=ps',//忽略
'ext': '',//忽略
}
console.log(this.deviceName, this.startTimes, this.endTimes, this.location, '......');
//这里的接口与预览的接口是不一样的
this.http.post('/xx/xxx/xxxx/xxxxxx', params).subscribe(res => {
if (res) {
let oData = JSON.parse(JSON.stringify(res))
let preUrl = JSON.parse(oData.message).data.url
console.log(oData, 'oDataoDataoDataoData');
console.log(preUrl, 'preUrlpreUrlpreUrl');
const param = {
playURL: preUrl,
// 1:高级模式 0:普通模式,高级模式支持所有
mode: 0
}
// 索引默认0
console.log(this.cameraIndexCode, preUrl, param, this.startTimes, this.endTimes, '回放的参数');
//预览和回放调用的H5player的api是一样的
that.player.JS_Play(preUrl, param, 0, this.startTimes, this.endTimes).then(() => {
console.log('播放成功')
},
(err) => {
console.log('播放失败')
})
}
})
}
suPlay() {
this.player.JS_Pause(0).then(
() => {
console.info('JS_Pause success');
// do you want...
},
(err) => {
console.info('JS_Pause failed');
// do you want...
}
);
}
rePlay() {
this.player.JS_Resume(0).then(
() => {
console.info('JS_Resume success');
// do you want...
},
(err) => {
console.info('JS_Resume failed');
// do you want...
}
);
}
stopPlay() {
this.player.JS_Stop(0).then(
() => {
console.info('JS_Stop success');
// do you want...
},
(err) => {
console.info('JS_Stop failed:', err);
// do you want...
}
);
}
slowPlay() {
this.player.JS_Slow(0).then(
() => {
console.info('JS_Slow success');
// do you want...
},
(err) => {
console.info('JS_Slow failed');
// do you want...
}
);
}
qePlay() {
this.player.JS_Fast(0).then(
() => {
console.info('JS_Fast success');
// do you want...
},
(err) => {
console.info('JS_Fast failed');
// do you want...
}
);
}
posPlay() {
if (this.posTime) {
this.player.JS_Seek(0,this.startTimes, this.posTime).then(
() => {
console.info('JS_Seek success');
// do you want...
},
(err) => {
console.info('JS_Seek failed');
// do you want...
}
);
} else {
this.store.dispatch(new ActionNotificationShow({
message: '请先确保视频正在回放且选择了回放时间!',
type: 'warn'
}));
}
}
posTimeChange(val) {
let start = moment(moment(this.startTime).format('YYYY-MM-DD HH:mm:ss')).unix()
let end = moment(moment(this.endTime).format('YYYY-MM-DD HH:mm:ss')).unix()
let pos = moment(moment(val).format('YYYY-MM-DD HH:mm:ss')).unix()
this.posTime = val + ':00Z'
if (this.startTime) {
if (pos > start && pos < end) {
} else {
this.posTime = ''
this.store.dispatch(new ActionNotificationShow({
message: '回放时间需在开始结束时间之间!',
type: 'warn'
}));
}
}
}
代码写完了,调试过程中发现初始加载视频可以正常播放,但是页面会很卡,而且一段时间后就会断流,导致这个问题的原因很多
报错:0x12f910011
原因及对应处理建议:由于客户端长时间无法正常收流,导致后端检测心跳异常,异常断开连接:
1、jsdecoder1.0(chrome92+版本上使用)最容易出现,在解高分辨率,或者是机器资源占用本身很高的情况较容易出现。详情见:
提示性能不足=>浏览器低于chrome80或chrome92+,发现视频卡顿不流畅(高级模式或普通模式下的h265点位播放场景)
2、CPU或GPU突然发生飙升到100%,会影响ws正常收流,还有网络不好,长期抖动,CPU负载不高的情况,可以将平台mgc更新至V5.15.102及以上版本解决,该版本加大了心跳检测超时次数。
3、CPU长期超过80%的利用率,性能超标,请降低路数
4、网络很差的环境(长期超过5%丢包和延时大于100ms),请自行调整网络.可通过ping ip地址 -l 1500 -t 查看丢包延时.
修改streamType为子码流,调整视频格式为H264格式,升级mgc版本,减少分屏,保证网络流畅,最后是在没办法了就换高性能电脑,(都试过还是不行的话那就改用插件方案吧)
总结
thingsboard作为一个物联网项目实现视频播放是每个项目都会涉猎的功能,但对于实现方式开发者应该有自己的考虑,开发一个能接收任何视频流的部件那是做好的实现方式,但是对于我这使用angular半生不熟的过客来说还是有些难度的,所以只是按照项目要求接入了海康视频然后对页面功能进行扩展与优化,如果你有好的想法并成功了,恭喜你将为thingsboard社区作出了很大贡献…