声明:本系列文章只提供交流与学习使用。文章中所有涉及到海康威视设备的SDK均可在海康威视官方网站下载得到。文章中所有除官方SDK以为的代码均可随意使用,任何涉及到海康威视公司利益的非正常使用由使用者自己负责,与本人无关。

前言:

海康威视频监控设备Web查看系统(一):概要篇

海康威视频监控设备Web查看系统(二):服务器篇

本文是本系列三篇文章中的最后一篇,在前两篇文章中,介绍了开发海康监控的方案及中转服务器的实现,本篇文章介绍Web端的功能实现,经过本篇文章中的项目开发,我们就实现了最初的项目需求。 项目中需要海康官方播放器SDK,请各位根据项目需要下载相应版本。先来作者就带着大家一步步来实现客户端插件的开发。

播放器开发:

根据海康官方的SDK,我们要做的播放器其实只是将海康的播放库引入到我们自己的项目中,然后接收来自中转服务器的数据,最后播放显示到客户Web浏览器上。其实整个就是一个引入了海康播放库的ActiveX插件开发。下面按照开发流程一步步实现播放器插件开发。

  1. 新建C#类库项目
  2. 将播放器SDK中文件引入到项目中
  3. 在项目中添加Winform用户控件
  4. 新建安装项目
  5. 发布项目
  6. 数字签名
  7. 发布Web网站

关于C#开发ActiveX的详细过程,园子里有好多文章写的非常详细,我这里不在累述,有不太了解的朋友,我这里推荐一篇比较详细的文章《ASP.NET C# 之 Activex用C#编写ActiveX控件》。本篇文章写播放器插件的核心功能。

首先来看SDK的C#调用的内容:

 public class PlayCtrlSDK
{
#region 解码库
[DllImport("PlayCtrl.dll")]
public static extern uint PlayM4_GetLastError(int nPort);
[DllImport("PlayCtrl.dll")]
public static extern int PlayM4_GetCaps();
/// <summary>
/// 获取未使用的通道号
/// </summary>
/// <param name="nPort"></param>
/// <returns></returns>
[DllImport("PlayCtrl.dll")]
public static extern bool PlayM4_GetPort(ref int nPort);
/// <summary>
/// 设置流播放模式
/// </summary>
/// <param name="port"></param>
/// <param name="mode"></param>
/// <returns></returns>
[DllImport("PlayCtrl.dll")]
public static extern bool PlayM4_SetStreamOpenMode(int nPort, int mode);
/// <summary>
/// 打开流
/// </summary>
/// <param name="nPort"></param>
/// <param name="pFileHeadBuf"></param>
/// <param name="nSize"></param>
/// <param name="nBufPoolSize"></param>
/// <returns></returns>
[DllImport("PlayCtrl.dll")]
public static extern bool PlayM4_OpenStream(int nPort, byte[] pFileHeadBuf, UInt32 nSize, uint nBufPoolSize);
/// <summary>
/// 设置播放缓冲区最大缓冲帧数
/// </summary>
/// <param name="nPort"></param>
/// <param name="nNum"></param>
/// <returns></returns>
[DllImport("PlayCtrl.dll")]
public static extern bool PlayM4_SetDisplayBuf(int nPort, uint nBufPoolSize);
/// <summary>
/// 开启播放
/// </summary>
/// <param name="nPort"></param>
/// <param name="hWnd"></param>
/// <returns></returns>
[DllImport("PlayCtrl.dll")]
public static extern bool PlayM4_Play(int nPort, IntPtr hWnd);
/// <summary>
/// 开始倒放
/// </summary>
/// <param name="nPort"></param>
/// <returns></returns>
[DllImport("PlayCtrl.dll")]
public static extern bool PlayM4_ReversePlay(int nPort);
/// <summary>
/// 输入流数据
/// </summary>
/// <param name="nPort"></param>
/// <param name="pBuf"></param>
/// <param name="nSize"></param>
/// <returns></returns>
[DllImport("PlayCtrl.dll")]
public static extern bool PlayM4_InputData(int nPort, byte[] pBuf, uint nSize);
/// <summary>
/// 关闭播放
/// </summary>
/// <param name="nPort"></param>
/// <returns></returns>
[DllImport("PlayCtrl.dll")]
public static extern bool PlayM4_Stop(int nPort);
/// <summary>
/// 关闭流
/// </summary>
/// <param name="nPort"></param>
/// <returns></returns>
[DllImport("PlayCtrl.dll")]
public static extern bool PlayM4_CloseStream(int nPort);
/// <summary>
/// 释放已使用的通道号
/// </summary>
/// <param name="nPort"></param>
/// <returns></returns>
[DllImport("PlayCtrl.dll")]
public static extern bool PlayM4_FreePort(int nPort); #endregion
}

根据SDK文档内的说明,这几个函数的调用顺序如下:

下面就该组织我们自己的程序接收来自中转服务器的数据,并将这些数据交给播放库的方法来处理。

    [Guid("A4277AC0-7F3F-4950-9130-27025D6E18F8")]
public partial class Player : UserControl, IObjectSafety
{
int prot = -;
static Socket socket;
bool isPlayInit = false;
IPEndPoint iep;
Thread thread; #region Web页面调用的接口
/// <summary>
/// 释放Socket连接和SDK播放库资源
/// </summary>
public void PageClose()
{
isPlayInit = false;
if (thread != null && thread.IsAlive)
{
thread.Abort();
}
if (socket != null && socket.Connected)
{
socket.Shutdown(SocketShutdown.Both);
socket.Close();
socket = null;
}
if (prot != -)
{
PlayCtrlSDK.PlayM4_CloseStream(prot);
}
}
//插件初始化
public Player()
{
InitializeComponent();
}
/// <summary>
/// 初始化网络连接
/// </summary>
/// <param name="ip">中转服务器IP</param>
/// <param name="iPprot">中转服务器端口</param>
public void InitPlay(string ip, int iPprot)
{
PageClose();
iep = new IPEndPoint(IPAddress.Parse(ip), iPprot);
socket = new Socket(iep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
thread = new Thread((object o) =>
{
socket.Connect(iep);
byte[] bt = new byte[];
while (true)
{
int count = socket.Receive(bt);
StreamType st = count == ? StreamType.Head : StreamType.Body;
setPlay(bt, (uint)count, st);
Thread.Sleep();
}
});
thread.IsBackground = true;
}
/// <summary>
/// 开始播放
/// </summary>
/// <returns></returns>
public bool ShowVideo()
{
thread.Start();
return true;
} #endregion /// <summary>
/// 调用SDK播放库
/// </summary>
/// <param name="buffer">从中转服务器接收到的数据</param>
/// <param name="size">中转服务器发送的数据大小</param>
/// <param name="type">数据类型</param>
private void setPlay(byte[] buffer, uint size, StreamType type)
{
switch (type)
{
case StreamType.Head:
if (size > )
{
return;
}
if (!PlayCtrlSDK.PlayM4_GetPort(ref prot))
{
PageClose();
showError(PlayCtrlSDK.PlayM4_GetLastError(prot));
break;
}
if (!PlayCtrlSDK.PlayM4_SetStreamOpenMode(prot, ))
{
PageClose();
showError(PlayCtrlSDK.PlayM4_GetLastError(prot));
break;
}
if (!PlayCtrlSDK.PlayM4_OpenStream(prot, buffer, size, * ))
{
PageClose();
showError(PlayCtrlSDK.PlayM4_GetLastError(prot));
break;
}
if (!PlayCtrlSDK.PlayM4_SetDisplayBuf(prot, ))
{
PageClose();
showError(PlayCtrlSDK.PlayM4_GetLastError(prot));
break;
}
this.Invoke(new MethodInvoker(delegate
{
//使用PictureBox控件句柄作为参数传给播放器,播放器将其作为容器进行图像渲染
if (!PlayCtrlSDK.PlayM4_Play(prot, this.pictureBox1.Handle))
{
PageClose();
showError(PlayCtrlSDK.PlayM4_GetLastError(prot));
}
}));
isPlayInit = true;
break;
case StreamType.Body:
if (isPlayInit && !PlayCtrlSDK.PlayM4_InputData(prot, buffer, size))
{
PageClose();
showError(PlayCtrlSDK.PlayM4_GetLastError(prot));
}
break;
}
}
/// <summary>
/// 错误提示
/// </summary>
/// <param name="p"></param>
private void showError(uint p)
{
MessageBox.Show(p.ToString());
} #region IObjectSafety接口方法
public void GetInterfacceSafyOptions(int riid, out int pdwSupportedOptions, out int pdwEnabledOptions)
{
pdwEnabledOptions = ;
pdwSupportedOptions = ;
}
public void SetInterfaceSafetyOptions(int riid, int dwOptionsSetMask, int dwEnabledOptions)
{
}
#endregion enum StreamType { Head, Body }
}

如上文所提到的,PlayCtrlSDK.PlayM4_OpenStream(int nPort, byte[] pFileHeadBuf, UInt32 nSize, uint nBufPoolSize);方法必须以中转服务器发送的长度为40个字节的数据作为形参pFileHeadBuf的实参传入,否则播放器无法正常工作。另外,InitPlay(string ip, int iPprot)用JS直接调用,讲实参传入即可,利于中转服务调整和扩展。

到这里,Web浏览器插件的内容介绍完了。最后直接贴出Web网站的内容给大家,相信一看就明白,真的不用不用说什么了吧。。。

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>视频播放</title>
<style type="text/css">
*
{
padding: 0;
margin: 0;
}
body
{
background: #000;
}
a
{
display: block;
text-decoration: none;
line-height: 40px;
color: #fff;
width: 293px;
height: 40px;
text-align: center;
background: #333;
}
a:hover
{
color: #000;
background: #eee;
}
</style>
<script type="text/javascript" language="javascript">
var channel = 1;
window.onbeforeunload = function () {
player.PageClose();
var result = getServer("unload");
}; function getServer(operate) {
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
}
else {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
//说明:
//******这里的方法是为取得视频中转服务器的IP以及端口***************
xmlhttp.open("GET", "ServerHandler.ashx?channel=" + channel + "&operate=" + operate, false); xmlhttp.send();
return xmlhttp.responseText;
} function Show(ch) {
getServer("unload");
var ctrls = document.getElementsByTagName("a");
for (var i = 0; i < ctrls.length; i++) {
ctrls[i].disabled = "";
}
channel = ch;
var host = getServer("load").split(':');
document.getElementById("errorDiv").innerHTML = "IP:" + host[0] + " Port:" + host[1] + " Count:" + host[2];
player.PageClose();
player.InitPlay(host[0], host[1]);
var result = player.ShowVideo();
document.getElementById("but" + channel).disabled = result;
} function refreshSession() {
getServer("refresh");
} setInterval("refreshSession()", 3000);
</script>
</head>
<body>
<table width="600" align="center">
<tr>
<td colspan="2" align="center">
<object id="player" classid="clsid:A4277AC0-7F3F-4950-9130-27025D6E18F8" width="600"
height="400" codebase="Setup.exe">
</object>
</td>
</tr>
<tr>
<td height="40" width="300" align="center">
<a href="#" onclick="Show(1)" id="but1">视频1</a>
</td>
<td width="300" align="center">
<a href="#" onclick="Show(2)" id="but2">视频2</a>
</td>
</tr>
<tr>
<td colspan="2">
<div id="errorDiv">
</div>
</td>
</tr>
</table>
<script language="javascript">
Show(1);
</script>
</body>
</html>

至此,关于海康威视视频中转系统的所有内容都已经介绍完了,希望本人的文章能给您带来一点帮助。如果您还有任何问题,非常欢迎发送邮件到maidi-mao@163.com进行交流。

另外也非常欢迎大家加入QQ群:107943411来交流学习。

海康威视频监控设备Web查看系统(三):Web篇的更多相关文章

  1. 海康威视频监控设备Web查看系统(二):服务器篇

    声明:本系列文章只提供交流与学习使用.文章中所有涉及到海康威视设备的SDK均可在海康威视官方网站下载得到.文章中所有除官方SDK意外的代码均可随意使用,任何涉及到海康威视公司利益的非正常使用由使用者自 ...

  2. 海康威视频监控设备Web查看系统(一):概要篇

    声明:本系列文章只提供交流与学习使用.文章中所有涉及到海康威视设备的SDK均可在海康威视官方网站下载得到.文章中所有除官方SDK意外的代码均可随意使用,任何涉及到海康威视公司利益的非正常使用由使用者自 ...

  3. 海康视频监控---Demo

    1,使用在页面中调用ActiveX控件 <object classid='clsid:E7EF736D-B4E6-4A5A-BA94-732D71107808' codebase='' stan ...

  4. 视频监控——从其他浏览器打开低版本IE方案

    1. 方案背景 由于低版本IE浏览器并不支持很多新的页面技术,导致部分页面效果难以实现;另一方面IE浏览器版本与操作系统绑定,难以统一,不同版本IE间的不兼容导致多种兼容性问题,因此本项目暂定采用Ch ...

  5. VSAM:视频监控系统 A System for Video Surveillance and Monitoring

    VSAM(VideoSurveillance and Monitoring)视频监控系统 Robotics Institute CMU 1:引言 2:试验床介绍 3:基本的视频分析算法:运动目标检测, ...

  6. Qt编写安防视频监控系统18-云台控制

    一.前言 云台控制是视频监控系统中必备的一个功能,对球机进行上下左右的移动,还有焦距的控制,其实核心就是控制XYZ三个坐标轴,为了开发这个模块,特意研究了各种云台控制的方法和开源库比如soap,有些厂 ...

  7. 开源倾情奉献:基于.NET打造IP智能网络视频监控系统(一)开放源代码

    本文为 Dennis Gao 原创技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载. 开源倾情奉献系列链接 开源倾情奉献:基于.NET打造IP智能网络视频监控系统(一)开放源代码 开源倾 ...

  8. 基于.NET打造IP智能网络视频监控系统

    开源倾情奉献:基于.NET打造IP智能网络视频监控系统(一)开放源代码   开源倾情奉献系列链接 开源倾情奉献:基于.NET打造IP智能网络视频监控系统(一)开放源代码 开源倾情奉献:基于.NET打造 ...

  9. EasyCamera Android安卓移动视频监控单兵设备接入EasyDarwin开源流媒体云平台

    前言 随着Android系统的不断更新和发展,现在越来越多的硬件产品选择用安卓系统作为运行环境,电视机,机顶盒.门禁.行车记录仪.车载系统.单兵设备等等,Android系统底层还是Linux,但对上层 ...

随机推荐

  1. Android学习--Assets资源文件读取及AssetManager介绍

    APK安装过程        复制APK安装包到data/app目录下,解压并扫描安装包,把dex文件(Dalvik字节码)保存到dalvik-cache目录,并data/data目录下创建对应的应用 ...

  2. yii联查

    $count = Acticle::find()->select("acticle_type.act_type,acticle.act_id,acticle.act_title,act ...

  3. OpenCV中基于Haar特征和级联分类器的人脸检测

    使用机器学习的方法进行人脸检测的第一步需要训练人脸分类器,这是一个耗时耗力的过程,需要收集大量的正负样本,并且样本质量的好坏对结果影响巨大,如果样本没有处理好,再优秀的机器学习分类算法都是零. 今年3 ...

  4. WPF Clip实现百叶窗

    原文:WPF Clip实现百叶窗 效果图; 后台代码: public MainWindow()         {             InitializeComponent();         ...

  5. WPF之VLC流媒体播放

    原文:WPF之VLC流媒体播放 最近在做关于在WPF使用VLC流媒体播放的问题,现在可以在WPF中实现VLC本地播放了,流播放解决了,在下面的代码中注释流媒体播放那两段代码,更多的在乎大家摸索了^^, ...

  6. UVE开发环境搭建及项目启动

    1.IDE安装visual studio code ,略: 2.node安装(node-v10.5.0-win-x64.zip),解压即可: 3.配置node环境变量,cmd 输入node -v.np ...

  7. WPF 左键单击弹出菜单 ContextMenu

    原文:WPF 左键单击弹出菜单 ContextMenu WPF中的ContextMenu在XAML中可直接做出来,但是仅限于右键弹出菜单,如果需要添加左键弹出功能,只需要在事件中添加Click事件 X ...

  8. x:key和x:name

    x:Key用在xaml Resources,ResourceDictionary需要key来访问x:Name用在ResourceDictionary以外任何地方,可以使用x:Name在code-beh ...

  9. Bootstrap 分页翻页

    @{    Layout = null;}<!DOCTYPE html><html><head>    <meta name="viewport&q ...

  10. OnPropertyChanged的使用

    #region INotifyPropertyChanged         public event PropertyChangedEventHandler PropertyChanged;     ...