Commit 130dc5d82da0e89241eefd4ea91ba7d861de866d

Authored by 648540858
1 parent 483d5e04

优化拉流代理逻辑,修复ffmpeg拉流代理鉴权

sql/2.6.9更新.sql
@@ -3,3 +3,6 @@ alter table wvp_device_channel @@ -3,3 +3,6 @@ alter table wvp_device_channel
3 3
4 alter table wvp_platform 4 alter table wvp_platform
5 add auto_push_channel bool default false 5 add auto_push_channel bool default false
  6 +
  7 +alter table wvp_stream_proxy
  8 + add stream_key varying(255)
sql/初始化.sql
@@ -244,6 +244,7 @@ create table wvp_stream_proxy ( @@ -244,6 +244,7 @@ create table wvp_stream_proxy (
244 create_time character varying(50), 244 create_time character varying(50),
245 name character varying(255), 245 name character varying(255),
246 update_time character varying(50), 246 update_time character varying(50),
  247 + stream_key character varying(255),
247 enable_disable_none_reader bool default false, 248 enable_disable_none_reader bool default false,
248 constraint uk_stream_proxy_app_stream unique (app, stream) 249 constraint uk_stream_proxy_app_stream unique (app, stream)
249 ); 250 );
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java
@@ -93,7 +93,10 @@ public class CatalogEventLister implements ApplicationListener<CatalogEvent> { @@ -93,7 +93,10 @@ public class CatalogEventLister implements ApplicationListener<CatalogEvent> {
93 } 93 }
94 if (event.getGbStreams() != null && event.getGbStreams().size() > 0){ 94 if (event.getGbStreams() != null && event.getGbStreams().size() > 0){
95 for (GbStream gbStream : event.getGbStreams()) { 95 for (GbStream gbStream : event.getGbStreams()) {
96 - if (gbStream != null && gbStream.getStreamType().equals("push") && !userSetting.isUsePushingAsStatus()) { 96 + if (gbStream != null
  97 + && gbStream.getStreamType() != null
  98 + && gbStream.getStreamType().equals("push")
  99 + && !userSetting.isUsePushingAsStatus()) {
97 continue; 100 continue;
98 } 101 }
99 DeviceChannel deviceChannelByStream = gbStreamService.getDeviceChannelListByStream(gbStream, gbStream.getCatalogId(), parentPlatform); 102 DeviceChannel deviceChannelByStream = gbStreamService.getDeviceChannelListByStream(gbStream, gbStream.getCatalogId(), parentPlatform);
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -199,6 +199,13 @@ public class ZLMHttpHookListener { @@ -199,6 +199,13 @@ public class ZLMHttpHookListener {
199 } 199 }
200 // 推流鉴权的处理 200 // 推流鉴权的处理
201 if (!"rtp".equals(param.getApp())) { 201 if (!"rtp".equals(param.getApp())) {
  202 + StreamProxyItem stream = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream());
  203 + if (stream != null) {
  204 + HookResultForOnPublish result = HookResultForOnPublish.SUCCESS();
  205 + result.setEnable_audio(stream.isEnableAudio());
  206 + result.setEnable_mp4(stream.isEnableMp4());
  207 + return result;
  208 + }
202 if (userSetting.getPushAuthority()) { 209 if (userSetting.getPushAuthority()) {
203 // 推流鉴权 210 // 推流鉴权
204 if (param.getParams() == null) { 211 if (param.getParams() == null) {
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
@@ -272,6 +272,12 @@ public class ZLMRESTfulUtils { @@ -272,6 +272,12 @@ public class ZLMRESTfulUtils {
272 return sendPost(mediaServerItem, "delFFmpegSource",param, null); 272 return sendPost(mediaServerItem, "delFFmpegSource",param, null);
273 } 273 }
274 274
  275 + public JSONObject delStreamProxy(MediaServerItem mediaServerItem, String key){
  276 + Map<String, Object> param = new HashMap<>();
  277 + param.put("key", key);
  278 + return sendPost(mediaServerItem, "delStreamProxy",param, null);
  279 + }
  280 +
275 public JSONObject getMediaServerConfig(MediaServerItem mediaServerItem){ 281 public JSONObject getMediaServerConfig(MediaServerItem mediaServerItem){
276 return sendPost(mediaServerItem, "getServerConfig",null, null); 282 return sendPost(mediaServerItem, "getServerConfig",null, null);
277 } 283 }
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java
@@ -41,6 +41,9 @@ public class StreamProxyItem extends GbStream { @@ -41,6 +41,9 @@ public class StreamProxyItem extends GbStream {
41 @Schema(description = "是否 无人观看时自动停用") 41 @Schema(description = "是否 无人观看时自动停用")
42 private boolean enableDisableNoneReader; 42 private boolean enableDisableNoneReader;
43 43
  44 + @Schema(description = "拉流代理时zlm返回的key,用于停止拉流代理")
  45 + private String streamKey;
  46 +
44 public String getType() { 47 public String getType() {
45 return type; 48 return type;
46 } 49 }
@@ -167,5 +170,11 @@ public class StreamProxyItem extends GbStream { @@ -167,5 +170,11 @@ public class StreamProxyItem extends GbStream {
167 this.enableAudio = enable_audio; 170 this.enableAudio = enable_audio;
168 } 171 }
169 172
  173 + public String getStreamKey() {
  174 + return streamKey;
  175 + }
170 176
  177 + public void setStreamKey(String streamKey) {
  178 + this.streamKey = streamKey;
  179 + }
171 } 180 }
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
@@ -10,6 +10,7 @@ import com.genersoft.iot.vmp.conf.exception.ControllerException; @@ -10,6 +10,7 @@ import com.genersoft.iot.vmp.conf.exception.ControllerException;
10 import com.genersoft.iot.vmp.gb28181.event.EventPublisher; 10 import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
11 import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; 11 import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
12 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; 12 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
  13 +import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
13 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; 14 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
14 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; 15 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
15 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; 16 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
@@ -62,6 +63,9 @@ public class StreamProxyServiceImpl implements IStreamProxyService { @@ -62,6 +63,9 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
62 private ZLMRESTfulUtils zlmresTfulUtils; 63 private ZLMRESTfulUtils zlmresTfulUtils;
63 64
64 @Autowired 65 @Autowired
  66 + private ZLMServerFactory zlmServerFactory;
  67 +
  68 + @Autowired
65 private StreamProxyMapper streamProxyMapper; 69 private StreamProxyMapper streamProxyMapper;
66 70
67 @Autowired 71 @Autowired
@@ -145,7 +149,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService { @@ -145,7 +149,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
145 dstUrl = String.format("%s://%s:%s/%s/%s", schemaForUri, "127.0.0.1", port, param.getApp(), 149 dstUrl = String.format("%s://%s:%s/%s/%s", schemaForUri, "127.0.0.1", port, param.getApp(),
146 param.getStream()); 150 param.getStream());
147 }else { 151 }else {
148 - dstUrl = String.format("rtmp://%s:%s/%s/%s", "127.0.0.1", mediaInfo.getRtmpPort(), param.getApp(), 152 + dstUrl = String.format("rtsp://%s:%s/%s/%s", "127.0.0.1", mediaInfo.getRtspPort(), param.getApp(),
149 param.getStream()); 153 param.getStream());
150 } 154 }
151 param.setDstUrl(dstUrl); 155 param.setDstUrl(dstUrl);
@@ -170,12 +174,6 @@ public class StreamProxyServiceImpl implements IStreamProxyService { @@ -170,12 +174,6 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
170 }); 174 });
171 if (param.isEnable()) { 175 if (param.isEnable()) {
172 String talkKey = UUID.randomUUID().toString(); 176 String talkKey = UUID.randomUUID().toString();
173 -// dynamicTask.startCron(talkKey, ()->{  
174 -// StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(param.getApp(), param.getStream(), mediaInfo.getId(), false);  
175 -// if (streamInfo != null) {  
176 -// callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo);  
177 -// }  
178 -// }, 3000);  
179 String delayTalkKey = UUID.randomUUID().toString(); 177 String delayTalkKey = UUID.randomUUID().toString();
180 dynamicTask.startDelay(delayTalkKey, ()->{ 178 dynamicTask.startDelay(delayTalkKey, ()->{
181 StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(param.getApp(), param.getStream(), mediaInfo.getId(), false); 179 StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(param.getApp(), param.getStream(), mediaInfo.getId(), false);
@@ -318,13 +316,32 @@ public class StreamProxyServiceImpl implements IStreamProxyService { @@ -318,13 +316,32 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
318 if (mediaServerItem == null) { 316 if (mediaServerItem == null) {
319 return null; 317 return null;
320 } 318 }
321 - if ("default".equals(param.getType())){  
322 - result = zlmresTfulUtils.addStreamProxy(mediaServerItem, param.getApp(), param.getStream(), param.getUrl().trim(),  
323 - param.isEnableAudio(), param.isEnableMp4(), param.getRtpType());  
324 - }else if ("ffmpeg".equals(param.getType())) { 319 + if (zlmServerFactory.isStreamReady(mediaServerItem, param.getApp(), param.getStream())) {
  320 + zlmresTfulUtils.closeStreams(mediaServerItem, param.getApp(), param.getStream());
  321 + }
  322 + if ("ffmpeg".equalsIgnoreCase(param.getType())){
325 result = zlmresTfulUtils.addFFmpegSource(mediaServerItem, param.getSrcUrl().trim(), param.getDstUrl(), 323 result = zlmresTfulUtils.addFFmpegSource(mediaServerItem, param.getSrcUrl().trim(), param.getDstUrl(),
326 param.getTimeoutMs() + "", param.isEnableAudio(), param.isEnableMp4(), 324 param.getTimeoutMs() + "", param.isEnableAudio(), param.isEnableMp4(),
327 param.getFfmpegCmdKey()); 325 param.getFfmpegCmdKey());
  326 + }else {
  327 + result = zlmresTfulUtils.addStreamProxy(mediaServerItem, param.getApp(), param.getStream(), param.getUrl().trim(),
  328 + param.isEnableAudio(), param.isEnableMp4(), param.getRtpType());
  329 + }
  330 + System.out.println("addStreamProxyToZlm====");
  331 + System.out.println(result);
  332 + if (result != null && result.getInteger("code") == 0) {
  333 + JSONObject data = result.getJSONObject("data");
  334 + if (data == null) {
  335 + logger.warn("[获取拉流代理的结果数据Data] 失败: {}", result );
  336 + return result;
  337 + }
  338 + String key = data.getString("key");
  339 + if (key == null) {
  340 + logger.warn("[获取拉流代理的结果数据Data中的KEY] 失败: {}", result );
  341 + return result;
  342 + }
  343 + param.setStreamKey(key);
  344 + streamProxyMapper.update(param);
328 } 345 }
329 return result; 346 return result;
330 } 347 }
@@ -335,7 +352,12 @@ public class StreamProxyServiceImpl implements IStreamProxyService { @@ -335,7 +352,12 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
335 return null; 352 return null;
336 } 353 }
337 MediaServerItem mediaServerItem = mediaServerService.getOne(param.getMediaServerId()); 354 MediaServerItem mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
338 - JSONObject result = zlmresTfulUtils.closeStreams(mediaServerItem, param.getApp(), param.getStream()); 355 + JSONObject result = null;
  356 + if ("ffmpeg".equalsIgnoreCase(param.getType())){
  357 + result = zlmresTfulUtils.delFFmpegSource(mediaServerItem, param.getStreamKey());
  358 + }else {
  359 + result = zlmresTfulUtils.delStreamProxy(mediaServerItem, param.getStreamKey());
  360 + }
339 return result; 361 return result;
340 } 362 }
341 363
@@ -350,19 +372,18 @@ public class StreamProxyServiceImpl implements IStreamProxyService { @@ -350,19 +372,18 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
350 if (streamProxyItem != null) { 372 if (streamProxyItem != null) {
351 gbStreamService.sendCatalogMsg(streamProxyItem, CatalogEvent.DEL); 373 gbStreamService.sendCatalogMsg(streamProxyItem, CatalogEvent.DEL);
352 374
  375 + // 如果关联了国标那么移除关联
  376 + platformGbStreamMapper.delByAppAndStream(app, stream);
  377 + gbStreamMapper.del(app, stream);
  378 + videoManagerStorager.deleteStreamProxy(app, stream);
  379 + redisCatchStorage.removeStream(streamProxyItem.getMediaServerId(), "PULL", app, stream);
353 JSONObject jsonObject = removeStreamProxyFromZlm(streamProxyItem); 380 JSONObject jsonObject = removeStreamProxyFromZlm(streamProxyItem);
354 if (jsonObject != null && jsonObject.getInteger("code") == 0) { 381 if (jsonObject != null && jsonObject.getInteger("code") == 0) {
355 - // 如果关联了国标那么移除关联  
356 - int i = platformGbStreamMapper.delByAppAndStream(app, stream);  
357 - gbStreamMapper.del(app, stream);  
358 - System.out.println();  
359 - // TODO 如果关联的推流, 那么状态设置为离线 382 + logger.info("[移除代理]: 代理: {}/{}, 从zlm移除成功", app, stream);
  383 + }else {
  384 + logger.info("[移除代理]: 代理: {}/{}, 从zlm移除失败", app, stream);
360 } 385 }
361 - videoManagerStorager.deleteStreamProxy(app, stream);  
362 - redisCatchStorage.removeStream(streamProxyItem.getMediaServerId(), "PULL", app, stream);  
363 } 386 }
364 -  
365 -  
366 } 387 }
367 388
368 @Override 389 @Override
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java
@@ -12,9 +12,9 @@ import java.util.List; @@ -12,9 +12,9 @@ import java.util.List;
12 public interface StreamProxyMapper { 12 public interface StreamProxyMapper {
13 13
14 @Insert("INSERT INTO wvp_stream_proxy (type, name, app, stream,media_server_id, url, src_url, dst_url, " + 14 @Insert("INSERT INTO wvp_stream_proxy (type, name, app, stream,media_server_id, url, src_url, dst_url, " +
15 - "timeout_ms, ffmpeg_cmd_key, rtp_type, enable_audio, enable_mp4, enable, status, enable_remove_none_reader, enable_disable_none_reader, create_time) VALUES" + 15 + "timeout_ms, ffmpeg_cmd_key, rtp_type, enable_audio, enable_mp4, enable, status, stream_key, enable_remove_none_reader, enable_disable_none_reader, create_time) VALUES" +
16 "(#{type}, #{name}, #{app}, #{stream}, #{mediaServerId}, #{url}, #{srcUrl}, #{dstUrl}, " + 16 "(#{type}, #{name}, #{app}, #{stream}, #{mediaServerId}, #{url}, #{srcUrl}, #{dstUrl}, " +
17 - "#{timeoutMs}, #{ffmpegCmdKey}, #{rtpType}, #{enableAudio}, #{enableMp4}, #{enable}, #{status}, " + 17 + "#{timeoutMs}, #{ffmpegCmdKey}, #{rtpType}, #{enableAudio}, #{enableMp4}, #{enable}, #{status}, #{streamKey}, " +
18 "#{enableRemoveNoneReader}, #{enableDisableNoneReader}, #{createTime} )") 18 "#{enableRemoveNoneReader}, #{enableDisableNoneReader}, #{createTime} )")
19 int add(StreamProxyItem streamProxyDto); 19 int add(StreamProxyItem streamProxyDto);
20 20
@@ -33,6 +33,7 @@ public interface StreamProxyMapper { @@ -33,6 +33,7 @@ public interface StreamProxyMapper {
33 "enable_audio=#{enableAudio}, " + 33 "enable_audio=#{enableAudio}, " +
34 "enable=#{enable}, " + 34 "enable=#{enable}, " +
35 "status=#{status}, " + 35 "status=#{status}, " +
  36 + "stream_key=#{streamKey}, " +
36 "enable_remove_none_reader=#{enableRemoveNoneReader}, " + 37 "enable_remove_none_reader=#{enableRemoveNoneReader}, " +
37 "enable_disable_none_reader=#{enableDisableNoneReader}, " + 38 "enable_disable_none_reader=#{enableDisableNoneReader}, " +
38 "enable_mp4=#{enableMp4} " + 39 "enable_mp4=#{enableMp4} " +
@@ -45,7 +46,7 @@ public interface StreamProxyMapper { @@ -45,7 +46,7 @@ public interface StreamProxyMapper {
45 @Select("SELECT st.*, pgs.gb_id, pgs.name, pgs.longitude, pgs.latitude FROM wvp_stream_proxy st LEFT join wvp_gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream order by st.create_time desc") 46 @Select("SELECT st.*, pgs.gb_id, pgs.name, pgs.longitude, pgs.latitude FROM wvp_stream_proxy st LEFT join wvp_gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream order by st.create_time desc")
46 List<StreamProxyItem> selectAll(); 47 List<StreamProxyItem> selectAll();
47 48
48 - @Select("SELECT st.*, pgs.gb_id, pgs.name, pgs.longitude, pgs.latitude FROM wvp_stream_proxy st LEFT join wvp_gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.enable=#{enable} order by st.create_time desc") 49 + @Select("SELECT st.*, pgs.gb_id, pgs.name, pgs.longitude, pgs.latitude, 'proxy' as streamType FROM wvp_stream_proxy st LEFT join wvp_gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.enable=#{enable} order by st.create_time desc")
49 List<StreamProxyItem> selectForEnable(boolean enable); 50 List<StreamProxyItem> selectForEnable(boolean enable);
50 51
51 @Select("SELECT st.*, pgs.gb_id, pgs.name, pgs.longitude, pgs.latitude FROM wvp_stream_proxy st LEFT join wvp_gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.app=#{app} AND st.stream=#{stream} order by st.create_time desc") 52 @Select("SELECT st.*, pgs.gb_id, pgs.name, pgs.longitude, pgs.latitude FROM wvp_stream_proxy st LEFT join wvp_gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.app=#{app} AND st.stream=#{stream} order by st.create_time desc")
src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java
@@ -67,6 +67,16 @@ public class StreamProxyController { @@ -67,6 +67,16 @@ public class StreamProxyController {
67 return streamProxyService.getAll(page, count); 67 return streamProxyService.getAll(page, count);
68 } 68 }
69 69
  70 + @Operation(summary = "查询流代理")
  71 + @Parameter(name = "app", description = "应用名")
  72 + @Parameter(name = "stream", description = "流Id")
  73 + @GetMapping(value = "/one")
  74 + @ResponseBody
  75 + public StreamProxyItem one(String app, String stream){
  76 +
  77 + return streamProxyService.getStreamProxyByAppAndStream(app, stream);
  78 + }
  79 +
70 @Operation(summary = "保存代理", parameters = { 80 @Operation(summary = "保存代理", parameters = {
71 @Parameter(name = "param", description = "代理参数", required = true), 81 @Parameter(name = "param", description = "代理参数", required = true),
72 }) 82 })
@@ -86,6 +96,10 @@ public class StreamProxyController { @@ -86,6 +96,10 @@ public class StreamProxyController {
86 if (ObjectUtils.isEmpty(param.getGbId())) { 96 if (ObjectUtils.isEmpty(param.getGbId())) {
87 param.setGbId(null); 97 param.setGbId(null);
88 } 98 }
  99 + StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream());
  100 + if (streamProxyItem != null) {
  101 + streamProxyService.del(param.getApp(), param.getStream());
  102 + }
89 103
90 RequestMessage requestMessage = new RequestMessage(); 104 RequestMessage requestMessage = new RequestMessage();
91 String key = DeferredResultHolder.CALLBACK_CMD_PROXY + param.getApp() + param.getStream(); 105 String key = DeferredResultHolder.CALLBACK_CMD_PROXY + param.getApp() + param.getStream();