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 @@