xiangpei
2024-10-10 5602c458099e38c6c4278334e5cb4f8029c63a50
初始化
7个文件已修改
2个文件已添加
28239 ■■■■■ 已修改文件
pom.xml 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/utils/IdUtils.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application-dev.yml 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/package-lock.json 28064 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml
@@ -95,6 +95,14 @@
    </profiles>
    <dependencies>
        <!--视频处理-->
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv-platform</artifactId>
            <version>1.5.7</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
@@ -117,7 +117,7 @@
                .authorizeRequests()
                .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
                .antMatchers(userSetting.getInterfaceAuthenticationExcludes().toArray(new String[0])).permitAll()
                .antMatchers("/api/user/login", "/index/hook/**","/index/hook/abl/**", "/swagger-ui/**", "/doc.html#/**").permitAll()
                .antMatchers("/api/device/query/devices/**","/api/play/start/img/**", "/api/user/login", "/index/hook/**","/index/hook/abl/**", "/swagger-ui/**", "/doc.html#/**").permitAll()
                .anyRequest().authenticated()
                // 异常处理器
                .and()
src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java
@@ -460,7 +460,7 @@
            logger.info("获取负载最低的节点时无在线节点");
            return null;
        }
        logger.error("ddddddd");
        // 获取分数最低的,及并发最低的
        Set<Object> objects = redisTemplate.opsForZSet().range(key, 0, -1);
        ArrayList<Object> mediaServerObjectS = new ArrayList<>(objects);
@@ -468,7 +468,9 @@
        if (hasAssist == null) {
            String mediaServerId = (String)mediaServerObjectS.get(0);
            mediaServer = getOne(mediaServerId);
            logger.error("111");
        }else if (hasAssist) {
            logger.error("222");
            for (Object mediaServerObject : mediaServerObjectS) {
                String mediaServerId = (String)mediaServerObject;
                MediaServer serverItem = getOne(mediaServerId);
@@ -478,6 +480,7 @@
                }
            }
        }else if (!hasAssist) {
            logger.error("333");
            for (Object mediaServerObject : mediaServerObjectS) {
                String mediaServerId = (String)mediaServerObject;
                MediaServer serverItem = getOne(mediaServerId);
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -726,13 +726,16 @@
    @Override
    public MediaServer getNewMediaServerItem(Device device) {
        logger.error(device.getMediaServerId(), "wocnm");
        if (device == null) {
            return null;
        }
        MediaServer mediaServerItem;
        if (ObjectUtils.isEmpty(device.getMediaServerId()) || "auto".equals(device.getMediaServerId())) {
            logger.error("进的这");
            mediaServerItem = mediaServerService.getMediaServerForMinimumLoad(null);
        } else {
            logger.error("进的else");
            mediaServerItem = mediaServerService.getOne(device.getMediaServerId());
        }
        if (mediaServerItem == null) {
src/main/java/com/genersoft/iot/vmp/utils/IdUtils.java
New file
@@ -0,0 +1,56 @@
package com.genersoft.iot.vmp.utils;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
/**
 * ID生成器工具类
 *
 * @author ruoyi
 */
public class IdUtils
{
    private final static SimpleDateFormat FORMAT = new SimpleDateFormat("yyyyMMddHHmmss");
    private final static SimpleDateFormat DAY_FORMAT = new SimpleDateFormat("yyyyMMdd");
    /**
     * 获取随机UUID
     *
     * @return 随机UUID
     */
    public static String randomUUID()
    {
        return UUID.randomUUID().toString();
    }
    /**
     * 简化的UUID,去掉了横线
     *
     * @return 简化的UUID,去掉了横线
     */
    public static String simpleUUID()
    {
        return UUID.randomUUID().toString().replaceAll("_", "").replaceAll("-", "");
    }
    /**
     * 获取当前时间+随机数的编号
     *
     * @return 编号
     */
    public static String randomNO(Date now)
    {
        return DAY_FORMAT.format(now) + UUID.randomUUID().toString().replaceAll("-","").substring(0, 18);
    }
    /**
     * 获取当前时间+工单数的编号
     *
     * @return 编号
     */
    public static String workOrderNO(Date now,String orderNumber)
    {
        return DAY_FORMAT.format(now) +"_"+ orderNumber;
    }
}
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
@@ -2,6 +2,7 @@
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.genersoft.iot.vmp.common.InviteSessionType;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.UserSetting;
@@ -20,6 +21,7 @@
import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.utils.IdUtils;
import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
@@ -28,16 +30,25 @@
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.FrameGrabber;
import org.bytedeco.javacv.OpenCVFrameConverter;
import org.bytedeco.opencv.global.opencv_imgcodecs;
import org.bytedeco.opencv.opencv_core.Mat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
import javax.servlet.http.HttpServletRequest;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.UUID;
@@ -76,6 +87,8 @@
    @Autowired
    private UserSetting userSetting;
    private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
    @Operation(summary = "开始点播", security = @SecurityRequirement(name = JwtUtils.HEADER))
    @Parameter(name = "deviceId", description = "设备国标编号", required = true)
@@ -149,6 +162,76 @@
        return result;
    }
    @Operation(summary = "开始点播并返回图片", security = @SecurityRequirement(name = JwtUtils.HEADER))
    @Parameter(name = "deviceId", description = "设备国标编号", required = true)
    @Parameter(name = "channelId", description = "通道国标编号", required = true)
    @GetMapping("/start/img/{deviceId}/{channelId}")
    public DeferredResult<WVPResult<String>> playReturnImg(HttpServletRequest request, @PathVariable String deviceId,
                                                         @PathVariable String channelId) {
        DeferredResult<WVPResult<StreamContent>> play = this.play(request, deviceId, channelId);
        Object resultStr = play.getResult();
        System.out.println("获取结果:" + resultStr);
        WVPResult wvpResult = (WVPResult) resultStr;
        WVPResult<String> result = new WVPResult<>();
        result.setData(this.getImg(wvpResult));
        result.setCode(wvpResult.getCode());
        result.setMsg(wvpResult.getMsg());
        DeferredResult<WVPResult<String>> r = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
        r.setResult(result);
        return r;
    }
    private String getImg(WVPResult<StreamContent> wvpResult) {
        String imgUrl = null;
        if (wvpResult.getCode() == 0) {
            String rtspUrl = wvpResult.getData().getFmp4(); // 取mp4地址
            if (StringUtils.hasText(rtspUrl)) {
                System.out.println("目标地址:" + rtspUrl);
                FFmpegFrameGrabber grabber = null;
                try {
                    grabber = new FFmpegFrameGrabber(rtspUrl);
//                    grabber.setOption("rtsp_transport", "tcp"); // 使用tcp的方式,不然会丢包很严重
//                    grabber.setVideoOption("probesize", "10000"); // 设置捕获分析的最大字节
                    grabber.start();
                    Frame frame = grabber.grabImage(); // 直接捕获一帧
                    if (frame != null) {
                        System.out.println("成功捕获一帧");
                        // 将Frame转换为Mat
                        OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat();
                        Mat mat = converter.convertToMat(frame);
                        imgUrl = format.format(new Date()) + "_" + IdUtils.randomUUID() + ".png";
                        // 生成图片路径
                        String imgPath = "/home/zgyw/uploadPath/" + imgUrl;
                        System.out.println("图片保存地址:" + imgPath);
                        imgUrl = "/profile/" + imgUrl;
                        // 保存图片
                        opencv_imgcodecs.imwrite(imgPath, mat);
                    } else {
                        System.out.println("未捕获到帧");
                    }
                } catch (FrameGrabber.Exception e) {
                    e.printStackTrace();
                } finally {
                    if (grabber != null) {
                        try {
                            grabber.stop(); // 停止捕获
                        } catch (FrameGrabber.Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        } else {
            System.out.println("请求失败,错误码:" + wvpResult.getCode() + "--" + wvpResult.getMsg());
        }
        System.out.println("图片URL:" + imgUrl);
        return imgUrl;
    }
    @Operation(summary = "停止点播", security = @SecurityRequirement(name = JwtUtils.HEADER))
    @Parameter(name = "deviceId", description = "设备国标编号", required = true)
    @Parameter(name = "channelId", description = "通道国标编号", required = true)
src/main/resources/application-dev.yml
@@ -32,9 +32,9 @@
        master:
          type: com.zaxxer.hikari.HikariDataSource
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://127.0.0.1:3306/wvp2?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true
          url: jdbc:mysql://51.92.65.72:3306/wvp2?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true
          username: root
          password: root123
          password: zgyw@202488
          hikari:
            connection-timeout: 20000             # 是客户端等待连接池连接的最大毫秒数
            initialSize: 50                       # 连接池初始化连接数
@@ -44,7 +44,7 @@
            max-lifetime: 1200000                 # 是池中连接关闭后的最长生命周期(以毫秒为单位)
#[可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口
server:
  port: 8080
  port: 7788
  # [可选] HTTPS配置, 默认不开启
  ssl:
    # [可选] 是否开启HTTPS访问
@@ -76,21 +76,21 @@
media:
  id: zlmediakit-local
  # [必须修改] zlm服务器的内网IP
  ip: 172.19.128.50
  ip: 51.92.65.72
  # [可选] 有公网IP就配置公网IP, 不可用域名
  wan_ip:
  # [必须修改] zlm服务器的http.port
  http-port: 9092
  http-port: 800
  # [可选] zlm服务器访问WVP所使用的IP, 默认使用127.0.0.1,zlm和wvp没有部署在同一台服务器时必须配置
  hook-ip: 172.19.128.50
  hook-ip: 51.92.65.72
  # [必选选] zlm服务器的hook.admin_params=secret
  secret: TWSYFgYJOQWB4ftgeYut8DW4wbs7pQnj
  secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc
  # 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试
  rtp:
    # [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输
    enable: true
    # [可选] 在此范围内选择端口用于媒体流传输, 必须提前在zlm上配置该属性,不然自动配置此属性可能不成功
    port-range: 50000,50300 # 端口范围
    port-range: 30000,30300 # 端口范围
    # [可选] 国标级联在此范围内选择端口发送媒体流,
    send-port-range: 50000,50300 # 端口范围
# [根据业务需求配置]
src/main/resources/application.yml
@@ -2,4 +2,4 @@
  application:
    name: wvp
  profiles:
    active: local272
    active: dev
web_src/package-lock.json
New file
Diff too large