panlinlin
4 years ago
11 changed files with 446 additions and 7 deletions
@ -0,0 +1,3 @@ |
|||||
|
[submodule "be.teletask.onvif-java"] |
||||
|
path = be.teletask.onvif-java |
||||
|
url = https://gitee.com/18010473990/be.teletask.onvif-java.git |
Binary file not shown.
@ -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<List<String>> callBack); |
||||
|
|
||||
|
void getRTSPUrl(int timeout, OnvifDevice device, ONVIFCallBack<String> callBack); |
||||
|
} |
@ -0,0 +1,5 @@ |
|||||
|
package com.genersoft.iot.vmp.onvif.dto; |
||||
|
|
||||
|
public interface ONVIFCallBack<T> { |
||||
|
void run(int errorCode, T t); |
||||
|
} |
@ -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<List<String>> callBack) { |
||||
|
DiscoveryManager manager = new DiscoveryManager(); |
||||
|
manager.setDiscoveryTimeout(timeout); |
||||
|
Map<String, Device> deviceMap = new HashMap<>(); |
||||
|
// 搜索设备
|
||||
|
manager.discover(new DiscoveryListener() { |
||||
|
@Override |
||||
|
public void onDiscoveryStarted() { |
||||
|
logger.info("Discovery started"); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onDevicesFound(List<Device> 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<String> 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<String> 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<OnvifMediaProfile> 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()); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
} |
@ -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<ResponseEntity<WVPResult>> search(@RequestParam(required = false)Integer timeout){ |
||||
|
DeferredResult<ResponseEntity<WVPResult>> result = new DeferredResult<>(timeout + 10L); |
||||
|
UUID uuid = UUID.randomUUID(); |
||||
|
result.onTimeout(()->{ |
||||
|
RequestMessage msg = new RequestMessage(); |
||||
|
msg.setId(DeferredResultHolder.CALLBACK_ONVIF + uuid); |
||||
|
WVPResult<String> 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<List<String>> 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<ResponseEntity<WVPResult>> 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<ResponseEntity<WVPResult>> result = new DeferredResult<>(timeout + 10L); |
||||
|
UUID uuid = UUID.randomUUID(); |
||||
|
result.onTimeout(()->{ |
||||
|
RequestMessage msg = new RequestMessage(); |
||||
|
msg.setId(DeferredResultHolder.CALLBACK_ONVIF + uuid); |
||||
|
WVPResult<String> 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<String> 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; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,121 @@ |
|||||
|
<template> |
||||
|
<div id="onvif搜索" v-loading="isLoging"> |
||||
|
<el-dialog |
||||
|
title="onvif搜索" |
||||
|
width="40%" |
||||
|
top="2rem" |
||||
|
:close-on-click-modal="false" |
||||
|
:visible.sync="showDialog" |
||||
|
:destroy-on-close="true" |
||||
|
@close="close()" |
||||
|
> |
||||
|
<div id="shared" style="margin-top: 1rem;margin-right: 100px;"> |
||||
|
<el-form ref="form" :rules="rules" :model="form" label-width="140px" > |
||||
|
<el-form-item label="地址" prop="hostName" > |
||||
|
<el-select v-model="form.hostName" style="float: left; width: 100%" > |
||||
|
<el-option |
||||
|
v-for="item in hostNames" |
||||
|
:key="item" |
||||
|
:label="item.replace('http://', '')" |
||||
|
:value="item"> |
||||
|
</el-option> |
||||
|
</el-select> |
||||
|
|
||||
|
</el-form-item> |
||||
|
<el-form-item label="用户名" prop="username"> |
||||
|
<el-input v-model="form.username" clearable></el-input> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="密码" prop="password"> |
||||
|
<el-input v-model="form.password" clearable></el-input> |
||||
|
</el-form-item> |
||||
|
<el-form-item> |
||||
|
<div style="float: right;"> |
||||
|
<el-button type="primary" @click="onSubmit" >确认</el-button> |
||||
|
<el-button @click="close">取消</el-button> |
||||
|
</div> |
||||
|
|
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
name: "onvifEdit", |
||||
|
props: {}, |
||||
|
computed: {}, |
||||
|
created() {}, |
||||
|
data() { |
||||
|
return { |
||||
|
listChangeCallback: null, |
||||
|
showDialog: false, |
||||
|
isLoging: false, |
||||
|
hostNames:[], |
||||
|
form: { |
||||
|
hostName: null, |
||||
|
username: "admin", |
||||
|
password: "admin123", |
||||
|
}, |
||||
|
|
||||
|
rules: { |
||||
|
hostName: [{ required: true, message: "请选择", trigger: "blur" }], |
||||
|
username: [{ required: true, message: "请输入用户名", trigger: "blur" }], |
||||
|
password: [{ required: true, message: "请输入密码", trigger: "blur" }], |
||||
|
}, |
||||
|
}; |
||||
|
}, |
||||
|
methods: { |
||||
|
openDialog: function (hostNamesParam, callback) { |
||||
|
console.log(hostNamesParam) |
||||
|
this.showDialog = true; |
||||
|
this.listChangeCallback = callback; |
||||
|
if (hostNamesParam != null) { |
||||
|
this.hostNames = hostNamesParam; |
||||
|
} |
||||
|
|
||||
|
}, |
||||
|
onSubmit: function () { |
||||
|
console.log("onSubmit"); |
||||
|
console.log(this.form); |
||||
|
this.$axios({ |
||||
|
method: 'get', |
||||
|
url:`api/onvif/rtsp`, |
||||
|
params: { |
||||
|
hostname: this.form.hostName, |
||||
|
timeout: 3000, |
||||
|
username: this.form.username, |
||||
|
password: this.form.password, |
||||
|
} |
||||
|
}).then((res) => { |
||||
|
console.log(res.data) |
||||
|
if (res.data.code == 0) { |
||||
|
if (res.data.data != null) { |
||||
|
this.listChangeCallback(res.data.data) |
||||
|
}else { |
||||
|
this.$message({ |
||||
|
showClose: true, |
||||
|
message: res.data.msg, |
||||
|
type: "error", |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
}else { |
||||
|
this.$message({ |
||||
|
showClose: true, |
||||
|
message: res.data.msg, |
||||
|
type: "error", |
||||
|
}); |
||||
|
} |
||||
|
}).catch(function (error) { |
||||
|
console.log(error); |
||||
|
}); |
||||
|
}, |
||||
|
close: function () { |
||||
|
this.showDialog = false; |
||||
|
this.$refs.form.resetFields(); |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
Loading…
Reference in new issue