WEB端播放华为海康大华视频方案

类似标题:谷歌浏览器播放华为海康大华视频方案

方案

以下方案相当于给需要播放视频的WEB系统做了一个专用的浏览器,通过专用浏览器的CS客户端组件播放视频,当然,这个专用浏览器是需要安装的
  1. 使用WPF编写一个客户端程序,嵌入CefSharp浏览器控件,除了浏览器之外无其它界面元素,客户端窗体也没有边框和标题栏,如效果图所示
  2. 浏览器加载WEB系统,WEB系统登录后把Token传给WPF客户端,客户端使用Token可以请求WEB系统的接口,获取数据。
  3. WEB系统需要播放实时视频或录像回放时,使用nanoid.js为播放器生成一个唯一标识,计算播放器在浏览器中的位置、长宽,然后把播放器唯一标识、位置、长宽、摄像机设备ID集合通过JS调用C#方法传给客户端,客户端根据位置、长宽显示播放器组件。

说明

  1. WEB端为Vue开发的系统,WEB系统内有Tab页,如果有子系统跳转,或window.open,客户端会打开新窗体加载跳转页

效果图

效果图说明

  1. 页面为BS页面,视频弹窗是用layui做的,也是BS的,视频播放是CS控件,WPF通过WindowsFormsHost加载的Winform控件播放视频
  2. 当BS弹窗最大化、还原、移动时,通过JS调用C#方法更新视频播放CS控件的位置、长宽
  3. BS弹窗最小化时隐藏视频播放CS控件,还原时显示
  4. BS弹窗关闭时,释放视频播放CS控件占用的资源
  5. 视频播放CS控件,全屏功能正常,单视频全屏功能正常,单视频仅在视频播放CS控件中最大化显示功能正常

现场截图

WEB端测试页面代码

<!DOCTYPE html>
<html> <head>
<title>CefSharpDemo</title> <meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1"> <script type="text/javascript" src="jquery-1.9.1.js"></script>
<script type="text/javascript" src="nanoid.js"></script>
<script src="layui/layui.js"></script> <style type="text/css">
input {
height: 21px;
line-height: 21px;
border: solid 1px #666;
outline: none;
}
</style> <script type="text/javascript">
//测试JS调用C#方法
function testCallCSharp() {
if (jsObjExists()) jsObj.TestCallCSharp("测试参数123");
} //测试C#调用JS方法
function testCallJs(data) {
alert("测试C#调用JS方法:" + data);
} //判断jsObj是否存在
function jsObjExists() {
return typeof (jsObj) != typeof (undefined);
} //获取url参数
getQueryString = function (name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
var r = window.location.search.substring(1).match(reg);
if (r != null) return decodeURIComponent(r[2]);
return null;
}
</script>
</head> <body style="background-color: #ffffff; border: solid 2px #ff0000; padding: 0; margin: 0;">
<div style="margin-bottom: 10px; font-weight: bold;">
<span id="title"></span>
</div>
<div style="height: 30px;">
<span>测试输入框:</span><input type="text" />
</div>
<div style="height: 30px; user-select: none;">
<span id="msg" style="line-height: 30px;"></span>
</div>
<div style="height: 30px; user-select: none;">
<span id="msg2" style="line-height: 30px;"></span>
</div> <div style="user-select: none;">
<input type="button" value="测试调用C#方法" title="测试调用C#方法" onclick="testCallCSharp()" />
<input type="button" value="跳转" title="跳转" onclick="openNew()" />
<input type="button" value="设置Token或登录信息" title="设置Token或登录信息" onclick="setToken()" />
</div>
<div style="user-select: none; margin-top: 20px;">
<input type="button" value="播放单个视频" title="播放单个视频" onclick="playSingle()" />
<input type="button" value="替换播放单个视频" title="替换播放单个视频" onclick="playSingleReplace()" />
<input type="button" value="播放多路视频" title="播放多路视频" onclick="playMulti()" />
<input type="button" value="追加播放" title="追加播放" onclick="appendToPlayMulti()" />
<input type="button" value="播放单个录像" title="播放单个录像" onclick="playOneRecord()" />
<input type="button" value="录像回放" title="录像回放" onclick="playRecord()" />
<input type="button" value="追加录像回放" title="追加录像回放" onclick="appendToPlayRecord()" />
</div>
<div style="position: absolute; float: right; top:5px;right:5px;">
<input type="button" value="最小化" title="最小化" onclick="minimizeApp()" style="margin-right: 10px;" />
<input type="button" value="最大化" title="最大化" onclick="maximizeApp()" style="margin-right: 10px;" />
<input type="button" value="还原" title="还原" onclick="normalizeApp()" style="margin-right: 10px;" />
<input type="button" value="关闭" title="关闭" onclick="closeApp()" />
</div> <!-- 一个BS组件 -->
<div
style="position: absolute; float: right; top: 200px; right: 100px; width: 300px; height: 300px; background-color:#FFEE33; padding: 10px; color: #333333;">
<span>
这是一个BS组件,视频能把我挡住
</span>
<br />
<span style="margin-top: 100px; display: block;">
这是一个BS组件,视频能把我挡住
</span>
<br />
<span style="margin-top: 100px; display: block;">
这是一个BS组件,视频能把我挡住
</span>
</div> <script type="text/javascript">
//JS调用C#方法的接口,jsObj.XXX(...)
//下面所有方法,调用的C#方法是首字母大写 let title = getQueryString("title");
$("#title").text(title); //页面加载完成时调用C#方法(重要,页面加载完成一定要调用)
if (jsObjExists()) jsObj.WebPageLoaded(title); //跳转
function openNew() {
window.open("http://localhost:8066/?title=跳转页");
} //设置Token或登录信息
function setToken() {
if (jsObjExists()) jsObj.SetToken("这是登录信息或Token");
} //窗口ID
let windowIdForSingle;
let windowIdForMulti;
let windowIdForOneRecord;
let windowIdForPlayRecord;
let windowIdForPtz; //播放单个视频
function playSingle() {
if (windowIdForSingle) {
if (jsObjExists()) jsObj.ShowWindow(windowIdForSingle);
alert("单个视频播放窗口已存在");
return;
} let moveWindow = function () {
if (!windowIdForSingle) return;
let left = parseFloat($("#layui-layer" + handle).css('left').replace('px', ''));
let top = parseFloat($("#layui-layer" + handle).css('top').replace('px', '')) + 51;
let width = $("#layui-layer" + handle).width();
let height = $("#layui-layer" + handle).height() - 51;
jsObj.MoveWindow(windowIdForSingle, left, top, width, height);
} let interval = setInterval(() => {
moveWindow();
}, 100); windowIdForSingle = nanoid(); //窗口ID
let handle = layer.open({
type: 1,
title: '视频',
shadeClose: false,
shade: false,
maxmin: true, //开启最大化最小化按钮
area: ['500px', '351px'],
content: '<div>空白页面</div>',
cancel: function () {
if (jsObjExists()) {
clearInterval(interval);
jsObj.CloseWindow(windowIdForSingle);
windowIdForSingle = undefined;
}
},
min: function () {
if (jsObjExists()) {
jsObj.HideWindow(windowIdForSingle);
//jsObj.StopWindowPlay(windowIdForSingle); //可选操作,停止窗体所有正在播放的视频
}
},
restore: function () {
if (jsObjExists()) {
jsObj.ShowWindow(windowIdForSingle);
moveWindow();
}
},
full: function () {
moveWindow();
}
}); let left = parseFloat($("#layui-layer" + handle).css('left').replace('px', ''));
let top = parseFloat($("#layui-layer" + handle).css('top').replace('px', '')) + 51;
let width = 500;
let height = 300; let cameraId = "BD4F35031E61B4BCE053070C0822BF04"; //摄像机设备ID if (jsObjExists()) jsObj.PlaySingle(left, top, width, height, windowIdForSingle, cameraId);
} //替换播放单个视频
function playSingleReplace() {
let cameraId = "BC77ACF9EFCE1A48E053070C0822157A"; //摄像机设备ID if (jsObjExists()) jsObj.PlaySingleReplace(windowIdForSingle, cameraId);
} //播放多个视频
function playMulti() {
if (windowIdForMulti) {
if (jsObjExists()) jsObj.ShowWindow(windowIdForMulti);
alert("多路视频播放窗口已存在,您可以追加播放");
return;
} let moveWindow = function () {
if (!windowIdForMulti) return;
let left = parseFloat($("#layui-layer" + handle).css('left').replace('px', ''));
let top = parseFloat($("#layui-layer" + handle).css('top').replace('px', '')) + 51;
let width = $("#layui-layer" + handle).width();
let height = $("#layui-layer" + handle).height() - 51;
jsObj.MoveWindow(windowIdForMulti, left, top, width, height);
} let interval = setInterval(() => {
moveWindow();
}, 100); windowIdForMulti = nanoid(); //窗口ID
let handle = layer.open({
type: 1,
title: '视频',
shadeClose: false,
shade: false,
maxmin: true, //开启最大化最小化按钮
area: ['1100px', '651px'],
content: '<div>空白页面</div>',
cancel: function () {
if (jsObjExists()) {
clearInterval(interval);
jsObj.CloseWindow(windowIdForMulti);
windowIdForMulti = undefined;
hidePTZ();
}
},
min: function () {
if (jsObjExists()) {
jsObj.HideWindow(windowIdForMulti);
//jsObj.StopWindowPlay(windowIdForMulti); //可选操作,停止窗体所有正在播放的视频
}
},
restore: function () {
if (jsObjExists()) {
jsObj.ShowWindow(windowIdForMulti);
moveWindow();
}
},
full: function () {
moveWindow();
}
}); let left = parseFloat($("#layui-layer" + handle).css('left').replace('px', ''));
let top = parseFloat($("#layui-layer" + handle).css('top').replace('px', '')) + 51;
let width = 1000;
let height = 600;
let cameraIds = "BD4F31B4DBFEB3A1E053070C0822FD40,BC77ACF9F04D1A48E053070C0822157A"; //摄像机设备ID if (jsObjExists()) jsObj.PlayMulti(left, top, width, height, windowIdForMulti, 4, true, cameraIds);
} //追加播放
function appendToPlayMulti() {
let cameraIds = "BC77ACF9EFCE1A48E053070C0822157A,BC77ACF9F0801A48E053070C0822157A,BC77ACF9F04D1A48E053070C0822157A,BD4F31B4DBFEB3A1E053070C0822FD40,BD4F31B4DC10B3A1E053070C0822FD40,BD4F35031E50B4BCE053070C0822BF04,BD4F35031E61B4BCE053070C0822BF04"; //摄像机设备ID if (jsObjExists()) jsObj.AppendToPlayMulti(windowIdForMulti, cameraIds);
} //播放单个录像
function playOneRecord() {
layer.msg("请稍等......", { icon: 1, offset: "t" }); if (windowIdForOneRecord) {
if (jsObjExists()) jsObj.ShowWindow(windowIdForOneRecord);
alert("视频回放弹框已存在,您可以追加回放");
return;
} let moveWindow = function () {
if (!windowIdForOneRecord) return;
let left = parseFloat($("#layui-layer" + handle).css('left').replace('px', ''));
let top = parseFloat($("#layui-layer" + handle).css('top').replace('px', '')) + 51;
let width = $("#layui-layer" + handle).width();
let height = $("#layui-layer" + handle).height() - 51;
jsObj.MoveWindow(windowIdForOneRecord, left, top, width, height);
} let interval = setInterval(() => {
moveWindow();
}, 100); windowIdForOneRecord = nanoid(); //窗口ID
let handle = layer.open({
type: 1,
title: '视频',
shadeClose: false,
shade: false,
maxmin: true, //开启最大化最小化按钮
area: ['500px', '351px'],
content: '<div style="padding: 20px;">请稍等......</div>',
cancel: function () {
if (jsObjExists()) {
clearInterval(interval);
jsObj.CloseWindow(windowIdForOneRecord);
windowIdForOneRecord = undefined;
}
},
min: function () {
if (jsObjExists()) {
jsObj.HideWindow(windowIdForOneRecord);
//jsObj.StopWindowPlay(windowIdForOneRecord); //可选操作,停止窗体所有正在播放的视频
}
},
restore: function () {
if (jsObjExists()) {
jsObj.ShowWindow(windowIdForOneRecord);
moveWindow();
}
},
full: function () {
moveWindow();
}
}); let left = parseFloat($("#layui-layer" + handle).css('left').replace('px', ''));
let top = parseFloat($("#layui-layer" + handle).css('top').replace('px', '')) + 51;
let width = 500;
let height = 300; let cameraId = "BD4F31B4DBFEB3A1E053070C0822FD40"; //摄像机设备ID
let startTime = "2022-04-20 01:00:00";
let endTime = "2022-04-20 02:00:00"; if (jsObjExists()) jsObj.PlayOneRecord(left, top, width, height, windowIdForOneRecord, cameraId, startTime, endTime);
} //录像回放
function playRecord() {
layer.msg("请稍等......", { icon: 1, offset: "t" }); if (windowIdForPlayRecord) {
if (jsObjExists()) jsObj.ShowWindow(windowIdForPlayRecord);
alert("视频回放弹框已存在,您可以追加回放");
return;
} let moveWindow = function () {
if (!windowIdForPlayRecord) return;
let left = parseFloat($("#layui-layer" + handle).css('left').replace('px', ''));
let top = parseFloat($("#layui-layer" + handle).css('top').replace('px', '')) + 51;
let width = $("#layui-layer" + handle).width();
let height = $("#layui-layer" + handle).height() - 51;
jsObj.MoveWindow(windowIdForPlayRecord, left, top, width, height);
} let interval = setInterval(() => {
moveWindow();
}, 100); windowIdForPlayRecord = nanoid(); //窗口ID
let handle = layer.open({
type: 1,
title: '视频',
shadeClose: false,
shade: false,
maxmin: true, //开启最大化最小化按钮
area: ['1100px', '651px'],
content: '<div style="padding: 20px;">请稍等......</div>',
cancel: function () {
if (jsObjExists()) {
clearInterval(interval);
jsObj.CloseWindow(windowIdForPlayRecord);
windowIdForPlayRecord = undefined;
}
},
min: function () {
if (jsObjExists()) {
jsObj.HideWindow(windowIdForPlayRecord);
//jsObj.StopWindowPlay(windowIdForPlayRecord); //可选操作,停止窗体所有正在播放的视频
}
},
restore: function () {
if (jsObjExists()) {
jsObj.ShowWindow(windowIdForPlayRecord);
moveWindow();
}
},
full: function () {
moveWindow();
}
}); let left = parseFloat($("#layui-layer" + handle).css('left').replace('px', ''));
let top = parseFloat($("#layui-layer" + handle).css('top').replace('px', '')) + 51;
let width = 1100;
let height = 600; let cameraId = "BD4F31B4DBFEB3A1E053070C0822FD40"; //摄像机设备ID
let startTime = "2022-04-20 01:00:00";
let endTime = "2022-04-20 02:00:00"; if (jsObjExists()) jsObj.PlayRecord(left, top, width, height, windowIdForPlayRecord, 4, cameraId, startTime, endTime);
} //追加录像回放
function appendToPlayRecord() {
layer.msg("请稍等......", { icon: 1, offset: "t" }); let cameraIds = "BD4F31B4DBFEB3A1E053070C0822FD40"; //摄像机设备ID
let startTime = "2022-04-20 01:00:00";
let endTime = "2022-04-20 02:00:00"; if (jsObjExists()) jsObj.AppendToPlayRecord(windowIdForPlayRecord, cameraIds, startTime, endTime);
} //关闭App
function closeApp() {
if (jsObjExists()) jsObj.CloseApp();
} //显示摄像机的云台控制
function showPTZ(cameraId) {
layer.msg("显示摄像机的云台控制,cameraId=" + cameraId, { icon: 1, offset: "t" }); if (!windowIdForPtz) {
windowIdForPtz = nanoid(); //窗口ID
jsObj.ShowPTZ(1603, 650, windowIdForPtz, cameraId);
}
} //隐藏摄像机的云台控制
function hidePTZ(cameraId) {
layer.msg("隐藏摄像机的云台控制,cameraId=" + cameraId, { icon: 1, offset: "t" }); if (windowIdForPtz) {
jsObj.ClosePTZ(windowIdForPtz);
windowIdForPtz = undefined;
}
} //最大化
function maximizeApp() {
if (jsObjExists()) jsObj.Maximize();
} //最小化
function minimizeApp() {
if (jsObjExists()) jsObj.Minimize();
} //还原
function normalizeApp() {
if (jsObjExists()) jsObj.Normalize();
} //窗体最大化事件
function onMaximize() {
layer.msg("窗体最大化", { icon: 1, offset: "t" });
} //窗体还原事件
function onNormalize() {
layer.msg("窗体还原", { icon: 1, offset: "t" });
} //设置body高度
function setBodyHeight() {
let windowHeight = $(window).height();
$("body").height(windowHeight - 4);
}
setBodyHeight();
window.onresize = function () {
setBodyHeight();
}
</script>
</body> </html>

WEB端播放华为海康大华视频方案的更多相关文章

  1. 海康&大华&DSS视频拉流-RTSP转RTMP多媒体播放技术

    海康&大华&DSS获取RTSP 实时流 海康:rtsp://[username]:[password]@[ip]:[port]/[codec]/[channel]/[subtype]/ ...

  2. EasyPlayer播放海康大华RTSP流时RTSPClient客户端连接兼容问题的解决

    在之前的博客<EasyPlayer RTSP播放器对RTSP播放地址url的通用兼容修改意见>中,我描述了遇到的一个客户在播放大华某款摄像机时地址不兼容的问题,这不,团队刚刚参考我的这个意 ...

  3. 浏览器低延时播放监控摄像头RTSP海康大华硬盘录像机NVR视频(EasyNVR播放FLV视频流)

    背景描述 EasyNVR的使用者应该都是清楚的知道,EasyNVR一个强大的功能就是可以进行全平台的无插件直播.主要原因在于rtsp协议的视频流(默认是需要插件才可以播放的)经由EasyNVR处理后可 ...

  4. RTSP安防摄像机(海康大华宇视等)如何推送到RTMP流媒体服务器进行直播

    方案介绍 目前互联网直播的CDN和标准RTMP流媒体服务器通常只能接收RTMP格式的音视频推流.目前市场上有一些自带RTMP推流的摄像机和编码器,可以直接在其rtmp推流配置里面配置推送到RTMP流媒 ...

  5. 海康/大华 IpCamera RTSP地址和格式

    海康:rtsp://[username]:[password]@[ip]:[port]/[codec]/[channel]/[subtype]/av_stream说明:username: 用户名.例如 ...

  6. 海康大华RTSP格式

    海康实时流:rtsp://admin:12345@192.2.82.50:554/h264/ch4/main/av_stream海康回放流(模拟通道):rtsp://admin:12345@192.2 ...

  7. 将海康大华等网络摄像机RTSP流进行网页Flash rtmp和H5 hls直播的技术方案

    前言 再小的技术点也会有他的市场! 一直以来,都有一些不被看好,认为是成本太高,无法大规模展开的软件和产品形态,就好比每一座城市都会有他的著名小吃一样,即使是慕名而来的人源源不断,受众群体也总是有限, ...

  8. 来自iSpy整理的最全海康大华IPC的RTSP连接地址

    来自iSpy整理的最全海康大华IPC的RTSP连接地址 先贴出处: 海康:http://www.ispyconnect.com/man.aspx?n=Hikvision 大华:http://www.i ...

  9. php在web端播放amr语音(如微信语音)

    在使用微信JSSDK的上传下载语音接口时,发现一个问题: 下载的语音在iPhone上不能播放,测试了之后原因竟然是: 微信接口返回的音频内容是amr格式的,但iPhone不支持播放此类型格式. 那么转 ...

  10. 在做RTSP摄像机H5无插件直播中遇到的对接海康摄像机发送OPTIONS心跳时遇到的坑

    我们在实现一套EasyNVR无插件直播方案时,选择了采用厂家无关化的通用协议RTSP/Onvif接入摄像机IPC/NVR设备,总所周知,Onvif是摄像机的发现与控制管理协议,Onvif用到的流媒体协 ...

随机推荐

  1. JavaScript Date转字符串格式

    JavaScript Date转字符串格式

  2. 【主流技术】详解 Spring Boot 2.7.x 集成 ElasticSearch7.x 全过程(二)

    目录 前言 一.添加依赖 二. yml 配置 三.注入依赖 四.CRUD 常用 API ES 实体类 documents 操作 常见条件查询(重点) 分页查询 排序 构造查询 测试调用 五.文章小结 ...

  3. python数值列表之range()和list()

    range() 学习了for循环后,显示数字当然也可以很轻松啦,这个时候我们就可以用到range()函数 for list_2 in range(1, 5): print(list_2) range( ...

  4. 【死亡小学期第二章:没头脑和不高兴】数据库jdbc系统

    自己做一个JDBC的数据库系统,因为这个一直做嘛,所以很简单啦,并没有想提高技术拔拔高啥的,就想做一个简单的,然后自己感兴趣的内容.让自己快乐快乐那才叫做意义~~~~~~~kkkk 学到的东西: 展示 ...

  5. MacOS|matplotlib 无法显示中文 解决办法

    matplotlib 无法显示中文 解决办法 画图时,中文无法正常显示,如图 下载字体 点击这里获取字体 提取码: wnby 查看字体路径 在 python 环境中执行以下指令 import matp ...

  6. 踩坑:nacos启动报错提示需要设置JDK环境 ,报错:ERROR: Please set the JAVA_HOME variable in your environment, We need java(x64)! jdk8 or later is better! !!

    换了个Windows11的新电脑,因为个人工作.学习需要,就重新下载了Nacos并解压使用,结果就踩了个坑,使用下面命令启动Nacos服务端时: startup.cmd -m standalone 直 ...

  7. 使用IDEA2022.3创建web工程~

    为什么突然记录这么一篇博客呢? 以前都是用2019IDEA的,突然换成了IDEA2022懵逼了,所以记录一下~ 具体步骤 1.创建一个新的Project 2.注意选择BuildSystem 3.在当前 ...

  8. 华企盾DSC忘记了数据库解锁密码

    解决方法:登录数据库控制台,找到DSE所使用数据库默认名字"DSEDB",打开表"FileEncryptKey_TABLE",如下图所示: ​ 第一行,自动生成 ...

  9. 在CentOS安装BIND,把所有DNS请求日志转发到syslog服务器去

    在CentOS安装BIND,把所有DNS请求日志转发到syslog服务器去 在vim /etc/named.conf里配置的内容 logging { channel default_debug { f ...

  10. CUDA个人入坟笔记

    CUDA是建立在NVIDIA的GPUs上的一个通用并行计算平台和编程模型,基于CUDA编程可以利用GPUs的并行计算引擎来更加高效地解决比较复杂的计算难题.近年来,GPU最成功的一个应用就是深度学习领 ...