离在线状态样式修改
修复未回复200ok导致catalog一直发送的bug
修改点播接口未收到视频后回复
12个文件已修改
259 ■■■■■ 已修改文件
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/channelList.vue 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/gb28181/devicePlayer.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/videoList.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
@@ -3,11 +3,13 @@
public class StreamInfo {
    private String ssrc;
    private String deviceID;
    private String cahnnelId;
    private String flv;
    private String WS_FLV;
    private String RTMP;
    private String HLS;
    private String RTSP;
    private String ws_flv;
    private String rtmp;
    private String hls;
    private String rtsp;
    public String getSsrc() {
        return ssrc;
@@ -25,35 +27,51 @@
        this.flv = flv;
    }
    public String getWS_FLV() {
        return WS_FLV;
    public String getWs_flv() {
        return ws_flv;
    }
    public void setWS_FLV(String WS_FLV) {
        this.WS_FLV = WS_FLV;
    public void setWs_flv(String ws_flv) {
        this.ws_flv = ws_flv;
    }
    public String getRTMP() {
        return RTMP;
    public String getRtmp() {
        return rtmp;
    }
    public void setRTMP(String RTMP) {
        this.RTMP = RTMP;
    public void setRtmp(String rtmp) {
        this.rtmp = rtmp;
    }
    public String getHLS() {
        return HLS;
    public String getHls() {
        return hls;
    }
    public void setHLS(String HLS) {
        this.HLS = HLS;
    public void setHls(String hls) {
        this.hls = hls;
    }
    public String getRTSP() {
        return RTSP;
    public String getRtsp() {
        return rtsp;
    }
    public void setRTSP(String RTSP) {
        this.RTSP = RTSP;
    public void setRtsp(String rtsp) {
        this.rtsp = rtsp;
    }
    public String getDeviceID() {
        return deviceID;
    }
    public void setDeviceID(String deviceID) {
        this.deviceID = deviceID;
    }
    public String getCahnnelId() {
        return cahnnelId;
    }
    public void setCahnnelId(String cahnnelId) {
        this.cahnnelId = cahnnelId;
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -242,14 +242,15 @@
            StreamInfo streamInfo = new StreamInfo();
            streamInfo.setSsrc(ssrc);
//            String streamId = Integer.toHexString(Integer.parseInt(streamInfo.getSsrc()));
            String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase(); // ZLM 要求大写且首位补零
            streamInfo.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId));
            streamInfo.setWS_FLV(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId));
            streamInfo.setRTMP(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getLocalIP(), mediaInfo.getRtmpPort(), streamId));
            streamInfo.setHLS(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId));
            streamInfo.setRTSP(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getLocalIP(), mediaInfo.getRtspPort(), streamId));
            storager.startPlay(device.getDeviceId(), channelId, streamInfo);
//            String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase(); // ZLM 要求大写且首位补零
//            streamInfo.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId));
//            streamInfo.setWS_FLV(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId));
//            streamInfo.setRTMP(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getLocalIP(), mediaInfo.getRtmpPort(), streamId));
//            streamInfo.setHLS(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId));
//            streamInfo.setRTSP(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getLocalIP(), mediaInfo.getRtspPort(), streamId));
            streamInfo.setCahnnelId(channelId);
            streamInfo.setDeviceID(device.getDeviceId());
            storager.startPlay(streamInfo);
            return streamInfo;
        } catch ( SipException | ParseException | InvalidArgumentException e) {
            e.printStackTrace();
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
@@ -210,8 +210,11 @@
                msg.setType(DeferredResultHolder.CALLBACK_CMD_CATALOG);
                msg.setData(device);
                deferredResultHolder.invokeResult(msg);
                // 回复200
                responseAck(evt);
            }
        } catch (DocumentException e) {
        } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
            e.printStackTrace();
        }
    }
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -1,11 +1,13 @@
package com.genersoft.iot.vmp.media.zlm;
import java.math.BigInteger;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.MediaServerConfig;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.IpUtil;
@@ -35,7 +37,8 @@
public class ZLMHttpHookListener {
    private final static Logger logger = LoggerFactory.getLogger(ZLMHttpHookListener.class);
    @Autowired
    private SIPCommander cmder;
@@ -54,7 +57,7 @@
            logger.debug("ZLM HOOK on_flow_report API调用,参数:" + json.toString());
        }
        // TODO Auto-generated method stub
        
        JSONObject ret = new JSONObject();
        ret.put("code", 0);
@@ -113,6 +116,21 @@
        if (logger.isDebugEnabled()) {
            logger.debug("ZLM HOOK on_publish API调用,参数:" + json.toString());
        }
        String app = json.getString("app");
        String streamId = json.getString("id");
//        String ssrc = String.format("%10d", Integer.parseInt(streamId, 16)); // ZLM 要求大写且首位补零
        String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));
        StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
        if ("rtp".equals(app) && streamInfo != null ) {
            MediaServerConfig mediaInfo = storager.getMediaInfo();
            streamInfo.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId));
            streamInfo.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId));
            streamInfo.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getLocalIP(), mediaInfo.getRtmpPort(), streamId));
            streamInfo.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId));
            streamInfo.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getLocalIP(), mediaInfo.getRtspPort(), streamId));
            storager.startPlay(streamInfo);
        }
        // TODO Auto-generated method stub
        
        JSONObject ret = new JSONObject();
@@ -213,8 +231,18 @@
        if (logger.isDebugEnabled()) {
            logger.debug("ZLM HOOK on_stream_changed API调用,参数:" + json.toString());
        }
        // TODO Auto-generated method stub
        // 流消失移除redis play
        String app = json.getString("app");
        String streamId = json.getString("stream");
        boolean regist = json.getBoolean("regist");
//        String ssrc = String.format("%10d", Integer.parseInt(streamId, 16)); // ZLM 要求大写且首位补零
        String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));
        StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
        if ("rtp".equals(app) && !regist ) {
            storager.stopPlay(streamInfo);
        }
        JSONObject ret = new JSONObject();
        ret.put("code", 0);
        ret.put("msg", "success");
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
@@ -136,30 +136,24 @@
    /**
     * 开始播放时将流存入
     *
     * @param deviceId 设备ID
     * @param channelId 通道ID
     * @param stream 流信息
     * @return
     */
    public boolean startPlay(String deviceId, String channelId, StreamInfo stream);
    public boolean startPlay(StreamInfo stream);
    /**
     * 停止播放时删除
     *
     * @param deviceId 设备ID
     * @param channelId 通道ID
     * @return
     */
    public boolean stopPlay(String deviceId, String channelId);
    public boolean stopPlay(StreamInfo streamInfo);
    /**
     * 查找视频流
     *
     * @param deviceId 设备ID
     * @param channelId 通道ID
     * @return
     */
    public StreamInfo queryPlay(String deviceId, String channelId);
    public StreamInfo queryPlay(StreamInfo streamInfo);
    /**
     * 查询子设备
@@ -182,4 +176,8 @@
     * @param deviceId
     */
    void cleanChannelsForDevice(String deviceId);
    StreamInfo queryPlayBySSRC(String ssrc);
    StreamInfo queryPlayByDevice(String deviceId, String code);
}
src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java
@@ -148,17 +148,12 @@
    }
    @Override
    public boolean startPlay(String deviceId, String channelId, StreamInfo stream) {
    public boolean stopPlay(StreamInfo streamInfo) {
        return false;
    }
    @Override
    public boolean stopPlay(String deviceId, String channelId) {
        return false;
    }
    @Override
    public StreamInfo queryPlay(String deviceId, String channelId) {
    public StreamInfo queryPlay(StreamInfo streamInfo) {
        return null;
    }
@@ -176,4 +171,19 @@
    public void cleanChannelsForDevice(String deviceId) {
    }
    @Override
    public boolean startPlay(StreamInfo stream) {
        return false;
    }
    @Override
    public StreamInfo queryPlayBySSRC(String ssrc) {
        return null;
    }
    @Override
    public StreamInfo queryPlayByDevice(String deviceId, String code) {
        return null;
    }
}
src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java
@@ -329,40 +329,53 @@
    /**
     * 开始播放时将流存入redis
     *
     * @param deviceId 设备ID
     * @param channelId 通道ID
     * @return
     */
    @Override
    public boolean startPlay(String deviceId, String channelId, StreamInfo stream) {
        return redis.set(String.format("%S_%s_%s", VideoManagerConstants.PLAYER_PREFIX, deviceId, channelId),
    public boolean startPlay(StreamInfo stream) {
        return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, stream.getSsrc(),stream.getDeviceID(), stream.getCahnnelId()),
                stream);
    }
    /**
     * 停止播放时从redis删除
     *
     * @param deviceId 设备ID
     * @param channelId 通道ID
     * @return
     */
    @Override
    public boolean stopPlay(String deviceId, String channelId) {
        return redis.del(String.format("%S_%s_%s", VideoManagerConstants.PLAYER_PREFIX, deviceId, channelId));
    public boolean stopPlay(StreamInfo streamInfo) {
        return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
                streamInfo.getSsrc(),
                streamInfo.getDeviceID(),
                streamInfo.getCahnnelId()));
    }
    /**
     * 查询播放列表
     * @param deviceId 设备ID
     * @param channelId 通道ID
     * @return
     */
    @Override
    public StreamInfo queryPlay(String deviceId, String channelId) {
        return (StreamInfo)redis.get(String.format("%S_%s_%s", VideoManagerConstants.PLAYER_PREFIX, deviceId, channelId));
    public StreamInfo queryPlay(StreamInfo streamInfo) {
        return (StreamInfo)redis.get(String.format("%S_%s_%s_%s",
                VideoManagerConstants.PLAYER_PREFIX,
                streamInfo.getSsrc(),
                streamInfo.getDeviceID(),
                streamInfo.getCahnnelId()));
    }
    @Override
    public StreamInfo queryPlayBySSRC(String ssrc) {
        List<Object> playLeys = redis.keys(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, ssrc));
        if (playLeys.size() == 0) return null;
        return (StreamInfo)redis.get(playLeys.get(0).toString());
    }
    @Override
    public StreamInfo queryPlayByDevice(String deviceId, String code) {
        List<Object> playLeys = redis.keys(String.format("%S_*_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
                deviceId,
                code));
        return (StreamInfo)redis.get(playLeys.get(0).toString());
    }
    /**
     * 更新流媒体信息
@@ -423,4 +436,7 @@
            }
        }
    }
}
src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
@@ -37,7 +37,18 @@
        
        Device device = storager.queryVideoDevice(deviceId);
        StreamInfo streamInfo = cmder.playStreamCmd(device, channelId);
        // 等待推流, TODO 默认超时15s
        long startTime = System.currentTimeMillis();
        while (storager.queryPlay(streamInfo) == null || storager.queryPlay(streamInfo).getFlv() == null) {
            try {
                if (System.currentTimeMillis() - startTime > 15 * 1000)
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        streamInfo = storager.queryPlay(streamInfo);
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("设备预览 API调用,deviceId:%s ,channelId:%s",deviceId, channelId));
            logger.debug("设备预览 API调用,ssrc:"+streamInfo.getSsrc()+",ZLMedia streamId:"+Integer.toHexString(Integer.parseInt(streamInfo.getSsrc())));
@@ -55,7 +66,8 @@
    public ResponseEntity<String> playStop(@PathVariable String ssrc){
        
        cmder.streamByeCmd(ssrc);
        StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
        storager.stopPlay(streamInfo);
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("设备预览停止API调用,ssrc:%s", ssrc));
        }
src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java
@@ -70,7 +70,7 @@
            return result;
        }
        // 查询是否已经在播放
        StreamInfo streamInfo = storager.queryPlay(device.getDeviceId(), code);
        StreamInfo streamInfo = storager.queryPlayByDevice(device.getDeviceId(), code);
        if (streamInfo == null) streamInfo = cmder.playStreamCmd(device, code);
        if (logger.isDebugEnabled()) {
@@ -86,10 +86,10 @@
            result.put("ChannelName", deviceChannel.getName());
            result.put("ChannelCustomName ", "");
            result.put("FLV ", streamInfo.getFlv());
            result.put("WS_FLV ", streamInfo.getWS_FLV());
            result.put("RTMP", streamInfo.getRTMP());
            result.put("HLS", streamInfo.getHLS());
            result.put("RTSP", streamInfo.getRTSP());
            result.put("WS_FLV ", streamInfo.getWs_flv());
            result.put("RTMP", streamInfo.getRtmp());
            result.put("HLS", streamInfo.getHls());
            result.put("RTSP", streamInfo.getRtsp());
            result.put("CDN", "");
            result.put("SnapURL", "");
            result.put("Transport", device.getTransport());
@@ -135,14 +135,14 @@
                             @RequestParam(required = false)String check_outputs
    ){
        StreamInfo streamInfo = storager.queryPlay(serial, code);
        StreamInfo streamInfo = storager.queryPlayByDevice(serial, code);
        if (streamInfo == null) {
            JSONObject result = new JSONObject();
            result.put("error","未找到流信息");
            return result;
        }
        cmder.streamByeCmd(streamInfo.getSsrc());
        storager.stopPlay(serial, code);
        storager.stopPlay(streamInfo);
        return null;
    }
@@ -151,7 +151,6 @@
     * @param serial 设备编号
     * @param channel 通道序号
     * @param code 通道国标编号
     * @param check_outputs
     * @return
     */
    @RequestMapping(value = "/touch")
web_src/src/components/channelList.vue
@@ -35,8 +35,16 @@
                        </el-table-column>
                        <el-table-column prop="subCount" label="子节点数">
                        </el-table-column>
                        <el-table-column prop="ptztypeText" label="云台类型">
                        </el-table-column>
          <el-table-column label="状态" width="180" align="center">
            <template slot-scope="scope">
              <div slot="reference" class="name-wrapper">
                <el-tag size="medium" v-if="scope.row.status == 1">在线</el-tag>
                <el-tag size="medium" type="info" v-if="scope.row.status == 0">离线</el-tag>
              </div>
            </template>
          </el-table-column>
            <el-table-column prop="ptztypeText" label="云台类型">
            </el-table-column>
                        <el-table-column label="操作" width="240" align="center" fixed="right">
                            <template slot-scope="scope">
                                <el-button size="mini" icon="el-icon-video-play" v-if="scope.row.parental == 0" @click="sendDevicePush(scope.row)">预览视频</el-button>
@@ -58,17 +66,20 @@
            </el-main>
        </el-container>
    <Loading v-if="isLoging" marginTop="-50%"></Loading>
    </div>
</template>
<script>
     import devicePlayer from './gb28181/devicePlayer.vue'
     import uiHeader from './UiHeader.vue'
   import Loading from './Loading.vue'
    export default {
        name: 'channelList',
        components: {
            devicePlayer,
            uiHeader
            uiHeader,
      Loading
        },
        data() {
            return {
@@ -85,7 +96,8 @@
                currentPage: parseInt(this.$route.params.page),
                count: parseInt(this.$route.params.count),
                total:0,
                beforeUrl:"/videoList"
                beforeUrl:"/videoList",
        isLoging: false
            };
        },
@@ -182,7 +194,7 @@
            //通知设备上传媒体流
            sendDevicePush: function(itemData) {
                let deviceId = this.deviceId;
        this.isLoging = true;
                let channelId = itemData.channelId;
                console.log("通知设备推流1:" + deviceId + " : " + channelId);
                let that = this;
@@ -191,6 +203,7 @@
                    url: '/api/play/' + deviceId + '/' + channelId
                }).then(function(res) {
                    let ssrc = res.data.ssrc;
          that.isLoging = false
                    that.$refs.devicePlayer.play(res.data,deviceId,channelId);
                }).catch(function(e) {
                });
web_src/src/components/gb28181/devicePlayer.vue
@@ -115,6 +115,7 @@
                deviceId: '',
                channelId: '',
                tabActiveName: 'media'
            };
        },
        methods: {
web_src/src/components/videoList.vue
@@ -1,7 +1,6 @@
<template>
    <div id="app">
        <el-container>
            <el-header>
                <uiHeader></uiHeader>
            </el-header>
@@ -37,14 +36,15 @@
                    <el-table-column label="状态" width="180" align="center">
                        <template slot-scope="scope">
                            <div slot="reference" class="name-wrapper">
                                <el-tag size="medium">{{ scope.row.online==1?'在线' :'离线'}}</el-tag>
                                <el-tag size="medium" v-if="scope.row.online == 1">在线</el-tag>
                                <el-tag size="medium" type="info" v-if="scope.row.online == 0">离线</el-tag>
                            </div>
                        </template>
                    </el-table-column>
                    <el-table-column label="操作" width="240" align="center" fixed="right">
                        <template slot-scope="scope">
                            <el-button size="mini" icon="el-icon-refresh"  @click="refDevice(scope.row)">刷新</el-button>
                            <el-button size="mini" icon="el-icon-refresh"  @click="refDevice(scope.row)">刷新通道</el-button>
                            <el-button size="mini" icon="el-icon-s-open"  type="primary" @click="showChannelList(scope.row)">查看通道</el-button>
                        </template>
                    </el-table-column>