diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/rtsp/RtspDeviceController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/rtsp/RtspDeviceController.java new file mode 100644 index 0000000..fae4943 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/rtsp/RtspDeviceController.java @@ -0,0 +1,147 @@ +package com.ruoyi.web.controller.rtsp; + +import ai.onnxruntime.OrtException; +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.rtsp.domain.RtspDevice; +import com.ruoyi.rtsp.domain.bo.RtspDeviceBo; +import com.ruoyi.rtsp.domain.bo.alarmClockBo; +import com.ruoyi.rtsp.service.IRtspDeviceService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * rtsp设备Controller + * + * @author 陈江灿 + * @date 2025-04-22 + */ +@RestController +@RequestMapping("/rtsp/RtspDevice") +public class RtspDeviceController extends BaseController { + + @Autowired + private IRtspDeviceService rtspDeviceService; + + /** + * 历史播放 + * + * @param bo + * @return + */ + @PreAuthorize("@ss.hasPermi('rtsp:RtspDevice:AlarmClock')") + @GetMapping("/alarmClock") + public AjaxResult alarmClock(alarmClockBo bo) { + return success(rtspDeviceService.alarmClock(bo)); + } + + + /** + * 查询rtsp设备列表 + */ + @PreAuthorize("@ss.hasPermi('rtsp:RtspDevice:list')") + @GetMapping("/list") + public TableDataInfo list(RtspDevice rtspDevice) { + startPage(); + List list = rtspDeviceService.selectRtspDeviceList(rtspDevice); + return getDataTable(list); + } + + /** + * 查询rtsp设备列表 + */ + @PreAuthorize("@ss.hasPermi('rtsp:RtspDevice:list')") + @GetMapping("/rtspDeviceList") + public AjaxResult rtspDeviceList(RtspDevice rtspDevice, String mapType) { + List list = new ArrayList<>(); + if ("map".equals(mapType)) { + list = rtspDeviceService.selectRtspDeviceListMap(rtspDevice); + } else { + list = rtspDeviceService.selectRtspDeviceList(rtspDevice); + } + return success(list); + } + + /** + * 导出rtsp设备列表 + */ + @PreAuthorize("@ss.hasPermi('rtsp:RtspDevice:export')") + @Log(title = "rtsp设备", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, RtspDevice rtspDevice) { + List list = rtspDeviceService.selectRtspDeviceList(rtspDevice); + ExcelUtil util = new ExcelUtil(RtspDevice.class); + util.exportExcel(response, list, "rtsp设备数据"); + } + + /** + * 获取rtsp设备详细信息 + */ + @PreAuthorize("@ss.hasPermi('rtsp:RtspDevice:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) { + return success(rtspDeviceService.selectRtspDeviceById(id)); + } + + /** + * 新增rtsp设备 + */ + @PreAuthorize("@ss.hasPermi('rtsp:RtspDevice:add')") + @Log(title = "rtsp设备", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody RtspDevice rtspDevice) { + return toAjax(rtspDeviceService.insertRtspDevice(rtspDevice)); + } + + /** + * 修改rtsp设备 + */ + @PreAuthorize("@ss.hasPermi('rtsp:RtspDevice:edit')") + @Log(title = "rtsp设备", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody RtspDevice rtspDevice) { + return toAjax(rtspDeviceService.updateRtspDevice(rtspDevice)); + } + + /** + * 删除rtsp设备 + */ + @PreAuthorize("@ss.hasPermi('rtsp:RtspDevice:remove')") + @Log(title = "rtsp设备", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) { + return toAjax(rtspDeviceService.deleteRtspDeviceByIds(ids)); + } + + /** + * 新增目标检测 + * + * @param bo + * @return + */ + @PreAuthorize("@ss.hasPermi('rtsp:RtspDevice:addDetection')") + @PostMapping("/addDetection") + public AjaxResult addDetection(@RequestBody RtspDeviceBo bo) throws IOException, OrtException { + rtspDeviceService.insertRtspDetection(bo); + return success(); + } + + @PreAuthorize("@ss.hasPermi('rtsp:RtspDevice:stopDetection')") + @PostMapping("/stopDetection") + public AjaxResult stopDetection(@RequestBody RtspDeviceBo bo) throws IOException, OrtException { + rtspDeviceService.stopRtspDetection(bo); + return success(); + } + + +} diff --git a/ruoyi-admin/src/main/resources/application-druid.yml b/ruoyi-admin/src/main/resources/application-druid.yml index 6ccc7cf..4ede34e 100644 --- a/ruoyi-admin/src/main/resources/application-druid.yml +++ b/ruoyi-admin/src/main/resources/application-druid.yml @@ -6,9 +6,9 @@ spring: druid: # 主库数据源 master: - url: jdbc:mysql://192.168.158.200:3306/ry-wvp?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowMultiQueries=true + url: jdbc:mysql://localhost:3306/git-wvp?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowMultiQueries=true username: root - password: haoxin + password: admin123 # 从库数据源 slave: # 从数据源开关/默认关闭 diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index a5a360e..8646c80 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -87,9 +87,9 @@ spring: # 端口,默认为6379 port: 6379 # 数据库索引 - database: 8 + database: 6 # 密码 - password: + password: ruoyi123 # password: 123456 # 连接超时时间 timeout: 10s @@ -162,64 +162,45 @@ sip: alarm: false ##zlm 默认服务器配置 +#media: +# id: qsh-network +# # [必须修改] zlm服务器的内网IP +# ip: 127.0.0.1 +# # [必须修改] zlm服务器的http.port +# http-port: 80 +# # [必选选] zlm服务器的hook.admin_params=secret +# secret: qsh-network +# # 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试 +# rtp: +# # [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输 +# enable: true +# # [可选] 在此范围内选择端口用于媒体流传输, 必须提前在zlm上配置该属性,不然自动配置此属性可能不成功 +# port-range: 40000,40300 # 端口范围 +# # [可选] 国标级联在此范围内选择端口发送媒体流, +# send-port-range: 40000,40300 # 端口范围 + media: - id: haoxin-zlm-1 + id: hxkj_zlm # [必须修改] zlm服务器的内网IP - ip: 192.168.158.199 + ip: 192.168.2.199 # [必须修改] zlm服务器的http.port http-port: 8092 # [可选] zlm服务器的hook所使用的IP, 默认使用sip.ip - hook-ip: 192.168.158.199 + hook-ip: 192.168.2.199 # [必选选] zlm服务器的hook.admin_params=secret - secret: haoxin + secret: hxkj_zlm + # # [可选] 录像文件存储路径 + # record-path: F:/zml/record + # [可选] 录像保存时间,单位是天 + record-day: 3 # 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试 rtp: # [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输 enable: true # [可选] 在此范围内选择端口用于媒体流传输, 必须提前在zlm上配置该属性,不然自动配置此属性可能不成功 - port-range: 40000,40300 # 端口范围 + port-range: 30000,30500 # 端口范围 # [可选] 国标级联在此范围内选择端口发送媒体流, - send-port-range: 40000,40300 # 端口范围 - -##zlm 默认服务器配置 -#media: -# id: hxkj_zlm -# # [必须修改] zlm服务器的内网IP -# ip: 192.168.1.113 -# # [必须修改] zlm服务器的http.port -# http-port: 8092 -# # [可选] zlm服务器的hook所使用的IP, 默认使用sip.ip -# hook-ip: 192.168.1.113 -# # [必选选] zlm服务器的hook.admin_params=secret -# secret: hxkj_zlm -# # 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试 -# rtp: -# # [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输 -# enable: true -# # [可选] 在此范围内选择端口用于媒体流传输, 必须提前在zlm上配置该属性,不然自动配置此属性可能不成功 -# port-range: 30000,30500 # 端口范围 -# # [可选] 国标级联在此范围内选择端口发送媒体流, -# send-port-range: 30000,30500 # 端口范围 - -#zlm 默认服务器配置 -#media: -# id: hxkj_zlm -# # [必须修改] zlm服务器的内网IP -# ip: 192.168.158.200 -# # [必须修改] zlm服务器的http.port -# http-port: 8092 -# # [可选] zlm服务器的hook所使用的IP, 默认使用sip.ip -# hook-ip: 192.168.158.200 -# # [必选选] zlm服务器的hook.admin_params=secret -# secret: hxkj_zlm -# # 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试 -# rtp: -# # [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输 -# enable: true -# # [可选] 在此范围内选择端口用于媒体流传输, 必须提前在zlm上配置该属性,不然自动配置此属性可能不成功 -# port-range: 30000,30500 # 端口范围 -# # [可选] 国标级联在此范围内选择端口发送媒体流, -# send-port-range: 30000,30500 # 端口范围 + send-port-range: 30000,30500 # 端口范围 # [根据业务需求配置] @@ -240,7 +221,7 @@ user-settings: # ISUP配置 isup: #注册服务器监听地址(服务器本地地址) - IP: 192.168.158.200 + IP: 192.168.2.199 route: Isup cmsServer: Port: 7660 @@ -248,7 +229,7 @@ isup: smsServer: Port: 7665 #取流服务器监听地址端口(服务器本地地址) - ListenIP: 192.168.158.200 + ListenIP: 192.168.2.199 ListenPort: 7665 # ISUP5.0登录秘钥 isupKey: 12345678 diff --git a/ruoyi-rtsp/pom.xml b/ruoyi-rtsp/pom.xml index ab332e6..11778b8 100644 --- a/ruoyi-rtsp/pom.xml +++ b/ruoyi-rtsp/pom.xml @@ -18,13 +18,40 @@ + + org.projectlombok + lombok + + com.ruoyi ruoyi-common + + com.microsoft.onnxruntime + onnxruntime + 1.16.1 + + + org.openpnp + opencv + 4.7.0-0 + + + + com.squareup.okhttp3 + okhttp + 4.9.3 + + + + com.google.code.gson + gson + 2.9.1 + diff --git a/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/constants/StreamTypeConstants.java b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/constants/StreamTypeConstants.java new file mode 100644 index 0000000..596943a --- /dev/null +++ b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/constants/StreamTypeConstants.java @@ -0,0 +1,13 @@ +package com.ruoyi.rtsp.constants; + +/** + * 流类型常量 + * @Author: 陈江灿 + * @CreateTime: 2025-04-22 + */ +public class StreamTypeConstants { + public static final String HIKVISION = "1"; // 海康 + public static final String DAHUA = "2"; // 大华 + public static final String UNIVIEW = "3"; // 宇视 + public static final String MERCURY = "4"; // 水星 +} diff --git a/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/CarDetection.java b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/CarDetection.java new file mode 100644 index 0000000..9a20393 --- /dev/null +++ b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/CarDetection.java @@ -0,0 +1,62 @@ +package com.ruoyi.rtsp.domain; + +public class CarDetection extends Detection{ + + /**是否为单行车牌**/ + public boolean single; + + /**车牌旋转角度**/ + public float angle; + + /**车牌文本信息**/ + public String plateNo; + /**车牌的颜色信息**/ + public String plateColor; + + public CarDetection(String label, Integer clsId, float[] bbox, float confidence, boolean single, float angle, String plateNo, String plateColor) { + super(label, clsId, bbox, confidence); + this.single = single; + this.angle = angle; + this.plateNo = plateNo; + this.plateColor = plateColor; + } + + public CarDetection(boolean single, float angle, String plateNo, String plateColor) { + this.single = single; + this.angle = angle; + this.plateNo = plateNo; + this.plateColor = plateColor; + } + + public boolean isSingle() { + return single; + } + + public void setSingle(boolean single) { + this.single = single; + } + + public float getAngle() { + return angle; + } + + public void setAngle(float angle) { + this.angle = angle; + } + + public String getPlateNo() { + return plateNo; + } + + public void setPlateNo(String plateNo) { + this.plateNo = plateNo; + } + + public String getPlateColor() { + return plateColor; + } + + public void setPlateColor(String plateColor) { + this.plateColor = plateColor; + } +} diff --git a/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/Detection.java b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/Detection.java new file mode 100644 index 0000000..b92d9c0 --- /dev/null +++ b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/Detection.java @@ -0,0 +1,59 @@ +package com.ruoyi.rtsp.domain; + +public class Detection{ + + public String label; + + private Integer clsId; + + public float[] bbox; + + public float confidence; + + + public Detection(String label,Integer clsId, float[] bbox, float confidence){ + this.clsId = clsId; + this.label = label; + this.bbox = bbox; + this.confidence = confidence; + } + + public Detection(){ + + } + + public Integer getClsId() { + return clsId; + } + + public void setClsId(Integer clsId) { + this.clsId = clsId; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public float[] getBbox() { + return bbox; + } + + public void setBbox(float[] bbox) { + } + + + @Override + public String toString() { + return " label="+label + + " \t clsId="+clsId + + " \t x0="+bbox[0] + + " \t y0="+bbox[1] + + " \t x1="+bbox[2] + + " \t y1="+bbox[3] + + " \t score="+confidence; + } +} diff --git a/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/KeyPoint.java b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/KeyPoint.java new file mode 100644 index 0000000..0add020 --- /dev/null +++ b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/KeyPoint.java @@ -0,0 +1,40 @@ +package com.ruoyi.rtsp.domain; + +public class KeyPoint { + private final Integer id; + private final Float x; + private final Float y; + private final Float score; + + public KeyPoint(Integer id, Float x, Float y, Float score) { + this.id = id; + this.x = x; + this.y = y; + this.score = score; + } + + public Integer getId() { + return id; + } + + public Float getX() { + return x; + } + + public Float getY() { + return y; + } + + public Float getScore() { + return score; + } + + @Override + public String toString() { + return " 第 " + (id+1) + " 个关键点: " + + " x=" + x + + " y=" + y + + " c=" + score + + "\n"; + } +} diff --git a/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/ODResult.java b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/ODResult.java new file mode 100644 index 0000000..3cc06c9 --- /dev/null +++ b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/ODResult.java @@ -0,0 +1,82 @@ +package com.ruoyi.rtsp.domain; + +import java.text.DecimalFormat; + + +public class ODResult { + private final Integer batchId; + private final Float x0; + private final Float y0; + private final Float x1; + private final Float y1; + private final Integer clsId; + private final Float score; + + public ODResult(float[] x) { + this.batchId = (int) x[0]; + this.x0 = x[1]; + this.y0 = x[2]; + this.x1 = x[3]; + this.y1 = x[4]; + this.clsId = (int) x[5]; + this.score = x[6]; + } + + public Integer getBatchId() { + return batchId; + } + + public Float getX0() { + return x0; + } + + public Float getY0() { + return y0; + } + + public Float getX1() { + return x1; + } + + public Float getY1() { + return y1; + } + + public Integer getClsId() { + return clsId; + } + + public Float setX0(Float x0) { + return this.x0; + } + + public Float setY0(Float y0) { + return this.y0; + } + + public Float setX1(Float x1) { + return this.x1; + } + + public Float setY1(Float y1) { + return this.y1; + } + + + + public String getScore() { + DecimalFormat df = new DecimalFormat("0.00"); + return df.format(this.score); + } + + @Override + public String toString() { + return " batchId=" + batchId + + " \t x0=" + x0 + + " \t y0=" + y0 + + " \t x1=" + x1 + + " \t y1=" + y1 + + " \t clsId=" + clsId + + " \t score=" + getScore(); + } +} diff --git a/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/PEResult.java b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/PEResult.java new file mode 100644 index 0000000..cb3d21b --- /dev/null +++ b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/PEResult.java @@ -0,0 +1,79 @@ +package com.ruoyi.rtsp.domain; + + +import java.util.ArrayList; +import java.util.List; + +public class PEResult { + + + private final Float x0; + private final Float y0; + private final Float x1; + private final Float y1; + private final Float score; + private final Integer clsId; + private final List keyPointList; + + public PEResult(float[] peResult) { + float x = peResult[0]; + float y = peResult[1]; + float w = peResult[2]/2.0f; + float h = peResult[3]/2.0f; + this.x0 = x-w; + this.y0 = y-h; + this.x1 = x+w; + this.y1 = y+h; + this.score = peResult[4]; + this.clsId = (int) peResult[5]; + this.keyPointList = new ArrayList<>(); + int keyPointNum = (peResult.length-6)/3; + for (int i=0;i getKeyPointList() { + return keyPointList; + } + + @Override + public String toString() { + StringBuilder result = new StringBuilder("PEResult:" + + " x0=" + x0 + + ", y0=" + y0 + + ", x1=" + x1 + + ", y1=" + y1 + + ", score=" + score + + ", clsId=" + clsId + + "\n"); + for (KeyPoint x : keyPointList) { + result.append(x.toString()); + } + return result.toString(); + } +} diff --git a/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/RtspDevice.java b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/RtspDevice.java new file mode 100644 index 0000000..a0eb853 --- /dev/null +++ b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/RtspDevice.java @@ -0,0 +1,107 @@ +package com.ruoyi.rtsp.domain; + +import com.ruoyi.common.annotation.Excel; +import com.ruoyi.common.core.domain.BaseEntity; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * rtsp设备对象 rtsp_device + * + * @author 陈江灿 + * @date 2025-04-22 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class RtspDevice extends BaseEntity { + private static final long serialVersionUID = 1L; + + /** + * id + */ + private Long id; + + /** + * 部门ID + */ + private Long deptId; + + /** + * ip + */ + @Excel(name = "ip") + private String ip; + + /** + * 摄像头名称 + */ + @Excel(name = "摄像头名称") + private String name; + + /** + * 用户名 + */ + @Excel(name = "用户名") + private String userName; + + /** + * 密码 + */ + @Excel(name = "密码") + private String password; + + /** + * 通道号 + */ + @Excel(name = "通道号") + private String channel; + + /** + * 播放类型(1=本地,2=推流,3=EasyNTS) + */ + @Excel(name = "播放类型") + private String playType; + + /** + * 直播流播放地址 + */ + @Excel(name = "直播流播放地址") + private String url; + + /** + * 流id + */ + @Excel(name = "流id") + private String streamId; + + /** + * 直播流播放地址 + */ + @Excel(name = "EasyNTS播放地址") + private String easyNTSUrl; + + /** + * 设备厂商 + */ + @Excel(name = "设备厂商") + private String firm; + + /** + * 部门名称 + */ + private String deptName; + + /** 纬度 */ + @Excel(name = "纬度") + private String lat; + + /** 经度 */ + @Excel(name = "经度") + private String lng; + + /** 地图定位地址 */ + @Excel(name = "地图定位地址") + private String addressMap; +} diff --git a/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/bo/RtspDeviceBo.java b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/bo/RtspDeviceBo.java new file mode 100644 index 0000000..05ea643 --- /dev/null +++ b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/bo/RtspDeviceBo.java @@ -0,0 +1,46 @@ +package com.ruoyi.rtsp.domain.bo; + +/** + * ai 播放bo + * + * @Author: 陈江灿 + * @CreateTime: 2025-04-28 + */ +public class RtspDeviceBo { + private String type; + private String url; + private String mediaId; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getMediaId() { + return mediaId; + } + + public void setMediaId(String mediaId) { + this.mediaId = mediaId; + } + + @Override + public String toString() { + return "RtspDeviceBo{" + + "type='" + type + '\'' + + ", url='" + url + '\'' + + ", mediaId='" + mediaId + '\'' + + '}'; + } +} diff --git a/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/bo/alarmClockBo.java b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/bo/alarmClockBo.java new file mode 100644 index 0000000..6eea523 --- /dev/null +++ b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/domain/bo/alarmClockBo.java @@ -0,0 +1,32 @@ +package com.ruoyi.rtsp.domain.bo; + +import lombok.Data; + +import java.util.Date; + +/** + * 历史播放 bo + * + * @Author: 陈江灿 + * @CreateTime: 2025-05-24 + */ +@Data +public class alarmClockBo { + + /** + * id + */ + private Long id; + + /** + * 开始时间 + */ + private Date startTime; + + /** + * 结束时间 + */ + private Date endTime; + + +} diff --git a/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/mapper/RtspDeviceMapper.java b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/mapper/RtspDeviceMapper.java new file mode 100644 index 0000000..71931ec --- /dev/null +++ b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/mapper/RtspDeviceMapper.java @@ -0,0 +1,69 @@ +package com.ruoyi.rtsp.mapper; + +import java.util.List; +import com.ruoyi.rtsp.domain.RtspDevice; + +/** + * rtsp设备Mapper接口 + * + * @author 陈江灿 + * @date 2025-04-22 + */ +public interface RtspDeviceMapper +{ + /** + * 查询rtsp设备 + * + * @param id rtsp设备主键 + * @return rtsp设备 + */ + public RtspDevice selectRtspDeviceById(Long id); + + /** + * 查询rtsp设备列表 + * + * @param rtspDevice rtsp设备 + * @return rtsp设备集合 + */ + public List selectRtspDeviceList(RtspDevice rtspDevice); + + /** + * 新增rtsp设备 + * + * @param rtspDevice rtsp设备 + * @return 结果 + */ + public int insertRtspDevice(RtspDevice rtspDevice); + + /** + * 修改rtsp设备 + * + * @param rtspDevice rtsp设备 + * @return 结果 + */ + public int updateRtspDevice(RtspDevice rtspDevice); + + /** + * 删除rtsp设备 + * + * @param id rtsp设备主键 + * @return 结果 + */ + public int deleteRtspDeviceById(Long id); + + /** + * 批量删除rtsp设备 + * + * @param ids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteRtspDeviceByIds(Long[] ids); + + /** + * 查询地图rtsp设备列表 + * + * @param rtspDevice + * @return + */ + List selectRtspDeviceListMap(RtspDevice rtspDevice); +} diff --git a/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/service/IRtspDeviceService.java b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/service/IRtspDeviceService.java new file mode 100644 index 0000000..c14cab0 --- /dev/null +++ b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/service/IRtspDeviceService.java @@ -0,0 +1,98 @@ +package com.ruoyi.rtsp.service; + +import java.io.IOException; +import java.util.List; + +import ai.onnxruntime.OrtException; +import com.ruoyi.rtsp.domain.RtspDevice; +import com.ruoyi.rtsp.domain.bo.RtspDeviceBo; +import com.ruoyi.rtsp.domain.bo.alarmClockBo; + +/** + * rtsp设备Service接口 + * + * @author 陈江灿 + * @date 2025-04-22 + */ +public interface IRtspDeviceService { + /** + * 查询rtsp设备 + * + * @param id rtsp设备主键 + * @return rtsp设备 + */ + public RtspDevice selectRtspDeviceById(Long id); + + /** + * 查询rtsp设备列表 + * + * @param rtspDevice rtsp设备 + * @return rtsp设备集合 + */ + public List selectRtspDeviceList(RtspDevice rtspDevice); + + /** + * 新增rtsp设备 + * + * @param rtspDevice rtsp设备 + * @return 结果 + */ + public int insertRtspDevice(RtspDevice rtspDevice); + + /** + * 修改rtsp设备 + * + * @param rtspDevice rtsp设备 + * @return 结果 + */ + public int updateRtspDevice(RtspDevice rtspDevice); + + /** + * 批量删除rtsp设备 + * + * @param ids 需要删除的rtsp设备主键集合 + * @return 结果 + */ + public int deleteRtspDeviceByIds(Long[] ids); + + /** + * 删除rtsp设备信息 + * + * @param id rtsp设备主键 + * @return 结果 + */ + public int deleteRtspDeviceById(Long id); + + + /** + * 新增目标检测新增目标检测 + * + * @param rtspDevice + */ + public void insertRtspDetection(RtspDeviceBo rtspDevice) throws OrtException, IOException; + + /** + * 停止检测/推流 + * @param rtspDevice + * @throws OrtException + * @throws IOException + */ + public void stopRtspDetection(RtspDeviceBo rtspDevice) throws OrtException, IOException; + + + + /** + * 历史播放 + * @param bo + * @return + */ + String alarmClock(alarmClockBo bo); + + /** + * 查询地图rtsp设备列表 + * + * @param rtspDevice + * @return + */ + List selectRtspDeviceListMap(RtspDevice rtspDevice); +} diff --git a/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/service/IRtspStreamPushService.java b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/service/IRtspStreamPushService.java new file mode 100644 index 0000000..f9fa519 --- /dev/null +++ b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/service/IRtspStreamPushService.java @@ -0,0 +1,12 @@ +package com.ruoyi.rtsp.service; + +/** + * @Author: 陈江灿 + * @CreateTime: 2025-06-10 + */ +public interface IRtspStreamPushService { + + public boolean startPush(String streamId, String rtspUrl, String pushUrl); + + public boolean stopPush(String streamId); +} diff --git a/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/service/impl/RtspDeviceServiceImpl.java b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/service/impl/RtspDeviceServiceImpl.java new file mode 100644 index 0000000..a7c0111 --- /dev/null +++ b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/service/impl/RtspDeviceServiceImpl.java @@ -0,0 +1,180 @@ +package com.ruoyi.rtsp.service.impl; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.TimeZone; + + +import ai.onnxruntime.OrtException; +import com.ruoyi.common.annotation.DataScope; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.rtsp.constants.StreamTypeConstants; +import com.ruoyi.rtsp.domain.bo.RtspDeviceBo; +import com.ruoyi.rtsp.domain.bo.alarmClockBo; +import com.ruoyi.rtsp.tool.RtspTool; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.ruoyi.rtsp.mapper.RtspDeviceMapper; +import com.ruoyi.rtsp.domain.RtspDevice; +import com.ruoyi.rtsp.service.IRtspDeviceService; + +/** + * rtsp设备Service业务层处理 + * + * @author 陈江灿 + * @date 2025-04-22 + */ +@Service +public class RtspDeviceServiceImpl implements IRtspDeviceService { + @Autowired + private RtspDeviceMapper rtspDeviceMapper; + + /** + * 查询rtsp设备 + * + * @param id rtsp设备主键 + * @return rtsp设备 + */ + @Override + public RtspDevice selectRtspDeviceById(Long id) { + return rtspDeviceMapper.selectRtspDeviceById(id); + } + + /** + * 查询rtsp设备列表 + * + * @param rtspDevice rtsp设备 + * @return rtsp设备 + */ + @Override + @DataScope(deptAlias = "d") + public List selectRtspDeviceList(RtspDevice rtspDevice) { + return rtspDeviceMapper.selectRtspDeviceList(rtspDevice); + } + + /** + * 新增rtsp设备 + * + * @param rtspDevice rtsp设备 + * @return 结果 + */ + @Override + public int insertRtspDevice(RtspDevice rtspDevice) { + // 生成rtsp地址 + String rtspUrl = RtspTool.generateRtspUrl(rtspDevice); + if (rtspDevice != null) { + rtspDevice.setUrl(rtspUrl); + } + rtspDevice.setCreateTime(DateUtils.getNowDate()); + return rtspDeviceMapper.insertRtspDevice(rtspDevice); + } + + /** + * 修改rtsp设备 + * + * @param rtspDevice rtsp设备 + * @return 结果 + */ + @Override + public int updateRtspDevice(RtspDevice rtspDevice) { + // 生成rtsp地址 + String rtspUrl = RtspTool.generateRtspUrl(rtspDevice); + if (rtspDevice != null) { + rtspDevice.setUrl(rtspUrl); + } + rtspDevice.setUpdateTime(DateUtils.getNowDate()); + return rtspDeviceMapper.updateRtspDevice(rtspDevice); + } + + /** + * 批量删除rtsp设备 + * + * @param ids 需要删除的rtsp设备主键 + * @return 结果 + */ + @Override + public int deleteRtspDeviceByIds(Long[] ids) { + return rtspDeviceMapper.deleteRtspDeviceByIds(ids); + } + + /** + * 删除rtsp设备信息 + * + * @param id rtsp设备主键 + * @return 结果 + */ + @Override + public int deleteRtspDeviceById(Long id) { + return rtspDeviceMapper.deleteRtspDeviceById(id); + } + + /** + * 新增目标检测 + * + * @param bo + */ + @Override + public void insertRtspDetection(RtspDeviceBo bo) throws OrtException, IOException { + } + + @Override + public void stopRtspDetection(RtspDeviceBo bo) throws OrtException, IOException { + } + + @Override + public String alarmClock(alarmClockBo bo) { + RtspDevice device = rtspDeviceMapper.selectRtspDeviceById(bo.getId()); + String firm = device.getFirm(); + if (firm.equals(StreamTypeConstants.HIKVISION)) { + String startTime = this.formatAlarmTimeHIKVISION(bo.getStartTime()); + String endTime = this.formatAlarmTimeHIKVISION(bo.getEndTime()); + String url = "rtsp://" + device.getUserName() + ":" + device.getPassword() + "@" + device.getIp() + ":554/Streaming/tracks/" + + device.getChannel() + "?starttime=" + startTime + "&endtime=" + endTime; + return url; + } else if (firm.equals(StreamTypeConstants.DAHUA)) { + String startTime = this.formatAlarmTimeDaHua(bo.getStartTime()); + String endTime = this.formatAlarmTimeDaHua(bo.getEndTime()); + String url = "rtsp://" + device.getUserName() + ":" + device.getPassword() + "@" + device.getIp() + ":554/cam/playback?channel=" + + device.getChannel() + "&subtype=1&starttime=" + startTime + "&endtime=" + endTime; + return url; + } + throw new RuntimeException("暂不支持该厂商"); + } + + /** + * 查询地图rtsp设备列表 + * + * @param rtspDevice + * @return + */ + @Override + public List selectRtspDeviceListMap(RtspDevice rtspDevice) { + return rtspDeviceMapper.selectRtspDeviceListMap(rtspDevice); + } + + /** + * 大华-格式化时间 + * @param date + * @return + */ + public static String formatAlarmTimeDaHua(Date date) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss"); + sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai")); + return sdf.format(date); + } + + /** + * HIKVISION-格式化时间 + * @param date + * @return + */ + public static String formatAlarmTimeHIKVISION(Date date) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'"); + sdf.setTimeZone(TimeZone.getTimeZone("UTC")); + return sdf.format(date); + } + + +} diff --git a/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/service/impl/RtspStreamPushServiceImpl.java b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/service/impl/RtspStreamPushServiceImpl.java new file mode 100644 index 0000000..b0bb30e --- /dev/null +++ b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/service/impl/RtspStreamPushServiceImpl.java @@ -0,0 +1,78 @@ +package com.ruoyi.rtsp.service.impl; + +import com.ruoyi.rtsp.service.IRtspStreamPushService; +import org.springframework.stereotype.Service; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * @Author: 陈江灿 + * @CreateTime: 2025-06-10 + */ +@Service +public class RtspStreamPushServiceImpl implements IRtspStreamPushService { + + private final ConcurrentHashMap streamProcessMap = new ConcurrentHashMap<>(); + + private final ExecutorService executorService = Executors.newCachedThreadPool(); + + @Override + public boolean startPush(String streamId, String rtspUrl, String pushUrl) { + if (streamProcessMap.containsKey(streamId)) { + stopPush(streamId); + } + String[] command = new String[]{ + "ffmpeg", + "-rtsp_transport", "tcp", + "-i", rtspUrl, + "-map", "0:v", + "-map", "0:a?", + "-c:v", "copy", + "-c:a", "aac", + "-f", "flv", + pushUrl + }; + try { + ProcessBuilder pb = new ProcessBuilder(command); + pb.redirectErrorStream(true); + Process process = pb.start(); + executorService.submit(() -> { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + String line; + while ((line = reader.readLine()) != null) { + System.out.println("[ffmpeg-" + streamId + "] " + line); + } + } catch (IOException e) { + e.printStackTrace(); + } + }); + + streamProcessMap.put(streamId, process); + executorService.submit(() -> { + try { + int exitCode = process.waitFor(); + System.out.println("ffmpeg process for streamId " + streamId + " exited with code " + exitCode); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + streamProcessMap.remove(streamId); + } + }); + return true; + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } + + @Override + public boolean stopPush(String streamId) { + return false; + } + +} diff --git a/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/tool/RtspTool.java b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/tool/RtspTool.java new file mode 100644 index 0000000..a338626 --- /dev/null +++ b/ruoyi-rtsp/src/main/java/com/ruoyi/rtsp/tool/RtspTool.java @@ -0,0 +1,36 @@ +package com.ruoyi.rtsp.tool; + +import com.ruoyi.rtsp.constants.StreamTypeConstants; +import com.ruoyi.rtsp.domain.RtspDevice; + +/** + * @Description: rtsp工具类 + * @Author: 陈江灿 + * @CreateTime: 2025-04-22 + */ +public class RtspTool { + + + /** + * 生成rtsp地址 + * @return + */ + public static String generateRtspUrl(RtspDevice rtspDevice) { + String username = rtspDevice.getUserName(); + String password = rtspDevice.getPassword(); + String ip = rtspDevice.getIp(); + String channel = rtspDevice.getChannel(); + String firm = rtspDevice.getFirm(); + String port = "554"; + if (firm.equals(StreamTypeConstants.HIKVISION)) { + return String.format("rtsp://%s:%s@%s:%s/Streaming/Channels/%s", username, password, ip, port, channel); + } else if (firm.equals(StreamTypeConstants.DAHUA)) { + return String.format("rtsp://%s:%s@%s:%s/cam/realmonitor?channel=%s&subtype=0", username, password, ip, port, channel); + } else if (firm.equals(StreamTypeConstants.UNIVIEW)) { + return String.format("rtsp://%s:%s@%s:%s/media/video%s", username, password, ip, port, channel); + } else if (firm.equals(StreamTypeConstants.MERCURY)) { + return String.format("rtsp://%s:%s@%s:%s/stream%s", username, password, ip, port, channel); + } + return null; + } +} diff --git a/ruoyi-rtsp/src/main/resources/mapper/rtsp/RtspDeviceMapper.xml b/ruoyi-rtsp/src/main/resources/mapper/rtsp/RtspDeviceMapper.xml new file mode 100644 index 0000000..6338720 --- /dev/null +++ b/ruoyi-rtsp/src/main/resources/mapper/rtsp/RtspDeviceMapper.xml @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select r.id, + r.dept_id, + r.ip, + r.name, + r.user_name, + r.password, + r.channel, + r.play_type, + r.url, + r.stream_id, + r.easy_NTS_url, + r.firm, + r.lat, + r.lng, + r.address_map, + r.create_by, + r.create_time, + r.update_by, + r.update_time, + r.remark, + d.dept_name + from rtsp_device r + left join sys_dept d on r.dept_id = d.dept_id + + + + + + + + + + insert into rtsp_device + + dept_id, + ip, + name, + user_name, + password, + channel, + play_type, + url, + stream_id, + easy_NTS_url, + firm, + lat, + lng, + address_map, + create_by, + create_time, + update_by, + update_time, + remark, + + + #{deptId}, + #{ip}, + #{name}, + #{userName}, + #{password}, + #{channel}, + #{playType}, + #{url}, + #{streamId}, + #{easyNTSUrl}, + #{firm}, + #{lat}, + #{lng}, + #{addressMap}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + #{remark}, + + + + + update rtsp_device + + dept_id = #{deptId}, + ip = #{ip}, + name = #{name}, + user_name = #{userName}, + password = #{password}, + channel = #{channel}, + play_type = #{playType}, + url = #{url}, + stream_id = #{streamId}, + easy_NTS_url = #{easyNTSUrl}, + firm = #{firm}, + lat = #{lat}, + lng = #{lng}, + address_map = #{addressMap}, + create_by = #{createBy}, + create_time = #{createTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + remark = #{remark}, + + where id = #{id} + + + + delete from rtsp_device where id = #{id} + + + + delete from rtsp_device where id in + + #{id} + + +