src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/resources/application.yml | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
web_src/src/components/channelList.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
web_src/src/components/gb28181/devicePlayer.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java
@@ -148,6 +148,11 @@ */ private boolean hasAudio; /** * 是否正在播放 */ private boolean play; public String getChannelId() { return channelId; } @@ -388,4 +393,12 @@ public void setHasAudio(boolean hasAudio) { this.hasAudio = hasAudio; } public boolean isPlay() { return play; } public void setPlay(boolean play) { this.play = play; } } src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
@@ -38,6 +38,9 @@ @Value("${media.secret}") private String mediaSecret; @Value("${media.streamNoneReaderDelayMS}") private String streamNoneReaderDelayMS; @Value("${sip.ip}") private String sipIP; @@ -54,9 +57,10 @@ MediaServerConfig mediaServerConfig = getMediaServerConfig(); if (mediaServerConfig != null) { logger.info("zlm接入成功..."); storager.updateMediaInfo(mediaServerConfig); logger.info("设置zlm..."); saveZLMConfig(); mediaServerConfig = getMediaServerConfig(); storager.updateMediaInfo(mediaServerConfig); } } @@ -79,7 +83,7 @@ } catch (InterruptedException e) { e.printStackTrace(); } getMediaServerConfig(); mediaServerConfig = getMediaServerConfig(); } return mediaServerConfig; } @@ -106,6 +110,7 @@ param.put("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrex)); param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrex)); param.put("hook.timeoutSec","20"); param.put("general.streamNoneReaderDelayMS",streamNoneReaderDelayMS); JSONObject responseJSON = zlmresTfulUtils.setServerConfig(param); src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
@@ -1,6 +1,7 @@ package com.genersoft.iot.vmp.storager; import java.util.List; import java.util.Map; import com.alibaba.fastjson.JSONObject; import com.genersoft.iot.vmp.common.PageResult; @@ -180,4 +181,6 @@ StreamInfo queryPlayBySSRC(String ssrc); StreamInfo queryPlayByDevice(String deviceId, String code); Map<String, StreamInfo> queryPlayByDeviceId(String deviceId); } src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java
@@ -1,6 +1,7 @@ package com.genersoft.iot.vmp.storager.jdbc; import java.util.List; import java.util.Map; import com.genersoft.iot.vmp.common.PageResult; import com.genersoft.iot.vmp.common.StreamInfo; @@ -186,4 +187,9 @@ public StreamInfo queryPlayByDevice(String deviceId, String code) { return null; } @Override public Map<String, StreamInfo> queryPlayByDeviceId(String deviceId) { return null; } } src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java
@@ -134,6 +134,8 @@ @Override public PageResult queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, String online, int page, int count) { // 获取到所有正在播放的流 Map<String, StreamInfo> stringStreamInfoMap = queryPlayByDeviceId(deviceId); List<DeviceChannel> result = new ArrayList<>(); PageResult pageResult = new PageResult<DeviceChannel>(); String queryContent = "*"; @@ -154,13 +156,19 @@ int maxCount = (page + 1 ) * count; if (deviceChannelList != null && deviceChannelList.size() > 0 ) { for (int i = page * count; i < (pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal() ); i++) { result.add((DeviceChannel)redis.get((String)deviceChannelList.get(i))); DeviceChannel deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(i)); StreamInfo streamInfo = stringStreamInfoMap.get(deviceId + "_" + deviceChannel.getChannelId()); deviceChannel.setPlay(streamInfo != null); if (streamInfo != null) deviceChannel.setSsrc(streamInfo.getSsrc()); result.add(deviceChannel); } pageResult.setData(result); } return pageResult; } @Override public List<DeviceChannel> queryChannelsByDeviceId(String deviceId) { @@ -231,7 +239,13 @@ @Override public DeviceChannel queryChannel(String deviceId, String channelId) { return (DeviceChannel)redis.get(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + channelId + "_"); DeviceChannel deviceChannel = null; List<Object> deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + channelId + "*"); if (deviceChannelList != null && deviceChannelList.size() > 0 ) { deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(0)); } return deviceChannel; } @@ -345,6 +359,12 @@ @Override public boolean stopPlay(StreamInfo streamInfo) { if (streamInfo == null) return false; DeviceChannel deviceChannel = queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId()); if (deviceChannel != null) { deviceChannel.setSsrc(null); deviceChannel.setPlay(false); updateChannel(streamInfo.getDeviceID(), deviceChannel); } return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, streamInfo.getSsrc(), streamInfo.getDeviceID(), @@ -366,7 +386,7 @@ @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; if (playLeys == null || playLeys.size() == 0) return null; return (StreamInfo)redis.get(playLeys.get(0).toString()); } @@ -375,6 +395,7 @@ List<Object> playLeys = redis.keys(String.format("%S_*_%s_%s", VideoManagerConstants.PLAYER_PREFIX, deviceId, code)); if (playLeys == null || playLeys.size() == 0) return null; return (StreamInfo)redis.get(playLeys.get(0).toString()); } @@ -438,6 +459,19 @@ } } @Override public Map<String, StreamInfo> queryPlayByDeviceId(String deviceId) { Map<String, StreamInfo> streamInfos = new HashMap<>(); List<Object> playLeys = redis.keys(String.format("%S_*_%S_*", VideoManagerConstants.PLAYER_PREFIX, deviceId)); if (playLeys.size() == 0) return streamInfos; for (int i = 0; i < playLeys.size(); i++) { String key = (String) playLeys.get(i); StreamInfo streamInfo = (StreamInfo)redis.get(key); streamInfos.put(streamInfo.getDeviceID() + "_" + streamInfo.getCahnnelId(), streamInfo); } return streamInfos; } } src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
@@ -41,18 +41,36 @@ public ResponseEntity<String> play(@PathVariable String deviceId,@PathVariable String channelId){ Device device = storager.queryVideoDevice(deviceId); StreamInfo streamInfo = cmder.playStreamCmd(device, channelId); StreamInfo streamInfo = storager.queryPlayByDevice(deviceId, channelId); if (streamInfo == null) { streamInfo = cmder.playStreamCmd(device, channelId); }else { String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase(); JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId); if (rtpInfo.getBoolean("exist")) { return new ResponseEntity<String>(JSON.toJSONString(streamInfo),HttpStatus.OK); }else { storager.stopPlay(streamInfo); streamInfo = cmder.playStreamCmd(device, channelId); } } String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase(); // 等待推流, TODO 默认超时15s boolean lockFlag = true; long startTime = System.currentTimeMillis(); String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase(); // 判断推流是否存在 while (lockFlag) { try { if (System.currentTimeMillis() - startTime > 15 * 1000) { storager.stopPlay(streamInfo); return new ResponseEntity<String>("timeout",HttpStatus.OK); }else { JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId); if (rtpInfo == null){ Boolean exist = rtpInfo.getBoolean("exist"); if (rtpInfo == null || !rtpInfo.getBoolean("exist") || streamInfo.getFlv() != null){ continue; }else { lockFlag = false; @@ -72,10 +90,9 @@ } } }; } Thread.sleep(200); streamInfo = storager.queryPlayByDevice(deviceId, channelId); } catch (InterruptedException e) { e.printStackTrace(); } src/main/resources/application.yml
@@ -43,4 +43,5 @@ ip: 192.168.1.20 port: 9080 secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc streamNoneReaderDelayMS: 1800000 # 无人观看多久关闭流 web_src/src/components/channelList.vue
@@ -56,7 +56,8 @@ </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> <el-button size="mini" icon="el-icon-video-play" v-if="scope.row.parental == 0" @click="sendDevicePush(scope.row)">播放</el-button> <el-button size="mini" icon="el-icon-switch-button" type="danger" v-if="scope.row.play" @click="stopDevicePush(scope.row)">停止</el-button> <el-button size="mini" icon="el-icon-s-open" type="primary" v-if="scope.row.parental == 1" @click="changeSubchannel(scope.row)">查看子目录</el-button> <!-- <el-button size="mini" @click="sendDevicePush(scope.row)">录像查询</el-button> --> </template> @@ -198,7 +199,7 @@ message: '请求成功', type: 'success' }); });; }); }, //通知设备上传媒体流 sendDevicePush: function(itemData) { @@ -212,12 +213,30 @@ method: 'get', url: '/api/play/' + deviceId + '/' + channelId }).then(function(res) { console.log(res.data) let ssrc = res.data.ssrc; that.isLoging = false that.$refs.devicePlayer.play(res.data,deviceId,channelId,itemData.hasAudio); if (!!ssrc) { that.$refs.devicePlayer.play(res.data,deviceId,channelId,itemData.hasAudio); that.initData(); }else { that.$message.error(res.data); } }).catch(function(e) { }); }, stopDevicePush: function(itemData) { console.log(itemData) var that = this; this.$axios({ method: 'post', url: '/api/play/' + itemData.ssrc + '/stop' }).then(function(res) { console.log(JSON.stringify(res)); that.initData(); }); }, showDevice: function(){ this.$router.push(this.beforeUrl).then(()=>{ this.initParam(); web_src/src/components/gb28181/devicePlayer.vue
@@ -1,6 +1,6 @@ <template> <div id="devicePlayer"> <el-dialog title="视频播放" top="0" :visible.sync="showVideoDialog" :destroy-on-close="true" @close="stop()"> <el-dialog title="视频播放" top="0" :visible.sync="showVideoDialog" :destroy-on-close="true" @close="close()"> <LivePlayer v-if="showVideoDialog" ref="videoPlayer" :videoUrl="videoUrl" :error="videoError" :hasaudio="hasaudio" fluent autoplay live ></LivePlayer> <div id="shared" style="text-align: right; margin-top: 1rem;"> <el-tabs v-model="tabActiveName"> @@ -145,24 +145,11 @@ this.showVideoDialog = true; console.log(this.ssrc); }, stop: function() { close: function() { console.log('关闭视频'); this.$refs.videoPlayer.pause(); this.videoUrl = ''; this.showVideoDialog = false; this.$axios({ method: 'post', url: '/api/play/' + this.ssrc + '/stop' }).then(function(res) { console.log(JSON.stringify(res)); }); this.$axios({ method: 'post', url: '/api/playback/' + this.ssrc + '/stop' }).then(function(res) { console.log(JSON.stringify(res)); }); }, copySharedInfo: function(data) { console.log('复制内容:' + data);