648540858
2021-12-04 5b0b17d7410785aef2bedb22447bd458a3713300
添加第三方服务参与的推流直接转发到国标功能
22个文件已修改
1个文件已添加
401 ■■■■ 已修改文件
sql/mysql.sql 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/UserSetup.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/bean/ThirdPartyGB.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/all-application.yml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/wvp.sqlite 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/PushVideoList.vue 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/StreamProxyList.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/platformEdit.vue 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sql/mysql.sql
@@ -173,6 +173,7 @@
    ptz            int          null,
    rtcp           int          null,
    status         bit          null,
    shareAllLiveStream         int          null,
    primary key (id, serverGBId)
);
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
@@ -55,5 +55,8 @@
    public static final String MEDIA_TRANSACTION_USED_PREFIX = "VMP_MEDIA_TRANSACTION_";
    //************************** redis 消息*********************************
    public static final String WVP_MSG_STREAM_CHANGE__PREFIX = "WVP_MSG_STREAM_CHANGE_";
    public static final String WVP_MSG_STREAM_CHANGE_PREFIX = "WVP_MSG_STREAM_CHANGE_";
    //**************************    第三方  ****************************************
    public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_";
}
src/main/java/com/genersoft/iot/vmp/conf/UserSetup.java
@@ -29,6 +29,8 @@
    private String serverId = "000000";
    private String thirdPartyGBIdReg = "[\\s\\S]*";
    private List<String> interfaceAuthenticationExcludes = new ArrayList<>();
    public Boolean getSavePositionHistory() {
@@ -114,4 +116,12 @@
    public void setServerId(String serverId) {
        this.serverId = serverId;
    }
    public String getThirdPartyGBIdReg() {
        return thirdPartyGBIdReg;
    }
    public void setThirdPartyGBIdReg(String thirdPartyGBIdReg) {
        this.thirdPartyGBIdReg = thirdPartyGBIdReg;
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java
@@ -104,6 +104,11 @@
     */
    private int channelCount;
    /**
     * 共享所有的直播流
     */
    private boolean shareAllLiveStream;
    public Integer getId() {
        return id;
    }
@@ -264,4 +269,12 @@
        this.channelCount = channelCount;
    }
    public boolean isShareAllLiveStream() {
        return shareAllLiveStream;
    }
    public void setShareAllLiveStream(boolean shareAllLiveStream) {
        this.shareAllLiveStream = shareAllLiveStream;
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
@@ -31,6 +31,7 @@
import javax.sip.message.Request;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.List;
import java.util.Vector;
/**
@@ -105,7 +106,8 @@
            if (platform != null) {
                // 查询平台下是否有该通道
                DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
                GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId);
                List<GbStream> gbStreams = storager.queryStreamInParentPlatform(requesterId, channelId);
                GbStream gbStream = gbStreams.size() > 0? gbStreams.get(0):null;
                MediaServerItem mediaServerItem = null;
                // 不是通道可能是直播流
                if (channel != null && gbStream == null ) {
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java
@@ -1,21 +1,28 @@
package com.genersoft.iot.vmp.media.zlm;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.media.zlm.dto.MediaItem;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
import com.genersoft.iot.vmp.service.IStreamPushService;
import com.genersoft.iot.vmp.service.bean.ThirdPartyGB;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.storager.dao.GbStreamMapper;
import com.genersoft.iot.vmp.storager.dao.PlatformGbStreamMapper;
import com.genersoft.iot.vmp.storager.dao.StreamPushMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Component
public class ZLMMediaListManager {
@@ -41,7 +48,13 @@
    private IStreamPushService streamPushService;
    @Autowired
    private StreamPushMapper streamPushMapper;
    @Autowired
    private ZLMHttpHookSubscribe subscribe;
    @Autowired
    private UserSetup userSetup;
    public void updateMediaList(MediaServerItem mediaServerItem) {
@@ -89,7 +102,43 @@
    }
    public void addMedia(MediaItem mediaItem) {
        storager.updateMedia(streamPushService.transform(mediaItem));
        // 查找此直播流是否存在redis预设gbId
        StreamPushItem transform = streamPushService.transform(mediaItem);
        // 从streamId取出查询关键值
        Pattern pattern = Pattern.compile(userSetup.getThirdPartyGBIdReg());
        Matcher matcher = pattern.matcher(mediaItem.getStream());// 指定要匹配的字符串
        String queryKey = null;
        if (matcher.find()) { //此处find()每次被调用后,会偏移到下一个匹配
            queryKey = matcher.group();
        }
        if (queryKey != null) {
            ThirdPartyGB thirdPartyGB = redisCatchStorage.queryMemberNoGBId(queryKey);
            if (thirdPartyGB != null && !StringUtils.isEmpty(thirdPartyGB.getNationalStandardNo())) {
                transform.setGbId(thirdPartyGB.getNationalStandardNo());
                transform.setName(thirdPartyGB.getName());
            }
        }
        storager.updateMedia(transform);
        if (!StringUtils.isEmpty(transform.getGbId())) {
            // 如果这个国标ID已经给了其他推流且流已离线,则移除其他推流
            List<GbStream> gbStreams = gbStreamMapper.selectByGBId(transform.getGbId());
            if (gbStreams.size() > 0) {
                for (GbStream gbStream : gbStreams) {
                    // 出现使用相同国标Id的视频流时,使用新流替换旧流,
                    gbStreamMapper.del(gbStream.getApp(), gbStream.getStream());
                    platformGbStreamMapper.delByAppAndStream(gbStream.getApp(), gbStream.getStream());
                    if (!gbStream.isStatus()) {
                        streamPushMapper.del(gbStream.getApp(), gbStream.getStream());
                    }
                }
            }
            if (gbStreamMapper.selectOne(transform.getApp(), transform.getStream()) != null) {
                gbStreamMapper.update(transform);
            }else {
                gbStreamMapper.add(transform);
            }
        }
    }
src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java
@@ -37,4 +37,13 @@
    StreamPushItem transform(MediaItem item);
    StreamPushItem getPush(String app, String streamId);
    /**
     * 停止一路推流
     * @param app 应用名
     * @param streamId 流ID
     * @return
     */
    boolean stop(String app, String streamId);
}
src/main/java/com/genersoft/iot/vmp/service/bean/ThirdPartyGB.java
New file
@@ -0,0 +1,23 @@
package com.genersoft.iot.vmp.service.bean;
public class ThirdPartyGB {
    private String name;
    private String nationalStandardNo;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getNationalStandardNo() {
        return nationalStandardNo;
    }
    public void setNationalStandardNo(String nationalStandardNo) {
        this.nationalStandardNo = nationalStandardNo;
    }
}
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
@@ -79,44 +79,38 @@
        StringBuffer result = new StringBuffer();
        boolean streamLive = false;
        param.setMediaServerId(mediaInfo.getId());
        boolean saveResult;
        // 更新
        if (videoManagerStorager.queryStreamProxy(param.getApp(), param.getStream()) != null) {
            if (videoManagerStorager.updateStreamProxy(param)) {
                result.append("保存成功");
                if (param.isEnable()){
                    JSONObject jsonObject = addStreamProxyToZlm(param);
                    if (jsonObject == null) {
                        result.append(", 但是启用失败,请检查流地址是否可用");
                        param.setEnable(false);
                        videoManagerStorager.updateStreamProxy(param);
                    }else {
                        StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(
                                mediaInfo, param.getApp(), param.getStream(), null);
                        wvpResult.setData(streamInfo);
                    }
                }
            }
            saveResult = videoManagerStorager.updateStreamProxy(param);
        }else { // 新增
            if (videoManagerStorager.addStreamProxy(param)){
                result.append("保存成功");
                streamLive = true;
                if (param.isEnable()) {
                    JSONObject jsonObject = addStreamProxyToZlm(param);
                    if (jsonObject == null) {
                        streamLive = false;
                        result.append(", 但是启用失败,请检查流地址是否可用");
                        param.setEnable(false);
                        videoManagerStorager.updateStreamProxy(param);
                    }else {
            saveResult = videoManagerStorager.addStreamProxy(param);
        }
        if (saveResult) {
            result.append("保存成功");
            if (param.isEnable()) {
                JSONObject jsonObject = addStreamProxyToZlm(param);
                if (jsonObject == null) {
                    streamLive = false;
                    result.append(", 但是启用失败,请检查流地址是否可用");
                    param.setEnable(false);
                    videoManagerStorager.updateStreamProxy(param);
                }else {
                    Integer code = jsonObject.getInteger("code");
                    if (code == 0) {
                        StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(
                                mediaInfo, param.getApp(), param.getStream(), null);
                        wvpResult.setData(streamInfo);
                    }else {
                        result.append(", 但是启用失败,请检查流地址是否可用");
                        param.setEnable(false);
                        videoManagerStorager.updateStreamProxy(param);
                    }
                }
            }else {
                result.append("保存失败");
            }
                }
            }
        }else {
            result.append("保存失败");
        }
        if (param.getPlatformGbId() != null && streamLive) {
            List<GbStream> gbStreams = new ArrayList<>();
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java
@@ -12,6 +12,7 @@
import com.genersoft.iot.vmp.service.IStreamPushService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.dao.GbStreamMapper;
import com.genersoft.iot.vmp.storager.dao.PlatformGbStreamMapper;
import com.genersoft.iot.vmp.storager.dao.StreamPushMapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
@@ -31,6 +32,9 @@
    @Autowired
    private StreamPushMapper streamPushMapper;
    @Autowired
    private PlatformGbStreamMapper platformGbStreamMapper;
    @Autowired
    private ZLMRESTfulUtils zlmresTfulUtils;
@@ -116,4 +120,18 @@
        return streamPushMapper.selectOne(app, streamId);
    }
    @Override
    public boolean stop(String app, String streamId) {
        StreamPushItem streamPushItem = streamPushMapper.selectOne(app, streamId);
        int delStream = streamPushMapper.del(app, streamId);
        gbStreamMapper.del(app, streamId);
        platformGbStreamMapper.delByAppAndStream(app, streamId);
        if (delStream > 0) {
            MediaServerItem mediaServerItem = mediaServerService.getOne(streamPushItem.getMediaServerId());
            zlmresTfulUtils.closeStreams(mediaServerItem,app, streamId);
        }
        return true;
    }
}
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
@@ -6,6 +6,7 @@
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.bean.ThirdPartyGB;
import java.util.List;
import java.util.Map;
@@ -152,4 +153,11 @@
    boolean startDownload(StreamInfo streamInfo);
    StreamInfo queryDownloadByStreamId(String streamId);
    /**
     * 查找第三方系统留下的国标预设值
     * @param queryKey
     * @return
     */
    ThirdPartyGB queryMemberNoGBId(String queryKey);
}
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
@@ -327,7 +327,7 @@
     * @param channelId
     * @return
     */
    GbStream queryStreamInParentPlatform(String platformId, String channelId);
    List<GbStream> queryStreamInParentPlatform(String platformId, String channelId);
    /**
     * 获取平台关联的直播流
src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java
@@ -40,10 +40,13 @@
    @Select("SELECT * FROM gb_stream WHERE app=#{app} AND stream=#{stream}")
    StreamProxyItem selectOne(String app, String stream);
    @Select("SELECT * FROM gb_stream WHERE gbId=#{gbId}")
    List<GbStream> selectByGBId(String gbId);
    @Select("SELECT gs.*, pgs.platformId FROM gb_stream gs " +
            "LEFT JOIN platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream " +
            "WHERE gs.gbId = '${gbId}' AND pgs.platformId = '${platformId}'")
    GbStream queryStreamInPlatform(String platformId, String gbId);
    List<GbStream> queryStreamInPlatform(String platformId, String gbId);
    @Select("SELECT gs.*, pgs.platformId FROM gb_stream gs " +
            "LEFT JOIN platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream " +
src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java
@@ -15,10 +15,10 @@
    @Insert("INSERT INTO parent_platform (enable, name, serverGBId, serverGBDomain, serverIP, serverPort, deviceGBId, deviceIp,  " +
            "            devicePort, username, password, expires, keepTimeout, transport, characterSet, ptz, rtcp, " +
            "            status) " +
            "            status, shareAllLiveStream) " +
            "            VALUES (${enable}, '${name}', '${serverGBId}', '${serverGBDomain}', '${serverIP}', ${serverPort}, '${deviceGBId}', '${deviceIp}', " +
            "            '${devicePort}', '${username}', '${password}', '${expires}', '${keepTimeout}', '${transport}', '${characterSet}', ${ptz}, ${rtcp}, " +
            "            ${status})")
            "            ${status}, ${shareAllLiveStream})")
    int addParentPlatform(ParentPlatform parentPlatform);
    @Update("UPDATE parent_platform " +
@@ -39,7 +39,8 @@
            "characterSet=#{characterSet}, " +
            "ptz=#{ptz}, " +
            "rtcp=#{rtcp}, " +
            "status=#{status} " +
            "status=#{status}, " +
            "shareAllLiveStream=#{shareAllLiveStream} " +
            "WHERE id=#{id}")
    int updateParentPlatform(ParentPlatform parentPlatform);
@@ -70,4 +71,7 @@
    @Update("UPDATE parent_platform SET status=#{online} WHERE serverGBId=#{platformGbID}" )
    int updateParentPlatformStatus(String platformGbID, boolean online);
    @Select("SELECT * FROM parent_platform WHERE shareAllLiveStream=true")
    List<ParentPlatform> selectAllAhareAllLiveStream();
}
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java
@@ -24,4 +24,7 @@
    @Select("SELECT * FROM platform_gb_stream WHERE app=#{app} AND stream=#{stream}")
    List<StreamProxyItem> selectByAppAndStream(String app, String stream);
    @Select("SELECT * FROM platform_gb_stream WHERE app=#{app} AND stream=#{stream} AND platformId=#{serverGBId}")
    StreamProxyItem selectOne(String app, String stream, String serverGBId);
}
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
@@ -6,6 +6,7 @@
import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.bean.ThirdPartyGB;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
@@ -13,6 +14,7 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.text.SimpleDateFormat;
import java.util.*;
@@ -324,7 +326,7 @@
    @Override
    public void sendStreamChangeMsg(String type, JSONObject jsonObject) {
        String key = VideoManagerConstants.WVP_MSG_STREAM_CHANGE__PREFIX + type;
        String key = VideoManagerConstants.WVP_MSG_STREAM_CHANGE_PREFIX + type;
        logger.debug("[redis 流变化事件] {}: {}", key, jsonObject.toString());
        redis.convertAndSend(key, jsonObject);
    }
@@ -350,4 +352,11 @@
        if (playLeys == null || playLeys.size() == 0) return null;
        return (StreamInfo)redis.get(playLeys.get(0).toString());
    }
    @Override
    public ThirdPartyGB queryMemberNoGBId(String queryKey) {
        String key = VideoManagerConstants.WVP_STREAM_GB_ID_PREFIX + queryKey;
        JSONObject jsonObject = (JSONObject)redis.get(key);
        return  JSONObject.toJavaObject(jsonObject, ThirdPartyGB.class);
    }
}
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
@@ -5,6 +5,7 @@
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
import com.genersoft.iot.vmp.service.IGbStreamService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.storager.dao.*;
@@ -19,6 +20,7 @@
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -69,6 +71,16 @@
    @Autowired
    private GbStreamMapper gbStreamMapper;
;
    @Autowired
    private PlatformGbStreamMapper platformGbStreamMapper;
    @Autowired
    private IGbStreamService gbStreamService;
    @Autowired
    private ParentPlatformMapper parentPlatformMapper;
    @Autowired
    private VideoStreamSessionManager streamSession;
@@ -356,6 +368,15 @@
        // 更新缓存
        parentPlatformCatch.setParentPlatform(parentPlatform);
        redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
        // 共享所有视频流,需要将现有视频流添加到此平台
        List<GbStream> gbStreams = gbStreamMapper.selectAll();
        if (gbStreams.size() > 0) {
            if (parentPlatform.isShareAllLiveStream()) {
                gbStreamService.addPlatformInfo(gbStreams, parentPlatform.getServerGBId());
            }else {
                gbStreamService.delPlatformInfo(gbStreams);
            }
        }
        return result > 0;
    }
@@ -561,7 +582,7 @@
     * @return
     */
    @Override
    public GbStream queryStreamInParentPlatform(String platformId, String gbId) {
    public List<GbStream> queryStreamInParentPlatform(String platformId, String gbId) {
        return gbStreamMapper.queryStreamInPlatform(platformId, gbId);
    }
@@ -602,6 +623,22 @@
        streamPushMapper.del(streamPushItem.getApp(), streamPushItem.getStream());
        streamPushMapper.add(streamPushItem);
        gbStreamMapper.setStatus(streamPushItem.getApp(), streamPushItem.getStream(), true);
        if(!StringUtils.isEmpty(streamPushItem.getGbId() )){
            // 查找开启了全部直播流共享的上级平台
            List<ParentPlatform> parentPlatforms = parentPlatformMapper.selectAllAhareAllLiveStream();
            if (parentPlatforms.size() > 0) {
                for (ParentPlatform parentPlatform : parentPlatforms) {
                    streamPushItem.setPlatformId(parentPlatform.getServerGBId());
                    String stream = streamPushItem.getStream();
                    StreamProxyItem streamProxyItems = platformGbStreamMapper.selectOne(streamPushItem.getApp(), stream, parentPlatform.getServerGBId());
                    if (streamProxyItems == null) {
                        platformGbStreamMapper.add(streamPushItem);
                    }
                }
            }
        }
    }
    @Override
src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java
@@ -3,6 +3,7 @@
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
import com.genersoft.iot.vmp.service.IStreamPushService;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.github.pagehelper.PageInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
@@ -71,4 +72,21 @@
            return "fail";
        }
    }
    @ApiOperation("中止一个推流")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "app", value = "应用名", required = true, dataTypeClass = String.class),
            @ApiImplicitParam(name = "streamId", value = "流ID", required = true, dataTypeClass = String.class),
    })
    @PostMapping(value = "/stop")
    @ResponseBody
    public Object removeFormGB(@RequestParam(required = true)String app, @RequestParam(required = true)String streamId){
        if (streamPushService.stop(app, streamId)){
            return "success";
        }else {
            return "fail";
        }
    }
}
src/main/resources/all-application.yml
@@ -160,6 +160,8 @@
    record-push-live: true
    # 是否将日志存储进数据库
    logInDatebase: true
    # 第三方匹配,用于从stream钟获取有效信息
    thirdPartyGBIdReg: [\s\S]*
# 在线文档: swagger-ui(生产环境建议关闭)
swagger-ui:
src/main/resources/wvp.sqlite
Binary files differ
web_src/src/components/PushVideoList.vue
@@ -36,7 +36,7 @@
                        <template slot-scope="scope">
                            <el-button-group>
                                <el-button size="mini" icon="el-icon-video-play" @click="playPuhsh(scope.row)">播放</el-button>
                                <el-button size="mini" icon="el-icon-switch-button" type="danger" v-if="!!scope.row.streamId" @click="stopPuhsh(scope.row)">停止</el-button>
                                <el-button size="mini" icon="el-icon-switch-button" type="danger" @click="stopPuhsh(scope.row)">移除</el-button>
                                <el-button size="mini" icon="el-icon-position" type="primary" v-if="!!!scope.row.gbId" @click="addToGB(scope.row)">加入国标</el-button>
                                <el-button size="mini" icon="el-icon-position" type="primary" v-if="!!scope.row.gbId" @click="removeFromGB(scope.row)">移出国标</el-button>
                            </el-button-group>
@@ -151,7 +151,21 @@
                });
            },
            stopPuhsh: function(row){
                console.log(row)
        var that = this;
        that.$axios({
          method:"post",
          url:"/api/push/stop",
          params: {
            app: row.app,
            streamId: row.stream
          }
        }).then((res)=>{
          if (res.data == "success") {
            that.initData()
          }
        }).catch(function (error) {
          console.log(error);
        });
            },
            addToGB: function(row){
                this.$refs.addStreamTOGB.openDialog({app: row.app, stream: row.stream, mediaServerId: row.mediaServerId}, this.initData);
@@ -159,16 +173,16 @@
            removeFromGB: function(row){
                var that = this;
                that.$axios({
                    method:"delete",
                    url:"/api/push/remove_form_gb",
                    data:row
                }).then((res)=>{
                    if (res.data == "success") {
            method:"delete",
            url:"/api/push/remove_form_gb",
            data:row
        }).then((res)=>{
            if (res.data == "success") {
                            that.initData()
                        }
                }).catch(function (error) {
                    console.log(error);
                });
        }).catch(function (error) {
            console.log(error);
        });
            },
            dateFormat: function(/** timestamp=0 **/) {
                var ts = arguments[0] || 0;
web_src/src/components/StreamProxyList.vue
@@ -50,6 +50,7 @@
              </div>
            </template>
          </el-table-column>
          <el-table-column prop="createTime" label="创建时间" align="center" width="150" show-overflow-tooltip/>
                    <el-table-column label="转HLS" width="120" align="center">
                        <template slot-scope="scope">
                        <div slot="reference" class="name-wrapper">
web_src/src/components/dialog/platformEdit.vue
@@ -17,7 +17,7 @@
                <el-input v-model="platform.name"></el-input>
              </el-form-item>
              <el-form-item label="SIP服务国标编码" prop="serverGBId">
                <el-input v-model="platform.serverGBId" clearable></el-input>
                <el-input v-model="platform.serverGBId" clearable @input="serverGBIdChange"></el-input>
              </el-form-item>
              <el-form-item label="SIP服务国标域" prop="serverGBDomain">
                <el-input v-model="platform.serverGBDomain" clearable></el-input>
@@ -29,7 +29,7 @@
                <el-input v-model="platform.serverPort" clearable type="number"></el-input>
              </el-form-item>
              <el-form-item label="设备国标编号" prop="deviceGBId">
                <el-input v-model="platform.deviceGBId" clearable></el-input>
                <el-input v-model="platform.deviceGBId" clearable @input="deviceGBIdChange"></el-input>
              </el-form-item>
              <el-form-item label="本地IP" prop="deviceIp">
                <el-input v-model="platform.deviceIp" :disabled="true"></el-input>
@@ -76,7 +76,7 @@
              <el-form-item label="其他选项">
                <el-checkbox label="启用" v-model="platform.enable" @change="checkExpires"></el-checkbox>
                <el-checkbox label="云台控制" v-model="platform.ptz"></el-checkbox>
                <el-checkbox label="RTCP保活" v-model="platform.rtcp"></el-checkbox>
                <el-checkbox label="共享所有直播流" v-model="platform.shareAllLiveStream"></el-checkbox>
              </el-form-item>
              <el-form-item>
                <el-button type="primary" @click="onSubmit">{{
@@ -97,28 +97,6 @@
  name: "platformEdit",
  props: {},
  computed: {},
  created() {
    this.platform = {
      id: null,
      enable: true,
      ptz: true,
      rtcp: false,
      name: null,
      serverGBId: null,
      serverGBDomain: null,
      serverIP: null,
      serverPort: null,
      deviceGBId: null,
      deviceIp: null,
      devicePort: null,
      username: null,
      password: null,
      expires: 300,
      keepTimeout: 60,
      transport: "UDP",
      characterSet: "GB2312",
    }
  },
  data() {
    var deviceGBIdRules = async (rule, value, callback) => {
      console.log(value);
@@ -158,6 +136,7 @@
        keepTimeout: 60,
        transport: "UDP",
        characterSet: "GB2312",
        shareAllLiveStream: false,
      },
      rules: {
        name: [{ required: true, message: "请输入平台名称", trigger: "blur" }],
@@ -198,11 +177,38 @@
          console.log(error);
        });
      }else {
        this.platform = platform;
        this.platform.id = platform.id;
        this.platform.enable = platform.enable;
        this.platform.ptz = platform.ptz;
        this.platform.rtcp = platform.rtcp;
        this.platform.name = platform.name;
        this.platform.serverGBId = platform.serverGBId;
        this.platform.serverGBDomain = platform.serverGBDomain;
        this.platform.serverIP = platform.serverIP;
        this.platform.serverPort = platform.serverPort;
        this.platform.deviceGBId = platform.deviceGBId;
        this.platform.deviceIp = platform.deviceIp;
        this.platform.devicePort = platform.devicePort;
        this.platform.username = platform.username;
        this.platform.password = platform.password;
        this.platform.expires = platform.expires;
        this.platform.keepTimeout = platform.keepTimeout;
        this.platform.transport = platform.transport;
        this.platform.characterSet = platform.characterSet;
        this.platform.shareAllLiveStream = platform.shareAllLiveStream;
        this.onSubmit_text = "保存";
      }
      this.showDialog = true;
      this.listChangeCallback = callback;
    },
    serverGBIdChange: function () {
      if (this.platform.serverGBId.length > 10) {
        this.platform.serverGBDomain = this.platform.serverGBId.substr(0, 10);
      }
    },
    deviceGBIdChange: function () {
      this.platform.username = this.platform.deviceGBId ;
    },
    onSubmit: function () {
      console.log("onSubmit");
@@ -228,10 +234,30 @@
        });
    },
    close: function () {
      console.log("关闭添加视频平台");
      this.showDialog = false;
      this.$refs.platform1.resetFields();
      this.$refs.platform2.resetFields();
      this.platform = {
        id: null,
        enable: true,
        ptz: true,
        rtcp: false,
        name: null,
        serverGBId: null,
        serverGBDomain: null,
        serverIP: null,
        serverPort: null,
        deviceGBId: null,
        deviceIp: null,
        devicePort: null,
        username: null,
        password: null,
        expires: 300,
        keepTimeout: 60,
        transport: "UDP",
        characterSet: "GB2312",
        shareAllLiveStream: false,
      }
    },
    deviceGBIdExit: async function (deviceGbId) {
      var result = false;