Commit b0080159d98cd441175ddaf90a77d30b8264003d
1 parent
0188ffd1
去除ssrc作为流ID传递,ssrc只作为sdp消息使用。动态端口的情况下支持固定流地址,同时支持未点播时直接播放流地址,代码自动发起点播
Showing
17 changed files
with
117 additions
and
127 deletions
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
| ... | ... | @@ -4,7 +4,6 @@ import com.alibaba.fastjson.JSONArray; |
| 4 | 4 | |
| 5 | 5 | public class StreamInfo { |
| 6 | 6 | |
| 7 | - private String ssrc; | |
| 8 | 7 | private String streamId; |
| 9 | 8 | private String deviceID; |
| 10 | 9 | private String cahnnelId; |
| ... | ... | @@ -20,14 +19,6 @@ public class StreamInfo { |
| 20 | 19 | private String rtsp; |
| 21 | 20 | private JSONArray tracks; |
| 22 | 21 | |
| 23 | - public String getSsrc() { | |
| 24 | - return ssrc; | |
| 25 | - } | |
| 26 | - | |
| 27 | - public void setSsrc(String ssrc) { | |
| 28 | - this.ssrc = ssrc; | |
| 29 | - } | |
| 30 | - | |
| 31 | 22 | public String getDeviceID() { |
| 32 | 23 | return deviceID; |
| 33 | 24 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java
| ... | ... | @@ -141,7 +141,7 @@ public class DeviceChannel { |
| 141 | 141 | /** |
| 142 | 142 | * 流唯一编号,存在表示正在直播 |
| 143 | 143 | */ |
| 144 | - private String ssrc; | |
| 144 | + private String streamId; | |
| 145 | 145 | |
| 146 | 146 | /** |
| 147 | 147 | * 是否含有音频 |
| ... | ... | @@ -379,14 +379,6 @@ public class DeviceChannel { |
| 379 | 379 | this.subCount = subCount; |
| 380 | 380 | } |
| 381 | 381 | |
| 382 | - public String getSsrc() { | |
| 383 | - return ssrc; | |
| 384 | - } | |
| 385 | - | |
| 386 | - public void setSsrc(String ssrc) { | |
| 387 | - this.ssrc = ssrc; | |
| 388 | - } | |
| 389 | - | |
| 390 | 382 | public boolean isHasAudio() { |
| 391 | 383 | return hasAudio; |
| 392 | 384 | } |
| ... | ... | @@ -402,4 +394,12 @@ public class DeviceChannel { |
| 402 | 394 | public void setPlay(boolean play) { |
| 403 | 395 | this.play = play; |
| 404 | 396 | } |
| 397 | + | |
| 398 | + public String getStreamId() { | |
| 399 | + return streamId; | |
| 400 | + } | |
| 401 | + | |
| 402 | + public void setStreamId(String streamId) { | |
| 403 | + this.streamId = streamId; | |
| 404 | + } | |
| 405 | 405 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
| ... | ... | @@ -277,17 +277,22 @@ public class SIPCommander implements ISIPCommander { |
| 277 | 277 | try { |
| 278 | 278 | |
| 279 | 279 | String ssrc = streamSession.createPlaySsrc(); |
| 280 | + String streamId = null; | |
| 281 | + if (rtpEnable) { | |
| 282 | + streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId); | |
| 283 | + }else { | |
| 284 | + streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); | |
| 285 | + } | |
| 280 | 286 | String streamMode = device.getStreamMode().toUpperCase(); |
| 281 | 287 | MediaServerConfig mediaInfo = storager.getMediaInfo(); |
| 282 | 288 | String mediaPort = null; |
| 283 | 289 | // 使用动态udp端口 |
| 284 | 290 | if (rtpEnable) { |
| 285 | - mediaPort = zlmUtils.getNewRTPPort(ssrc) + ""; | |
| 291 | + mediaPort = zlmUtils.getNewRTPPort(streamId) + ""; | |
| 286 | 292 | }else { |
| 287 | 293 | mediaPort = mediaInfo.getRtpProxyPort(); |
| 288 | 294 | } |
| 289 | 295 | |
| 290 | - String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); | |
| 291 | 296 | // 添加订阅 |
| 292 | 297 | JSONObject subscribeKey = new JSONObject(); |
| 293 | 298 | subscribeKey.put("app", "rtp"); |
| ... | ... | @@ -330,10 +335,10 @@ public class SIPCommander implements ISIPCommander { |
| 330 | 335 | Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "live", null, ssrc); |
| 331 | 336 | |
| 332 | 337 | ClientTransaction transaction = transmitRequest(device, request); |
| 333 | - streamSession.put(ssrc, transaction); | |
| 338 | + streamSession.put(streamId, transaction); | |
| 334 | 339 | DeviceChannel deviceChannel = storager.queryChannel(device.getDeviceId(), channelId); |
| 335 | 340 | if (deviceChannel != null) { |
| 336 | - deviceChannel.setSsrc(ssrc); | |
| 341 | + deviceChannel.setStreamId(streamId); | |
| 337 | 342 | storager.updateChannel(device.getDeviceId(), deviceChannel); |
| 338 | 343 | } |
| 339 | 344 | |
| ... | ... | @@ -378,7 +383,7 @@ public class SIPCommander implements ISIPCommander { |
| 378 | 383 | String mediaPort = null; |
| 379 | 384 | // 使用动态udp端口 |
| 380 | 385 | if (rtpEnable) { |
| 381 | - mediaPort = zlmUtils.getNewRTPPort(ssrc) + ""; | |
| 386 | + mediaPort = zlmUtils.getNewRTPPort(streamId) + ""; | |
| 382 | 387 | }else { |
| 383 | 388 | mediaPort = mediaInfo.getRtpProxyPort(); |
| 384 | 389 | } |
| ... | ... | @@ -412,7 +417,7 @@ public class SIPCommander implements ISIPCommander { |
| 412 | 417 | Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "playback", null); |
| 413 | 418 | |
| 414 | 419 | ClientTransaction transaction = transmitRequest(device, request); |
| 415 | - streamSession.put(ssrc, transaction); | |
| 420 | + streamSession.put(streamId, transaction); | |
| 416 | 421 | |
| 417 | 422 | } catch ( SipException | ParseException | InvalidArgumentException e) { |
| 418 | 423 | e.printStackTrace(); |
| ... | ... | @@ -424,10 +429,10 @@ public class SIPCommander implements ISIPCommander { |
| 424 | 429 | * |
| 425 | 430 | */ |
| 426 | 431 | @Override |
| 427 | - public void streamByeCmd(String ssrc) { | |
| 432 | + public void streamByeCmd(String streamId) { | |
| 428 | 433 | |
| 429 | 434 | try { |
| 430 | - ClientTransaction transaction = streamSession.get(ssrc); | |
| 435 | + ClientTransaction transaction = streamSession.get(streamId); | |
| 431 | 436 | if (transaction == null) { |
| 432 | 437 | return; |
| 433 | 438 | } |
| ... | ... | @@ -453,7 +458,7 @@ public class SIPCommander implements ISIPCommander { |
| 453 | 458 | clientTransaction = udpSipProvider.getNewClientTransaction(byeRequest); |
| 454 | 459 | } |
| 455 | 460 | dialog.sendRequest(clientTransaction); |
| 456 | - streamSession.remove(ssrc); | |
| 461 | + streamSession.remove(streamId); | |
| 457 | 462 | } catch (TransactionDoesNotExistException e) { |
| 458 | 463 | e.printStackTrace(); |
| 459 | 464 | } catch (SipException e) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
| ... | ... | @@ -450,7 +450,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { |
| 450 | 450 | StreamInfo streamInfo = storager.queryPlaybackByDevice(deviceId, "*"); |
| 451 | 451 | if (streamInfo != null) { |
| 452 | 452 | storager.stopPlayback(streamInfo); |
| 453 | - cmder.streamByeCmd(streamInfo.getSsrc()); | |
| 453 | + cmder.streamByeCmd(streamInfo.getStreamId()); | |
| 454 | 454 | } |
| 455 | 455 | } |
| 456 | 456 | } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
| ... | ... | @@ -4,13 +4,16 @@ import java.math.BigInteger; |
| 4 | 4 | import java.text.DecimalFormat; |
| 5 | 5 | import java.util.ArrayList; |
| 6 | 6 | import java.util.List; |
| 7 | +import java.util.UUID; | |
| 7 | 8 | |
| 8 | 9 | import com.alibaba.fastjson.JSON; |
| 9 | 10 | import com.alibaba.fastjson.JSONArray; |
| 10 | 11 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 11 | 12 | import com.genersoft.iot.vmp.conf.MediaServerConfig; |
| 13 | +import com.genersoft.iot.vmp.gb28181.bean.Device; | |
| 12 | 14 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| 13 | 15 | import com.genersoft.iot.vmp.utils.IpUtil; |
| 16 | +import com.genersoft.iot.vmp.vmanager.service.IPlayService; | |
| 14 | 17 | import org.slf4j.Logger; |
| 15 | 18 | import org.slf4j.LoggerFactory; |
| 16 | 19 | import org.springframework.beans.factory.annotation.Autowired; |
| ... | ... | @@ -44,6 +47,9 @@ public class ZLMHttpHookListener { |
| 44 | 47 | private SIPCommander cmder; |
| 45 | 48 | |
| 46 | 49 | @Autowired |
| 50 | + private IPlayService playService; | |
| 51 | + | |
| 52 | + @Autowired | |
| 47 | 53 | private IVideoManagerStorager storager; |
| 48 | 54 | |
| 49 | 55 | @Autowired |
| ... | ... | @@ -52,6 +58,9 @@ public class ZLMHttpHookListener { |
| 52 | 58 | @Autowired |
| 53 | 59 | private ZLMHttpHookSubscribe subscribe; |
| 54 | 60 | |
| 61 | + @Value("${media.autoApplyPlay}") | |
| 62 | + private boolean autoApplyPlay; | |
| 63 | + | |
| 55 | 64 | @Value("${media.ip}") |
| 56 | 65 | private String mediaIp; |
| 57 | 66 | |
| ... | ... | @@ -135,34 +144,6 @@ public class ZLMHttpHookListener { |
| 135 | 144 | ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json); |
| 136 | 145 | if (subscribe != null) subscribe.response(json); |
| 137 | 146 | |
| 138 | -// if ("rtp".equals(app)) { | |
| 139 | -// String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16)); | |
| 140 | -// StreamInfo streamInfoForPlay = storager.queryPlayBySSRC(ssrc); | |
| 141 | -// if ("rtp".equals(app) && streamInfoForPlay != null ) { | |
| 142 | -// MediaServerConfig mediaInfo = storager.getMediaInfo(); | |
| 143 | -// streamInfoForPlay.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 144 | -// streamInfoForPlay.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 145 | -// streamInfoForPlay.setFmp4(String.format("http://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 146 | -// streamInfoForPlay.setWs_fmp4(String.format("ws://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 147 | -// streamInfoForPlay.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), streamId)); | |
| 148 | -// streamInfoForPlay.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 149 | -// streamInfoForPlay.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId)); | |
| 150 | -// storager.startPlay(streamInfoForPlay); | |
| 151 | -// } | |
| 152 | -// | |
| 153 | -// StreamInfo streamInfoForPlayBack = storager.queryPlaybackBySSRC(ssrc); | |
| 154 | -// if ("rtp".equals(app) && streamInfoForPlayBack != null ) { | |
| 155 | -// MediaServerConfig mediaInfo = storager.getMediaInfo(); | |
| 156 | -// streamInfoForPlayBack.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 157 | -// streamInfoForPlayBack.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 158 | -// streamInfoForPlayBack.setFmp4(String.format("http://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 159 | -// streamInfoForPlayBack.setWs_fmp4(String.format("ws://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 160 | -// streamInfoForPlayBack.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), streamId)); | |
| 161 | -// streamInfoForPlayBack.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); | |
| 162 | -// streamInfoForPlayBack.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId)); | |
| 163 | -// storager.startPlayback(streamInfoForPlayBack); | |
| 164 | -// } | |
| 165 | -// } | |
| 166 | 147 | |
| 167 | 148 | // TODO Auto-generated method stub |
| 168 | 149 | |
| ... | ... | @@ -268,14 +249,12 @@ public class ZLMHttpHookListener { |
| 268 | 249 | String app = json.getString("app"); |
| 269 | 250 | String streamId = json.getString("stream"); |
| 270 | 251 | boolean regist = json.getBoolean("regist"); |
| 271 | -// String ssrc = String.format("%10d", Integer.parseInt(streamId, 16)); // ZLM 要求大写且首位补零 | |
| 272 | - String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16)); | |
| 273 | - StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc); | |
| 252 | + StreamInfo streamInfo = storager.queryPlayByStreamId(streamId); | |
| 274 | 253 | if ("rtp".equals(app) && !regist ) { |
| 275 | 254 | if (streamInfo!=null){ |
| 276 | 255 | storager.stopPlay(streamInfo); |
| 277 | 256 | }else{ |
| 278 | - streamInfo = storager.queryPlaybackBySSRC(ssrc); | |
| 257 | + streamInfo = storager.queryPlaybackByStreamId(streamId); | |
| 279 | 258 | storager.stopPlayback(streamInfo); |
| 280 | 259 | } |
| 281 | 260 | } |
| ... | ... | @@ -299,16 +278,14 @@ public class ZLMHttpHookListener { |
| 299 | 278 | logger.debug("ZLM HOOK on_stream_none_reader API调用,参数:" + json.toString()); |
| 300 | 279 | } |
| 301 | 280 | |
| 302 | - BigInteger bigint=new BigInteger(json.getString("stream"), 16); | |
| 303 | - int numb=bigint.intValue(); | |
| 304 | - String ssrc = String.format("%010d", numb); | |
| 305 | - | |
| 306 | - cmder.streamByeCmd(ssrc); | |
| 307 | - StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc); | |
| 281 | + String streamId = json.getString("stream"); | |
| 282 | + | |
| 283 | + cmder.streamByeCmd(streamId); | |
| 284 | + StreamInfo streamInfo = storager.queryPlayByStreamId(streamId); | |
| 308 | 285 | if (streamInfo!=null){ |
| 309 | 286 | storager.stopPlay(streamInfo); |
| 310 | 287 | }else{ |
| 311 | - streamInfo = storager.queryPlaybackBySSRC(ssrc); | |
| 288 | + streamInfo = storager.queryPlaybackByStreamId(streamId); | |
| 312 | 289 | storager.stopPlayback(streamInfo); |
| 313 | 290 | } |
| 314 | 291 | |
| ... | ... | @@ -330,7 +307,30 @@ public class ZLMHttpHookListener { |
| 330 | 307 | logger.debug("ZLM HOOK on_stream_not_found API调用,参数:" + json.toString()); |
| 331 | 308 | } |
| 332 | 309 | // TODO Auto-generated method stub |
| 333 | - | |
| 310 | + | |
| 311 | + if (autoApplyPlay) { | |
| 312 | + String app = json.getString("app"); | |
| 313 | + String streamId = json.getString("stream"); | |
| 314 | + if ("rtp".equals(app) && streamId.indexOf("gb_play") > -1) { | |
| 315 | + String[] s = streamId.split("_"); | |
| 316 | + if (s.length == 4) { | |
| 317 | + String deviceId = s[2]; | |
| 318 | + String channelId = s[3]; | |
| 319 | + Device device = storager.queryVideoDevice(deviceId); | |
| 320 | + if (device != null) { | |
| 321 | + UUID uuid = UUID.randomUUID(); | |
| 322 | + cmder.playStreamCmd(device, channelId, (JSONObject response) -> { | |
| 323 | + logger.info("收到订阅消息: " + response.toJSONString()); | |
| 324 | + playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString()); | |
| 325 | + }); | |
| 326 | + } | |
| 327 | + | |
| 328 | + } | |
| 329 | + | |
| 330 | + } | |
| 331 | + | |
| 332 | + } | |
| 333 | + | |
| 334 | 334 | JSONObject ret = new JSONObject(); |
| 335 | 335 | ret.put("code", 0); |
| 336 | 336 | ret.put("msg", "success"); | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMUtils.java
| ... | ... | @@ -21,8 +21,8 @@ public class ZLMUtils { |
| 21 | 21 | |
| 22 | 22 | private int currentPort = 0; |
| 23 | 23 | |
| 24 | - public int getNewRTPPort(String ssrc) { | |
| 25 | - String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); | |
| 24 | + public int getNewRTPPort(String streamId) { | |
| 25 | +// String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); | |
| 26 | 26 | Map<String, Object> param = new HashMap<>(); |
| 27 | 27 | int newPort = getPortFromUdpPortRange(); |
| 28 | 28 | param.put("port", newPort); |
| ... | ... | @@ -32,7 +32,7 @@ public class ZLMUtils { |
| 32 | 32 | if (jsonObject != null && jsonObject.getInteger("code") == 0) { |
| 33 | 33 | return newPort; |
| 34 | 34 | } else { |
| 35 | - return getNewRTPPort(ssrc); | |
| 35 | + return getNewRTPPort(streamId); | |
| 36 | 36 | } |
| 37 | 37 | } |
| 38 | 38 | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
| ... | ... | @@ -178,7 +178,7 @@ public interface IVideoManagerStorager { |
| 178 | 178 | */ |
| 179 | 179 | void cleanChannelsForDevice(String deviceId); |
| 180 | 180 | |
| 181 | - StreamInfo queryPlayBySSRC(String ssrc); | |
| 181 | + StreamInfo queryPlayByStreamId(String streamId); | |
| 182 | 182 | |
| 183 | 183 | StreamInfo queryPlayByDevice(String deviceId, String code); |
| 184 | 184 | |
| ... | ... | @@ -190,5 +190,5 @@ public interface IVideoManagerStorager { |
| 190 | 190 | |
| 191 | 191 | StreamInfo queryPlaybackByDevice(String deviceId, String channelId); |
| 192 | 192 | |
| 193 | - StreamInfo queryPlaybackBySSRC(String ssrc); | |
| 193 | + StreamInfo queryPlaybackByStreamId(String streamId); | |
| 194 | 194 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java
| ... | ... | @@ -178,10 +178,6 @@ public class VideoManagerJdbcStoragerImpl implements IVideoManagerStorager { |
| 178 | 178 | return false; |
| 179 | 179 | } |
| 180 | 180 | |
| 181 | - @Override | |
| 182 | - public StreamInfo queryPlayBySSRC(String ssrc) { | |
| 183 | - return null; | |
| 184 | - } | |
| 185 | 181 | |
| 186 | 182 | @Override |
| 187 | 183 | public StreamInfo queryPlayByDevice(String deviceId, String code) { |
| ... | ... | @@ -210,7 +206,12 @@ public class VideoManagerJdbcStoragerImpl implements IVideoManagerStorager { |
| 210 | 206 | } |
| 211 | 207 | |
| 212 | 208 | @Override |
| 213 | - public StreamInfo queryPlaybackBySSRC(String ssrc) { | |
| 209 | + public StreamInfo queryPlayByStreamId(String streamId) { | |
| 210 | + return null; | |
| 211 | + } | |
| 212 | + | |
| 213 | + @Override | |
| 214 | + public StreamInfo queryPlaybackByStreamId(String streamId) { | |
| 214 | 215 | return null; |
| 215 | 216 | } |
| 216 | 217 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java
| ... | ... | @@ -151,7 +151,6 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager { |
| 151 | 151 | "_" + queryOnline + // 搜索是否在线 |
| 152 | 152 | "_" + queryHasSubChannel + // 搜索是否含有子节点 |
| 153 | 153 | "_" + "*"; |
| 154 | -// List<Object> deviceChannelList = redis.keys(queryStr); | |
| 155 | 154 | List<Object> deviceChannelList = redis.scan(queryStr); |
| 156 | 155 | //对查询结果排序,避免出现通道排列顺序乱序的情况 |
| 157 | 156 | Collections.sort(deviceChannelList,new Comparator<Object>(){ |
| ... | ... | @@ -169,7 +168,7 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager { |
| 169 | 168 | DeviceChannel deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(i)); |
| 170 | 169 | StreamInfo streamInfo = stringStreamInfoMap.get(deviceId + "_" + deviceChannel.getChannelId()); |
| 171 | 170 | deviceChannel.setPlay(streamInfo != null); |
| 172 | - if (streamInfo != null) deviceChannel.setSsrc(streamInfo.getSsrc()); | |
| 171 | + if (streamInfo != null) deviceChannel.setStreamId(streamInfo.getStreamId()); | |
| 173 | 172 | result.add(deviceChannel); |
| 174 | 173 | } |
| 175 | 174 | pageResult.setData(result); |
| ... | ... | @@ -384,7 +383,7 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager { |
| 384 | 383 | */ |
| 385 | 384 | @Override |
| 386 | 385 | public boolean startPlay(StreamInfo stream) { |
| 387 | - return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, stream.getSsrc(),stream.getDeviceID(), stream.getCahnnelId()), | |
| 386 | + return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, stream.getStreamId(),stream.getDeviceID(), stream.getCahnnelId()), | |
| 388 | 387 | stream); |
| 389 | 388 | } |
| 390 | 389 | |
| ... | ... | @@ -398,12 +397,12 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager { |
| 398 | 397 | if (streamInfo == null) return false; |
| 399 | 398 | DeviceChannel deviceChannel = queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId()); |
| 400 | 399 | if (deviceChannel != null) { |
| 401 | - deviceChannel.setSsrc(null); | |
| 400 | + deviceChannel.setStreamId(null); | |
| 402 | 401 | deviceChannel.setPlay(false); |
| 403 | 402 | updateChannel(streamInfo.getDeviceID(), deviceChannel); |
| 404 | 403 | } |
| 405 | 404 | return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, |
| 406 | - streamInfo.getSsrc(), | |
| 405 | + streamInfo.getStreamId(), | |
| 407 | 406 | streamInfo.getDeviceID(), |
| 408 | 407 | streamInfo.getCahnnelId())); |
| 409 | 408 | } |
| ... | ... | @@ -416,22 +415,20 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager { |
| 416 | 415 | public StreamInfo queryPlay(StreamInfo streamInfo) { |
| 417 | 416 | return (StreamInfo)redis.get(String.format("%S_%s_%s_%s", |
| 418 | 417 | VideoManagerConstants.PLAYER_PREFIX, |
| 419 | - streamInfo.getSsrc(), | |
| 418 | + streamInfo.getStreamId(), | |
| 420 | 419 | streamInfo.getDeviceID(), |
| 421 | 420 | streamInfo.getCahnnelId())); |
| 422 | 421 | } |
| 423 | 422 | @Override |
| 424 | - public StreamInfo queryPlayBySSRC(String ssrc) { | |
| 425 | -// List<Object> playLeys = redis.keys(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, ssrc)); | |
| 426 | - List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, ssrc)); | |
| 423 | + public StreamInfo queryPlayByStreamId(String steamId) { | |
| 424 | + List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, steamId)); | |
| 427 | 425 | if (playLeys == null || playLeys.size() == 0) return null; |
| 428 | 426 | return (StreamInfo)redis.get(playLeys.get(0).toString()); |
| 429 | 427 | } |
| 430 | 428 | |
| 431 | 429 | @Override |
| 432 | - public StreamInfo queryPlaybackBySSRC(String ssrc) { | |
| 433 | -// List<Object> playLeys = redis.keys(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, ssrc)); | |
| 434 | - List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAY_BLACK_PREFIX, ssrc)); | |
| 430 | + public StreamInfo queryPlaybackByStreamId(String steamId) { | |
| 431 | + List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAY_BLACK_PREFIX, steamId)); | |
| 435 | 432 | if (playLeys == null || playLeys.size() == 0) return null; |
| 436 | 433 | return (StreamInfo)redis.get(playLeys.get(0).toString()); |
| 437 | 434 | } |
| ... | ... | @@ -526,7 +523,7 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager { |
| 526 | 523 | |
| 527 | 524 | @Override |
| 528 | 525 | public boolean startPlayback(StreamInfo stream) { |
| 529 | - return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, stream.getSsrc(),stream.getDeviceID(), stream.getCahnnelId()), | |
| 526 | + return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, stream.getStreamId(),stream.getDeviceID(), stream.getCahnnelId()), | |
| 530 | 527 | stream); |
| 531 | 528 | } |
| 532 | 529 | |
| ... | ... | @@ -536,12 +533,12 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager { |
| 536 | 533 | if (streamInfo == null) return false; |
| 537 | 534 | DeviceChannel deviceChannel = queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId()); |
| 538 | 535 | if (deviceChannel != null) { |
| 539 | - deviceChannel.setSsrc(null); | |
| 536 | + deviceChannel.setStreamId(null); | |
| 540 | 537 | deviceChannel.setPlay(false); |
| 541 | 538 | updateChannel(streamInfo.getDeviceID(), deviceChannel); |
| 542 | 539 | } |
| 543 | 540 | return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, |
| 544 | - streamInfo.getSsrc(), | |
| 541 | + streamInfo.getStreamId(), | |
| 545 | 542 | streamInfo.getDeviceID(), |
| 546 | 543 | streamInfo.getCahnnelId())); |
| 547 | 544 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
| ... | ... | @@ -80,7 +80,7 @@ public class PlayController { |
| 80 | 80 | playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString()); |
| 81 | 81 | }); |
| 82 | 82 | } else { |
| 83 | - String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase(); | |
| 83 | + String streamId = streamInfo.getStreamId(); | |
| 84 | 84 | JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId); |
| 85 | 85 | if (rtpInfo.getBoolean("exist")) { |
| 86 | 86 | RequestMessage msg = new RequestMessage(); |
| ... | ... | @@ -99,21 +99,21 @@ public class PlayController { |
| 99 | 99 | return result; |
| 100 | 100 | } |
| 101 | 101 | |
| 102 | - @PostMapping("/play/{ssrc}/stop") | |
| 103 | - public ResponseEntity<String> playStop(@PathVariable String ssrc) { | |
| 102 | + @PostMapping("/play/{streamId}/stop") | |
| 103 | + public ResponseEntity<String> playStop(@PathVariable String streamId) { | |
| 104 | 104 | |
| 105 | - cmder.streamByeCmd(ssrc); | |
| 106 | - StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc); | |
| 105 | + cmder.streamByeCmd(streamId); | |
| 106 | + StreamInfo streamInfo = storager.queryPlayByStreamId(streamId); | |
| 107 | 107 | if (streamInfo == null) |
| 108 | - return new ResponseEntity<String>("ssrc not found", HttpStatus.OK); | |
| 108 | + return new ResponseEntity<String>("streamId not found", HttpStatus.OK); | |
| 109 | 109 | storager.stopPlay(streamInfo); |
| 110 | 110 | if (logger.isDebugEnabled()) { |
| 111 | - logger.debug(String.format("设备预览停止API调用,ssrc:%s", ssrc)); | |
| 111 | + logger.debug(String.format("设备预览停止API调用,streamId:%s", streamId)); | |
| 112 | 112 | } |
| 113 | 113 | |
| 114 | - if (ssrc != null) { | |
| 114 | + if (streamId != null) { | |
| 115 | 115 | JSONObject json = new JSONObject(); |
| 116 | - json.put("ssrc", ssrc); | |
| 116 | + json.put("streamId", streamId); | |
| 117 | 117 | return new ResponseEntity<String>(json.toString(), HttpStatus.OK); |
| 118 | 118 | } else { |
| 119 | 119 | logger.warn("设备预览停止API调用失败!"); |
| ... | ... | @@ -123,17 +123,16 @@ public class PlayController { |
| 123 | 123 | |
| 124 | 124 | /** |
| 125 | 125 | * 将不是h264的视频通过ffmpeg 转码为h264 + aac |
| 126 | - * @param ssrc | |
| 126 | + * @param streamId 流ID | |
| 127 | 127 | * @return |
| 128 | 128 | */ |
| 129 | - @PostMapping("/play/{ssrc}/convert") | |
| 130 | - public ResponseEntity<String> playConvert(@PathVariable String ssrc) { | |
| 131 | - StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc); | |
| 129 | + @PostMapping("/play/{streamId}/convert") | |
| 130 | + public ResponseEntity<String> playConvert(@PathVariable String streamId) { | |
| 131 | + StreamInfo streamInfo = storager.queryPlayByStreamId(streamId); | |
| 132 | 132 | if (streamInfo == null) { |
| 133 | 133 | logger.warn("视频转码API调用失败!, 视频流已经停止!"); |
| 134 | 134 | return new ResponseEntity<String>("未找到视频流信息, 视频流可能已经停止", HttpStatus.OK); |
| 135 | 135 | } |
| 136 | - String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); | |
| 137 | 136 | JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId); |
| 138 | 137 | if (!rtpInfo.getBoolean("exist")) { |
| 139 | 138 | logger.warn("视频转码API调用失败!, 视频流已停止推流!"); | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java
| ... | ... | @@ -72,7 +72,7 @@ public class PlaybackController { |
| 72 | 72 | StreamInfo streamInfo = storager.queryPlaybackByDevice(deviceId, channelId); |
| 73 | 73 | if (streamInfo != null) { |
| 74 | 74 | // 停止之前的回放 |
| 75 | - cmder.streamByeCmd(streamInfo.getSsrc()); | |
| 75 | + cmder.streamByeCmd(streamInfo.getStreamId()); | |
| 76 | 76 | } |
| 77 | 77 | resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result); |
| 78 | 78 | cmder.playbackStreamCmd(device, channelId, startTime, endTime, (JSONObject response) -> { | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java
| ... | ... | @@ -61,9 +61,7 @@ public class PlayServiceImpl implements IPlayService { |
| 61 | 61 | |
| 62 | 62 | public StreamInfo onPublishHandler(JSONObject resonse, String deviceId, String channelId, String uuid) { |
| 63 | 63 | String streamId = resonse.getString("id"); |
| 64 | - String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16)); | |
| 65 | 64 | StreamInfo streamInfo = new StreamInfo(); |
| 66 | - streamInfo.setSsrc(ssrc); | |
| 67 | 65 | streamInfo.setStreamId(streamId); |
| 68 | 66 | streamInfo.setDeviceID(deviceId); |
| 69 | 67 | streamInfo.setCahnnelId(channelId); | ... | ... |
src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java
| ... | ... | @@ -159,7 +159,7 @@ public class ApiDeviceController { |
| 159 | 159 | deviceJOSNChannel.put("PTZType ", deviceChannel.getPTZType()); // 云台类型, 0 - 未知, 1 - 球机, 2 - 半球, |
| 160 | 160 | // 3 - 固定枪机, 4 - 遥控枪机 |
| 161 | 161 | deviceJOSNChannel.put("CustomPTZType", ""); |
| 162 | - deviceJOSNChannel.put("StreamID", deviceChannel.getSsrc()); // StreamID 直播流ID, 有值表示正在直播 | |
| 162 | + deviceJOSNChannel.put("StreamID", deviceChannel.getStreamId()); // StreamID 直播流ID, 有值表示正在直播 | |
| 163 | 163 | deviceJOSNChannel.put("NumOutputs ", -1); // 直播在线人数 |
| 164 | 164 | channleJSONList.add(deviceJOSNChannel); |
| 165 | 165 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java
| ... | ... | @@ -96,12 +96,12 @@ public class ApiStreamController { |
| 96 | 96 | // streamInfo = cmder.playStreamCmd(device, code); |
| 97 | 97 | }else { |
| 98 | 98 | logger.debug("streamInfo 不等于null, 向流媒体查询是否正在推流"); |
| 99 | - String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase(); | |
| 99 | + String streamId = streamInfo.getStreamId(); | |
| 100 | 100 | JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId); |
| 101 | 101 | if (rtpInfo.getBoolean("exist")) { |
| 102 | 102 | logger.debug("向流媒体查询正在推流, 直接返回: " + streamInfo.getRtsp()); |
| 103 | 103 | JSONObject result = new JSONObject(); |
| 104 | - result.put("StreamID", streamInfo.getSsrc()); | |
| 104 | + result.put("StreamID", streamInfo.getStreamId()); | |
| 105 | 105 | result.put("DeviceID", device.getDeviceId()); |
| 106 | 106 | result.put("ChannelID", code); |
| 107 | 107 | result.put("ChannelName", deviceChannel.getName()); |
| ... | ... | @@ -141,7 +141,7 @@ public class ApiStreamController { |
| 141 | 141 | |
| 142 | 142 | if (logger.isDebugEnabled()) { |
| 143 | 143 | logger.debug(String.format("设备预览 API调用,deviceId:%s ,channelId:%s",serial, code)); |
| 144 | - logger.debug("设备预览 API调用,ssrc:"+streamInfo.getSsrc()+",ZLMedia streamId:"+Integer.toHexString(Integer.parseInt(streamInfo.getSsrc()))); | |
| 144 | + logger.debug("设备预览 API调用,streamId:"+streamInfo.getStreamId()); | |
| 145 | 145 | } |
| 146 | 146 | boolean lockFlag = true; |
| 147 | 147 | long startTime = System.currentTimeMillis(); |
| ... | ... | @@ -173,7 +173,7 @@ public class ApiStreamController { |
| 173 | 173 | } |
| 174 | 174 | if(streamInfo!=null) { |
| 175 | 175 | JSONObject result = new JSONObject(); |
| 176 | - result.put("StreamID", streamInfo.getSsrc()); | |
| 176 | + result.put("StreamID", streamInfo.getStreamId()); | |
| 177 | 177 | result.put("DeviceID", device.getDeviceId()); |
| 178 | 178 | result.put("ChannelID", code); |
| 179 | 179 | result.put("ChannelName", deviceChannel.getName()); |
| ... | ... | @@ -234,7 +234,7 @@ public class ApiStreamController { |
| 234 | 234 | result.put("error","未找到流信息"); |
| 235 | 235 | return result; |
| 236 | 236 | } |
| 237 | - cmder.streamByeCmd(streamInfo.getSsrc()); | |
| 237 | + cmder.streamByeCmd(streamInfo.getStreamId()); | |
| 238 | 238 | storager.stopPlay(streamInfo); |
| 239 | 239 | return null; |
| 240 | 240 | } | ... | ... |
src/main/resources/application-dev.yml
| ... | ... | @@ -74,6 +74,8 @@ media: |
| 74 | 74 | # 设为false可以获得更好的兼容性,保证返回后流就可以播放, |
| 75 | 75 | # 设为true可以快速打开播放窗口,可以获得更好的体验 |
| 76 | 76 | closeWaitRTPInfo: false |
| 77 | + # [可选] 自动点播, 使用固定流地址进行播放时,如果未点播则自动进行点播 | |
| 78 | + autoApplyPlay: true | |
| 77 | 79 | # 启用udp多端口模式, 详细解释参考: https://github.com/xia-chu/ZLMediaKit/wiki/GB28181%E6%8E%A8%E6%B5%81 下的高阶使用 |
| 78 | 80 | rtp: |
| 79 | 81 | # [可选] 是否启用udp多端口模式, 开启后会在udpPortRange范围内选择端口用于媒体流传输 | ... | ... |
web_src/src/components/channelList.vue
| ... | ... | @@ -187,9 +187,9 @@ export default { |
| 187 | 187 | url: '/api/play/' + deviceId + '/' + channelId + '?getEncoding=' + getEncoding |
| 188 | 188 | }).then(function (res) { |
| 189 | 189 | console.log(res.data) |
| 190 | - let ssrc = res.data.ssrc; | |
| 190 | + let streamId = res.data.streamId; | |
| 191 | 191 | that.isLoging = false; |
| 192 | - if (!!ssrc) { | |
| 192 | + if (!!streamId) { | |
| 193 | 193 | // that.$refs.devicePlayer.play(res.data, deviceId, channelId, itemData.hasAudio); |
| 194 | 194 | that.$refs.devicePlayer.openDialog("media", deviceId, channelId, { |
| 195 | 195 | streamInfo: res.data, |
| ... | ... | @@ -212,7 +212,7 @@ export default { |
| 212 | 212 | var that = this; |
| 213 | 213 | this.$axios({ |
| 214 | 214 | method: 'post', |
| 215 | - url: '/api/play/' + itemData.ssrc + '/stop' | |
| 215 | + url: '/api/play/' + itemData.streamId + '/stop' | |
| 216 | 216 | }).then(function (res) { |
| 217 | 217 | console.log(JSON.stringify(res)); |
| 218 | 218 | that.initData(); | ... | ... |
web_src/src/components/gb28181/devicePlayer.vue
| ... | ... | @@ -158,7 +158,6 @@ export default { |
| 158 | 158 | searchHistoryResult: [] //媒体流历史记录搜索结果 |
| 159 | 159 | }, |
| 160 | 160 | showVideoDialog: false, |
| 161 | - ssrc: '', | |
| 162 | 161 | streamId: '', |
| 163 | 162 | convertKey: '', |
| 164 | 163 | deviceId: '', |
| ... | ... | @@ -210,7 +209,6 @@ export default { |
| 210 | 209 | this.tabActiveName = tab; |
| 211 | 210 | this.channelId = channelId; |
| 212 | 211 | this.deviceId = deviceId; |
| 213 | - this.ssrc = ""; | |
| 214 | 212 | this.streamId = ""; |
| 215 | 213 | this.videoUrl = "" |
| 216 | 214 | if (!!this.$refs.videoPlayer) { |
| ... | ... | @@ -238,7 +236,6 @@ export default { |
| 238 | 236 | this.hasaudio = hasAudio; |
| 239 | 237 | this.isLoging = false; |
| 240 | 238 | this.videoUrl = streamInfo.ws_flv; |
| 241 | - this.ssrc = streamInfo.ssrc; | |
| 242 | 239 | this.streamId = streamInfo.streamId; |
| 243 | 240 | this.playFromStreamInfo(false, streamInfo) |
| 244 | 241 | }, |
| ... | ... | @@ -248,7 +245,7 @@ export default { |
| 248 | 245 | this.$refs.videoPlayer.pause() |
| 249 | 246 | that.$axios({ |
| 250 | 247 | method: 'post', |
| 251 | - url: '/api/play/' + that.ssrc + '/convert' | |
| 248 | + url: '/api/play/' + that.streamId + '/convert' | |
| 252 | 249 | }).then(function (res) { |
| 253 | 250 | if (res.data.code == 0) { |
| 254 | 251 | that.convertKey = res.data.key; |
| ... | ... | @@ -368,9 +365,9 @@ export default { |
| 368 | 365 | }, |
| 369 | 366 | playRecord: function (row) { |
| 370 | 367 | let that = this; |
| 371 | - if (that.ssrc != "") { | |
| 368 | + if (that.streamId != "") { | |
| 372 | 369 | that.stopPlayRecord(function () { |
| 373 | - that.ssrc = "", | |
| 370 | + that.streamId = "", | |
| 374 | 371 | that.playRecord(row); |
| 375 | 372 | }) |
| 376 | 373 | } else { |
| ... | ... | @@ -380,7 +377,7 @@ export default { |
| 380 | 377 | row.endTime |
| 381 | 378 | }).then(function (res) { |
| 382 | 379 | var streamInfo = res.data; |
| 383 | - that.ssrc = streamInfo.ssrc; | |
| 380 | + that.streamId = streamInfo.streamId; | |
| 384 | 381 | that.videoUrl = streamInfo.ws_flv; |
| 385 | 382 | }); |
| 386 | 383 | } |
| ... | ... | @@ -390,7 +387,7 @@ export default { |
| 390 | 387 | this.videoUrl = ''; |
| 391 | 388 | this.$axios({ |
| 392 | 389 | method: 'get', |
| 393 | - url: '/api/playback/' + this.ssrc + '/stop' | |
| 390 | + url: '/api/playback/' + this.streamId + '/stop' | |
| 394 | 391 | }).then(function (res) { |
| 395 | 392 | if (callback) callback() |
| 396 | 393 | }); | ... | ... |