添加云端录像功能
This commit is contained in:
@@ -51,6 +51,9 @@ public class MediaConfig {
|
||||
@Value("${media.rtp.portRange}")
|
||||
private String rtpPortRange;
|
||||
|
||||
@Value("${media.recordAssistPort}")
|
||||
private int recordAssistPort;
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
@@ -174,4 +177,12 @@ public class MediaConfig {
|
||||
public void setRtspSSLPort(String rtspSSLPort) {
|
||||
this.rtspSSLPort = rtspSSLPort;
|
||||
}
|
||||
|
||||
public int getRecordAssistPort() {
|
||||
return recordAssistPort;
|
||||
}
|
||||
|
||||
public void setRecordAssistPort(int recordAssistPort) {
|
||||
this.recordAssistPort = recordAssistPort;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.genersoft.iot.vmp.conf;
|
||||
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.mitre.dsmiley.httpproxy.ProxyServlet;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import java.io.IOException;
|
||||
import java.net.ConnectException;
|
||||
import java.util.Locale;
|
||||
|
||||
|
||||
@Configuration
|
||||
public class ProxyServletConfig {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(ProxyServletConfig.class);
|
||||
|
||||
@Autowired
|
||||
private MediaConfig mediaConfig;
|
||||
|
||||
@Bean
|
||||
public ServletRegistrationBean zlmServletRegistrationBean(){
|
||||
String ip = StringUtils.isEmpty(mediaConfig.getWanIp())? mediaConfig.getIp(): mediaConfig.getWanIp();
|
||||
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new ZLMProxySerlet(),"/zlm/*");
|
||||
servletRegistrationBean.setName("zlm_Proxy");
|
||||
servletRegistrationBean.addInitParameter("targetUri", String.format("http://%s:%s", ip, mediaConfig.getHttpPort()));
|
||||
if (logger.isDebugEnabled()) {
|
||||
servletRegistrationBean.addInitParameter("log", "true");
|
||||
}
|
||||
return servletRegistrationBean;
|
||||
}
|
||||
|
||||
class ZLMProxySerlet extends ProxyServlet{
|
||||
@Override
|
||||
protected void handleRequestException(HttpRequest proxyRequest, HttpResponse proxyResonse, Exception e){
|
||||
System.out.println(e.getMessage());
|
||||
try {
|
||||
super.handleRequestException(proxyRequest, proxyResonse, e);
|
||||
} catch (ServletException servletException) {
|
||||
logger.error("zlm 代理失败: ", e);
|
||||
} catch (IOException ioException) {
|
||||
if (ioException instanceof ConnectException) {
|
||||
logger.error("zlm 连接失败");
|
||||
}else {
|
||||
logger.error("zlm 代理失败: ", e);
|
||||
}
|
||||
} catch (RuntimeException exception){
|
||||
logger.error("zlm 代理失败: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -43,7 +43,6 @@ public class RedisConfig extends CachingConfigurerSupport {
|
||||
* 通过反射技术调用消息订阅处理器的相关方法进行一些业务处理
|
||||
*
|
||||
* @param connectionFactory
|
||||
* @param listenerAdapter
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
|
||||
@@ -8,11 +8,53 @@ public class UserSetup {
|
||||
@Value("${userSettings.savePositionHistory}")
|
||||
boolean savePositionHistory;
|
||||
|
||||
@Value("${userSettings.autoApplyPlay}")
|
||||
private boolean autoApplyPlay;
|
||||
|
||||
@Value("${userSettings.seniorSdp}")
|
||||
private boolean seniorSdp;
|
||||
|
||||
@Value("${userSettings.playTimeout}")
|
||||
private long playTimeout;
|
||||
|
||||
@Value("${userSettings.waitTrack}")
|
||||
private boolean waitTrack;
|
||||
|
||||
@Value("${userSettings.interfaceAuthentication}")
|
||||
private boolean interfaceAuthentication;
|
||||
|
||||
@Value("${userSettings.recordPushLive}")
|
||||
private boolean recordPushLive;
|
||||
|
||||
public boolean getSavePositionHistory() {
|
||||
return savePositionHistory;
|
||||
}
|
||||
|
||||
public void setSavePositionHistory(boolean savePositionHistory) {
|
||||
this.savePositionHistory = savePositionHistory;
|
||||
public boolean isSavePositionHistory() {
|
||||
return savePositionHistory;
|
||||
}
|
||||
|
||||
public boolean isAutoApplyPlay() {
|
||||
return autoApplyPlay;
|
||||
}
|
||||
|
||||
public boolean isSeniorSdp() {
|
||||
return seniorSdp;
|
||||
}
|
||||
|
||||
public long getPlayTimeout() {
|
||||
return playTimeout;
|
||||
}
|
||||
|
||||
public boolean isWaitTrack() {
|
||||
return waitTrack;
|
||||
}
|
||||
|
||||
public boolean isInterfaceAuthentication() {
|
||||
return interfaceAuthentication;
|
||||
}
|
||||
|
||||
public boolean isRecordPushLive() {
|
||||
return recordPushLive;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.genersoft.iot.vmp.conf.security;
|
||||
|
||||
import com.genersoft.iot.vmp.conf.UserSetup;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -22,8 +23,8 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Value("${userSettings.interfaceAuthentication}")
|
||||
private boolean interfaceAuthentication;
|
||||
@Autowired
|
||||
private UserSetup userSetup;
|
||||
|
||||
@Autowired
|
||||
private DefaultUserDetailsServiceImpl userDetailsService;
|
||||
@@ -71,7 +72,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
public void configure(WebSecurity web) {
|
||||
|
||||
if (!interfaceAuthentication) {
|
||||
if (!userSetup.isInterfaceAuthentication()) {
|
||||
web.ignoring().antMatchers("**");
|
||||
}else {
|
||||
// 可以直接访问的静态数据
|
||||
|
||||
@@ -32,7 +32,7 @@ public class KeepaliveTimeoutListenerForPlatform extends KeyExpirationEventMessa
|
||||
/**
|
||||
* 监听失效的key
|
||||
* @param message
|
||||
* @param bytes
|
||||
* @param pattern
|
||||
*/
|
||||
@Override
|
||||
public void onMessage(Message message, byte[] pattern) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.conf.UserSetup;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
|
||||
@@ -24,7 +25,6 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -83,14 +83,8 @@ public class SIPCommander implements ISIPCommander {
|
||||
@Autowired
|
||||
private MediaConfig mediaConfig;
|
||||
|
||||
@Value("${userSettings.seniorSdp}")
|
||||
private boolean seniorSdp;
|
||||
|
||||
@Value("${userSettings.autoApplyPlay}")
|
||||
private boolean autoApplyPlay;
|
||||
|
||||
@Value("${userSettings.waitTrack}")
|
||||
private boolean waitTrack;
|
||||
@Autowired
|
||||
private UserSetup userSetup;
|
||||
|
||||
@Autowired
|
||||
private ZLMHttpHookSubscribe subscribe;
|
||||
@@ -377,7 +371,7 @@ public class SIPCommander implements ISIPCommander {
|
||||
subscribeKey.put("regist", true);
|
||||
|
||||
subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, json->{
|
||||
if (waitTrack && json.getJSONArray("tracks") == null) return;
|
||||
if (userSetup.isWaitTrack() && json.getJSONArray("tracks") == null) return;
|
||||
event.response(json);
|
||||
subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
|
||||
});
|
||||
@@ -390,7 +384,7 @@ public class SIPCommander implements ISIPCommander {
|
||||
content.append("c=IN IP4 "+mediaInfo.getWanIp()+"\r\n");
|
||||
content.append("t=0 0\r\n");
|
||||
|
||||
if (seniorSdp) {
|
||||
if (userSetup.isSeniorSdp()) {
|
||||
if("TCP-PASSIVE".equals(streamMode)) {
|
||||
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
|
||||
}else if ("TCP-ACTIVE".equals(streamMode)) {
|
||||
@@ -478,7 +472,7 @@ public class SIPCommander implements ISIPCommander {
|
||||
subscribeKey.put("regist", true);
|
||||
logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
|
||||
subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, json->{
|
||||
if (waitTrack && json.getJSONArray("tracks") == null) return;
|
||||
if (userSetup.isWaitTrack() && json.getJSONArray("tracks") == null) return;
|
||||
event.response(json);
|
||||
subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
|
||||
});
|
||||
@@ -500,7 +494,7 @@ public class SIPCommander implements ISIPCommander {
|
||||
}
|
||||
String streamMode = device.getStreamMode().toUpperCase();
|
||||
|
||||
if (seniorSdp) {
|
||||
if (userSetup.isSeniorSdp()) {
|
||||
if("TCP-PASSIVE".equals(streamMode)) {
|
||||
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
|
||||
}else if ("TCP-ACTIVE".equals(streamMode)) {
|
||||
|
||||
@@ -1,54 +1,54 @@
|
||||
package com.genersoft.iot.vmp.media.zlm;
|
||||
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
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;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/zlm")
|
||||
public class ZLMHTTPProxyController {
|
||||
|
||||
|
||||
// private final static Logger logger = LoggerFactory.getLogger(ZLMHTTPProxyController.class);
|
||||
|
||||
@Autowired
|
||||
private IRedisCatchStorage redisCatchStorage;
|
||||
|
||||
@Autowired
|
||||
private MediaConfig mediaConfig;
|
||||
|
||||
@ResponseBody
|
||||
@RequestMapping(value = "/**/**/**", produces = "application/json;charset=UTF-8")
|
||||
public Object proxy(HttpServletRequest request, HttpServletResponse response){
|
||||
|
||||
if (redisCatchStorage.getMediaInfo() == null) {
|
||||
return "未接入流媒体";
|
||||
}
|
||||
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
|
||||
String requestURI = String.format("http://%s:%s%s?%s&%s",
|
||||
mediaInfo.getLocalIP(),
|
||||
mediaConfig.getHttpPort(),
|
||||
request.getRequestURI().replace("/zlm",""),
|
||||
mediaInfo.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;
|
||||
}
|
||||
}
|
||||
//package com.genersoft.iot.vmp.media.zlm;
|
||||
//
|
||||
//import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
//import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
//import org.springframework.beans.factory.annotation.Autowired;
|
||||
//import org.springframework.beans.factory.annotation.Value;
|
||||
//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;
|
||||
//
|
||||
//@RestController
|
||||
//@RequestMapping("/zlm")
|
||||
//public class ZLMHTTPProxyController {
|
||||
//
|
||||
//
|
||||
// // private final static Logger logger = LoggerFactory.getLogger(ZLMHTTPProxyController.class);
|
||||
//
|
||||
// @Autowired
|
||||
// private IRedisCatchStorage redisCatchStorage;
|
||||
//
|
||||
// @Autowired
|
||||
// private MediaConfig mediaConfig;
|
||||
//
|
||||
// @ResponseBody
|
||||
// @RequestMapping(value = "/**/**/**", produces = "application/json;charset=UTF-8")
|
||||
// public Object proxy(HttpServletRequest request, HttpServletResponse response){
|
||||
//
|
||||
// if (redisCatchStorage.getMediaInfo() == null) {
|
||||
// return "未接入流媒体";
|
||||
// }
|
||||
// ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
|
||||
// String requestURI = String.format("http://%s:%s%s?%s&%s",
|
||||
// mediaInfo.getLocalIP(),
|
||||
// mediaConfig.getHttpPort(),
|
||||
// request.getRequestURI().replace("/zlm",""),
|
||||
// mediaInfo.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;
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.conf.UserSetup;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
@@ -62,8 +63,8 @@ public class ZLMHttpHookListener {
|
||||
@Autowired
|
||||
private ZLMHttpHookSubscribe subscribe;
|
||||
|
||||
@Value("${userSettings.autoApplyPlay}")
|
||||
private boolean autoApplyPlay;
|
||||
@Autowired
|
||||
private UserSetup userSetup;
|
||||
|
||||
@Autowired
|
||||
private MediaConfig mediaConfig;
|
||||
@@ -132,10 +133,8 @@ public class ZLMHttpHookListener {
|
||||
@ResponseBody
|
||||
@PostMapping(value = "/on_publish", produces = "application/json;charset=UTF-8")
|
||||
public ResponseEntity<String> onPublish(@RequestBody JSONObject json){
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("ZLM HOOK on_publish API调用,参数:" + json.toString());
|
||||
}
|
||||
|
||||
logger.debug("ZLM HOOK on_publish API调用,参数:" + json.toString());
|
||||
|
||||
ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json);
|
||||
if (subscribe != null) subscribe.response(json);
|
||||
@@ -144,7 +143,7 @@ public class ZLMHttpHookListener {
|
||||
ret.put("code", 0);
|
||||
ret.put("msg", "success");
|
||||
ret.put("enableHls", true);
|
||||
ret.put("enableMP4", false);
|
||||
ret.put("enableMP4", userSetup.isRecordPushLive());
|
||||
ret.put("enableRtxp", true);
|
||||
return new ResponseEntity<String>(ret.toString(),HttpStatus.OK);
|
||||
}
|
||||
@@ -333,7 +332,7 @@ public class ZLMHttpHookListener {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("ZLM HOOK on_stream_not_found API调用,参数:" + json.toString());
|
||||
}
|
||||
if (autoApplyPlay) {
|
||||
if (userSetup.isAutoApplyPlay()) {
|
||||
String app = json.getString("app");
|
||||
String streamId = json.getString("stream");
|
||||
StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
|
||||
|
||||
@@ -109,6 +109,10 @@ public class ZLMRunner implements CommandLineRunner {
|
||||
if (StringUtils.isEmpty(mediaConfig.getHookIp())) mediaConfig.setHookIp(sipConfig.getSipIp());
|
||||
String protocol = sslEnabled ? "https" : "http";
|
||||
String hookPrex = String.format("%s://%s:%s/index/hook", protocol, mediaConfig.getHookIp(), serverPort);
|
||||
String recordHookPrex = null;
|
||||
if (mediaConfig.getRecordAssistPort() != 0) {
|
||||
recordHookPrex = String.format("http://127.0.0.1:%s/api/record", mediaConfig.getRecordAssistPort());
|
||||
}
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("api.secret",mediaConfig.getSecret()); // -profile:v Baseline
|
||||
param.put("ffmpeg.cmd","%s -fflags nobuffer -rtsp_transport tcp -i %s -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s");
|
||||
@@ -116,8 +120,8 @@ public class ZLMRunner implements CommandLineRunner {
|
||||
param.put("hook.on_flow_report","");
|
||||
param.put("hook.on_play",String.format("%s/on_play", hookPrex));
|
||||
param.put("hook.on_http_access","");
|
||||
param.put("hook.on_publish",String.format("%s/on_publish", hookPrex));
|
||||
param.put("hook.on_record_mp4","");
|
||||
param.put("hook.on_publish", String.format("%s/on_publish", hookPrex));
|
||||
param.put("hook.on_record_mp4",recordHookPrex != null? String.format("%s/on_record_mp4", recordHookPrex): "");
|
||||
param.put("hook.on_record_ts","");
|
||||
param.put("hook.on_rtsp_auth","");
|
||||
param.put("hook.on_rtsp_realm","");
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.genersoft.iot.vmp.service;
|
||||
|
||||
import com.genersoft.iot.vmp.storager.dao.dto.RecordInfo;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
|
||||
public interface IRecordInfoServer {
|
||||
PageInfo<RecordInfo> getRecordList(int page, int count);
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.conf.UserSetup;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
|
||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||
@@ -64,8 +65,8 @@ public class PlayServiceImpl implements IPlayService {
|
||||
@Autowired
|
||||
private VideoStreamSessionManager streamSession;
|
||||
|
||||
@Value("${userSettings.playTimeout}")
|
||||
private long playTimeout;
|
||||
@Autowired
|
||||
private UserSetup userSetup;
|
||||
|
||||
|
||||
@Override
|
||||
@@ -76,7 +77,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
playResult.setDevice(device);
|
||||
UUID uuid = UUID.randomUUID();
|
||||
playResult.setUuid(uuid.toString());
|
||||
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(playTimeout);
|
||||
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(userSetup.getPlayTimeout());
|
||||
playResult.setResult(result);
|
||||
// 录像查询以channelId作为deviceId查询
|
||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result);
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.genersoft.iot.vmp.service.impl;
|
||||
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
|
||||
import com.genersoft.iot.vmp.service.IRecordInfoServer;
|
||||
import com.genersoft.iot.vmp.storager.dao.RecordInfoDao;
|
||||
import com.genersoft.iot.vmp.storager.dao.dto.RecordInfo;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class RecordInfoServerImpl implements IRecordInfoServer {
|
||||
|
||||
@Autowired
|
||||
private RecordInfoDao recordInfoDao;
|
||||
|
||||
@Override
|
||||
public PageInfo<RecordInfo> getRecordList(int page, int count) {
|
||||
PageHelper.startPage(page, count);
|
||||
List<RecordInfo> all = recordInfoDao.selectAll();
|
||||
return new PageInfo<>(all);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.genersoft.iot.vmp.storager.dao;
|
||||
|
||||
import com.genersoft.iot.vmp.storager.dao.dto.RecordInfo;
|
||||
import com.genersoft.iot.vmp.storager.dao.dto.User;
|
||||
import org.apache.ibatis.annotations.Delete;
|
||||
import org.apache.ibatis.annotations.Insert;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
@Repository
|
||||
public interface RecordInfoDao {
|
||||
|
||||
@Insert("INSERT INTO recordInfo (app, stream, mediaServerId, createTime, type, deviceId, channelId, name) VALUES" +
|
||||
"('${app}', '${stream}', '${mediaServerId}', datetime('now','localtime')), '${type}', '${deviceId}', '${channelId}', '${name}'")
|
||||
int add(RecordInfo recordInfo);
|
||||
|
||||
@Delete("DELETE FROM user WHERE createTime < '${beforeTime}'")
|
||||
int deleteBefore(String beforeTime);
|
||||
|
||||
@Select("select * FROM recordInfo")
|
||||
List<RecordInfo> selectAll();
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package com.genersoft.iot.vmp.storager.dao.dto;
|
||||
|
||||
/**
|
||||
* 录像记录
|
||||
*/
|
||||
public class RecordInfo {
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
private int id;
|
||||
|
||||
/**
|
||||
* 应用名
|
||||
*/
|
||||
private String app;
|
||||
|
||||
/**
|
||||
* 流ID
|
||||
*/
|
||||
private String stream;
|
||||
|
||||
/**
|
||||
* 对应的zlm流媒体的ID
|
||||
*/
|
||||
private String mediaServerId;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private String createTime;
|
||||
|
||||
/**
|
||||
* 类型 对应zlm的 originType
|
||||
* unknown = 0,
|
||||
* rtmp_push=1,
|
||||
* rtsp_push=2,
|
||||
* rtp_push=3,
|
||||
* pull=4,
|
||||
* ffmpeg_pull=5,
|
||||
* mp4_vod=6,
|
||||
* device_chn=7,
|
||||
* rtc_push=8
|
||||
*/
|
||||
private int type;
|
||||
|
||||
/**
|
||||
* 国标录像时的设备ID
|
||||
*/
|
||||
private String deviceId;
|
||||
|
||||
/**
|
||||
* 国标录像时的通道ID
|
||||
*/
|
||||
private String channelId;
|
||||
|
||||
/**
|
||||
* 拉流代理录像时的名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(String app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public String getStream() {
|
||||
return stream;
|
||||
}
|
||||
|
||||
public void setStream(String stream) {
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
public String getMediaServerId() {
|
||||
return mediaServerId;
|
||||
}
|
||||
|
||||
public void setMediaServerId(String mediaServerId) {
|
||||
this.mediaServerId = mediaServerId;
|
||||
}
|
||||
|
||||
public String getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(String createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public void setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
public String getChannelId() {
|
||||
return channelId;
|
||||
}
|
||||
|
||||
public void setChannelId(String channelId) {
|
||||
this.channelId = channelId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@@ -26,9 +26,9 @@ import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
||||
@CrossOrigin
|
||||
@RestController
|
||||
@RequestMapping("/api/gb_record")
|
||||
public class RecordController {
|
||||
public class GBRecordController {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(RecordController.class);
|
||||
private final static Logger logger = LoggerFactory.getLogger(GBRecordController.class);
|
||||
|
||||
@Autowired
|
||||
private SIPCommander cmder;
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.genersoft.iot.vmp.vmanager.record;
|
||||
|
||||
import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.net.URLDecoder;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/record_proxy")
|
||||
public class RecoderProxyController {
|
||||
|
||||
|
||||
// private final static Logger logger = LoggerFactory.getLogger(ZLMHTTPProxyController.class);
|
||||
|
||||
@Autowired
|
||||
private IRedisCatchStorage redisCatchStorage;
|
||||
|
||||
@Autowired
|
||||
private MediaConfig mediaConfig;
|
||||
|
||||
@ResponseBody
|
||||
@RequestMapping(value = "/**/**/**", produces = "application/json;charset=UTF-8")
|
||||
public Object proxy(HttpServletRequest request, HttpServletResponse response){
|
||||
|
||||
|
||||
String baseRequestURI = request.getRequestURI();
|
||||
String[] split = baseRequestURI.split("/");
|
||||
if (split.length <= 2) {
|
||||
response.setStatus(HttpStatus.NOT_FOUND.value());
|
||||
return null;
|
||||
}
|
||||
String mediaId = split[2];
|
||||
if (StringUtils.isEmpty(mediaId)){
|
||||
response.setStatus(HttpStatus.BAD_REQUEST.value());
|
||||
return null;
|
||||
}
|
||||
// 后续改为根据Id获取对应的ZLM
|
||||
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
|
||||
String requestURI = String.format("http://%s:%s%s?%s",
|
||||
mediaInfo.getLocalIP(),
|
||||
mediaConfig.getRecordAssistPort(),
|
||||
baseRequestURI.substring(baseRequestURI.indexOf(mediaId) + mediaId.length()),
|
||||
URLDecoder.decode(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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
//package com.genersoft.iot.vmp.vmanager.record;
|
||||
//
|
||||
//import com.alibaba.fastjson.JSONObject;
|
||||
//import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
|
||||
//import com.genersoft.iot.vmp.service.IRecordInfoServer;
|
||||
//import com.genersoft.iot.vmp.storager.dao.dto.RecordInfo;
|
||||
//import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||
//import com.github.pagehelper.PageInfo;
|
||||
//import io.swagger.annotations.Api;
|
||||
//import io.swagger.annotations.ApiImplicitParam;
|
||||
//import io.swagger.annotations.ApiImplicitParams;
|
||||
//import io.swagger.annotations.ApiOperation;
|
||||
//import org.springframework.beans.factory.annotation.Autowired;
|
||||
//import org.springframework.web.bind.annotation.*;
|
||||
//
|
||||
//@Api(tags = "云端录像")
|
||||
//@CrossOrigin
|
||||
//@RestController
|
||||
//@RequestMapping("/api/record")
|
||||
//public class RecordController {
|
||||
//
|
||||
// @Autowired
|
||||
// private IRecordInfoServer recordInfoServer;
|
||||
//
|
||||
// @ApiOperation("录像列表查询")
|
||||
// @ApiImplicitParams({
|
||||
// @ApiImplicitParam(name="page", value = "当前页", required = true, dataTypeClass = Integer.class),
|
||||
// @ApiImplicitParam(name="count", value = "每页查询数量", required = true, dataTypeClass = Integer.class),
|
||||
// @ApiImplicitParam(name="query", value = "查询内容", dataTypeClass = String.class),
|
||||
// })
|
||||
// @GetMapping(value = "/app/list")
|
||||
// @ResponseBody
|
||||
// public Object list(@RequestParam(required = false)Integer page,
|
||||
// @RequestParam(required = false)Integer count ){
|
||||
//
|
||||
// PageInfo<RecordInfo> recordList = recordInfoServer.getRecordList(page - 1, page - 1 + count);
|
||||
// return recordList;
|
||||
// }
|
||||
//
|
||||
// @ApiOperation("获取录像详情")
|
||||
// @ApiImplicitParams({
|
||||
// @ApiImplicitParam(name="recordInfo", value = "录像记录", required = true, dataTypeClass = RecordInfo.class)
|
||||
// })
|
||||
// @GetMapping(value = "/detail")
|
||||
// @ResponseBody
|
||||
// public JSONObject list(RecordInfo recordInfo, String time ){
|
||||
//
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
//}
|
||||
@@ -1,6 +1,9 @@
|
||||
package com.genersoft.iot.vmp.vmanager.server;
|
||||
|
||||
import com.genersoft.iot.vmp.VManageBootstrap;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.impl.RedisCatchStorageImpl;
|
||||
import com.genersoft.iot.vmp.utils.SpringBeanFactory;
|
||||
import gov.nist.javax.sip.SipStackImpl;
|
||||
import io.swagger.annotations.Api;
|
||||
@@ -12,6 +15,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
import javax.sip.ListeningPoint;
|
||||
import javax.sip.ObjectInUseException;
|
||||
import javax.sip.SipProvider;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@@ -24,6 +28,20 @@ public class ServerController {
|
||||
@Autowired
|
||||
private ConfigurableApplicationContext context;
|
||||
|
||||
@Autowired
|
||||
private IRedisCatchStorage redisCatchStorage;
|
||||
|
||||
|
||||
@ApiOperation("流媒体服务列表")
|
||||
@GetMapping(value = "/media_server/list")
|
||||
@ResponseBody
|
||||
public Object getMediaServerList(){
|
||||
// TODO 为后续多个zlm支持准备
|
||||
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
|
||||
ArrayList<ZLMServerConfig> result = new ArrayList<>();
|
||||
result.add(mediaInfo);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ApiOperation("重启服务")
|
||||
@GetMapping(value = "/restart")
|
||||
|
||||
Reference in New Issue
Block a user