From 57fd18cd7c842a821bd03fafe2a954c605e387f6 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Wed, 30 Sep 2020 17:59:11 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=88=86=E9=A1=B5,=E6=90=9C?= =?UTF-8?q?=E7=B4=A2,=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/encodings.xml | 1 + README.md | 29 +- .../iot/vmp/conf/VManagerConfig.java | 2 + .../iot/vmp/gb28181/bean/DeviceChannel.java | 13 + .../gb28181/transmit/SIPProcessorFactory.java | 2 + .../request/impl/MessageRequestProcessor.java | 7 +- .../vmp/storager/IVideoManagerStorager.java | 17 +- .../iot/vmp/storager/VodeoMannagerTask.java | 17 + .../jdbc/VideoManagerJdbcStoragerImpl.java | 12 +- .../redis/VideoManagerRedisStoragerImpl.java | 695 +++++++++++------- .../vmp/vmanager/device/DeviceController.java | 45 +- .../iot/vmp/web/ApiDeviceController.java | 6 +- src/main/resources/application.yml | 6 +- 13 files changed, 533 insertions(+), 319 deletions(-) create mode 100644 src/main/java/com/genersoft/iot/vmp/storager/VodeoMannagerTask.java diff --git a/.idea/encodings.xml b/.idea/encodings.xml index fade66b8..e470467d 100644 --- a/.idea/encodings.xml +++ b/.idea/encodings.xml @@ -3,5 +3,6 @@ + \ No newline at end of file diff --git a/README.md b/README.md index 1f1dbc91..8eb641f3 100644 --- a/README.md +++ b/README.md @@ -6,38 +6,25 @@ WEB VIDEO PLATFORM是一个基于GB28181-2016标准实现的网络视频平台 ### fork自 [swwheihei/wvp-GB28181](https://github.com/swwheihei/wvp-GB28181) # 应用场景: -主要应用在IPC等设备没有固定IP地址,但需要在互联网中观看的场景。 -要求IPC设备可以访问互联网,有云服务器用于部署本服务。 -预计7月可以达到商用级别的文档性 +原项目比较侧重单个摄像机的接入,当前这个更侧重平台接入,当然,直接接摄像机也是没有问题的。 # 支持特性: 1、视频预览 2、云台控制(方向、缩放控制) 3、视频设备信息同步 -4、离在线监控 -5、录像查询与回放(基于NVR\DVR,暂不支持快进、seek操作) -6、无人观看自动断流 +4、离在线监控 +5、无人观看自动断流 -# 2020路线图: -5月中旬-录像回放(基于NVR\DVR)、设备认证(基于密码) -5月下旬-设备报警 -6月上旬-流媒体认证(ZLM推流、取流) -6月下旬-语音对讲、Android Deme\iOS Demo -7月下旬-设备认证(基于数字证书)、集群部署 -8月下旬-云端录像与回放 -9月下旬-Onvif协议支持 -10月下旬-GB28181-2011版设备适配 +# 待实现: +录像查询与回放(基于NVR\DVR,暂不支持快进、seek操作) 12月底-上级级联、时间同步、其他国标能力 # 项目部署 -参考wiki说明 + # 使用帮助 -参考wiki说明 + # 致谢 感谢作者[夏楚](https://github.com/xiongziliang) 提供这么棒的开源流媒体服务框架 -感谢作者[kkkkk5G](https://gitee.com/kkkkk5G) 提供这么棒的前端UI - - -[]: https://github.com/swwheihei/wvp-GB28181 \ No newline at end of file +感谢作者[kkkkk5G](https://gitee.com/kkkkk5G) 提供这么棒的前端UI \ No newline at end of file diff --git a/src/main/java/com/genersoft/iot/vmp/conf/VManagerConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/VManagerConfig.java index 6045ea26..be83a88f 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/VManagerConfig.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/VManagerConfig.java @@ -21,5 +21,7 @@ public class VManagerConfig { public void setDatabase(String database) { this.database = database; } + + } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java index 5c3989a2..73fafc19 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java @@ -128,6 +128,11 @@ public class DeviceChannel { */ private double latitude; + /** + * 子设备数 + */ + private int subCount; + /** * 流唯一编号,存在表示正在直播 */ @@ -332,4 +337,12 @@ public class DeviceChannel { public void setSsrc(String ssrc) { this.ssrc = ssrc; } + + public int getSubCount() { + return subCount; + } + + public void setSubCount(int subCount) { + this.subCount = subCount; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java index fe97e2b6..63f28cd7 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java @@ -7,6 +7,7 @@ import javax.sip.header.CSeqHeader; import javax.sip.message.Request; import javax.sip.message.Response; +import com.alibaba.fastjson.JSON; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -126,6 +127,7 @@ public class SIPProcessorFactory { processor.setRequestEvent(evt); return processor; } else if (Request.MESSAGE.equals(method)) { + MessageRequestProcessor processor = new MessageRequestProcessor(); processor.setRequestEvent(evt); processor.setTcpSipProvider(getTcpSipProvider()); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java index e9f59061..0dfcdb0f 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java @@ -144,6 +144,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { private void processMessageCatalogList(RequestEvent evt) { try { Element rootElement = getRootElement(evt); + String s = rootElement.toString(); Element deviceIdElement = rootElement.element("DeviceID"); String deviceId = deviceIdElement.getText().toString(); Element deviceListElement = rootElement.element("DeviceList"); @@ -171,10 +172,10 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { DeviceChannel deviceChannel = new DeviceChannel(); deviceChannel.setName(channelName); deviceChannel.setChannelId(channelDeviceId); - if(status.equals("ON")) { + if(status.equals("ON") || status.equals("On")) { deviceChannel.setStatus(1); } - if(status.equals("OFF")) { + if(status.equals("OFF") || status.equals("Off")) { deviceChannel.setStatus(0); } @@ -185,7 +186,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { deviceChannel.setBlock(XmlUtil.getText(itemDevice,"Block")); deviceChannel.setAddress(XmlUtil.getText(itemDevice,"Address")); deviceChannel.setParental(itemDevice.element("Parental") == null? 0:Integer.parseInt(XmlUtil.getText(itemDevice,"Parental"))); - deviceChannel.setParentId(XmlUtil.getText(itemDevice,"ParentId")); + deviceChannel.setParentId(XmlUtil.getText(itemDevice,"ParentID")); deviceChannel.setSafetyWay(itemDevice.element("SafetyWay") == null? 0:Integer.parseInt(XmlUtil.getText(itemDevice,"SafetyWay"))); deviceChannel.setRegisterWay(itemDevice.element("RegisterWay") == null? 1:Integer.parseInt(XmlUtil.getText(itemDevice,"RegisterWay"))); deviceChannel.setCertNum(XmlUtil.getText(itemDevice,"CertNum")); diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java index 0993c116..69ac02be 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java @@ -77,7 +77,7 @@ public interface IVideoManagerStorager { * @param count 每页数量 * @return */ - public PageResult queryChannelsByDeviceId(String deviceId, int page, int count); + public PageResult queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, String online, int page, int count); /** * 获取某个设备的通道列表 @@ -161,6 +161,19 @@ public interface IVideoManagerStorager { */ public StreamInfo queryPlay(String deviceId, String channelId); + /** + * 查询子设备 + * + * @param deviceId + * @param channelId + * @param page + * @param count + * @return + */ + PageResult querySubChannels(String deviceId, String channelId, String query, Boolean hasSubChannel, String online, int page, int count); - + /** + * 更新缓存 + */ + public void updateCatch(); } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/VodeoMannagerTask.java b/src/main/java/com/genersoft/iot/vmp/storager/VodeoMannagerTask.java new file mode 100644 index 00000000..c96e4bb0 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/storager/VodeoMannagerTask.java @@ -0,0 +1,17 @@ +package com.genersoft.iot.vmp.storager; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +@Component +public class VodeoMannagerTask implements CommandLineRunner { + + @Autowired + private IVideoManagerStorager storager; + + @Override + public void run(String... strings) throws Exception { + storager.updateCatch(); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java index b4e2ff93..40ec1674 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java @@ -79,10 +79,11 @@ public class VideoManagerJdbcStoragerImpl implements IVideoManagerStorager { } @Override - public PageResult queryChannelsByDeviceId(String deviceId, int page, int count) { + public PageResult queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, String online, int page, int count) { return null; } + @Override public List queryChannelsByDeviceId(String deviceId) { return null; @@ -161,4 +162,13 @@ public class VideoManagerJdbcStoragerImpl implements IVideoManagerStorager { return null; } + @Override + public PageResult querySubChannels(String deviceId, String channelId, String query, Boolean hasSubChannel, String online, int page, int count) { + return null; + } + + @Override + public void updateCatch() { + + } } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java index 8ea9f7ee..e1411ab5 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java @@ -1,278 +1,417 @@ -package com.genersoft.iot.vmp.storager.redis; - -import java.util.ArrayList; -import java.util.List; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.genersoft.iot.vmp.common.PageResult; -import com.genersoft.iot.vmp.common.StreamInfo; -import com.genersoft.iot.vmp.conf.MediaServerConfig; -import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import com.genersoft.iot.vmp.common.VideoManagerConstants; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.storager.IVideoManagerStorager; -import com.genersoft.iot.vmp.utils.redis.RedisUtil; - -/** - * @Description:视频设备数据存储-redis实现 - * @author: swwheihei - * @date: 2020年5月6日 下午2:31:42 - */ -@Component("redisStorager") -public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager { - - @Autowired - private RedisUtil redis; - - - /** - * 根据设备ID判断设备是否存在 - * - * @param deviceId 设备ID - * @return true:存在 false:不存在 - */ - @Override - public boolean exists(String deviceId) { - return redis.hasKey(VideoManagerConstants.DEVICE_PREFIX+deviceId); - } - - /** - * 视频设备创建 - * - * @param device 设备对象 - * @return true:创建成功 false:创建失败 - */ - @Override - public boolean create(Device device) { - return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device); - } - - - - /** - * 视频设备更新 - * - * @param device 设备对象 - * @return true:更新成功 false:更新失败 - */ - @Override - public boolean updateDevice(Device device) { - List deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + device.getDeviceId() + "_" + "*"); - // 更新device中的通道数量 - device.setChannelCount(deviceChannelList.size()); - // 存储device - return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device); - - - } - - @Override - public void updateChannel(String deviceId, DeviceChannel channel) { - // 存储通道 - redis.set(VideoManagerConstants.CACHEKEY_PREFIX+deviceId + "_" + channel.getChannelId(), - channel); - List deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*"); - // 更新device中的通道数量 - Device device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId); - device.setChannelCount(deviceChannelList.size()); - redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device); - } - - /** - * 获取设备 - * - * @param deviceId 设备ID - * @return Device 设备对象 - */ - @Override - public Device queryVideoDevice(String deviceId) { - return (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId); - } - - @Override - public PageResult queryChannelsByDeviceId(String deviceId, int page, int count) { - List result = new ArrayList<>(); - PageResult pageResult = new PageResult(); - List deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*"); - pageResult.setPage(page); - pageResult.setCount(count); - pageResult.setTotal(deviceChannelList.size()); - int maxCount = (page + 1 ) * count; - if (deviceChannelList != null && deviceChannelList.size() > 0 ) { - for (int i = page * count; i < (pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal() ); i++) { - result.add((DeviceChannel)redis.get((String)deviceChannelList.get(i))); - } - pageResult.setData(result); - } - - return pageResult; - } - - @Override - public List queryChannelsByDeviceId(String deviceId) { - List result = new ArrayList<>(); - List deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*"); - if (deviceChannelList != null && deviceChannelList.size() > 0 ) { - for (int i = 0; i < deviceChannelList.size(); i++) { - result.add((DeviceChannel)redis.get((String)deviceChannelList.get(i))); - } - } - return result; - } - - @Override - public DeviceChannel queryChannel(String deviceId, String channelId) { - return (DeviceChannel)redis.get(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + channelId); - } - - - /** - * 获取多个设备 - * - * @param deviceIds 设备ID数组 - * @return List 设备对象数组 - */ - @Override - public PageResult queryVideoDeviceList(String[] deviceIds, int page, int count) { - List devices = new ArrayList<>(); - PageResult pageResult = new PageResult(); - pageResult.setPage(page); - pageResult.setCount(count); - - if (deviceIds == null || deviceIds.length == 0) { - - List deviceIdList = redis.keys(VideoManagerConstants.DEVICE_PREFIX+"*"); - pageResult.setTotal(deviceIdList.size()); - int maxCount = (page + 1)* count; - for (int i = page * count; i < (pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal() ); i++) { - devices.add((Device)redis.get((String)deviceIdList.get(i))); - } - } else { - for (int i = 0; i < deviceIds.length; i++) { - devices.add((Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceIds[i])); - } - } - pageResult.setData(devices); - return pageResult; - } - - /** - * 获取多个设备 - * - * @param deviceIds 设备ID数组 - * @return List 设备对象数组 - */ - @Override - public List queryVideoDeviceList(String[] deviceIds) { - List devices = new ArrayList<>(); - - if (deviceIds == null || deviceIds.length == 0) { - List deviceIdList = redis.keys(VideoManagerConstants.DEVICE_PREFIX+"*"); - for (int i = 0; i < deviceIdList.size(); i++) { - devices.add((Device)redis.get((String)deviceIdList.get(i))); - } - } else { - for (int i = 0; i < deviceIds.length; i++) { - devices.add((Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceIds[i])); - } - } - return devices; - } - - /** - * 删除设备 - * - * @param deviceId 设备ID - * @return true:删除成功 false:删除失败 - */ - @Override - public boolean delete(String deviceId) { - return redis.del(VideoManagerConstants.DEVICE_PREFIX+deviceId); - } - - /** - * 更新设备在线 - * - * @param deviceId 设备ID - * @return true:更新成功 false:更新失败 - */ - @Override - public boolean online(String deviceId) { - Device device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId); - device.setOnline(1); - return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device); - } - - /** - * 更新设备离线 - * - * @param deviceId 设备ID - * @return true:更新成功 false:更新失败 - */ - @Override - public boolean outline(String deviceId) { - Device device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId); - if (device == null) return false; - device.setOnline(0); - return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device); - } - - /** - * 开始播放时将流存入redis - * - * @param deviceId 设备ID - * @param channelId 通道ID - * @return - */ - @Override - public boolean startPlay(String deviceId, String channelId, StreamInfo stream) { - return redis.set(String.format("%S_%s_%s", VideoManagerConstants.PLAYER_PREFIX, deviceId, channelId), - stream); - } - - /** - * 停止播放时从redis删除 - * - * @param deviceId 设备ID - * @param channelId 通道ID - * @return - */ - @Override - public boolean stopPlay(String deviceId, String channelId) { - return redis.del(String.format("%S_%s_%s", VideoManagerConstants.PLAYER_PREFIX, deviceId, channelId)); - } - - /** - * 查询播放列表 - * @param deviceId 设备ID - * @param channelId 通道ID - * @return - */ - @Override - public StreamInfo queryPlay(String deviceId, String channelId) { - return (StreamInfo)redis.get(String.format("%S_%s_%s", VideoManagerConstants.PLAYER_PREFIX, deviceId, channelId)); - } - - /** - * 更新流媒体信息 - * @param mediaServerConfig - * @return - */ - @Override - public boolean updateMediaInfo(MediaServerConfig mediaServerConfig) { - return redis.set(VideoManagerConstants.MEDIA_SERVER_PREFIX,mediaServerConfig); - } - - /** - * 获取流媒体信息 - * @return - */ - @Override - public MediaServerConfig getMediaInfo() { - return (MediaServerConfig)redis.get(VideoManagerConstants.MEDIA_SERVER_PREFIX); - } -} +package com.genersoft.iot.vmp.storager.redis; + +import java.util.*; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.genersoft.iot.vmp.common.PageResult; +import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.conf.MediaServerConfig; +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.genersoft.iot.vmp.common.VideoManagerConstants; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; +import com.genersoft.iot.vmp.utils.redis.RedisUtil; +import org.springframework.util.StringUtils; + +/** + * @Description:视频设备数据存储-redis实现 + * @author: swwheihei + * @date: 2020年5月6日 下午2:31:42 + */ +@Component("redisStorager") +public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager { + + @Autowired + private RedisUtil redis; + + private HashMap>> deviceMap = new HashMap<>(); + + + /** + * 根据设备ID判断设备是否存在 + * + * @param deviceId 设备ID + * @return true:存在 false:不存在 + */ + @Override + public boolean exists(String deviceId) { + return redis.hasKey(VideoManagerConstants.DEVICE_PREFIX+deviceId); + } + + /** + * 视频设备创建 + * + * @param device 设备对象 + * @return true:创建成功 false:创建失败 + */ + @Override + public boolean create(Device device) { + return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device); + } + + + + /** + * 视频设备更新 + * + * @param device 设备对象 + * @return true:更新成功 false:更新失败 + */ + @Override + public boolean updateDevice(Device device) { + if (deviceMap.get(device.getDeviceId()) == null) { + deviceMap.put(device.getDeviceId(), new HashMap>()); + } +// List deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + device.getDeviceId() + "_" + "*"); + // 更新device中的通道数量 + device.setChannelCount(deviceMap.get(device.getDeviceId()).size()); + // 存储device + return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device); + + + } + + @Override + public void updateChannel(String deviceId, DeviceChannel channel) { + String channelId = channel.getChannelId(); + HashMap> channelMap = deviceMap.get(deviceId); + if (channelMap == null) return; + + // 作为父设备, 确定自己的子节点数 + if (channelMap.get(channelId) == null) { + channelMap.put(channelId, new HashSet()); + }else if (channelMap.get(channelId).size()> 0) { + channel.setSubCount(channelMap.get(channelId).size()); + } + + // 存储通道 + redis.set(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + + "_" + channel.getChannelId() + + ":" + channel.getName() + + "_" + (channel.getStatus() == 1 ? "on":"off") + + "_" + (channelMap.get(channelId).size() > 0)+ + "_" + channel.getParentId(), + channel); + // 更新device中的通道数量 + Device device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId); + device.setChannelCount(deviceMap.get(deviceId).size()); + redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device); + + + // 如果有父设备,更新父设备内子节点数 + String parentId = channel.getParentId(); + if (!StringUtils.isEmpty(parentId)) { + + if (channelMap.get(parentId) == null) { + channelMap.put(parentId, new HashSet<>()); + } + channelMap.get(parentId).add(channelId); + + DeviceChannel deviceChannel = queryChannel(deviceId, parentId); + if (deviceChannel != null) { + deviceChannel.setSubCount(channelMap.get(parentId).size()); + redis.set(VideoManagerConstants.CACHEKEY_PREFIX+deviceId + "_" + deviceChannel.getChannelId(), + deviceChannel); + + } + } + + } + + /** + * 获取设备 + * + * @param deviceId 设备ID + * @return Device 设备对象 + */ + @Override + public Device queryVideoDevice(String deviceId) { + return (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId); + } + + @Override + public PageResult queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, String online, int page, int count) { + List result = new ArrayList<>(); + PageResult pageResult = new PageResult(); + String queryContent = "*"; + if (!StringUtils.isEmpty(query)) queryContent = String.format("*%S*",query); + String queryHasSubChannel = "*"; + if (hasSubChannel != null) queryHasSubChannel = hasSubChannel?"true":"false"; + String queryOnline = "*"; + if (!StringUtils.isEmpty(online)) queryOnline = online; + String queryStr = VideoManagerConstants.CACHEKEY_PREFIX + deviceId + + "_" + queryContent + // 搜索编号和名称 + "_" + queryOnline + // 搜索是否在线 + "_" + queryHasSubChannel + // 搜索是否含有子节点 + "_" + "*"; + List deviceChannelList = redis.keys(queryStr); + pageResult.setPage(page); + pageResult.setCount(count); + pageResult.setTotal(deviceChannelList.size()); + int maxCount = (page + 1 ) * count; + if (deviceChannelList != null && deviceChannelList.size() > 0 ) { + for (int i = page * count; i < (pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal() ); i++) { + result.add((DeviceChannel)redis.get((String)deviceChannelList.get(i))); + } + pageResult.setData(result); + } + + return pageResult; + } + + @Override + public List queryChannelsByDeviceId(String deviceId) { + List result = new ArrayList<>(); + List deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*"); + if (deviceChannelList != null && deviceChannelList.size() > 0 ) { + for (int i = 0; i < deviceChannelList.size(); i++) { + result.add((DeviceChannel)redis.get((String)deviceChannelList.get(i))); + } + } + return result; + } + + @Override + public PageResult querySubChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, String online, int page, int count) { + List allDeviceChannels = new ArrayList<>(); + String queryContent = "*"; + if (!StringUtils.isEmpty(query)) queryContent = String.format("*%S*",query); + String queryHasSubChannel = "*"; + if (hasSubChannel != null) queryHasSubChannel = hasSubChannel?"true":"false"; + String queryOnline = "*"; + if (!StringUtils.isEmpty(online)) queryOnline = online; + String queryStr = VideoManagerConstants.CACHEKEY_PREFIX + deviceId + + "_" + queryContent + // 搜索编号和名称 + "_" + queryOnline + // 搜索是否在线 + "_" + queryHasSubChannel + // 搜索是否含有子节点 + "_" + parentChannelId; + + List deviceChannelList = redis.keys(queryStr); + + if (deviceChannelList != null && deviceChannelList.size() > 0 ) { + for (int i = 0; i < deviceChannelList.size(); i++) { + DeviceChannel deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(i)); + if (deviceChannel.getParentId() != null && deviceChannel.getParentId().equals(parentChannelId)) { + allDeviceChannels.add(deviceChannel); + } + } + } + int maxCount = (page + 1 ) * count; + PageResult pageResult = new PageResult(); + pageResult.setPage(page); + pageResult.setCount(count); + pageResult.setTotal(allDeviceChannels.size()); + + if (allDeviceChannels.size() > 0) { + pageResult.setData(allDeviceChannels.subList( + page * count, pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal() + )); + } + return pageResult; + } + + public List querySubChannels(String deviceId, String parentChannelId) { + List allDeviceChannels = new ArrayList<>(); + List deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*"); + + if (deviceChannelList != null && deviceChannelList.size() > 0 ) { + for (int i = 0; i < deviceChannelList.size(); i++) { + DeviceChannel deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(i)); + if (deviceChannel.getParentId() != null && deviceChannel.getParentId().equals(parentChannelId)) { + allDeviceChannels.add(deviceChannel); + } + } + } + + return allDeviceChannels; + } + + @Override + public DeviceChannel queryChannel(String deviceId, String channelId) { + return (DeviceChannel)redis.get(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + channelId + "_"); + } + + + /** + * 获取多个设备 + * + * @param deviceIds 设备ID数组 + * @return List 设备对象数组 + */ + @Override + public PageResult queryVideoDeviceList(String[] deviceIds, int page, int count) { + List devices = new ArrayList<>(); + PageResult pageResult = new PageResult(); + pageResult.setPage(page); + pageResult.setCount(count); + + if (deviceIds == null || deviceIds.length == 0) { + + List deviceIdList = redis.keys(VideoManagerConstants.DEVICE_PREFIX+"*"); + pageResult.setTotal(deviceIdList.size()); + int maxCount = (page + 1)* count; + for (int i = page * count; i < (pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal() ); i++) { + devices.add((Device)redis.get((String)deviceIdList.get(i))); + } + } else { + for (int i = 0; i < deviceIds.length; i++) { + devices.add((Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceIds[i])); + } + } + pageResult.setData(devices); + return pageResult; + } + + /** + * 获取多个设备 + * + * @param deviceIds 设备ID数组 + * @return List 设备对象数组 + */ + @Override + public List queryVideoDeviceList(String[] deviceIds) { + List devices = new ArrayList<>(); + + if (deviceIds == null || deviceIds.length == 0) { + List deviceIdList = redis.keys(VideoManagerConstants.DEVICE_PREFIX+"*"); + for (int i = 0; i < deviceIdList.size(); i++) { + devices.add((Device)redis.get((String)deviceIdList.get(i))); + } + } else { + for (int i = 0; i < deviceIds.length; i++) { + devices.add((Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceIds[i])); + } + } + return devices; + } + + /** + * 删除设备 + * + * @param deviceId 设备ID + * @return true:删除成功 false:删除失败 + */ + @Override + public boolean delete(String deviceId) { + return redis.del(VideoManagerConstants.DEVICE_PREFIX+deviceId); + } + + /** + * 更新设备在线 + * + * @param deviceId 设备ID + * @return true:更新成功 false:更新失败 + */ + @Override + public boolean online(String deviceId) { + Device device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId); + device.setOnline(1); + return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device); + } + + /** + * 更新设备离线 + * + * @param deviceId 设备ID + * @return true:更新成功 false:更新失败 + */ + @Override + public boolean outline(String deviceId) { + Device device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId); + if (device == null) return false; + device.setOnline(0); + return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device); + } + + /** + * 开始播放时将流存入redis + * + * @param deviceId 设备ID + * @param channelId 通道ID + * @return + */ + @Override + public boolean startPlay(String deviceId, String channelId, StreamInfo stream) { + return redis.set(String.format("%S_%s_%s", VideoManagerConstants.PLAYER_PREFIX, deviceId, channelId), + stream); + } + + /** + * 停止播放时从redis删除 + * + * @param deviceId 设备ID + * @param channelId 通道ID + * @return + */ + @Override + public boolean stopPlay(String deviceId, String channelId) { + return redis.del(String.format("%S_%s_%s", VideoManagerConstants.PLAYER_PREFIX, deviceId, channelId)); + } + + /** + * 查询播放列表 + * @param deviceId 设备ID + * @param channelId 通道ID + * @return + */ + @Override + public StreamInfo queryPlay(String deviceId, String channelId) { + return (StreamInfo)redis.get(String.format("%S_%s_%s", VideoManagerConstants.PLAYER_PREFIX, deviceId, channelId)); + } + + + + /** + * 更新流媒体信息 + * @param mediaServerConfig + * @return + */ + @Override + public boolean updateMediaInfo(MediaServerConfig mediaServerConfig) { + return redis.set(VideoManagerConstants.MEDIA_SERVER_PREFIX,mediaServerConfig); + } + + /** + * 获取流媒体信息 + * @return + */ + @Override + public MediaServerConfig getMediaInfo() { + return (MediaServerConfig)redis.get(VideoManagerConstants.MEDIA_SERVER_PREFIX); + } + + @Override + public void updateCatch() { + deviceMap = new HashMap<>(); + // 更新设备 + List devices = queryVideoDeviceList(null); + if (devices == null && devices.size() == 0) return; + for (Device device : devices) { + // 更新设备下的通道 + HashMap> channelMap = new HashMap>(); + List deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + + device.getDeviceId() + "_" + "*"); + if (deviceChannelList != null && deviceChannelList.size() > 0 ) { + for (int i = 0; i < deviceChannelList.size(); i++) { + String key = (String)deviceChannelList.get(i); + String[] s = key.split("_"); + String channelId = s[3]; + HashSet subChannel = channelMap.get(channelId); + if (subChannel == null) { + subChannel = new HashSet<>(); + } + if (s.length > 4) { + subChannel.add(s[4]); + } + channelMap.put(channelId, subChannel); + System.out.println(); + } + } + deviceMap.put(device.getDeviceId(),channelMap); + } + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java index 9b229acd..7958a8a1 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java @@ -9,12 +9,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.CrossOrigin; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import org.springframework.web.context.request.async.DeferredResult; import com.alibaba.fastjson.JSONObject; @@ -72,12 +67,17 @@ public class DeviceController { * @return 通道列表 */ @GetMapping("devices/{deviceId}/channels") - public ResponseEntity channels(@PathVariable String deviceId, int page, int count){ + public ResponseEntity channels(@PathVariable String deviceId, + int page, int count, + @RequestParam(required = false) String query, + @RequestParam(required = false) String online, + @RequestParam(required = false) Boolean channelType + ){ if (logger.isDebugEnabled()) { logger.debug("查询所有视频设备API调用"); } - PageResult pageResult = storager.queryChannelsByDeviceId(deviceId, page, count); + PageResult pageResult = storager.queryChannelsByDeviceId(deviceId, query, channelType, online, page, count); return new ResponseEntity<>(pageResult,HttpStatus.OK); } @@ -115,4 +115,33 @@ public class DeviceController { return new ResponseEntity("设备预览API调用失败!", HttpStatus.INTERNAL_SERVER_ERROR); } } + + /** + * 分页查询通道数 + * @param channelId 通道id + * @param page 当前页 + * @param count 每页条数 + * @return 子通道列表 + */ + @GetMapping("subChannels/{deviceId}/{channelId}/channels") + public ResponseEntity subChannels(@PathVariable String deviceId, + @PathVariable String channelId, + int page, + int count, + @RequestParam(required = false) String query, + @RequestParam(required = false) String online, + @RequestParam(required = false) Boolean channelType){ + + if (logger.isDebugEnabled()) { + logger.debug("查询所有视频设备API调用"); + } + DeviceChannel deviceChannel = storager.queryChannel(deviceId,channelId); + if (deviceChannel == null) { + PageResult deviceChannelPageResult = new PageResult<>(); + new ResponseEntity<>(deviceChannelPageResult,HttpStatus.OK); + } + + PageResult pageResult = storager.querySubChannels(deviceId, channelId, query, channelType, online, page, count); + return new ResponseEntity<>(pageResult,HttpStatus.OK); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java b/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java index 57b102c8..ce3b7ec8 100644 --- a/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java +++ b/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java @@ -68,7 +68,7 @@ public class ApiDeviceController { devices = storager.queryVideoDeviceList(null); result.put("DeviceCount", devices.size()); }else { - PageResult deviceList = storager.queryVideoDeviceList(null, start, limit); + PageResult deviceList = storager.queryVideoDeviceList(null, start/limit, limit); result.put("DeviceCount", deviceList.getTotal()); devices = deviceList.getData(); } @@ -123,7 +123,7 @@ public class ApiDeviceController { deviceChannels = storager.queryChannelsByDeviceId(serial); result.put("ChannelCount", deviceChannels.size()); }else { - PageResult pageResult = storager.queryChannelsByDeviceId(serial, start, limit); + PageResult pageResult = storager.queryChannelsByDeviceId(serial, null, null, null,start/limit, limit); result.put("ChannelCount", pageResult.getTotal()); deviceChannels = pageResult.getData(); } @@ -139,7 +139,7 @@ public class ApiDeviceController { deviceJOSNChannel.put("Name", deviceChannel.getName()); deviceJOSNChannel.put("Custom", false); deviceJOSNChannel.put("CustomName", ""); - deviceJOSNChannel.put("SubCount", 0); // TODO ? 子节点数, SubCount > 0 表示该通道为子目录 + deviceJOSNChannel.put("SubCount", deviceChannel.getSubCount()); // TODO ? 子节点数, SubCount > 0 表示该通道为子目录 deviceJOSNChannel.put("SnapURL", ""); deviceJOSNChannel.put("Manufacturer ", deviceChannel.getManufacture()); deviceJOSNChannel.put("Model", deviceChannel.getModel()); diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index b59b1398..235caa68 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -12,7 +12,7 @@ spring: port: 6379 database: 6 #访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接 - password: + password: 4767cb971b40a1300fa09b7f87b09d1c #超时时间 timeout: 10000 datasource: @@ -31,8 +31,8 @@ sip: # 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007) # 后两位为行业编码,定义参照附录D.3 # 3701020049标识山东济南历下区 信息行业接入 - domain: 3701020049 - id: 37010200492000000001 + domain: 3402000000 + id: 34020000002000000001 # 默认设备认证密码,后续扩展使用设备单独密码 password: 12345678 media: