Browse Source

去除ssrc作为流ID传递,ssrc只作为sdp消息使用。动态端口的情况下支持固定流地址,同时支持未点播时直接播放流地址,代码自动发起点播

pull/31/head
panlinlin 4 years ago
parent
commit
b0080159d9
  1. 9
      src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
  2. 18
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java
  3. 23
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
  4. 2
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
  5. 80
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
  6. 6
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMUtils.java
  7. 4
      src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
  8. 11
      src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java
  9. 27
      src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java
  10. 27
      src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
  11. 2
      src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java
  12. 2
      src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java
  13. 2
      src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java
  14. 10
      src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java
  15. 2
      src/main/resources/application-dev.yml
  16. 6
      web_src/src/components/channelList.vue
  17. 13
      web_src/src/components/gb28181/devicePlayer.vue

9
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java

@ -4,7 +4,6 @@ import com.alibaba.fastjson.JSONArray;
public class StreamInfo { public class StreamInfo {
private String ssrc;
private String streamId; private String streamId;
private String deviceID; private String deviceID;
private String cahnnelId; private String cahnnelId;
@ -20,14 +19,6 @@ public class StreamInfo {
private String rtsp; private String rtsp;
private JSONArray tracks; private JSONArray tracks;
public String getSsrc() {
return ssrc;
}
public void setSsrc(String ssrc) {
this.ssrc = ssrc;
}
public String getDeviceID() { public String getDeviceID() {
return deviceID; return deviceID;
} }

18
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; this.subCount = subCount;
} }
public String getSsrc() {
return ssrc;
}
public void setSsrc(String ssrc) {
this.ssrc = ssrc;
}
public boolean isHasAudio() { public boolean isHasAudio() {
return hasAudio; return hasAudio;
} }
@ -402,4 +394,12 @@ public class DeviceChannel {
public void setPlay(boolean play) { public void setPlay(boolean play) {
this.play = play; this.play = play;
} }
public String getStreamId() {
return streamId;
}
public void setStreamId(String streamId) {
this.streamId = streamId;
}
} }

23
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java

@ -277,17 +277,22 @@ public class SIPCommander implements ISIPCommander {
try { try {
String ssrc = streamSession.createPlaySsrc(); 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(); String streamMode = device.getStreamMode().toUpperCase();
MediaServerConfig mediaInfo = storager.getMediaInfo(); MediaServerConfig mediaInfo = storager.getMediaInfo();
String mediaPort = null; String mediaPort = null;
// 使用动态udp端口 // 使用动态udp端口
if (rtpEnable) { if (rtpEnable) {
mediaPort = zlmUtils.getNewRTPPort(ssrc) + ""; mediaPort = zlmUtils.getNewRTPPort(streamId) + "";
}else { }else {
mediaPort = mediaInfo.getRtpProxyPort(); mediaPort = mediaInfo.getRtpProxyPort();
} }
String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
// 添加订阅 // 添加订阅
JSONObject subscribeKey = new JSONObject(); JSONObject subscribeKey = new JSONObject();
subscribeKey.put("app", "rtp"); 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); Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "live", null, ssrc);
ClientTransaction transaction = transmitRequest(device, request); ClientTransaction transaction = transmitRequest(device, request);
streamSession.put(ssrc, transaction); streamSession.put(streamId, transaction);
DeviceChannel deviceChannel = storager.queryChannel(device.getDeviceId(), channelId); DeviceChannel deviceChannel = storager.queryChannel(device.getDeviceId(), channelId);
if (deviceChannel != null) { if (deviceChannel != null) {
deviceChannel.setSsrc(ssrc); deviceChannel.setStreamId(streamId);
storager.updateChannel(device.getDeviceId(), deviceChannel); storager.updateChannel(device.getDeviceId(), deviceChannel);
} }
@ -378,7 +383,7 @@ public class SIPCommander implements ISIPCommander {
String mediaPort = null; String mediaPort = null;
// 使用动态udp端口 // 使用动态udp端口
if (rtpEnable) { if (rtpEnable) {
mediaPort = zlmUtils.getNewRTPPort(ssrc) + ""; mediaPort = zlmUtils.getNewRTPPort(streamId) + "";
}else { }else {
mediaPort = mediaInfo.getRtpProxyPort(); mediaPort = mediaInfo.getRtpProxyPort();
} }
@ -412,7 +417,7 @@ public class SIPCommander implements ISIPCommander {
Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "playback", null); Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "playback", null);
ClientTransaction transaction = transmitRequest(device, request); ClientTransaction transaction = transmitRequest(device, request);
streamSession.put(ssrc, transaction); streamSession.put(streamId, transaction);
} catch ( SipException | ParseException | InvalidArgumentException e) { } catch ( SipException | ParseException | InvalidArgumentException e) {
e.printStackTrace(); e.printStackTrace();
@ -424,10 +429,10 @@ public class SIPCommander implements ISIPCommander {
* *
*/ */
@Override @Override
public void streamByeCmd(String ssrc) { public void streamByeCmd(String streamId) {
try { try {
ClientTransaction transaction = streamSession.get(ssrc); ClientTransaction transaction = streamSession.get(streamId);
if (transaction == null) { if (transaction == null) {
return; return;
} }
@ -453,7 +458,7 @@ public class SIPCommander implements ISIPCommander {
clientTransaction = udpSipProvider.getNewClientTransaction(byeRequest); clientTransaction = udpSipProvider.getNewClientTransaction(byeRequest);
} }
dialog.sendRequest(clientTransaction); dialog.sendRequest(clientTransaction);
streamSession.remove(ssrc); streamSession.remove(streamId);
} catch (TransactionDoesNotExistException e) { } catch (TransactionDoesNotExistException e) {
e.printStackTrace(); e.printStackTrace();
} catch (SipException e) { } catch (SipException e) {

2
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, "*"); StreamInfo streamInfo = storager.queryPlaybackByDevice(deviceId, "*");
if (streamInfo != null) { if (streamInfo != null) {
storager.stopPlayback(streamInfo); storager.stopPlayback(streamInfo);
cmder.streamByeCmd(streamInfo.getSsrc()); cmder.streamByeCmd(streamInfo.getStreamId());
} }
} }
} catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) {

80
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.text.DecimalFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.MediaServerConfig; 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.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.IpUtil; import com.genersoft.iot.vmp.utils.IpUtil;
import com.genersoft.iot.vmp.vmanager.service.IPlayService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -43,6 +46,9 @@ public class ZLMHttpHookListener {
@Autowired @Autowired
private SIPCommander cmder; private SIPCommander cmder;
@Autowired
private IPlayService playService;
@Autowired @Autowired
private IVideoManagerStorager storager; private IVideoManagerStorager storager;
@ -52,6 +58,9 @@ public class ZLMHttpHookListener {
@Autowired @Autowired
private ZLMHttpHookSubscribe subscribe; private ZLMHttpHookSubscribe subscribe;
@Value("${media.autoApplyPlay}")
private boolean autoApplyPlay;
@Value("${media.ip}") @Value("${media.ip}")
private String mediaIp; private String mediaIp;
@ -135,34 +144,6 @@ public class ZLMHttpHookListener {
ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json); ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json);
if (subscribe != null) subscribe.response(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 // TODO Auto-generated method stub
@ -268,14 +249,12 @@ public class ZLMHttpHookListener {
String app = json.getString("app"); String app = json.getString("app");
String streamId = json.getString("stream"); String streamId = json.getString("stream");
boolean regist = json.getBoolean("regist"); boolean regist = json.getBoolean("regist");
// String ssrc = String.format("%10d", Integer.parseInt(streamId, 16)); // ZLM 要求大写且首位补零 StreamInfo streamInfo = storager.queryPlayByStreamId(streamId);
String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));
StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
if ("rtp".equals(app) && !regist ) { if ("rtp".equals(app) && !regist ) {
if (streamInfo!=null){ if (streamInfo!=null){
storager.stopPlay(streamInfo); storager.stopPlay(streamInfo);
}else{ }else{
streamInfo = storager.queryPlaybackBySSRC(ssrc); streamInfo = storager.queryPlaybackByStreamId(streamId);
storager.stopPlayback(streamInfo); storager.stopPlayback(streamInfo);
} }
} }
@ -299,16 +278,14 @@ public class ZLMHttpHookListener {
logger.debug("ZLM HOOK on_stream_none_reader API调用,参数:" + json.toString()); logger.debug("ZLM HOOK on_stream_none_reader API调用,参数:" + json.toString());
} }
BigInteger bigint=new BigInteger(json.getString("stream"), 16); String streamId = json.getString("stream");
int numb=bigint.intValue();
String ssrc = String.format("%010d", numb); cmder.streamByeCmd(streamId);
StreamInfo streamInfo = storager.queryPlayByStreamId(streamId);
cmder.streamByeCmd(ssrc);
StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
if (streamInfo!=null){ if (streamInfo!=null){
storager.stopPlay(streamInfo); storager.stopPlay(streamInfo);
}else{ }else{
streamInfo = storager.queryPlaybackBySSRC(ssrc); streamInfo = storager.queryPlaybackByStreamId(streamId);
storager.stopPlayback(streamInfo); storager.stopPlayback(streamInfo);
} }
@ -330,7 +307,30 @@ public class ZLMHttpHookListener {
logger.debug("ZLM HOOK on_stream_not_found API调用,参数:" + json.toString()); logger.debug("ZLM HOOK on_stream_not_found API调用,参数:" + json.toString());
} }
// TODO Auto-generated method stub // 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(); JSONObject ret = new JSONObject();
ret.put("code", 0); ret.put("code", 0);
ret.put("msg", "success"); ret.put("msg", "success");

6
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMUtils.java

@ -21,8 +21,8 @@ public class ZLMUtils {
private int currentPort = 0; private int currentPort = 0;
public int getNewRTPPort(String ssrc) { public int getNewRTPPort(String streamId) {
String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); // String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
Map<String, Object> param = new HashMap<>(); Map<String, Object> param = new HashMap<>();
int newPort = getPortFromUdpPortRange(); int newPort = getPortFromUdpPortRange();
param.put("port", newPort); param.put("port", newPort);
@ -32,7 +32,7 @@ public class ZLMUtils {
if (jsonObject != null && jsonObject.getInteger("code") == 0) { if (jsonObject != null && jsonObject.getInteger("code") == 0) {
return newPort; return newPort;
} else { } else {
return getNewRTPPort(ssrc); return getNewRTPPort(streamId);
} }
} }

4
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java

@ -178,7 +178,7 @@ public interface IVideoManagerStorager {
*/ */
void cleanChannelsForDevice(String deviceId); void cleanChannelsForDevice(String deviceId);
StreamInfo queryPlayBySSRC(String ssrc); StreamInfo queryPlayByStreamId(String streamId);
StreamInfo queryPlayByDevice(String deviceId, String code); StreamInfo queryPlayByDevice(String deviceId, String code);
@ -190,5 +190,5 @@ public interface IVideoManagerStorager {
StreamInfo queryPlaybackByDevice(String deviceId, String channelId); StreamInfo queryPlaybackByDevice(String deviceId, String channelId);
StreamInfo queryPlaybackBySSRC(String ssrc); StreamInfo queryPlaybackByStreamId(String streamId);
} }

11
src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java

@ -178,10 +178,6 @@ public class VideoManagerJdbcStoragerImpl implements IVideoManagerStorager {
return false; return false;
} }
@Override
public StreamInfo queryPlayBySSRC(String ssrc) {
return null;
}
@Override @Override
public StreamInfo queryPlayByDevice(String deviceId, String code) { public StreamInfo queryPlayByDevice(String deviceId, String code) {
@ -210,7 +206,12 @@ public class VideoManagerJdbcStoragerImpl implements IVideoManagerStorager {
} }
@Override @Override
public StreamInfo queryPlaybackBySSRC(String ssrc) { public StreamInfo queryPlayByStreamId(String streamId) {
return null;
}
@Override
public StreamInfo queryPlaybackByStreamId(String streamId) {
return null; return null;
} }
} }

27
src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java

@ -151,7 +151,6 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
"_" + queryOnline + // 搜索是否在线 "_" + queryOnline + // 搜索是否在线
"_" + queryHasSubChannel + // 搜索是否含有子节点 "_" + queryHasSubChannel + // 搜索是否含有子节点
"_" + "*"; "_" + "*";
// List<Object> deviceChannelList = redis.keys(queryStr);
List<Object> deviceChannelList = redis.scan(queryStr); List<Object> deviceChannelList = redis.scan(queryStr);
//对查询结果排序,避免出现通道排列顺序乱序的情况 //对查询结果排序,避免出现通道排列顺序乱序的情况
Collections.sort(deviceChannelList,new Comparator<Object>(){ Collections.sort(deviceChannelList,new Comparator<Object>(){
@ -169,7 +168,7 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
DeviceChannel deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(i)); DeviceChannel deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(i));
StreamInfo streamInfo = stringStreamInfoMap.get(deviceId + "_" + deviceChannel.getChannelId()); StreamInfo streamInfo = stringStreamInfoMap.get(deviceId + "_" + deviceChannel.getChannelId());
deviceChannel.setPlay(streamInfo != null); deviceChannel.setPlay(streamInfo != null);
if (streamInfo != null) deviceChannel.setSsrc(streamInfo.getSsrc()); if (streamInfo != null) deviceChannel.setStreamId(streamInfo.getStreamId());
result.add(deviceChannel); result.add(deviceChannel);
} }
pageResult.setData(result); pageResult.setData(result);
@ -384,7 +383,7 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
*/ */
@Override @Override
public boolean startPlay(StreamInfo stream) { 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); stream);
} }
@ -398,12 +397,12 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
if (streamInfo == null) return false; if (streamInfo == null) return false;
DeviceChannel deviceChannel = queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId()); DeviceChannel deviceChannel = queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId());
if (deviceChannel != null) { if (deviceChannel != null) {
deviceChannel.setSsrc(null); deviceChannel.setStreamId(null);
deviceChannel.setPlay(false); deviceChannel.setPlay(false);
updateChannel(streamInfo.getDeviceID(), deviceChannel); updateChannel(streamInfo.getDeviceID(), deviceChannel);
} }
return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
streamInfo.getSsrc(), streamInfo.getStreamId(),
streamInfo.getDeviceID(), streamInfo.getDeviceID(),
streamInfo.getCahnnelId())); streamInfo.getCahnnelId()));
} }
@ -416,22 +415,20 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
public StreamInfo queryPlay(StreamInfo streamInfo) { public StreamInfo queryPlay(StreamInfo streamInfo) {
return (StreamInfo)redis.get(String.format("%S_%s_%s_%s", return (StreamInfo)redis.get(String.format("%S_%s_%s_%s",
VideoManagerConstants.PLAYER_PREFIX, VideoManagerConstants.PLAYER_PREFIX,
streamInfo.getSsrc(), streamInfo.getStreamId(),
streamInfo.getDeviceID(), streamInfo.getDeviceID(),
streamInfo.getCahnnelId())); streamInfo.getCahnnelId()));
} }
@Override @Override
public StreamInfo queryPlayBySSRC(String ssrc) { public StreamInfo queryPlayByStreamId(String steamId) {
// 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, steamId));
List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, ssrc));
if (playLeys == null || playLeys.size() == 0) return null; if (playLeys == null || playLeys.size() == 0) return null;
return (StreamInfo)redis.get(playLeys.get(0).toString()); return (StreamInfo)redis.get(playLeys.get(0).toString());
} }
@Override @Override
public StreamInfo queryPlaybackBySSRC(String ssrc) { public StreamInfo queryPlaybackByStreamId(String steamId) {
// 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, steamId));
List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAY_BLACK_PREFIX, ssrc));
if (playLeys == null || playLeys.size() == 0) return null; if (playLeys == null || playLeys.size() == 0) return null;
return (StreamInfo)redis.get(playLeys.get(0).toString()); return (StreamInfo)redis.get(playLeys.get(0).toString());
} }
@ -526,7 +523,7 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
@Override @Override
public boolean startPlayback(StreamInfo stream) { 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); stream);
} }
@ -536,12 +533,12 @@ public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
if (streamInfo == null) return false; if (streamInfo == null) return false;
DeviceChannel deviceChannel = queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId()); DeviceChannel deviceChannel = queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId());
if (deviceChannel != null) { if (deviceChannel != null) {
deviceChannel.setSsrc(null); deviceChannel.setStreamId(null);
deviceChannel.setPlay(false); deviceChannel.setPlay(false);
updateChannel(streamInfo.getDeviceID(), deviceChannel); updateChannel(streamInfo.getDeviceID(), deviceChannel);
} }
return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
streamInfo.getSsrc(), streamInfo.getStreamId(),
streamInfo.getDeviceID(), streamInfo.getDeviceID(),
streamInfo.getCahnnelId())); streamInfo.getCahnnelId()));
} }

27
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()); playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
}); });
} else { } else {
String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase(); String streamId = streamInfo.getStreamId();
JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId); JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
if (rtpInfo.getBoolean("exist")) { if (rtpInfo.getBoolean("exist")) {
RequestMessage msg = new RequestMessage(); RequestMessage msg = new RequestMessage();
@ -99,21 +99,21 @@ public class PlayController {
return result; return result;
} }
@PostMapping("/play/{ssrc}/stop") @PostMapping("/play/{streamId}/stop")
public ResponseEntity<String> playStop(@PathVariable String ssrc) { public ResponseEntity<String> playStop(@PathVariable String streamId) {
cmder.streamByeCmd(ssrc); cmder.streamByeCmd(streamId);
StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc); StreamInfo streamInfo = storager.queryPlayByStreamId(streamId);
if (streamInfo == null) if (streamInfo == null)
return new ResponseEntity<String>("ssrc not found", HttpStatus.OK); return new ResponseEntity<String>("streamId not found", HttpStatus.OK);
storager.stopPlay(streamInfo); storager.stopPlay(streamInfo);
if (logger.isDebugEnabled()) { 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(); JSONObject json = new JSONObject();
json.put("ssrc", ssrc); json.put("streamId", streamId);
return new ResponseEntity<String>(json.toString(), HttpStatus.OK); return new ResponseEntity<String>(json.toString(), HttpStatus.OK);
} else { } else {
logger.warn("设备预览停止API调用失败!"); logger.warn("设备预览停止API调用失败!");
@ -123,17 +123,16 @@ public class PlayController {
/** /**
* 将不是h264的视频通过ffmpeg 转码为h264 + aac * 将不是h264的视频通过ffmpeg 转码为h264 + aac
* @param ssrc * @param streamId 流ID
* @return * @return
*/ */
@PostMapping("/play/{ssrc}/convert") @PostMapping("/play/{streamId}/convert")
public ResponseEntity<String> playConvert(@PathVariable String ssrc) { public ResponseEntity<String> playConvert(@PathVariable String streamId) {
StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc); StreamInfo streamInfo = storager.queryPlayByStreamId(streamId);
if (streamInfo == null) { if (streamInfo == null) {
logger.warn("视频转码API调用失败!, 视频流已经停止!"); logger.warn("视频转码API调用失败!, 视频流已经停止!");
return new ResponseEntity<String>("未找到视频流信息, 视频流可能已经停止", HttpStatus.OK); return new ResponseEntity<String>("未找到视频流信息, 视频流可能已经停止", HttpStatus.OK);
} }
String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId); JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
if (!rtpInfo.getBoolean("exist")) { if (!rtpInfo.getBoolean("exist")) {
logger.warn("视频转码API调用失败!, 视频流已停止推流!"); logger.warn("视频转码API调用失败!, 视频流已停止推流!");

2
src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java

@ -72,7 +72,7 @@ public class PlaybackController {
StreamInfo streamInfo = storager.queryPlaybackByDevice(deviceId, channelId); StreamInfo streamInfo = storager.queryPlaybackByDevice(deviceId, channelId);
if (streamInfo != null) { if (streamInfo != null) {
// 停止之前的回放 // 停止之前的回放
cmder.streamByeCmd(streamInfo.getSsrc()); cmder.streamByeCmd(streamInfo.getStreamId());
} }
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result); resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result);
cmder.playbackStreamCmd(device, channelId, startTime, endTime, (JSONObject response) -> { cmder.playbackStreamCmd(device, channelId, startTime, endTime, (JSONObject response) -> {

2
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) { public StreamInfo onPublishHandler(JSONObject resonse, String deviceId, String channelId, String uuid) {
String streamId = resonse.getString("id"); String streamId = resonse.getString("id");
String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));
StreamInfo streamInfo = new StreamInfo(); StreamInfo streamInfo = new StreamInfo();
streamInfo.setSsrc(ssrc);
streamInfo.setStreamId(streamId); streamInfo.setStreamId(streamId);
streamInfo.setDeviceID(deviceId); streamInfo.setDeviceID(deviceId);
streamInfo.setCahnnelId(channelId); streamInfo.setCahnnelId(channelId);

2
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 - 半球, deviceJOSNChannel.put("PTZType ", deviceChannel.getPTZType()); // 云台类型, 0 - 未知, 1 - 球机, 2 - 半球,
// 3 - 固定枪机, 4 - 遥控枪机 // 3 - 固定枪机, 4 - 遥控枪机
deviceJOSNChannel.put("CustomPTZType", ""); deviceJOSNChannel.put("CustomPTZType", "");
deviceJOSNChannel.put("StreamID", deviceChannel.getSsrc()); // StreamID 直播流ID, 有值表示正在直播 deviceJOSNChannel.put("StreamID", deviceChannel.getStreamId()); // StreamID 直播流ID, 有值表示正在直播
deviceJOSNChannel.put("NumOutputs ", -1); // 直播在线人数 deviceJOSNChannel.put("NumOutputs ", -1); // 直播在线人数
channleJSONList.add(deviceJOSNChannel); channleJSONList.add(deviceJOSNChannel);
} }

10
src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java

@ -96,12 +96,12 @@ public class ApiStreamController {
// streamInfo = cmder.playStreamCmd(device, code); // streamInfo = cmder.playStreamCmd(device, code);
}else { }else {
logger.debug("streamInfo 不等于null, 向流媒体查询是否正在推流"); logger.debug("streamInfo 不等于null, 向流媒体查询是否正在推流");
String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase(); String streamId = streamInfo.getStreamId();
JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId); JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
if (rtpInfo.getBoolean("exist")) { if (rtpInfo.getBoolean("exist")) {
logger.debug("向流媒体查询正在推流, 直接返回: " + streamInfo.getRtsp()); logger.debug("向流媒体查询正在推流, 直接返回: " + streamInfo.getRtsp());
JSONObject result = new JSONObject(); JSONObject result = new JSONObject();
result.put("StreamID", streamInfo.getSsrc()); result.put("StreamID", streamInfo.getStreamId());
result.put("DeviceID", device.getDeviceId()); result.put("DeviceID", device.getDeviceId());
result.put("ChannelID", code); result.put("ChannelID", code);
result.put("ChannelName", deviceChannel.getName()); result.put("ChannelName", deviceChannel.getName());
@ -141,7 +141,7 @@ public class ApiStreamController {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug(String.format("设备预览 API调用,deviceId:%s ,channelId:%s",serial, code)); 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; boolean lockFlag = true;
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
@ -173,7 +173,7 @@ public class ApiStreamController {
} }
if(streamInfo!=null) { if(streamInfo!=null) {
JSONObject result = new JSONObject(); JSONObject result = new JSONObject();
result.put("StreamID", streamInfo.getSsrc()); result.put("StreamID", streamInfo.getStreamId());
result.put("DeviceID", device.getDeviceId()); result.put("DeviceID", device.getDeviceId());
result.put("ChannelID", code); result.put("ChannelID", code);
result.put("ChannelName", deviceChannel.getName()); result.put("ChannelName", deviceChannel.getName());
@ -234,7 +234,7 @@ public class ApiStreamController {
result.put("error","未找到流信息"); result.put("error","未找到流信息");
return result; return result;
} }
cmder.streamByeCmd(streamInfo.getSsrc()); cmder.streamByeCmd(streamInfo.getStreamId());
storager.stopPlay(streamInfo); storager.stopPlay(streamInfo);
return null; return null;
} }

2
src/main/resources/application-dev.yml

@ -74,6 +74,8 @@ media:
# 设为false可以获得更好的兼容性,保证返回后流就可以播放, # 设为false可以获得更好的兼容性,保证返回后流就可以播放,
# 设为true可以快速打开播放窗口,可以获得更好的体验 # 设为true可以快速打开播放窗口,可以获得更好的体验
closeWaitRTPInfo: false closeWaitRTPInfo: false
# [可选] 自动点播, 使用固定流地址进行播放时,如果未点播则自动进行点播
autoApplyPlay: true
# 启用udp多端口模式, 详细解释参考: https://github.com/xia-chu/ZLMediaKit/wiki/GB28181%E6%8E%A8%E6%B5%81 下的高阶使用 # 启用udp多端口模式, 详细解释参考: https://github.com/xia-chu/ZLMediaKit/wiki/GB28181%E6%8E%A8%E6%B5%81 下的高阶使用
rtp: rtp:
# [可选] 是否启用udp多端口模式, 开启后会在udpPortRange范围内选择端口用于媒体流传输 # [可选] 是否启用udp多端口模式, 开启后会在udpPortRange范围内选择端口用于媒体流传输

6
web_src/src/components/channelList.vue

@ -187,9 +187,9 @@ export default {
url: '/api/play/' + deviceId + '/' + channelId + '?getEncoding=' + getEncoding url: '/api/play/' + deviceId + '/' + channelId + '?getEncoding=' + getEncoding
}).then(function (res) { }).then(function (res) {
console.log(res.data) console.log(res.data)
let ssrc = res.data.ssrc; let streamId = res.data.streamId;
that.isLoging = false; that.isLoging = false;
if (!!ssrc) { if (!!streamId) {
// that.$refs.devicePlayer.play(res.data, deviceId, channelId, itemData.hasAudio); // that.$refs.devicePlayer.play(res.data, deviceId, channelId, itemData.hasAudio);
that.$refs.devicePlayer.openDialog("media", deviceId, channelId, { that.$refs.devicePlayer.openDialog("media", deviceId, channelId, {
streamInfo: res.data, streamInfo: res.data,
@ -212,7 +212,7 @@ export default {
var that = this; var that = this;
this.$axios({ this.$axios({
method: 'post', method: 'post',
url: '/api/play/' + itemData.ssrc + '/stop' url: '/api/play/' + itemData.streamId + '/stop'
}).then(function (res) { }).then(function (res) {
console.log(JSON.stringify(res)); console.log(JSON.stringify(res));
that.initData(); that.initData();

13
web_src/src/components/gb28181/devicePlayer.vue

@ -158,7 +158,6 @@ export default {
searchHistoryResult: [] // searchHistoryResult: [] //
}, },
showVideoDialog: false, showVideoDialog: false,
ssrc: '',
streamId: '', streamId: '',
convertKey: '', convertKey: '',
deviceId: '', deviceId: '',
@ -210,7 +209,6 @@ export default {
this.tabActiveName = tab; this.tabActiveName = tab;
this.channelId = channelId; this.channelId = channelId;
this.deviceId = deviceId; this.deviceId = deviceId;
this.ssrc = "";
this.streamId = ""; this.streamId = "";
this.videoUrl = "" this.videoUrl = ""
if (!!this.$refs.videoPlayer) { if (!!this.$refs.videoPlayer) {
@ -238,7 +236,6 @@ export default {
this.hasaudio = hasAudio; this.hasaudio = hasAudio;
this.isLoging = false; this.isLoging = false;
this.videoUrl = streamInfo.ws_flv; this.videoUrl = streamInfo.ws_flv;
this.ssrc = streamInfo.ssrc;
this.streamId = streamInfo.streamId; this.streamId = streamInfo.streamId;
this.playFromStreamInfo(false, streamInfo) this.playFromStreamInfo(false, streamInfo)
}, },
@ -248,7 +245,7 @@ export default {
this.$refs.videoPlayer.pause() this.$refs.videoPlayer.pause()
that.$axios({ that.$axios({
method: 'post', method: 'post',
url: '/api/play/' + that.ssrc + '/convert' url: '/api/play/' + that.streamId + '/convert'
}).then(function (res) { }).then(function (res) {
if (res.data.code == 0) { if (res.data.code == 0) {
that.convertKey = res.data.key; that.convertKey = res.data.key;
@ -368,9 +365,9 @@ export default {
}, },
playRecord: function (row) { playRecord: function (row) {
let that = this; let that = this;
if (that.ssrc != "") { if (that.streamId != "") {
that.stopPlayRecord(function () { that.stopPlayRecord(function () {
that.ssrc = "", that.streamId = "",
that.playRecord(row); that.playRecord(row);
}) })
} else { } else {
@ -380,7 +377,7 @@ export default {
row.endTime row.endTime
}).then(function (res) { }).then(function (res) {
var streamInfo = res.data; var streamInfo = res.data;
that.ssrc = streamInfo.ssrc; that.streamId = streamInfo.streamId;
that.videoUrl = streamInfo.ws_flv; that.videoUrl = streamInfo.ws_flv;
}); });
} }
@ -390,7 +387,7 @@ export default {
this.videoUrl = ''; this.videoUrl = '';
this.$axios({ this.$axios({
method: 'get', method: 'get',
url: '/api/playback/' + this.ssrc + '/stop' url: '/api/playback/' + this.streamId + '/stop'
}).then(function (res) { }).then(function (res) {
if (callback) callback() if (callback) callback()
}); });

Loading…
Cancel
Save