From 3e162ea358c60c2e8952aebb1b5420a9d41dcee9 Mon Sep 17 00:00:00 2001 From: lin <648540858@qq.com> Date: Tue, 14 Apr 2026 18:11:14 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=94=99=E8=AF=AF=E5=A4=84?= =?UTF-8?q?=E7=90=86=EF=BC=8C=E5=9B=9E=E6=BB=9A=E6=92=AD=E6=94=BE=E5=99=A8?= =?UTF-8?q?=E7=89=88=E6=9C=AC=EF=BC=8C=E9=87=8D=E6=9E=84RTP=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E5=99=A8=E6=8E=A5=E5=8F=A3=E4=BB=A5=E5=8C=BA=E5=88=86?= =?UTF-8?q?=E4=B8=8D=E5=90=8C=E7=9A=84=E6=8E=A5=E5=8F=A3=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96=E5=8F=82=E6=95=B0=E6=95=B0=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/vmp/common/VideoManagerConstants.java | 1 + .../iot/vmp/common/enums/MediaStreamUtil.java | 2 +- .../service/impl/PlatformServiceImpl.java | 52 +-- .../gb28181/service/impl/PlayServiceImpl.java | 13 +- .../cmd/impl/SIPCommanderForPlatform.java | 10 +- .../service/impl/jt1078PlayServiceImpl.java | 4 +- .../vmp/media/zlm/dto/hook/HookResult.java | 20 +- .../vmp/service/IReceiveRtpServerService.java | 17 +- .../iot/vmp/service/bean/SSRCInfo.java | 4 +- .../service/impl/RtpServerServiceImpl.java | 197 +++++++++- .../iot/vmp/vmanager/ps/PsController.java | 2 +- .../iot/vmp/vmanager/rtp/RtpController.java | 4 +- web/public/index.html | 5 +- web/src/views/common/h265web.vue | 64 ++-- web/src/views/common/h265web.vue.bak | 344 ++++++++++++++++++ web/src/views/jtDevice/edit.vue | 14 +- 16 files changed, 623 insertions(+), 130 deletions(-) create mode 100644 web/src/views/common/h265web.vue.bak diff --git a/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java b/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java index e848d38f4..5ee058f02 100644 --- a/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java +++ b/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java @@ -53,6 +53,7 @@ public class VideoManagerConstants { public static final String START_SEND_PUSH_STREAM = "VMP_START_SEND_PUSH_STREAM:"; public static final String SSE_TASK_KEY = "SSE_TASK_"; public static final String DRAW_THIN_PROCESS_PREFIX = "VMP_DRAW_THIN_PROCESS_"; + public static final String RTP_AUTHENTICATE = "VMP_RTP_AUTHENTICATE"; diff --git a/src/main/java/com/genersoft/iot/vmp/common/enums/MediaStreamUtil.java b/src/main/java/com/genersoft/iot/vmp/common/enums/MediaStreamUtil.java index 1ae95860d..3f297ca31 100644 --- a/src/main/java/com/genersoft/iot/vmp/common/enums/MediaStreamUtil.java +++ b/src/main/java/com/genersoft/iot/vmp/common/enums/MediaStreamUtil.java @@ -17,7 +17,7 @@ public class MediaStreamUtil { } public static boolean isGB28181(String app, String streamId) { - return RTP_APP.equals(app) || !streamId.startsWith(RTP_STREAM_REST_PREFIX); + return RTP_APP.equals(app) && !streamId.startsWith(RTP_STREAM_REST_PREFIX); } public static boolean isTalk(String app, String streamId) { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformServiceImpl.java index 9700808a3..eb4299fcf 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformServiceImpl.java @@ -607,24 +607,7 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner } } - String streamId = null; - if (mediaServerItem.isRtpEnable()) { - streamId = String.format("%s_%s", platform.getServerGBId(), channel.getGbDeviceId()); - } - // 默认不进行SSRC校验, TODO 后续可改为配置 - boolean ssrcCheck = false; - int tcpMode; - if (userSetting.getBroadcastForPlatform().equalsIgnoreCase("TCP-PASSIVE")) { - tcpMode = 1; - }else if (userSetting.getBroadcastForPlatform().equalsIgnoreCase("TCP-ACTIVE")) { - tcpMode = 2; - } else { - tcpMode = 0; - } - - - SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServer(mediaServerItem, streamId, null, tcpMode, - false, ssrcCheck, true, false, ((code, msg, data) -> { + SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServerForBroadcast(mediaServerItem, platform, channel, ((code, msg, data) -> { if (code == InviteErrorCode.SUCCESS.getCode() && data != null && data.getHookData() != null) { log.info("[国标级联] 发起语音喊话 收到上级推流 deviceId: {}, channelId: {}", platform.getServerGBId(), channel.getGbDeviceId()); HookData hookData = data.getHookData(); @@ -662,7 +645,7 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner return; } log.info("[国标级联] 语音喊话,发起Invite消息 deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}", - platform.getServerGBId(), channel.getGbDeviceId(), ssrcInfo.getPort(), userSetting.getBroadcastForPlatform(), ssrcInfo.getSsrc(), ssrcCheck); + platform.getServerGBId(), channel.getGbDeviceId(), ssrcInfo.getPort(), userSetting.getBroadcastForPlatform(), ssrcInfo.getSsrc(), false); // 初始化redis中的invite消息状态 InviteInfo inviteInfo = InviteInfo.getInviteInfo(platform.getServerGBId(), channel.getGbId(), ssrcInfo.getStream(), ssrcInfo, mediaServerItem.getId(), @@ -670,7 +653,7 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner InviteSessionStatus.ready, userSetting.getRecordSip()); inviteStreamService.updateInviteInfo(inviteInfo); commanderForPlatform.broadcastInviteCmd(platform, channel,sourceId, mediaServerItem, ssrcInfo, event -> { - inviteOKHandler(event, ssrcInfo, tcpMode, ssrcCheck, mediaServerItem, platform, channel, + inviteOKHandler(event, ssrcInfo, false, mediaServerItem, platform, channel, null, inviteInfo, InviteSessionType.BROADCAST); }, eventResult -> { // 收到错误回复 @@ -692,7 +675,7 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner } } - private void inviteOKHandler(SipSubscribe.EventResult eventResult, SSRCInfo ssrcInfo, int tcpMode, boolean ssrcCheck, MediaServer mediaServerItem, + private void inviteOKHandler(SipSubscribe.EventResult eventResult, SSRCInfo ssrcInfo, boolean ssrcCheck, MediaServer mediaServerItem, Platform platform, CommonGBChannel channel, ErrorCallback callback, InviteInfo inviteInfo, InviteSessionType inviteSessionType){ inviteInfo.setStatus(InviteSessionStatus.ok); @@ -704,16 +687,11 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner ssrcInResponse = ssrcInfo.getSsrc(); } if (ssrcInfo.getSsrc().equals(ssrcInResponse)) { - // ssrc 一致 - if (mediaServerItem.isRtpEnable()) { - // 多端口 - if (tcpMode == 2) { - tcpActiveHandler(platform, channel, contentString, mediaServerItem, tcpMode, ssrcCheck, + if (userSetting.getBroadcastForPlatform().equalsIgnoreCase("TCP-ACTIVE")) { + if (mediaServerItem.isRtpEnable()) { + tcpActiveHandler(platform, channel, contentString, mediaServerItem, ssrcCheck, ssrcInfo, callback); - } - }else { - // 单端口 - if (tcpMode == 2) { + }else { log.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流"); } } @@ -751,9 +729,9 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner updateSsrcTransaction(ssrcInfo.getApp(), ssrcInfo.getStream(), ssrcInResponse, null); inviteInfo.setSsrcInfo(ssrcInfo); inviteInfo.setStream(ssrcInfo.getStream()); - if (tcpMode == 2) { + if (userSetting.getBroadcastForPlatform().equalsIgnoreCase("TCP-ACTIVE")) { if (mediaServerItem.isRtpEnable()) { - tcpActiveHandler(platform, channel, contentString, mediaServerItem, tcpMode, ssrcCheck, + tcpActiveHandler(platform, channel, contentString, mediaServerItem, ssrcCheck, ssrcInfo, callback); }else { log.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流"); @@ -767,9 +745,9 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner updateSsrcTransaction(ssrcInfo.getApp(), ssrcInfo.getStream(), ssrcInResponse, null); inviteInfo.setSsrcInfo(ssrcInfo); inviteInfo.setStream(ssrcInfo.getStream()); - if (tcpMode == 2) { + if (userSetting.getBroadcastForPlatform().equalsIgnoreCase("TCP-ACTIVE")) { if (mediaServerItem.isRtpEnable()) { - tcpActiveHandler(platform, channel, contentString, mediaServerItem, tcpMode, ssrcCheck, + tcpActiveHandler(platform, channel, contentString, mediaServerItem, ssrcCheck, ssrcInfo, callback); }else { log.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流"); @@ -825,12 +803,8 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner private void tcpActiveHandler(Platform platform, CommonGBChannel channel, String contentString, - MediaServer mediaServerItem, int tcpMode, boolean ssrcCheck, + MediaServer mediaServerItem, boolean ssrcCheck, SSRCInfo ssrcInfo, ErrorCallback callback){ - if (tcpMode != 2) { - return; - } - String substring; if (contentString.indexOf("y=") > 0) { substring = contentString.substring(0, contentString.indexOf("y=")); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlayServiceImpl.java index ba108044b..6a970ffb3 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlayServiceImpl.java @@ -375,10 +375,8 @@ public class PlayServiceImpl implements IPlayService { } String streamId = String.format("%s_%s", device.getDeviceId(), channel.getDeviceId()); - int tcpMode = device.getStreamMode().equals("TCP-ACTIVE")? 2: (device.getStreamMode().equals("TCP-PASSIVE")? 1:0); - SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServer(mediaServer, streamId, ssrc, tcpMode, false, - device.isSsrcCheck(), false, !channel.isHasAudio(), (code, msg, result) -> { + SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServerForPlay(mediaServer, device, channel, ssrc, (code, msg, result) -> { if (code == InviteErrorCode.SUCCESS.getCode() && result != null && result.getHookData() != null) { // hook 响应 @@ -770,10 +768,8 @@ public class PlayServiceImpl implements IPlayService { .replace(" ", ""); String stream = device.getDeviceId() + "_" + channel.getDeviceId() + "_" + startTimeStr + "_" + endTimeTimeStr; - int tcpMode = device.getStreamMode().equals("TCP-ACTIVE")? 2: (device.getStreamMode().equals("TCP-PASSIVE")? 1:0); - SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServer(mediaServer, stream, null, tcpMode, true, - device.isSsrcCheck(), false, !channel.isHasAudio(), (code, msg, result) -> { + SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServerForPlayback(mediaServer, device, channel, startTimeStr, endTimeTimeStr, (code, msg, result) -> { if (code == InviteErrorCode.SUCCESS.getCode() && result != null && result.getHookData() != null) { // hook响应 StreamInfo streamInfo = onPublishHandlerForPlayback(result.getHookData().getMediaServer(), result.getHookData().getMediaInfo(), device, channel, startTime, endTime); @@ -1009,10 +1005,7 @@ public class PlayServiceImpl implements IPlayService { return; } - int tcpMode = device.getStreamMode().equals("TCP-ACTIVE")? 2: (device.getStreamMode().equals("TCP-PASSIVE")? 1:0); - - SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServer(mediaServer, null, null, tcpMode, false, - device.isSsrcCheck(), false, !channel.isHasAudio(), (code, msg, result) -> { + SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServerForDownload(mediaServer, device, channel, (code, msg, result) -> { if (code == InviteErrorCode.SUCCESS.getCode() && result != null && result.getHookData() != null) { // hook响应 StreamInfo streamInfo = onPublishHandlerForDownload(mediaServer, result.getHookData().getMediaInfo(), device, channel, startTime, endTime); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderForPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderForPlatform.java index 467084e47..46198e5fb 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderForPlatform.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderForPlatform.java @@ -695,7 +695,7 @@ public class SIPCommanderForPlatform implements ISIPCommanderForPlatform { } @Override - public void broadcastInviteCmd(Platform platform, CommonGBChannel channel,String sourceId, MediaServer mediaServerItem, + public void broadcastInviteCmd(Platform platform, CommonGBChannel channel,String sourceId, MediaServer mediaServer, SSRCInfo ssrcInfo, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws ParseException, SipException, InvalidArgumentException { String stream = ssrcInfo.getStream(); @@ -704,8 +704,8 @@ public class SIPCommanderForPlatform implements ISIPCommanderForPlatform { return; } - log.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); - String sdpIp = mediaServerItem.getSdpIp(); + log.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServer.getId(), mediaServer.getIp(), ssrcInfo.getPort()); + String sdpIp = mediaServer.getSdpIp(); StringBuffer content = new StringBuffer(200); content.append("v=0\r\n"); @@ -744,13 +744,13 @@ public class SIPCommanderForPlatform implements ISIPCommanderForPlatform { callIdHeader); sipSender.transmitRequest(sipLayer.getLocalIp(platform.getDeviceIp()), request, (e -> { sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream()); - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrcToRelease()); + mediaServerService.releaseSsrc(mediaServer.getId(), ssrcInfo.getSsrcToRelease()); errorEvent.response(e); }), e -> { ResponseEvent responseEvent = (ResponseEvent) e.event; SIPResponse response = (SIPResponse) responseEvent.getResponse(); SsrcTransaction ssrcTransaction = SsrcTransaction.buildForPlatform(platform.getServerGBId(), channel.getGbId(), - callIdHeader.getCallId(), ssrcInfo.getApp(), stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.BROADCAST); + callIdHeader.getCallId(), ssrcInfo.getApp(), stream, ssrcInfo.getSsrc(), mediaServer.getId(), response, InviteSessionType.BROADCAST); ssrcTransaction.setAllocatedSsrc(ssrcInfo.getAllocatedSsrc()); sessionManager.put(ssrcTransaction); okEvent.response(e); diff --git a/src/main/java/com/genersoft/iot/vmp/jt1078/service/impl/jt1078PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/jt1078/service/impl/jt1078PlayServiceImpl.java index 2cae36a1c..e4941bfe8 100644 --- a/src/main/java/com/genersoft/iot/vmp/jt1078/service/impl/jt1078PlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/jt1078/service/impl/jt1078PlayServiceImpl.java @@ -240,7 +240,7 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService { rtpServerParam.setOnlyAuto(false); rtpServerParam.setDisableAudio(!channel.isHasAudio()); - int port = receiveRtpServerService.openRTPServer(rtpServerParam, (code, msg, hookData) -> { + int port = receiveRtpServerService.openCommonRTPServer(rtpServerParam, (code, msg, hookData) -> { if (code == InviteErrorCode.SUCCESS.getCode() && hookData != null ) { // hook响应 @@ -459,7 +459,7 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService { rtpServerParam.setOnlyAuto(false); rtpServerParam.setDisableAudio(!channel.isHasAudio()); - int port = receiveRtpServerService.openRTPServer(rtpServerParam, (code, msg, hookData) -> { + int port = receiveRtpServerService.openCommonRTPServer(rtpServerParam, (code, msg, hookData) -> { if (code == InviteErrorCode.SUCCESS.getCode() && hookData != null ) { // hook 响应 diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResult.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResult.java index dee9d6608..4f2af6423 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResult.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResult.java @@ -1,5 +1,10 @@ package com.genersoft.iot.vmp.media.zlm.dto.hook; +import lombok.Getter; +import lombok.Setter; + +@Setter +@Getter public class HookResult { private int code; @@ -22,19 +27,4 @@ public class HookResult { return new HookResultForOnPublish(-1, "fail"); } - public int getCode() { - return code; - } - - public void setCode(int code) { - this.code = code; - } - - public String getMsg() { - return msg; - } - - public void setMsg(String msg) { - this.msg = msg; - } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/IReceiveRtpServerService.java b/src/main/java/com/genersoft/iot/vmp/service/IReceiveRtpServerService.java index b5f3c8ac7..f0987b4cd 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/IReceiveRtpServerService.java +++ b/src/main/java/com/genersoft/iot/vmp/service/IReceiveRtpServerService.java @@ -1,7 +1,6 @@ package com.genersoft.iot.vmp.service; -import com.genersoft.iot.vmp.common.StreamInfo; -import com.genersoft.iot.vmp.gb28181.bean.OpenRTPServerResult; +import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.event.hook.HookData; import com.genersoft.iot.vmp.service.bean.ErrorCallback; @@ -14,7 +13,19 @@ public interface IReceiveRtpServerService { boolean playback, boolean ssrcCheck, boolean onlyAuto, boolean disableAuto, ErrorCallback callback); - int openRTPServer(RTPServerParam rtpServerParam, ErrorCallback callback); + SSRCInfo openGbRTPServerForPlay(MediaServer mediaServer, Device device, DeviceChannel channel, + String presetSSRC, ErrorCallback callback); + + SSRCInfo openGbRTPServerForPlayback(MediaServer mediaServer, Device device, DeviceChannel channel, + String startTime, String endTime, ErrorCallback callback); + + SSRCInfo openGbRTPServerForDownload(MediaServer mediaServer, Device device, DeviceChannel channel, + ErrorCallback callback); + + SSRCInfo openGbRTPServerForBroadcast(MediaServer mediaServer, Platform platform, CommonGBChannel channel, + ErrorCallback callback); + + int openCommonRTPServer(RTPServerParam rtpServerParam, ErrorCallback callback); void closeRTPServer(MediaServer mediaServer, String app, String stream); diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/SSRCInfo.java b/src/main/java/com/genersoft/iot/vmp/service/bean/SSRCInfo.java index b14bffffd..5ee85ca78 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/bean/SSRCInfo.java +++ b/src/main/java/com/genersoft/iot/vmp/service/bean/SSRCInfo.java @@ -9,13 +9,13 @@ public class SSRCInfo { private String ssrc; private String allocatedSsrc; private String app; - private String Stream; + private String stream; public SSRCInfo(int port, String ssrc, String app, String stream) { this.port = port; this.ssrc = ssrc; this.app = app; - this.Stream = stream; + this.stream = stream; } public String getSsrcToRelease() { diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/RtpServerServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/RtpServerServiceImpl.java index 8ee28c0ce..6fea42bb6 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/RtpServerServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/RtpServerServiceImpl.java @@ -1,11 +1,11 @@ package com.genersoft.iot.vmp.service.impl; +import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.common.enums.MediaStreamUtil; import com.genersoft.iot.vmp.conf.DynamicTask; import com.genersoft.iot.vmp.conf.UserSetting; -import com.genersoft.iot.vmp.gb28181.bean.OpenRTPServerResult; +import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.session.SSRCFactory; -import com.genersoft.iot.vmp.gb28181.session.SipInviteSessionManager; import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.event.hook.Hook; import com.genersoft.iot.vmp.media.event.hook.HookData; @@ -14,6 +14,7 @@ import com.genersoft.iot.vmp.media.event.hook.HookType; import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent; import com.genersoft.iot.vmp.media.event.media.MediaDepartureEvent; import com.genersoft.iot.vmp.media.service.IMediaServerService; +import com.genersoft.iot.vmp.media.zlm.dto.hook.HookResultForOnPublish; import com.genersoft.iot.vmp.service.IReceiveRtpServerService; import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.service.bean.InviteErrorCode; @@ -22,10 +23,12 @@ import com.genersoft.iot.vmp.service.bean.SSRCInfo; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.event.EventListener; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.util.Objects; +import java.util.concurrent.TimeUnit; @Slf4j @Service @@ -49,7 +52,7 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService { private HookSubscribe subscribe; @Autowired - private SipInviteSessionManager sessionManager; + private RedisTemplate redisTemplate; /** * 流到来的处理 @@ -106,7 +109,7 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService { ssrcInfo.setAllocatedSsrc(ssrc); } RTPServerParam rtpServerParam = new RTPServerParam(mediaServer, MediaStreamUtil.RTP_APP, streamId, ssrcCheck ? Long.parseLong(ssrc): 0L, null, onlyAuto, disableAuto, false, tcpMode); - int rtpServerPort = openRTPServer(rtpServerParam, ((code, msg, data) -> { + int rtpServerPort = openCommonRTPServer(rtpServerParam, ((code, msg, data) -> { if (code == InviteErrorCode.SUCCESS.getCode()) { OpenRTPServerResult openRTPServerResult = new OpenRTPServerResult(); openRTPServerResult.setHookData(data); @@ -128,7 +131,165 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService { } @Override - public int openRTPServer(RTPServerParam rtpServerParam, ErrorCallback callback) { + public SSRCInfo openGbRTPServerForPlay(MediaServer mediaServer, Device device, DeviceChannel channel, + String presetSSRC, ErrorCallback callback) { + if (callback == null) { + log.warn("[开启国标点播RTP收流] 失败,回调为NULL"); + return null; + } + if (mediaServer == null) { + log.warn("[开启国标点播RTP收流] 失败,媒体节点为NULL"); + return null; + } + + String streamId = String.format("%s_%s", device.getDeviceId(), channel.getDeviceId()); + int tcpMode = device.getStreamMode().equals("TCP-ACTIVE")? 2: (device.getStreamMode().equals("TCP-PASSIVE")? 1:0); + + // 获取 mediaServer 可用的 ssrc + final String ssrc; + if (presetSSRC != null) { + ssrc = presetSSRC; + }else { + ssrc = ssrcFactory.getPlaySsrc(mediaServer.getId()); + } + if (device.isSsrcCheck() && tcpMode > 0) { + // 目前zlm不支持 tcp模式更新ssrc,暂时关闭ssrc校验 + log.warn("[开启国标点播RTP收流] 平台对接时下级可能自定义ssrc,但是tcp模式zlm收流目前无法更新ssrc,可能收流超时,此时请使用udp收流或者关闭ssrc校验"); + } + + Long checkSsrc = device.isSsrcCheck() ? Long.parseLong(ssrc) : 0L; + + SSRCInfo ssrcInfo = new SSRCInfo(0, ssrc, MediaStreamUtil.RTP_APP, streamId); + if (presetSSRC == null) { + ssrcInfo.setAllocatedSsrc(ssrc); + } + openRtpServer(mediaServer, ssrcInfo, checkSsrc, !channel.isHasAudio(), false, tcpMode, callback); + return ssrcInfo; + } + + @Override + public SSRCInfo openGbRTPServerForPlayback(MediaServer mediaServer, Device device, DeviceChannel channel, + String startTimeStr, String endTimeTimeStr, ErrorCallback callback) { + if (callback == null) { + log.warn("[开启国标回放RTP收流] 失败,回调为NULL"); + return null; + } + if (mediaServer == null) { + log.warn("[开启国标回放RTP收流] 失败,媒体节点为NULL"); + return null; + } + + String streamId = device.getDeviceId() + "_" + channel.getDeviceId() + "_" + startTimeStr + "_" + endTimeTimeStr; + int tcpMode = device.getStreamMode().equals("TCP-ACTIVE")? 2: (device.getStreamMode().equals("TCP-PASSIVE")? 1:0); + + // 获取 mediaServer 可用的 ssrc + final String ssrc = ssrcFactory.getPlayBackSsrc(mediaServer.getId()); + + if (device.isSsrcCheck() && tcpMode > 0) { + // 目前zlm不支持 tcp模式更新ssrc,暂时关闭ssrc校验 + log.warn("[开启国标回放RTP收流] 平台对接时下级可能自定义ssrc,但是tcp模式zlm收流目前无法更新ssrc,可能收流超时,此时请使用udp收流或者关闭ssrc校验"); + } + + Long checkSsrc = device.isSsrcCheck() ? Long.parseLong(ssrc) : 0L; + + SSRCInfo ssrcInfo = new SSRCInfo(0, ssrc, MediaStreamUtil.RTP_APP, streamId); + ssrcInfo.setAllocatedSsrc(ssrc); + openRtpServer(mediaServer, ssrcInfo, checkSsrc, !channel.isHasAudio(), false, tcpMode, callback); + return ssrcInfo; + } + + @Override + public SSRCInfo openGbRTPServerForDownload(MediaServer mediaServer, Device device, DeviceChannel channel, + ErrorCallback callback) { + if (callback == null) { + log.warn("[开启国标录像下载RTP收流] 失败,回调为NULL"); + return null; + } + if (mediaServer == null) { + log.warn("[开启国标录像下载RTP收流] 失败,媒体节点为NULL"); + return null; + } + + int tcpMode = device.getStreamMode().equals("TCP-ACTIVE")? 2: (device.getStreamMode().equals("TCP-PASSIVE")? 1:0); + + // 获取 mediaServer 可用的 ssrc + String ssrc = ssrcFactory.getPlaySsrc(mediaServer.getId()); + String streamId = String.format("%08x", Long.parseLong(ssrc)).toUpperCase();; + if (device.isSsrcCheck() && tcpMode > 0) { + // 目前zlm不支持 tcp模式更新ssrc,暂时关闭ssrc校验 + log.warn("[开启国标录像下载RTP收流] 平台对接时下级可能自定义ssrc,但是tcp模式zlm收流目前无法更新ssrc,可能收流超时,此时请使用udp收流或者关闭ssrc校验"); + } + + Long checkSsrc = device.isSsrcCheck() ? Long.parseLong(ssrc) : 0L; + + SSRCInfo ssrcInfo = new SSRCInfo(0, ssrc, MediaStreamUtil.RTP_APP, streamId); + ssrcInfo.setAllocatedSsrc(ssrc); + openRtpServer(mediaServer, ssrcInfo, checkSsrc, !channel.isHasAudio(), false, tcpMode, callback); + return ssrcInfo; + } + + @Override + public SSRCInfo openGbRTPServerForBroadcast(MediaServer mediaServer, Platform platform, CommonGBChannel channel, + ErrorCallback callback) { + if (callback == null) { + log.warn("[开启国标喊话RTP收流] 失败,回调为NULL"); + return null; + } + if (mediaServer == null) { + log.warn("[开启国标喊话RTP收流] 失败,媒体节点为NULL"); + return null; + } + + String streamId = null; + if (mediaServer.isRtpEnable()) { + streamId = String.format("%s_%s", platform.getServerGBId(), channel.getGbDeviceId()); + } + // 默认不进行SSRC校验, TODO 后续可改为配置 + int tcpMode; + if (userSetting.getBroadcastForPlatform().equalsIgnoreCase("TCP-PASSIVE")) { + tcpMode = 1; + }else if (userSetting.getBroadcastForPlatform().equalsIgnoreCase("TCP-ACTIVE")) { + tcpMode = 2; + } else { + tcpMode = 0; + } + + // 获取 mediaServer 可用的 ssrc + String ssrc = ssrcFactory.getPlaySsrc(mediaServer.getId()); + + + SSRCInfo ssrcInfo = new SSRCInfo(0, ssrc, MediaStreamUtil.RTP_APP, streamId); + ssrcInfo.setAllocatedSsrc(ssrc); + openRtpServer(mediaServer, ssrcInfo, 0L, false, true, tcpMode, callback); + return ssrcInfo; + } + + private void openRtpServer(MediaServer mediaServer, SSRCInfo ssrcInfo, Long checkSsrc, boolean disableAuto, boolean onlyAuto, int tcpMode, + ErrorCallback callback) { + + RTPServerParam rtpServerParam = new RTPServerParam(mediaServer, MediaStreamUtil.RTP_APP, ssrcInfo.getStream(), checkSsrc, null, onlyAuto, disableAuto, false, tcpMode); + int rtpServerPort = openCommonRTPServer(rtpServerParam, ((code, msg, data) -> { + if (code == InviteErrorCode.SUCCESS.getCode()) { + OpenRTPServerResult openRTPServerResult = new OpenRTPServerResult(); + openRTPServerResult.setHookData(data); + openRTPServerResult.setSsrcInfo(ssrcInfo); + callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), openRTPServerResult); + } else { + // 释放ssrc + if (ssrcInfo.getAllocatedSsrc() != null) { + ssrcFactory.releaseSsrc(mediaServer.getId(), ssrcInfo.getAllocatedSsrc()); + ssrcInfo.setAllocatedSsrc(null); + } + OpenRTPServerResult openRTPServerResult = new OpenRTPServerResult(); + openRTPServerResult.setSsrcInfo(ssrcInfo); + callback.run(code, msg, openRTPServerResult); + } + })); + ssrcInfo.setPort(rtpServerPort); + } + + @Override + public int openCommonRTPServer(RTPServerParam rtpServerParam, ErrorCallback callback) { if (callback == null) { log.warn("[开启RTP收流] 失败,回调为NULL"); return -1; @@ -192,4 +353,30 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService { } closeRTPServer(mediaServer, app, stream); } + + private void addAuthenticateInfoForGb28181(MediaServer mediaServer, String streamId, Boolean enableMp4, Boolean enableAudio, String mapSavePath, Integer modifyStamp) { + String streamReplace = null; + + if (!mediaServer.isRtpEnable() ) { + streamReplace = streamId; + } + + addAuthenticateInfo(streamId, streamReplace, enableAudio, enableMp4, mapSavePath, modifyStamp); + } + + private void addAuthenticateInfo(String streamId, String streamReplace, Boolean enableAudio, Boolean enableMp4, String mapSavePath, Integer modifyStamp) { + HookResultForOnPublish hookResultForOnPublish = new HookResultForOnPublish(); + hookResultForOnPublish.setCode(0); + hookResultForOnPublish.setMsg("success"); + hookResultForOnPublish.setStream_replace(streamReplace); + hookResultForOnPublish.setEnable_audio(enableAudio); + hookResultForOnPublish.setEnable_mp4(enableMp4); + hookResultForOnPublish.setMp4_save_path(mapSavePath); + hookResultForOnPublish.setModify_stamp(modifyStamp); + + String key = String.format("%s:%s", VideoManagerConstants.RTP_AUTHENTICATE, streamId); + // 存储认证信息,过期时间为60秒, 过期则无法通过认证 + redisTemplate.opsForValue().set(key, hookResultForOnPublish); + redisTemplate.expire(key, 60, TimeUnit.SECONDS); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/ps/PsController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/ps/PsController.java index c90010aea..057398ddd 100755 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/ps/PsController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/ps/PsController.java @@ -106,7 +106,7 @@ public class PsController { rtpServerParam.setSsrc(ssrcInt); rtpServerParam.setTcpMode(tcpMode); - int rtpServerPort = receiveRtpServerService.openRTPServer(rtpServerParam, ((code, msg, data) -> { + int rtpServerPort = receiveRtpServerService.openCommonRTPServer(rtpServerParam, ((code, msg, data) -> { if (callBack == null) { return; } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java index e20c6039b..e7085ec2b 100755 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java @@ -107,7 +107,7 @@ public class RtpController { rtpServerParam.setTcpMode(tcpMode); - int rtpServerPortForVideo = receiveRtpServerService.openRTPServer(rtpServerParam, ((code, msg, data) -> { + int rtpServerPortForVideo = receiveRtpServerService.openCommonRTPServer(rtpServerParam, ((code, msg, data) -> { if (callBack == null) { return; } @@ -129,7 +129,7 @@ public class RtpController { rtpServerParam.setStreamId(stream + "_a"); - int rtpServerPortForAudio = receiveRtpServerService.openRTPServer(rtpServerParam, ((code, msg, data) -> { + int rtpServerPortForAudio = receiveRtpServerService.openCommonRTPServer(rtpServerParam, ((code, msg, data) -> { if (code == InviteErrorCode.SUCCESS.getCode()) { log.info("[开启收流和获取发流信息] 音频流收流成功,callId->{},stream->{}", callId, stream); }else { diff --git a/web/public/index.html b/web/public/index.html index 5825d0f3c..6e248f8e2 100644 --- a/web/public/index.html +++ b/web/public/index.html @@ -11,8 +11,9 @@ - - + + + diff --git a/web/src/views/common/h265web.vue b/web/src/views/common/h265web.vue index 3cb4a17dc..cf7be7f8d 100644 --- a/web/src/views/common/h265web.vue +++ b/web/src/views/common/h265web.vue @@ -134,48 +134,34 @@ export default { }, create(url) { this.playerLoading = true - const options = { - player_id: 'glplayer', - base_url: './static/js/h265web2/', - wasm_js_uri: 'h265web_wasm.js', - wasm_wasm_uri: 'h265web_wasm.wasm', - ext_src_js_uri: 'extjs.js', - ext_wasm_js_uri: 'extwasm.js', - width: '100%', - height: 480, - color: '#101318', - auto_play: false, - readframe_multi_times: -1, - ignore_audio: false - } - - - h265webPlayer[this._uid] = H265webjsPlayer() + const options = {} + h265webPlayer[this._uid] = new window.new265webjs(url, Object.assign( + { + player: 'glplayer', // 播放器容器id + width: this.playerWidth, + height: this.playerHeight, + token: token, + extInfo: { + coreProbePart: 0.4, + probeSize: 8192, + ignoreAudio: this.hasAudio === null ? 0 : (this.hasAudio ? 0 : 1) + } + }, + options + )) const h265web = h265webPlayer[this._uid] - - h265web.on_ready_show_done_callback = () => { - console.log('ready_show_done_callback') - h265web.play() - console.log('ready_show_done_callback---22') - this.playing = true - this.playerLoading = false - } - h265web.video_probe_callback = (mediaInfo) => { - console.log('video_probe_callback: ', mediaInfo) - } - - h265web.build(options) - h265web.load_media(url) - - - - h265web.onOpenFullScreen = () => { this.fullscreen = true } h265web.onCloseFullScreen = () => { this.fullscreen = false } + h265web.onReadyShowDone = () => { + // 准备好显示了,尝试自动播放 + const result = h265web.play() + this.playing = result + this.playerLoading = false + } h265web.onLoadFinish = () => { this.loaded = true // 可以获取mediaInfo @@ -185,7 +171,7 @@ export default { h265web.onPlayTime = (videoPTS) => { this.$emit('playTimeChange', videoPTS * 1000) } - // h265web.do() + h265web.do() }, screenshot: function() { if (h265webPlayer[this._uid]) { @@ -193,7 +179,7 @@ export default { console.log(this.mediaInfo) canvas.width = this.mediaInfo.meta.size.width canvas.height = this.mediaInfo.meta.size.height - h265webPlayer[this._uid].screenshot(canvas) // snapshot to canvas + h265webPlayer[this._uid].snapshot(canvas) // snapshot to canvas // 下载截图 const link = document.createElement('a') @@ -227,14 +213,14 @@ export default { unPause: function() { if (h265webPlayer[this._uid]) { h265webPlayer[this._uid].play() - this.playing = true + this.playing = h265webPlayer[this._uid].isPlaying() } this.err = '' }, pause: function() { if (h265webPlayer[this._uid]) { h265webPlayer[this._uid].pause() - this.playing = false + this.playing = h265webPlayer[this._uid].isPlaying() } this.err = '' }, diff --git a/web/src/views/common/h265web.vue.bak b/web/src/views/common/h265web.vue.bak new file mode 100644 index 000000000..3cb4a17dc --- /dev/null +++ b/web/src/views/common/h265web.vue.bak @@ -0,0 +1,344 @@ + + + + + diff --git a/web/src/views/jtDevice/edit.vue b/web/src/views/jtDevice/edit.vue index 52f3aff75..19f0116c5 100755 --- a/web/src/views/jtDevice/edit.vue +++ b/web/src/views/jtDevice/edit.vue @@ -65,16 +65,22 @@ export default { .then(data => { this.listChangeCallback() }) - .catch(function(error) { - console.log(error) + .catch((error) => { + this.$message.error({ + showClose: true, + message: error + }) }) } else { this.$store.dispatch('jtDevice/add', this.form) .then(data => { this.listChangeCallback() }) - .catch(function(error) { - console.log(error) + .catch((error) => { + this.$message.error({ + showClose: true, + message: error + }) }) } },