src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -329,7 +329,7 @@ streamInfo.setSsrc(ssrc); streamInfo.setCahnnelId(channelId); streamInfo.setDeviceID(device.getDeviceId()); boolean b = storager.startPlayBlack(streamInfo); boolean b = storager.startPlayback(streamInfo); return streamInfo; } catch ( SipException | ParseException | InvalidArgumentException e) { src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
@@ -106,6 +106,7 @@ /** * 收到deviceInfo设备信息请求 处理 * * @param evt */ private void processMessageDeviceInfo(RequestEvent evt) { @@ -132,13 +133,19 @@ msg.setType(DeferredResultHolder.CALLBACK_CMD_DEVICEINFO); msg.setData(device); deferredResultHolder.invokeResult(msg); } catch (DocumentException e) { // 回复200 OK responseAck(evt); if (offLineDetector.isOnline(deviceId)) { publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE); } } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { e.printStackTrace(); } } /*** * 收到catalog设备目录列表请求 处理 * * @param evt */ private void processMessageCatalogList(RequestEvent evt) { @@ -184,21 +191,30 @@ deviceChannel.setCivilCode(XmlUtil.getText(itemDevice,"CivilCode")); 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.setParental(itemDevice.element("Parental") == null ? 0 : Integer.parseInt(XmlUtil.getText(itemDevice, "Parental"))); 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.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")); deviceChannel.setCertifiable(itemDevice.element("Certifiable") == null? 0:Integer.parseInt(XmlUtil.getText(itemDevice,"Certifiable"))); deviceChannel.setErrCode(itemDevice.element("ErrCode") == null? 0:Integer.parseInt(XmlUtil.getText(itemDevice,"ErrCode"))); deviceChannel.setCertifiable(itemDevice.element("Certifiable") == null ? 0 : Integer.parseInt(XmlUtil.getText(itemDevice, "Certifiable"))); deviceChannel.setErrCode(itemDevice.element("ErrCode") == null ? 0 : Integer.parseInt(XmlUtil.getText(itemDevice, "ErrCode"))); deviceChannel.setEndTime(XmlUtil.getText(itemDevice,"EndTime")); deviceChannel.setSecrecy(XmlUtil.getText(itemDevice,"Secrecy")); deviceChannel.setIpAddress(XmlUtil.getText(itemDevice,"IPAddress")); deviceChannel.setPort(itemDevice.element("Port") == null? 0:Integer.parseInt(XmlUtil.getText(itemDevice,"Port"))); deviceChannel.setPort(itemDevice.element("Port") == null ? 0 : Integer.parseInt(XmlUtil.getText(itemDevice, "Port"))); deviceChannel.setPassword(XmlUtil.getText(itemDevice,"Password")); deviceChannel.setLongitude(itemDevice.element("Longitude") == null? 0.00:Double.parseDouble(XmlUtil.getText(itemDevice,"Longitude"))); deviceChannel.setLatitude(itemDevice.element("Latitude") == null? 0.00:Double.parseDouble(XmlUtil.getText(itemDevice,"Latitude"))); deviceChannel.setPTZType(itemDevice.element("PTZType") == null? 0:Integer.parseInt(XmlUtil.getText(itemDevice,"PTZType"))); deviceChannel.setLongitude(itemDevice.element("Longitude") == null ? 0.00 : Double.parseDouble(XmlUtil.getText(itemDevice, "Longitude"))); deviceChannel.setLatitude(itemDevice.element("Latitude") == null ? 0.00 : Double.parseDouble(XmlUtil.getText(itemDevice, "Latitude"))); deviceChannel.setPTZType(itemDevice.element("PTZType") == null ? 0 : Integer.parseInt(XmlUtil.getText(itemDevice, "PTZType"))); deviceChannel.setHasAudio(true); // 默认含有音频,播放时再检查是否有音频及是否AAC storager.updateChannel(device.getDeviceId(), deviceChannel); } @@ -208,13 +224,11 @@ msg.setType(DeferredResultHolder.CALLBACK_CMD_CATALOG); msg.setData(device); deferredResultHolder.invokeResult(msg); // 回复200 if (offLineDetector.isOnline(deviceId)) { // 回复200 OK responseAck(evt); if (offLineDetector.isOnline(deviceId)) { publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE); } } } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { e.printStackTrace(); @@ -223,6 +237,7 @@ /*** * 收到alarm设备报警信息 处理 * * @param evt */ private void processMessageAlarm(RequestEvent evt) { @@ -246,21 +261,29 @@ } storager.updateDevice(device); cmder.catalogQuery(device); } catch (DocumentException e) { // 回复200 OK responseAck(evt); if (offLineDetector.isOnline(deviceId)) { publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE); } } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { // } catch (DocumentException e) { e.printStackTrace(); } } /*** * 收到keepalive请求 处理 * * @param evt */ private void processMessageKeepAlive(RequestEvent evt){ try { Element rootElement = getRootElement(evt); String deviceId = XmlUtil.getText(rootElement,"DeviceID"); if (offLineDetector.isOnline(deviceId)) { // 回复200 OK responseAck(evt); if (offLineDetector.isOnline(deviceId)) { publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE); } else { } @@ -270,12 +293,14 @@ } /*** * 收到catalog设备目录列表请求 处理 * TODO 过期时间暂时写死180秒,后续与DeferredResult超时时间保持一致 * 收到catalog设备目录列表请求 处理 TODO 过期时间暂时写死180秒,后续与DeferredResult超时时间保持一致 * * @param evt */ private void processMessageRecordInfo(RequestEvent evt) { try { // 回复200 OK responseAck(evt); RecordInfo recordInfo = new RecordInfo(); Element rootElement = getRootElement(evt); Element deviceIdElement = rootElement.element("DeviceID"); @@ -286,6 +311,8 @@ String sn = XmlUtil.getText(rootElement,"SN"); Element recordListElement = rootElement.element("RecordList"); if (recordListElement == null) { logger.info("无录像数据"); // responseAck(evt); return; } @@ -293,11 +320,13 @@ List<RecordItem> recordList = new ArrayList<RecordItem>(); if (recordListIterator != null) { RecordItem record = new RecordItem(); logger.info("处理录像列表数据..."); // 遍历DeviceList while (recordListIterator.hasNext()) { Element itemRecord = recordListIterator.next(); Element recordElement = itemRecord.element("DeviceID"); if (recordElement == null) { logger.info("记录为空,下一个..."); continue; } record = new RecordItem(); @@ -305,9 +334,11 @@ record.setName(XmlUtil.getText(itemRecord,"Name")); record.setFilePath(XmlUtil.getText(itemRecord,"FilePath")); record.setAddress(XmlUtil.getText(itemRecord,"Address")); record.setStartTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(XmlUtil.getText(itemRecord,"StartTime"))); record.setStartTime( DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(XmlUtil.getText(itemRecord, "StartTime"))); record.setEndTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(XmlUtil.getText(itemRecord,"EndTime"))); record.setSecrecy(itemRecord.element("Secrecy") == null? 0:Integer.parseInt(XmlUtil.getText(itemRecord,"Secrecy"))); record.setSecrecy(itemRecord.element("Secrecy") == null ? 0 : Integer.parseInt(XmlUtil.getText(itemRecord, "Secrecy"))); record.setType(XmlUtil.getText(itemRecord,"Type")); record.setRecorderId(XmlUtil.getText(itemRecord,"RecorderID")); recordList.add(record); @@ -328,17 +359,21 @@ } // 本分支表示录像列表被拆包,且加上之前的数据还是不够,保存缓存返回,等待下个包再处理 if (recordList.size() < recordInfo.getSumNum()) { redis.set(cacheKey, recordList, 180); logger.info("已获取" + recordList.size() + "项录像数据,共" + recordInfo.getSumNum() + "项"); redis.set(cacheKey, recordList, 90); return; } else { // 本分支表示录像被拆包,但加上之前的数据够足够,返回响应 // 因设备心跳有监听redis过期机制,为提高性能,此处手动删除 logger.info("录像数据已全部获取"); redis.del(cacheKey); } } else { // 本分支有两种可能:1、录像列表被拆包,且是第一个包,直接保存缓存返回,等待下个包再处理 // 2、之前有包,但超时清空了,那么这次sn批次的响应数据已经不完整,等待过期时间后redis自动清空数据 redis.set(cacheKey, recordList, 180); logger.info("等待后续的包..."); redis.set(cacheKey, recordList, 90); return; } @@ -355,7 +390,8 @@ recordInfo.getRecordList().sort(Comparator.naturalOrder()); msg.setData(recordInfo); deferredResultHolder.invokeResult(msg); } catch (DocumentException e) { logger.info("处理完成,返回结果"); } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { e.printStackTrace(); } } src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -142,7 +142,7 @@ storager.startPlay(streamInfoForPlay); } StreamInfo streamInfoForPlayBack = storager.queryPlayBlackBySSRC(ssrc); StreamInfo streamInfoForPlayBack = storager.queryPlaybackBySSRC(ssrc); if ("rtp".equals(app) && streamInfoForPlayBack != null ) { MediaServerConfig mediaInfo = storager.getMediaInfo(); streamInfoForPlayBack.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId)); @@ -150,7 +150,7 @@ streamInfoForPlayBack.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getLocalIP(), mediaInfo.getRtmpPort(), streamId)); streamInfoForPlayBack.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId)); streamInfoForPlayBack.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getLocalIP(), mediaInfo.getRtspPort(), streamId)); storager.startPlayBlack(streamInfoForPlayBack); storager.startPlayback(streamInfoForPlayBack); } // TODO Auto-generated method stub @@ -261,7 +261,12 @@ String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16)); StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc); if ("rtp".equals(app) && !regist ) { if (streamInfo!=null){ storager.stopPlay(streamInfo); }else{ streamInfo = storager.queryPlaybackBySSRC(ssrc); storager.stopPlayback(streamInfo); } } @@ -288,6 +293,13 @@ String ssrc = String.format("%010d", numb); cmder.streamByeCmd(ssrc); StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc); if (streamInfo!=null){ storager.stopPlay(streamInfo); }else{ streamInfo = storager.queryPlaybackBySSRC(ssrc); storager.stopPlayback(streamInfo); } JSONObject ret = new JSONObject(); ret.put("code", 0); src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
@@ -184,11 +184,11 @@ Map<String, StreamInfo> queryPlayByDeviceId(String deviceId); boolean startPlayBlack(StreamInfo streamInfo); boolean startPlayback(StreamInfo streamInfo); boolean stopPlayBlack(StreamInfo streamInfo); boolean stopPlayback(StreamInfo streamInfo); StreamInfo queryPlayBlackByDevice(String deviceId, String channelId); StreamInfo queryPlaybackByDevice(String deviceId, String channelId); StreamInfo queryPlayBlackBySSRC(String ssrc); StreamInfo queryPlaybackBySSRC(String ssrc); } src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java
@@ -195,22 +195,22 @@ } @Override public boolean startPlayBlack(StreamInfo streamInfo) { public boolean startPlayback(StreamInfo streamInfo) { return false; } @Override public boolean stopPlayBlack(StreamInfo streamInfo) { public boolean stopPlayback(StreamInfo streamInfo) { return false; } @Override public StreamInfo queryPlayBlackByDevice(String deviceId, String channelId) { public StreamInfo queryPlaybackByDevice(String deviceId, String channelId) { return null; } @Override public StreamInfo queryPlayBlackBySSRC(String ssrc) { public StreamInfo queryPlaybackBySSRC(String ssrc) { return null; } } src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java
@@ -409,7 +409,7 @@ } @Override public StreamInfo queryPlayBlackBySSRC(String ssrc) { public StreamInfo queryPlaybackBySSRC(String ssrc) { // List<Object> playLeys = redis.keys(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, ssrc)); List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAY_BLACK_PREFIX, ssrc)); if (playLeys == null || playLeys.size() == 0) return null; @@ -505,14 +505,14 @@ @Override public boolean startPlayBlack(StreamInfo stream) { public boolean startPlayback(StreamInfo stream) { return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, stream.getSsrc(),stream.getDeviceID(), stream.getCahnnelId()), stream); } @Override public boolean stopPlayBlack(StreamInfo streamInfo) { public boolean stopPlayback(StreamInfo streamInfo) { if (streamInfo == null) return false; DeviceChannel deviceChannel = queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId()); if (deviceChannel != null) { @@ -527,7 +527,7 @@ } @Override public StreamInfo queryPlayBlackByDevice(String deviceId, String code) { public StreamInfo queryPlaybackByDevice(String deviceId, String code) { String format = String.format("%S_*_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, deviceId, code); src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
@@ -60,34 +60,40 @@ String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase(); // 等待推流, TODO 默认超时30s boolean lockFlag = true; boolean rtpPushed = false; long startTime = System.currentTimeMillis(); JSONObject rtpInfo = null; while (lockFlag) { try { if (System.currentTimeMillis() - startTime > 30 * 1000) { if (System.currentTimeMillis() - startTime > 60 * 1000) { storager.stopPlay(streamInfo); logger.info("播放等待超时"); return new ResponseEntity<String>("timeout",HttpStatus.OK); }else { streamInfo = storager.queryPlayByDevice(deviceId, channelId); JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId); if (!rtpPushed) { logger.info("查询RTP推流信息..."); rtpInfo = zlmresTfulUtils.getRtpInfo(streamId); } if (rtpInfo != null && rtpInfo.getBoolean("exist") && streamInfo != null && streamInfo.getFlv() != null){ logger.info("RTP已推流,查询编码信息:"+streamInfo.getFlv()); logger.info("查询流编码信息:" + streamInfo.getFlv()); rtpPushed = true; Thread.sleep(2000); JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo("rtp", "rtmp", streamId); if (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online")) { lockFlag = false; logger.info("媒体编码信息已获取"); logger.info("流编码信息已获取"); JSONArray tracks = mediaInfo.getJSONArray("tracks"); streamInfo.setTracks(tracks); storager.startPlay(streamInfo); }else { logger.info("媒体编码信息未获取,2秒后重试..."); logger.info("流编码信息未获取,2秒后重试..."); } }else { Thread.sleep(2000); continue; }; } } } catch (InterruptedException e) { e.printStackTrace(); @@ -96,7 +102,8 @@ if (logger.isDebugEnabled()) { logger.debug(String.format("设备预览 API调用,deviceId:%s ,channelId:%s",deviceId, channelId)); logger.debug("设备预览 API调用,ssrc:"+streamInfo.getSsrc()+",ZLMedia streamId:"+Integer.toHexString(Integer.parseInt(streamInfo.getSsrc()))); logger.debug("设备预览 API调用,ssrc:" + streamInfo.getSsrc() + ",ZLMedia streamId:" + Integer.toHexString(Integer.parseInt(streamInfo.getSsrc()))); } if(streamInfo!=null) { @@ -112,7 +119,8 @@ cmder.streamByeCmd(ssrc); StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc); if (streamInfo == null) return new ResponseEntity<String>(HttpStatus.PAYMENT_REQUIRED); if (streamInfo == null) return new ResponseEntity<String>(HttpStatus.PAYMENT_REQUIRED); storager.stopPlay(streamInfo); if (logger.isDebugEnabled()) { logger.debug(String.format("设备预览停止API调用,ssrc:%s", ssrc)); src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java
@@ -52,7 +52,7 @@ } Device device = storager.queryVideoDevice(deviceId); StreamInfo streamInfo = storager.queryPlayBlackByDevice(deviceId, channelId); StreamInfo streamInfo = storager.queryPlaybackByDevice(deviceId, channelId); if (streamInfo != null) { cmder.streamByeCmd(streamInfo.getSsrc()); @@ -64,7 +64,7 @@ // if (rtpInfo.getBoolean("exist")) { // return new ResponseEntity<String>(JSON.toJSONString(streamInfo),HttpStatus.OK); // }else { // storager.stopPlayBlack(streamInfo); // storager.stopPlayback(streamInfo); // streamInfo = cmder.playbackStreamCmd(device, channelId, startTime, endTime); // } // } @@ -77,29 +77,40 @@ } // 等待推流, TODO 默认超时15s boolean lockFlag = true; boolean rtpPushed = false; long lockStartTime = System.currentTimeMillis(); JSONObject rtpInfo = null; while (lockFlag) { try { if (System.currentTimeMillis() - lockStartTime > 75 * 1000) { storager.stopPlayBlack(streamInfo); storager.stopPlayback(streamInfo); logger.info("播放等待超时"); return new ResponseEntity<String>("timeout",HttpStatus.OK); }else { streamInfo = storager.queryPlayBlackByDevice(deviceId, channelId); JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId); if (rtpInfo != null && rtpInfo.getBoolean("exist") && streamInfo.getFlv() != null){ streamInfo = storager.queryPlaybackByDevice(deviceId, channelId); if (!rtpPushed) { logger.info("查询RTP推流信息..."); rtpInfo = zlmresTfulUtils.getRtpInfo(streamId); } if (rtpInfo != null && rtpInfo.getBoolean("exist") && streamInfo != null && streamInfo.getFlv() != null){ logger.info("查询流编码信息:"+streamInfo.getFlv()); rtpPushed = true; Thread.sleep(2000); JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo("rtp", "rtmp", streamId); if (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online")) { lockFlag = false; logger.info("流编码信息已获取"); JSONArray tracks = mediaInfo.getJSONArray("tracks"); streamInfo.setTracks(tracks); storager.startPlayBlack(streamInfo); storager.startPlayback(streamInfo); }else { logger.info("流编码信息未获取,2秒后重试..."); } }else { Thread.sleep(2000); continue; }; } } } catch (InterruptedException e) { e.printStackTrace(); web_src/src/components/gb28181/devicePlayer.vue
@@ -25,8 +25,7 @@ </el-tab-pane> <!--{"code":0,"data":{"paths":["22-29-30.mp4"],"rootPath":"/home/kkkkk/Documents/ZLMediaKit/release/linux/Debug/www/record/hls/kkkkk/2020-05-11/"}}--> <el-tab-pane label="录像查询" name="record"> <el-date-picker size="mini" v-model="videoHistory.date" type="date" value-format="yyyy-MM-dd" placeholder="日期" @change="queryRecords()"></el-date-picker> <el-date-picker size="mini" v-model="videoHistory.date" type="date" value-format="yyyy-MM-dd" placeholder="日期" @change="queryRecords()"></el-date-picker> <!-- <el-slider style="margin: 0 1rem 1rem 1rem;"--> <!-- v-model="timeVal"--> <!-- :min="timeMin"--> @@ -77,10 +76,8 @@ <div class="control-round"> <div class="control-round-inner"><i class="fa fa-pause-circle"></i></div> </div> <div style="position: absolute; left: 7.25rem; top: 1.25rem" @mousedown="ptzCamera(0, 0, 2)" @mouseup="ptzCamera(0, 0, 0)"><i class="el-icon-zoom-in" style="font-size: 1.875rem;"></i></div> <div style="position: absolute; left: 7.25rem; top: 3.25rem; font-size: 1.875rem;" @mousedown="ptzCamera(0, 0, 1)" @mouseup="ptzCamera(0, 0, 0)"><i class="el-icon-zoom-out"></i></div> <div style="position: absolute; left: 7.25rem; top: 1.25rem" @mousedown="ptzCamera(0, 0, 2)" @mouseup="ptzCamera(0, 0, 0)"><i class="el-icon-zoom-in" style="font-size: 1.875rem;"></i></div> <div style="position: absolute; left: 7.25rem; top: 3.25rem; font-size: 1.875rem;" @mousedown="ptzCamera(0, 0, 1)" @mouseup="ptzCamera(0, 0, 0)"><i class="el-icon-zoom-out"></i></div> </div> </div> @@ -108,8 +105,7 @@ }; } }, created() { }, created() {}, data() { return { video:'http://lndxyj.iqilu.com/public/upload/2019/10/14/8c001ea0c09cdc59a57829dabc8010fa.mp4', @@ -241,6 +237,7 @@ return; } this.recordsLoading = true; this.videoHistory.searchHistoryResult = []; let that = this; var startTime = this.videoHistory.date + " 00:00:00"; var endTime = this.videoHistory.date + " 23:59:59"; @@ -252,6 +249,7 @@ that.videoHistory.searchHistoryResult = res.data.recordList; that.recordsLoading = false; }).catch(function(e) { console.log(e.message); // that.videoHistory.searchHistoryResult = falsificationData.recordData; });