src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
web_src/src/components/gb28181/devicePlayer.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
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 @@ private String rtmp; private String hls; private String rtsp; private JSONArray tracks; public String getSsrc() { return ssrc; @@ -74,4 +77,12 @@ public void setCahnnelId(String cahnnelId) { this.cahnnelId = cahnnelId; } public JSONArray getTracks() { return tracks; } public void setTracks(JSONArray tracks) { this.tracks = tracks; } } src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -46,6 +46,9 @@ @Autowired private IVideoManagerStorager storager; @Autowired private ZLMRESTfulUtils zlmresTfulUtils; @Value("${media.ip}") private String mediaIp; @@ -125,6 +128,8 @@ } 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 @@ 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); } src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
New file @@ -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<String, Object> 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<String, Object> 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<String, Object> param = new HashMap<>(); param.put("stream_id",stream_id); return sendPost("getRtpInfo",param); } public JSONObject getMediaServerConfig(){ return sendPost("getServerConfig",null); } public JSONObject setServerConfig(Map<String, Object> param){ return sendPost("setServerConfig",param); } } src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
@@ -17,6 +17,8 @@ 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 @@ @Value("${server.port}") private String serverPort; @Autowired private ZLMRESTfulUtils zlmresTfulUtils; @Override public void run(String... strings) throws Exception { // 获取zlm信息 @@ -59,41 +64,23 @@ 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 @@ 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<String, Object> 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")); } } } 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 @@ @Autowired private IVideoManagerStorager storager; @Autowired private ZLMRESTfulUtils zlmresTfulUtils; @GetMapping("/play/{deviceId}/{channelId}") public ResponseEntity<String> play(@PathVariable String deviceId,@PathVariable String channelId){ @@ -38,17 +43,44 @@ 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()))); 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;