优化错误处理,回滚播放器版本,重构RTP服务器接口以区分不同的接口功能,优化参数数量

This commit is contained in:
lin 2026-04-14 18:11:14 +08:00
parent ab3d0da115
commit 3e162ea358
16 changed files with 623 additions and 130 deletions

View File

@ -53,6 +53,7 @@ public class VideoManagerConstants {
public static final String START_SEND_PUSH_STREAM = "VMP_START_SEND_PUSH_STREAM:"; 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 SSE_TASK_KEY = "SSE_TASK_";
public static final String DRAW_THIN_PROCESS_PREFIX = "VMP_DRAW_THIN_PROCESS_"; public static final String DRAW_THIN_PROCESS_PREFIX = "VMP_DRAW_THIN_PROCESS_";
public static final String RTP_AUTHENTICATE = "VMP_RTP_AUTHENTICATE";

View File

@ -17,7 +17,7 @@ public class MediaStreamUtil {
} }
public static boolean isGB28181(String app, String streamId) { 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) { public static boolean isTalk(String app, String streamId) {

View File

@ -607,24 +607,7 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner
} }
} }
String streamId = null; SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServerForBroadcast(mediaServerItem, platform, channel, ((code, msg, data) -> {
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) -> {
if (code == InviteErrorCode.SUCCESS.getCode() && data != null && data.getHookData() != null) { if (code == InviteErrorCode.SUCCESS.getCode() && data != null && data.getHookData() != null) {
log.info("[国标级联] 发起语音喊话 收到上级推流 deviceId: {}, channelId: {}", platform.getServerGBId(), channel.getGbDeviceId()); log.info("[国标级联] 发起语音喊话 收到上级推流 deviceId: {}, channelId: {}", platform.getServerGBId(), channel.getGbDeviceId());
HookData hookData = data.getHookData(); HookData hookData = data.getHookData();
@ -662,7 +645,7 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner
return; return;
} }
log.info("[国标级联] 语音喊话发起Invite消息 deviceId: {}, channelId: {},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验{}", 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消息状态 // 初始化redis中的invite消息状态
InviteInfo inviteInfo = InviteInfo.getInviteInfo(platform.getServerGBId(), channel.getGbId(), ssrcInfo.getStream(), ssrcInfo, mediaServerItem.getId(), 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()); InviteSessionStatus.ready, userSetting.getRecordSip());
inviteStreamService.updateInviteInfo(inviteInfo); inviteStreamService.updateInviteInfo(inviteInfo);
commanderForPlatform.broadcastInviteCmd(platform, channel,sourceId, mediaServerItem, ssrcInfo, event -> { 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); null, inviteInfo, InviteSessionType.BROADCAST);
}, eventResult -> { }, 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<Object> callback, Platform platform, CommonGBChannel channel, ErrorCallback<Object> callback,
InviteInfo inviteInfo, InviteSessionType inviteSessionType){ InviteInfo inviteInfo, InviteSessionType inviteSessionType){
inviteInfo.setStatus(InviteSessionStatus.ok); inviteInfo.setStatus(InviteSessionStatus.ok);
@ -704,16 +687,11 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner
ssrcInResponse = ssrcInfo.getSsrc(); ssrcInResponse = ssrcInfo.getSsrc();
} }
if (ssrcInfo.getSsrc().equals(ssrcInResponse)) { if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
// ssrc 一致 if (userSetting.getBroadcastForPlatform().equalsIgnoreCase("TCP-ACTIVE")) {
if (mediaServerItem.isRtpEnable()) { if (mediaServerItem.isRtpEnable()) {
// 多端口 tcpActiveHandler(platform, channel, contentString, mediaServerItem, ssrcCheck,
if (tcpMode == 2) {
tcpActiveHandler(platform, channel, contentString, mediaServerItem, tcpMode, ssrcCheck,
ssrcInfo, callback); ssrcInfo, callback);
} }else {
}else {
// 单端口
if (tcpMode == 2) {
log.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流"); log.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流");
} }
} }
@ -751,9 +729,9 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner
updateSsrcTransaction(ssrcInfo.getApp(), ssrcInfo.getStream(), ssrcInResponse, null); updateSsrcTransaction(ssrcInfo.getApp(), ssrcInfo.getStream(), ssrcInResponse, null);
inviteInfo.setSsrcInfo(ssrcInfo); inviteInfo.setSsrcInfo(ssrcInfo);
inviteInfo.setStream(ssrcInfo.getStream()); inviteInfo.setStream(ssrcInfo.getStream());
if (tcpMode == 2) { if (userSetting.getBroadcastForPlatform().equalsIgnoreCase("TCP-ACTIVE")) {
if (mediaServerItem.isRtpEnable()) { if (mediaServerItem.isRtpEnable()) {
tcpActiveHandler(platform, channel, contentString, mediaServerItem, tcpMode, ssrcCheck, tcpActiveHandler(platform, channel, contentString, mediaServerItem, ssrcCheck,
ssrcInfo, callback); ssrcInfo, callback);
}else { }else {
log.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流"); log.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流");
@ -767,9 +745,9 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner
updateSsrcTransaction(ssrcInfo.getApp(), ssrcInfo.getStream(), ssrcInResponse, null); updateSsrcTransaction(ssrcInfo.getApp(), ssrcInfo.getStream(), ssrcInResponse, null);
inviteInfo.setSsrcInfo(ssrcInfo); inviteInfo.setSsrcInfo(ssrcInfo);
inviteInfo.setStream(ssrcInfo.getStream()); inviteInfo.setStream(ssrcInfo.getStream());
if (tcpMode == 2) { if (userSetting.getBroadcastForPlatform().equalsIgnoreCase("TCP-ACTIVE")) {
if (mediaServerItem.isRtpEnable()) { if (mediaServerItem.isRtpEnable()) {
tcpActiveHandler(platform, channel, contentString, mediaServerItem, tcpMode, ssrcCheck, tcpActiveHandler(platform, channel, contentString, mediaServerItem, ssrcCheck,
ssrcInfo, callback); ssrcInfo, callback);
}else { }else {
log.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流"); log.warn("[Invite 200OK] 单端口收流模式不支持tcp主动模式收流");
@ -825,12 +803,8 @@ public class PlatformServiceImpl implements IPlatformService, CommandLineRunner
private void tcpActiveHandler(Platform platform, CommonGBChannel channel, String contentString, private void tcpActiveHandler(Platform platform, CommonGBChannel channel, String contentString,
MediaServer mediaServerItem, int tcpMode, boolean ssrcCheck, MediaServer mediaServerItem, boolean ssrcCheck,
SSRCInfo ssrcInfo, ErrorCallback<Object> callback){ SSRCInfo ssrcInfo, ErrorCallback<Object> callback){
if (tcpMode != 2) {
return;
}
String substring; String substring;
if (contentString.indexOf("y=") > 0) { if (contentString.indexOf("y=") > 0) {
substring = contentString.substring(0, contentString.indexOf("y=")); substring = contentString.substring(0, contentString.indexOf("y="));

View File

@ -375,10 +375,8 @@ public class PlayServiceImpl implements IPlayService {
} }
String streamId = String.format("%s_%s", device.getDeviceId(), channel.getDeviceId()); 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, SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServerForPlay(mediaServer, device, channel, ssrc, (code, msg, result) -> {
device.isSsrcCheck(), false, !channel.isHasAudio(), (code, msg, result) -> {
if (code == InviteErrorCode.SUCCESS.getCode() && result != null && result.getHookData() != null) { if (code == InviteErrorCode.SUCCESS.getCode() && result != null && result.getHookData() != null) {
// hook 响应 // hook 响应
@ -770,10 +768,8 @@ public class PlayServiceImpl implements IPlayService {
.replace(" ", ""); .replace(" ", "");
String stream = device.getDeviceId() + "_" + channel.getDeviceId() + "_" + startTimeStr + "_" + endTimeTimeStr; 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, SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServerForPlayback(mediaServer, device, channel, startTimeStr, endTimeTimeStr, (code, msg, result) -> {
device.isSsrcCheck(), false, !channel.isHasAudio(), (code, msg, result) -> {
if (code == InviteErrorCode.SUCCESS.getCode() && result != null && result.getHookData() != null) { if (code == InviteErrorCode.SUCCESS.getCode() && result != null && result.getHookData() != null) {
// hook响应 // hook响应
StreamInfo streamInfo = onPublishHandlerForPlayback(result.getHookData().getMediaServer(), result.getHookData().getMediaInfo(), device, channel, startTime, endTime); StreamInfo streamInfo = onPublishHandlerForPlayback(result.getHookData().getMediaServer(), result.getHookData().getMediaInfo(), device, channel, startTime, endTime);
@ -1009,10 +1005,7 @@ public class PlayServiceImpl implements IPlayService {
return; return;
} }
int tcpMode = device.getStreamMode().equals("TCP-ACTIVE")? 2: (device.getStreamMode().equals("TCP-PASSIVE")? 1:0); SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServerForDownload(mediaServer, device, channel, (code, msg, result) -> {
SSRCInfo ssrcInfo = receiveRtpServerService.openGbRTPServer(mediaServer, null, null, tcpMode, false,
device.isSsrcCheck(), false, !channel.isHasAudio(), (code, msg, result) -> {
if (code == InviteErrorCode.SUCCESS.getCode() && result != null && result.getHookData() != null) { if (code == InviteErrorCode.SUCCESS.getCode() && result != null && result.getHookData() != null) {
// hook响应 // hook响应
StreamInfo streamInfo = onPublishHandlerForDownload(mediaServer, result.getHookData().getMediaInfo(), device, channel, startTime, endTime); StreamInfo streamInfo = onPublishHandlerForDownload(mediaServer, result.getHookData().getMediaInfo(), device, channel, startTime, endTime);

View File

@ -695,7 +695,7 @@ public class SIPCommanderForPlatform implements ISIPCommanderForPlatform {
} }
@Override @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, SSRCInfo ssrcInfo, SipSubscribe.Event okEvent,
SipSubscribe.Event errorEvent) throws ParseException, SipException, InvalidArgumentException { SipSubscribe.Event errorEvent) throws ParseException, SipException, InvalidArgumentException {
String stream = ssrcInfo.getStream(); String stream = ssrcInfo.getStream();
@ -704,8 +704,8 @@ public class SIPCommanderForPlatform implements ISIPCommanderForPlatform {
return; return;
} }
log.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); log.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServer.getId(), mediaServer.getIp(), ssrcInfo.getPort());
String sdpIp = mediaServerItem.getSdpIp(); String sdpIp = mediaServer.getSdpIp();
StringBuffer content = new StringBuffer(200); StringBuffer content = new StringBuffer(200);
content.append("v=0\r\n"); content.append("v=0\r\n");
@ -744,13 +744,13 @@ public class SIPCommanderForPlatform implements ISIPCommanderForPlatform {
callIdHeader); callIdHeader);
sipSender.transmitRequest(sipLayer.getLocalIp(platform.getDeviceIp()), request, (e -> { sipSender.transmitRequest(sipLayer.getLocalIp(platform.getDeviceIp()), request, (e -> {
sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream()); sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream());
mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrcToRelease()); mediaServerService.releaseSsrc(mediaServer.getId(), ssrcInfo.getSsrcToRelease());
errorEvent.response(e); errorEvent.response(e);
}), e -> { }), e -> {
ResponseEvent responseEvent = (ResponseEvent) e.event; ResponseEvent responseEvent = (ResponseEvent) e.event;
SIPResponse response = (SIPResponse) responseEvent.getResponse(); SIPResponse response = (SIPResponse) responseEvent.getResponse();
SsrcTransaction ssrcTransaction = SsrcTransaction.buildForPlatform(platform.getServerGBId(), channel.getGbId(), 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()); ssrcTransaction.setAllocatedSsrc(ssrcInfo.getAllocatedSsrc());
sessionManager.put(ssrcTransaction); sessionManager.put(ssrcTransaction);
okEvent.response(e); okEvent.response(e);

View File

@ -240,7 +240,7 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
rtpServerParam.setOnlyAuto(false); rtpServerParam.setOnlyAuto(false);
rtpServerParam.setDisableAudio(!channel.isHasAudio()); 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 ) { if (code == InviteErrorCode.SUCCESS.getCode() && hookData != null ) {
// hook响应 // hook响应
@ -459,7 +459,7 @@ public class jt1078PlayServiceImpl implements Ijt1078PlayService {
rtpServerParam.setOnlyAuto(false); rtpServerParam.setOnlyAuto(false);
rtpServerParam.setDisableAudio(!channel.isHasAudio()); 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 ) { if (code == InviteErrorCode.SUCCESS.getCode() && hookData != null ) {
// hook 响应 // hook 响应

View File

@ -1,5 +1,10 @@
package com.genersoft.iot.vmp.media.zlm.dto.hook; package com.genersoft.iot.vmp.media.zlm.dto.hook;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class HookResult { public class HookResult {
private int code; private int code;
@ -22,19 +27,4 @@ public class HookResult {
return new HookResultForOnPublish(-1, "fail"); 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;
}
} }

View File

@ -1,7 +1,6 @@
package com.genersoft.iot.vmp.service; package com.genersoft.iot.vmp.service;
import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.bean.OpenRTPServerResult;
import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.bean.MediaServer;
import com.genersoft.iot.vmp.media.event.hook.HookData; import com.genersoft.iot.vmp.media.event.hook.HookData;
import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.service.bean.ErrorCallback;
@ -14,7 +13,19 @@ public interface IReceiveRtpServerService {
boolean playback, boolean ssrcCheck, boolean onlyAuto, boolean disableAuto, boolean playback, boolean ssrcCheck, boolean onlyAuto, boolean disableAuto,
ErrorCallback<OpenRTPServerResult> callback); ErrorCallback<OpenRTPServerResult> callback);
int openRTPServer(RTPServerParam rtpServerParam, ErrorCallback<HookData> callback); SSRCInfo openGbRTPServerForPlay(MediaServer mediaServer, Device device, DeviceChannel channel,
String presetSSRC, ErrorCallback<OpenRTPServerResult> callback);
SSRCInfo openGbRTPServerForPlayback(MediaServer mediaServer, Device device, DeviceChannel channel,
String startTime, String endTime, ErrorCallback<OpenRTPServerResult> callback);
SSRCInfo openGbRTPServerForDownload(MediaServer mediaServer, Device device, DeviceChannel channel,
ErrorCallback<OpenRTPServerResult> callback);
SSRCInfo openGbRTPServerForBroadcast(MediaServer mediaServer, Platform platform, CommonGBChannel channel,
ErrorCallback<OpenRTPServerResult> callback);
int openCommonRTPServer(RTPServerParam rtpServerParam, ErrorCallback<HookData> callback);
void closeRTPServer(MediaServer mediaServer, String app, String stream); void closeRTPServer(MediaServer mediaServer, String app, String stream);

View File

@ -9,13 +9,13 @@ public class SSRCInfo {
private String ssrc; private String ssrc;
private String allocatedSsrc; private String allocatedSsrc;
private String app; private String app;
private String Stream; private String stream;
public SSRCInfo(int port, String ssrc, String app, String stream) { public SSRCInfo(int port, String ssrc, String app, String stream) {
this.port = port; this.port = port;
this.ssrc = ssrc; this.ssrc = ssrc;
this.app = app; this.app = app;
this.Stream = stream; this.stream = stream;
} }
public String getSsrcToRelease() { public String getSsrcToRelease() {

View File

@ -1,11 +1,11 @@
package com.genersoft.iot.vmp.service.impl; 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.common.enums.MediaStreamUtil;
import com.genersoft.iot.vmp.conf.DynamicTask; import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.conf.UserSetting; 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.SSRCFactory;
import com.genersoft.iot.vmp.gb28181.session.SipInviteSessionManager;
import com.genersoft.iot.vmp.media.bean.MediaServer; 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.Hook;
import com.genersoft.iot.vmp.media.event.hook.HookData; 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.MediaArrivalEvent;
import com.genersoft.iot.vmp.media.event.media.MediaDepartureEvent; import com.genersoft.iot.vmp.media.event.media.MediaDepartureEvent;
import com.genersoft.iot.vmp.media.service.IMediaServerService; 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.IReceiveRtpServerService;
import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import com.genersoft.iot.vmp.service.bean.InviteErrorCode; 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 lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener; import org.springframework.context.event.EventListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.TimeUnit;
@Slf4j @Slf4j
@Service @Service
@ -49,7 +52,7 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService {
private HookSubscribe subscribe; private HookSubscribe subscribe;
@Autowired @Autowired
private SipInviteSessionManager sessionManager; private RedisTemplate<Object, Object> redisTemplate;
/** /**
* 流到来的处理 * 流到来的处理
@ -106,7 +109,7 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService {
ssrcInfo.setAllocatedSsrc(ssrc); ssrcInfo.setAllocatedSsrc(ssrc);
} }
RTPServerParam rtpServerParam = new RTPServerParam(mediaServer, MediaStreamUtil.RTP_APP, streamId, ssrcCheck ? Long.parseLong(ssrc): 0L, null, onlyAuto, disableAuto, false, tcpMode); 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()) { if (code == InviteErrorCode.SUCCESS.getCode()) {
OpenRTPServerResult openRTPServerResult = new OpenRTPServerResult(); OpenRTPServerResult openRTPServerResult = new OpenRTPServerResult();
openRTPServerResult.setHookData(data); openRTPServerResult.setHookData(data);
@ -128,7 +131,165 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService {
} }
@Override @Override
public int openRTPServer(RTPServerParam rtpServerParam, ErrorCallback<HookData> callback) { public SSRCInfo openGbRTPServerForPlay(MediaServer mediaServer, Device device, DeviceChannel channel,
String presetSSRC, ErrorCallback<OpenRTPServerResult> 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<OpenRTPServerResult> 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<OpenRTPServerResult> 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<OpenRTPServerResult> 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<OpenRTPServerResult> 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<HookData> callback) {
if (callback == null) { if (callback == null) {
log.warn("[开启RTP收流] 失败回调为NULL"); log.warn("[开启RTP收流] 失败回调为NULL");
return -1; return -1;
@ -192,4 +353,30 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService {
} }
closeRTPServer(mediaServer, app, stream); 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);
}
} }

View File

@ -106,7 +106,7 @@ public class PsController {
rtpServerParam.setSsrc(ssrcInt); rtpServerParam.setSsrc(ssrcInt);
rtpServerParam.setTcpMode(tcpMode); rtpServerParam.setTcpMode(tcpMode);
int rtpServerPort = receiveRtpServerService.openRTPServer(rtpServerParam, ((code, msg, data) -> { int rtpServerPort = receiveRtpServerService.openCommonRTPServer(rtpServerParam, ((code, msg, data) -> {
if (callBack == null) { if (callBack == null) {
return; return;
} }

View File

@ -107,7 +107,7 @@ public class RtpController {
rtpServerParam.setTcpMode(tcpMode); rtpServerParam.setTcpMode(tcpMode);
int rtpServerPortForVideo = receiveRtpServerService.openRTPServer(rtpServerParam, ((code, msg, data) -> { int rtpServerPortForVideo = receiveRtpServerService.openCommonRTPServer(rtpServerParam, ((code, msg, data) -> {
if (callBack == null) { if (callBack == null) {
return; return;
} }
@ -129,7 +129,7 @@ public class RtpController {
rtpServerParam.setStreamId(stream + "_a"); 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()) { if (code == InviteErrorCode.SUCCESS.getCode()) {
log.info("[开启收流和获取发流信息] 音频流收流成功callId->{}stream->{}", callId, stream); log.info("[开启收流和获取发流信息] 音频流收流成功callId->{}stream->{}", callId, stream);
}else { }else {

View File

@ -11,8 +11,9 @@
<script type="text/javascript" src="./static/js/jessibuca/jessibuca.js"></script> <script type="text/javascript" src="./static/js/jessibuca/jessibuca.js"></script>
<script type="text/javascript" src="./static/js/ZLMRTCClient.js"></script> <script type="text/javascript" src="./static/js/ZLMRTCClient.js"></script>
<script type="text/javascript" src="./static/js/config.js"></script> <script type="text/javascript" src="./static/js/config.js"></script>
<script type="text/javascript" src="./static/js/h265web2/h265web.js"></script> <!-- <script type="text/javascript" src="./static/js/h265web2/h265web.js"></script>-->
<!-- <script type="text/javascript" src="./static/js/h265web/missile.js"></script>--> <script type="text/javascript" src="./static/js/h265web/h265webjs-v20221106.js"></script>
<script type="text/javascript" src="./static/js/h265web/missile.js"></script>
<noscript> <noscript>
<strong>We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> <strong>We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript> </noscript>

View File

@ -134,48 +134,34 @@ export default {
}, },
create(url) { create(url) {
this.playerLoading = true this.playerLoading = true
const options = { const options = {}
player_id: 'glplayer', h265webPlayer[this._uid] = new window.new265webjs(url, Object.assign(
base_url: './static/js/h265web2/', {
wasm_js_uri: 'h265web_wasm.js', player: 'glplayer', // id
wasm_wasm_uri: 'h265web_wasm.wasm', width: this.playerWidth,
ext_src_js_uri: 'extjs.js', height: this.playerHeight,
ext_wasm_js_uri: 'extwasm.js', token: token,
width: '100%', extInfo: {
height: 480, coreProbePart: 0.4,
color: '#101318', probeSize: 8192,
auto_play: false, ignoreAudio: this.hasAudio === null ? 0 : (this.hasAudio ? 0 : 1)
readframe_multi_times: -1, }
ignore_audio: false },
} options
))
h265webPlayer[this._uid] = H265webjsPlayer()
const h265web = h265webPlayer[this._uid] 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 = () => { h265web.onOpenFullScreen = () => {
this.fullscreen = true this.fullscreen = true
} }
h265web.onCloseFullScreen = () => { h265web.onCloseFullScreen = () => {
this.fullscreen = false this.fullscreen = false
} }
h265web.onReadyShowDone = () => {
//
const result = h265web.play()
this.playing = result
this.playerLoading = false
}
h265web.onLoadFinish = () => { h265web.onLoadFinish = () => {
this.loaded = true this.loaded = true
// mediaInfo // mediaInfo
@ -185,7 +171,7 @@ export default {
h265web.onPlayTime = (videoPTS) => { h265web.onPlayTime = (videoPTS) => {
this.$emit('playTimeChange', videoPTS * 1000) this.$emit('playTimeChange', videoPTS * 1000)
} }
// h265web.do() h265web.do()
}, },
screenshot: function() { screenshot: function() {
if (h265webPlayer[this._uid]) { if (h265webPlayer[this._uid]) {
@ -193,7 +179,7 @@ export default {
console.log(this.mediaInfo) console.log(this.mediaInfo)
canvas.width = this.mediaInfo.meta.size.width canvas.width = this.mediaInfo.meta.size.width
canvas.height = this.mediaInfo.meta.size.height 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') const link = document.createElement('a')
@ -227,14 +213,14 @@ export default {
unPause: function() { unPause: function() {
if (h265webPlayer[this._uid]) { if (h265webPlayer[this._uid]) {
h265webPlayer[this._uid].play() h265webPlayer[this._uid].play()
this.playing = true this.playing = h265webPlayer[this._uid].isPlaying()
} }
this.err = '' this.err = ''
}, },
pause: function() { pause: function() {
if (h265webPlayer[this._uid]) { if (h265webPlayer[this._uid]) {
h265webPlayer[this._uid].pause() h265webPlayer[this._uid].pause()
this.playing = false this.playing = h265webPlayer[this._uid].isPlaying()
} }
this.err = '' this.err = ''
}, },

View File

@ -0,0 +1,344 @@
<template>
<div id="h265Player" ref="container" style="background-color: #000000; " @dblclick="fullscreenSwich">
<div id="glplayer" ref="playerBox" style="width: 100%; height: 100%; margin: 0 auto;" >
<div v-if="playerLoading" class="play-loading">
<i class="el-icon-loading" />
视频加载中
</div>
</div>
<div v-if="showButton" id="buttonsBox" class="buttons-box">
<div class="buttons-box-left">
<i v-if="!playing" class="iconfont icon-play h265web-btn" @click="unPause" />
<i v-if="playing" class="iconfont icon-pause h265web-btn" @click="pause" />
<i class="iconfont icon-stop h265web-btn" @click="destroy" />
<i v-if="isNotMute" class="iconfont icon-audio-high h265web-btn" @click="mute()" />
<i v-if="!isNotMute" class="iconfont icon-audio-mute h265web-btn" @click="cancelMute()" />
</div>
<div class="buttons-box-right">
<!-- <i class="iconfont icon-file-record1 h265web-btn"></i>-->
<!-- <i class="iconfont icon-xiangqing2 h265web-btn" ></i>-->
<i
class="iconfont icon-camera1196054easyiconnet h265web-btn"
style="font-size: 1rem !important"
@click="screenshot"
/>
<i class="iconfont icon-shuaxin11 h265web-btn" @click="playBtnClick" />
<i v-if="!fullscreen" class="iconfont icon-weibiaoti10 h265web-btn" @click="fullscreenSwich" />
<i v-if="fullscreen" class="iconfont icon-weibiaoti11 h265web-btn" @click="fullscreenSwich" />
</div>
</div>
</div>
</template>
<script>
const h265webPlayer = {}
/**
* 从github上复制的
* @see https://github.com/numberwolf/h265web.js/blob/master/example_normal/index.js
*/
const token = 'base64:QXV0aG9yOmNoYW5neWFubG9uZ3xudW1iZXJ3b2xmLEdpdGh1YjpodHRwczovL2dpdGh1Yi5jb20vbnVtYmVyd29sZixFbWFpbDpwb3JzY2hlZ3QyM0Bmb3htYWlsLmNvbSxRUTo1MzEzNjU4NzIsSG9tZVBhZ2U6aHR0cDovL3h2aWRlby52aWRlbyxEaXNjb3JkOm51bWJlcndvbGYjODY5NCx3ZWNoYXI6bnVtYmVyd29sZjExLEJlaWppbmcsV29ya0luOkJhaWR1'
export default {
name: 'H265web',
props: ['videoUrl', 'error', 'hasAudio', 'height', 'showButton'],
data() {
return {
playing: false,
isNotMute: false,
quieting: false,
fullscreen: false,
loaded: false, // mute
speed: 0,
kBps: 0,
btnDom: null,
videoInfo: null,
volume: 1,
rotate: 0,
vod: true, //
forceNoOffscreen: false,
playerWidth: 0,
playerHeight: 0,
inited: false,
playerLoading: false,
mediaInfo: null
}
},
watch: {
videoUrl(newData, oldData) {
this.play(newData)
},
playing(newData, oldData) {
this.$emit('playStatusChange', newData)
},
immediate: true
},
mounted() {
const paramUrl = decodeURIComponent(this.$route.params.url)
window.onresize = () => {
this.updatePlayerDomSize()
}
this.btnDom = document.getElementById('buttonsBox')
console.log('初始化时的地址为: ' + paramUrl)
if (paramUrl) {
this.play(this.videoUrl)
}
},
destroyed() {
if (h265webPlayer[this._uid]) {
h265webPlayer[this._uid].destroy()
}
this.playing = false
this.loaded = false
this.playerLoading = false
},
methods: {
updatePlayerDomSize() {
const dom = this.$refs.container
if (!this.parentNodeResizeObserver) {
this.parentNodeResizeObserver = new ResizeObserver(entries => {
this.updatePlayerDomSize()
})
this.parentNodeResizeObserver.observe(dom.parentNode)
}
const boxWidth = dom.parentNode.clientWidth
const boxHeight = dom.parentNode.clientHeight
let width = boxWidth
let height = (9 / 16) * width
if (boxHeight > 0 && boxWidth > boxHeight / 9 * 16) {
height = boxHeight
width = boxHeight / 9 * 16
}
const clientHeight = Math.min(document.body.clientHeight, document.documentElement.clientHeight)
if (height > clientHeight) {
height = clientHeight
width = (16 / 9) * height
}
this.$refs.playerBox.style.width = width + 'px'
this.$refs.playerBox.style.height = height + 'px'
this.playerWidth = width
this.playerHeight = height
if (this.playing) {
h265webPlayer[this._uid].resize(this.playerWidth, this.playerHeight)
}
},
resize(width, height) {
this.playerWidth = width
this.playerHeight = height
this.$refs.playerBox.style.width = width + 'px'
this.$refs.playerBox.style.height = height + 'px'
if (this.playing) {
h265webPlayer[this._uid].resize(this.playerWidth, this.playerHeight)
}
},
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 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.onLoadFinish = () => {
this.loaded = true
// mediaInfo
// @see https://github.com/numberwolf/h265web.js/blob/8b26a31ffa419bd0a0f99fbd5111590e144e36a8/example_normal/index.js#L252C9-L263C11
this.mediaInfo = h265web.mediaInfo()
}
h265web.onPlayTime = (videoPTS) => {
this.$emit('playTimeChange', videoPTS * 1000)
}
// h265web.do()
},
screenshot: function() {
if (h265webPlayer[this._uid]) {
const canvas = document.createElement('canvas')
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
//
const link = document.createElement('a')
link.download = 'screenshot.png'
link.href = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream')
link.click()
}
},
playBtnClick: function(event) {
this.play(this.videoUrl)
},
refresh: function() {
this.play(this.videoUrl)
},
play: function(url) {
if (h265webPlayer[this._uid]) {
this.destroy()
}
if (!url) {
return
}
if (this.playerWidth === 0 || this.playerHeight === 0) {
this.updatePlayerDomSize()
setTimeout(() => {
this.play(url)
}, 300)
return
}
this.create(url)
},
unPause: function() {
if (h265webPlayer[this._uid]) {
h265webPlayer[this._uid].play()
this.playing = true
}
this.err = ''
},
pause: function() {
if (h265webPlayer[this._uid]) {
h265webPlayer[this._uid].pause()
this.playing = false
}
this.err = ''
},
mute: function() {
if (h265webPlayer[this._uid]) {
h265webPlayer[this._uid].setVoice(0.0)
this.isNotMute = false
}
},
cancelMute: function() {
if (h265webPlayer[this._uid]) {
h265webPlayer[this._uid].setVoice(1.0)
this.isNotMute = true
}
},
destroy: function() {
if (h265webPlayer[this._uid]) {
h265webPlayer[this._uid].release()
}
h265webPlayer[this._uid] = null
this.playing = false
this.err = ''
},
fullscreenSwich: function() {
const isFull = this.isFullscreen()
if (isFull) {
h265webPlayer[this._uid].closeFullScreen()
} else {
h265webPlayer[this._uid].fullScreen()
}
this.fullscreen = !isFull
},
isFullscreen: function() {
return document.fullscreenElement ||
document.msFullscreenElement ||
document.mozFullScreenElement ||
document.webkitFullscreenElement || false
},
setPlaybackRate: function(speed) {
h265webPlayer[this._uid].setPlaybackRate(speed)
}
}
}
</script>
<style>
.play-loading {
width: 100%;
height: 100%;
color: rgb(255, 255, 255);
display: flex;
align-items: center;
margin: 0 auto;
justify-content: center;
font-size: 18px;
}
.buttons-box {
width: 100%;
height: 28px;
background-color: rgba(43, 51, 63, 0.7);
position: absolute;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
left: 0;
bottom: 0;
user-select: none;
z-index: 10;
}
.h265web-btn {
width: 20px;
color: rgb(255, 255, 255);
line-height: 27px;
margin: 0px 10px;
padding: 0px 2px;
cursor: pointer;
text-align: center;
font-size: 0.8rem !important;
}
.buttons-box-right {
position: absolute;
right: 0;
}
.player-loading {
width: fit-content;
height: 30px;
position: absolute;
left: calc(50% - 52px);
top: calc(50% - 52px);
color: #fff;
font-size: 16px;
}
.player-loading i{
font-size: 24px;
line-height: 24px;
text-align: center;
display: block;
}
.player-loading span{
display: inline-block;
font-size: 16px;
height: 24px;
line-height: 24px;
}
</style>

View File

@ -65,16 +65,22 @@ export default {
.then(data => { .then(data => {
this.listChangeCallback() this.listChangeCallback()
}) })
.catch(function(error) { .catch((error) => {
console.log(error) this.$message.error({
showClose: true,
message: error
})
}) })
} else { } else {
this.$store.dispatch('jtDevice/add', this.form) this.$store.dispatch('jtDevice/add', this.form)
.then(data => { .then(data => {
this.listChangeCallback() this.listChangeCallback()
}) })
.catch(function(error) { .catch((error) => {
console.log(error) this.$message.error({
showClose: true,
message: error
})
}) })
} }
}, },