web页面集成

This commit is contained in:
648540858
2020-10-10 17:33:02 +08:00
parent 57fd18cd7c
commit d881c98224
32 changed files with 240 additions and 223 deletions

View File

@@ -31,6 +31,9 @@ public class MediaServerConfig {
@JSONField(name = "general.streamNoneReaderDelayMS")
private String generalStreamNoneReaderDelayMS;
@JSONField(name = "general.localIP")
private String localIP;
@JSONField(name = "hls.fileBufSize")
private String hlsFileBufSize;
@@ -163,6 +166,18 @@ public class MediaServerConfig {
@JSONField(name = "rtp.videoMtuSize")
private String rtpVideoMtuSize;
@JSONField(name = "rtp_proxy.checkSource")
private String rtpProxyCheckSource;
@JSONField(name = "rtp_proxy.dumpDir")
private String rtpProxyDumpDir;
@JSONField(name = "rtp_proxy.port")
private String rtpProxyPort;
@JSONField(name = "rtp_proxy.timeoutSec")
private String rtpProxyTimeoutSec;
@JSONField(name = "rtsp.authBasic")
private String rtspAuthBasic;
@@ -664,4 +679,44 @@ public class MediaServerConfig {
public void setShellPhell(String shellPhell) {
this.shellPhell = shellPhell;
}
public String getLocalIP() {
return localIP;
}
public void setLocalIP(String localIP) {
this.localIP = localIP;
}
public String getRtpProxyCheckSource() {
return rtpProxyCheckSource;
}
public void setRtpProxyCheckSource(String rtpProxyCheckSource) {
this.rtpProxyCheckSource = rtpProxyCheckSource;
}
public String getRtpProxyDumpDir() {
return rtpProxyDumpDir;
}
public void setRtpProxyDumpDir(String rtpProxyDumpDir) {
this.rtpProxyDumpDir = rtpProxyDumpDir;
}
public String getRtpProxyPort() {
return rtpProxyPort;
}
public void setRtpProxyPort(String rtpProxyPort) {
this.rtpProxyPort = rtpProxyPort;
}
public String getRtpProxyTimeoutSec() {
return rtpProxyTimeoutSec;
}
public void setRtpProxyTimeoutSec(String rtpProxyTimeoutSec) {
this.rtpProxyTimeoutSec = rtpProxyTimeoutSec;
}
}

View File

@@ -16,10 +16,6 @@ public class SipConfig {
String sipId;
@Value("${sip.password}")
String sipPassword;
@Value("${media.ip}")
String mediaIp;
@Value("${media.port}")
Integer mediaPort;
@Value("${sip.ptz.speed:50}")
Integer speed;
@@ -56,22 +52,6 @@ public class SipConfig {
this.sipPassword = sipPassword;
}
public String getMediaIp() {
return mediaIp;
}
public void setMediaIp(String mediaIp) {
this.mediaIp = mediaIp;
}
public Integer getMediaPort() {
return mediaPort;
}
public void setMediaPort(Integer mediaPort) {
this.mediaPort = mediaPort;
}
public Integer getSpeed() {
return speed;
}

View File

@@ -103,9 +103,14 @@ public class DeviceChannel {
private String password;
/**
* 云台控制
* 云台类型
*/
private int PTZType;
/**
* 云台类型描述字符串
*/
private String PTZTypeText;
/**
* 在线/离线
@@ -328,6 +333,27 @@ public class DeviceChannel {
public void setPTZType(int PTZType) {
this.PTZType = PTZType;
switch (PTZType) {
case 0:
this.PTZTypeText = "未知";
break;
case 1:
this.PTZTypeText = "球机";
break;
case 2:
this.PTZTypeText = "半球";
break;
case 3:
this.PTZTypeText = "固定枪机";
break;
case 4:
this.PTZTypeText = "遥控枪机";
break;
}
}
public String getPTZTypeText() {
return PTZTypeText;
}
public String getSsrc() {

View File

@@ -60,9 +60,7 @@ public class SIPCommander implements ISIPCommander {
@Qualifier(value="udpSipProvider")
private SipProvider udpSipProvider;
@Value("${media.ip}")
private String mediaIp;
/**
* 云台方向放控制,使用配置文件中的默认镜头移动速度
*
@@ -207,18 +205,19 @@ public class SIPCommander implements ISIPCommander {
String ssrc = streamSession.createPlaySsrc();
String transport = device.getTransport();
MediaServerConfig mediaInfo = storager.getMediaInfo();
//
StringBuffer content = new StringBuffer(200);
content.append("v=0\r\n");
content.append("o="+channelId+" 0 0 IN IP4 "+sipConfig.getSipIp()+"\r\n");
content.append("o="+channelId+" 0 0 IN IP4 "+mediaInfo.getLocalIP()+"\r\n");
content.append("s=Play\r\n");
content.append("c=IN IP4 "+sipConfig.getMediaIp()+"\r\n");
content.append("c=IN IP4 "+mediaInfo.getLocalIP()+"\r\n");
content.append("t=0 0\r\n");
if("TCP".equals(transport)) {
content.append("m=video "+sipConfig.getMediaPort()+" TCP/RTP/AVP 96 98 97\r\n");
content.append("m=video "+mediaInfo.getRtpProxyPort()+" TCP/RTP/AVP 96 98 97\r\n");
}
if("UDP".equals(transport)) {
content.append("m=video "+sipConfig.getMediaPort()+" RTP/AVP 96 98 97\r\n");
content.append("m=video "+mediaInfo.getRtpProxyPort()+" RTP/AVP 96 98 97\r\n");
}
content.append("a=recvonly\r\n");
content.append("a=rtpmap:96 PS/90000\r\n");
@@ -239,16 +238,16 @@ public class SIPCommander implements ISIPCommander {
deviceChannel.setSsrc(ssrc);
storager.updateChannel(device.getDeviceId(), deviceChannel);
}
MediaServerConfig mediaInfo = storager.getMediaInfo();
StreamInfo streamInfo = new StreamInfo();
streamInfo.setSsrc(ssrc);
// String streamId = Integer.toHexString(Integer.parseInt(streamInfo.getSsrc()));
String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase(); // ZLM 要求大写且首位补零
streamInfo.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaIp, mediaInfo.getHttpPort(), streamId));
streamInfo.setWS_FLV(String.format("ws://%s:%s/rtp/%s.flv", mediaIp, mediaInfo.getHttpPort(), streamId));
streamInfo.setRTMP(String.format("rtmp://%s:%s/rtp/%s", mediaIp, mediaInfo.getRtmpPort(), streamId));
streamInfo.setHLS(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaIp, mediaInfo.getHttpPort(), streamId));
streamInfo.setRTSP(String.format("rtsp://%s:%s/rtp/%s", mediaIp, mediaInfo.getRtspPort(), streamId));
streamInfo.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId));
streamInfo.setWS_FLV(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId));
streamInfo.setRTMP(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getLocalIP(), mediaInfo.getRtmpPort(), streamId));
streamInfo.setHLS(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId));
streamInfo.setRTSP(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getLocalIP(), mediaInfo.getRtspPort(), streamId));
storager.startPlay(device.getDeviceId(), channelId, streamInfo);
return streamInfo;
@@ -269,7 +268,7 @@ public class SIPCommander implements ISIPCommander {
@Override
public String playbackStreamCmd(Device device, String channelId, String startTime, String endTime) {
try {
MediaServerConfig mediaInfo = storager.getMediaInfo();
String ssrc = streamSession.createPlayBackSsrc();
//
StringBuffer content = new StringBuffer(200);
@@ -277,13 +276,13 @@ public class SIPCommander implements ISIPCommander {
content.append("o="+sipConfig.getSipId()+" 0 0 IN IP4 "+sipConfig.getSipIp()+"\r\n");
content.append("s=Playback\r\n");
content.append("u="+channelId+":0\r\n");
content.append("c=IN IP4 "+sipConfig.getMediaIp()+"\r\n");
content.append("c=IN IP4 "+mediaInfo.getLocalIP()+"\r\n");
content.append("t="+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)+" "+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) +"\r\n");
if(device.getTransport().equals("TCP")) {
content.append("m=video "+sipConfig.getMediaPort()+" TCP/RTP/AVP 96 98 97\r\n");
content.append("m=video "+mediaInfo.getRtpProxyPort()+" TCP/RTP/AVP 96 98 97\r\n");
}
if(device.getTransport().equals("UDP")) {
content.append("m=video "+sipConfig.getMediaPort()+" RTP/AVP 96 98 97\r\n");
content.append("m=video "+mediaInfo.getRtpProxyPort()+" RTP/AVP 96 98 97\r\n");
}
content.append("a=recvonly\r\n");
content.append("a=rtpmap:96 PS/90000\r\n");
@@ -300,6 +299,7 @@ public class SIPCommander implements ISIPCommander {
ClientTransaction transaction = transmitRequest(device, request);
streamSession.put(ssrc, transaction);
return ssrc;
} catch ( SipException | ParseException | InvalidArgumentException e) {
e.printStackTrace();
return null;
@@ -473,6 +473,8 @@ public class SIPCommander implements ISIPCommander {
*/
@Override
public boolean catalogQuery(Device device) {
// 清空通道
storager.cleanChannelsForDevice(device.getDeviceId());
try {
StringBuffer catalogXml = new StringBuffer(200);
catalogXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>");

View File

@@ -1,43 +0,0 @@
package com.genersoft.iot.vmp.media.zlm;
import com.google.common.collect.ImmutableMap;
import org.mitre.dsmiley.httpproxy.ProxyServlet;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Servlet;
import java.util.Map;
/**
* 对查询流媒体信息的请求进行反向代理
*/
@Configuration
public class SolrProxyServletConfiguration {
// 读取配置文件中路由设置
@Value("${proxy.servlet_url}")
private String servlet_url;
// 读取配置中代理目标地址
@Value("${proxy.target_url}")
private String target_url;
@Bean
public Servlet createProxyServlet(){
// 创建新的ProxyServlet
return new ProxyServlet();
}
@Bean
public ServletRegistrationBean proxyServletRegistration(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean(createProxyServlet(), servlet_url);
//设置网址以及参数
Map<String, String> params = ImmutableMap.of(
"targetUri", target_url,
"log", "true");
registrationBean.setInitParameters(params);
return registrationBean;
}
}

View File

@@ -0,0 +1,58 @@
package com.genersoft.iot.vmp.media.zlm;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import org.apache.http.HttpResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Enumeration;
@RestController
@RequestMapping("/zlm")
public class ZLMHTTPProxyController {
private final static Logger logger = LoggerFactory.getLogger(ZLMHTTPProxyController.class);
@Autowired
private IVideoManagerStorager storager;
@ResponseBody
@RequestMapping(value = "/**/**/**", produces = "application/json;charset=UTF-8")
public Object proxy(HttpServletRequest request, HttpServletResponse response){
if (storager.getMediaInfo() == null) {
return "未接入流媒体";
}
String requestURI = String.format("http://%s:%s%s?%s&%s",
storager.getMediaInfo().getLocalIP(),
storager.getMediaInfo().getHttpPort(),
request.getRequestURI().replace("/zlm",""),
storager.getMediaInfo().getHookAdminParams(),
request.getQueryString()
);
// 发送请求
RestTemplate restTemplate = new RestTemplate();
//将指定的url返回的参数自动封装到自定义好的对应类对象中
Object result = null;
try {
result = restTemplate.getForObject(requestURI,Object.class);
}catch (HttpClientErrorException httpClientErrorException) {
response.setStatus(httpClientErrorException.getStatusCode().value());
}
return result;
}
}

View File

@@ -8,6 +8,7 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.genersoft.iot.vmp.conf.MediaServerConfig;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.IpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -22,6 +23,8 @@ import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import javax.servlet.http.HttpServletRequest;
/**
* @Description:针对 ZLMediaServer的hook事件监听
* @author: swwheihei
@@ -267,7 +270,7 @@ public class ZLMHttpHookListener {
*/
@ResponseBody
@PostMapping(value = "/on_server_started", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> onServerStarted(@RequestBody JSONObject json){
public ResponseEntity<String> onServerStarted(HttpServletRequest request, @RequestBody JSONObject json){
if (logger.isDebugEnabled()) {
logger.debug("ZLM HOOK on_server_started API调用参数" + json.toString());

View File

@@ -176,4 +176,10 @@ public interface IVideoManagerStorager {
* 更新缓存
*/
public void updateCatch();
/**
* 清空通道
* @param deviceId
*/
void cleanChannelsForDevice(String deviceId);
}

View File

@@ -171,4 +171,9 @@ public class VideoManagerJdbcStoragerImpl implements IVideoManagerStorager {
public void updateCatch() {
}
@Override
public void cleanChannelsForDevice(String deviceId) {
}
}

View File

@@ -399,13 +399,13 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
for (int i = 0; i < deviceChannelList.size(); i++) {
String key = (String)deviceChannelList.get(i);
String[] s = key.split("_");
String channelId = s[3];
String channelId = s[3].split(":")[0];
HashSet<String> subChannel = channelMap.get(channelId);
if (subChannel == null) {
subChannel = new HashSet<>();
}
if (s.length > 4) {
subChannel.add(s[4]);
if ("null".equals(s[6])) {
subChannel.add(s[6]);
}
channelMap.put(channelId, subChannel);
System.out.println();
@@ -414,4 +414,15 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
deviceMap.put(device.getDeviceId(),channelMap);
}
}
@Override
public void cleanChannelsForDevice(String deviceId) {
List<DeviceChannel> result = new ArrayList<>();
List<Object> deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*");
if (deviceChannelList != null && deviceChannelList.size() > 0 ) {
for (int i = 0; i < deviceChannelList.size(); i++) {
redis.del((String)deviceChannelList.get(i));
}
}
}
}

View File

@@ -0,0 +1,48 @@
package com.genersoft.iot.vmp.utils;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class IpUtil {
public static String getIpAddr(HttpServletRequest request) {
String ipAddress = null;
try {
ipAddress = request.getHeader("x-forwarded-for");
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getRemoteAddr();
if (ipAddress.equals("127.0.0.1")) {
// 根据网卡取本机配置的IP
InetAddress inet = null;
try {
inet = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
ipAddress = inet.getHostAddress();
}
}
// 对于通过多个代理的情况第一个IP为客户端真实IP,多个IP按照','分割
if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
// = 15
if (ipAddress.indexOf(",") > 0) {
ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
}
}
} catch (Exception e) {
ipAddress="";
}
// ipAddress = this.getRequest().getRemoteAddr();
return ipAddress;
}
}

View File

@@ -85,9 +85,9 @@ public class DeviceController {
public DeferredResult<ResponseEntity<Device>> devicesSync(@PathVariable String deviceId){
if (logger.isDebugEnabled()) {
logger.debug("设备信息同步API调用deviceId" + deviceId);
}
logger.debug("设备信息同步API调用deviceId" + deviceId);
Device device = storager.queryVideoDevice(deviceId);
cmder.catalogQuery(device);
DeferredResult<ResponseEntity<Device>> result = new DeferredResult<ResponseEntity<Device>>();

View File

@@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.vmanager.play;
import com.alibaba.fastjson.JSON;
import com.genersoft.iot.vmp.common.StreamInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -43,9 +44,7 @@ public class PlayController {
}
if(streamInfo!=null) {
JSONObject json = new JSONObject();
json.put("ssrc", streamInfo.getSsrc());
return new ResponseEntity<String>(json.toString(),HttpStatus.OK);
return new ResponseEntity<String>(JSON.toJSONString(streamInfo),HttpStatus.OK);
} else {
logger.warn("设备预览API调用失败");
return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR);