1、下载依赖
相关依赖包,可从 “海康硬件开发平台” 下载
- jquery-1.7.1.min.js
- AES.js
- cryptico.min.js
- crypto-3.1.2.min.js
- webVideoCtrl.js
2、类型说明
可根据 “类” 的具体功能,进行类型的扩展。
// 配置:插件
export type PluginOptions = {
szWidth?: number | string; // 播放容器的宽度 =>(单位为”px”, 100%表示撑满插件容器)
szHight?: number | string; // 播放容器的高度 =>(单位为”px”, 100%表示撑满插件容器)
bWndFull?: boolean; // 是否支持单窗口双击全屏 => 默认 true
iPackageType?: 2 | 11; // 数据包类型 => 默认 2(2:PS 格式、11:MP4 格式)
iWndowType?: 1 | 2 | 3 | 4; // 分屏类型 => 默认 1(1:1*1、2:2*2、3:3*3、4:4*4)
cbSelWnd?: (xmlDoc: any) => void; // 窗口选中回调事件函数
cbDoubleClickWnd?: (iWndIndex: number, bFullScreen: boolean) => void; // 窗口双击回调事件函数
cbEvent?: (iEventType: number, iParam1: any, iParam2: any) => void; // 插件事件回调函数
cbRemoteConfig?: (xmlDoc: any) => void; // 远程配置库关闭回调
cbInitPluginComplete?: () => void; // 插件初始化完成回调
};
// 配置:登录
export type LoginOptions = {
szIP: string; // 设备的 IP 地址
szPrototocol?: number; // 协议类型 => 默认 1(1:http、2:https)
szPort: number | string; // 端口号
szUsername: string; // 用户名
szPassword: string; // 密码
async?: boolean; // 是否异步 => true 异步,false 同步
cgl?: number; // CGI 协议选择 => 默认 自动(1:ISAPI、2:PSIA)
success?: (xmlDoc: any) => void; // 成功回调
error?: (xmlDoc: any) => void; // 失败回调
};
// 播放:直播
export type StartRealPlayOptions = {
iWndIndex?: number; // 窗口索引号 => 默认 0
iStreamType?: number; // 码流类型 => 默认 1(1:主码流、2:子码流)
iChannelID?: number; // 设备通道号 => 默认 1
bZeroChannel?: boolean; // 是否是零通道 => 默认 false
iPort?: number; // RTSP 端口号 => 如果不传,会自动判断设备 RTSP 端口
success?: (xmlDoc: any) => void; // 成功回调
error?: (err: any) => void; // 失败回调
};
// 播放:停止
export type StopRealPlayOptions = {
iWndIndex?: number; // 窗口索引号 => 不传,表示操作当前选中窗口
success?: (xmlDoc: any) => void; // 成功回调
error?: (err: any) => void; // 失败回调
};
// 回放:开始
export type StartPlayBackOptions = {
iWndIndex?: number; // 窗口索引号 => 默认 0
szStartTime?: string; // 开始时间 => 默认为当天 00:00:00,格式如:2013-12-23 00:00:00
szEndTime?: string; // 结束时间 => 默认为当天 23:59:59,格式如:2013-12-23 23:59:59
iChannelID?: number; // 设备通道号 => 默认 1
iPort?: number; // RTSP 端口号 => 如果不传,会自动判断设备 RTSP 端口
iStreamType?: number; // 码流类型 => 默认 1(1:主码流、2:子码流)
oTransCodeParam?: {}; // 转码回放参数对象,传入此参数,将按照此对象中的编码参数进行转码回放(转码回放需要设备支持,如果不支持,则不要传入这个参数)。
success?: (xmlDoc: any) => void; // 成功回调
error?: (err: any) => void; // 失败回调
};
// 下载录像(按时间)
export type DownloadRecordOptions = {
szPlaybackURI: string; // 回放地址 => 录像 URL,这个 URL 在录像搜索中可以得到
szFileName: string; // 下载的文件名
szStartTime: string; // 开始时间
szEndTime: string; // 结束时间
bDateDir?: true; // 是否创建日期文件夹(true:创建,false:不创建),默认 true
};
// 搜索录像
export type SearchRecordOptions = {
iChannelID?: number; // 设备通道号 => 默认 1
szStartTime?: string; // 开始时间 => 默认为当天 00:00:00,格式如:2013-12-23 00:00:00
szEndTime?: string; // 结束时间 => 默认为当天 23:59:59,格式如:2013-12-23 23:59:59
async?: boolean; // 是否异步 => true 异步,false 同步
iStreamType?: number; // 码流类型 => 默认 1(1:主码流、2:子码流)
iSearchPos?: number; // 搜索录像的位置(默认为 0),0 表示返回结果的第 0-40 条,40 表示 40-80 条,依次类推
success?: (xmlDoc: any) => void; // 成功回调
error?: (status: any, xmlDoc: any) => void; // 失败回调
};
3、封装功能
3.1 创建新类
创建一个新类,用以承接状态与功能。
// 通过依赖包,已挂载到 Window 下
const { $, WebVideoCtrl } = window as any;
export default class HikCamera {
constructor() {
}
// 验证插件
static VerifyPlugin(thing: any) {
const type = Object.prototype.toString.call(thing);
if (type !== '[object Function]') {
return false;
}
return true;
}
// 抛出错误
static ThrowError(message: string) {
throw new Error(message);
}
// 销毁插件
destroy = () => {
};
}
3.2 插件初始化
// 通过依赖包,已挂载到 Window 下
const { $, WebVideoCtrl } = window as any;
export default class HikCamera {
public iWndIndex: number; // 当前选中的窗口
constructor() {
this.iWndIndex = 0;
}
// 验证插件
...
// 抛出错误
...
// 销毁插件
destroy = () => {
};
// 插件初始化
initPlugin = ({ szWidth = '100%', szHight = '100%', ...options }: PluginOptions = {}) => {
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_CheckPluginInstall)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
// 检查插件:是否已经安装
const iRet = WebVideoCtrl.I_CheckPluginInstall();
if (-1 == iRet) {
HikCamera.ThrowError('插件未安装,双击 WebComponentsKit.exe 安装!');
return;
}
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_InitPlugin)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
if (!HikCamera.VerifyPlugin($)) {
HikCamera.ThrowError('jquery 未加载成功!');
return;
}
WebVideoCtrl.I_InitPlugin(szWidth, szHight, {
bWndFull: true,
iPackageType: 2,
iWndowType: 1,
bNoPlugin: true,
cbSelWnd: (xmlDoc: any) => {
const index = window.parseInt($(xmlDoc).find('SelectWnd').eq(0).text(), 10);
this.iWndIndex = index;
},
cbDoubleClickWnd: (iWndIndex: number, bFullScreen: boolean) => {
console.log('窗口双击回调事件函数 =>', { iWndIndex, bFullScreen });
},
cbEvent: (iEventType: number, iParam1: any, iParam2: any) => {
if (iEventType == 2) {
console.log('回放结束 =>', { iParam1 });
} else if (iEventType == -1) {
console.log('网络错误 =>', { iParam1 });
} else if (iEventType == 3001) {
// clickStopRecord(g_szRecordType, iParam1);
}
},
cbRemoteConfig: () => {
console.log('远程配置库关闭回调!');
},
cbInitPluginComplete: () => {
WebVideoCtrl.I_InsertOBJECTPlugin('videoPlugin');
// 检查插件是否最新
if (WebVideoCtrl.I_CheckPluginVersion() == -1) {
HikCamera.ThrowError('检测到新版插件,双击 WebComponentsKit.exe 安装!');
return;
}
},
...(options || {}),
});
};
// 嵌入播放插件
insertOBJECTPlugin = (elementId: string = 'videoWindow') => {
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_InsertOBJECTPlugin)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
WebVideoCtrl.I_InsertOBJECTPlugin(elementId); // 嵌入播放插件
};
// 更新插件窗口(监听窗口大小变化时调用)
pluginResize = (width: number = 500, height: number = 300) => {
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_Resize)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
WebVideoCtrl.I_Resize(width, height);
};
}
3.3 设备登录
// 通过依赖包,已挂载到 Window 下
const { $, WebVideoCtrl } = window as any;
export default class HikCamera {
public iWndIndex: number; // 当前选中的窗口
public szDeviceIdentify: string; // 设备标识 => [IP]_[PORT]
public analogChannels: { id: string; name: string }[]; // 模拟通道
public digitalChannels: { id: string; name: string; online: boolean }[]; // 数字通道
public zeroChannels: { id: string; name: string; online: boolean }[]; // 零通道
public ports: { iDevicePort?: number; iHttpPort?: number; iRtspPort?: number }; // 端口
constructor() {
this.iWndIndex = 0;
this.szDeviceIdentify = '';
this.analogChannels = [];
this.digitalChannels = [];
this.zeroChannels = [];
this.ports = { iHttpPort: 80, iRtspPort: 554 };
}
// 验证插件
...
// 抛出错误
...
// 销毁插件
destroy = () => {
const { szDeviceIdentify } = this;
szDeviceIdentify && this.logoutDevice(szDeviceIdentify);
this.iWndIndex = 0;
this.szDeviceIdentify = '';
this.analogChannels = [];
this.digitalChannels = [];
this.zeroChannels = [];
this.ports = {};
};
// 插件初始化
...
// 嵌入播放插件
...
// 更新插件窗口(监听窗口大小变化时调用)
...
// 设备登录
loginDevice = ({
szIP,
szPrototocol,
szPort,
szUsername,
szPassword,
success,
...options
}: LoginOptions) => {
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_Login)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
if (!szIP) {
HikCamera.ThrowError('IP 不能为空!');
return;
}
if (!szPort) {
HikCamera.ThrowError('PORT 不能为空!');
return;
}
if (!szUsername) {
HikCamera.ThrowError('USERNAME 不能为空!');
return;
}
if (!szPassword) {
HikCamera.ThrowError('PASSWORD 不能为空!');
return;
}
const szDeviceIdentify = szIP + '_' + szPort;
this.szDeviceIdentify = szDeviceIdentify;
const _this = this;
const iRet = WebVideoCtrl.I_Login(
szIP,
szPrototocol || 1,
szPort || 80,
szUsername,
szPassword,
{
success: (xmlDoc: any) => {
setTimeout(() => {
_this.getAnalogChannelInfo(szDeviceIdentify);
_this.getDigitalChannelInfo(szDeviceIdentify);
_this.getZeroChannelInfo(szDeviceIdentify);
_this.getDevicePort(szDeviceIdentify);
}, 10);
success?.(xmlDoc);
},
error: () => {
HikCamera.ThrowError('设备登录失败!');
this.szDeviceIdentify = '';
this.analogChannels = [];
this.digitalChannels = [];
this.zeroChannels = [];
this.ports = {};
},
...(options || {}),
}
);
if (iRet == -1) {
HikCamera.ThrowError('已登录过!');
}
};
// 模拟通道
getAnalogChannelInfo = (szDeviceIdentify: string, options?: {}) => {
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_GetAnalogChannelInfo)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
if (!szDeviceIdentify) {
HikCamera.ThrowError('设备标识不能为空!');
return;
}
const _this = this;
WebVideoCtrl.I_GetAnalogChannelInfo(szDeviceIdentify, {
async: false,
success: (xmlDoc: any) => {
const OPTIONS: { id: string; name: string }[] = []; // 通道列表
const channelElements = $(xmlDoc).find('VideoInputChannel');
$.each(channelElements, () => {
const id = $(this).find('id').eq(0).text();
const name = $(this).find('name').eq(0).text();
OPTIONS.push({ id, name });
});
console.log('获取模拟通道 =>', { OPTIONS });
_this.analogChannels = OPTIONS;
},
error: (status: any, xmlDoc: any) => {
console.log('模拟通道取失败 =>', { status, xmlDoc });
},
...(options || {}),
});
};
// 数字通道
getDigitalChannelInfo = (szDeviceIdentify: string, options?: {}) => {
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_GetDigitalChannelInfo)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
if (!szDeviceIdentify) {
HikCamera.ThrowError('设备标识不能为空!');
return;
}
const _this = this;
WebVideoCtrl.I_GetDigitalChannelInfo(szDeviceIdentify, {
async: false,
success: (xmlDoc: any) => {
const OPTIONS: { id: string; name: string; online: boolean }[] = []; // 通道列表
const channelElements = $(xmlDoc).find('InputProxyChannelStatus');
$.each(channelElements, () => {
const id = $(this).find('id').eq(0).text();
const name = $(this).find('name').eq(0).text();
const online = $(this).find('online').eq(0).text(); // 是否在线
OPTIONS.push({ id, name, online: online === 'false' ? false : true });
});
console.log('获取数字通道 =>', { OPTIONS });
_this.digitalChannels = OPTIONS;
},
error: (status: any, xmlDoc: any) => {
console.log('数字通道取失败 =>', { status, xmlDoc });
},
...(options || {}),
});
};
// 零通道
getZeroChannelInfo = (szDeviceIdentify: string, options?: {}) => {
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_GetZeroChannelInfo)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
if (!szDeviceIdentify) {
HikCamera.ThrowError('设备标识不能为空!');
return;
}
const _this = this;
WebVideoCtrl.I_GetZeroChannelInfo(szDeviceIdentify, {
async: false,
success: (xmlDoc: any) => {
const OPTIONS: { id: string; name: string; online: boolean }[] = []; // 通道列表
const channelElements = $(xmlDoc).find('ZeroVideoChannel');
$.each(channelElements, () => {
const id = $(this).find('id').eq(0).text();
const name = $(this).find('name').eq(0).text();
const online = $(this).find('enabled').eq(0).text(); // 是否在线
OPTIONS.push({ id, name, online: online === 'false' ? false : true });
});
console.log('获取零通道 =>', { OPTIONS });
_this.zeroChannels = OPTIONS;
},
error: (status: any, xmlDoc: any) => {
console.log('零通道获取失败 =>', { status, xmlDoc });
},
...(options || {}),
});
};
// 获取设备端口
getDevicePort = (szDeviceIdentify: string) => {
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_GetDevicePort)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
if (!szDeviceIdentify) {
HikCamera.ThrowError('设备标识不能为空!');
return;
}
const oPort = WebVideoCtrl.I_GetDevicePort(szDeviceIdentify);
if (oPort?.iDevicePort && oPort?.iRtspPort) {
this.ports = oPort;
console.log('端口获取成功 =>', { oPort });
} else {
HikCamera.ThrowError('端口获取失败!');
}
return oPort;
};
// 设备登出
logoutDevice = (szDeviceIdentify: string) => {
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_Logout)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
if (!szDeviceIdentify) {
HikCamera.ThrowError('设备标识不能为空!');
return;
}
const iRet = WebVideoCtrl.I_Logout(szDeviceIdentify);
if (iRet == 0) {
console.log('退出成功!');
this.szDeviceIdentify = '';
this.analogChannels = [];
this.digitalChannels = [];
this.zeroChannels = [];
this.ports = {};
} else {
console.log('退出失败!');
}
};
}
3.4 直播预览
// 通过依赖包,已挂载到 Window 下
const { $, WebVideoCtrl } = window as any;
export default class HikCamera {
public iWndIndex: number; // 当前选中的窗口
...
constructor() {
...
}
// 验证插件
...
// 抛出错误
...
// 销毁插件
destroy = () => {
const { szDeviceIdentify } = this;
this.stopPlay();
...
};
// 插件初始化
...
// 嵌入播放插件
...
// 更新插件窗口(监听窗口大小变化时调用)
...
// 设备登录
...
// 模拟通道
...
// 数字通道
...
// 零通道
...
// 获取设备端口
...
// 设备登出
...
// 直播:开始预览
startRealPlay = (
szDeviceIdentify: string,
{ bZeroChannel, iChannelID, iPort, iStreamType, ...options }: StartRealPlayOptions
) => {
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_GetWindowStatus)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_Stop)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_StartRealPlay)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
if (!szDeviceIdentify) {
HikCamera.ThrowError('设备标识不能为空!');
return;
}
const { iRtspPort } = this.ports;
// ### 播放 [Begin]
const play = () => {
WebVideoCtrl.I_StartRealPlay(szDeviceIdentify, {
...(iPort ? { iRtspPort: iPort || iRtspPort } : {}),
...(iPort ? { iPort: iPort || iRtspPort } : {}),
iStreamType: iStreamType || 1,
iChannelID: iChannelID || 1,
bZeroChannel: bZeroChannel || false,
success: () => {
console.log('播放成功!');
},
error: (status: any, xmlDoc: any) => {
if (status === 403) {
HikCamera.ThrowError('设备不支持 Websocket 取流服务!');
} else {
HikCamera.ThrowError('播放失败!');
}
},
...(options || {}),
});
};
const { iWndIndex } = this;
const oWndInfo = WebVideoCtrl.I_GetWindowStatus(iWndIndex);
if (oWndInfo) {
// 已经在播放,先停止
WebVideoCtrl.I_Stop({ success: play });
} else {
play();
}
};
// 停止播放
stopPlay = (options?: StopRealPlayOptions) => {
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_Stop)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_GetWindowStatus)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
const { iWndIndex } = this;
const oWndInfo = WebVideoCtrl.I_GetWindowStatus(iWndIndex);
if (oWndInfo) {
WebVideoCtrl.I_Stop(options || {});
}
};
}
3.5 录像回放
// 通过依赖包,已挂载到 Window 下
const { $, WebVideoCtrl } = window as any;
// 回放:转码流配置
export const TRANS_CODE_PARAM = {
TransFrameRate: '14', // 0:全帧率,5:1,6:2,7:4,8:6,9:8,10:10,11:12,12:16,14:15,15:18,13:20,16:22
TransResolution: '1', // 255:Auto,3:4CIF,2:QCIF,1:CIF
TransBitrate: '19', // 2:32K,3:48K,4:64K,5:80K,6:96K,7:128K,8:160K,9:192K,10:224K,11:256K,12:320K,13:384K,14:448K,15:512K,16:640K,17:768K,18:896K,19:1024K,20:1280K,21:1536K,22:1792K,23:2048K,24:3072K,25:4096K,26:8192K
};
export default class HikCamera {
...
// 停止播放
...
// 开始回放
startPlayback = (
szDeviceIdentify: string,
{
iWndIndex,
iStreamType,
iPort,
szStartTime,
szEndTime,
iChannelID,
...options
}: StartPlayBackOptions
) => {
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_GetWindowStatus)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
if (!szDeviceIdentify) {
HikCamera.ThrowError('设备标识不能为空!');
return;
}
const bZeroChannel = false;
if (bZeroChannel) {
HikCamera.ThrowError('零通道不支持回放!');
return;
}
const { iWndIndex: _iWndIndex } = this;
const { iRtspPort } = this.ports;
const play = () => {
WebVideoCtrl.I_StartPlayback(szDeviceIdentify, {
iWndIndex: iWndIndex || _iWndIndex || 0,
iStreamType: iStreamType || 1,
iPort: iPort || iRtspPort || 554,
iRtspPort: iPort || iRtspPort || 554,
szStartTime: szStartTime || '2013-12-23 00:00:00',
szEndTime: szEndTime || '2013-12-23 23:59:59',
iChannelID: iChannelID || 1,
// oTransCodeParam: TRANS_CODE_PARAM,
success: () => {
console.log('回放成功!');
},
error: (status: any, xmlDoc: any) => {
if (status === 403) {
HikCamera.ThrowError('设备不支持 Websocket 取流服务!');
} else {
HikCamera.ThrowError('回放失败!');
}
},
...(options || {}),
});
};
const oWndInfo = WebVideoCtrl.I_GetWindowStatus(iWndIndex || _iWndIndex || 0);
if (oWndInfo) {
// 已经在播放,先停止
WebVideoCtrl.I_Stop({ success: play });
} else {
play();
}
};
// 减速播放
showPlay = (options?: StopRealPlayOptions) => {
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_PlaySlow)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_GetWindowStatus)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
const { iWndIndex } = this;
const oWndInfo = WebVideoCtrl.I_GetWindowStatus(iWndIndex);
if (oWndInfo) {
WebVideoCtrl.I_PlaySlow(options || {});
}
};
// 加速播放
falsePlay = (options?: StopRealPlayOptions) => {
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_PlayFast)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_GetWindowStatus)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
const { iWndIndex } = this;
const oWndInfo = WebVideoCtrl.I_GetWindowStatus(iWndIndex);
if (oWndInfo) {
WebVideoCtrl.I_PlayFast(options || {});
}
};
// 恢复播放
resumePlay = (options?: StopRealPlayOptions) => {
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_Resume)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_GetWindowStatus)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
const { iWndIndex } = this;
const oWndInfo = WebVideoCtrl.I_GetWindowStatus(iWndIndex);
if (oWndInfo) {
WebVideoCtrl.I_Resume(options || {});
}
};
// 暂停播放
pausePlay = (options?: StopRealPlayOptions) => {
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_Pause)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_GetWindowStatus)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
const { iWndIndex } = this;
const oWndInfo = WebVideoCtrl.I_GetWindowStatus(iWndIndex);
if (oWndInfo) {
WebVideoCtrl.I_Pause(options || {});
}
};
}
3.6 录像搜索
// 通过依赖包,已挂载到 Window 下
const { $, WebVideoCtrl } = window as any;
...
export default class HikCamera {
...
// 暂停播放
...
// 搜索录像
searchRecord = (
szDeviceIdentify: string,
{
iChannelID = 1,
szStartTime,
szEndTime,
iStreamType = 1,
success,
error,
pageIndex,
pageSize,
...options
}: SearchRecordOptions
) => {
const { szDeviceIdentify: _szDeviceIdentify } = this;
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_RecordSearch)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
if (!szDeviceIdentify && !_szDeviceIdentify) {
HikCamera.ThrowError('设备标识不能为空!');
return;
}
if (!iChannelID || !szStartTime || !szEndTime) {
HikCamera.ThrowError('参数不能为空!');
return;
}
const startTime = Date.parse(szStartTime.replace(/-/g, '/'));
const endTime = Date.parse(szEndTime.replace(/-/g, '/'));
if (endTime - startTime < 0) {
HikCamera.ThrowError('开始时间大于结束时间!');
return;
}
const bZeroChannel = false;
if (bZeroChannel) {
HikCamera.ThrowError('零通道不支持搜索!');
return;
}
const RecordList: {
total: string; // 总数
szStartTime: string; // 开始时间
szEndTime: string; // 结束时间
szFileName: string; // 文件名
szPlaybackURI: string; // 下载流
}[] = [];
// 搜索
const search = () => {
WebVideoCtrl.I_RecordSearch(
szDeviceIdentify || _szDeviceIdentify,
iChannelID,
szStartTime,
szEndTime,
{
iStreamType: iStreamType || 1,
iSearchPos: (pageIndex || 0) * (pageSize || 40),
success: (xmlDoc: any) => {
const IsLastPage = $(xmlDoc).find('responseStatusStrg').eq(0).text();
if (IsLastPage === 'MORE') {
const iLength = $(xmlDoc).find('searchMatchItem').length;
for (let i = 0, nLen = iLength; i < nLen; i++) {
const szPlaybackURI = $(xmlDoc).find('playbackURI').eq(i).text();
if (szPlaybackURI.indexOf('name=') < 0) break;
const szStartTime = $(xmlDoc).find('startTime').eq(i).text();
const szEndTime = $(xmlDoc).find('endTime').eq(i).text();
const szFileName = szPlaybackURI.substring(
szPlaybackURI.indexOf('name=') + 5,
szPlaybackURI.indexOf('&size=')
);
RecordList.push({ szStartTime, szEndTime, szFileName, szPlaybackURI });
}
success?.(RecordList);
} else if (IsLastPage === 'OK') {
const iLength = $(xmlDoc).find('searchMatchItem').length;
for (let i = 0; i < iLength; i++) {
const szPlaybackURI = $(xmlDoc).find('playbackURI').eq(i).text();
if (szPlaybackURI.indexOf('name=') < 0) break;
const szStartTime = $(xmlDoc).find('startTime').eq(i).text();
const szEndTime = $(xmlDoc).find('endTime').eq(i).text();
const szFileName = szPlaybackURI.substring(
szPlaybackURI.indexOf('name=') + 5,
szPlaybackURI.indexOf('&size=')
);
RecordList.push({ szStartTime, szEndTime, szFileName, szPlaybackURI });
}
success?.(RecordList);
console.log('搜索完成!');
} else if (IsLastPage === 'NO MATCHES') {
setTimeout(() => {
HikCamera.ThrowError('未检索到相关内容!');
}, 50);
}
},
error: (status: any, xmlDoc: any) => {
console.error('检索出错!');
error?.(status, xmlDoc);
},
}
);
};
search();
};
}
3.7 录像下载
// 通过依赖包,已挂载到 Window 下
const { $, WebVideoCtrl } = window as any;
...
export default class HikCamera {
...
// 搜索录像
...
// 下载录像(按时间)
downloadRecordByTime = (
szDeviceIdentify: string,
{ szPlaybackURI, szFileName, szStartTime, szEndTime, ...options }: DownloadRecordOptions
) => {
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_StartDownloadRecordByTime)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_GetLastError)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
if (!szDeviceIdentify) {
HikCamera.ThrowError('设备标识不能为空!');
return;
}
if (!szPlaybackURI || !szFileName || !szStartTime || !szEndTime) {
HikCamera.ThrowError('参数不能为空!');
return;
}
const startTime = Date.parse(szStartTime.replace(/-/g, '/'));
const endTime = Date.parse(szEndTime.replace(/-/g, '/'));
if (endTime - startTime < 0) {
HikCamera.ThrowError('开始时间大于结束时间!');
return;
}
let downloadId = -1; // 下载 ID
downloadId = WebVideoCtrl.I_StartDownloadRecordByTime(
szDeviceIdentify,
szPlaybackURI,
szFileName,
szStartTime,
szEndTime,
{
bDateDir: true,
...(options || {}),
}
);
if (downloadId < 0) {
const errorStatus = WebVideoCtrl.I_GetLastError();
if (errorStatus == 34) {
console.log('下载成功!');
} else if (errorStatus == 33) {
HikCamera.ThrowError('空间不足!');
} else {
HikCamera.ThrowError('下载失败!');
}
return { downloadId, errorStatus };
} else {
console.log('下载中...');
return { downloadId };
}
};
// 下载状态
downloadStatus = (downloadId: number) => {
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_GetDownloadStatus)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
const result = WebVideoCtrl.I_GetDownloadStatus(downloadId);
return result;
};
// 下载进度
downloadProgress = (downloadId: number) => {
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_GetDownloadProgress)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
const result = WebVideoCtrl.I_GetDownloadProgress(downloadId);
return result;
};
}
2.5 其它补充
// 通过依赖包,已挂载到 Window 下
const { $, WebVideoCtrl } = window as any;
...
export default class HikCamera {
...
// 下载进度
...
// 检查浏览器是否支持无插件
supportNoPlugin = () => {
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_SupportNoPlugin)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
const result = WebVideoCtrl.I_SupportNoPlugin();
return result;
};
// 检查插件是否已安装
checkPluginInstall = () => {
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_CheckPluginInstall)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
const result = WebVideoCtrl.I_CheckPluginInstall();
if (result === 0) {
return true;
} else if (result === -1) {
return false;
} else {
return false;
}
};
// 获取设备基本信息
getDeviceInfo = (szDeviceIdentify: string, options = {}) => {
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_GetDeviceInfo)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
if (!szDeviceIdentify) {
HikCamera.ThrowError('设备标识不能为空!');
return;
}
WebVideoCtrl.I_GetDeviceInfo(szDeviceIdentify, options);
};
// 获取播放窗口信息
getWindowStatus = (iWndIndex: number = this?.iWndIndex || 0) => {
if (!HikCamera.VerifyPlugin(WebVideoCtrl?.I_GetWindowStatus)) {
HikCamera.ThrowError('webVideoCtrl 未加载成功!');
return;
}
const oWndInfo = WebVideoCtrl.I_GetWindowStatus(iWndIndex);
return oWndInfo;
};
}
4、使用示例(React)
4.1 引入依赖
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="Web site created using create-react-app" />
<title>海康设备视频服务</title>
</head>
<body>
<div id="root"></div>
<!-- 必要的依赖包 -->
<script src="/jquery-1.7.1.min.js"></script>
<script src="/encryption/AES.js"></script>
<script src="/encryption/cryptico.min.js"></script>
<script src="/encryption/crypto-3.1.2.min.js"></script>
<script src="/webVideoCtrl.js"></script>
</body>
</html>
4.2 视频示例
import { useReducer, useRef, useEffect } from 'react';
import moment from 'moment';
import HikCamera from './HikCamera';
const hikCamera = new HikCamera();
const Fragment = ({}) => {
const videoRef = useRef(null);
const szStartTime = moment().subtract(30, 'minutes').format('YYYY-MM-DD HH:mm:ss');
const szEndTime = moment().format('YYYY-MM-DD HH:mm:ss');
// 窗口大小改变
const handleWindowResize = () => {
if (!videoRef?.current) return;
setTimeout(() => {
const width = (videoRef.current as any)?.offsetWidth || 500;
const height = (videoRef.current as any)?.offsetHeight || 300;
hikCamera.pluginResize(width, height);
}, 10);
};
useEffect(() => {
// ### 载入插件
setTimeout(() => {
const szWidth = (videoRef.current as any)?.offsetWidth || 500;
const szHight = (videoRef.current as any)?.offsetHeight || 300;
const playbackVideoDiv: any = document.getElementById('playbackVideo');
playbackVideoDiv.style.height = szHight + 'px';
playbackVideoDiv.style.width = szWidth + 'px';
hikCamera.initPlugin({
szWidth,
szHight,
cbInitPluginComplete: () => {
hikCamera.insertOBJECTPlugin('playbackVideo');
},
});
window.addEventListener('resize', handleWindowResize);
}, 10);
// ### 销毁插件
return () => {
hikCamera.destroy();
window.removeEventListener('resize', handleWindowResize);
};
}, []);
// 登录设备
const login = (success = () => {}) => {
hikCamera.resumePlay();
hikCamera.stopPlay();
hikCamera.logoutDevice(hikCamera.szDeviceIdentify); // 退出正在播放的设备
hikCamera.loginDevice({
szIP: '192.168.1.10',
szPort: 80,
szUsername: 'username',
szPassword: 'password',
success: () => {
console.log('登录成功!');
success();
},
error: () => {
console.log('登录失败!');
hikCamera.szDeviceIdentify = '';
hikCamera.analogChannels = [];
hikCamera.digitalChannels = [];
hikCamera.zeroChannels = [];
hikCamera.ports = {};
},
});
};
// 下载视频
const download = (
szDeviceIdentify,
{
szStartTime,
szEndTime,
szFileName,
szPlaybackURI,
}
) => {
const { downloadId, errorStatus } = hikCamera.downloadRecordByTime(szDeviceIdentify, {
szPlaybackURI,
szStartTime,
szEndTime,
szFileName,
});
if (downloadId < 0) {
if (errorStatus == 34) {
console.log('下载完成!');
} else if (errorStatus == 33) {
console.log('空间不足!');
} else {
message.error('下载失败!');
}
console.log('下载结果 =>', { downloadId, errorStatus });
} else {
message.success('开始下载...');
getDownloadProgress(downloadId);
}
};
return (
<div style={{ height: '100vh', width: '100vh' }}>
<div style={{ height: '80%', width: '100%' }} ref={videoRef}>
<div id="playbackVideo"></div>
</div>
<button onClick={() => {
login(() => {
const { szDeviceIdentify } = hikCamera;
if (szDeviceIdentify) {
hikCamera.startRealPlay(szDeviceIdentify, {
iPort: 'iPort',
iChannelID: 1,
iStreamType: 1,
success: () => {
console.log('播放成功!');
},
error: (status: any) => {
if (status === 403) {
console.log('设备不支持 Websocket 取流服务!');
} else {
console.log('播放失败!');
}
},
});
} else {
console.log('无法连接设备!');
}
});
}}>直播预览</button>
<button onClick={() => {
login(() => {
const { szDeviceIdentify } = hikCamera;
if (szDeviceIdentify) {
hikCamera.startPlayback(szDeviceIdentify, {
iPort: 'iPort',
iStreamType: 1,
iChannelID: 1,
szStartTime,
szEndTime,
success: () => {
console.log('回放成功!');
},
error: (status: any) => {
if (status === 403) {
console.log('设备不支持 Websocket 取流服务!');
} else {
console.log('播放失败!');
}
},
});
} else {
console.log('无法连接设备!');
}
});
}}>录像回放</button>
<button onClick={() => {
login(() => {
const { szDeviceIdentify } = hikCamera;
if (szDeviceIdentify) {
hikCamera.searchRecord(szDeviceIdentify, {
szStartTime,
szEndTime,
success: (RecordList) => {
const { szStartTime, szEndTime, szFileName, szPlaybackURI } = RecordList?.[0] || {};
download(szDeviceIdentify, {
szStartTime,
szEndTime,
szFileName,
szPlaybackURI,
});
},
error: () => {
console.log('下载内容获取失败!');
},
});
} else {
console.log('无法连接设备!');
}
});
}}>录像下载</button>
<button onClick={() => {
hikCamera.resumePlay();
hikCamera.stopPlay();
}}>停止播放</button>
<button onClick={() => hikCamera.pausePlay()}>暂停播放</button>
<button onClick={() => hikCamera.falsePlay()}>快进</button>
<button onClick={() => hikCamera.showPlay()}>慢放</button>
</div>
);
}
export default Fragment;