‘liusuyi’
2023-08-29 510c29eecab77493816d3f0cdb5e5c4462083cc8
增加流媒体数据库业务
增加电子围栏接口
已添加6个文件
已修改5个文件
770 ■■■■ 文件已修改
ard-work/src/main/java/com/ruoyi/alarmpoints/elecwall/controller/ArdWallController.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/media/controller/MediaController.java 178 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/media/controller/VtduController.java 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/media/domain/Vtdu.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/media/mapper/VtduMapper.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/media/service/IMediaService.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/media/service/IVtduService.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/media/service/impl/MediaService.java 101 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/media/service/impl/VtduServiceImpl.java 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/resources/mapper/vtdu/VtduMapper.xml 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/resources/templates/mediaMTX.html 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/alarmpoints/elecwall/controller/ArdWallController.java
@@ -2,6 +2,9 @@
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
@@ -27,6 +30,7 @@
 * @author ard
 * @date 2023-07-20
 */
@Api(tags = "电子围栏管理")
@RestController
@RequestMapping("/alarmpoints/wall")
public class ArdWallController extends BaseController
@@ -37,6 +41,7 @@
    /**
     * æŸ¥è¯¢ç”µå­å›´æ ç®¡ç†åˆ—表
     */
    @ApiOperation("查询电子围栏管理列表")
    @PreAuthorize("@ss.hasPermi('alarmpoints:wall:list')")
    @GetMapping("/list")
    public TableDataInfo list(ArdWall ardWall)
@@ -62,6 +67,7 @@
    /**
     * èŽ·å–ç”µå­å›´æ ç®¡ç†è¯¦ç»†ä¿¡æ¯
     */
    @ApiOperation("获取电子围栏管理详细信息")
    @PreAuthorize("@ss.hasPermi('alarmpoints:wall:query')")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") String id)
@@ -72,6 +78,7 @@
    /**
     * æ–°å¢žç”µå­å›´æ ç®¡ç†
     */
    @ApiOperation("新增电子围栏管理")
    @PreAuthorize("@ss.hasPermi('alarmpoints:wall:add')")
    @Log(title = "电子围栏管理", businessType = BusinessType.INSERT)
    @PostMapping
@@ -83,6 +90,7 @@
    /**
     * ä¿®æ”¹ç”µå­å›´æ ç®¡ç†
     */
    @ApiOperation("修改电子围栏管理")
    @PreAuthorize("@ss.hasPermi('alarmpoints:wall:edit')")
    @Log(title = "电子围栏管理", businessType = BusinessType.UPDATE)
    @PutMapping
@@ -94,6 +102,7 @@
    /**
     * åˆ é™¤ç”µå­å›´æ ç®¡ç†
     */
    @ApiOperation("删除电子围栏管理")
    @PreAuthorize("@ss.hasPermi('alarmpoints:wall:remove')")
    @Log(title = "电子围栏管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
ard-work/src/main/java/com/ruoyi/media/controller/MediaController.java
@@ -2,15 +2,15 @@
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.ruoyi.common.annotation.Anonymous;
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.StringUtils;
import com.ruoyi.device.camera.domain.ArdCameras;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.media.domain.StreamInfo;
import com.ruoyi.media.domain.Vtdu;
import com.ruoyi.media.service.IMediaService;
import com.ruoyi.media.service.IVtduService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
@@ -19,7 +19,6 @@
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
 * @Description:
@@ -35,11 +34,16 @@
public class MediaController extends BaseController {
    @Resource
    private IMediaService mediaService;
    @Resource
    private IVtduService vtduService;
    /**
     * å¢žåŠ é€šé“
     */
    @PostMapping()
    @ApiOperation("增加转码")
    @ApiOperation("增加通道")
    @PreAuthorize("@ss.hasPermi('media:stream:add')")
    @ApiOperationSupport(includeParameters = {"streamInfo.name", "streamInfo.rtspSource", "streamInfo.mode"})
    @ApiOperationSupport(includeParameters = {"streamInfo.name", "streamInfo.rtspSource", "streamInfo.mode", "streamInfo.isCode"}, order = 1)
    public AjaxResult addPath(@RequestBody StreamInfo streamInfo) {
        if (StringUtils.isEmpty(streamInfo.getName())) {
            return AjaxResult.error("通道名称不能为空");
@@ -48,107 +52,135 @@
            return AjaxResult.error("rtsp地址不能为空");
        }
        String rtsp = mediaService.addPath(streamInfo.getName(), streamInfo.getRtspSource(), streamInfo.getMode(), streamInfo.getIsCode());
        Vtdu vtdu = new Vtdu();
        vtdu.setName(streamInfo.getName());
        vtdu.setRtspUrl(streamInfo.getRtspSource());
        vtdu.setIsCode(streamInfo.getIsCode());
        vtdu.setCodeType(streamInfo.getMode());
        vtduService.insertVtdu(vtdu);
        return AjaxResult.success(rtsp);
    }
    /**
     * ä¿®æ”¹é€šé“
     */
    @ApiOperation("修改通道")
    @ApiOperationSupport(includeParameters = {"streamInfo.name", "streamInfo.rtspSource", "streamInfo.mode", "streamInfo.isCode"}, order = 2)
    @PreAuthorize("@ss.hasPermi('media:stream:edit')")
    @PutMapping
    public AjaxResult edit(@RequestBody StreamInfo streamInfo) {
        mediaService.removePath(new String[]{streamInfo.getName()});
        vtduService.deleteVtduByName(streamInfo.getName());
        String rtsp = mediaService.addPath(streamInfo.getName(), streamInfo.getRtspSource(), streamInfo.getMode(), streamInfo.getIsCode());
        Vtdu vtdu = new Vtdu();
        vtdu.setName(streamInfo.getName());
        vtdu.setRtspUrl(streamInfo.getRtspSource());
        vtdu.setIsCode(streamInfo.getIsCode());
        vtdu.setCodeType(streamInfo.getMode());
        vtduService.insertVtdu(vtdu);
        return AjaxResult.success(rtsp);
    }
    /**
     * èŽ·å–è½¬ç è¯¦ç»†ä¿¡æ¯
     * ç§»é™¤é€šé“
     */
    @ApiOperation("获取转码详细信息")
    @DeleteMapping("/path/{names}")
    @PreAuthorize("@ss.hasPermi('media:stream:remove')")
    @ApiOperation("移除通道")
    @ApiOperationSupport(order = 3)
    public AjaxResult removePath(@PathVariable String[] names) {
        mediaService.removePath(names);
        vtduService.deleteVtduByNames(names);
        return AjaxResult.success();
    }
    /**
     * ç§»é™¤æ‹‰æµ
     */
    @ApiOperation("移除拉流")
    @ApiOperationSupport(order =4 )
    @PreAuthorize("@ss.hasPermi('media:stream:remove')")
    @DeleteMapping("/{id}")
    public AjaxResult removePullStreamSession(@PathVariable String sessionId) {
        List<StreamInfo> pullStreamList = mediaService.getPullStreamList();
        StreamInfo streamInfo = pullStreamList.stream()
                .filter(object -> object.getId().equals(sessionId))
                .collect(Collectors.toList()).get(0);
        switch (streamInfo.getSessionType()) {
            case "rtsp":
                return AjaxResult.success(mediaService.kickRtspSession(sessionId));
            case "webrtc":
                return AjaxResult.success(mediaService.kickWebrtcSession(sessionId));
            case "rtmp":
                return AjaxResult.success(mediaService.kickRtmpSession(sessionId));
        }
        return AjaxResult.error();
    }
    /**
     * èŽ·å–é€šé“è¯¦ç»†ä¿¡æ¯
     */
    @ApiOperation("获取通道详细信息")
    @ApiOperationSupport(order =4 )
    @GetMapping(value = "/{name}")
    public AjaxResult getInfo(@PathVariable("name") String name) {
        return success(mediaService.getPathInfo(name));
    }
    /**
     * ä¿®æ”¹è½¬ç 
     * èŽ·å–å½“å‰é€šé“åˆ—è¡¨
     */
    @ApiOperation("修改转码")
    @PreAuthorize("@ss.hasPermi('media:stream:edit')")
    @PutMapping
    public AjaxResult edit(@RequestBody StreamInfo streamInfo) {
        mediaService.removePath(new String[]{streamInfo.getName()});
        String rtsp = mediaService.addPath(streamInfo.getName(), streamInfo.getRtspSource(), streamInfo.getMode(), streamInfo.getIsCode());
        return AjaxResult.success(rtsp);
    }
    @DeleteMapping("/path/{names}")
    @PreAuthorize("@ss.hasPermi('media:stream:remove')")
    @ApiOperation("移除转码")
    public AjaxResult removePath(@PathVariable String[] names) {
        mediaService.removePath(names);
        return AjaxResult.success();
    }
    @GetMapping("/path/list")
    @ApiOperation("获取当前转码列表")
    @ApiOperation("获取当前通道列表")
    @ApiOperationSupport(order = 5)
    public TableDataInfo getPaths() {
        startPage();
        return getDataTable(mediaService.paths());
    }
    @GetMapping("/getRtspSessions")
    @ApiOperation("获取rtsp会话列表")
    public AjaxResult getRtspSessions() {
        return AjaxResult.success(mediaService.rtspsessions());
    }
    @GetMapping("/getRtspConns")
    @ApiOperation("获取rtsp连接列表")
    public AjaxResult getRtspConns() {
        return AjaxResult.success(mediaService.rtspconns());
    }
    /**
     * æŒ‰ID查询拉流详情
     */
    @GetMapping("/getRtspSessionById")
    @ApiOperation("按ID查询会话")
    @ApiOperation("按ID查询拉流详情")
    public AjaxResult getRtspSessionById(String sessionId) {
        return AjaxResult.success(mediaService.getRtspSessionById(sessionId));
        List<StreamInfo> pullStreamList = mediaService.getPullStreamList();
        StreamInfo streamInfo = pullStreamList.stream()
                .filter(object -> object.getId().equals(sessionId))
                .collect(Collectors.toList()).get(0);
        switch (streamInfo.getSessionType()) {
            case "rtsp":
                return AjaxResult.success(mediaService.getRtspSessionById(sessionId));
            case "rtmp":
                return AjaxResult.success(mediaService.getRtmpSessionById(sessionId));
            case "webrtc":
                return AjaxResult.success(mediaService.getWebrtcSessionById(sessionId));
        }
        return AjaxResult.error();
    }
    @GetMapping("/getPushStreams")
    @ApiOperation("获取推流信息")
    public AjaxResult getPushStreams() {
        return AjaxResult.success(mediaService.getPushStreams());
    }
    @GetMapping("/getPullStreams")
    @ApiOperation("获取拉流信息")
    public AjaxResult getPullStreams() {
        return AjaxResult.success(mediaService.getPullStreams());
    }
    /**
     * èŽ·å–æŽ¨æµåˆ—è¡¨
     */
    @PreAuthorize("@ss.hasPermi('media:stream:list')")
    @GetMapping("/pushList")
    @ApiOperation("获取推流列表")
    @ApiOperationSupport(order = 6)
    public TableDataInfo getPushStreamList() {
        startPage();
        return getDataTable(mediaService.getPushStreamList());
    }
    /**
     * åˆ é™¤æµåª’体拉流
     */
    @PreAuthorize("@ss.hasPermi('media:stream:remove')")
    @DeleteMapping("/{id}")
    public AjaxResult removePullStreamSession(@PathVariable String id) {
        List<StreamInfo> pullStreamList = mediaService.getPullStreamList();
        StreamInfo streamInfo = pullStreamList.stream()
                .filter(object -> object.getId().equals(id))
                .collect(Collectors.toList()).get(0);
        switch (streamInfo.getSessionType()) {
            case "rtsp":
                return AjaxResult.success(mediaService.kickRtspSession(id));
            case "webrtc":
                return AjaxResult.success(mediaService.kickWebrtcSession(id));
            case "rtmp":
                return AjaxResult.success(mediaService.kickRtmpSession(id));
        }
        return AjaxResult.error();
    }
    /**
     * èŽ·å–æ‹‰æµåˆ—è¡¨
     */
    @PreAuthorize("@ss.hasPermi('media:stream:list')")
    @GetMapping("/pullList")
    @ApiOperation("获取拉流列表")
    @ApiOperationSupport(order = 7)
    public TableDataInfo getPullStreamList() {
        startPage();
        return getDataTable(mediaService.getPullStreamList());
ard-work/src/main/java/com/ruoyi/media/controller/VtduController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,104 @@
package com.ruoyi.media.controller;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.media.domain.Vtdu;
import com.ruoyi.media.service.IVtduService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
/**
 * æµåª’体管理Controller
 *
 * @author ard
 * @date 2023-08-29
 */
@RestController
@RequestMapping("/vtdu/media")
public class VtduController extends BaseController
{
    @Autowired
    private IVtduService vtduService;
    /**
     * æŸ¥è¯¢æµåª’体管理列表
     */
    @PreAuthorize("@ss.hasPermi('vtdu:media:list')")
    @GetMapping("/list")
    public TableDataInfo list(Vtdu vtdu)
    {
        startPage();
        List<Vtdu> list = vtduService.selectVtduList(vtdu);
        return getDataTable(list);
    }
    /**
     * å¯¼å‡ºæµåª’体管理列表
     */
    @PreAuthorize("@ss.hasPermi('vtdu:media:export')")
    @Log(title = "流媒体管理", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, Vtdu vtdu)
    {
        List<Vtdu> list = vtduService.selectVtduList(vtdu);
        ExcelUtil<Vtdu> util = new ExcelUtil<Vtdu>(Vtdu.class);
        util.exportExcel(response, list, "流媒体管理数据");
    }
    /**
     * èŽ·å–æµåª’ä½“ç®¡ç†è¯¦ç»†ä¿¡æ¯
     */
    @PreAuthorize("@ss.hasPermi('vtdu:media:query')")
    @GetMapping(value = "/{name}")
    public AjaxResult getInfo(@PathVariable("name") String name)
    {
        return success(vtduService.selectVtduByName(name));
    }
    /**
     * æ–°å¢žæµåª’体管理
     */
    @PreAuthorize("@ss.hasPermi('vtdu:media:add')")
    @Log(title = "流媒体管理", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody Vtdu vtdu)
    {
        return toAjax(vtduService.insertVtdu(vtdu));
    }
    /**
     * ä¿®æ”¹æµåª’体管理
     */
    @PreAuthorize("@ss.hasPermi('vtdu:media:edit')")
    @Log(title = "流媒体管理", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody Vtdu vtdu)
    {
        return toAjax(vtduService.updateVtdu(vtdu));
    }
    /**
     * åˆ é™¤æµåª’体管理
     */
    @PreAuthorize("@ss.hasPermi('vtdu:media:remove')")
    @Log(title = "流媒体管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{names}")
    public AjaxResult remove(@PathVariable String[] names)
    {
        return toAjax(vtduService.deleteVtduByNames(names));
    }
}
ard-work/src/main/java/com/ruoyi/media/domain/Vtdu.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
package com.ruoyi.media.domain;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
/**
 * æµåª’体管理对象 vtdu
 *
 * @author ard
 * @date 2023-08-29
 */
@Data
public class Vtdu extends BaseEntity {
    private static final long serialVersionUID = 1L;
    /**
     * ä¸»é”®åç§°
     */
    @Excel(name = "名称")
    private String name;
    /**
     * rtsp源地址
     */
    @Excel(name = "rtsp源地址")
    private String rtspUrl;
    /**
     * æ˜¯å¦è½¬ç 
     */
    @Excel(name = "是否转码")
    private String isCode;
    /**
     * è½¬ç æ¨¡å¼
     */
    @Excel(name = "转码模式")
    private String codeType;
}
ard-work/src/main/java/com/ruoyi/media/mapper/VtduMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,60 @@
package com.ruoyi.media.mapper;
import java.util.List;
import com.ruoyi.media.domain.Vtdu;
/**
 * æµåª’体管理Mapper接口
 *
 * @author ard
 * @date 2023-08-29
 */
public interface VtduMapper
{
    /**
     * æŸ¥è¯¢æµåª’体管理
     *
     * @param name æµåª’体管理主键
     * @return æµåª’体管理
     */
    public Vtdu selectVtduByName(String name);
    /**
     * æŸ¥è¯¢æµåª’体管理列表
     *
     * @param vtdu æµåª’体管理
     * @return æµåª’体管理集合
     */
    public List<Vtdu> selectVtduList(Vtdu vtdu);
    /**
     * æ–°å¢žæµåª’体管理
     *
     * @param vtdu æµåª’体管理
     * @return ç»“æžœ
     */
    public int insertVtdu(Vtdu vtdu);
    /**
     * ä¿®æ”¹æµåª’体管理
     *
     * @param vtdu æµåª’体管理
     * @return ç»“æžœ
     */
    public int updateVtdu(Vtdu vtdu);
    /**
     * åˆ é™¤æµåª’体管理
     *
     * @param name æµåª’体通道名称
     * @return ç»“æžœ
     */
    public int deleteVtduByName(String name);
    /**
     * æ‰¹é‡åˆ é™¤æµåª’体管理
     *
     * @param names éœ€è¦åˆ é™¤çš„æ•°æ®ä¸»é”®é›†åˆ
     * @return ç»“æžœ
     */
    public int deleteVtduByNames(String[] names);
}
ard-work/src/main/java/com/ruoyi/media/service/IMediaService.java
@@ -14,30 +14,27 @@
     * åˆ˜è‹ä¹‰
     * 2023/8/12 13:56:52
     */
    public String addPath(String name, String rtspPath, String mode, String isCode);
    String addPath(String name, String rtspPath, String mode, String isCode);
    StreamInfo getPathInfo(String name);
    public void removePath(String[] names);
    void removePath(String[] names);
    public List<StreamInfo> paths();
    public List<Items> rtspconns();
    public List<Items> rtspsessions();
    List<StreamInfo> paths();
    RtspSession getRtspSessionById(String sessionId);
    WebrtcSession getWebrtcSessionById(String sessionId);
    RtmpSession getRtmpSessionById(String sessionId);
    List<RtspSession> getPushStreams();
    List<RtspSession> getPullStreams();
    WebrtcSession getWebrtcSessionById(String sessionId);
    RtmpSession getRtmpSessionById(String sessionId);
    List<StreamInfo> getPushStreamList();
    List<StreamInfo> getPullStreamList();
    Boolean kickRtspSession(String sessionId);
    Boolean kickRtmpSession(String sessionId);
    Boolean kickWebrtcSession(String sessionId);
}
ard-work/src/main/java/com/ruoyi/media/service/IVtduService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,61 @@
package com.ruoyi.media.service;
import java.util.List;
import com.ruoyi.media.domain.Vtdu;
/**
 * æµåª’体管理Service接口
 *
 * @author ard
 * @date 2023-08-29
 */
public interface IVtduService
{
    /**
     * æŸ¥è¯¢æµåª’体管理
     *
     * @param name æµåª’体管理主键
     * @return æµåª’体管理
     */
    public Vtdu selectVtduByName(String name);
    /**
     * æŸ¥è¯¢æµåª’体管理列表
     *
     * @param vtdu æµåª’体管理
     * @return æµåª’体管理集合
     */
    public List<Vtdu> selectVtduList(Vtdu vtdu);
    /**
     * æ–°å¢žæµåª’体管理
     *
     * @param vtdu æµåª’体管理
     * @return ç»“æžœ
     */
    public int insertVtdu(Vtdu vtdu);
    /**
     * ä¿®æ”¹æµåª’体管理
     *
     * @param vtdu æµåª’体管理
     * @return ç»“æžœ
     */
    public int updateVtdu(Vtdu vtdu);
    /**
     * æ‰¹é‡åˆ é™¤æµåª’体管理
     *
     * @param names éœ€è¦åˆ é™¤çš„æµåª’体管理主键集合
     * @return ç»“æžœ
     */
    public int deleteVtduByNames(String[] names);
    /**
     * åˆ é™¤æµåª’体管理信息
     *
     * @param name æµåª’体管理主键
     * @return ç»“æžœ
     */
    public int deleteVtduByName(String name);
}
ard-work/src/main/java/com/ruoyi/media/service/impl/MediaService.java
@@ -2,7 +2,9 @@
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.media.domain.*;
import com.ruoyi.media.mapper.VtduMapper;
import com.ruoyi.media.service.IMediaService;
import com.ruoyi.utils.forest.MediaClient;
import com.ruoyi.utils.tools.ArdTool;
@@ -33,13 +35,16 @@
@Service
@Slf4j(topic = "cmd")
public class MediaService implements IMediaService {
    @Resource
    VtduMapper vtduMapper;
    @Resource
    MediaClient mediaClient;
    @Value("${mediamtx.host}")
    String mediamtxHost;
    @Value("${mediamtx.enabled}")
    Boolean mediamtxEnabled;
    @Value("${mediamtx.software_decoding}")
    Boolean softwareDecoding;
    String processName = "mediamtx.exe";
@@ -64,6 +69,10 @@
//            CmdUtils.commandStart(command);
            }
        }
        List<Vtdu> vtduList = vtduMapper.selectVtduList(new Vtdu());
        for (Vtdu v : vtduList) {
            addPath(v.getName(), v.getRtspUrl(), v.getCodeType(), v.getIsCode());
        }
    }
    @PreDestroy
@@ -81,18 +90,25 @@
    public String addPath(String name, String rtspPath, String mode, String isCode) {
        String rtspUrl = "rtsp://" + mediamtxHost + ":7554/" + name;
        Conf mediaInfo = new Conf();
        String rootPath = System.getProperty("user.dir").replaceAll("\\\\", "/");
        //-vcodec libx264 //指定视频编码器为 libx264,使用 H.264 ç¼–码格式进行视频压缩
        //-preset ultrafast  //--preset的参数主要调节编码速度和质量的平衡,有ultrafast(转码速度最快,视频往往也最模糊)、superfast、veryfast、faster、fast、medium、slow、slower、veryslow、placebo这10个选项,从快到慢
        //-r 25 //设置输出视频的帧率为 25 å¸§/秒
        //-rtsp_transport tcp //这个选项告诉 FFmpeg ä½¿ç”¨ TCP ä½œä¸º RTSP çš„传输协议
        //-threads 4: æŒ‡å®šè¦ä½¿ç”¨çš„线程数为 4。//这允许 FFmpeg åœ¨å¤šæ ¸å¤„理器上使用多个线程来进行视频编码,以加快速度。
        // -i //用于指定输入媒体文件或输入流的地址
        // -bf 0 ç¦ç”¨B帧,因为webrtc在网页调用时控制台一直输出 WebRTC doesn’t support H264 streams with B-frames
        //-f rtsp //这个选项告诉 FFmpeg è¾“出为 RTSP æ ¼å¼ã€‚
        //CPU软解码编码
        String cmd = "ffmpeg -rtsp_transport tcp -i \"" + rtspPath + "\" -vcodec libx264 -preset:v ultrafast -r 25 -threads 4  -b:v 4096k -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH";
        //String cmd = rootPath + "/lib/mediamtx/" +"ffmpeg -rtsp_transport tcp -i " + rtspPath + " -vcodec libx264 -preset:v ultrafast -r 25 -threads 4  -b:v 2048k -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH";
        //GPU硬解码编码 -hwaccel cuvid -c:v h264_cuvid  ä½¿ç”¨cuda解码   -c:v h264_nvenc ä½¿ç”¨cuda编码
        //String cmd = "ffmpeg -hwaccel cuvid -c:v h264_cuvid  -rtsp_transport udp  -i \"" + rtspPath + "\" -c:v h264_nvenc  -r 25 -threads 4  -b:v 4096k -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH";
        //String cmd = rootPath  + "/lib/mediamtx/" + "ffmpeg -hwaccel cuvid -c:v h264_cuvid  -rtsp_transport udp  -i " + rtspPath + " -c:v h264_nvenc  -r 25 -threads 4  -b:v 2048k -bf 0 -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH";
        if (isCode.equals("1")) {
            String cmd = rootPath + "/lib/mediamtx/" + "ffmpeg -rtsp_transport tcp -i " + rtspPath + " -vcodec libx264 -preset:v ultrafast -r 25 -threads 4  -b:v 2048k -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH";
            if (!softwareDecoding) {
                cmd = rootPath + "/lib/mediamtx/" + "ffmpeg -hwaccel cuvid -c:v h264_cuvid  -rtsp_transport udp  -i " + rtspPath + " -c:v h264_nvenc  -r 25 -threads 4  -b:v 2048k -bf 0 -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH";
            }
            if (mode.equals("1")) {
                mediaInfo.setRunondemand(cmd);
                mediaInfo.setRunondemandrestart(true);
@@ -188,19 +204,6 @@
        return pathInfoList;
    }
    @Override
    public List<Items> rtspconns() {
        String list = mediaClient.rtspconns();
        JsonsRoot jsonsRoot = JSONObject.parseObject(list, JsonsRoot.class);
        return jsonsRoot.getItems();
    }
    @Override
    public List<Items> rtspsessions() {
        String list = mediaClient.rtspsessions();
        JsonsRoot jsonsRoot = JSONObject.parseObject(list, JsonsRoot.class);
        return jsonsRoot.getItems();
    }
    @Override
    public RtspSession getRtspSessionById(String sessionId) {
@@ -223,39 +226,11 @@
        return rtmpSession;
    }
    @Override
    public List<RtspSession> getPushStreams() {
        List<RtspSession> rtspSessions = new ArrayList<>();
        String list = mediaClient.paths();
        JsonsRoot jsonsRoot = JSONObject.parseObject(list, JsonsRoot.class);
        List<Items> items = jsonsRoot.getItems();
        for (Items item : items) {
            Source source = item.getSource();
            RtspSession rtspSession = getRtspSessionById(source.getId());
            rtspSession.setName(item.getName());
            rtspSessions.add(rtspSession);
        }
        return rtspSessions;
    }
    @Override
    public List<RtspSession> getPullStreams() {
        List<RtspSession> rtspSessions = new ArrayList<>();
        String list = mediaClient.paths();
        JsonsRoot jsonsRoot = JSONObject.parseObject(list, JsonsRoot.class);
        List<Items> items = jsonsRoot.getItems();
        for (Items item : items) {
            List<Readers> readers = item.getReaders();
            for (Readers reader : readers) {
                RtspSession rtspSession = getRtspSessionById(reader.getId());
                rtspSession.setName(item.getName());
                rtspSessions.add(rtspSession);
            }
        }
        return rtspSessions;
    }
    /**
     * èŽ·å–æŽ¨æµåˆ—è¡¨
     * åˆ˜è‹ä¹‰
     * 2023/8/29 9:37:05
     */
    @Override
    public List<StreamInfo> getPushStreamList() {
        List<StreamInfo> PushStreamInfoList = new ArrayList<>();
@@ -329,6 +304,11 @@
        return PushStreamInfoList;
    }
    /**
     * èŽ·å–æ‹‰æµåˆ—è¡¨
     * åˆ˜è‹ä¹‰
     * 2023/8/29 9:37:05
     */
    @Override
    public List<StreamInfo> getPullStreamList() {
        List<StreamInfo> PullStreamInfoList = new ArrayList<>();
@@ -380,12 +360,12 @@
                        //开始拉流时间
                        info.setBeginTime(webrtcSession.getCreated());
                        //上行流量
                         bytesReceived = webrtcSession.getBytesReceived();
                         formatReceivedSize = ArdTool.formatFileSize(bytesReceived);
                        bytesReceived = webrtcSession.getBytesReceived();
                        formatReceivedSize = ArdTool.formatFileSize(bytesReceived);
                        info.setUpTraffic(formatReceivedSize);
                        //下行流量
                         bytesSent = webrtcSession.getBytesSent();
                         formatSentSize = ArdTool.formatFileSize(bytesSent);
                        bytesSent = webrtcSession.getBytesSent();
                        formatSentSize = ArdTool.formatFileSize(bytesSent);
                        info.setDownTraffic(formatSentSize);
                        //拉流服务器
                        info.setRemoteAddr(webrtcSession.getRemoteAddr());
@@ -421,6 +401,11 @@
        return PullStreamInfoList;
    }
    /**
     * è¸¢å‡ºrtsp会话
     * åˆ˜è‹ä¹‰
     * 2023/8/29 9:37:05
     */
    @Override
    public Boolean kickRtspSession(String sessionId) {
        try {
@@ -431,6 +416,11 @@
        }
    }
    /**
     * è¸¢å‡ºrtmp会话
     * åˆ˜è‹ä¹‰
     * 2023/8/29 9:37:05
     */
    @Override
    public Boolean kickRtmpSession(String sessionId) {
        try {
@@ -441,6 +431,11 @@
        }
    }
    /**
     * è¸¢å‡ºwebrtc会话
     * åˆ˜è‹ä¹‰
     * 2023/8/29 9:37:05
     */
    @Override
    public Boolean kickWebrtcSession(String sessionId) {
        try {
ard-work/src/main/java/com/ruoyi/media/service/impl/VtduServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,88 @@
package com.ruoyi.media.service.impl;
import java.util.List;
import com.ruoyi.common.utils.uuid.IdUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.media.mapper.VtduMapper;
import com.ruoyi.media.domain.Vtdu;
import com.ruoyi.media.service.IVtduService;
/**
 * æµåª’体管理Service业务层处理
 *
 * @author ard
 * @date 2023-08-29
 */
@Service
public class VtduServiceImpl implements IVtduService {
    @Autowired
    private VtduMapper vtduMapper;
    /**
     * æŸ¥è¯¢æµåª’体管理
     *
     * @param name æµåª’体管理主键
     * @return æµåª’体管理
     */
    @Override
    public Vtdu selectVtduByName(String name) {
        return vtduMapper.selectVtduByName(name);
    }
    /**
     * æŸ¥è¯¢æµåª’体管理列表
     *
     * @param vtdu æµåª’体管理
     * @return æµåª’体管理
     */
    @Override
    public List<Vtdu> selectVtduList(Vtdu vtdu) {
        return vtduMapper.selectVtduList(vtdu);
    }
    /**
     * æ–°å¢žæµåª’体管理
     *
     * @param vtdu æµåª’体管理
     * @return ç»“æžœ
     */
    @Override
    public int insertVtdu(Vtdu vtdu) {
        return vtduMapper.insertVtdu(vtdu);
    }
    /**
     * ä¿®æ”¹æµåª’体管理
     *
     * @param vtdu æµåª’体管理
     * @return ç»“æžœ
     */
    @Override
    public int updateVtdu(Vtdu vtdu) {
        return vtduMapper.updateVtdu(vtdu);
    }
    /**
     * æ‰¹é‡åˆ é™¤æµåª’体管理
     *
     * @param names éœ€è¦åˆ é™¤çš„æ•°æ®ä¸»é”®é›†åˆ
     * @return ç»“æžœ
     */
    @Override
    public int deleteVtduByNames(String[] names) {
        return vtduMapper.deleteVtduByNames(names);
    }
    /**
     * åˆ é™¤æµåª’体管理
     *
     * @param name æµåª’体通道名称
     * @return ç»“æžœ
     */
    @Override
    public int deleteVtduByName(String name) {
        return vtduMapper.deleteVtduByName(name);
    }
}
ard-work/src/main/resources/mapper/vtdu/VtduMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,69 @@
<?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.media.mapper.VtduMapper">
    <resultMap type="Vtdu" id="VtduResult">
        <result property="name"    column="name"    />
        <result property="rtspUrl"    column="rtsp_url"    />
        <result property="isCode"    column="is_code"    />
        <result property="codeType"    column="code_type"    />
    </resultMap>
    <sql id="selectVtduVo">
        select name, rtsp_url, is_code, code_type from vtdu
    </sql>
    <select id="selectVtduList" parameterType="Vtdu" resultMap="VtduResult">
        <include refid="selectVtduVo"/>
        <where>
            <if test="name != null  and name != ''"> and name like '%'||#{name}||'%'</if>
            <if test="rtspUrl != null  and rtspUrl != ''"> and rtsp_url = #{rtspUrl}</if>
            <if test="isCode != null  and isCode != ''"> and is_code = #{isCode}</if>
            <if test="codeType != null  and codeType != ''"> and code_type = #{codeType}</if>
        </where>
    </select>
    <select id="selectVtduByName" parameterType="String" resultMap="VtduResult">
        <include refid="selectVtduVo"/>
        where name = #{name}
    </select>
    <insert id="insertVtdu" parameterType="Vtdu">
        insert into vtdu
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="name != null">name,</if>
            <if test="rtspUrl != null">rtsp_url,</if>
            <if test="isCode != null">is_code,</if>
            <if test="codeType != null">code_type,</if>
         </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="name != null">#{name},</if>
            <if test="rtspUrl != null">#{rtspUrl},</if>
            <if test="isCode != null">#{isCode},</if>
            <if test="codeType != null">#{codeType},</if>
         </trim>
    </insert>
    <update id="updateVtdu" parameterType="Vtdu">
        update vtdu
        <trim prefix="SET" suffixOverrides=",">
            <if test="rtspUrl != null">rtsp_url = #{rtspUrl},</if>
            <if test="isCode != null">is_code = #{isCode},</if>
            <if test="codeType != null">code_type = #{codeType},</if>
        </trim>
        where name = #{name}
    </update>
    <delete id="deleteVtduByName" parameterType="String">
        delete from vtdu where name = #{name}
    </delete>
    <delete id="deleteVtduByNames" parameterType="String">
        delete from vtdu where name in
        <foreach item="name" collection="array" open="(" separator="," close=")">
            #{name}
        </foreach>
    </delete>
</mapper>
ard-work/src/main/resources/templates/mediaMTX.html
@@ -10,7 +10,7 @@
        .video-container {
            display: inline-block;
            vertical-align: top;
            width: 25%; /* å…­ä¸ªè§†é¢‘平均分配一行的宽度 */
            width: 33%; /* 3个视频平均分配一行的宽度 */
            /*padding: 2px; !* å¯ä»¥æ ¹æ®éœ€è¦è°ƒæ•´å†…边距 *!*/
            box-sizing: border-box;
        }
@@ -42,7 +42,16 @@
    </div>
</div>
<script th:inline="javascript">
    const restartPause = 2000;
    var chanMap = new Map();
    window.onload = function () {
        chanMap.set("video1", "http://127.0.0.1:8889/164/");
        chanMap.set("video2", "http://127.0.0.1:8889/164/");
        chanMap.set("video3", "http://127.0.0.1:8889/164/");
        chanMap.set("video4", "http://127.0.0.1:8889/165/");
        chanMap.set("video5", "http://127.0.0.1:8889/165/");
        console.log(chanMap);
    }
    const linkToIceServers = (links) => (
        (links !== null) ? links.split(', ').map((link) => {
            const m = link.match(/^<(.+?)>; rel="ice-server"(; username="(.*?)"; credential="(.*?)"; credential-type="password")?/i);
@@ -260,22 +269,37 @@
            this.eTag = '';
            this.queuedCandidates = [];
        }
        stop() {
            if (this.pc) {
                try {
                    this.pc.close();
                } catch (e) {
                    console.log("Failure close peer connection:" + e);
                }
                this.pc = null;
            }
        }
    }
    let videoMap = new Map();
    $('video').click(function (e) {
        let ID = e.target.id;//获取当前点击事件的元素
        console.log(ID);
        console.log(videoMap);
        if (videoMap.get(ID) != null) {
            closeVideo(ID, videoMap.get(ID));
            closeVideo(ID);
        } else {
            let client = new WHEPClient("http://127.0.0.1:8889/165/", ID);
            let stream = chanMap.get(ID);
            let client = new WHEPClient(stream, ID);
            videoMap.set(ID, client);
        }
    });
    function closeVideo(id) {
        let elementById = document.getElementById(id);
        elementById.pause();
        console.log("关闭" + id)
        let client = videoMap.get(id);
        client.stop(id);
        videoMap.delete(id);
    }
</script>