panlinlin
2021-04-26 5ba0fba03d9fcb09eea0c1e703a4f050378d7992
添加部分onvif代码
4个文件已修改
7个文件已添加
453 ■■■■■ 已修改文件
.gitmodules 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libs/onvif-java-1.0.2.jar 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/onvif/IONVIFServer.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/onvif/dto/ONVIFCallBack.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/onvif/impl/ONVIFServerIMpl.java 116 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/onvif/ONVIFController.java 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/StreamProxyList.vue 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/StreamProxyEdit.vue 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/onvifEdit.vue 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.gitmodules
New file
@@ -0,0 +1,3 @@
[submodule "be.teletask.onvif-java"]
    path = be.teletask.onvif-java
    url = https://gitee.com/18010473990/be.teletask.onvif-java.git
libs/onvif-java-1.0.2.jar
Binary files differ
pom.xml
@@ -10,7 +10,7 @@
    </parent>
    <groupId>com.genersoft</groupId>
    <artifactId>wvp</artifactId>
    <artifactId>wvp-gb28181</artifactId>
    <version>2.0.0</version>
    <name>web video platform</name>
@@ -44,6 +44,7 @@
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
        <!-- 依赖版本 -->
        <pagehelper.version>5.2.0</pagehelper.version>
@@ -167,10 +168,36 @@
            <artifactId>okhttp</artifactId>
            <version>4.9.0</version>
        </dependency>
    </dependencies>
        <!-- okhttp-digest -->
        <dependency>
            <groupId>com.burgstaller</groupId>
            <artifactId>okhttp-digest</artifactId>
            <version>2.1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/net.sf.kxml/kxml2 -->
        <dependency>
            <groupId>net.sf.kxml</groupId>
            <artifactId>kxml2</artifactId>
            <version>2.3.0</version>
        </dependency>
        <!-- onvif协议栈 -->
        <dependency>
            <groupId>be.teletask</groupId>
            <artifactId>onvif-java</artifactId>
            <version>1.0.2</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/libs/onvif-java-1.0.2.jar</systemPath>
        </dependency>
    </dependencies>
    
    <build>
        <finalName>wvp-2.0</finalName>
        <finalName>${project.artifactId}-${project.version}-${maven.build.timestamp}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
@@ -35,6 +35,8 @@
    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";
src/main/java/com/genersoft/iot/vmp/onvif/IONVIFServer.java
New file
@@ -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);
}
src/main/java/com/genersoft/iot/vmp/onvif/dto/ONVIFCallBack.java
New file
@@ -0,0 +1,5 @@
package com.genersoft.iot.vmp.onvif.dto;
public interface ONVIFCallBack<T> {
    void run(int errorCode, T t);
}
src/main/java/com/genersoft/iot/vmp/onvif/impl/ONVIFServerIMpl.java
New file
@@ -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());
        }
    }
}
src/main/java/com/genersoft/iot/vmp/vmanager/onvif/ONVIFController.java
New file
@@ -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;
    }
}
web_src/src/components/StreamProxyList.vue
@@ -10,6 +10,7 @@
                </div>
                <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;font-size: 14px;">
                    <el-button icon="el-icon-plus" size="mini" style="margin-right: 1rem;" type="primary" @click="addStreamProxy">添加代理</el-button>
                    <el-button v-if="false" icon="el-icon-search" size="mini" style="margin-right: 1rem;" type="primary" @click="addOnvif">搜索ONVIF</el-button>
                </div>
                <devicePlayer ref="devicePlayer"></devicePlayer>
                <el-table :data="streamProxyList" border style="width: 100%" :height="winHeight">
@@ -79,6 +80,7 @@
                    :total="total">
                </el-pagination>
            <streamProxyEdit ref="streamProxyEdit" ></streamProxyEdit>
            <onvifEdit ref="onvifEdit" ></onvifEdit>
            </el-main>
        </el-container>
    </div>
@@ -86,6 +88,7 @@
<script>
    import streamProxyEdit from './dialog/StreamProxyEdit.vue'
    import onvifEdit from './dialog/onvifEdit.vue'
    import devicePlayer from './dialog/devicePlayer.vue'
    import uiHeader from './UiHeader.vue'
    export default {
@@ -93,6 +96,7 @@
        components: {
            devicePlayer,
            streamProxyEdit,
      onvifEdit,
            uiHeader
        },
        data() {
@@ -113,7 +117,7 @@
        },
        mounted() {
            this.initData();
            // this.updateLooper = setInterval(this.initData, 10000);
            this.updateLooper = setInterval(this.initData, 1000);
        },
        destroyed() {
            this.$destroy('videojs');
@@ -155,6 +159,36 @@
            addStreamProxy: function(){
                this.$refs.streamProxyEdit.openDialog(null, this.initData)
            },
      addOnvif: function(){
        this.getListLoading = true;
        this.getListLoading = true;
        this.$axios({
          method: 'get',
          url:`/api/onvif/search?timeout=3000`,
        }).then((res) =>{
          this.getListLoading = false;
          if (res.data.code == 0 ){
            if (res.data.data.length > 0) {
              console.log(res.data.data)
              this.$refs.onvifEdit.openDialog(res.data.data, (url)=>{
                  if (url != null) {
                    this.$refs.onvifEdit.close();
                    this.$refs.streamProxyEdit.openDialog({type: "default", url: url, src_url: url}, this.initData())
                  }
              })
            }else {
              this.$message.success("未找到可用设备");
            }
        }else {
            this.$message.error(res.data.msg);
          }
        }).catch((error)=> {
          this.getListLoading = false;
          this.$message.error(error.response.data.msg);
        });
            },
            saveStreamProxy: function(){
            },
            play: function(row){
web_src/src/components/dialog/StreamProxyEdit.vue
@@ -139,9 +139,6 @@
      this.listChangeCallback = callback;
      if (proxyParam != null) {
        this.proxyParam = proxyParam;
        this.onSubmit_text = "保存";
      } else {
        this.onSubmit_text = "立即创建";
      }
    },
    onSubmit: function () {
@@ -163,6 +160,7 @@
          that.showDialog = false;
          if (that.listChangeCallback != null) {
            that.listChangeCallback();
            that.dialogLoading = false;
          }
        }
      }).catch(function (error) {
web_src/src/components/dialog/onvifEdit.vue
New file
@@ -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>