diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..202b14c8 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "be.teletask.onvif-java"] + path = be.teletask.onvif-java + url = https://gitee.com/18010473990/be.teletask.onvif-java.git diff --git a/libs/onvif-java-1.0.2.jar b/libs/onvif-java-1.0.2.jar new file mode 100644 index 00000000..dd62a238 Binary files /dev/null and b/libs/onvif-java-1.0.2.jar differ diff --git a/pom.xml b/pom.xml index 91b90e69..f8a8b532 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.genersoft - wvp + wvp-gb28181 2.0.0 web video platform @@ -44,6 +44,7 @@ UTF-8 + yyyyMMddHHmmss 5.2.0 @@ -167,10 +168,36 @@ okhttp 4.9.0 - + + + + com.burgstaller + okhttp-digest + 2.1 + + + + + net.sf.kxml + kxml2 + 2.3.0 + + + + + + be.teletask + onvif-java + 1.0.2 + system + ${project.basedir}/libs/onvif-java-1.0.2.jar + + + + - wvp-2.0 + ${project.artifactId}-${project.version}-${maven.build.timestamp} org.springframework.boot diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java index b7f592e1..f21895c4 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java @@ -35,6 +35,8 @@ public class DeferredResultHolder { public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP"; + public static final String CALLBACK_ONVIF = "CALLBACK_ONVIF"; + public static final String CALLBACK_CMD_MOBILEPOSITION = "CALLBACK_MOBILEPOSITION"; public static final String CALLBACK_CMD_PRESETQUERY = "CALLBACK_PRESETQUERY"; diff --git a/src/main/java/com/genersoft/iot/vmp/onvif/IONVIFServer.java b/src/main/java/com/genersoft/iot/vmp/onvif/IONVIFServer.java new file mode 100644 index 00000000..eb81a363 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/onvif/IONVIFServer.java @@ -0,0 +1,13 @@ +package com.genersoft.iot.vmp.onvif; + +import be.teletask.onvif.models.OnvifDevice; +import com.genersoft.iot.vmp.onvif.dto.ONVIFCallBack; + +import java.util.List; + +public interface IONVIFServer { + + void search(int timeout, ONVIFCallBack> callBack); + + void getRTSPUrl(int timeout, OnvifDevice device, ONVIFCallBack callBack); +} diff --git a/src/main/java/com/genersoft/iot/vmp/onvif/dto/ONVIFCallBack.java b/src/main/java/com/genersoft/iot/vmp/onvif/dto/ONVIFCallBack.java new file mode 100644 index 00000000..3fdbde5b --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/onvif/dto/ONVIFCallBack.java @@ -0,0 +1,5 @@ +package com.genersoft.iot.vmp.onvif.dto; + +public interface ONVIFCallBack { + void run(int errorCode, T t); +} diff --git a/src/main/java/com/genersoft/iot/vmp/onvif/impl/ONVIFServerIMpl.java b/src/main/java/com/genersoft/iot/vmp/onvif/impl/ONVIFServerIMpl.java new file mode 100644 index 00000000..e747118e --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/onvif/impl/ONVIFServerIMpl.java @@ -0,0 +1,116 @@ +package com.genersoft.iot.vmp.onvif.impl; + + +import be.teletask.onvif.DiscoveryManager; +import be.teletask.onvif.OnvifManager; +import be.teletask.onvif.listeners.*; +import be.teletask.onvif.models.*; +import be.teletask.onvif.responses.OnvifResponse; +import com.genersoft.iot.vmp.onvif.IONVIFServer; +import com.genersoft.iot.vmp.onvif.dto.ONVIFCallBack; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 处理onvif的各种操作 + */ +@Service +public class ONVIFServerIMpl implements IONVIFServer { + + private final static Logger logger = LoggerFactory.getLogger(ONVIFServerIMpl.class); + + @Override + public void search(int timeout, ONVIFCallBack> callBack) { + DiscoveryManager manager = new DiscoveryManager(); + manager.setDiscoveryTimeout(timeout); + Map deviceMap = new HashMap<>(); + // 搜索设备 + manager.discover(new DiscoveryListener() { + @Override + public void onDiscoveryStarted() { + logger.info("Discovery started"); + } + + @Override + public void onDevicesFound(List devices) { + if (devices == null || devices.size() == 0) return; + for (Device device : devices){ + System.out.println(device.getHostName()); + deviceMap.put(device.getHostName(), device); + } + } + + // 搜索结束 + @Override + public void onDiscoveryFinished() { + ArrayList result = new ArrayList<>(); + for (Device device : deviceMap.values()) { + System.out.println(device.getHostName()); + result.add(device.getHostName()); + } + callBack.run(0, result); + } + }); + } + + @Override + public void getRTSPUrl(int timeout, OnvifDevice device, ONVIFCallBack callBack) { + if (device.getHostName() == null ){ + callBack.run(400, null); + } + OnvifManager onvifManager = new OnvifManager(); + onvifManager.setOnvifResponseListener(new OnvifResponseListener(){ + + @Override + public void onResponse(OnvifDevice onvifDevice, OnvifResponse response) { + System.out.println("[RESPONSE] " + onvifDevice.getHostName() + + "======" + response.getErrorCode() + + "======" + response.getErrorMessage()); + } + + @Override + public void onError(OnvifDevice onvifDevice, int errorCode, String errorMessage) { + System.out.println("[ERROR] " + onvifDevice.getHostName() + "======" + errorCode + "=======" + errorMessage); + callBack.run(errorCode, errorMessage); + } + }); + + try { + onvifManager.getServices(device, (OnvifDevice onvifDevice, OnvifServices services) -> { + if (services.getProfilesPath().equals("/onvif/Media")) { + onvifDevice.setPath(services); + onvifManager.getMediaProfiles(onvifDevice, new OnvifMediaProfilesListener() { + @Override + public void onMediaProfilesReceived(OnvifDevice device, List mediaProfiles) { + for (OnvifMediaProfile mediaProfile : mediaProfiles) { + System.out.println(mediaProfile.getName()); + System.out.println(mediaProfile.getToken()); + if (mediaProfile.getName().equals("mainStream")) { + onvifManager.getMediaStreamURI(device, mediaProfile, (OnvifDevice onvifDevice, + OnvifMediaProfile profile, String uri) -> { + + uri = uri.replace("rtsp://", "rtsp://"+ device.getUsername() + ":"+ device.getPassword() + "@"); + logger.info(onvifDevice.getHostName() + "的地址" + uri); + callBack.run(0, uri); + }); + } + } + } + }); + } + }); + }catch (Exception e) { + callBack.run(400, e.getMessage()); + } + + + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/onvif/ONVIFController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/onvif/ONVIFController.java new file mode 100644 index 00000000..a484b51e --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/onvif/ONVIFController.java @@ -0,0 +1,120 @@ +package com.genersoft.iot.vmp.vmanager.onvif; + +import be.teletask.onvif.models.OnvifDevice; +import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; +import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; +import com.genersoft.iot.vmp.onvif.IONVIFServer; +import com.genersoft.iot.vmp.vmanager.bean.WVPResult; +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.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.context.request.async.DeferredResult; + +import java.util.List; +import java.util.UUID; + +@Api(tags = "onvif设备") +@CrossOrigin +@RestController +@RequestMapping("/api/onvif") +public class ONVIFController { + + + @Autowired + private DeferredResultHolder resultHolder; + + @Autowired + private IONVIFServer onvifServer; + + + @ApiOperation("搜索") + @ApiImplicitParams({ + @ApiImplicitParam(name="timeout", value = "超时时间", required = true, dataTypeClass = Integer.class), + }) + @GetMapping(value = "/search") + @ResponseBody + public DeferredResult> search(@RequestParam(required = false)Integer timeout){ + DeferredResult> result = new DeferredResult<>(timeout + 10L); + UUID uuid = UUID.randomUUID(); + result.onTimeout(()->{ + RequestMessage msg = new RequestMessage(); + msg.setId(DeferredResultHolder.CALLBACK_ONVIF + uuid); + WVPResult wvpResult = new WVPResult(); + wvpResult.setCode(0); + wvpResult.setMsg("搜索超时"); + msg.setData(wvpResult); + resultHolder.invokeResult(msg); + }); + resultHolder.put(DeferredResultHolder.CALLBACK_ONVIF + uuid, result); + + onvifServer.search(timeout, (errorCode, onvifDevices) ->{ + RequestMessage msg = new RequestMessage(); + msg.setId(DeferredResultHolder.CALLBACK_ONVIF + uuid); + WVPResult> resultData = new WVPResult(); + resultData.setCode(errorCode); + if (errorCode == 0) { + resultData.setMsg("success"); + resultData.setData(onvifDevices); + }else { + resultData.setMsg("fail"); + } + msg.setData(resultData); + msg.setData(resultData); + resultHolder.invokeResult(msg); + }); + + return result; + } + + @ApiOperation("获取onvif的rtsp地址") + @ApiImplicitParams({ + @ApiImplicitParam(name="timeout", value = "超时时间", required = true, dataTypeClass = Integer.class), + @ApiImplicitParam(name="hostname", value = "onvif地址", required = true, dataTypeClass = String.class), + @ApiImplicitParam(name="username", value = "用户名", required = true, dataTypeClass = String.class), + @ApiImplicitParam(name="password", value = "密码", required = true, dataTypeClass = String.class), + }) + @GetMapping(value = "/rtsp") + @ResponseBody + public DeferredResult> getRTSPUrl(@RequestParam(value="timeout", required=false, defaultValue="3000") Integer timeout, + @RequestParam(required = true) String hostname, + @RequestParam(required = false) String username, + @RequestParam(required = false) String password + ){ + + DeferredResult> result = new DeferredResult<>(timeout + 10L); + UUID uuid = UUID.randomUUID(); + result.onTimeout(()->{ + RequestMessage msg = new RequestMessage(); + msg.setId(DeferredResultHolder.CALLBACK_ONVIF + uuid); + WVPResult wvpResult = new WVPResult(); + wvpResult.setCode(0); + wvpResult.setMsg("获取onvif的rtsp地址超时"); + msg.setData(wvpResult); + resultHolder.invokeResult(msg); + }); + resultHolder.put(DeferredResultHolder.CALLBACK_ONVIF + uuid, result); + OnvifDevice onvifDevice = new OnvifDevice(hostname, username, password); + onvifServer.getRTSPUrl(timeout, onvifDevice, (errorCode, url) ->{ + RequestMessage msg = new RequestMessage(); + msg.setId(DeferredResultHolder.CALLBACK_ONVIF + uuid); + WVPResult resultData = new WVPResult(); + resultData.setCode(errorCode); + if (errorCode == 0) { + resultData.setMsg("success"); + resultData.setData(url); + }else { + resultData.setMsg(url); + } + msg.setData(resultData); + + resultHolder.invokeResult(msg); + }); + + return result; + } + +} diff --git a/web_src/src/components/StreamProxyList.vue b/web_src/src/components/StreamProxyList.vue index 0e0fcdd5..d71de84b 100644 --- a/web_src/src/components/StreamProxyList.vue +++ b/web_src/src/components/StreamProxyList.vue @@ -10,6 +10,7 @@
添加代理 + 搜索ONVIF
@@ -79,6 +80,7 @@ :total="total"> + @@ -86,6 +88,7 @@