智慧工地前端
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.
smart-factory/public/dahua/icc/PlayerManager.js

611 lines
25 KiB

// WSPlayer源码调试时使用
// import WSPlayer from '../WSPlayer/WSPlayer'
import API from "./api.js";
/**
* WSPlayer是核心组件
* API 封装了接口
*/
class PlayerManager {
constructor(opt) {
// 播放器所在的容器ID
this.el = opt.el;
// 实时预览播放器
this.realPlayer = null;
// 录像回放播放器
this.recordPlayer = null;
this.player = null;
// 实时预览还是录像回放播放器
this.type = "real";
// 窗口的数量
this.playNum = 1;
// 当前选中的窗口的索引
this.playIndex = 0;
// 当前选中窗口正在播放视频的通道
this.currentChannelId = "";
// 索引对应窗口,保存当日录像信息
this.recordList = [];
/**
* 兼容老版本字段 已废弃
* ws/wss 直连模式下, serverIp 表示MTS流媒体服务 IP
* 代理 模式下, serverIp 表示的是 代理服务器的IP 地址
*/
this.serverIp = opt.serverIp
/**
* V1.2.8 版本新增字段
* 解码库资源文件前缀
*/
this.prefixUrl = opt.prefixUrl || './static'
/**
* V1.2.8 版本新增字段
* 优先级最高该方法传入后
* 结构如下
* eg:
* (rtspUrl) => {
* return "wss://{ip}:9102"
* }
* 配置后protocol, isIntranet, proxyServerIp, streamServerIp
*/
this.setWSUrl = opt.setWSUrl
/**
* V1.2.8 版本新增字段
* websocket协议http支持wss协议拉流因此增加protocol配置
*/
this.protocol = opt.protocol
/**
* V1.2.8 版本新增字段[组合使用]
* @desc 注意事项 用于有内外网场景和分布式场景
* @param isIntranet 是否内网, 用于有内外网环境多台大华服务器[分布式]拉流场景配置
* @param intranetMap 映射关系结构 { "内网ip": "外网ip", ... }
*
*/
this.isIntranet = opt.isIntranet
this.intranetMap = opt.intranetMap
/**
* V1.2.7 版本新增字段
* 用于只有内网
* @desc 代理 模式下代理服务器的IP 地址
* 如果代理服务有端口则拼接端口
*
*/
this.proxyServerIp = opt.proxyServerIp
/**
* V1.2.7 版本新增字段
* 用于只有内网
* @desc 流媒体服务 IP 地址
* 如果拉流的 9100 9320 端口发生修改则需要后面拼接修改后的端口
*/
this.streamServerIp = opt.streamServerIp
/**
* V1.2.7 版本新增字段
* @desc 模式类型 是直连模式/代理模式
*/
this.useNginxProxy = opt.useNginxProxy || false
if(opt.importLoad) {
this.loadWSPlayer(() => {
this.initPlayer(opt)
})
return
}
this.initPlayer(opt)
}
loadWSPlayer(callback) {
let dom = document.createElement("script");
dom.src = `${this.prefixUrl}/WSPlayer/WSPlayer.js`;
document.head.appendChild(dom);
var loaded = false;
if(typeof callback === 'function') {
dom.onload = dom.onreadystatechange = function() {
if(!loaded && (!dom.readyState || /loaded|complete/.test(dom.readyState))) {
dom.onload = dom.onreadystatechange = null;
loaded = true;
callback();
}
}
}
}
// 初始化播放器
initPlayer(opt) {
// 初始化播放器
if(window.WSPlayer.WSPlayer) {
window.WSPlayer = window.WSPlayer.WSPlayer
}
switch(opt.type) {
case "real":
this.initRealPlayer(opt);
break;
case "record":
this.initRecordPlayer(opt);
break;
default:
break;
}
}
/**
* 初始化实时预览播放器
*/
initRealPlayer(opt) {
this.playNum = opt.num;
this.type = "real";
this.realPlayer = new WSPlayer({
el: this.el,
type: 'real',
importLoad: opt.importLoad, // 是否动态加载库
serverIp: this.serverIp, // V1.2.7 版本已废弃[兼容老版本]
prefixUrl: this.prefixUrl, // 解码库资源前缀
protocol: this.protocol, // 协议 ws wss
isIntranet: this.isIntranet, // 传入当前是 内网还是外网, true-内网 false-外网. 内外网 + 分布式下, 使用该模式
intranetMap: this.intranetMap, // 传入当前的内外网关系映射 {"内网ip": "外网ip"}. 内外网 + 分布式下, 使用该模式
proxyServerIp: this.proxyServerIp, // V1.2.7 版本新增该配置 代理服务器的ip 【ws/wss直连时不传】
streamServerIp: this.streamServerIp, // V1.2.7 版本新增该配置 流媒体服务器的ip
rtspResponseTimeout: opt.rtspResponseTimeout, // rtsp 拉流超时时间
setWSUrl: this.setWSUrl, // 开放式的 传入函数, return websocket 连接地址,第三方自行处理
config: {
num: opt.num,
maxNum: opt.maxNum,
showControl: opt.showControl, // 默认是否显示工具栏
useNginxProxy: this.useNginxProxy, // V1.2.7 版本新增该配置 直连时需要改为 false, 代理模式为 true
showIcons: opt.showIcons || {
streamChangeSelect: true, // 主辅码流切换
replayIcon:true, // 刷新重播按钮
ivsIcon: true, // 控制智能帧按钮
talkIcon: true, // 对讲功能按钮
localRecordIcon: true, // 本地录像功能按钮
audioIcon: true, // 开启关闭声音按钮
snapshotIcon: true, // 抓图按钮
closeIcon: true, // 关闭视频按钮
}, // V1.2.8 新增配置 顶部按钮自定义
openIvs: typeof opt.openIvs === 'boolean' ? opt.openIvs : true, // 默认显示智能帧
draggable: opt.draggable, // 1.3.0 新增,是否支持拖拽
downloadMp4Record: typeof opt.downloadMp4Record === 'boolean' ? opt.downloadMp4Record : true,
useH265MSE: typeof opt.useH265MSE === 'boolean' ? opt.useH265MSE : true,
localeLang: opt.localeLang || 'zhCN', // zhCN 中文 enUS 英文
localeI18n: opt.localeI18n, // 1.3.2新增配置
cacheMode: opt.cacheMode || 1, //1.3.4新增 0-关闭实时流自适应缓冲模式 1-自适应缓冲 2-实时优先 3-流畅优先 4-智能缓冲模式
ivsTypeArr: opt.ivsTypeArr || [1, 2], // 传入数组,支持显示的情况, 空表示没有智能信息,1-智能规则线 2-智能目标框
isWebView: opt.isWebView, // 是否webview引擎 true-是 false-不是
picCapCb: opt.picCapCb, // 是否需要抓图回调
onlyLoadSingleLib: typeof opt.onlyLoadSingleLib === 'boolean' ? opt.onlyLoadSingleLib : false,
},
receiveMessageFromWSPlayer: opt.receiveMessageFromWSPlayer || this.__receiveMessageFromWSPlayer.bind(this),
getRealRtsp: API.getRealmonitor, // 获取实时预览rtsp接口 (不要做任何改动, 只传入方法, API.getRealmonitor() 是错误的, 会报错)
getTalkRtsp: API.getTalkRtsp, // 获取对讲rtsp接口 (不要做任何改动, 只传入方法, API.getTalkRtsp() 是错误的, 会报错)
stopTalk: API.stopTalk, // 关闭对讲rtsp接口 (不要做任何改动, 只传入方法, API.stopTalk() 是错误的, 会报错)
})
this.player = this.realPlayer;
// 初始化云台控制组件
if(opt.pztEl) {
this.realPlayer.initPanTilt({
// 云台控制容器的id
el: opt.pztEl,
// 云台区域控制接口
setPtzDirection: API.setPtzDirection,
// 云台镜头控制接口
setPtzCamera: API.setPtzCamera,
// 云台三维定位接口
controlSitPosition: API.controlSitPosition
})
}
}
/**
* 初始化录像回放播放器
*/
initRecordPlayer(opt) {
this.playNum = opt.num;
this.type = "record";
this.recordPlayer = new WSPlayer({
el: this.el,
type: 'record',
importLoad: opt.importLoad, // 是否动态加载
serverIp: this.serverIp, // V1.2.7 版本已废弃[兼容老版本]
prefixUrl: this.prefixUrl, // 解码库资源前缀
protocol: this.protocol, // 协议 ws wss
isIntranet: this.isIntranet, // 传入当前是 内网还是外网, true-内网 false-外网. 内外网 + 分布式下, 使用该模式
intranetMap: this.intranetMap, // 传入当前的内外网关系映射 {"内网ip": "外网ip"}. 内外网 + 分布式下, 使用该模式
proxyServerIp: this.proxyServerIp, // V1.2.7 版本新增该配置 代理服务器的ip 【ws/wss直连时不传】
streamServerIp: this.streamServerIp, // V1.2.7 版本新增该配置 流媒体服务器的ip
setWSUrl: this.setWSUrl, // 开放式的 传入函数, return websocket 连接地址,第三方自行处理
rtspResponseTimeout: opt.rtspResponseTimeout, // rtsp 拉流超时时间
config: {
num: opt.num,
maxNum: opt.maxNum,
showControl: opt.showControl, // 默认是否显示工具栏
useNginxProxy: this.useNginxProxy, // V1.2.7 版本新增该配置 直连时需要改为 false, 【代理模式可不传】
showIcons: opt.showIcons || {
streamChangeSelect: true, // 主辅码流切换
replayIcon:true, // 刷新重播按钮
ivsIcon: true, // 控制智能帧按钮
talkIcon: true, // 对讲功能按钮
localRecordIcon: true, // 本地录像功能按钮
audioIcon: true, // 开启关闭声音按钮
snapshotIcon: true, // 抓图按钮
closeIcon: true, // 关闭视频按钮
}, // V1.2.8 新增配置 顶部按钮自定义
openIvs: typeof opt.openIvs === 'boolean' ? opt.openIvs : true, // 默认显示智能帧
showRecordProgressBar: typeof opt.showRecordProgressBar === 'boolean' ? opt.showRecordProgressBar : true, // V1.2.8 新增配置 是否显示回放进度条
draggable: opt.draggable, // 1.3.0 新增,是否支持拖拽
downloadMp4Record: typeof opt.downloadMp4Record === 'boolean' ? opt.downloadMp4Record : true,
useH265MSE: typeof opt.useH265MSE === 'boolean' ? opt.useH265MSE : true,
localeLang: opt.localeLang || 'zhCN', // zhCN 中文 enUS 英文
localeI18n: opt.localeI18n, // 1.3.2新增配置
ivsTypeArr: opt.ivsTypeArr || [1, 2], // 传入数组,支持显示的情况, 空表示没有智能信息,1-智能规则线 2-智能目标框
isWebView: opt.isWebView, // 是否webview引擎 true-是 false-不是
picCapCb: opt.picCapCb, // 是否需要抓图回调
onlyLoadSingleLib: typeof opt.onlyLoadSingleLib === 'boolean' ? opt.onlyLoadSingleLib : false,
},
receiveMessageFromWSPlayer: opt.receiveMessageFromWSPlayer || this.__receiveMessageFromWSPlayer.bind(this),
getRecords: API.getRecords, // 获取录像列表接口 (不要做任何改动, 只传入方法, API.getRecords() 是错误的, 会报错)
getRecordRtspByTime: API.getRecordRtspByTime, // 根据时间形式获取录像rtsp接口 (不要做任何改动, 只传入方法, API.getRecordRtspByTime() 是错误的, 会报错)
getRecordRtspByFile: API.getRecordRtspByFile, // 根据文件形式获取录像rtsp接口 (不要做任何改动, 只传入方法, API.getRecordRtspByFile() 是错误的, 会报错)
})
this.player = this.recordPlayer;
}
/**
* 播放实时预览视频
* @param opt.channelList: {Array<Object>} 必填通道列表
* @param opt.streamType: {Number|String} 选填码流类型不填默认播放辅码流1若不存在辅码流1则自动切换到主码流 1-主码流 2-辅码流1 3-辅码流2
* @param opt.windowIndex: {Number} 选填指定从哪个窗口开始播放不填默认从选中的窗口开始播放
*/
// channelList: [{
// id: channelCode, // {String} 通道编码 -- 用于预览,必填
// deviceCode: deviceCode, // {String} 设备编码 -- 用于对讲,对讲必填,无对讲功能可不填
// deviceType: deviceType, // {String} 设备类型 -- 用于对讲,对讲必填,无对讲功能可不填
// channelSeq: channelSeq, // {String|Number} 通道序号 -- 用于对讲,对讲必填,无对讲功能可不填
// cameraType: cameraType, // {String|Number} 摄像头类型 -- 用于云台,云台必填,无云台功能可不填
// capability: capability, // {String} 能力集 -- 用于云台,云台必填,无云台功能可不填
// }]
playRealVideo(opt) {
this.realPlayer && this.realPlayer.playRealVideo({
channelList: opt.channelList,
streamType: opt.streamType,
windowIndex: opt.windowIndex
})
}
/**
* 传入 wsUri wsUrl 播放预览视频
* @param { String } opt.rtspURL 必传 rtsp流地址
* @param { String } opt.wsURL 必传 建立的websocket连接地址
* @param { String } opt.channelId 必传 通道id
* @param { String } opt.streamType 必传 码流类型 1-主码流 2-辅码流1 3-辅码流2
* @param { String } opt.streamServerIp 选传 流媒体服务ip
* @param { String } opt.playerAdapter 选传 是否拉伸窗口 selfAdaption 自适应 | stretching 拉伸
* @param { Number } opt.selectIndex 必传 窗口号 从0开始
* @param { Object } opt.channelData 选传 通道信息若使用云台功能则必传
*/
realByUrl(opt) {
this.realPlayer && this.realPlayer.realByUrl(opt)
}
/**
* @name talkByUrl
* @desc 通过流地址方式进行对讲
* @param playTalk 流地址方式
* @param rtspURL rtsp的地址
* @param wsURL websocket地址
* @param selectIndex 窗口号
* @param audioType 音频类型
*/
talkByUrl(opt) {
this.realPlayer && this.realPlayer.talkByUrl(opt)
}
/**
* @name 停止流地址对讲
* @desc 流地址停止对讲
*/
stopUrlTalk(windowIndex) {
this.realPlayer && this.realPlayer.stopUrlTalk(windowIndex)
}
// 音量设置
/**
* 开启声音
*/
openVolume(windowIndex) {
this.player.openVolume(windowIndex)
}
/**
* 关闭声音
*/
closeVolume(windowIndex) {
this.player.closeVolume(windowIndex)
}
/**
* 设置声音
* @param volume 声音大小 0-1 小数点一位的小数
*/
setVolume(windowIndex, volume) {
this.player.setVolume(windowIndex, volume)
}
/**
* 播放录像回放
* @param opt.channelList {Array<Object>} 通道集合 必填
* @param opt.startTime {String|Number} 开始时间 必选 timestamp到秒
* @param opt.endTime {String|Number} 结束时间 必选 timestamp到秒
* @param opt.recordSource {String|Number} 录像来源 必选 2表示设备录像 3表示中心录像
* @param opt.streamType {String|Number} 码流类型 可选
* @param opt.recordType {String|Number} 录像类型 可选
* @param {Boolean} opt.playRecordByFile 选传 是否根据文件播放默认为false
*/
// channelList: [{
// id: channelCode, // {String} 通道编码 -- 用于回放,必填
// }]
playRecordVideo(opt) {
this.recordPlayer && this.recordPlayer.playRecordVideo(opt)
}
/**
* 传入 wsUri wsUrl 播放回放视频
* @param {Object} opt
* @param {String} opt.wsURL 必传 拉流的websocket连接地址
* @param {String} opt.rtspURL 必传 rtsp地址
* @param {String} opt.channelId 必传 通道id
* @param {String} opt.startTime 必传 开始时间 到秒的时间戳
* @param {String} opt.endTime 必传 结束时间 到秒的时间戳
* @param {String} opt.playerAdapter 选传 是否拉伸窗口 selfAdaption 自适应 | stretching 拉伸
* @param {Number} opt.selectIndex 选传 窗口号
* @param {Object} opt.channelData 选传 通道信息
* @param {Array} opt.records 录像文件信息 [数组格式用于渲染进度条]
* @param {Boolean} opt.playRecordByTime 是否设备录像播放 true-设备录像播放false-中心录像播放
*/
recordByUrl(opt) {
this.recordPlayer && this.recordPlayer.recordByUrl(opt)
}
/**
* 录像暂停
* 只有正在播放的录像调用才有效
* @param { number } index 窗口号
*/
pause(index) {
this.recordPlayer && this.recordPlayer.pause(index);
}
/**
* 录像暂停后播放
* 只有暂停后的录像调用才有效
* @param { number } index 窗口号
*/
play(index) {
this.recordPlayer && this.recordPlayer.play(index);
}
/**
* 倍速播放
* @param { number } speed 速率 0.125 0.25 0.5 1 1.25 1.5 2 4 8 共7种速率
* @param { number } index 窗口号
*/
playSpeed(speed, index) {
this.recordPlayer && this.recordPlayer.playSpeed(speed, index);
}
/**
* 关闭播放器
* @param {number} index 可选关闭指定索引的窗口的播放器不传则表示关闭所有播放器
*/
close(index) {
this.player && this.player.close(index);
}
/**
* 设置全屏
*/
setFullScreen() {
this.player.setFullScreen();
}
/**
* 设置退出全屏
*/
setExitFullScreen() {
this.player.setExitFullScreen();
}
/**
* 设置窗口自适应还是拉伸
* @param {string} playerAdapter selfAdaption 自适应 | stretching 拉伸
*/
setPlayerAdapter(playerAdapter) {
this.player.setPlayerAdapter(playerAdapter);
}
/**
* 控制视频播放器显示的路数: 1 2 3 4 6 8 9 16 25不会超过最大显示路数
* @param {number} number
*/
setPlayerNum(number) {
this.player.setPlayerNum(number);
}
/**
* 设置选中的播放器的索引
* @param {number} index 设置选中的窗口的索引
*/
setSelectIndex(index) {
this.player.setSelectIndex(index);
}
/**
* 录像跳转播放
* /**
* 根据时间跳转播放
* @param {String|Number} time
* time格式支持情况如下
* new Date("2024-11-01 01:00:00") // 时间戳对象格式 (直接跳转到当前时间)
* "2024-11-01 01:00:00" // 时间字符串 (同上)
* "2024/11/01 01:00:00" // 时间字符串 (同上)
* 1706979600 // 到秒时间戳, (同上)
* "1706979600" // 到秒时间戳字符串 (同上)
* 1706979600000 // 到毫秒时间戳 (同上)
* "1706979600000" // 到毫秒时间戳字符串 (同上)
* "01:00:00" // 当日时分秒跳转 (此值跳转到开始播放的当前的时间点, 如录像是 11-1号的,则跳转到 11-1号01:00:00)
* "3600" // 1点的时间戳 (此值根据录像的开始时间,往后推1小时,跳转到这个时间点, 如开始时间为 11-1号2点,则跳转到 11-1号3点开始播放)
* 3600 // 1点的时间戳字符串 (同上)
* @param {number} selectIndex 窗口号
*/
jumpPlayByTime(time, selectIndex) {
this.player.jumpPlayByTime(time, selectIndex);
}
/**
* 开始本地录像
* @param selectIndex 选择本地录像下载的窗口索引 必填
* @param name 录像名称 必填
* @param size 单个录像文件大小单位M 可选默认值为 ./config/config.js localRecordSize
* @param downloadMp4Record 可选默认值为全局配置 true - 以MP4格式下载录像false - 以dav格式下载录像
*/
startLocalRecord(selectIndex, name, size, downloadMp4Record) {
this.player.startLocalRecord(selectIndex, name, size, downloadMp4Record)
}
/**
* 停止本地录像下载
* @param {Number} selectIndex 选择关闭本地录像下载的窗口索引
*/
stopLocalRecord(selectIndex) {
this.player.stopLocalRecord(selectIndex)
}
/**
* 智能规则线和目标框设置
* @param {Boolean} showIvs 是否显示智能规则线和目标框true-显示false-隐藏
* @param {Number} selectIndex 选择的窗口号
* @param {Array} ivsType [1] - 智能规则线 [2] - 智能目标框 [1, 2] - 规则线和智能目标框都显示
*/
setIvs(showIvs, selectIndex, ivsType) {
this.player.setIvs({
showIvs,
ivsType,
selectIndex
})
}
/**
* 抓图
* @param {Number} index 抓图的窗口索引
* @param {String} name 抓图的图片名称选填
*/
picCap(index, name) {
this.player.picCap(index, name)
}
/**
* 在窗口里显示自定义信息
* @param index 窗口索引
* @param msg 显示的信息
* @param channelData 通道信息
*/
showMsgInWindow(index, msg, channelData) {
this.player.showMsgInWindow(index, msg, channelData)
}
/**
* 创建自定义dom(可自定义水印,智能帧等)
* @param {*} domId
*/
createCustomDom(domId) {
this.player.createCustomDom(domId)
}
/**
* destroy 销毁播放器
* @param {*} method
* @param {*} data
*/
destroy() {
this.player.destroy();
}
// ----------------- 播放器事件 ------------------------
__receiveMessageFromWSPlayer(method, data) {
switch(method) {
// ------------- 公共事件 ---------------------
case "initializationCompleted":
// 初始化完成,可调用播放方法(适用于动态加载解码库)
break;
case "realSuccess": // 实时预览成功
console.log("实时预览成功")
break;
case "realError": // 实时预览失败
console.log("实时预览失败", err)
break;
case "talkError": // 对讲失败
console.log("对讲失败");
break;
case "recordSuccess": // 录像回放成功
console.log("录像回放成功");
break;
case "recordError": // 录像回放失败
console.log("录像回放失败", err);
break;
case 'recordFinish':
console.log("当前录像播放完成", data)
break;
case "selectWindowChanged": // 选中的窗口发生改变
this.currentChannelId = data.channelId;
this.playIndex = data.playIndex;
break;
case "windowNumChanged": // 播放器显示的路数发生改变
this.playNum = data;
break;
case "closeVideo": // 视频关闭
// 点击关闭按钮引发的视频关闭进行提示
// 切换视频引发的视频关闭不进行提示
if(!data.changeVideoFlag) {
console.log(`窗口${data.selectIndex}的视频已关闭`)
}
break;
case "statusChanged": // 视频状态发生改变
break;
case "getVideoFrameInfo":
// 获取视频帧信息
break;
case "getAudioFrameInfo":
// 获取视频内音频帧信息
break;
case "getPlayBackStreamRange":
// 获取录像回放时长
console.log("getPlayBackStreamRange", data)
break;
case "dragWindow":
// 拖拽窗口
console.log(`窗口${data.dragIndex}的视频拖拽到窗口${data.dropIndex}`)
break;
case "errorInfo": // 错误信息提示
console.log(data, "可打印查看错误消息");
// data = {
// errorCode: xxx,
// errorMsg: "",
// errorData: {
// channelList: [],
// apiErrorInfo: {},
// method: "",
// arguments: [],
// },
// }
console.error(data)
break;
case 'picCap': // 抓图回调,配置在 new PlayerManager 中配置 picCapCb为true后即可触发
// data.index 窗口索引
// data.base64Img
break;
default:
break;
}
}
}
export {
PlayerManager
}
export default PlayerManager