Commit 59d8f2f9152b3c3106abae64bef343cde842f225

Authored by 648540858
1 parent 51634b1b

支持录像回放使用固定流地址以及自动点播录像回放

sql/2.6.9更新.sql 0 → 100644
  1 +alter table wvp_device_channel
  2 + change stream_id stream_id varying(255)
0 \ No newline at end of file 3 \ No newline at end of file
sql/初始化.sql
@@ -79,7 +79,7 @@ create table wvp_device_channel ( @@ -79,7 +79,7 @@ create table wvp_device_channel (
79 custom_longitude double precision, 79 custom_longitude double precision,
80 latitude double precision, 80 latitude double precision,
81 custom_latitude double precision, 81 custom_latitude double precision,
82 - stream_id character varying(50), 82 + stream_id character varying(255),
83 device_id character varying(50) not null, 83 device_id character varying(50) not null,
84 parental character varying(50), 84 parental character varying(50),
85 has_audio bool default false, 85 has_audio bool default false,
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
@@ -59,6 +59,7 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp @@ -59,6 +59,7 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
59 // 未注册的设备不做处理 59 // 未注册的设备不做处理
60 return; 60 return;
61 } 61 }
  62 + logger.info("[收到心跳], device: {}", device.getDeviceId());
62 SIPRequest request = (SIPRequest) evt.getRequest(); 63 SIPRequest request = (SIPRequest) evt.getRequest();
63 // 回复200 OK 64 // 回复200 OK
64 try { 65 try {
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -24,8 +24,10 @@ import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; @@ -24,8 +24,10 @@ import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
24 import com.genersoft.iot.vmp.media.zlm.dto.hook.*; 24 import com.genersoft.iot.vmp.media.zlm.dto.hook.*;
25 import com.genersoft.iot.vmp.service.*; 25 import com.genersoft.iot.vmp.service.*;
26 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; 26 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
  27 +import com.genersoft.iot.vmp.service.bean.SSRCInfo;
27 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 28 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
28 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 29 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
  30 +import com.genersoft.iot.vmp.utils.DateUtil;
29 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; 31 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
30 import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo; 32 import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo;
31 import com.genersoft.iot.vmp.vmanager.bean.StreamContent; 33 import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
@@ -559,7 +561,7 @@ public class ZLMHttpHookListener { @@ -559,7 +561,7 @@ public class ZLMHttpHookListener {
559 561
560 if ("rtp".equals(param.getApp())) { 562 if ("rtp".equals(param.getApp())) {
561 String[] s = param.getStream().split("_"); 563 String[] s = param.getStream().split("_");
562 - if (!mediaInfo.isRtpEnable() || s.length != 2) { 564 + if (!mediaInfo.isRtpEnable() || (s.length != 2 && s.length != 4)) {
563 defaultResult.setResult(HookResult.SUCCESS()); 565 defaultResult.setResult(HookResult.SUCCESS());
564 return defaultResult; 566 return defaultResult;
565 } 567 }
@@ -575,33 +577,79 @@ public class ZLMHttpHookListener { @@ -575,33 +577,79 @@ public class ZLMHttpHookListener {
575 defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg())); 577 defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg()));
576 return defaultResult; 578 return defaultResult;
577 } 579 }
578 - logger.info("[ZLM HOOK] 流未找到, 发起自动点播:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());  
579 -  
580 - RequestMessage msg = new RequestMessage();  
581 - String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId;  
582 - boolean exist = resultHolder.exist(key, null);  
583 - msg.setKey(key);  
584 - String uuid = UUID.randomUUID().toString();  
585 - msg.setId(uuid);  
586 - DeferredResult<HookResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());  
587 -  
588 - result.onTimeout(() -> {  
589 - logger.info("[ZLM HOOK] 自动点播, 等待超时");  
590 - // 释放rtpserver  
591 - msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时"));  
592 - resultHolder.invokeResult(msg);  
593 - });  
594 -  
595 - // 录像查询以channelId作为deviceId查询  
596 - resultHolder.put(key, uuid, result);  
597 -  
598 - if (!exist) {  
599 - playService.play(mediaInfo, deviceId, channelId, null, (code, message, data) -> {  
600 - msg.setData(new HookResult(code, message)); 580 + if (s.length == 2) {
  581 + logger.info("[ZLM HOOK] 预览流未找到, 发起自动点播:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
  582 +
  583 + RequestMessage msg = new RequestMessage();
  584 + String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId;
  585 + boolean exist = resultHolder.exist(key, null);
  586 + msg.setKey(key);
  587 + String uuid = UUID.randomUUID().toString();
  588 + msg.setId(uuid);
  589 + DeferredResult<HookResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
  590 +
  591 + result.onTimeout(() -> {
  592 + logger.info("[ZLM HOOK] 预览流自动点播, 等待超时");
  593 + // 释放rtpserver
  594 + msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时"));
601 resultHolder.invokeResult(msg); 595 resultHolder.invokeResult(msg);
602 }); 596 });
  597 +
  598 + resultHolder.put(key, uuid, result);
  599 +
  600 + if (!exist) {
  601 + playService.play(mediaInfo, deviceId, channelId, null, (code, message, data) -> {
  602 + msg.setData(new HookResult(code, message));
  603 + resultHolder.invokeResult(msg);
  604 + });
  605 + }
  606 + return result;
  607 + }else if(s.length == 4){
  608 + // 此时为录像回放, 录像回放格式为> 设备ID_通道ID_开始时间_结束时间
  609 + String startTimeStr = s[2];
  610 + String endTimeStr = s[3];
  611 + if (startTimeStr == null || endTimeStr == null || startTimeStr.length() != 14 || endTimeStr.length() != 14) {
  612 + defaultResult.setResult(HookResult.SUCCESS());
  613 + return defaultResult;
  614 + }
  615 + String startTime = DateUtil.urlToyyyy_MM_dd_HH_mm_ss(startTimeStr);
  616 + String endTime = DateUtil.urlToyyyy_MM_dd_HH_mm_ss(endTimeStr);
  617 + logger.info("[ZLM HOOK] 回放流未找到, 发起自动点播:{}->{}->{}/{}-{}-{}",
  618 + param.getMediaServerId(), param.getSchema(),
  619 + param.getApp(), param.getStream(),
  620 + startTime, endTime
  621 + );
  622 + RequestMessage msg = new RequestMessage();
  623 + String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId;
  624 + boolean exist = resultHolder.exist(key, null);
  625 + msg.setKey(key);
  626 + String uuid = UUID.randomUUID().toString();
  627 + msg.setId(uuid);
  628 + DeferredResult<HookResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
  629 +
  630 + result.onTimeout(() -> {
  631 + logger.info("[ZLM HOOK] 回放流自动点播, 等待超时");
  632 + // 释放rtpserver
  633 + msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时"));
  634 + resultHolder.invokeResult(msg);
  635 + });
  636 +
  637 + resultHolder.put(key, uuid, result);
  638 +
  639 + if (!exist) {
  640 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaInfo, param.getStream(), null,
  641 + device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam());
  642 + playService.playBack(mediaInfo, ssrcInfo, deviceId, channelId, startTime, endTime, (code, message, data) -> {
  643 + msg.setData(new HookResult(code, message));
  644 + resultHolder.invokeResult(msg);
  645 + });
  646 + }
  647 + return result;
  648 + }else {
  649 + defaultResult.setResult(HookResult.SUCCESS());
  650 + return defaultResult;
603 } 651 }
604 - return result; 652 +
605 } else { 653 } else {
606 // 拉流代理 654 // 拉流代理
607 StreamProxyItem streamProxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream()); 655 StreamProxyItem streamProxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream());
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
@@ -29,7 +29,6 @@ public interface IPlayService { @@ -29,7 +29,6 @@ public interface IPlayService {
29 29
30 void playBack(String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback); 30 void playBack(String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback);
31 void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback); 31 void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback);
32 -  
33 void zlmServerOffline(String mediaServerId); 32 void zlmServerOffline(String mediaServerId);
34 33
35 void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback); 34 void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback);
@@ -44,4 +43,6 @@ public interface IPlayService { @@ -44,4 +43,6 @@ public interface IPlayService {
44 void resumeRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException; 43 void resumeRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException;
45 44
46 void getSnap(String deviceId, String channelId, String fileName, ErrorCallback errorCallback); 45 void getSnap(String deviceId, String channelId, String fileName, ErrorCallback errorCallback);
  46 +
  47 +
47 } 48 }
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -539,7 +539,19 @@ public class PlayServiceImpl implements IPlayService { @@ -539,7 +539,19 @@ public class PlayServiceImpl implements IPlayService {
539 return; 539 return;
540 } 540 }
541 MediaServerItem newMediaServerItem = getNewMediaServerItem(device); 541 MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
542 - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam()); 542 + String stream = null;
  543 + if (newMediaServerItem.isRtpEnable()) {
  544 + String startTimeStr = startTime.replace("-", "")
  545 + .replace(":", "")
  546 + .replace(" ", "");
  547 + System.out.println(startTimeStr);
  548 + String endTimeTimeStr = endTime.replace("-", "")
  549 + .replace(":", "")
  550 + .replace(" ", "");
  551 + System.out.println(endTimeTimeStr);
  552 + stream = deviceId + "_" + channelId + "_" + startTimeStr + "_" + endTimeTimeStr;
  553 + }
  554 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, stream, null, device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam());
543 playBack(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, callback); 555 playBack(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, callback);
544 } 556 }
545 557
src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java
@@ -53,6 +53,10 @@ public class DateUtil { @@ -53,6 +53,10 @@ public class DateUtil {
53 return formatter.format(formatterCompatibleISO8601.parse(formatTime)); 53 return formatter.format(formatterCompatibleISO8601.parse(formatTime));
54 } 54 }
55 55
  56 + public static String urlToyyyy_MM_dd_HH_mm_ss(String formatTime) {
  57 + return formatter.format(urlFormatter.parse(formatTime));
  58 + }
  59 +
56 /** 60 /**
57 * yyyy_MM_dd_HH_mm_ss 转时间戳 61 * yyyy_MM_dd_HH_mm_ss 转时间戳
58 * @param formatTime 62 * @param formatTime
@@ -82,6 +86,7 @@ public class DateUtil { @@ -82,6 +86,7 @@ public class DateUtil {
82 return urlFormatter.format(nowDateTime); 86 return urlFormatter.format(nowDateTime);
83 } 87 }
84 88
  89 +
85 /** 90 /**
86 * 格式校验 91 * 格式校验
87 * @param timeStr 时间字符串 92 * @param timeStr 时间字符串