家里安装的小米摄像头,以前就一直好奇如何完成的控制和监控,刚好此时有类似的项目需要完成,经过研究顺利实现初步功能,把项目经验分析出来:
此项目主要难点在于视频监控在外网实现监控。项目的思路图如下:
简单来说就是下发顺序 网页->云服务->前端。 回传信息 前端->云服务->网页。云服务上运行 相关流媒体服务的应用
那么本文就先从核心中转开始讲:
一. 云服务-设计思路
1.设计思路:
云服务需要能够分发控制监控应用的管控程序,主要是主流后端语言+数据库的形式完成。
本项目中使用的是webapi,主要接口是 开始监控,停止监控,下发云台控制。
数据库设计也是建了2表 主表是统计前端设备的序列号,开始停止取流,取流的地址,前端设备的内网穿透分配的域名地址,设备注册时间(定时心跳),还有一些基本的数据创改时间。
附表主要是记录网页取流的信息,当用户停止取流的时候,会根据设备序列号查询附表,看是否全部用户都停止取流,然后才向前端发送停止取流的命令
至于云台控制逻辑只是单纯根据序列号查表找到前端设备内网穿透地址,下发云台控制命令。
考虑到多端取流问题,需要确认网页的唯一标识,这里我使用的是token。
后续我也加上前端web界面的向webapi定时发送心跳操作,用来更新数据库附表的状态。
注意需要考虑的问题:web端用户可能发生强制关闭操作,而不是通过切换界面路由来停止取流,这里我采用上传程序向服务端上传心跳的时候,也会顺带检查附表的web端的上传状态,不符合的给予关闭行为,当附表中同一序列号的取流web端全部都关闭时,服务器会向上传程序发送停止取流的操作。
总而言之:web端和前端都要向服务器发送心跳,从而服务器内部根据两端状态进行对应的分析和操作,达到流量资源不浪费,多端查看的需求
2.流媒体服务器:
项目使用的流媒体服务器是nginx window的版本(云服务是window),一般这种版本没有现成的模块需要自行加入rtmp等相关模板编译版本
以下提供这次项目使用的上传资源
【免费】nginxwindow流媒体服务器资源-CSDN文库
简要来说就是rtmp推送流到服务器,取流是http-flv和hls,注意配置文件使用的是http-flv.conf。 其中以下几个配置注意:主要是配置rtmp推送。取流方面 http-flv和hls
rtmp {
***
***
server {
listen 1935;
#server_name www.test.*; #用于虚拟主机名后缀通配
application live {
live on;
gop_cache on; #打开GOP缓存,减少首屏等待时间
hls on;
hls_path temp/hls;
}
}
}
http {
include mime.types;
default_type application/octet-stream;
keepalive_timeout 65;
server {
listen 8081;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
location /live {
flv_live on; #打开HTTP播放FLV直播流功能
chunked_transfer_encoding on; #支持'Transfer-Encoding: chunked'方式回复
add_header 'Access-Control-Allow-Origin' '*'; #添加额外的HTTP头
add_header 'Access-Control-Allow-Credentials' 'true'; #添加额外的HTTP头
}
location /hls {
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
root temp;
add_header 'Cache-Control' 'no-cache';
}
***
***
}
}
注意:云服务的端口要在控制台进行映射配置
二.前端设备-设计思路
前端主要是一个监听发送的程序,接收相关开停取流和云台控制,向服务器发送心跳(把相关配置信息发送给服务器)。
需要注意的是此项目我才用的是内网穿透的前端设备。其实可以采取长轮询的方式与云服务进行交互,就不需要内网穿透 让服务器再开新的连接发送给前端设备
使用 sse方式理论上也是可行的
三.前端网页-设计思路
web界面没什么好讲的 主要是使用flv.js 来获取播放视频流。
云台的控制图形代码绘制,其中IconFont 是使用antd的icon的方式完成,请到antd官网查看制作流程
展示图如下:
代码如下:
<div className="ptz">
<div className="outer-ring">
{/* <!-- 上 --> */}
<IconFont type="icon-tongyong_jiantouxiangshang" className="caret-up" onClick={(e)=>{console.log("我是上");ControlPTZ('up')}}/>
{/* <!-- 下 --> */}
<IconFont type="icon-tongyong_jiantouxiangxia" className="caret-down" onClick={(e)=>{console.log("我是下");ControlPTZ('down')}}/>
{/* <!-- 左 --> */}
<IconFont type="icon-tongyong_jiantouxiangzuo" className="caret-left" onClick={(e)=>{console.log("我是左");ControlPTZ('left')}}/>
{/* <!-- 右 --> */}
<IconFont type="icon-tongyong_jiantouxiangyou" className="caret-right" onClick={(e)=>{console.log("我是右");ControlPTZ('right')}}/>
<div class="inner-ring">
<IconFont type="icon-lujing" style={{fontSize:'30px'}} className="plus" onClick={(e)=>{console.log("停止");ControlPTZ('stop')}}/>
</div>
</div>
</div>
.ptz .outer-ring {
position: relative;
width: 150px;
height: 150px;
background-color: #fff;
border-radius: 50%;
box-shadow: inset 0 0 25px #e8e8e8, 0 1px 0 #c3c3c3, 0 2px 0 #c9c9c9, 0 2px 3px #333;
}
.ptz .outer-ring i {
font-size: 20px;
cursor: pointer;
}
.ptz .outer-ring i:hover {
color: #00B176;
}
.ptz .outer-ring .caret-up {
position: absolute;
top: 6px;
left: 77px;
margin-left: -10px;
}
.ptz .outer-ring .caret-down {
position: absolute;
bottom: 6px;
left: 77px;
margin-left: -10px;
}
.ptz .outer-ring .caret-left {
position: absolute;
left: 6px;
top: 75px;
margin-top: -10px;
}
.ptz .outer-ring .caret-right {
position: absolute;
right: 6px;
top: 75px;
margin-top: -10px;
}
.ptz .outer-ring .ob-caret-left {
transform: rotate(45deg);
position: absolute;
top: 24px;
left: 24px;
}
.ptz .outer-ring .ob-caret-up {
transform: rotate(45deg);
position: absolute;
top: 24px;
right: 24px;
}
.ptz .outer-ring .ob-caret-right {
transform: rotate(45deg);
position: absolute;
bottom: 24px;
right: 24px;
}
.ptz .outer-ring .ob-caret-down {
transform: rotate(45deg);
position: absolute;
bottom: 24px;
left: 24px;
}
.ptz .outer-ring .inner-ring {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 80px;
height: 80px;
border-radius: 50%;
background-color: #fff;
border: 1px solid #ddd;
}
.ptz .outer-ring .inner-ring .plus {
position: absolute;
top: 26px;
left: 35px;
margin-left: -10px;
}
.ptz .outer-ring .inner-ring .line {
height: 1px;
width: 100%;
background-color: #ddd;
position: absolute;
top: 39px;
left: 0;
}
.ptz .outer-ring .inner-ring .minus {
position: absolute;
bottom: 10px;
left: 40px;
margin-left: -10px;
}
总结:本文章属于项目小结,分析思路总结经验,有啥问题请留言