From fbdad00cdb294a857f55e33b2dd92c61dc37475c Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Tue, 13 Oct 2020 18:55:42 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=97=A0=E9=9F=B3=E9=A2=91?= =?UTF-8?q?=E9=80=9A=E9=81=93=E5=BC=80=E5=90=AF=E9=80=9A=E9=81=93=E9=9F=B3?= =?UTF-8?q?=E9=A2=91=E5=90=8E=E6=97=A0=E6=B3=95=E6=92=AD=E6=94=BE=E7=9A=84?= =?UTF-8?q?bug=20=E4=BF=AE=E5=A4=8D=E7=82=B9=E6=92=AD=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E7=9C=9F=E7=9A=84=E6=94=B6=E5=88=B0=E8=A7=86=E9=A2=91=E5=90=8E?= =?UTF-8?q?=E5=9B=9E=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../genersoft/iot/vmp/common/StreamInfo.java | 11 ++ .../vmp/media/zlm/ZLMHttpHookListener.java | 7 ++ .../iot/vmp/media/zlm/ZLMRESTfulUtils.java | 86 +++++++++++++ .../iot/vmp/media/zlm/ZLMRunner.java | 116 +++++++----------- .../iot/vmp/vmanager/play/PlayController.java | 40 +++++- .../src/components/gb28181/devicePlayer.vue | 12 ++ 6 files changed, 193 insertions(+), 79 deletions(-) create mode 100644 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java 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 0e7da448..270f72aa 100644 --- a/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java +++ b/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java @@ -1,5 +1,7 @@ package com.genersoft.iot.vmp.common; +import com.alibaba.fastjson.JSONArray; + public class StreamInfo { private String ssrc; @@ -10,6 +12,7 @@ public class StreamInfo { private String rtmp; private String hls; private String rtsp; + private JSONArray tracks; public String getSsrc() { return ssrc; @@ -74,4 +77,12 @@ public class StreamInfo { public void setCahnnelId(String cahnnelId) { this.cahnnelId = cahnnelId; } + + public JSONArray getTracks() { + return tracks; + } + + public void setTracks(JSONArray tracks) { + this.tracks = tracks; + } } 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 666cc258..4c9f6fdc 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 @@ -46,6 +46,9 @@ public class ZLMHttpHookListener { @Autowired private IVideoManagerStorager storager; + @Autowired + private ZLMRESTfulUtils zlmresTfulUtils; + @Value("${media.ip}") private String mediaIp; @@ -125,6 +128,8 @@ public class ZLMHttpHookListener { } String app = json.getString("app"); String streamId = json.getString("id"); + + // 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); @@ -135,6 +140,8 @@ public class ZLMHttpHookListener { streamInfo.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getLocalIP(), mediaInfo.getRtmpPort(), streamId)); streamInfo.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getLocalIP(), mediaInfo.getHttpPort(), streamId)); streamInfo.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getLocalIP(), mediaInfo.getRtspPort(), streamId)); + + storager.startPlay(streamInfo); } diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java new file mode 100644 index 00000000..01aa341a --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java @@ -0,0 +1,86 @@ +package com.genersoft.iot.vmp.media.zlm; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import okhttp3.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +@Component +public class ZLMRESTfulUtils { + + private final static Logger logger = LoggerFactory.getLogger(ZLMRESTfulUtils.class); + + @Value("${media.ip}") + private String mediaIp; + + @Value("${media.port}") + private int mediaPort; + + @Value("${media.secret}") + private String mediaSecret; + + public JSONObject sendPost(String api, Map param) { + OkHttpClient client = new OkHttpClient(); + String url = String.format("http://%s:%s/index/api/%s", mediaIp, mediaPort, api); + JSONObject responseJSON = null; + logger.debug(url); + + FormBody.Builder builder = new FormBody.Builder(); + builder.add("secret",mediaSecret); + if (param != null) { + for (String key : param.keySet()){ + builder.add(key, param.get(key).toString()); + } + } + + FormBody body = builder.build(); + + Request request = new Request.Builder() + .post(body) + .url(url) + .build(); + try { + Response response = client.newCall(request).execute(); + if (response.isSuccessful()) { + String responseStr = response.body().string(); + if (responseStr != null) { + responseJSON = JSON.parseObject(responseStr); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + + return responseJSON; + } + + public JSONObject getMediaList(String app, String schema){ + Map param = new HashMap<>(); + param.put("app",app); + param.put("schema",schema); + param.put("vhost","__defaultVhost__"); + return sendPost("getMediaList",param); + } + + public JSONObject getRtpInfo(String stream_id){ + Map param = new HashMap<>(); + param.put("stream_id",stream_id); + return sendPost("getRtpInfo",param); + } + + public JSONObject getMediaServerConfig(){ + return sendPost("getServerConfig",null); + } + + public JSONObject setServerConfig(Map param){ + return sendPost("setServerConfig",param); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java index 8dc8e501..81148144 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java @@ -17,6 +17,8 @@ import org.springframework.stereotype.Component; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; +import java.util.HashMap; +import java.util.Map; @Component @Order(value=1) @@ -42,6 +44,9 @@ public class ZLMRunner implements CommandLineRunner { @Value("${server.port}") private String serverPort; + @Autowired + private ZLMRESTfulUtils zlmresTfulUtils; + @Override public void run(String... strings) throws Exception { // 获取zlm信息 @@ -59,41 +64,23 @@ public class ZLMRunner implements CommandLineRunner { public MediaServerConfig getMediaServerConfig() { + JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig(); MediaServerConfig mediaServerConfig = null; - OkHttpClient client = new OkHttpClient(); - String url = String.format("http://%s:%s/index/api/getServerConfig?secret=%s", mediaIp, mediaPort, mediaSecret); - //创建一个Request - Request request = new Request.Builder() - .get() - .url(url) - .build(); - //通过client发起请求 - final Call call = client.newCall(request); - //执行同步请求,获取Response对象 - Response response = null; - try { - response = call.execute(); - if (response.isSuccessful()) { - String responseStr = response.body().string(); - if (responseStr != null) { - JSONObject responseJSON = JSON.parseObject(responseStr); - JSONArray data = responseJSON.getJSONArray("data"); - if (data != null && data.size() > 0) { - mediaServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), MediaServerConfig.class); - mediaServerConfig.setLocalIP(mediaIp); - } - } - }else { - logger.error("getMediaServerConfig失败, 1s后重试"); - Thread.sleep(1000); - getMediaServerConfig(); + if (responseJSON != null) { + JSONArray data = responseJSON.getJSONArray("data"); + if (data != null && data.size() > 0) { + mediaServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), MediaServerConfig.class); + mediaServerConfig.setLocalIP(mediaIp); } - } catch (IOException e) { - e.printStackTrace(); - } catch (InterruptedException e) { - e.printStackTrace(); + } else { + logger.error("getMediaServerConfig失败, 1s后重试"); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + getMediaServerConfig(); } - return mediaServerConfig; } @@ -102,51 +89,30 @@ public class ZLMRunner implements CommandLineRunner { if (mediaIp.equals(sipIP)) { hookIP = "127.0.0.1"; } - OkHttpClient client = new OkHttpClient(); - String url = String.format("http://%s:%s/index/api/setServerConfig", mediaIp, mediaPort); + String hookPrex = String.format("http://%s:%s/index/hook", hookIP, serverPort); + Map param = new HashMap<>(); + param.put("secret",mediaSecret); + param.put("hook.enable","1"); + param.put("hook.on_flow_report",""); + param.put("hook.on_http_access",""); + param.put("hook.on_publish",String.format("%s/on_publish", hookPrex)); + param.put("hook.on_record_mp4",""); + param.put("hook.on_record_ts",""); + param.put("hook.on_rtsp_auth",""); + param.put("hook.on_rtsp_realm",""); + param.put("hook.on_server_started",String.format("%s/on_server_started", hookPrex)); + param.put("hook.on_shell_login",String.format("%s/on_shell_login", hookPrex)); + param.put("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrex)); + param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrex)); + param.put("hook.timeoutSec","20"); - RequestBody body = new FormBody.Builder() - .add("secret",mediaSecret) - .add("hook.enable","1") - .add("hook.on_flow_report","") - .add("hook.on_http_access","") - .add("hook.on_publish",String.format("%s/on_publish", hookPrex)) - .add("hook.on_record_mp4","") - .add("hook.on_record_ts","") - .add("hook.on_rtsp_auth","") - .add("hook.on_rtsp_realm","") - .add("hook.on_server_started",String.format("%s/on_server_started", hookPrex)) - .add("hook.on_shell_login",String.format("%s/on_shell_login", hookPrex)) - .add("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrex)) - .add("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrex)) - .add("hook.timeoutSec","20") - .build(); + JSONObject responseJSON = zlmresTfulUtils.setServerConfig(param); - Request request = new Request.Builder() - .post(body) - .url(url) - .build(); - client.newCall(request).enqueue(new Callback() { - @Override - public void onFailure(Call call, IOException e) { - logger.error("saveZLMConfig ",e); - } - @Override - public void onResponse(Call call, Response response) throws IOException { - if (response.isSuccessful()) { - String responseStr = response.body().string(); - if (responseStr != null) { - JSONObject responseJSON = JSON.parseObject(responseStr); - if (responseJSON.getInteger("code") == 0) { - logger.info("设置zlm成功"); - }else { - logger.info("设置zlm失败: " + responseJSON.getString("msg")); - } - } - } - - } - }); + if (responseJSON != null && responseJSON.getInteger("code") == 0) { + logger.info("设置zlm成功"); + }else { + logger.info("设置zlm失败: " + responseJSON.getString("msg")); + } } } 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 119426a6..996039ee 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 @@ -1,7 +1,9 @@ package com.genersoft.iot.vmp.vmanager.play; import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -31,6 +33,9 @@ public class PlayController { @Autowired private IVideoManagerStorager storager; + + @Autowired + private ZLMRESTfulUtils zlmresTfulUtils; @GetMapping("/play/{deviceId}/{channelId}") public ResponseEntity play(@PathVariable String deviceId,@PathVariable String channelId){ @@ -38,17 +43,44 @@ public class PlayController { Device device = storager.queryVideoDevice(deviceId); StreamInfo streamInfo = cmder.playStreamCmd(device, channelId); // 等待推流, TODO 默认超时15s - + boolean lockFlag = true; long startTime = System.currentTimeMillis(); - while (storager.queryPlay(streamInfo) == null || storager.queryPlay(streamInfo).getFlv() == null) { + String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase(); + + // 判断推流是否存在 + while (lockFlag) { try { - if (System.currentTimeMillis() - startTime > 15 * 1000) + if (System.currentTimeMillis() - startTime > 15 * 1000) { + JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId); + if (rtpInfo == null){ + continue; + }else { + lockFlag = false; + streamInfo = storager.queryPlay(streamInfo); + // 获取媒体信息 + JSONObject mediaList = zlmresTfulUtils.getMediaList("rtp", "rtmp"); + if (mediaList.getInteger("code") == 0) { + JSONArray data = mediaList.getJSONArray("data"); + if (data!= null) { + for (Object datum : data) { + JSONObject media = (JSONObject)datum; + if (streamId.equals(media.getString("stream"))) { + streamInfo.setTracks(media.getJSONArray("tracks")); + storager.startPlay(streamInfo); + } + } + } + } + }; + + } + Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } - streamInfo = storager.queryPlay(streamInfo); + if (logger.isDebugEnabled()) { logger.debug(String.format("设备预览 API调用,deviceId:%s ,channelId:%s",deviceId, channelId)); logger.debug("设备预览 API调用,ssrc:"+streamInfo.getSsrc()+",ZLMedia streamId:"+Integer.toHexString(Integer.parseInt(streamInfo.getSsrc()))); diff --git a/web_src/src/components/gb28181/devicePlayer.vue b/web_src/src/components/gb28181/devicePlayer.vue index f49e03f0..9e497e4c 100644 --- a/web_src/src/components/gb28181/devicePlayer.vue +++ b/web_src/src/components/gb28181/devicePlayer.vue @@ -124,6 +124,18 @@ play: function(streamInfo, deviceId, channelId, hasAudio) { console.log(hasAudio); this.hasaudio = hasAudio; + // 根据媒体流信息二次判断 + if( this.hasaudio && !!streamInfo.tracks && streamInfo.tracks.length > 0) { + var realHasAudio = false; + for (let i = 0; i < streamInfo.tracks; i++) { + if (streamInfo.tracks[i].codec_type == 1) { // 判断为音频 + realHasAudio = true; + } + } + this.hasaudio = realHasAudio && this.hasaudio; + } + console.log("111") + console.log(this.hasaudio) this.ssrc = streamInfo.ssrc; this.deviceId = deviceId; this.channelId = channelId;