From b0080159d98cd441175ddaf90a77d30b8264003d Mon Sep 17 00:00:00 2001
From: panlinlin <648540858@qq.com>
Date: Sat, 19 Dec 2020 21:52:20 +0800
Subject: [PATCH] =?UTF-8?q?=E5=8E=BB=E9=99=A4ssrc=E4=BD=9C=E4=B8=BA?=
 =?UTF-8?q?=E6=B5=81ID=E4=BC=A0=E9=80=92=EF=BC=8Cssrc=E5=8F=AA=E4=BD=9C?=
 =?UTF-8?q?=E4=B8=BAsdp=E6=B6=88=E6=81=AF=E4=BD=BF=E7=94=A8=E3=80=82?=
 =?UTF-8?q?=E5=8A=A8=E6=80=81=E7=AB=AF=E5=8F=A3=E7=9A=84=E6=83=85=E5=86=B5?=
 =?UTF-8?q?=E4=B8=8B=E6=94=AF=E6=8C=81=E5=9B=BA=E5=AE=9A=E6=B5=81=E5=9C=B0?=
 =?UTF-8?q?=E5=9D=80=EF=BC=8C=E5=90=8C=E6=97=B6=E6=94=AF=E6=8C=81=E6=9C=AA?=
 =?UTF-8?q?=E7=82=B9=E6=92=AD=E6=97=B6=E7=9B=B4=E6=8E=A5=E6=92=AD=E6=94=BE?=
 =?UTF-8?q?=E6=B5=81=E5=9C=B0=E5=9D=80=EF=BC=8C=E4=BB=A3=E7=A0=81=E8=87=AA?=
 =?UTF-8?q?=E5=8A=A8=E5=8F=91=E8=B5=B7=E7=82=B9=E6=92=AD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../genersoft/iot/vmp/common/StreamInfo.java  |  9 ---
 .../iot/vmp/gb28181/bean/DeviceChannel.java   | 18 ++---
 .../transmit/cmd/impl/SIPCommander.java       | 23 +++---
 .../request/impl/MessageRequestProcessor.java |  2 +-
 .../vmp/media/zlm/ZLMHttpHookListener.java    | 80 +++++++++----------
 .../genersoft/iot/vmp/media/zlm/ZLMUtils.java |  6 +-
 .../vmp/storager/IVideoManagerStorager.java   |  4 +-
 .../jdbc/VideoManagerJdbcStoragerImpl.java    | 11 +--
 .../redis/VideoManagerRedisStoragerImpl.java  | 27 +++----
 .../iot/vmp/vmanager/play/PlayController.java | 27 +++----
 .../vmanager/playback/PlaybackController.java |  2 +-
 .../service/impl/PlayServiceImpl.java         |  2 -
 .../iot/vmp/web/ApiDeviceController.java      |  2 +-
 .../iot/vmp/web/ApiStreamController.java      | 10 +--
 src/main/resources/application-dev.yml        |  2 +
 web_src/src/components/channelList.vue        |  6 +-
 .../src/components/gb28181/devicePlayer.vue   | 13 ++-
 17 files changed, 117 insertions(+), 127 deletions(-)

diff --git a/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java b/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
index 53bda91ad..0fb76b936 100644
--- a/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
+++ b/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
@@ -4,7 +4,6 @@ import com.alibaba.fastjson.JSONArray;
 
 public class StreamInfo {
 
-    private String ssrc;
     private String streamId;
     private String deviceID;
     private String cahnnelId;
@@ -20,14 +19,6 @@ public class StreamInfo {
     private String rtsp;
     private JSONArray tracks;
 
-    public String getSsrc() {
-        return ssrc;
-    }
-
-    public void setSsrc(String ssrc) {
-        this.ssrc = ssrc;
-    }
-
     public String getDeviceID() {
         return deviceID;
     }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java
index 810feabdd..19e9eda93 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java
@@ -141,7 +141,7 @@ public class DeviceChannel {
 	/**
 	 * 流唯一编号,存在表示正在直播
 	 */
-	private String  ssrc;
+	private String  streamId;
 
 	/**
 	 *  是否含有音频
@@ -379,14 +379,6 @@ public class DeviceChannel {
 		this.subCount = subCount;
 	}
 
-	public String getSsrc() {
-		return ssrc;
-	}
-
-	public void setSsrc(String ssrc) {
-		this.ssrc = ssrc;
-	}
-
 	public boolean isHasAudio() {
 		return hasAudio;
 	}
@@ -402,4 +394,12 @@ public class DeviceChannel {
 	public void setPlay(boolean play) {
 		this.play = play;
 	}
+
+	public String getStreamId() {
+		return streamId;
+	}
+
+	public void setStreamId(String streamId) {
+		this.streamId = streamId;
+	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
index 3d5aaccf6..097d2b702 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -277,17 +277,22 @@ public class SIPCommander implements ISIPCommander {
 		try {
 
 			String ssrc = streamSession.createPlaySsrc();
+			String streamId = null;
+			if (rtpEnable) {
+				streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
+			}else {
+				streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
+			}
 			String streamMode = device.getStreamMode().toUpperCase();
 			MediaServerConfig mediaInfo = storager.getMediaInfo();
 			String mediaPort = null;
 			// 使用动态udp端口
 			if (rtpEnable) {
-				mediaPort = zlmUtils.getNewRTPPort(ssrc) + "";
+				mediaPort = zlmUtils.getNewRTPPort(streamId) + "";
 			}else {
 				mediaPort = mediaInfo.getRtpProxyPort();
 			}
 
-			String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
 			// 添加订阅
 			JSONObject subscribeKey = new JSONObject();
 			subscribeKey.put("app", "rtp");
@@ -330,10 +335,10 @@ public class SIPCommander implements ISIPCommander {
 			Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "live", null, ssrc);
 
 			ClientTransaction transaction = transmitRequest(device, request);
-			streamSession.put(ssrc, transaction);
+			streamSession.put(streamId, transaction);
 			DeviceChannel deviceChannel = storager.queryChannel(device.getDeviceId(), channelId);
 			if (deviceChannel != null) {
-				deviceChannel.setSsrc(ssrc);
+				deviceChannel.setStreamId(streamId);
 				storager.updateChannel(device.getDeviceId(), deviceChannel);
 			}
 
@@ -378,7 +383,7 @@ public class SIPCommander implements ISIPCommander {
 			String mediaPort = null;
 			// 使用动态udp端口
 			if (rtpEnable) {
-				mediaPort = zlmUtils.getNewRTPPort(ssrc) + "";
+				mediaPort = zlmUtils.getNewRTPPort(streamId) + "";
 			}else {
 				mediaPort = mediaInfo.getRtpProxyPort();
 			}
@@ -412,7 +417,7 @@ public class SIPCommander implements ISIPCommander {
 	        Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "playback", null);
 	
 	        ClientTransaction transaction = transmitRequest(device, request);
-	        streamSession.put(ssrc, transaction);
+	        streamSession.put(streamId, transaction);
 
 		} catch ( SipException | ParseException | InvalidArgumentException e) {
 			e.printStackTrace();
@@ -424,10 +429,10 @@ public class SIPCommander implements ISIPCommander {
 	 * 
 	 */
 	@Override
-	public void streamByeCmd(String ssrc) {
+	public void streamByeCmd(String streamId) {
 		
 		try {
-			ClientTransaction transaction = streamSession.get(ssrc);
+			ClientTransaction transaction = streamSession.get(streamId);
 			if (transaction == null) {
 				return;
 			}
@@ -453,7 +458,7 @@ public class SIPCommander implements ISIPCommander {
 				clientTransaction = udpSipProvider.getNewClientTransaction(byeRequest);
 			}
 			dialog.sendRequest(clientTransaction);
-			streamSession.remove(ssrc);
+			streamSession.remove(streamId);
 		} catch (TransactionDoesNotExistException e) {
 			e.printStackTrace();
 		} catch (SipException e) {
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
index c987f5ee6..3c90e8eaf 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
@@ -450,7 +450,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
 				StreamInfo streamInfo = storager.queryPlaybackByDevice(deviceId, "*");
 				if (streamInfo != null) {
 					storager.stopPlayback(streamInfo);
-					cmder.streamByeCmd(streamInfo.getSsrc());
+					cmder.streamByeCmd(streamInfo.getStreamId());
 				}
 			}
 		} catch (ParseException | SipException | InvalidArgumentException | DocumentException e) {
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
index 99da6243f..03031f044 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -4,13 +4,16 @@ import java.math.BigInteger;
 import java.text.DecimalFormat;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.UUID;
 
 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.gb28181.bean.Device;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import com.genersoft.iot.vmp.utils.IpUtil;
+import com.genersoft.iot.vmp.vmanager.service.IPlayService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -43,6 +46,9 @@ public class ZLMHttpHookListener {
 	@Autowired
 	private SIPCommander cmder;
 
+	@Autowired
+	private IPlayService playService;
+
 	@Autowired
 	private IVideoManagerStorager storager;
 
@@ -52,6 +58,9 @@ public class ZLMHttpHookListener {
 	@Autowired
 	private ZLMHttpHookSubscribe subscribe;
 
+	@Value("${media.autoApplyPlay}")
+	private boolean autoApplyPlay;
+
 	@Value("${media.ip}")
 	private String mediaIp;
 
@@ -135,34 +144,6 @@ public class ZLMHttpHookListener {
 		ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json);
 		if (subscribe != null) subscribe.response(json);
 
-//		if ("rtp".equals(app)) {
-//			String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));
-//			StreamInfo streamInfoForPlay = storager.queryPlayBySSRC(ssrc);
-//			if ("rtp".equals(app) && streamInfoForPlay != null ) {
-//				MediaServerConfig mediaInfo = storager.getMediaInfo();
-//				streamInfoForPlay.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-//				streamInfoForPlay.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-//				streamInfoForPlay.setFmp4(String.format("http://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-//				streamInfoForPlay.setWs_fmp4(String.format("ws://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-//				streamInfoForPlay.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), streamId));
-//				streamInfoForPlay.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-//				streamInfoForPlay.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId));
-//				storager.startPlay(streamInfoForPlay);
-//			}
-//
-//			StreamInfo streamInfoForPlayBack = storager.queryPlaybackBySSRC(ssrc);
-//			if ("rtp".equals(app) && streamInfoForPlayBack != null ) {
-//				MediaServerConfig mediaInfo = storager.getMediaInfo();
-//				streamInfoForPlayBack.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-//				streamInfoForPlayBack.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-//				streamInfoForPlayBack.setFmp4(String.format("http://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-//				streamInfoForPlayBack.setWs_fmp4(String.format("ws://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-//				streamInfoForPlayBack.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), streamId));
-//				streamInfoForPlayBack.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-//				streamInfoForPlayBack.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId));
-//				storager.startPlayback(streamInfoForPlayBack);
-//			}
-//		}
 
 		// TODO Auto-generated method stub
 		
@@ -268,14 +249,12 @@ public class ZLMHttpHookListener {
 		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);
+		StreamInfo streamInfo = storager.queryPlayByStreamId(streamId);
 		if ("rtp".equals(app) && !regist ) {
 			if (streamInfo!=null){
 				storager.stopPlay(streamInfo);
 			}else{
-				streamInfo = storager.queryPlaybackBySSRC(ssrc);
+				streamInfo = storager.queryPlaybackByStreamId(streamId);
 				storager.stopPlayback(streamInfo);
 			}
 		}
@@ -299,16 +278,14 @@ public class ZLMHttpHookListener {
 			logger.debug("ZLM HOOK on_stream_none_reader API调用,参数:" + json.toString());
 		}
 		
-		BigInteger bigint=new BigInteger(json.getString("stream"), 16);
-		int numb=bigint.intValue();
-		String ssrc = String.format("%010d", numb); 
-		
-		cmder.streamByeCmd(ssrc);
-		StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
+		String streamId = json.getString("stream");
+
+		cmder.streamByeCmd(streamId);
+		StreamInfo streamInfo = storager.queryPlayByStreamId(streamId);
 		if (streamInfo!=null){
 			storager.stopPlay(streamInfo);
 		}else{
-			streamInfo = storager.queryPlaybackBySSRC(ssrc);
+			streamInfo = storager.queryPlaybackByStreamId(streamId);
 			storager.stopPlayback(streamInfo);
 		}
 		
@@ -330,7 +307,30 @@ public class ZLMHttpHookListener {
 			logger.debug("ZLM HOOK on_stream_not_found API调用,参数:" + json.toString());
 		}
 		// TODO Auto-generated method stub
-		
+
+		if (autoApplyPlay) {
+			String app = json.getString("app");
+			String streamId = json.getString("stream");
+			if ("rtp".equals(app) && streamId.indexOf("gb_play") > -1) {
+				String[] s = streamId.split("_");
+				if (s.length == 4) {
+					String deviceId = s[2];
+					String channelId = s[3];
+					Device device = storager.queryVideoDevice(deviceId);
+					if (device != null) {
+						UUID uuid = UUID.randomUUID();
+						cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
+							logger.info("收到订阅消息: " + response.toJSONString());
+							playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
+						});
+					}
+
+				}
+
+			}
+
+		}
+
 		JSONObject ret = new JSONObject();
 		ret.put("code", 0);
 		ret.put("msg", "success");
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMUtils.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMUtils.java
index 8195b6567..132e1e178 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMUtils.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMUtils.java
@@ -21,8 +21,8 @@ public class ZLMUtils {
 
     private int currentPort = 0;
 
-    public int getNewRTPPort(String ssrc) {
-        String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
+    public int getNewRTPPort(String streamId) {
+//        String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
         Map<String, Object> param = new HashMap<>();
         int newPort = getPortFromUdpPortRange();
         param.put("port", newPort);
@@ -32,7 +32,7 @@ public class ZLMUtils {
         if (jsonObject != null && jsonObject.getInteger("code") == 0) {
             return newPort;
         } else {
-            return getNewRTPPort(ssrc);
+            return getNewRTPPort(streamId);
         }
     }
 
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
index fdf4bc33f..f427e5e5e 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
@@ -178,7 +178,7 @@ public interface IVideoManagerStorager {
 	 */
 	void cleanChannelsForDevice(String deviceId);
 
-	StreamInfo queryPlayBySSRC(String ssrc);
+	StreamInfo queryPlayByStreamId(String streamId);
 
 	StreamInfo queryPlayByDevice(String deviceId, String code);
 
@@ -190,5 +190,5 @@ public interface IVideoManagerStorager {
 
 	StreamInfo queryPlaybackByDevice(String deviceId, String channelId);
 
-	StreamInfo queryPlaybackBySSRC(String ssrc);
+	StreamInfo queryPlaybackByStreamId(String streamId);
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java
index 75b9c929f..3302aa351 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java
@@ -178,10 +178,6 @@ public class VideoManagerJdbcStoragerImpl implements IVideoManagerStorager {
 		return false;
 	}
 
-	@Override
-	public StreamInfo queryPlayBySSRC(String ssrc) {
-		return null;
-	}
 
 	@Override
 	public StreamInfo queryPlayByDevice(String deviceId, String code) {
@@ -210,7 +206,12 @@ public class VideoManagerJdbcStoragerImpl implements IVideoManagerStorager {
 	}
 
 	@Override
-	public StreamInfo queryPlaybackBySSRC(String ssrc) {
+	public StreamInfo queryPlayByStreamId(String streamId) {
+		return null;
+	}
+
+	@Override
+	public StreamInfo queryPlaybackByStreamId(String streamId) {
 		return null;
 	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java
index fe7b8e680..00d41fc48 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java
@@ -151,7 +151,6 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
 				"_" + queryOnline + // 搜索是否在线
 				"_" + queryHasSubChannel + // 搜索是否含有子节点
 				"_" + "*";
-//		List<Object> deviceChannelList = redis.keys(queryStr);
 		List<Object> deviceChannelList = redis.scan(queryStr);
 		//对查询结果排序,避免出现通道排列顺序乱序的情况
 		Collections.sort(deviceChannelList,new Comparator<Object>(){
@@ -169,7 +168,7 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
 				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());
+				if (streamInfo != null) deviceChannel.setStreamId(streamInfo.getStreamId());
 				result.add(deviceChannel);
 			}
 			pageResult.setData(result);
@@ -384,7 +383,7 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
 	 */
 	@Override
 	public boolean startPlay(StreamInfo stream) {
-		return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, stream.getSsrc(),stream.getDeviceID(), stream.getCahnnelId()),
+		return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, stream.getStreamId(),stream.getDeviceID(), stream.getCahnnelId()),
 				stream);
 	}
 
@@ -398,12 +397,12 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
 		if (streamInfo == null) return false;
 		DeviceChannel deviceChannel = queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId());
 		if (deviceChannel != null) {
-			deviceChannel.setSsrc(null);
+			deviceChannel.setStreamId(null);
 			deviceChannel.setPlay(false);
 			updateChannel(streamInfo.getDeviceID(), deviceChannel);
 		}
 		return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
-				streamInfo.getSsrc(),
+				streamInfo.getStreamId(),
 				streamInfo.getDeviceID(),
 				streamInfo.getCahnnelId()));
 	}
@@ -416,22 +415,20 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
 	public StreamInfo queryPlay(StreamInfo streamInfo) {
 		return (StreamInfo)redis.get(String.format("%S_%s_%s_%s",
 				VideoManagerConstants.PLAYER_PREFIX,
-				streamInfo.getSsrc(),
+				streamInfo.getStreamId(),
 				streamInfo.getDeviceID(),
 				streamInfo.getCahnnelId()));
 	}
 	@Override
-	public StreamInfo queryPlayBySSRC(String ssrc) {
-//		List<Object> playLeys = redis.keys(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, ssrc));
-		List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, ssrc));
+	public StreamInfo queryPlayByStreamId(String steamId) {
+		List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, steamId));
 		if (playLeys == null || playLeys.size() == 0) return null;
 		return (StreamInfo)redis.get(playLeys.get(0).toString());
 	}
 
 	@Override
-	public StreamInfo queryPlaybackBySSRC(String ssrc) {
-//		List<Object> playLeys = redis.keys(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, ssrc));
-		List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAY_BLACK_PREFIX, ssrc));
+	public StreamInfo queryPlaybackByStreamId(String steamId) {
+		List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAY_BLACK_PREFIX, steamId));
 		if (playLeys == null || playLeys.size() == 0) return null;
 		return (StreamInfo)redis.get(playLeys.get(0).toString());
 	}
@@ -526,7 +523,7 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
 
 	@Override
 	public boolean startPlayback(StreamInfo stream) {
-		return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, stream.getSsrc(),stream.getDeviceID(), stream.getCahnnelId()),
+		return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, stream.getStreamId(),stream.getDeviceID(), stream.getCahnnelId()),
 				stream);
 	}
 
@@ -536,12 +533,12 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
 		if (streamInfo == null) return false;
 		DeviceChannel deviceChannel = queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId());
 		if (deviceChannel != null) {
-			deviceChannel.setSsrc(null);
+			deviceChannel.setStreamId(null);
 			deviceChannel.setPlay(false);
 			updateChannel(streamInfo.getDeviceID(), deviceChannel);
 		}
 		return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
-				streamInfo.getSsrc(),
+				streamInfo.getStreamId(),
 				streamInfo.getDeviceID(),
 				streamInfo.getCahnnelId()));
 	}
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
index e741b5af7..3da666aa7 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
@@ -80,7 +80,7 @@ public class PlayController {
 				playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
 			});
 		} else {
-			String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase();
+			String streamId = streamInfo.getStreamId();
 			JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
 			if (rtpInfo.getBoolean("exist")) {
 				RequestMessage msg = new RequestMessage();
@@ -99,21 +99,21 @@ public class PlayController {
 		return result;
 	}
 
-	@PostMapping("/play/{ssrc}/stop")
-	public ResponseEntity<String> playStop(@PathVariable String ssrc) {
+	@PostMapping("/play/{streamId}/stop")
+	public ResponseEntity<String> playStop(@PathVariable String streamId) {
 
-		cmder.streamByeCmd(ssrc);
-		StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
+		cmder.streamByeCmd(streamId);
+		StreamInfo streamInfo = storager.queryPlayByStreamId(streamId);
 		if (streamInfo == null)
-			return new ResponseEntity<String>("ssrc not found", HttpStatus.OK);
+			return new ResponseEntity<String>("streamId not found", HttpStatus.OK);
 		storager.stopPlay(streamInfo);
 		if (logger.isDebugEnabled()) {
-			logger.debug(String.format("设备预览停止API调用,ssrc:%s", ssrc));
+			logger.debug(String.format("设备预览停止API调用,streamId:%s", streamId));
 		}
 
-		if (ssrc != null) {
+		if (streamId != null) {
 			JSONObject json = new JSONObject();
-			json.put("ssrc", ssrc);
+			json.put("streamId", streamId);
 			return new ResponseEntity<String>(json.toString(), HttpStatus.OK);
 		} else {
 			logger.warn("设备预览停止API调用失败!");
@@ -123,17 +123,16 @@ public class PlayController {
 
 	/**
 	 * 将不是h264的视频通过ffmpeg 转码为h264 + aac
-	 * @param ssrc
+	 * @param streamId 流ID
 	 * @return
 	 */
-	@PostMapping("/play/{ssrc}/convert")
-	public ResponseEntity<String> playConvert(@PathVariable String ssrc) {
-		StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
+	@PostMapping("/play/{streamId}/convert")
+	public ResponseEntity<String> playConvert(@PathVariable String streamId) {
+		StreamInfo streamInfo = storager.queryPlayByStreamId(streamId);
 		if (streamInfo == null) {
 			logger.warn("视频转码API调用失败!, 视频流已经停止!");
 			return new ResponseEntity<String>("未找到视频流信息, 视频流可能已经停止", HttpStatus.OK);
 		}
-		String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
 		JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
 		if (!rtpInfo.getBoolean("exist")) {
 			logger.warn("视频转码API调用失败!, 视频流已停止推流!");
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java
index 2e32b1bbd..5fbaabfe1 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java
@@ -72,7 +72,7 @@ public class PlaybackController {
 		StreamInfo streamInfo = storager.queryPlaybackByDevice(deviceId, channelId);
 		if (streamInfo != null) {
 			// 停止之前的回放
-			cmder.streamByeCmd(streamInfo.getSsrc());
+			cmder.streamByeCmd(streamInfo.getStreamId());
 		}
 		resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result);
 		cmder.playbackStreamCmd(device, channelId, startTime, endTime, (JSONObject response) -> {
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java
index e9528d1db..2800882a4 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java
@@ -61,9 +61,7 @@ public class PlayServiceImpl implements IPlayService {
 
     public StreamInfo onPublishHandler(JSONObject resonse, String deviceId, String channelId, String uuid) {
         String streamId = resonse.getString("id");
-        String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));
         StreamInfo streamInfo = new StreamInfo();
-        streamInfo.setSsrc(ssrc);
         streamInfo.setStreamId(streamId);
         streamInfo.setDeviceID(deviceId);
         streamInfo.setCahnnelId(channelId);
diff --git a/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java b/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java
index ce3b7ec84..fdb677814 100644
--- a/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java
+++ b/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java
@@ -159,7 +159,7 @@ public class ApiDeviceController {
             deviceJOSNChannel.put("PTZType ", deviceChannel.getPTZType()); // 云台类型, 0 - 未知, 1 - 球机, 2 - 半球,
                                                                             //   3 - 固定枪机, 4 - 遥控枪机
             deviceJOSNChannel.put("CustomPTZType", "");
-            deviceJOSNChannel.put("StreamID", deviceChannel.getSsrc()); // StreamID 直播流ID, 有值表示正在直播
+            deviceJOSNChannel.put("StreamID", deviceChannel.getStreamId()); // StreamID 直播流ID, 有值表示正在直播
             deviceJOSNChannel.put("NumOutputs ", -1); // 直播在线人数
             channleJSONList.add(deviceJOSNChannel);
         }
diff --git a/src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java b/src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java
index 6180fbb68..b3fc2473f 100644
--- a/src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java
+++ b/src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java
@@ -96,12 +96,12 @@ public class ApiStreamController {
 //            streamInfo = cmder.playStreamCmd(device, code);
         }else {
             logger.debug("streamInfo 不等于null, 向流媒体查询是否正在推流");
-            String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase();
+            String streamId = streamInfo.getStreamId();
             JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
             if (rtpInfo.getBoolean("exist")) {
                 logger.debug("向流媒体查询正在推流, 直接返回: " + streamInfo.getRtsp());
                 JSONObject result = new JSONObject();
-                result.put("StreamID", streamInfo.getSsrc());
+                result.put("StreamID", streamInfo.getStreamId());
                 result.put("DeviceID", device.getDeviceId());
                 result.put("ChannelID", code);
                 result.put("ChannelName", deviceChannel.getName());
@@ -141,7 +141,7 @@ public class ApiStreamController {
 
         if (logger.isDebugEnabled()) {
             logger.debug(String.format("设备预览 API调用,deviceId:%s ,channelId:%s",serial, code));
-            logger.debug("设备预览 API调用,ssrc:"+streamInfo.getSsrc()+",ZLMedia streamId:"+Integer.toHexString(Integer.parseInt(streamInfo.getSsrc())));
+            logger.debug("设备预览 API调用,streamId:"+streamInfo.getStreamId());
         }
         boolean lockFlag = true;
         long startTime = System.currentTimeMillis();
@@ -173,7 +173,7 @@ public class ApiStreamController {
         }
         if(streamInfo!=null) {
             JSONObject result = new JSONObject();
-            result.put("StreamID", streamInfo.getSsrc());
+            result.put("StreamID", streamInfo.getStreamId());
             result.put("DeviceID", device.getDeviceId());
             result.put("ChannelID", code);
             result.put("ChannelName", deviceChannel.getName());
@@ -234,7 +234,7 @@ public class ApiStreamController {
             result.put("error","未找到流信息");
             return result;
         }
-        cmder.streamByeCmd(streamInfo.getSsrc());
+        cmder.streamByeCmd(streamInfo.getStreamId());
         storager.stopPlay(streamInfo);
         return null;
     }
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
index b58c06365..868298a65 100644
--- a/src/main/resources/application-dev.yml
+++ b/src/main/resources/application-dev.yml
@@ -74,6 +74,8 @@ media:
     # 设为false可以获得更好的兼容性,保证返回后流就可以播放,
     # 设为true可以快速打开播放窗口,可以获得更好的体验
     closeWaitRTPInfo: false
+    # [可选] 自动点播, 使用固定流地址进行播放时,如果未点播则自动进行点播
+    autoApplyPlay: true
     # 启用udp多端口模式, 详细解释参考: https://github.com/xia-chu/ZLMediaKit/wiki/GB28181%E6%8E%A8%E6%B5%81 下的高阶使用
     rtp:
         # [可选] 是否启用udp多端口模式, 开启后会在udpPortRange范围内选择端口用于媒体流传输
diff --git a/web_src/src/components/channelList.vue b/web_src/src/components/channelList.vue
index 4c39a3f87..738012d2e 100644
--- a/web_src/src/components/channelList.vue
+++ b/web_src/src/components/channelList.vue
@@ -187,9 +187,9 @@ export default {
                 url: '/api/play/' + deviceId + '/' + channelId + '?getEncoding=' + getEncoding
             }).then(function (res) {
                 console.log(res.data)
-                let ssrc = res.data.ssrc;
+                let streamId = res.data.streamId;
                 that.isLoging = false;
-                if (!!ssrc) {
+                if (!!streamId) {
                     // that.$refs.devicePlayer.play(res.data, deviceId, channelId, itemData.hasAudio);
                     that.$refs.devicePlayer.openDialog("media", deviceId, channelId, {
                         streamInfo: res.data,
@@ -212,7 +212,7 @@ export default {
             var that = this;
             this.$axios({
                 method: 'post',
-                url: '/api/play/' + itemData.ssrc + '/stop'
+                url: '/api/play/' + itemData.streamId + '/stop'
             }).then(function (res) {
                 console.log(JSON.stringify(res));
                 that.initData();
diff --git a/web_src/src/components/gb28181/devicePlayer.vue b/web_src/src/components/gb28181/devicePlayer.vue
index 8442a82fd..ed8464af5 100644
--- a/web_src/src/components/gb28181/devicePlayer.vue
+++ b/web_src/src/components/gb28181/devicePlayer.vue
@@ -158,7 +158,6 @@ export default {
                 searchHistoryResult: [] //媒体流历史记录搜索结果
             },
             showVideoDialog: false,
-            ssrc: '',
             streamId: '',
             convertKey: '',
             deviceId: '',
@@ -210,7 +209,6 @@ export default {
             this.tabActiveName = tab;
             this.channelId = channelId;
             this.deviceId = deviceId;
-            this.ssrc = "";
             this.streamId = "";
             this.videoUrl = ""
             if (!!this.$refs.videoPlayer) {
@@ -238,7 +236,6 @@ export default {
             this.hasaudio = hasAudio;
             this.isLoging = false;
             this.videoUrl = streamInfo.ws_flv;
-            this.ssrc = streamInfo.ssrc;
             this.streamId = streamInfo.streamId;
             this.playFromStreamInfo(false, streamInfo)
         },
@@ -248,7 +245,7 @@ export default {
             this.$refs.videoPlayer.pause()
             that.$axios({
                 method: 'post',
-                url: '/api/play/' + that.ssrc + '/convert'
+                url: '/api/play/' + that.streamId + '/convert'
                 }).then(function (res) {
                     if (res.data.code == 0) {
                         that.convertKey = res.data.key;
@@ -368,9 +365,9 @@ export default {
         },
         playRecord: function (row) {
             let that = this;
-            if (that.ssrc != "") {
+            if (that.streamId != "") {
                 that.stopPlayRecord(function () {
-                    that.ssrc = "",
+                    that.streamId = "",
                         that.playRecord(row);
                 })
             } else {
@@ -380,7 +377,7 @@ export default {
                         row.endTime
                 }).then(function (res) {
                     var streamInfo = res.data;
-                    that.ssrc = streamInfo.ssrc;
+                    that.streamId = streamInfo.streamId;
                     that.videoUrl = streamInfo.ws_flv;
                 });
             }
@@ -390,7 +387,7 @@ export default {
             this.videoUrl = '';
             this.$axios({
                 method: 'get',
-                url: '/api/playback/' + this.ssrc + '/stop'
+                url: '/api/playback/' + this.streamId + '/stop'
             }).then(function (res) {
                 if (callback) callback()
             });