This commit is contained in:
orange
2025-08-28 12:52:05 +08:00
parent 05f0ddfe55
commit 83753c01b5
20 changed files with 1373 additions and 52 deletions

View File

@@ -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<RtspDevice> list = rtspDeviceService.selectRtspDeviceList(rtspDevice);
return getDataTable(list);
}
/**
* 查询rtsp设备列表
*/
@PreAuthorize("@ss.hasPermi('rtsp:RtspDevice:list')")
@GetMapping("/rtspDeviceList")
public AjaxResult rtspDeviceList(RtspDevice rtspDevice, String mapType) {
List<RtspDevice> 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<RtspDevice> list = rtspDeviceService.selectRtspDeviceList(rtspDevice);
ExcelUtil<RtspDevice> util = new ExcelUtil<RtspDevice>(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();
}
}

View File

@@ -6,9 +6,9 @@ spring:
druid: druid:
# 主库数据源 # 主库数据源
master: 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 username: root
password: haoxin password: admin123
# 从库数据源 # 从库数据源
slave: slave:
# 从数据源开关/默认关闭 # 从数据源开关/默认关闭

View File

@@ -87,9 +87,9 @@ spring:
# 端口默认为6379 # 端口默认为6379
port: 6379 port: 6379
# 数据库索引 # 数据库索引
database: 8 database: 6
# 密码 # 密码
password: password: ruoyi123
# password: 123456 # password: 123456
# 连接超时时间 # 连接超时时间
timeout: 10s timeout: 10s
@@ -162,64 +162,45 @@ sip:
alarm: false alarm: false
##zlm 默认服务器配置 ##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: media:
id: haoxin-zlm-1 id: hxkj_zlm
# [必须修改] zlm服务器的内网IP # [必须修改] zlm服务器的内网IP
ip: 192.168.158.199 ip: 192.168.2.199
# [必须修改] zlm服务器的http.port # [必须修改] zlm服务器的http.port
http-port: 8092 http-port: 8092
# [可选] zlm服务器的hook所使用的IP, 默认使用sip.ip # [可选] zlm服务器的hook所使用的IP, 默认使用sip.ip
hook-ip: 192.168.158.199 hook-ip: 192.168.2.199
# [必选选] zlm服务器的hook.admin_params=secret # [必选选] zlm服务器的hook.admin_params=secret
secret: haoxin secret: hxkj_zlm
# # [可选] 录像文件存储路径
# record-path: F:/zml/record
# [可选] 录像保存时间,单位是天
record-day: 3
# 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分 点播超时建议使用多端口测试 # 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分 点播超时建议使用多端口测试
rtp: rtp:
# [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输 # [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输
enable: true enable: true
# [可选] 在此范围内选择端口用于媒体流传输, 必须提前在zlm上配置该属性不然自动配置此属性可能不成功 # [可选] 在此范围内选择端口用于媒体流传输, 必须提前在zlm上配置该属性不然自动配置此属性可能不成功
port-range: 40000,40300 # 端口范围 port-range: 30000,30500 # 端口范围
# [可选] 国标级联在此范围内选择端口发送媒体流, # [可选] 国标级联在此范围内选择端口发送媒体流,
send-port-range: 40000,40300 # 端口范围 send-port-range: 30000,30500 # 端口范围
##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 # 端口范围
# [根据业务需求配置] # [根据业务需求配置]
@@ -240,7 +221,7 @@ user-settings:
# ISUP配置 # ISUP配置
isup: isup:
#注册服务器监听地址(服务器本地地址) #注册服务器监听地址(服务器本地地址)
IP: 192.168.158.200 IP: 192.168.2.199
route: Isup route: Isup
cmsServer: cmsServer:
Port: 7660 Port: 7660
@@ -248,7 +229,7 @@ isup:
smsServer: smsServer:
Port: 7665 Port: 7665
#取流服务器监听地址端口(服务器本地地址) #取流服务器监听地址端口(服务器本地地址)
ListenIP: 192.168.158.200 ListenIP: 192.168.2.199
ListenPort: 7665 ListenPort: 7665
# ISUP5.0登录秘钥 # ISUP5.0登录秘钥
isupKey: 12345678 isupKey: 12345678

View File

@@ -18,13 +18,40 @@
</properties> </properties>
<dependencies> <dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- 通用工具--> <!-- 通用工具-->
<dependency> <dependency>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.microsoft.onnxruntime</groupId>
<artifactId>onnxruntime</artifactId>
<version>1.16.1</version>
</dependency>
<dependency>
<groupId>org.openpnp</groupId>
<artifactId>opencv</artifactId>
<version>4.7.0-0</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.3</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.9.1</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -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"; // 水星
}

View File

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

View File

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

View File

@@ -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";
}
}

View File

@@ -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();
}
}

View File

@@ -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<KeyPoint> 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<keyPointNum;i++) {
this.keyPointList.add(new KeyPoint(i, peResult[6+3*i], peResult[6+3*i+1], peResult[6+3*i+2]));
}
}
public Float getX0() {
return x0;
}
public Float getY0() {
return y0;
}
public Float getX1() {
return x1;
}
public Float getY1() {
return y1;
}
public Float getScore() {
return score;
}
public Integer getClsId() {
return clsId;
}
public List<KeyPoint> 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();
}
}

View File

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

View File

@@ -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 + '\'' +
'}';
}
}

View File

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

View File

@@ -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<RtspDevice> 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<RtspDevice> selectRtspDeviceListMap(RtspDevice rtspDevice);
}

View File

@@ -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<RtspDevice> 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<RtspDevice> selectRtspDeviceListMap(RtspDevice rtspDevice);
}

View File

@@ -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);
}

View File

@@ -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<RtspDevice> 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<RtspDevice> 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);
}
}

View File

@@ -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<String, Process> 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;
}
}

View File

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

View File

@@ -0,0 +1,173 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.rtsp.mapper.RtspDeviceMapper">
<resultMap type="RtspDevice" id="RtspDeviceResult">
<result property="id" column="id" />
<result property="deptId" column="dept_id" />
<result property="ip" column="ip" />
<result property="name" column="name" />
<result property="userName" column="user_name" />
<result property="password" column="password" />
<result property="channel" column="channel" />
<result property="playType" column="play_type" />
<result property="url" column="url" />
<result property="streamId" column="stream_id" />
<result property="easyNTSUrl" column="easy_NTS_url" />
<result property="firm" column="firm" />
<result property="lat" column="lat" />
<result property="lng" column="lng" />
<result property="addressMap" column="address_map" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
</resultMap>
<sql id="selectRtspDeviceVo">
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
</sql>
<select id="selectRtspDeviceList" parameterType="RtspDevice" resultMap="RtspDeviceResult">
<include refid="selectRtspDeviceVo"/>
<where>
<if test="deptId != null">and (r.dept_id = #{deptId} OR r.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(#{deptId}, ancestors) ))</if>
<if test="ip != null and ip != ''"> and r.ip = #{ip}</if>
<if test="name != null and name != ''"> and r.name like concat('%', #{name}, '%')</if>
<if test="firm != null and firm != ''"> and r.firm = #{firm}</if>
<!-- 数据范围过滤 -->
${params.dataScope}
</where>
order by r.create_time desc
</select>
<select id="selectRtspDeviceById" parameterType="Long" resultMap="RtspDeviceResult">
<include refid="selectRtspDeviceVo"/>
where id = #{id}
</select>
<select id="selectRtspDeviceListMap" parameterType="RtspDevice" resultMap="RtspDeviceResult">
<include refid="selectRtspDeviceVo"/>
<where>
<if test="deptId != null">and (r.dept_id = #{deptId} OR r.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(#{deptId}, ancestors) ))</if>
<if test="ip != null and ip != ''"> and r.ip = #{ip}</if>
<if test="name != null and name != ''"> and r.name like concat('%', #{name}, '%')</if>
<if test="firm != null and firm != ''"> and r.firm = #{firm}</if>
and lat IS NOT NULL AND lng IS NOT NULL
<!-- 数据范围过滤 -->
${params.dataScope}
</where>
order by r.create_time desc
</select>
<insert id="insertRtspDevice" parameterType="RtspDevice" useGeneratedKeys="true" keyProperty="id">
insert into rtsp_device
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="deptId != null">dept_id,</if>
<if test="ip != null and ip != ''">ip,</if>
<if test="name != null and name != ''">name,</if>
<if test="userName != null and userName != ''">user_name,</if>
<if test="password != null and password != ''">password,</if>
<if test="channel != null and channel != ''">channel,</if>
<if test="playType != null">play_type,</if>
<if test="url != null">url,</if>
<if test="streamId != null">stream_id,</if>
<if test="easyNTSUrl != null">easy_NTS_url,</if>
<if test="firm != null">firm,</if>
<if test="lat != null">lat,</if>
<if test="lng != null">lng,</if>
<if test="addressMap != null">address_map,</if>
<if test="createBy != null">create_by,</if>
<if test="createTime != null">create_time,</if>
<if test="updateBy != null">update_by,</if>
<if test="updateTime != null">update_time,</if>
<if test="remark != null">remark,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="deptId != null">#{deptId},</if>
<if test="ip != null and ip != ''">#{ip},</if>
<if test="name != null and name != ''">#{name},</if>
<if test="userName != null and userName != ''">#{userName},</if>
<if test="password != null and password != ''">#{password},</if>
<if test="channel != null and channel != ''">#{channel},</if>
<if test="playType != null">#{playType},</if>
<if test="url != null">#{url},</if>
<if test="streamId != null">#{streamId},</if>
<if test="easyNTSUrl != null">#{easyNTSUrl},</if>
<if test="firm != null">#{firm},</if>
<if test="lat != null">#{lat},</if>
<if test="lng != null">#{lng},</if>
<if test="addressMap != null">#{addressMap},</if>
<if test="createBy != null">#{createBy},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateBy != null">#{updateBy},</if>
<if test="updateTime != null">#{updateTime},</if>
<if test="remark != null">#{remark},</if>
</trim>
</insert>
<update id="updateRtspDevice" parameterType="RtspDevice">
update rtsp_device
<trim prefix="SET" suffixOverrides=",">
<if test="deptId != null">dept_id = #{deptId},</if>
<if test="ip != null and ip != ''">ip = #{ip},</if>
<if test="name != null and name != ''">name = #{name},</if>
<if test="userName != null and userName != ''">user_name = #{userName},</if>
<if test="password != null and password != ''">password = #{password},</if>
<if test="channel != null and channel != ''">channel = #{channel},</if>
<if test="playType != null">play_type = #{playType},</if>
<if test="url != null">url = #{url},</if>
<if test="streamId != null">stream_id = #{streamId},</if>
<if test="easyNTSUrl != null">easy_NTS_url = #{easyNTSUrl},</if>
<if test="firm != null">firm = #{firm},</if>
<if test="lat != null">lat = #{lat},</if>
<if test="lng != null">lng = #{lng},</if>
<if test="addressMap != null">address_map = #{addressMap},</if>
<if test="createBy != null">create_by = #{createBy},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="updateBy != null">update_by = #{updateBy},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
<if test="remark != null">remark = #{remark},</if>
</trim>
where id = #{id}
</update>
<delete id="deleteRtspDeviceById" parameterType="Long">
delete from rtsp_device where id = #{id}
</delete>
<delete id="deleteRtspDeviceByIds" parameterType="String">
delete from rtsp_device where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>